summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-24 13:56:24 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-24 13:56:24 -0700
commitbe122abe4bcd6d39b37892daae28c8bf5e4030fc (patch)
treee8ad84c41c2acde27c77fa212b8865cd3acfe6fb /drivers/spi
parentb343c8beec664ef6f0e9964d3001c7c7966331ae (diff)
parent1e8a52e18cfb381bc9cc1f0b720540364d2a6edd (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.c3
-rw-r--r--drivers/spi/spi-coldfire-qspi.c255
-rw-r--r--drivers/spi/spi-dw-pci.c13
-rw-r--r--drivers/spi/spi-ep93xx.c37
-rw-r--r--drivers/spi/spi-fsl-espi.c1
-rw-r--r--drivers/spi/spi-fsl-lib.c2
-rw-r--r--drivers/spi/spi-fsl-spi.c2
-rw-r--r--drivers/spi/spi-lm70llp.c3
-rw-r--r--drivers/spi/spi-mpc52xx.c3
-rw-r--r--drivers/spi/spi-omap2-mcspi.c373
-rw-r--r--drivers/spi/spi-ppc4xx.c4
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c12
-rw-r--r--drivers/spi/spi-rspi.c320
-rw-r--r--drivers/spi/spi-sirf.c20
-rw-r--r--drivers/spi/spi-topcliff-pch.c3
-rw-r--r--drivers/spi/spi.c98
16 files changed, 705 insertions, 444 deletions
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index acc88b4d2869..249077e5cc48 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 6eee64a5d240..b2d4b9e4e010 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 14f7cc9523f0..ff81abbb3066 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 e8055073e84d..f97f1d248800 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 7523a2429d09..27bdc47b5250 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 2674fad7f68a..1503574b215a 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 5f748c0d96bd..6a62934ca74c 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 933eb9d9ddd4..0759b5db9883 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 57633d963456..cb3a3830b0a5 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 bb9274c2526d..46ef5fe51db5 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) {