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 | |
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
-rw-r--r-- | drivers/of/Kconfig | 6 | ||||
-rw-r--r-- | drivers/of/Makefile | 1 | ||||
-rw-r--r-- | drivers/of/of_spi.c | 99 | ||||
-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 | ||||
-rw-r--r-- | include/linux/of_spi.h | 23 | ||||
-rw-r--r-- | include/linux/spi/rspi.h | 31 |
21 files changed, 736 insertions, 573 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 8e84ce9765a..f623f17a0b9 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -67,12 +67,6 @@ config OF_NET depends on NETDEVICES def_bool y -config OF_SPI - def_tristate SPI - depends on SPI && !SPARC - help - OpenFirmware SPI accessors - config OF_MDIO def_tristate PHYLIB depends on PHYLIB diff --git a/drivers/of/Makefile b/drivers/of/Makefile index aa90e602c8a..0040d185866 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o obj-$(CONFIG_OF_NET) += of_net.o -obj-$(CONFIG_OF_SPI) += of_spi.o obj-$(CONFIG_OF_SELFTEST) += selftest.o obj-$(CONFIG_OF_MDIO) += of_mdio.o obj-$(CONFIG_OF_PCI) += of_pci.o diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c deleted file mode 100644 index 6dbc074e487..00000000000 --- a/drivers/of/of_spi.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SPI OF support routines - * Copyright (C) 2008 Secret Lab Technologies Ltd. - * - * Support routines for deriving SPI device attachments from the device - * tree. - */ - -#include <linux/module.h> -#include <linux/of.h> -#include <linux/device.h> -#include <linux/spi/spi.h> -#include <linux/of_irq.h> -#include <linux/of_spi.h> - -/** - * of_register_spi_devices - Register child devices onto the SPI bus - * @master: Pointer to spi_master device - * - * Registers an spi_device for each child node of master node which has a 'reg' - * property. - */ -void of_register_spi_devices(struct spi_master *master) -{ - struct spi_device *spi; - struct device_node *nc; - const __be32 *prop; - int rc; - int len; - - if (!master->dev.of_node) - return; - - for_each_child_of_node(master->dev.of_node, nc) { - /* Alloc an spi_device */ - spi = spi_alloc_device(master); - if (!spi) { - dev_err(&master->dev, "spi_device alloc error for %s\n", - nc->full_name); - spi_dev_put(spi); - continue; - } - - /* Select device driver */ - if (of_modalias_node(nc, spi->modalias, - sizeof(spi->modalias)) < 0) { - dev_err(&master->dev, "cannot find modalias for %s\n", - nc->full_name); - spi_dev_put(spi); - continue; - } - - /* Device address */ - prop = of_get_property(nc, "reg", &len); - if (!prop || len < sizeof(*prop)) { - dev_err(&master->dev, "%s has no 'reg' property\n", - nc->full_name); - spi_dev_put(spi); - continue; - } - spi->chip_select = be32_to_cpup(prop); - - /* Mode (clock phase/polarity/etc.) */ - if (of_find_property(nc, "spi-cpha", NULL)) - spi->mode |= SPI_CPHA; - if (of_find_property(nc, "spi-cpol", NULL)) - spi->mode |= SPI_CPOL; - if (of_find_property(nc, "spi-cs-high", NULL)) - spi->mode |= SPI_CS_HIGH; - - /* Device speed */ - prop = of_get_property(nc, "spi-max-frequency", &len); - if (!prop || len < sizeof(*prop)) { - dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n", - nc->full_name); - spi_dev_put(spi); - continue; - } - spi->max_speed_hz = be32_to_cpup(prop); - - /* IRQ */ - spi->irq = irq_of_parse_and_map(nc, 0); - - /* Store a pointer to the node in the device structure */ - of_node_get(nc); - spi->dev.of_node = nc; - - /* Register the new device */ - request_module(spi->modalias); - rc = spi_add_device(spi); - if (rc) { - dev_err(&master->dev, "spi_device register error %s\n", - nc->full_name); - spi_dev_put(spi); - } - - } -} -EXPORT_SYMBOL(of_register_spi_devices); 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 += count; - /* ignore the "leave it on after last xfer" hint */ - if (t->cs_change) { - omap2_mcspi_force_cs(spi, 0); - cs_active = 0; + if (count != t->len) { + status = -EIO; + break; } } - /* Restore defaults if they were overriden */ - if (par_override) { - par_override = 0; - status = omap2_mcspi_setup_transfer(spi, NULL); - } + if (t->delay_usecs) + udelay(t->delay_usecs); - if (cs_active) + /* ignore the "leave it on after last xfer" hint */ + if (t->cs_change) { omap2_mcspi_force_cs(spi, 0); + cs_active = 0; + } + } + /* Restore defaults if they were overriden */ + if (par_override) { + par_override = 0; + status = omap2_mcspi_setup_transfer(spi, NULL); + } - omap2_mcspi_set_enable(spi, 0); - - m->status = status; - m->complete(m->context); + if (cs_active) + omap2_mcspi_force_cs(spi, 0); - spin_lock_irq(&mcspi->lock); - } + omap2_mcspi_set_enable(spi, 0); - spin_unlock_irq(&mcspi->lock); + m->status = status; - omap2_mcspi_disable_clocks(mcspi); } -static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) +static int omap2_mcspi_transfer_one_message(struct spi_master *master, + struct spi_message *m) { struct omap2_mcspi *mcspi; - unsigned long flags; struct spi_transfer *t; + mcspi = spi_master_get_devdata(master); m->actual_length = 0; m->status = 0; /* reject invalid messages and transfers */ - if (list_empty(&m->transfers) || !m->complete) + if (list_empty(&m->transfers)) return -EINVAL; list_for_each_entry(t, &m->transfers, transfer_list) { const void *tx_buf = t->tx_buf; @@ -999,7 +985,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) || (t->bits_per_word && ( t->bits_per_word < 4 || t->bits_per_word > 32))) { - dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", + dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", t->speed_hz, len, tx_buf ? "tx" : "", @@ -1008,7 +994,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) return -EINVAL; } if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) { - dev_dbg(&spi->dev, "speed_hz %d below minimum %d Hz\n", + dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n", t->speed_hz, OMAP2_MCSPI_MAX_FREQ >> 15); return -EINVAL; @@ -1018,51 +1004,46 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) continue; if (tx_buf != NULL) { - t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf, + t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf, len, DMA_TO_DEVICE); - if (dma_mapping_error(&spi->dev, t->tx_dma)) { - dev_dbg(&spi->dev, "dma %cX %d bytes error\n", + if (dma_mapping_error(mcspi->dev, t->tx_dma)) { + dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", 'T', len); return -EINVAL; } } if (rx_buf != NULL) { - t->rx_dma = dma_map_single(&spi->dev, rx_buf, t->len, + t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len, DMA_FROM_DEVICE); - if (dma_mapping_error(&spi->dev, t->rx_dma)) { - dev_dbg(&spi->dev, "dma %cX %d bytes error\n", + if (dma_mapping_error(mcspi->dev, t->rx_dma)) { + dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", 'R', len); if (tx_buf != NULL) - dma_unmap_single(&spi->dev, t->tx_dma, + dma_unmap_single(mcspi->dev, t->tx_dma, len, DMA_TO_DEVICE); return -EINVAL; } } } - mcspi = spi_master_get_devdata(spi->master); - - spin_lock_irqsave(&mcspi->lock, flags); - list_add_tail(&m->queue, &mcspi->msg_queue); - queue_work(mcspi->wq, &mcspi->work); - spin_unlock_irqrestore(&mcspi->lock, flags); - + omap2_mcspi_work(mcspi, m); + spi_finalize_current_message(master); return 0; } static int __init omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) { struct spi_master *master = mcspi->master; - u32 tmp; - int ret = 0; + struct omap2_mcspi_regs *ctx = &mcspi->ctx; + int ret = 0; ret = omap2_mcspi_enable_clocks(mcspi); if (ret < 0) return ret; - tmp = OMAP2_MCSPI_WAKEUPENABLE_WKEN; - mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, tmp); - omap2_mcspi_ctx[master->bus_num - 1].wakeupenable = tmp; + mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, + OMAP2_MCSPI_WAKEUPENABLE_WKEN); + ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN; omap2_mcspi_set_master_mode(master); omap2_mcspi_disable_clocks(mcspi); @@ -1102,14 +1083,13 @@ static const struct of_device_id omap_mcspi_of_match[] = { }; MODULE_DEVICE_TABLE(of, omap_mcspi_of_match); -static int __init omap2_mcspi_probe(struct platform_device *pdev) +static int __devinit omap2_mcspi_probe(struct platform_device *pdev) { struct spi_master *master; struct omap2_mcspi_platform_config *pdata; struct omap2_mcspi *mcspi; struct resource *r; int status = 0, i; - char wq_name[20]; u32 regs_offset = 0; static int bus_num = 1; struct device_node *node = pdev->dev.of_node; @@ -1125,7 +1105,9 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->setup = omap2_mcspi_setup; - master->transfer = omap2_mcspi_transfer; + master->prepare_transfer_hardware = omap2_prepare_transfer; + master->unprepare_transfer_hardware = omap2_unprepare_transfer; + master->transfer_one_message = omap2_mcspi_transfer_one_message; master->cleanup = omap2_mcspi_cleanup; master->dev.of_node = node; @@ -1150,13 +1132,6 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) mcspi = spi_master_get_devdata(master); mcspi->master = master; - sprintf(wq_name, "omap2_mcspi/%d", master->bus_num); - mcspi->wq = alloc_workqueue(wq_name, WQ_MEM_RECLAIM, 1); - if (mcspi->wq == NULL) { - status = -ENOMEM; - goto free_master; - } - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { status = -ENODEV; @@ -1166,32 +1141,24 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) r->start += regs_offset; r->end += regs_offset; mcspi->phys = r->start; - if (!request_mem_region(r->start, resource_size(r), - dev_name(&pdev->dev))) { - status = -EBUSY; - goto free_master; - } - mcspi->base = ioremap(r->start, resource_size(r)); + mcspi->base = devm_request_and_ioremap(&pdev->dev, r); if (!mcspi->base) { dev_dbg(&pdev->dev, "can't ioremap MCSPI\n"); status = -ENOMEM; - goto release_region; + goto free_master; } mcspi->dev = &pdev->dev; - INIT_WORK(&mcspi->work, omap2_mcspi_work); - spin_lock_init(&mcspi->lock); - INIT_LIST_HEAD(&mcspi->msg_queue); - INIT_LIST_HEAD(&omap2_mcspi_ctx[master->bus_num - 1].cs); + INIT_LIST_HEAD(&mcspi->ctx.cs); mcspi->dma_channels = kcalloc(master->num_chipselect, sizeof(struct omap2_mcspi_dma), GFP_KERNEL); if (mcspi->dma_channels == NULL) - goto unmap_io; + goto free_master; for (i = 0; i < master->num_chipselect; i++) { char dma_ch_name[14]; @@ -1224,6 +1191,8 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) if (status < 0) goto dma_chnl_free; + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_enable(&pdev->dev); if (status || omap2_mcspi_master_setup(mcspi) < 0) @@ -1241,23 +1210,17 @@ disable_pm: pm_runtime_disable(&pdev->dev); dma_chnl_free: kfree(mcspi->dma_channels); -unmap_io: - iounmap(mcspi->base); -release_region: - release_mem_region(r->start, resource_size(r)); free_master: kfree(master); platform_set_drvdata(pdev, NULL); return status; } -static int __exit omap2_mcspi_remove(struct platform_device *pdev) +static int __devexit omap2_mcspi_remove(struct platform_device *pdev) { struct spi_master *master; struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *dma_channels; - struct resource *r; - void __iomem *base; master = dev_get_drvdata(&pdev->dev); mcspi = spi_master_get_devdata(master); @@ -1265,14 +1228,9 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev) omap2_mcspi_disable_clocks(mcspi); pm_runtime_disable(&pdev->dev); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); - base = mcspi->base; spi_unregister_master(master); - iounmap(base); kfree(dma_channels); - destroy_workqueue(mcspi->wq); platform_set_drvdata(pdev, NULL); return 0; @@ -1291,13 +1249,12 @@ static int omap2_mcspi_resume(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct omap2_mcspi *mcspi = spi_master_get_devdata(master); - struct omap2_mcspi_cs *cs; + struct omap2_mcspi_regs *ctx = &mcspi->ctx; + struct omap2_mcspi_cs *cs; omap2_mcspi_enable_clocks(mcspi); - list_for_each_entry(cs, &omap2_mcspi_ctx[master->bus_num - 1].cs, - node) { + list_for_each_entry(cs, &ctx->cs, node) { if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { - /* * We need to toggle CS state for OMAP take this * change in account. @@ -1327,21 +1284,9 @@ static struct platform_driver omap2_mcspi_driver = { .pm = &omap2_mcspi_pm_ops, .of_match_table = omap_mcspi_of_match, }, - .remove = __exit_p(omap2_mcspi_remove), + .probe = omap2_mcspi_probe, + .remove = __devexit_p(omap2_mcspi_remove), }; - -static int __init omap2_mcspi_init(void) -{ - return platform_driver_probe(&omap2_mcspi_driver, omap2_mcspi_probe); -} -subsys_initcall(omap2_mcspi_init); - -static void __exit omap2_mcspi_exit(void) -{ - platform_driver_unregister(&omap2_mcspi_driver); - -} -module_exit(omap2_mcspi_exit); - +module_platform_driver(omap2_mcspi_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 98ec53285fc..75ac9d48ef4 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -30,7 +30,6 @@ #include <linux/errno.h> #include <linux/wait.h> #include <linux/of_platform.h> -#include <linux/of_spi.h> #include <linux/of_gpio.h> #include <linux/interrupt.h> #include <linux/delay.h> @@ -467,9 +466,6 @@ static int __init spi_ppc4xx_of_probe(struct platform_device *op) bbp->master->setup = spi_ppc4xx_setup; bbp->master->cleanup = spi_ppc4xx_cleanup; - /* Allocate bus num dynamically. */ - bbp->master->bus_num = -1; - /* the spi->mode bits understood by this driver: */ bbp->master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST; diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 3fb44afe27b..9f6ba34b172 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -164,17 +164,7 @@ static struct pci_driver ce4100_spi_driver = { .remove = __devexit_p(ce4100_spi_remove), }; -static int __init ce4100_spi_init(void) -{ - return pci_register_driver(&ce4100_spi_driver); -} -module_init(ce4100_spi_init); - -static void __exit ce4100_spi_exit(void) -{ - pci_unregister_driver(&ce4100_spi_driver); -} -module_exit(ce4100_spi_exit); +module_pci_driver(ce4100_spi_driver); MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 354f170eab9..4894bde4bbf 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -31,7 +31,11 @@ #include <linux/platform_device.h> #include <linux/io.h> #include <linux/clk.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/sh_dma.h> #include <linux/spi/spi.h> +#include <linux/spi/rspi.h> #define RSPI_SPCR 0x00 #define RSPI_SSLP 0x01 @@ -141,6 +145,16 @@ struct rspi_data { spinlock_t lock; struct clk *clk; unsigned char spsr; + + /* for dmaengine */ + struct sh_dmae_slave dma_tx; + struct sh_dmae_slave dma_rx; + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + int irq; + + unsigned dma_width_16bit:1; + unsigned dma_callbacked:1; }; static void rspi_write8(struct rspi_data *rspi, u8 data, u16 offset) @@ -265,11 +279,125 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, return 0; } -static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t) +static void rspi_dma_complete(void *arg) +{ + struct rspi_data *rspi = arg; + + rspi->dma_callbacked = 1; + wake_up_interruptible(&rspi->wait); +} + +static int rspi_dma_map_sg(struct scatterlist *sg, void *buf, unsigned len, + struct dma_chan *chan, + enum dma_transfer_direction dir) +{ + sg_init_table(sg, 1); + sg_set_buf(sg, buf, len); + sg_dma_len(sg) = len; + return dma_map_sg(chan->device->dev, sg, 1, dir); +} + +static void rspi_dma_unmap_sg(struct scatterlist *sg, struct dma_chan *chan, + enum dma_transfer_direction dir) +{ + dma_unmap_sg(chan->device->dev, sg, 1, dir); +} + +static void rspi_memory_to_8bit(void *buf, const void *data, unsigned len) +{ + u16 *dst = buf; + const u8 *src = data; + + while (len) { + *dst++ = (u16)(*src++); + len--; + } +} + +static void rspi_memory_from_8bit(void *buf, const void *data, unsigned len) +{ + u8 *dst = buf; + const u16 *src = data; + + while (len) { + *dst++ = (u8)*src++; + len--; + } +} + +static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) +{ + struct scatterlist sg; + void *buf = NULL; + struct dma_async_tx_descriptor *desc; + unsigned len; + int ret = 0; + + if (rspi->dma_width_16bit) { + /* + * If DMAC bus width is 16-bit, the driver allocates a dummy + * buffer. And, the driver converts original data into the + * DMAC data as the following format: + * original data: 1st byte, 2nd byte ... + * DMAC data: 1st byte, dummy, 2nd byte, dummy ... + */ + len = t->len * 2; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + rspi_memory_to_8bit(buf, t->tx_buf, t->len); + } else { + len = t->len; + buf = (void *)t->tx_buf; + } + + if (!rspi_dma_map_sg(&sg, buf, len, rspi->chan_tx, DMA_TO_DEVICE)) { + ret = -EFAULT; + goto end_nomap; + } + desc = dmaengine_prep_slave_sg(rspi->chan_tx, &sg, 1, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + ret = -EIO; + goto end; + } + + /* + * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be + * called. So, this driver disables the IRQ while DMA transfer. + */ + disable_irq(rspi->irq); + + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR); + rspi_enable_irq(rspi, SPCR_SPTIE); + rspi->dma_callbacked = 0; + + desc->callback = rspi_dma_complete; + desc->callback_param = rspi; + dmaengine_submit(desc); + dma_async_issue_pending(rspi->chan_tx); + + ret = wait_event_interruptible_timeout(rspi->wait, + rspi->dma_callbacked, HZ); + if (ret > 0 && rspi->dma_callbacked) + ret = 0; + else if (!ret) + ret = -ETIMEDOUT; + rspi_disable_irq(rspi, SPCR_SPTIE); + + enable_irq(rspi->irq); + +end: + rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE); +end_nomap: + if (rspi->dma_width_16bit) + kfree(buf); + + return ret; +} + +static void rspi_receive_init(struct rspi_data *rspi) { - int remain = t->len; - u8 *data; unsigned char spsr; spsr = rspi_read8(rspi, RSPI_SPSR); @@ -278,6 +406,15 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, if (spsr & SPSR_OVRF) rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF, RSPI_SPCR); +} + +static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, + struct spi_transfer *t) +{ + int remain = t->len; + u8 *data; + + rspi_receive_init(rspi); data = (u8 *)t->rx_buf; while (remain > 0) { @@ -307,6 +444,120 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, return 0; } +static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) +{ + struct scatterlist sg, sg_dummy; + void *dummy = NULL, *rx_buf = NULL; + struct dma_async_tx_descriptor *desc, *desc_dummy; + unsigned len; + int ret = 0; + + if (rspi->dma_width_16bit) { + /* + * If DMAC bus width is 16-bit, the driver allocates a dummy + * buffer. And, finally the driver converts the DMAC data into + * actual data as the following format: + * DMAC data: 1st byte, dummy, 2nd byte, dummy ... + * actual data: 1st byte, 2nd byte ... + */ + len = t->len * 2; + rx_buf = kmalloc(len, GFP_KERNEL); + if (!rx_buf) + return -ENOMEM; + } else { + len = t->len; + rx_buf = t->rx_buf; + } + + /* prepare dummy transfer to generate SPI clocks */ + dummy = kzalloc(len, GFP_KERNEL); + if (!dummy) { + ret = -ENOMEM; + goto end_nomap; + } + if (!rspi_dma_map_sg(&sg_dummy, dummy, len, rspi->chan_tx, + DMA_TO_DEVICE)) { + ret = -EFAULT; + goto end_nomap; + } + desc_dummy = dmaengine_prep_slave_sg(rspi->chan_tx, &sg_dummy, 1, + DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_dummy) { + ret = -EIO; + goto end_dummy_mapped; + } + + /* prepare receive transfer */ + if (!rspi_dma_map_sg(&sg, rx_buf, len, rspi->chan_rx, + DMA_FROM_DEVICE)) { + ret = -EFAULT; + goto end_dummy_mapped; + + } + desc = dmaengine_prep_slave_sg(rspi->chan_rx, &sg, 1, DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + ret = -EIO; + goto end; + } + + rspi_receive_init(rspi); + + /* + * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be + * called. So, this driver disables the IRQ while DMA transfer. + */ + disable_irq(rspi->irq); + + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR); + rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); + rspi->dma_callbacked = 0; + + desc->callback = rspi_dma_complete; + desc->callback_param = rspi; + dmaengine_submit(desc); + dma_async_issue_pending(rspi->chan_rx); + + desc_dummy->callback = NULL; /* No callback */ + dmaengine_submit(desc_dummy); + dma_async_issue_pending(rspi->chan_tx); + + ret = wait_event_interruptible_timeout(rspi->wait, + rspi->dma_callbacked, HZ); + if (ret > 0 && rspi->dma_callbacked) + ret = 0; + else if (!ret) + ret = -ETIMEDOUT; + rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); + + enable_irq(rspi->irq); + +end: + rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE); +end_dummy_mapped: + rspi_dma_unmap_sg(&sg_dummy, rspi->chan_tx, DMA_TO_DEVICE); +end_nomap: + if (rspi->dma_width_16bit) { + if (!ret) + rspi_memory_from_8bit(t->rx_buf, rx_buf, t->len); + kfree(rx_buf); + } + kfree(dummy); + + return ret; +} + +static int rspi_is_dma(struct rspi_data *rspi, struct spi_transfer *t) +{ + if (t->tx_buf && rspi->chan_tx) + return 1; + /* If the module receives data by DMAC, it also needs TX DMAC */ + if (t->rx_buf && rspi->chan_tx && rspi->chan_rx) + return 1; + + return 0; +} + static void rspi_work(struct work_struct *work) { struct rspi_data *rspi = container_of(work, struct rspi_data, ws); @@ -325,12 +576,18 @@ static void rspi_work(struct work_struct *work) list_for_each_entry(t, &mesg->transfers, transfer_list) { if (t->tx_buf) { - ret = rspi_send_pio(rspi, mesg, t); + if (rspi_is_dma(rspi, t)) + ret = rspi_send_dma(rspi, t); + else + ret = rspi_send_pio(rspi, mesg, t); if (ret < 0) goto error; } if (t->rx_buf) { - ret = rspi_receive_pio(rspi, mesg, t); + if (rspi_is_dma(rspi, t)) + ret = rspi_receive_dma(rspi, t); + else + ret = rspi_receive_pio(rspi, mesg, t); if (ret < 0) goto error; } @@ -406,11 +663,58 @@ static irqreturn_t rspi_irq(int irq, void *_sr) return ret; } +static bool rspi_filter(struct dma_chan *chan, void *filter_param) +{ + chan->private = filter_param; + return true; +} + +static void __devinit rspi_request_dma(struct rspi_data *rspi, + struct platform_device *pdev) +{ + struct rspi_plat_data *rspi_pd = pdev->dev.platform_data; + dma_cap_mask_t mask; + + if (!rspi_pd) + return; + + rspi->dma_width_16bit = rspi_pd->dma_width_16bit; + + /* If the module receives data by DMAC, it also needs TX DMAC */ + if (rspi_pd->dma_rx_id && rspi_pd->dma_tx_id) { + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + rspi->dma_rx.slave_id = rspi_pd->dma_rx_id; + rspi->chan_rx = dma_request_channel(mask, rspi_filter, + &rspi->dma_rx); + if (rspi->chan_rx) + dev_info(&pdev->dev, "Use DMA when rx.\n"); + } + if (rspi_pd->dma_tx_id) { + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + rspi->dma_tx.slave_id = rspi_pd->dma_tx_id; + rspi->chan_tx = dma_request_channel(mask, rspi_filter, + &rspi->dma_tx); + if (rspi->chan_tx) + dev_info(&pdev->dev, "Use DMA when tx\n"); + } +} + +static void __devexit rspi_release_dma(struct rspi_data *rspi) +{ + if (rspi->chan_tx) + dma_release_channel(rspi->chan_tx); + if (rspi->chan_rx) + dma_release_channel(rspi->chan_rx); +} + static int __devexit rspi_remove(struct platform_device *pdev) { struct rspi_data *rspi = dev_get_drvdata(&pdev->dev); spi_unregister_master(rspi->master); + rspi_release_dma(rspi); free_irq(platform_get_irq(pdev, 0), rspi); clk_put(rspi->clk); iounmap(rspi->addr); @@ -483,6 +787,9 @@ static int __devinit rspi_probe(struct platform_device *pdev) goto error3; } + rspi->irq = irq; + rspi_request_dma(rspi, pdev); + ret = spi_register_master(master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); @@ -494,6 +801,7 @@ static int __devinit rspi_probe(struct platform_device *pdev) return 0; error4: + rspi_release_dma(rspi); free_irq(irq, rspi); error3: clk_put(rspi->clk); diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 52fe495bb32..ecc3d9763d1 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -19,7 +19,7 @@ #include <linux/of_gpio.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> -#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/consumer.h> #define DRIVER_NAME "sirfsoc_spi" @@ -127,7 +127,7 @@ struct sirfsoc_spi { void __iomem *base; u32 ctrl_freq; /* SPI controller clock speed */ struct clk *clk; - struct pinmux *pmx; + struct pinctrl *p; /* rx & tx bufs from the spi_transfer */ const void *tx; @@ -560,17 +560,15 @@ static int __devinit spi_sirfsoc_probe(struct platform_device *pdev) master->bus_num = pdev->id; sspi->bitbang.master->dev.of_node = pdev->dev.of_node; - sspi->pmx = pinmux_get(&pdev->dev, NULL); - ret = IS_ERR(sspi->pmx); + sspi->p = pinctrl_get_select_default(&pdev->dev); + ret = IS_ERR(sspi->p); if (ret) goto free_master; - pinmux_enable(sspi->pmx); - sspi->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(sspi->clk)) { ret = -EINVAL; - goto free_pmx; + goto free_pin; } clk_enable(sspi->clk); sspi->ctrl_freq = clk_get_rate(sspi->clk); @@ -598,9 +596,8 @@ static int __devinit spi_sirfsoc_probe(struct platform_device *pdev) free_clk: clk_disable(sspi->clk); clk_put(sspi->clk); -free_pmx: - pinmux_disable(sspi->pmx); - pinmux_put(sspi->pmx); +free_pin: + pinctrl_put(sspi->p); free_master: spi_master_put(master); err_cs: @@ -623,8 +620,7 @@ static int __devexit spi_sirfsoc_remove(struct platform_device *pdev) } clk_disable(sspi->clk); clk_put(sspi->clk); - pinmux_disable(sspi->pmx); - pinmux_put(sspi->pmx); + pinctrl_put(sspi->p); spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index ec47d3bdfd1..cd56dcf4632 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1438,7 +1438,6 @@ static int __devinit pch_spi_pd_probe(struct platform_device *plat_dev) plat_dev->id, data->io_remap_addr); /* initialize members of SPI master */ - master->bus_num = -1; master->num_chipselect = PCH_MAX_CS; master->setup = pch_spi_setup; master->transfer = pch_spi_transfer; @@ -1779,7 +1778,7 @@ static struct pci_driver pch_spi_pcidev_driver = { .name = "pch_spi", .id_table = pch_spi_pcidev_id, .probe = pch_spi_probe, - .remove = pch_spi_remove, + .remove = __devexit_p(pch_spi_remove), .suspend = pch_spi_suspend, .resume = pch_spi_resume, }; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 3d8f662e4fe..1041cb83d67 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2,6 +2,7 @@ * SPI init/core code * * Copyright (C) 2005 David Brownell + * Copyright (C) 2008 Secret Lab Technologies Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,15 +20,16 @@ */ #include <linux/kernel.h> +#include <linux/kmod.h> #include <linux/device.h> #include <linux/init.h> #include <linux/cache.h> #include <linux/mutex.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/slab.h> #include <linux/mod_devicetable.h> #include <linux/spi/spi.h> -#include <linux/of_spi.h> #include <linux/pm_runtime.h> #include <linux/export.h> #include <linux/sched.h> @@ -530,7 +532,7 @@ static void spi_pump_messages(struct kthread_work *work) /* Lock queue and check for queue work */ spin_lock_irqsave(&master->queue_lock, flags); if (list_empty(&master->queue) || !master->running) { - if (master->busy) { + if (master->busy && master->unprepare_transfer_hardware) { ret = master->unprepare_transfer_hardware(master); if (ret) { spin_unlock_irqrestore(&master->queue_lock, flags); @@ -560,7 +562,7 @@ static void spi_pump_messages(struct kthread_work *work) master->busy = true; spin_unlock_irqrestore(&master->queue_lock, flags); - if (!was_busy) { + if (!was_busy && master->prepare_transfer_hardware) { ret = master->prepare_transfer_hardware(master); if (ret) { dev_err(&master->dev, @@ -798,6 +800,94 @@ err_init_queue: /*-------------------------------------------------------------------------*/ +#if defined(CONFIG_OF) && !defined(CONFIG_SPARC) +/** + * of_register_spi_devices() - Register child devices onto the SPI bus + * @master: Pointer to spi_master device + * + * Registers an spi_device for each child node of master node which has a 'reg' + * property. + */ +static void of_register_spi_devices(struct spi_master *master) +{ + struct spi_device *spi; + struct device_node *nc; + const __be32 *prop; + int rc; + int len; + + if (!master->dev.of_node) + return; + + for_each_child_of_node(master->dev.of_node, nc) { + /* Alloc an spi_device */ + spi = spi_alloc_device(master); + if (!spi) { + dev_err(&master->dev, "spi_device alloc error for %s\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + + /* Select device driver */ + if (of_modalias_node(nc, spi->modalias, + sizeof(spi->modalias)) < 0) { + dev_err(&master->dev, "cannot find modalias for %s\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + + /* Device address */ + prop = of_get_property(nc, "reg", &len); + if (!prop || len < sizeof(*prop)) { + dev_err(&master->dev, "%s has no 'reg' property\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + spi->chip_select = be32_to_cpup(prop); + + /* Mode (clock phase/polarity/etc.) */ + if (of_find_property(nc, "spi-cpha", NULL)) + spi->mode |= SPI_CPHA; + if (of_find_property(nc, "spi-cpol", NULL)) + spi->mode |= SPI_CPOL; + if (of_find_property(nc, "spi-cs-high", NULL)) + spi->mode |= SPI_CS_HIGH; + + /* Device speed */ + prop = of_get_property(nc, "spi-max-frequency", &len); + if (!prop || len < sizeof(*prop)) { + dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + spi->max_speed_hz = be32_to_cpup(prop); + + /* IRQ */ + spi->irq = irq_of_parse_and_map(nc, 0); + + /* Store a pointer to the node in the device structure */ + of_node_get(nc); + spi->dev.of_node = nc; + + /* Register the new device */ + request_module(spi->modalias); + rc = spi_add_device(spi); + if (rc) { + dev_err(&master->dev, "spi_device register error %s\n", + nc->full_name); + spi_dev_put(spi); + } + + } +} +#else +static void of_register_spi_devices(struct spi_master *master) { } +#endif + static void spi_master_release(struct device *dev) { struct spi_master *master; @@ -846,6 +936,8 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) return NULL; device_initialize(&master->dev); + master->bus_num = -1; + master->num_chipselect = 1; master->dev.class = &spi_master_class; master->dev.parent = get_device(dev); spi_master_set_devdata(master, &master[1]); diff --git a/include/linux/of_spi.h b/include/linux/of_spi.h deleted file mode 100644 index 9e3e70f78ae..00000000000 --- a/include/linux/of_spi.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * OpenFirmware SPI support routines - * Copyright (C) 2008 Secret Lab Technologies Ltd. - * - * Support routines for deriving SPI device attachments from the device - * tree. - */ - -#ifndef __LINUX_OF_SPI_H -#define __LINUX_OF_SPI_H - -#include <linux/spi/spi.h> - -#if defined(CONFIG_OF_SPI) || defined(CONFIG_OF_SPI_MODULE) -extern void of_register_spi_devices(struct spi_master *master); -#else -static inline void of_register_spi_devices(struct spi_master *master) -{ - return; -} -#endif /* CONFIG_OF_SPI */ - -#endif /* __LINUX_OF_SPI */ diff --git a/include/linux/spi/rspi.h b/include/linux/spi/rspi.h new file mode 100644 index 00000000000..900f0e32823 --- /dev/null +++ b/include/linux/spi/rspi.h @@ -0,0 +1,31 @@ +/* + * Renesas SPI driver + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __LINUX_SPI_RENESAS_SPI_H__ +#define __LINUX_SPI_RENESAS_SPI_H__ + +struct rspi_plat_data { + unsigned int dma_tx_id; + unsigned int dma_rx_id; + + unsigned dma_width_16bit:1; /* DMAC read/write width = 16-bit */ +}; + +#endif |