aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorEero Nurkkala <ext-eero.nurkkala@nokia.com>2009-07-29 18:02:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-07-29 22:10:35 -0400
commit57c5c28dbc835c67a9c23912bab56b7f165e7715 (patch)
tree6d3ddbbff6aa875b00f52fb7efc792faf51b9ae2 /drivers/spi
parentddb22195cb3dc5175ba3aac5e957d0e34cd2ee73 (diff)
spi: omap2_mcspi rxdma bugfix
When data is read through DMA, the last element must be read separately through the RX register. It cannot be transferred by the DMA. For further details see e.g. OMAP35x TRM (table 19-16). Without the fix the driver causes extra clocks to be clocked to the bus after DMA RX operations. This can cause interesting behaviour with some devices. Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Signed-off-by: Eero Nurkkala <ext-eero.nurkkala@nokia.com> [aaro.koskinen@nokia.com: Simplified the patch while keeping the idea.] Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/omap2_mcspi.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index 2b64091b0f1f..9b80ad36dbba 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -272,7 +272,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
272 272
273 if (rx != NULL) { 273 if (rx != NULL) {
274 omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel, 274 omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
275 data_type, element_count, 1, 275 data_type, element_count - 1, 1,
276 OMAP_DMA_SYNC_ELEMENT, 276 OMAP_DMA_SYNC_ELEMENT,
277 mcspi_dma->dma_rx_sync_dev, 1); 277 mcspi_dma->dma_rx_sync_dev, 1);
278 278
@@ -303,6 +303,25 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
303 if (rx != NULL) { 303 if (rx != NULL) {
304 wait_for_completion(&mcspi_dma->dma_rx_completion); 304 wait_for_completion(&mcspi_dma->dma_rx_completion);
305 dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE); 305 dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
306 omap2_mcspi_set_enable(spi, 0);
307 if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
308 & OMAP2_MCSPI_CHSTAT_RXS)) {
309 u32 w;
310
311 w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
312 if (word_len <= 8)
313 ((u8 *)xfer->rx_buf)[element_count - 1] = w;
314 else if (word_len <= 16)
315 ((u16 *)xfer->rx_buf)[element_count - 1] = w;
316 else /* word_len <= 32 */
317 ((u32 *)xfer->rx_buf)[element_count - 1] = w;
318 } else {
319 dev_err(&spi->dev, "DMA RX last word empty");
320 count -= (word_len <= 8) ? 1 :
321 (word_len <= 16) ? 2 :
322 /* word_len <= 32 */ 4;
323 }
324 omap2_mcspi_set_enable(spi, 1);
306 } 325 }
307 return count; 326 return count;
308} 327}