aboutsummaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig45
-rw-r--r--drivers/spi/au1550_spi.c207
-rw-r--r--drivers/spi/spi.c6
-rw-r--r--drivers/spi/spi_mpc83xx.c29
-rw-r--r--drivers/spi/spidev.c23
-rw-r--r--drivers/spi/xilinx_spi.c5
6 files changed, 184 insertions, 131 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 66ec5d8808d..2303521b4f0 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -49,25 +49,26 @@ config SPI_MASTER
controller and the protocol drivers for the SPI slave chips
that are connected.
+if SPI_MASTER
+
comment "SPI Master Controller Drivers"
- depends on SPI_MASTER
config SPI_ATMEL
tristate "Atmel SPI Controller"
- depends on (ARCH_AT91 || AVR32) && SPI_MASTER
+ depends on (ARCH_AT91 || AVR32)
help
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
config SPI_BFIN
tristate "SPI controller driver for ADI Blackfin5xx"
- depends on SPI_MASTER && BLACKFIN
+ depends on BLACKFIN
help
This is the SPI controller master driver for Blackfin 5xx processor.
config SPI_AU1550
tristate "Au1550/Au12x0 SPI Controller"
- depends on SPI_MASTER && (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
+ depends on (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
select SPI_BITBANG
help
If you say yes to this option, support will be included for the
@@ -78,7 +79,6 @@ config SPI_AU1550
config SPI_BITBANG
tristate "Bitbanging SPI master"
- depends on SPI_MASTER && EXPERIMENTAL
help
With a few GPIO pins, your system can bitbang the SPI protocol.
Select this to get SPI support through I/O pins (GPIO, parallel
@@ -92,7 +92,7 @@ config SPI_BITBANG
config SPI_BUTTERFLY
tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
- depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+ depends on PARPORT
select SPI_BITBANG
help
This uses a custom parallel port cable to connect to an AVR
@@ -102,14 +102,14 @@ config SPI_BUTTERFLY
config SPI_IMX
tristate "Freescale iMX SPI controller"
- depends on SPI_MASTER && ARCH_IMX && EXPERIMENTAL
+ depends on ARCH_IMX && EXPERIMENTAL
help
This enables using the Freescale iMX SPI controller in master
mode.
config SPI_LM70_LLP
tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
- depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+ depends on PARPORT && EXPERIMENTAL
select SPI_BITBANG
help
This driver supports the NS LM70 LLP Evaluation Board,
@@ -118,14 +118,14 @@ config SPI_LM70_LLP
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
- depends on SPI_MASTER && PPC_MPC52xx && EXPERIMENTAL
+ depends on PPC_MPC52xx && EXPERIMENTAL
help
This enables using the Freescale MPC52xx Programmable Serial
Controller in master SPI mode.
config SPI_MPC83xx
tristate "Freescale MPC83xx/QUICC Engine SPI controller"
- depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
+ depends on (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
help
This enables using the Freescale MPC83xx and QUICC Engine SPI
controllers in master mode.
@@ -137,21 +137,21 @@ config SPI_MPC83xx
config SPI_OMAP_UWIRE
tristate "OMAP1 MicroWire"
- depends on SPI_MASTER && ARCH_OMAP1
+ depends on ARCH_OMAP1
select SPI_BITBANG
help
This hooks up to the MicroWire controller on OMAP1 chips.
config SPI_OMAP24XX
tristate "McSPI driver for OMAP24xx/OMAP34xx"
- depends on SPI_MASTER && (ARCH_OMAP24XX || ARCH_OMAP34XX)
+ depends on ARCH_OMAP24XX || ARCH_OMAP34XX
help
SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
(McSPI) modules.
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
- depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL
+ depends on ARCH_PXA && EXPERIMENTAL
select PXA_SSP
help
This enables using a PXA2xx SSP port as a SPI master controller.
@@ -160,14 +160,14 @@ config SPI_PXA2XX
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
- depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL
+ depends on ARCH_S3C2410 && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs
config SPI_S3C24XX_GPIO
tristate "Samsung S3C24XX series SPI by GPIO"
- depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL
+ depends on ARCH_S3C2410 && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs using
@@ -177,20 +177,20 @@ config SPI_S3C24XX_GPIO
config SPI_SH_SCI
tristate "SuperH SCI SPI controller"
- depends on SPI_MASTER && SUPERH
+ depends on SUPERH
select SPI_BITBANG
help
SPI driver for SuperH SCI blocks.
config SPI_TXX9
tristate "Toshiba TXx9 SPI controller"
- depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX
+ depends on GENERIC_GPIO && CPU_TX49XX
help
SPI driver for Toshiba TXx9 MIPS SoCs
config SPI_XILINX
tristate "Xilinx SPI controller"
- depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL
+ depends on XILINX_VIRTEX && EXPERIMENTAL
select SPI_BITBANG
help
This exposes the SPI controller IP from the Xilinx EDK.
@@ -207,11 +207,10 @@ config SPI_XILINX
# being probably the most widely used ones.
#
comment "SPI Protocol Masters"
- depends on SPI_MASTER
config SPI_AT25
tristate "SPI EEPROMs from most vendors"
- depends on SPI_MASTER && SYSFS
+ depends on SYSFS
help
Enable this driver to get read/write support to most SPI EEPROMs,
after you configure the board init code to know about each eeprom
@@ -222,7 +221,7 @@ config SPI_AT25
config SPI_SPIDEV
tristate "User mode SPI device driver support"
- depends on SPI_MASTER && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
This supports user mode SPI protocol drivers.
@@ -231,7 +230,7 @@ config SPI_SPIDEV
config SPI_TLE62X0
tristate "Infineon TLE62X0 (for power switching)"
- depends on SPI_MASTER && SYSFS
+ depends on SYSFS
help
SPI driver for Infineon TLE62X0 series line driver chips,
such as the TLE6220, TLE6230 and TLE6240. This provides a
@@ -242,6 +241,8 @@ config SPI_TLE62X0
# Add new SPI protocol masters in alphabetical order above this line
#
+endif # SPI_MASTER
+
# (slave support would go here)
endif # SPI
diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c
index 072c4a59533..9149689c79d 100644
--- a/drivers/spi/au1550_spi.c
+++ b/drivers/spi/au1550_spi.c
@@ -26,6 +26,7 @@
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/resource.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/dma-mapping.h>
@@ -81,6 +82,7 @@ struct au1550_spi {
struct spi_master *master;
struct device *dev;
struct au1550_spi_info *pdata;
+ struct resource *ioarea;
};
@@ -96,6 +98,8 @@ static dbdev_tab_t au1550_spi_mem_dbdev =
.dev_intpolarity = 0
};
+static int ddma_memid; /* id to above mem dma device */
+
static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw);
@@ -480,9 +484,13 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
au1xxx_dbdma_reset(hw->dma_tx_ch);
au1550_spi_reset_fifos(hw);
- dev_err(hw->dev,
- "Unexpected SPI error: event=0x%x stat=0x%x!\n",
- evnt, stat);
+ if (evnt == PSC_SPIEVNT_RO)
+ dev_err(hw->dev,
+ "dma transfer: receive FIFO overflow!\n");
+ else
+ dev_err(hw->dev,
+ "dma transfer: unexpected SPI error "
+ "(event=0x%x stat=0x%x)!\n", evnt, stat);
complete(&hw->master_done);
return IRQ_HANDLED;
@@ -592,17 +600,17 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO
| PSC_SPIEVNT_RU | PSC_SPIEVNT_TO
- | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD))
+ | PSC_SPIEVNT_SD))
!= 0) {
- dev_err(hw->dev,
- "Unexpected SPI error: event=0x%x stat=0x%x!\n",
- evnt, stat);
/*
* due to an error we consider transfer as done,
* so mask all events until before next transfer start
*/
au1550_spi_mask_ack_all(hw);
au1550_spi_reset_fifos(hw);
+ dev_err(hw->dev,
+ "pio transfer: unexpected SPI error "
+ "(event=0x%x stat=0x%x)!\n", evnt, stat);
complete(&hw->master_done);
return IRQ_HANDLED;
}
@@ -616,27 +624,50 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
stat = hw->regs->psc_spistat;
au_sync();
- if ((stat & PSC_SPISTAT_RE) == 0 && hw->rx_count < hw->len) {
+ /*
+ * Take care to not let the Rx FIFO overflow.
+ *
+ * We only write a byte if we have read one at least. Initially,
+ * the write fifo is full, so we should read from the read fifo
+ * first.
+ * In case we miss a word from the read fifo, we should get a
+ * RO event and should back out.
+ */
+ if (!(stat & PSC_SPISTAT_RE) && hw->rx_count < hw->len) {
hw->rx_word(hw);
- /* ack the receive request event */
- hw->regs->psc_spievent = PSC_SPIEVNT_RR;
- au_sync();
busy = 1;
- }
- if ((stat & PSC_SPISTAT_TF) == 0 && hw->tx_count < hw->len) {
- hw->tx_word(hw);
- /* ack the transmit request event */
- hw->regs->psc_spievent = PSC_SPIEVNT_TR;
- au_sync();
- busy = 1;
+ if (!(stat & PSC_SPISTAT_TF) && hw->tx_count < hw->len)
+ hw->tx_word(hw);
}
} while (busy);
- evnt = hw->regs->psc_spievent;
+ hw->regs->psc_spievent = PSC_SPIEVNT_RR | PSC_SPIEVNT_TR;
au_sync();
- if (hw->rx_count >= hw->len || (evnt & PSC_SPIEVNT_MD) != 0) {
+ /*
+ * Restart the SPI transmission in case of a transmit underflow.
+ * This seems to work despite the notes in the Au1550 data book
+ * of Figure 8-4 with flowchart for SPI master operation:
+ *
+ * """Note 1: An XFR Error Interrupt occurs, unless masked,
+ * for any of the following events: Tx FIFO Underflow,
+ * Rx FIFO Overflow, or Multiple-master Error
+ * Note 2: In case of a Tx Underflow Error, all zeroes are
+ * transmitted."""
+ *
+ * By simply restarting the spi transfer on Tx Underflow Error,
+ * we assume that spi transfer was paused instead of zeroes
+ * transmittion mentioned in the Note 2 of Au1550 data book.
+ */
+ if (evnt & PSC_SPIEVNT_TU) {
+ hw->regs->psc_spievent = PSC_SPIEVNT_TU | PSC_SPIEVNT_MD;
+ au_sync();
+ hw->regs->psc_spipcr = PSC_SPIPCR_MS;
+ au_sync();
+ }
+
+ if (hw->rx_count >= hw->len) {
/* transfer completed successfully */
au1550_spi_mask_ack_all(hw);
complete(&hw->master_done);
@@ -725,6 +756,8 @@ static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
stat = hw->regs->psc_spistat;
au_sync();
} while ((stat & PSC_SPISTAT_DR) == 0);
+
+ au1550_spi_reset_fifos(hw);
}
@@ -732,6 +765,7 @@ static int __init au1550_spi_probe(struct platform_device *pdev)
{
struct au1550_spi *hw;
struct spi_master *master;
+ struct resource *r;
int err = 0;
master = spi_alloc_master(&pdev->dev, sizeof(struct au1550_spi));
@@ -753,76 +787,64 @@ static int __init au1550_spi_probe(struct platform_device *pdev)
goto err_no_pdata;
}
- platform_set_drvdata(pdev, hw);
-
- init_completion(&hw->master_done);
-
- hw->bitbang.master = hw->master;
- hw->bitbang.setup_transfer = au1550_spi_setupxfer;
- hw->bitbang.chipselect = au1550_spi_chipsel;
- hw->bitbang.master->setup = au1550_spi_setup;
- hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "no IRQ\n");
+ err = -ENODEV;
+ goto err_no_iores;
+ }
+ hw->irq = r->start;
+
+ hw->usedma = 0;
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (r) {
+ hw->dma_tx_id = r->start;
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (r) {
+ hw->dma_rx_id = r->start;
+ if (usedma && ddma_memid) {
+ if (pdev->dev.dma_mask == NULL)
+ dev_warn(&pdev->dev, "no dma mask\n");
+ else
+ hw->usedma = 1;
+ }
+ }
+ }
- switch (hw->pdata->bus_num) {
- case 0:
- hw->irq = AU1550_PSC0_INT;
- hw->regs = (volatile psc_spi_t *)PSC0_BASE_ADDR;
- hw->dma_rx_id = DSCR_CMD0_PSC0_RX;
- hw->dma_tx_id = DSCR_CMD0_PSC0_TX;
- break;
- case 1:
- hw->irq = AU1550_PSC1_INT;
- hw->regs = (volatile psc_spi_t *)PSC1_BASE_ADDR;
- hw->dma_rx_id = DSCR_CMD0_PSC1_RX;
- hw->dma_tx_id = DSCR_CMD0_PSC1_TX;
- break;
- case 2:
- hw->irq = AU1550_PSC2_INT;
- hw->regs = (volatile psc_spi_t *)PSC2_BASE_ADDR;
- hw->dma_rx_id = DSCR_CMD0_PSC2_RX;
- hw->dma_tx_id = DSCR_CMD0_PSC2_TX;
- break;
- case 3:
- hw->irq = AU1550_PSC3_INT;
- hw->regs = (volatile psc_spi_t *)PSC3_BASE_ADDR;
- hw->dma_rx_id = DSCR_CMD0_PSC3_RX;
- hw->dma_tx_id = DSCR_CMD0_PSC3_TX;
- break;
- default:
- dev_err(&pdev->dev, "Wrong bus_num of SPI\n");
- err = -ENOENT;
- goto err_no_pdata;
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "no mmio resource\n");
+ err = -ENODEV;
+ goto err_no_iores;
}
- if (request_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t),
- pdev->name) == NULL) {
+ hw->ioarea = request_mem_region(r->start, sizeof(psc_spi_t),
+ pdev->name);
+ if (!hw->ioarea) {
dev_err(&pdev->dev, "Cannot reserve iomem region\n");
err = -ENXIO;
goto err_no_iores;
}
-
- if (usedma) {
- if (pdev->dev.dma_mask == NULL)
- dev_warn(&pdev->dev, "no dma mask\n");
- else
- hw->usedma = 1;
+ hw->regs = (psc_spi_t __iomem *)ioremap(r->start, sizeof(psc_spi_t));
+ if (!hw->regs) {
+ dev_err(&pdev->dev, "cannot ioremap\n");
+ err = -ENXIO;
+ goto err_ioremap;
}
- if (hw->usedma) {
- /*
- * create memory device with 8 bits dev_devwidth
- * needed for proper byte ordering to spi fifo
- */
- int memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev);
- if (!memid) {
- dev_err(&pdev->dev,
- "Cannot create dma 8 bit mem device\n");
- err = -ENXIO;
- goto err_dma_add_dev;
- }
+ platform_set_drvdata(pdev, hw);
+
+ init_completion(&hw->master_done);
+
+ hw->bitbang.master = hw->master;
+ hw->bitbang.setup_transfer = au1550_spi_setupxfer;
+ hw->bitbang.chipselect = au1550_spi_chipsel;
+ hw->bitbang.master->setup = au1550_spi_setup;
+ hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
- hw->dma_tx_ch = au1xxx_dbdma_chan_alloc(memid,
+ if (hw->usedma) {
+ hw->dma_tx_ch = au1xxx_dbdma_chan_alloc(ddma_memid,
hw->dma_tx_id, NULL, (void *)hw);
if (hw->dma_tx_ch == 0) {
dev_err(&pdev->dev,
@@ -841,7 +863,7 @@ static int __init au1550_spi_probe(struct platform_device *pdev)
hw->dma_rx_ch = au1xxx_dbdma_chan_alloc(hw->dma_rx_id,
- memid, NULL, (void *)hw);
+ ddma_memid, NULL, (void *)hw);
if (hw->dma_rx_ch == 0) {
dev_err(&pdev->dev,
"Cannot allocate rx dma channel\n");
@@ -874,7 +896,7 @@ static int __init au1550_spi_probe(struct platform_device *pdev)
goto err_no_irq;
}
- master->bus_num = hw->pdata->bus_num;
+ master->bus_num = pdev->id;
master->num_chipselect = hw->pdata->num_chipselect;
/*
@@ -924,8 +946,11 @@ err_no_txdma_descr:
au1xxx_dbdma_chan_free(hw->dma_tx_ch);
err_no_txdma:
-err_dma_add_dev:
- release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t));
+ iounmap((void __iomem *)hw->regs);
+
+err_ioremap:
+ release_resource(hw->ioarea);
+ kfree(hw->ioarea);
err_no_iores:
err_no_pdata:
@@ -944,7 +969,9 @@ static int __exit au1550_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&hw->bitbang);
free_irq(hw->irq, hw);
- release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t));
+ iounmap((void __iomem *)hw->regs);
+ release_resource(hw->ioarea);
+ kfree(hw->ioarea);
if (hw->usedma) {
au1550_spi_dma_rxtmp_free(hw);
@@ -971,12 +998,24 @@ static struct platform_driver au1550_spi_drv = {
static int __init au1550_spi_init(void)
{
+ /*
+ * create memory device with 8 bits dev_devwidth
+ * needed for proper byte ordering to spi fifo
+ */
+ if (usedma) {
+ ddma_memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev);
+ if (!ddma_memid)
+ printk(KERN_ERR "au1550-spi: cannot add memory"
+ "dbdma device\n");
+ }
return platform_driver_probe(&au1550_spi_drv, au1550_spi_probe);
}
module_init(au1550_spi_init);
static void __exit au1550_spi_exit(void)
{
+ if (usedma && ddma_memid)
+ au1xxx_ddma_del_device(ddma_memid);
platform_driver_unregister(&au1550_spi_drv);
}
module_exit(au1550_spi_exit);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 1ad12afc6ba..ecca4a6a6f9 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -218,6 +218,8 @@ struct spi_device *spi_new_device(struct spi_master *master,
if (!spi_master_get(master))
return NULL;
+ WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
+
proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
if (!proxy) {
dev_err(dev, "can't alloc dev for cs%d\n",
@@ -229,7 +231,7 @@ struct spi_device *spi_new_device(struct spi_master *master,
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
- proxy->modalias = chip->modalias;
+ strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
"%s.%u", master->dev.bus_id,
@@ -502,7 +504,7 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
struct device *dev;
struct spi_master *master = NULL;
- dev = class_find_device(&spi_master_class, &bus_num,
+ dev = class_find_device(&spi_master_class, NULL, &bus_num,
__spi_master_match);
if (dev)
master = container_of(dev, struct spi_master, dev);
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 6832da6f710..070c6219e2d 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -266,21 +266,24 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
cs->hw_mode |= SPMODE_LEN(bits_per_word);
- if ((mpc83xx_spi->spibrg / hz) >= 64) {
- pm = mpc83xx_spi->spibrg / (hz * 64) - 1;
- if (pm > 0x0f) {
- dev_err(&spi->dev, "Requested speed is too "
- "low: %d Hz. Will use %d Hz instead.\n",
- hz, mpc83xx_spi->spibrg / 1024);
- pm = 0x0f;
+ if ((mpc83xx_spi->spibrg / hz) > 64) {
+ pm = mpc83xx_spi->spibrg / (hz * 64);
+ if (pm > 16) {
+ cs->hw_mode |= SPMODE_DIV16;
+ pm /= 16;
+ if (pm > 16) {
+ dev_err(&spi->dev, "Requested speed is too "
+ "low: %d Hz. Will use %d Hz instead.\n",
+ hz, mpc83xx_spi->spibrg / 1024);
+ pm = 16;
+ }
}
- cs->hw_mode |= SPMODE_PM(pm) | SPMODE_DIV16;
- } else {
+ } else
pm = mpc83xx_spi->spibrg / (hz * 4);
- if (pm)
- pm--;
- cs->hw_mode |= SPMODE_PM(pm);
- }
+ if (pm)
+ pm--;
+
+ cs->hw_mode |= SPMODE_PM(pm);
regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
if (cs->hw_mode != regval) {
unsigned long flags;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index ddbe1a5e970..e5e0cfed5e3 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -228,7 +228,6 @@ static int spidev_message(struct spidev_data *spidev,
* We walk the array of user-provided transfers, using each one
* to initialize a kernel version of the same transfer.
*/
- mutex_lock(&spidev->buf_lock);
buf = spidev->buffer;
total = 0;
for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
@@ -296,14 +295,12 @@ static int spidev_message(struct spidev_data *spidev,
status = total;
done:
- mutex_unlock(&spidev->buf_lock);
kfree(k_xfers);
return status;
}
-static int
-spidev_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static long
+spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int err = 0;
int retval = 0;
@@ -341,6 +338,14 @@ spidev_ioctl(struct inode *inode, struct file *filp,
if (spi == NULL)
return -ESHUTDOWN;
+ /* use the buffer lock here for triple duty:
+ * - prevent I/O (from us) so calling spi_setup() is safe;
+ * - prevent concurrent SPI_IOC_WR_* from morphing
+ * data fields while SPI_IOC_RD_* reads them;
+ * - SPI_IOC_MESSAGE needs the buffer locked "normally".
+ */
+ mutex_lock(&spidev->buf_lock);
+
switch (cmd) {
/* read requests */
case SPI_IOC_RD_MODE:
@@ -456,6 +461,8 @@ spidev_ioctl(struct inode *inode, struct file *filp,
kfree(ioc);
break;
}
+
+ mutex_unlock(&spidev->buf_lock);
spi_dev_put(spi);
return retval;
}
@@ -533,7 +540,7 @@ static struct file_operations spidev_fops = {
*/
.write = spidev_write,
.read = spidev_read,
- .ioctl = spidev_ioctl,
+ .unlocked_ioctl = spidev_ioctl,
.open = spidev_open,
.release = spidev_release,
};
@@ -576,7 +583,8 @@ static int spidev_probe(struct spi_device *spi)
struct device *dev;
spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
- dev = device_create(spidev_class, &spi->dev, spidev->devt,
+ dev = device_create_drvdata(spidev_class, &spi->dev,
+ spidev->devt, spidev,
"spidev%d.%d",
spi->master->bus_num, spi->chip_select);
status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
@@ -586,7 +594,6 @@ static int spidev_probe(struct spi_device *spi)
}
if (status == 0) {
set_bit(minor, minors);
- spi_set_drvdata(spi, spidev);
list_add(&spidev->device_entry, &device_list);
}
mutex_unlock(&device_list_lock);
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 113a0468ffc..68d6f4988fb 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -353,11 +353,12 @@ static int __init xilinx_spi_probe(struct platform_device *dev)
goto put_master;
}
- xspi->irq = platform_get_irq(dev, 0);
- if (xspi->irq < 0) {
+ ret = platform_get_irq(dev, 0);
+ if (ret < 0) {
ret = -ENXIO;
goto unmap_io;
}
+ xspi->irq = ret;
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->num_chipselect;