summaryrefslogtreecommitdiff
path: root/drivers/spi/dw_spi.c
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-12-24 08:59:11 +0300
committerGrant Likely <grant.likely@secretlab.ca>2010-12-24 11:23:25 +0300
commit7063c0d942a1af2993531fbe52b4c74c1db818c4 (patch)
treefe91b01bd61449849736c47e0a05840fc47a5eb3 /drivers/spi/dw_spi.c
parent79290a2aa2fd1c179a285218472092475630dc0e (diff)
downloadlinux-7063c0d942a1af2993531fbe52b4c74c1db818c4.tar.xz
spi/dw_spi: add DMA support
dw_spi driver in upstream only supports PIO mode, and this patch will support it to cowork with the Designware dma controller used on Intel Moorestown platform, at the same time it provides a general framework to support dw_spi core to cowork with dma controllers on other platforms It has been tested with a Option GTM501L 3G modem and Infenion 60x60 modem. To use DMA mode, DMA controller 2 of Moorestown has to be enabled Also change the dma interface suggested by Linus Walleij. Acked-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Feng Tang <feng.tang@intel.com> [Typo fix and renames to match intel_mid_dma renaming] Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi/dw_spi.c')
-rw-r--r--drivers/spi/dw_spi.c33
1 files changed, 21 insertions, 12 deletions
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c
index b50bf5ba873f..497ecb3ab83f 100644
--- a/drivers/spi/dw_spi.c
+++ b/drivers/spi/dw_spi.c
@@ -288,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws)
*/
static int map_dma_buffers(struct dw_spi *dws)
{
- if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited
- || !dws->cur_chip->enable_dma)
+ if (!dws->cur_msg->is_dma_mapped
+ || !dws->dma_inited
+ || !dws->cur_chip->enable_dma
+ || !dws->dma_ops)
return 0;
if (dws->cur_transfer->tx_dma)
@@ -341,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg)
tasklet_schedule(&dws->pump_transfers);
}
-static void transfer_complete(struct dw_spi *dws)
+void dw_spi_xfer_done(struct dw_spi *dws)
{
/* Update total byte transfered return count actual bytes read */
dws->cur_msg->actual_length += dws->len;
@@ -356,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws)
} else
tasklet_schedule(&dws->pump_transfers);
}
+EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
static irqreturn_t interrupt_transfer(struct dw_spi *dws)
{
@@ -387,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
if (dws->tx_end > dws->tx)
spi_umask_intr(dws, SPI_INT_TXEI);
else
- transfer_complete(dws);
+ dw_spi_xfer_done(dws);
}
return IRQ_HANDLED;
@@ -422,11 +425,7 @@ static void poll_transfer(struct dw_spi *dws)
*/
dws->read(dws);
- transfer_complete(dws);
-}
-
-static void dma_transfer(struct dw_spi *dws, int cs_change)
-{
+ dw_spi_xfer_done(dws);
}
static void pump_transfers(unsigned long data)
@@ -608,7 +607,7 @@ static void pump_transfers(unsigned long data)
}
if (dws->dma_mapped)
- dma_transfer(dws, cs_change);
+ dws->dma_ops->dma_transfer(dws, cs_change);
if (chip->poll_mode)
poll_transfer(dws);
@@ -904,11 +903,17 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
master->setup = dw_spi_setup;
master->transfer = dw_spi_transfer;
- dws->dma_inited = 0;
-
/* Basic HW init */
spi_hw_init(dws);
+ if (dws->dma_ops && dws->dma_ops->dma_init) {
+ ret = dws->dma_ops->dma_init(dws);
+ if (ret) {
+ dev_warn(&master->dev, "DMA init failed\n");
+ dws->dma_inited = 0;
+ }
+ }
+
/* Initial and start queue */
ret = init_queue(dws);
if (ret) {
@@ -933,6 +938,8 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
err_queue_alloc:
destroy_queue(dws);
+ if (dws->dma_ops && dws->dma_ops->dma_exit)
+ dws->dma_ops->dma_exit(dws);
err_diable_hw:
spi_enable_chip(dws, 0);
free_irq(dws->irq, dws);
@@ -957,6 +964,8 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
"complete, message memory not freed\n");
+ if (dws->dma_ops && dws->dma_ops->dma_exit)
+ dws->dma_ops->dma_exit(dws);
spi_enable_chip(dws, 0);
/* Disable clk */
spi_set_clk(dws, 0);