From 7d6b6d83139d0eab087645edc8c3f6b4b3cef34d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 14 Mar 2012 11:18:30 +0200 Subject: spi: omap2-mcspi: make it behave as a module move probe away from __init section and use platform_driver_register() instead of platform_driver_probe(). Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/spi/spi-omap2-mcspi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/spi/spi-omap2-mcspi.c') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 0b0dfb71c640..5f4419e8786f 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1080,7 +1080,7 @@ static int omap_mcspi_runtime_resume(struct device *dev) } -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 = pdev->dev.platform_data; @@ -1212,7 +1212,7 @@ free_master: 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; @@ -1287,13 +1287,14 @@ static struct platform_driver omap2_mcspi_driver = { .owner = THIS_MODULE, .pm = &omap2_mcspi_pm_ops }, - .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); + return platform_driver_register(&omap2_mcspi_driver); } subsys_initcall(omap2_mcspi_init); -- cgit v1.2.2 From 9fdca9dfe093c76fe1ac1a09888ba9679d46996a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 14 Mar 2012 11:18:31 +0200 Subject: spi: omap2-mcspi: convert to module_platform_driver this will delete a few lines of code, no functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/spi/spi-omap2-mcspi.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/spi/spi-omap2-mcspi.c') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 5f4419e8786f..7745f91f105d 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1291,18 +1291,5 @@ static struct platform_driver omap2_mcspi_driver = { .remove = __devexit_p(omap2_mcspi_remove), }; - -static int __init omap2_mcspi_init(void) -{ - return platform_driver_register(&omap2_mcspi_driver); -} -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"); -- cgit v1.2.2 From 1a77b127ae147f5827043a9896d7f4cb248b402e Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Sat, 17 Mar 2012 12:44:01 +0530 Subject: OMAP : SPI : use devm_* functions The various devm_* functions allocate memory that is released when a driver detaches. This patch uses devm_request_and_ioremap to request memory in probe function. Since the freeing is not needed the calls are deleted from remove function.Also use use devm_kzalloc for the cs memory allocation. Signed-off-by: Shubhrajyoti D --- drivers/spi/spi-omap2-mcspi.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) (limited to 'drivers/spi/spi-omap2-mcspi.c') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 7745f91f105d..cb2c0e390b1f 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -789,7 +789,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) 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; @@ -831,7 +831,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) { @@ -1127,17 +1126,12 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) r->start += pdata->regs_offset; r->end += pdata->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; @@ -1152,7 +1146,7 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) 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]; @@ -1202,10 +1196,6 @@ 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); @@ -1217,8 +1207,6 @@ 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); @@ -1226,12 +1214,8 @@ static int __devexit 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); -- cgit v1.2.2 From 1bd897f84964c2ce3a28d11f7eb7c4e0a8d3ca3c Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Mon, 26 Mar 2012 15:32:33 +0530 Subject: spi/omap: Remove bus_num usage for instance index bus_num was used to reference the mcspi controller instance in a fixed array. Remove this array and store this information directly inside drvdata structure. bus_num is now just set if the pdev->id is present or with -1 for dynamic allocation by SPI core, but the driver does not access it anymore. Clean some bad comments format, and remove un-needed space. Signed-off-by: Benoit Cousson [Cleanup the OMAP2_MCSPI_MAX_CTRL macro as it is not needed anymore] Signed-off-by: Shubhrajyoti D --- drivers/spi/spi-omap2-mcspi.c | 75 ++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 41 deletions(-) (limited to 'drivers/spi/spi-omap2-mcspi.c') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 33f54cd07fe0..1907ed2e2958 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -45,9 +45,6 @@ #define OMAP2_MCSPI_MAX_FREQ 48000000 -/* OMAP2 has 3 SPI controllers, while OMAP3 has 4 */ -#define OMAP2_MCSPI_MAX_CTRL 4 - #define OMAP2_MCSPI_REVISION 0x00 #define OMAP2_MCSPI_SYSSTATUS 0x14 #define OMAP2_MCSPI_IRQSTATUS 0x18 @@ -111,6 +108,16 @@ 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 */ @@ -122,8 +129,9 @@ struct omap2_mcspi { unsigned long phys; /* SPI1 has 4 channels, while SPI2 has 2 */ struct omap2_mcspi_dma *dma_channels; - struct device *dev; + struct device *dev; struct workqueue_struct *wq; + struct omap2_mcspi_regs ctx; }; struct omap2_mcspi_cs { @@ -135,17 +143,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 +233,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,24 +247,20 @@ 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_MODULCTRL, ctx->modulctrl); + mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable); - mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, - omap2_mcspi_ctx[spi_cntrl->bus_num - 1].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) @@ -777,7 +773,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,7 +784,6 @@ 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) { @@ -799,8 +795,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 @@ -1052,8 +1047,9 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) static int __init omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) { struct spi_master *master = mcspi->master; + struct omap2_mcspi_regs *ctx = &mcspi->ctx; u32 tmp; - int ret = 0; + int ret = 0; ret = omap2_mcspi_enable_clocks(mcspi); if (ret < 0) @@ -1061,7 +1057,7 @@ static int __init omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) tmp = OMAP2_MCSPI_WAKEUPENABLE_WKEN; mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, tmp); - omap2_mcspi_ctx[master->bus_num - 1].wakeupenable = tmp; + ctx->wakeupenable = tmp; omap2_mcspi_set_master_mode(master); omap2_mcspi_disable_clocks(mcspi); @@ -1108,7 +1104,6 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) 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; @@ -1149,8 +1144,7 @@ static int __devinit 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); + mcspi->wq = alloc_workqueue(dev_name(&pdev->dev), WQ_MEM_RECLAIM, 1); if (mcspi->wq == NULL) { status = -ENOMEM; goto free_master; @@ -1178,7 +1172,7 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) 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), @@ -1275,13 +1269,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. -- cgit v1.2.2 From 27b5284cfbe187732ebb184b03ea693f44837f9d Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 26 Mar 2012 17:04:22 +0530 Subject: spi: omap2-mcspi: add support for pm_runtime autosuspend Adds support for configuring the omap2-mcspi driver use autosuspend for runtime power management. This can reduce the latency in starting an spi transfer by not suspending the device immediately following completion of a transfer. If another transfer then takes place before the autosuspend timeout (2 secs), the call to resume the device can return immediately saving some save/ restore cycles. Acked-by: Govindraj.R Signed-off-by: Shubhrajyoti D --- drivers/spi/spi-omap2-mcspi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/spi/spi-omap2-mcspi.c') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 1907ed2e2958..0b0da2f7ce23 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -44,6 +44,7 @@ #include #define OMAP2_MCSPI_MAX_FREQ 48000000 +#define SPI_AUTOSUSPEND_TIMEOUT 2000 #define OMAP2_MCSPI_REVISION 0x00 #define OMAP2_MCSPI_SYSSTATUS 0x14 @@ -265,7 +266,8 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) } 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) @@ -1212,6 +1214,8 @@ static int __devinit 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) -- cgit v1.2.2 From 39f8052d2e0c35533e776ef1235e4cc32cc35d02 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Thu, 29 Mar 2012 22:11:07 +0530 Subject: spi/omap2-mcspi: Trivial optimisation Trivial optimisation of tmp variable by directly writing the value to the register. Cc: Tarun Kanti DebBarma Signed-off-by: Shubhrajyoti D --- drivers/spi/spi-omap2-mcspi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/spi/spi-omap2-mcspi.c') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 0b0da2f7ce23..f374eeebb8c2 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1050,16 +1050,15 @@ static int __init omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) { struct spi_master *master = mcspi->master; struct omap2_mcspi_regs *ctx = &mcspi->ctx; - u32 tmp; 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); - ctx->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); -- cgit v1.2.2 From 5fda88f5e17ea0e767360a3f09eac80f83296ea9 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Thu, 10 May 2012 18:27:45 +0530 Subject: spi/omap2-mcspi: convert to the pump message infrastructure This patch converts the OMAP SPI driver to use the SPI infrastructure pump message queue.Also fixes the below warning. master is unqueued, this is deprecated Signed-off-by: Shubhrajyoti D Acked-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/spi/spi-omap2-mcspi.c | 243 +++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 133 deletions(-) (limited to 'drivers/spi/spi-omap2-mcspi.c') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index f374eeebb8c2..46ef5fe51db5 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -120,10 +120,6 @@ struct omap2_mcspi_regs { }; 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; @@ -131,7 +127,6 @@ struct omap2_mcspi { /* SPI1 has 4 channels, while SPI2 has 2 */ struct omap2_mcspi_dma *dma_channels; struct device *dev; - struct workqueue_struct *wq; struct omap2_mcspi_regs ctx; }; @@ -275,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; @@ -846,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; + + /* RX_ONLY mode needs dummy data in TX reg */ + if (t->tx_buf == NULL) + __raw_writel(0, cs->base + + OMAP2_MCSPI_TX0); - if (t->delay_usecs) - udelay(t->delay_usecs); + 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; @@ -995,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" : "", @@ -1004,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; @@ -1014,35 +1004,30 @@ 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; } @@ -1120,7 +1105,9 @@ static int __devinit 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; @@ -1145,12 +1132,6 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) mcspi = spi_master_get_devdata(master); mcspi->master = master; - mcspi->wq = alloc_workqueue(dev_name(&pdev->dev), 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; @@ -1169,10 +1150,7 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) } 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(&mcspi->ctx.cs); mcspi->dma_channels = kcalloc(master->num_chipselect, @@ -1253,7 +1231,6 @@ static int __devexit omap2_mcspi_remove(struct platform_device *pdev) spi_unregister_master(master); kfree(dma_channels); - destroy_workqueue(mcspi->wq); platform_set_drvdata(pdev, NULL); return 0; -- cgit v1.2.2