aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-dw-dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-dw-dma.c')
-rw-r--r--drivers/spi/spi-dw-dma.c45
1 files changed, 28 insertions, 17 deletions
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index b5bed02b7e50..c34c202d617e 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -6,6 +6,7 @@
*/
#include <linux/completion.h>
+#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/irqreturn.h>
@@ -329,7 +330,6 @@ static int dw_spi_dma_config_tx(struct dw_spi *dws)
txconf.direction = DMA_MEM_TO_DEV;
txconf.dst_addr = dws->dma_addr;
txconf.dst_maxburst = dws->txburst;
- txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
txconf.dst_addr_width = dw_spi_dma_convert_width(dws->n_bytes);
txconf.device_fc = false;
@@ -430,7 +430,6 @@ static int dw_spi_dma_config_rx(struct dw_spi *dws)
rxconf.direction = DMA_DEV_TO_MEM;
rxconf.src_addr = dws->dma_addr;
rxconf.src_maxburst = dws->rxburst;
- rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
rxconf.src_addr_width = dw_spi_dma_convert_width(dws->n_bytes);
rxconf.device_fc = false;
@@ -470,13 +469,12 @@ static int dw_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
u16 imr, dma_ctrl;
int ret;
- if (!xfer->tx_buf)
- return -EINVAL;
-
/* Setup DMA channels */
- ret = dw_spi_dma_config_tx(dws);
- if (ret)
- return ret;
+ if (xfer->tx_buf) {
+ ret = dw_spi_dma_config_tx(dws);
+ if (ret)
+ return ret;
+ }
if (xfer->rx_buf) {
ret = dw_spi_dma_config_rx(dws);
@@ -485,13 +483,17 @@ static int dw_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
}
/* Set the DMA handshaking interface */
- dma_ctrl = DW_SPI_DMACR_TDMAE;
+ dma_ctrl = 0;
+ if (xfer->tx_buf)
+ dma_ctrl |= DW_SPI_DMACR_TDMAE;
if (xfer->rx_buf)
dma_ctrl |= DW_SPI_DMACR_RDMAE;
dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
/* Set the interrupt mask */
- imr = DW_SPI_INT_TXOI;
+ imr = 0;
+ if (xfer->tx_buf)
+ imr |= DW_SPI_INT_TXOI;
if (xfer->rx_buf)
imr |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI;
dw_spi_umask_intr(dws, imr);
@@ -508,15 +510,16 @@ static int dw_spi_dma_transfer_all(struct dw_spi *dws,
{
int ret;
- /* Submit the DMA Tx transfer */
- ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents);
- if (ret)
- goto err_clear_dmac;
+ /* Submit the DMA Tx transfer if required */
+ if (xfer->tx_buf) {
+ ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents);
+ if (ret)
+ goto err_clear_dmac;
+ }
/* Submit the DMA Rx transfer if required */
if (xfer->rx_buf) {
- ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl,
- xfer->rx_sg.nents);
+ ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl, xfer->rx_sg.nents);
if (ret)
goto err_clear_dmac;
@@ -524,7 +527,15 @@ static int dw_spi_dma_transfer_all(struct dw_spi *dws,
dma_async_issue_pending(dws->rxchan);
}
- dma_async_issue_pending(dws->txchan);
+ if (xfer->tx_buf) {
+ dma_async_issue_pending(dws->txchan);
+ } else {
+ /* Pause to allow DMA channel to fetch RX descriptor */
+ usleep_range(5, 10);
+
+ /* Write something to the TX FIFO to start the transfer */
+ dw_writel(dws, DW_SPI_DR, 0);
+ }
ret = dw_spi_dma_wait(dws, xfer->len, xfer->effective_speed_hz);