summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Gong <b38343@freescale.com>2014-12-13 21:55:25 +0800
committerRobin Gong <b38343@freescale.com>2014-12-19 10:25:31 +0800
commitc7ecc24637babcb76edf20600f0535ab118e0101 (patch)
treedc0a5cf0a6343b1d146f202d99acd1b537841ec2
parentd0fa9b74641285ef62bad2e8e39ee13467549967 (diff)
MLK-9986-2 spi: spi-imx: use pio mode for the tail data in DMA mode
Sometimes the tail data can't trigger SDMA to read from rxfifo, or SDMA miss the last dma request, in this case, DMA report RX timeout and the rest tail data kept in rxfifo. Whatever, use pio read for the tail rx data. Signed-off-by: Robin Gong <b38343@freescale.com> (cherry picked from commit 61fec9e4511e7626a2c5299f37c12cca95d12e88)
-rw-r--r--drivers/spi/spi-imx.c39
1 files changed, 25 insertions, 14 deletions
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index b1f5ccc8e317..203bb6a5f389 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -205,8 +205,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
- if (spi_imx->dma_is_inited && (transfer->len > spi_imx->rx_wml)
- && (transfer->len > spi_imx->tx_wml))
+ if (spi_imx->dma_is_inited &&
+ (transfer->len > spi_imx_get_fifosize(spi_imx)) &&
+ (transfer->len > spi_imx_get_fifosize(spi_imx)))
return true;
return false;
}
@@ -895,8 +896,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
{
struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
int ret;
- u32 dma;
- int left;
+ int left = 0;
struct spi_master *master = spi_imx->bitbang.master;
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
@@ -913,6 +913,18 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
}
if (rx) {
+ struct scatterlist *sgl_last = &rx->sgl[rx->nents - 1];
+ unsigned int orig_length = sgl_last->length;
+ int wml_mask = ~(spi_imx->rx_wml - 1);
+ /*
+ * Adjust the transfer lenth of the last scattlist if there are
+ * some tail data, use PIO read to get the tail data since DMA
+ * sometimes miss the last tail interrupt.
+ */
+ left = transfer->len % spi_imx->rx_wml;
+ if (left)
+ sgl_last->length = orig_length & wml_mask;
+
desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
rx->sgl, rx->nents, DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -930,13 +942,6 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
/* Trigger the cspi module. */
spi_imx->dma_finished = 0;
- dma = readl(spi_imx->base + MX51_ECSPI_DMA);
- dma = dma & (~MX51_ECSPI_DMA_RXT_WML_MASK);
- /* Change RX_DMA_LENGTH trigger dma fetch tail data */
- left = transfer->len % spi_imx->rxt_wml;
- if (left)
- writel(dma | (left << MX51_ECSPI_DMA_RXT_WML_OFFSET),
- spi_imx->base + MX51_ECSPI_DMA);
spi_imx->devtype_data->trigger(spi_imx);
dma_async_issue_pending(master->dma_tx);
@@ -958,10 +963,16 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
dev_name(&master->dev), transfer->len);
spi_imx->devtype_data->reset(spi_imx);
dmaengine_terminate_all(master->dma_rx);
+ } else if (left) {
+ /* read the tail data by PIO */
+ void *tmpbuf = transfer->rx_buf + transfer->len - left;
+
+ while (readl(spi_imx->base + MX51_ECSPI_STAT) & 0x8) {
+ *(char *)tmpbuf =
+ readl(spi_imx->base + MXC_CSPIRXDATA);
+ tmpbuf++;
+ }
}
- writel(dma |
- spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET,
- spi_imx->base + MX51_ECSPI_DMA);
}
spi_imx->dma_finished = 1;