aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/dw_spi.c
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-12-24 00:59:11 -0500
committerGrant Likely <grant.likely@secretlab.ca>2010-12-24 03:23:25 -0500
commit7063c0d942a1af2993531fbe52b4c74c1db818c4 (patch)
treefe91b01bd61449849736c47e0a05840fc47a5eb3 /drivers/spi/dw_spi.c
parent79290a2aa2fd1c179a285218472092475630dc0e (diff)
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)
288 */ 288 */
289static int map_dma_buffers(struct dw_spi *dws) 289static int map_dma_buffers(struct dw_spi *dws)
290{ 290{
291 if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited 291 if (!dws->cur_msg->is_dma_mapped
292 || !dws->cur_chip->enable_dma) 292 || !dws->dma_inited
293 || !dws->cur_chip->enable_dma
294 || !dws->dma_ops)
293 return 0; 295 return 0;
294 296
295 if (dws->cur_transfer->tx_dma) 297 if (dws->cur_transfer->tx_dma)
@@ -341,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg)
341 tasklet_schedule(&dws->pump_transfers); 343 tasklet_schedule(&dws->pump_transfers);
342} 344}
343 345
344static void transfer_complete(struct dw_spi *dws) 346void dw_spi_xfer_done(struct dw_spi *dws)
345{ 347{
346 /* Update total byte transfered return count actual bytes read */ 348 /* Update total byte transfered return count actual bytes read */
347 dws->cur_msg->actual_length += dws->len; 349 dws->cur_msg->actual_length += dws->len;
@@ -356,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws)
356 } else 358 } else
357 tasklet_schedule(&dws->pump_transfers); 359 tasklet_schedule(&dws->pump_transfers);
358} 360}
361EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
359 362
360static irqreturn_t interrupt_transfer(struct dw_spi *dws) 363static irqreturn_t interrupt_transfer(struct dw_spi *dws)
361{ 364{
@@ -387,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
387 if (dws->tx_end > dws->tx) 390 if (dws->tx_end > dws->tx)
388 spi_umask_intr(dws, SPI_INT_TXEI); 391 spi_umask_intr(dws, SPI_INT_TXEI);
389 else 392 else
390 transfer_complete(dws); 393 dw_spi_xfer_done(dws);
391 } 394 }
392 395
393 return IRQ_HANDLED; 396 return IRQ_HANDLED;
@@ -422,11 +425,7 @@ static void poll_transfer(struct dw_spi *dws)
422 */ 425 */
423 dws->read(dws); 426 dws->read(dws);
424 427
425 transfer_complete(dws); 428 dw_spi_xfer_done(dws);
426}
427
428static void dma_transfer(struct dw_spi *dws, int cs_change)
429{
430} 429}
431 430
432static void pump_transfers(unsigned long data) 431static void pump_transfers(unsigned long data)
@@ -608,7 +607,7 @@ static void pump_transfers(unsigned long data)
608 } 607 }
609 608
610 if (dws->dma_mapped) 609 if (dws->dma_mapped)
611 dma_transfer(dws, cs_change); 610 dws->dma_ops->dma_transfer(dws, cs_change);
612 611
613 if (chip->poll_mode) 612 if (chip->poll_mode)
614 poll_transfer(dws); 613 poll_transfer(dws);
@@ -904,11 +903,17 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
904 master->setup = dw_spi_setup; 903 master->setup = dw_spi_setup;
905 master->transfer = dw_spi_transfer; 904 master->transfer = dw_spi_transfer;
906 905
907 dws->dma_inited = 0;
908
909 /* Basic HW init */ 906 /* Basic HW init */
910 spi_hw_init(dws); 907 spi_hw_init(dws);
911 908
909 if (dws->dma_ops && dws->dma_ops->dma_init) {
910 ret = dws->dma_ops->dma_init(dws);
911 if (ret) {
912 dev_warn(&master->dev, "DMA init failed\n");
913 dws->dma_inited = 0;
914 }
915 }
916
912 /* Initial and start queue */ 917 /* Initial and start queue */
913 ret = init_queue(dws); 918 ret = init_queue(dws);
914 if (ret) { 919 if (ret) {
@@ -933,6 +938,8 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
933 938
934err_queue_alloc: 939err_queue_alloc:
935 destroy_queue(dws); 940 destroy_queue(dws);
941 if (dws->dma_ops && dws->dma_ops->dma_exit)
942 dws->dma_ops->dma_exit(dws);
936err_diable_hw: 943err_diable_hw:
937 spi_enable_chip(dws, 0); 944 spi_enable_chip(dws, 0);
938 free_irq(dws->irq, dws); 945 free_irq(dws->irq, dws);
@@ -957,6 +964,8 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
957 dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not " 964 dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
958 "complete, message memory not freed\n"); 965 "complete, message memory not freed\n");
959 966
967 if (dws->dma_ops && dws->dma_ops->dma_exit)
968 dws->dma_ops->dma_exit(dws);
960 spi_enable_chip(dws, 0); 969 spi_enable_chip(dws, 0);
961 /* Disable clk */ 970 /* Disable clk */
962 spi_set_clk(dws, 0); 971 spi_set_clk(dws, 0);