aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Semin <[email protected]>2020-05-15 13:47:42 +0300
committerMark Brown <[email protected]>2020-05-15 18:29:17 +0100
commit0327f0b881dc5645c7ba670331e822cdaa8c5e09 (patch)
treecfd79617fa6391a399db20d1259e27dd2787e138
parent77810d484f4f28107391787dfa1c6c53d994c4fc (diff)
spi: dw: Clear DMAC register when done or stopped
If DMAC register is left uncleared any further DMAless transfers may cause the DMAC hardware handshaking interface getting activated. So the next DMA-based Rx/Tx transaction will be started right after the dma_async_issue_pending() method is invoked even if no DMATDLR/DMARDLR conditions are met. This at the same time may cause the Tx/Rx FIFO buffers underrun/overrun. In order to fix this we must clear DMAC register after a current DMA-based transaction is finished. Co-developed-by: Georgy Vlasov <[email protected]> Signed-off-by: Georgy Vlasov <[email protected]> Signed-off-by: Serge Semin <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
-rw-r--r--drivers/spi/spi-dw-mid.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 177e1f5ec62b..f9757a370699 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -106,6 +106,8 @@ static void mid_spi_dma_exit(struct dw_spi *dws)
dmaengine_terminate_sync(dws->rxchan);
dma_release_channel(dws->rxchan);
}
+
+ dw_writel(dws, DW_SPI_DMACR, 0);
}
static irqreturn_t dma_transfer(struct dw_spi *dws)
@@ -152,6 +154,8 @@ static void dw_spi_dma_tx_done(void *arg)
clear_bit(TX_BUSY, &dws->dma_chan_busy);
if (test_bit(RX_BUSY, &dws->dma_chan_busy))
return;
+
+ dw_writel(dws, DW_SPI_DMACR, 0);
spi_finalize_current_transfer(dws->master);
}
@@ -199,6 +203,8 @@ static void dw_spi_dma_rx_done(void *arg)
clear_bit(RX_BUSY, &dws->dma_chan_busy);
if (test_bit(TX_BUSY, &dws->dma_chan_busy))
return;
+
+ dw_writel(dws, DW_SPI_DMACR, 0);
spi_finalize_current_transfer(dws->master);
}
@@ -292,6 +298,8 @@ static void mid_spi_dma_stop(struct dw_spi *dws)
dmaengine_terminate_sync(dws->rxchan);
clear_bit(RX_BUSY, &dws->dma_chan_busy);
}
+
+ dw_writel(dws, DW_SPI_DMACR, 0);
}
static const struct dw_spi_dma_ops mfld_dma_ops = {