summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Niebuhr <bniebuhr@efjohnson.com>2010-10-04 14:05:34 +0200
committerSekhar Nori <nsekhar@ti.com>2010-11-18 14:08:35 +0100
commit523c37e7006522e778a1fd0aea2746ceb788572f (patch)
treecc2146d573961b5cb62615c136042a88984c842a
parentspi: davinci: do not allocate DMA channels during SPI device setup (diff)
downloadlinux-523c37e7006522e778a1fd0aea2746ceb788572f.tar.xz
linux-523c37e7006522e778a1fd0aea2746ceb788572f.zip
spi: davinci: fix EDMA CC errors at end of transfers
Use a dummy param slot linked to itself to take care of the extra "sync event" that gets sent to EDMA controller after the last byte has been transferred. The dummy PaRAM slot that is linked to the actual DMA PaRAM slot "absorbs" this event and prevents a EDMA CC error to be asserted. Without this provision, the EDMA CC error would be asserted because the channel PaRAM would be empty after the transfer and EDMA would not know what to make out of the extra sync event. Signed-off-by: Brian Niebuhr <bniebuhr@efjohnson.com> Tested-By: Michael Williamson <michael.williamson@criticallink.com> Signed-off-by: Sekhar Nori <nsekhar@ti.com>
-rw-r--r--drivers/spi/davinci_spi.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 6db478601024..975c2a228d0a 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -116,6 +116,7 @@
struct davinci_spi_dma {
int dma_tx_channel;
int dma_rx_channel;
+ int dummy_param_slot;
enum dma_event_q eventq;
struct completion dma_tx_completion;
@@ -697,6 +698,8 @@ static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t)
param.src_dst_cidx = 0;
param.ccnt = 1;
edma_write_slot(davinci_spi_dma->dma_tx_channel, &param);
+ edma_link(davinci_spi_dma->dma_tx_channel,
+ davinci_spi_dma->dummy_param_slot);
/*
* Receive DMA setup
@@ -779,19 +782,37 @@ static int davinci_spi_request_dma(struct davinci_spi_dma *davinci_spi_dma)
davinci_spi_dma->eventq);
if (r < 0) {
pr_err("Unable to request DMA channel for SPI RX\n");
- return -EAGAIN;
+ r = -EAGAIN;
+ goto rx_dma_failed;
}
r = edma_alloc_channel(davinci_spi_dma->dma_tx_channel,
davinci_spi_dma_tx_callback, davinci_spi_dma,
davinci_spi_dma->eventq);
if (r < 0) {
- edma_free_channel(davinci_spi_dma->dma_rx_channel);
pr_err("Unable to request DMA channel for SPI TX\n");
- return -EAGAIN;
+ r = -EAGAIN;
+ goto tx_dma_failed;
}
+ r = edma_alloc_slot(EDMA_CTLR(davinci_spi_dma->dma_tx_channel),
+ EDMA_SLOT_ANY);
+ if (r < 0) {
+ pr_err("Unable to request SPI TX DMA param slot\n");
+ r = -EAGAIN;
+ goto param_failed;
+ }
+ davinci_spi_dma->dummy_param_slot = r;
+ edma_link(davinci_spi_dma->dummy_param_slot,
+ davinci_spi_dma->dummy_param_slot);
+
return 0;
+param_failed:
+ edma_free_channel(davinci_spi_dma->dma_tx_channel);
+tx_dma_failed:
+ edma_free_channel(davinci_spi_dma->dma_rx_channel);
+rx_dma_failed:
+ return r;
}
/**
@@ -970,6 +991,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
free_dma:
edma_free_channel(davinci_spi->dma_channels.dma_tx_channel);
edma_free_channel(davinci_spi->dma_channels.dma_rx_channel);
+ edma_free_slot(davinci_spi->dma_channels.dummy_param_slot);
free_clk:
clk_disable(davinci_spi->clk);
clk_put(davinci_spi->clk);