diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 13:56:24 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 13:56:24 -0700 |
commit | be122abe4bcd6d39b37892daae28c8bf5e4030fc (patch) | |
tree | e8ad84c41c2acde27c77fa212b8865cd3acfe6fb /drivers/spi | |
parent | b343c8beec664ef6f0e9964d3001c7c7966331ae (diff) | |
parent | 1e8a52e18cfb381bc9cc1f0b720540364d2a6edd (diff) |
Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6
Pull SPI changes from Grant Likely:
"Bug fixes and new features for SPI device drivers. Also move device
tree support code out of drivers/of and into drivers/spi/spi.c where
it makes more sense."
* tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6:
spi: By default setup spi_masters with 1 chipselect and dynamics bus number
SPI: PRIMA2: use the newest APIs of PINCTRL to fix compiling errors
spi/spi-fsl-spi: reference correct pdata in fsl_spi_cs_control
spi: refactor spi-coldfire-qspi to use SPI queue framework.
spi/omap2-mcspi: convert to the pump message infrastructure
spi/rspi: add dmaengine support
spi/topcliff: use correct __devexit_p annotation
spi: Dont call prepare/unprepare transfer if not populated
spi/ep93xx: clean probe/remove routines
spi/devicetree: Move devicetree support code into spi directory
spi: use module_pci_driver
spi/omap2-mcspi: Trivial optimisation
spi: omap2-mcspi: add support for pm_runtime autosuspend
spi/omap: Remove bus_num usage for instance index
OMAP : SPI : use devm_* functions
spi: omap2-mcspi: convert to module_platform_driver
spi: omap2-mcspi: make it behave as a module
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-ath79.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-coldfire-qspi.c | 255 | ||||
-rw-r--r-- | drivers/spi/spi-dw-pci.c | 13 | ||||
-rw-r--r-- | drivers/spi/spi-ep93xx.c | 37 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-espi.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-lib.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-spi.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-lm70llp.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-mpc52xx.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 373 | ||||
-rw-r--r-- | drivers/spi/spi-ppc4xx.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx-pci.c | 12 | ||||
-rw-r--r-- | drivers/spi/spi-rspi.c | 320 | ||||
-rw-r--r-- | drivers/spi/spi-sirf.c | 20 | ||||
-rw-r--r-- | drivers/spi/spi-topcliff-pch.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi.c | 98 |
16 files changed, 705 insertions, 444 deletions
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index acc88b4d286..249077e5cc4 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -216,9 +216,6 @@ static __devinit int ath79_spi_probe(struct platform_device *pdev) if (pdata) { master->bus_num = pdata->bus_num; master->num_chipselect = pdata->num_chipselect; - } else { - master->bus_num = -1; - master->num_chipselect = 1; } sp->bitbang.master = spi_master_get(master); diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 6eee64a5d24..b2d4b9e4e01 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -25,12 +25,12 @@ #include <linux/errno.h> #include <linux/platform_device.h> #include <linux/sched.h> -#include <linux/workqueue.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/spi/spi.h> +#include <linux/pm_runtime.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> @@ -78,10 +78,7 @@ struct mcfqspi { wait_queue_head_t waitq; - struct work_struct work; - struct workqueue_struct *workq; - spinlock_t lock; - struct list_head msgq; + struct device *dev; }; static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val) @@ -303,120 +300,80 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count, } } -static void mcfqspi_work(struct work_struct *work) +static int mcfqspi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) { - struct mcfqspi *mcfqspi = container_of(work, struct mcfqspi, work); - unsigned long flags; - - spin_lock_irqsave(&mcfqspi->lock, flags); - while (!list_empty(&mcfqspi->msgq)) { - struct spi_message *msg; - struct spi_device *spi; - struct spi_transfer *xfer; - int status = 0; - - msg = container_of(mcfqspi->msgq.next, struct spi_message, - queue); - - list_del_init(&msg->queue); - spin_unlock_irqrestore(&mcfqspi->lock, flags); - - spi = msg->spi; - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - bool cs_high = spi->mode & SPI_CS_HIGH; - u16 qmr = MCFQSPI_QMR_MSTR; - - if (xfer->bits_per_word) - qmr |= xfer->bits_per_word << 10; - else - qmr |= spi->bits_per_word << 10; - if (spi->mode & SPI_CPHA) - qmr |= MCFQSPI_QMR_CPHA; - if (spi->mode & SPI_CPOL) - qmr |= MCFQSPI_QMR_CPOL; - if (xfer->speed_hz) - qmr |= mcfqspi_qmr_baud(xfer->speed_hz); - else - qmr |= mcfqspi_qmr_baud(spi->max_speed_hz); - mcfqspi_wr_qmr(mcfqspi, qmr); - - mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high); - - mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE); - if ((xfer->bits_per_word ? xfer->bits_per_word : - spi->bits_per_word) == 8) - mcfqspi_transfer_msg8(mcfqspi, xfer->len, - xfer->tx_buf, - xfer->rx_buf); - else - mcfqspi_transfer_msg16(mcfqspi, xfer->len / 2, - xfer->tx_buf, - xfer->rx_buf); - mcfqspi_wr_qir(mcfqspi, 0); - - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); - if (xfer->cs_change) { - if (!list_is_last(&xfer->transfer_list, - &msg->transfers)) - mcfqspi_cs_deselect(mcfqspi, - spi->chip_select, - cs_high); - } else { - if (list_is_last(&xfer->transfer_list, - &msg->transfers)) - mcfqspi_cs_deselect(mcfqspi, - spi->chip_select, - cs_high); - } - msg->actual_length += xfer->len; + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); + struct spi_device *spi = msg->spi; + struct spi_transfer *t; + int status = 0; + + list_for_each_entry(t, &msg->transfers, transfer_list) { + bool cs_high = spi->mode & SPI_CS_HIGH; + u16 qmr = MCFQSPI_QMR_MSTR; + + if (t->bits_per_word) + qmr |= t->bits_per_word << 10; + else + qmr |= spi->bits_per_word << 10; + if (spi->mode & SPI_CPHA) + qmr |= MCFQSPI_QMR_CPHA; + if (spi->mode & SPI_CPOL) + qmr |= MCFQSPI_QMR_CPOL; + if (t->speed_hz) + qmr |= mcfqspi_qmr_baud(t->speed_hz); + else + qmr |= mcfqspi_qmr_baud(spi->max_speed_hz); + mcfqspi_wr_qmr(mcfqspi, qmr); + + mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high); + + mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE); + if ((t->bits_per_word ? t->bits_per_word : + spi->bits_per_word) == 8) + mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, + t->rx_buf); + else + mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf, + t->rx_buf); + mcfqspi_wr_qir(mcfqspi, 0); + + if (t->delay_usecs) + udelay(t->delay_usecs); + if (t->cs_change) { + if (!list_is_last(&t->transfer_list, &msg->transfers)) + mcfqspi_cs_deselect(mcfqspi, spi->chip_select, + cs_high); + } else { + if (list_is_last(&t->transfer_list, &msg->transfers)) + mcfqspi_cs_deselect(mcfqspi, spi->chip_select, + cs_high); } - msg->status = status; - msg->complete(msg->context); - - spin_lock_irqsave(&mcfqspi->lock, flags); + msg->actual_length += t->len; } - spin_unlock_irqrestore(&mcfqspi->lock, flags); + msg->status = status; + spi_finalize_current_message(master); + + return status; + } -static int mcfqspi_transfer(struct spi_device *spi, struct spi_message *msg) +static int mcfqspi_prepare_transfer_hw(struct spi_master *master) { - struct mcfqspi *mcfqspi; - struct spi_transfer *xfer; - unsigned long flags; - - mcfqspi = spi_master_get_devdata(spi->master); - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if (xfer->bits_per_word && ((xfer->bits_per_word < 8) - || (xfer->bits_per_word > 16))) { - dev_dbg(&spi->dev, - "%d bits per word is not supported\n", - xfer->bits_per_word); - goto fail; - } - if (xfer->speed_hz) { - u32 real_speed = MCFQSPI_BUSCLK / - mcfqspi_qmr_baud(xfer->speed_hz); - if (real_speed != xfer->speed_hz) - dev_dbg(&spi->dev, - "using speed %d instead of %d\n", - real_speed, xfer->speed_hz); - } - } - msg->status = -EINPROGRESS; - msg->actual_length = 0; + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - spin_lock_irqsave(&mcfqspi->lock, flags); - list_add_tail(&msg->queue, &mcfqspi->msgq); - queue_work(mcfqspi->workq, &mcfqspi->work); - spin_unlock_irqrestore(&mcfqspi->lock, flags); + pm_runtime_get_sync(mcfqspi->dev); + + return 0; +} + +static int mcfqspi_unprepare_transfer_hw(struct spi_master *master) +{ + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); + + pm_runtime_put_sync(mcfqspi->dev); return 0; -fail: - msg->status = -EINVAL; - return -EINVAL; } static int mcfqspi_setup(struct spi_device *spi) @@ -502,21 +459,10 @@ static int __devinit mcfqspi_probe(struct platform_device *pdev) } clk_enable(mcfqspi->clk); - mcfqspi->workq = create_singlethread_workqueue(dev_name(master->dev.parent)); - if (!mcfqspi->workq) { - dev_dbg(&pdev->dev, "create_workqueue failed\n"); - status = -ENOMEM; - goto fail4; - } - INIT_WORK(&mcfqspi->work, mcfqspi_work); - spin_lock_init(&mcfqspi->lock); - INIT_LIST_HEAD(&mcfqspi->msgq); - init_waitqueue_head(&mcfqspi->waitq); - pdata = pdev->dev.platform_data; if (!pdata) { dev_dbg(&pdev->dev, "platform data is missing\n"); - goto fail5; + goto fail4; } master->bus_num = pdata->bus_num; master->num_chipselect = pdata->num_chipselect; @@ -525,28 +471,33 @@ static int __devinit mcfqspi_probe(struct platform_device *pdev) status = mcfqspi_cs_setup(mcfqspi); if (status) { dev_dbg(&pdev->dev, "error initializing cs_control\n"); - goto fail5; + goto fail4; } + init_waitqueue_head(&mcfqspi->waitq); + mcfqspi->dev = &pdev->dev; + master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; master->setup = mcfqspi_setup; - master->transfer = mcfqspi_transfer; + master->transfer_one_message = mcfqspi_transfer_one_message; + master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw; + master->unprepare_transfer_hardware = mcfqspi_unprepare_transfer_hw; platform_set_drvdata(pdev, master); status = spi_register_master(master); if (status) { dev_dbg(&pdev->dev, "spi_register_master failed\n"); - goto fail6; + goto fail5; } + pm_runtime_enable(mcfqspi->dev); + dev_info(&pdev->dev, "Coldfire QSPI bus driver\n"); return 0; -fail6: - mcfqspi_cs_teardown(mcfqspi); fail5: - destroy_workqueue(mcfqspi->workq); + mcfqspi_cs_teardown(mcfqspi); fail4: clk_disable(mcfqspi->clk); clk_put(mcfqspi->clk); @@ -570,12 +521,12 @@ static int __devexit mcfqspi_remove(struct platform_device *pdev) struct mcfqspi *mcfqspi = spi_master_get_devdata(master); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pm_runtime_disable(mcfqspi->dev); /* disable the hardware (set the baud rate to 0) */ mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR); platform_set_drvdata(pdev, NULL); mcfqspi_cs_teardown(mcfqspi); - destroy_workqueue(mcfqspi->workq); clk_disable(mcfqspi->clk); clk_put(mcfqspi->clk); free_irq(mcfqspi->irq, mcfqspi); @@ -587,11 +538,13 @@ static int __devexit mcfqspi_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP static int mcfqspi_suspend(struct device *dev) { - struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); + struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); + + spi_master_suspend(master); clk_disable(mcfqspi->clk); @@ -600,27 +553,47 @@ static int mcfqspi_suspend(struct device *dev) static int mcfqspi_resume(struct device *dev) { - struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); + struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); + + spi_master_resume(master); clk_enable(mcfqspi->clk); return 0; } +#endif -static struct dev_pm_ops mcfqspi_dev_pm_ops = { - .suspend = mcfqspi_suspend, - .resume = mcfqspi_resume, -}; +#ifdef CONFIG_PM_RUNTIME +static int mcfqspi_runtime_suspend(struct device *dev) +{ + struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); -#define MCFQSPI_DEV_PM_OPS (&mcfqspi_dev_pm_ops) -#else -#define MCFQSPI_DEV_PM_OPS NULL + clk_disable(mcfqspi->clk); + + return 0; +} + +static int mcfqspi_runtime_resume(struct device *dev) +{ + struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); + + clk_enable(mcfqspi->clk); + + return 0; +} #endif +static const struct dev_pm_ops mcfqspi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(mcfqspi_suspend, mcfqspi_resume) + SET_RUNTIME_PM_OPS(mcfqspi_runtime_suspend, mcfqspi_runtime_resume, + NULL) +}; + static struct platform_driver mcfqspi_driver = { .driver.name = DRIVER_NAME, .driver.owner = THIS_MODULE, - .driver.pm = MCFQSPI_DEV_PM_OPS, + .driver.pm = &mcfqspi_pm, .probe = mcfqspi_probe, .remove = __devexit_p(mcfqspi_remove), }; diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 14f7cc9523f..ff81abbb306 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -164,18 +164,7 @@ static struct pci_driver dw_spi_driver = { .resume = spi_resume, }; -static int __init mrst_spi_init(void) -{ - return pci_register_driver(&dw_spi_driver); -} - -static void __exit mrst_spi_exit(void) -{ - pci_unregister_driver(&dw_spi_driver); -} - -module_init(mrst_spi_init); -module_exit(mrst_spi_exit); +module_pci_driver(dw_spi_driver); MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>"); MODULE_DESCRIPTION("PCI interface driver for DW SPI Core"); diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index e8055073e84..f97f1d24880 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -76,7 +76,6 @@ * @clk: clock for the controller * @regs_base: pointer to ioremap()'d registers * @sspdr_phys: physical address of the SSPDR register - * @irq: IRQ number used by the driver * @min_rate: minimum clock rate (in Hz) supported by the controller * @max_rate: maximum clock rate (in Hz) supported by the controller * @running: is the queue running @@ -114,7 +113,6 @@ struct ep93xx_spi { struct clk *clk; void __iomem *regs_base; unsigned long sspdr_phys; - int irq; unsigned long min_rate; unsigned long max_rate; bool running; @@ -1031,6 +1029,7 @@ static int __devinit ep93xx_spi_probe(struct platform_device *pdev) struct ep93xx_spi_info *info; struct ep93xx_spi *espi; struct resource *res; + int irq; int error; info = pdev->dev.platform_data; @@ -1070,8 +1069,8 @@ static int __devinit ep93xx_spi_probe(struct platform_device *pdev) espi->min_rate = clk_get_rate(espi->clk) / (254 * 256); espi->pdev = pdev; - espi->irq = platform_get_irq(pdev, 0); - if (espi->irq < 0) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) { error = -EBUSY; dev_err(&pdev->dev, "failed to get irq resources\n"); goto fail_put_clock; @@ -1084,26 +1083,20 @@ static int __devinit ep93xx_spi_probe(struct platform_device *pdev) goto fail_put_clock; } - res = request_mem_region(res->start, resource_size(res), pdev->name); - if (!res) { - dev_err(&pdev->dev, "unable to request iomem resources\n"); - error = -EBUSY; - goto fail_put_clock; - } - espi->sspdr_phys = res->start + SSPDR; - espi->regs_base = ioremap(res->start, resource_size(res)); + + espi->regs_base = devm_request_and_ioremap(&pdev->dev, res); if (!espi->regs_base) { dev_err(&pdev->dev, "failed to map resources\n"); error = -ENODEV; - goto fail_free_mem; + goto fail_put_clock; } - error = request_irq(espi->irq, ep93xx_spi_interrupt, 0, - "ep93xx-spi", espi); + error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt, + 0, "ep93xx-spi", espi); if (error) { dev_err(&pdev->dev, "failed to request irq\n"); - goto fail_unmap_regs; + goto fail_put_clock; } if (info->use_dma && ep93xx_spi_setup_dma(espi)) @@ -1128,7 +1121,7 @@ static int __devinit ep93xx_spi_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n", - (unsigned long)res->start, espi->irq); + (unsigned long)res->start, irq); return 0; @@ -1136,11 +1129,6 @@ fail_free_queue: destroy_workqueue(espi->wq); fail_free_dma: ep93xx_spi_release_dma(espi); - free_irq(espi->irq, espi); -fail_unmap_regs: - iounmap(espi->regs_base); -fail_free_mem: - release_mem_region(res->start, resource_size(res)); fail_put_clock: clk_put(espi->clk); fail_release_master: @@ -1154,7 +1142,6 @@ static int __devexit ep93xx_spi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct ep93xx_spi *espi = spi_master_get_devdata(master); - struct resource *res; spin_lock_irq(&espi->lock); espi->running = false; @@ -1180,10 +1167,6 @@ static int __devexit ep93xx_spi_remove(struct platform_device *pdev) spin_unlock_irq(&espi->lock); ep93xx_spi_release_dma(espi); - free_irq(espi->irq, espi); - iounmap(espi->regs_base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); clk_put(espi->clk); platform_set_drvdata(pdev, NULL); diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 7523a2429d0..27bdc47b525 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -17,7 +17,6 @@ #include <linux/mm.h> #include <linux/of.h> #include <linux/of_platform.h> -#include <linux/of_spi.h> #include <linux/interrupt.h> #include <linux/err.h> #include <sysdev/fsl_soc.h> diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index 2674fad7f68..1503574b215 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -22,7 +22,7 @@ #include <linux/dma-mapping.h> #include <linux/mm.h> #include <linux/of_platform.h> -#include <linux/of_spi.h> +#include <linux/spi/spi.h> #include <sysdev/fsl_soc.h> #include "spi-fsl-lib.h" diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 5f748c0d96b..6a62934ca74 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -933,7 +933,7 @@ err: static void fsl_spi_cs_control(struct spi_device *spi, bool on) { - struct device *dev = spi->dev.parent; + struct device *dev = spi->dev.parent->parent; struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data); u16 cs = spi->chip_select; int gpio = pinfo->gpios[cs]; diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c index 933eb9d9ddd..0759b5db988 100644 --- a/drivers/spi/spi-lm70llp.c +++ b/drivers/spi/spi-lm70llp.c @@ -219,9 +219,6 @@ static void spi_lm70llp_attach(struct parport *p) } pp = spi_master_get_devdata(master); - master->bus_num = -1; /* dynamic alloc of a bus number */ - master->num_chipselect = 1; - /* * SPI and bitbang hookup. */ diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index 57633d96345..cb3a3830b0a 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -433,7 +433,6 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op) goto err_alloc; } - master->bus_num = -1; master->setup = mpc52xx_spi_setup; master->transfer = mpc52xx_spi_transfer; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; @@ -479,8 +478,6 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op) gpio_direction_output(gpio_cs, 1); ms->gpio_cs[i] = gpio_cs; } - } else { - master->num_chipselect = 1; } spin_lock_init(&ms->lock); diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index bb9274c2526..46ef5fe51db 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -44,9 +44,7 @@ #include <plat/mcspi.h> #define OMAP2_MCSPI_MAX_FREQ 48000000 - -/* OMAP2 has 3 SPI controllers, while OMAP3 has 4 */ -#define OMAP2_MCSPI_MAX_CTRL 4 +#define SPI_AUTOSUSPEND_TIMEOUT 2000 #define OMAP2_MCSPI_REVISION 0x00 #define OMAP2_MCSPI_SYSSTATUS 0x14 @@ -111,19 +109,25 @@ struct omap2_mcspi_dma { #define DMA_MIN_BYTES 160 +/* + * Used for context save and restore, structure members to be updated whenever + * corresponding registers are modified. + */ +struct omap2_mcspi_regs { + u32 modulctrl; + u32 wakeupenable; + struct list_head cs; +}; + struct omap2_mcspi { - struct work_struct work; - /* lock protects queue and registers */ - spinlock_t lock; - struct list_head msg_queue; struct spi_master *master; /* Virtual base address of the controller */ void __iomem *base; unsigned long phys; /* SPI1 has 4 channels, while SPI2 has 2 */ struct omap2_mcspi_dma *dma_channels; - struct device *dev; - struct workqueue_struct *wq; + struct device *dev; + struct omap2_mcspi_regs ctx; }; struct omap2_mcspi_cs { @@ -135,17 +139,6 @@ struct omap2_mcspi_cs { u32 chconf0; }; -/* used for context save and restore, structure members to be updated whenever - * corresponding registers are modified. - */ -struct omap2_mcspi_regs { - u32 modulctrl; - u32 wakeupenable; - struct list_head cs; -}; - -static struct omap2_mcspi_regs omap2_mcspi_ctx[OMAP2_MCSPI_MAX_CTRL]; - #define MOD_REG_BIT(val, mask, set) do { \ if (set) \ val |= mask; \ @@ -236,9 +229,12 @@ static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active) static void omap2_mcspi_set_master_mode(struct spi_master *master) { + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + struct omap2_mcspi_regs *ctx = &mcspi->ctx; u32 l; - /* setup when switching from (reset default) slave mode + /* + * Setup when switching from (reset default) slave mode * to single-channel master mode */ l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL); @@ -247,29 +243,26 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master) MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1); mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l); - omap2_mcspi_ctx[master->bus_num - 1].modulctrl = l; + ctx->modulctrl = l; } static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) { - struct spi_master *spi_cntrl; - struct omap2_mcspi_cs *cs; - spi_cntrl = mcspi->master; + struct spi_master *spi_cntrl = mcspi->master; + struct omap2_mcspi_regs *ctx = &mcspi->ctx; + struct omap2_mcspi_cs *cs; /* McSPI: context restore */ - mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL, - omap2_mcspi_ctx[spi_cntrl->bus_num - 1].modulctrl); - - mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, - omap2_mcspi_ctx[spi_cntrl->bus_num - 1].wakeupenable); + mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); + mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable); - list_for_each_entry(cs, &omap2_mcspi_ctx[spi_cntrl->bus_num - 1].cs, - node) + list_for_each_entry(cs, &ctx->cs, node) __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); } static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi) { - pm_runtime_put_sync(mcspi->dev); + pm_runtime_mark_last_busy(mcspi->dev); + pm_runtime_put_autosuspend(mcspi->dev); } static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi) @@ -277,6 +270,23 @@ static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi) return pm_runtime_get_sync(mcspi->dev); } +static int omap2_prepare_transfer(struct spi_master *master) +{ + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + + pm_runtime_get_sync(mcspi->dev); + return 0; +} + +static int omap2_unprepare_transfer(struct spi_master *master) +{ + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + + pm_runtime_mark_last_busy(mcspi->dev); + pm_runtime_put_autosuspend(mcspi->dev); + return 0; +} + static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) { unsigned long timeout; @@ -777,7 +787,8 @@ static int omap2_mcspi_request_dma(struct spi_device *spi) static int omap2_mcspi_setup(struct spi_device *spi) { int ret; - struct omap2_mcspi *mcspi; + struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); + struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_cs *cs = spi->controller_state; @@ -787,11 +798,10 @@ static int omap2_mcspi_setup(struct spi_device *spi) return -EINVAL; } - mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = devm_kzalloc(&spi->dev , sizeof *cs, GFP_KERNEL); if (!cs) return -ENOMEM; cs->base = mcspi->base + spi->chip_select * 0x14; @@ -799,8 +809,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) cs->chconf0 = 0; spi->controller_state = cs; /* Link this to context save list */ - list_add_tail(&cs->node, - &omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs); + list_add_tail(&cs->node, &ctx->cs); } if (mcspi_dma->dma_rx_channel == -1 @@ -833,7 +842,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) cs = spi->controller_state; list_del(&cs->node); - kfree(spi->controller_state); } if (spi->chip_select < spi->master->num_chipselect) { @@ -850,144 +858,122 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) } } -static void omap2_mcspi_work(struct work_struct *work) +static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) { - struct omap2_mcspi *mcspi; - - mcspi = container_of(work, struct omap2_mcspi, work); - - if (omap2_mcspi_enable_clocks(mcspi) < 0) - return; - - spin_lock_irq(&mcspi->lock); /* We only enable one channel at a time -- the one whose message is - * at the head of the queue -- although this controller would gladly + * -- although this controller would gladly * arbitrate among multiple channels. This corresponds to "single * channel" master mode. As a side effect, we need to manage the * chipselect with the FORCE bit ... CS != channel enable. */ - while (!list_empty(&mcspi->msg_queue)) { - struct spi_message *m; - struct spi_device *spi; - struct spi_transfer *t = NULL; - int cs_active = 0; - struct omap2_mcspi_cs *cs; - struct omap2_mcspi_device_config *cd; - int par_override = 0; - int status = 0; - u32 chconf; - - m = container_of(mcspi->msg_queue.next, struct spi_message, - queue); - - list_del_init(&m->queue); - spin_unlock_irq(&mcspi->lock); - - spi = m->spi; - cs = spi->controller_state; - cd = spi->controller_data; - omap2_mcspi_set_enable(spi, 1); - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { - status = -EINVAL; - break; - } - if (par_override || t->speed_hz || t->bits_per_word) { - par_override = 1; - status = omap2_mcspi_setup_transfer(spi, t); - if (status < 0) - break; - if (!t->speed_hz && !t->bits_per_word) - par_override = 0; - } + struct spi_device *spi; + struct spi_transfer *t = NULL; + int cs_active = 0; + struct omap2_mcspi_cs *cs; + struct omap2_mcspi_device_config *cd; + int par_override = 0; + int status = 0; + u32 chconf; - if (!cs_active) { - omap2_mcspi_force_cs(spi, 1); - cs_active = 1; - } + spi = m->spi; + cs = spi->controller_state; + cd = spi->controller_data; - chconf = mcspi_cached_chconf0(spi); - chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; - chconf &= ~OMAP2_MCSPI_CHCONF_TURBO; + omap2_mcspi_set_enable(spi, 1); + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { + status = -EINVAL; + break; + } + if (par_override || t->speed_hz || t->bits_per_word) { + par_override = 1; + status = omap2_mcspi_setup_transfer(spi, t); + if (status < 0) + break; + if (!t->speed_hz && !t->bits_per_word) + par_override = 0; + } - if (t->tx_buf == NULL) - chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY; - else if (t->rx_buf == NULL) - chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY; - - if (cd && cd->turbo_mode && t->tx_buf == NULL) { - /* Turbo mode is for more than one word */ - if (t->len > ((cs->word_len + 7) >> 3)) - chconf |= OMAP2_MCSPI_CHCONF_TURBO; - } + if (!cs_active) { + omap2_mcspi_force_cs(spi, 1); + cs_active = 1; + } - mcspi_write_chconf0(spi, chconf); + chconf = mcspi_cached_chconf0(spi); + chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; + chconf &= ~OMAP2_MCSPI_CHCONF_TURBO; - if (t->len) { - unsigned count; + if (t->tx_buf == NULL) + chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY; + else if (t->rx_buf == NULL) + chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY; - /* RX_ONLY mode needs dummy data in TX reg */ - if (t->tx_buf == NULL) - __raw_writel(0, cs->base - + OMAP2_MCSPI_TX0); + if (cd && cd->turbo_mode && t->tx_buf == NULL) { + /* Turbo mode is for more than one word */ + if (t->len > ((cs->word_len + 7) >> 3)) + chconf |= OMAP2_MCSPI_CHCONF_TURBO; + } - if (m->is_dma_mapped || t->len >= DMA_MIN_BYTES) - count = omap2_mcspi_txrx_dma(spi, t); - else - count = omap2_mcspi_txrx_pio(spi, t); - m->actual_length += count; + mcspi_write_chconf0(spi, chconf); - if (count != t->len) { - status = -EIO; - break; - } - } + if (t->len) { + unsigned count; - if (t->delay_usecs) - udelay(t->delay_usecs); + /* RX_ONLY mode needs dummy data in TX reg */ + if (t->tx_buf == NULL) + __raw_writel(0, cs->base + + OMAP2_MCSPI_TX0); + + if (m->is_dma_mapped || t->len >= DMA_MIN_BYTES) + count = omap2_mcspi_txrx_dma(spi, t); + else + count = omap2_mcspi_txrx_pio(spi, t); + m->actual_length += co |