diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 45 | ||||
-rw-r--r-- | drivers/spi/atmel_spi.c | 4 | ||||
-rw-r--r-- | drivers/spi/au1550_spi.c | 213 | ||||
-rw-r--r-- | drivers/spi/mpc52xx_psc_spi.c | 24 | ||||
-rw-r--r-- | drivers/spi/omap2_mcspi.c | 4 | ||||
-rw-r--r-- | drivers/spi/pxa2xx_spi.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi.c | 143 | ||||
-rw-r--r-- | drivers/spi/spi_imx.c | 60 | ||||
-rw-r--r-- | drivers/spi/spi_mpc83xx.c | 29 | ||||
-rw-r--r-- | drivers/spi/spi_s3c24xx.c | 1 | ||||
-rw-r--r-- | drivers/spi/spidev.c | 36 | ||||
-rw-r--r-- | drivers/spi/xilinx_spi.c | 5 |
12 files changed, 342 insertions, 226 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 66ec5d8..2303521 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/atmel_spi.c b/drivers/spi/atmel_spi.c index e81d59d..0c71656 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -313,14 +313,14 @@ atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) xfer->tx_dma = dma_map_single(dev, (void *) xfer->tx_buf, xfer->len, DMA_TO_DEVICE); - if (dma_mapping_error(xfer->tx_dma)) + if (dma_mapping_error(dev, xfer->tx_dma)) return -ENOMEM; } if (xfer->rx_buf) { xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, xfer->len, DMA_FROM_DEVICE); - if (dma_mapping_error(xfer->rx_dma)) { + if (dma_mapping_error(dev, xfer->rx_dma)) { if (xfer->tx_buf) dma_unmap_single(dev, xfer->tx_dma, xfer->len, diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c index 072c4a5..87b73e0 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); @@ -330,7 +334,7 @@ static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned size) hw->dma_rx_tmpbuf_size = size; hw->dma_rx_tmpbuf_addr = dma_map_single(hw->dev, hw->dma_rx_tmpbuf, size, DMA_FROM_DEVICE); - if (dma_mapping_error(hw->dma_rx_tmpbuf_addr)) { + if (dma_mapping_error(hw->dev, hw->dma_rx_tmpbuf_addr)) { kfree(hw->dma_rx_tmpbuf); hw->dma_rx_tmpbuf = 0; hw->dma_rx_tmpbuf_size = 0; @@ -374,7 +378,7 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t) dma_rx_addr = dma_map_single(hw->dev, (void *)t->rx_buf, t->len, DMA_FROM_DEVICE); - if (dma_mapping_error(dma_rx_addr)) + if (dma_mapping_error(hw->dev, dma_rx_addr)) dev_err(hw->dev, "rx dma map error\n"); } } else { @@ -397,7 +401,7 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t) dma_tx_addr = dma_map_single(hw->dev, (void *)t->tx_buf, t->len, DMA_TO_DEVICE); - if (dma_mapping_error(dma_tx_addr)) + if (dma_mapping_error(hw->dev, dma_tx_addr)) dev_err(hw->dev, "tx dma map error\n"); } } else { @@ -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/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index 681d623..25eda71 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -17,7 +17,7 @@ #include <linux/interrupt.h> #if defined(CONFIG_PPC_MERGE) -#include <asm/of_platform.h> +#include <linux/of_platform.h> #else #include <linux/platform_device.h> #endif @@ -148,7 +148,6 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, unsigned rfalarm; unsigned send_at_once = MPC52xx_PSC_BUFSIZE; unsigned recv_at_once; - unsigned bpw = mps->bits_per_word / 8; if (!t->tx_buf && !t->rx_buf && t->len) return -EINVAL; @@ -164,22 +163,15 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, } dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once); - if (tx_buf) { - for (; send_at_once; sb++, send_at_once--) { - /* set EOF flag */ - if (mps->bits_per_word - && (sb + 1) % bpw == 0) - out_8(&psc->ircr2, 0x01); + for (; send_at_once; sb++, send_at_once--) { + /* set EOF flag before the last word is sent */ + if (send_at_once == 1) + out_8(&psc->ircr2, 0x01); + + if (tx_buf) out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]); - } - } else { - for (; send_at_once; sb++, send_at_once--) { - /* set EOF flag */ - if (mps->bits_per_word - && ((sb + 1) % bpw) == 0) - out_8(&psc->ircr2, 0x01); + else out_8(&psc->mpc52xx_psc_buffer_8, 0); - } } diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index b1cc148..f6f987b 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -836,7 +836,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) if (tx_buf != NULL) { t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf, len, DMA_TO_DEVICE); - if (dma_mapping_error(t->tx_dma)) { + if (dma_mapping_error(&spi->dev, t->tx_dma)) { dev_dbg(&spi->dev, "dma %cX %d bytes error\n", 'T', len); return -EINVAL; @@ -845,7 +845,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) if (rx_buf != NULL) { t->rx_dma = dma_map_single(&spi->dev, rx_buf, t->len, DMA_FROM_DEVICE); - if (dma_mapping_error(t->rx_dma)) { + if (dma_mapping_error(&spi->dev, t->rx_dma)) { dev_dbg(&spi->dev, "dma %cX %d bytes error\n", 'R', len); if (tx_buf != NULL) diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 0c452c4..067299d 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -353,7 +353,7 @@ static int map_dma_buffers(struct driver_data *drv_data) drv_data->rx_dma = dma_map_single(dev, drv_data->rx, drv_data->rx_map_len, DMA_FROM_DEVICE); - if (dma_mapping_error(drv_data->rx_dma)) + if (dma_mapping_error(dev, drv_data->rx_dma)) return 0; /* Stream map the tx buffer */ @@ -361,7 +361,7 @@ static int map_dma_buffers(struct driver_data *drv_data) drv_data->tx_map_len, DMA_TO_DEVICE); - if (dma_mapping_error(drv_data->tx_dma)) { + if (dma_mapping_error(dev, drv_data->tx_dma)) { dma_unmap_single(dev, drv_data->rx_dma, drv_data->rx_map_len, DMA_FROM_DEVICE); return 0; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 1ad12af..964124b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -178,6 +178,96 @@ struct boardinfo { static LIST_HEAD(board_list); static DEFINE_MUTEX(board_lock); +/** + * spi_alloc_device - Allocate a new SPI device + * @master: Controller to which device is connected + * Context: can sleep + * + * Allows a driver to allocate and initialize a spi_device without + * registering it immediately. This allows a driver to directly + * fill the spi_device with device parameters before calling + * spi_add_device() on it. + * + * Caller is responsible to call spi_add_device() on the returned + * spi_device structure to add it to the SPI master. If the caller + * needs to discard the spi_device without adding it, then it should + * call spi_dev_put() on it. + * + * Returns a pointer to the new device, or NULL. + */ +struct spi_device *spi_alloc_device(struct spi_master *master) +{ + struct spi_device *spi; + struct device *dev = master->dev.parent; + + if (!spi_master_get(master)) + return NULL; + + spi = kzalloc(sizeof *spi, GFP_KERNEL); + if (!spi) { + dev_err(dev, "cannot alloc spi_device\n"); + spi_master_put(master); + return NULL; + } + + spi->master = master; + spi->dev.parent = dev; + spi->dev.bus = &spi_bus_type; + spi->dev.release = spidev_release; + device_initialize(&spi->dev); + return spi; +} +EXPORT_SYMBOL_GPL(spi_alloc_device); + +/** + * spi_add_device - Add spi_device allocated with spi_alloc_device + * @spi: spi_device to register + * + * Companion function to spi_alloc_device. Devices allocated with + * spi_alloc_device can be added onto the spi bus with this function. + * + * Returns 0 on success; non-zero on failure + */ +int spi_add_device(struct spi_device *spi) +{ + struct device *dev = spi->master->dev.parent; + int status; + + /* Chipselects are numbered 0..max; validate. */ + if (spi->chip_select >= spi->master->num_chipselect) { + dev_err(dev, "cs%d >= max %d\n", + spi->chip_select, + spi->master->num_chipselect); + return -EINVAL; + } + + /* Set the bus ID string */ + snprintf(spi->dev.bus_id, sizeof spi->dev.bus_id, + "%s.%u", spi->master->dev.bus_id, + spi->chip_select); + + /* drivers may modify this initial i/o setup */ + status = spi->master->setup(spi); + if (status < 0) { + dev_err(dev, "can't %s %s, status %d\n", + "setup", spi->dev.bus_id, status); + return status; + } + + /* driver core catches callers that misbehave by defining + * devices that already exist. + */ + status = device_add(&spi->dev); + if (status < 0) { + dev_err(dev, "can't %s %s, status %d\n", + "add", spi->dev.bus_id, status); + return status; + } + + dev_dbg(dev, "registered child %s\n", spi->dev.bus_id); + return 0; +} +EXPORT_SYMBOL_GPL(spi_add_device); /** * spi_new_device - instantiate one new SPI device @@ -197,7 +287,6 @@ struct spi_device *spi_new_device(struct spi_master *master, struct spi_board_info *chip) { struct spi_device *proxy; - struct device *dev = master->dev.parent; int status; /* NOTE: caller did any chip->bus_num checks necessary. @@ -207,64 +296,28 @@ struct spi_device *spi_new_device(struct spi_master *master, * suggests syslogged diagnostics are best here (ugh). */ - /* Chipselects are numbered 0..max; validate. */ - if (chip->chip_select >= master->num_chipselect) { - dev_err(dev, "cs%d > max %d\n", - chip->chip_select, - master->num_chipselect); + proxy = spi_alloc_device(master); + if (!proxy) return NULL; - } - 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", - chip->chip_select); - goto fail; - } - proxy->master = master; proxy->chip_select = chip->chip_select; proxy->max_speed_hz = chip->max_speed_hz; proxy->mode = chip->mode; proxy->irq = chip->irq; - proxy->modalias = chip->modalias; - - snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, - "%s.%u", master->dev.bus_id, - chip->chip_select); - proxy->dev.parent = dev; - proxy->dev.bus = &spi_bus_type; + strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias)); proxy->dev.platform_data = (void *) chip->platform_data; proxy->controller_data = chip->controller_data; proxy->controller_state = NULL; - proxy->dev.release = spidev_release; - /* drivers may modify this initial i/o setup */ - status = master->setup(proxy); + status = spi_add_device(proxy); if (status < 0) { - dev_err(dev, "can't %s %s, status %d\n", - "setup", proxy->dev.bus_id, status); - goto fail; + spi_dev_put(proxy); + return NULL; } - /* driver core catches callers that misbehave by defining - * devices that already exist. - */ - status = device_register(&proxy->dev); - if (status < 0) { - dev_err(dev, "can't %s %s, status %d\n", - "add", proxy->dev.bus_id, status); - goto fail; - } - dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id); return proxy; - -fail: - spi_master_put(master); - kfree(proxy); - return NULL; } EXPORT_SYMBOL_GPL(spi_new_device); @@ -502,7 +555,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_imx.c b/drivers/spi/spi_imx.c index c730d05..6fb77fc 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -29,6 +29,7 @@ #include <linux/spi/spi.h> #include <linux/workqueue.h> #include <linux/delay.h> +#include <linux/clk.h> #include <asm/io.h> #include <asm/irq.h> @@ -250,6 +251,8 @@ struct driver_data { int tx_dma_needs_unmap; size_t tx_map_len; u32 dummy_dma_buf ____cacheline_aligned; + + struct clk *clk; }; /* Runtime state */ @@ -488,7 +491,7 @@ static int map_dma_buffers(struct driver_data *drv_data) buf, drv_data->tx_map_len, DMA_TO_DEVICE); - if (dma_mapping_error(drv_data->tx_dma)) + if (dma_mapping_error(dev, drv_data->tx_dma)) return -1; drv_data->tx_dma_needs_unmap = 1; @@ -513,7 +516,7 @@ static int map_dma_buffers(struct driver_data *drv_data) buf, drv_data->len, DMA_FROM_DEVICE); - if (dma_mapping_error(drv_data->rx_dma)) + if (dma_mapping_error(dev, drv_data->rx_dma)) return -1; drv_data->rx_dma_needs_unmap = 1; } @@ -531,7 +534,7 @@ static int map_dma_buffers(struct driver_data *drv_data) buf, drv_data->tx_map_len, DMA_TO_DEVICE); - if (dma_mapping_error(drv_data->tx_dma)) { + if (dma_mapping_error(dev, drv_data->tx_dma)) { if (drv_data->rx_dma) { dma_unmap_single(dev, drv_data->rx_dma, @@ -855,15 +858,15 @@ static irqreturn_t spi_int(int irq, void *dev_id) return drv_data->transfer_handler(drv_data); } -static inline u32 spi_speed_hz(u32 data_rate) +static inline u32 spi_speed_hz(struct driver_data *drv_data, u32 data_rate) { - return imx_get_perclk2() / (4 << ((data_rate) >> 13)); + return clk_get_rate(drv_data->clk) / (4 << ((data_rate) >> 13)); } -static u32 spi_data_rate(u32 speed_hz) +static u32 spi_data_rate(struct driver_data *drv_data, u32 speed_hz) { u32 div; - u32 quantized_hz = imx_get_perclk2() >> 2; + u32 quantized_hz = clk_get_rate(drv_data->clk) >> 2; for (div = SPI_PERCLK2_DIV_MIN; div <= SPI_PERCLK2_DIV_MAX; @@ -947,7 +950,7 @@ static void pump_transfers(unsigned long data) tmp = transfer->speed_hz; if (tmp == 0) tmp = chip->max_speed_hz; - tmp = spi_data_rate(tmp); + tmp = spi_data_rate(drv_data, tmp); u32_EDIT(control, SPI_CONTROL_DATARATE, tmp); writel(control, regs + SPI_CONTROL); @@ -1109,7 +1112,7 @@ static int transfer(struct spi_device *spi, struct spi_message *msg) msg->actual_length = 0; /* Per transfer setup check */ - min_speed_hz = spi_speed_hz(SPI_CONTROL_DATARATE_MIN); + min_speed_hz = spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN); max_speed_hz = spi->max_speed_hz; list_for_each_entry(trans, &msg->transfers, transfer_list) { tmp = trans->bits_per_word; @@ -1176,6 +1179,7 @@ msg_rejected: applied and notified to the calling driver. */ static int setup(struct spi_device *spi) { + struct driver_data *drv_data = spi_master_get_devdata(spi->master); struct spi_imx_chip *chip_info; struct chip_data *chip; int first_setup = 0; @@ -1304,14 +1308,14 @@ static int setup(struct spi_device *spi) chip->n_bytes = (tmp <= 8) ? 1 : 2; /* SPI datarate */ - tmp = spi_data_rate(spi->max_speed_hz); + tmp = spi_data_rate(drv_data, spi->max_speed_hz); if (tmp == SPI_CONTROL_DATARATE_BAD) { status = -EINVAL; dev_err(&spi->dev, "setup - " "HW min speed (%d Hz) exceeds required " "max speed (%d Hz)\n", - spi_speed_hz(SPI_CONTROL_DATARATE_MIN), + spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN), spi->max_speed_hz); if (first_setup) goto err_first_setup; @@ -1321,7 +1325,7 @@ static int setup(struct spi_device *spi) } else { u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp); /* Actual rounded max_speed_hz */ - tmp = spi_speed_hz(tmp); + tmp = spi_speed_hz(drv_data, tmp); spi->max_speed_hz = tmp; chip->max_speed_hz = tmp; } @@ -1352,7 +1356,7 @@ static int setup(struct spi_device *spi) chip->period & SPI_PERIOD_WAIT, spi->mode, spi->bits_per_word, - spi_speed_hz(SPI_CONTROL_DATARATE_MIN), + spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN), spi->max_speed_hz); return status; @@ -1465,6 +1469,14 @@ static int __init spi_imx_probe(struct platform_device *pdev) goto err_no_pdata; } + drv_data->clk = clk_get(&pdev->dev, "perclk2"); + if (IS_ERR(drv_data->clk)) { + dev_err(&pdev->dev, "probe - cannot get get\n"); + status = PTR_ERR(drv_data->clk); + goto err_no_clk; + } + clk_enable(drv_data->clk); + /* Allocate master with space for drv_data */ master = spi_alloc_master(dev, sizeof(struct driver_data)); if (!master) { @@ -1526,24 +1538,24 @@ static int __init spi_imx_probe(struct platform_device *pdev) drv_data->rx_channel = -1; if (platform_info->enable_dma) { /* Get rx DMA channel */ - status = imx_dma_request_by_prio(&drv_data->rx_channel, - "spi_imx_rx", DMA_PRIO_HIGH); - if (status < 0) { + drv_data->rx_channel = imx_dma_request_by_prio("spi_imx_rx", + DMA_PRIO_HIGH); + if (drv_data->rx_channel < 0) { dev_err(dev, "probe - problem (%d) requesting rx channel\n", - status); + drv_data->rx_channel); goto err_no_rxdma; } else imx_dma_setup_handlers(drv_data->rx_channel, NULL, dma_err_handler, drv_data); /* Get tx DMA channel */ - status = imx_dma_request_by_prio(&drv_data->tx_channel, - "spi_imx_tx", DMA_PRIO_MEDIUM); - if (status < 0) { + drv_data->tx_channel = imx_dma_request_by_prio("spi_imx_tx", + DMA_PRIO_MEDIUM); + if (drv_data->tx_channel < 0) { dev_err(dev, "probe - problem (%d) requesting tx channel\n", - status); + drv_data->tx_channel); imx_dma_free(drv_data->rx_channel); goto err_no_txdma; } else @@ -1623,6 +1635,9 @@ err_no_iores: spi_master_put(master); err_no_pdata: + clk_disable(drv_data->clk); + clk_put(drv_data->clk); +err_no_clk: err_no_mem: return status; } @@ -1662,6 +1677,9 @@ static int __exit spi_imx_remove(struct platform_device *pdev) if (irq >= 0) free_irq(irq, drv_data); + clk_disable(drv_data->clk); + clk_put(drv_data->clk); + /* Release map resources */ iounmap(drv_data->regs); release_resource(drv_data->ioarea); diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c index 6832da6..070c621 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/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index 0885cc3..1c643c9 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -270,6 +270,7 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev) /* setup the master state. */ master->num_chipselect = hw->pdata->num_cs; + master->bus_num = pdata->bus_num; /* setup the state for the bitbang driver */ diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 799337f..e5e0cfe 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -30,6 +30,7 @@ #include <linux/errno.h> #include <linux/mutex.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/spi/spi.h> #include <linux/spi/spidev.h> @@ -167,14 +168,14 @@ spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) mutex_lock(&spidev->buf_lock); status = spidev_sync_read(spidev, count); - if (status == 0) { + if (status > 0) { unsigned long missing; - missing = copy_to_user(buf, spidev->buffer, count); - if (count && missing == count) + missing = copy_to_user(buf, spidev->buffer, status); + if (missing == status) status = -EFAULT; else - status = count - missing; + status = status - missing; } mutex_unlock(&spidev->buf_lock); @@ -200,8 +201,6 @@ spidev_write(struct file *filp, const char __user *buf, missing = copy_from_user(spidev->buffer, buf, count); if (missing == 0) { status = spidev_sync_write(spidev, count); - if (status == 0) - status = count; } else status = -EFAULT; mutex_unlock(&spidev->buf_lock); @@ -229,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; @@ -297,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; @@ -342,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: @@ -457,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; } @@ -466,6 +472,7 @@ static int spidev_open(struct inode *inode, struct file *filp) struct spidev_data *spidev; int status = -ENXIO; + lock_kernel(); mutex_lock(&device_list_lock); list_for_each_entry(spidev, &device_list, device_entry) { @@ -491,6 +498,7 @@ static int spidev_open(struct inode *inode, struct file *filp) pr_debug("spidev: nothing for minor %d\n", iminor(inode)); mutex_unlock(&device_list_lock); + unlock_kernel(); return status; } @@ -532,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, }; @@ -575,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; @@ -585,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 113a046..68d6f49 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; |