summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/mxs_spi.c43
1 files changed, 25 insertions, 18 deletions
diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c
index c399707..42e4c99 100644
--- a/drivers/spi/mxs_spi.c
+++ b/drivers/spi/mxs_spi.c
@@ -227,6 +227,7 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
const uint32_t dstart = (uint32_t)data;
int dmach;
int tl;
+ int ret = 0;
ALLOC_CACHE_ALIGN_BUFFER(struct mxs_dma_desc, desc, desc_count);
@@ -240,8 +241,6 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
if (!write)
ctrl0 |= SSP_CTRL0_READ;
- writel(length, &ssp_regs->hw_ssp_xfer_size);
-
if (length % ARCH_DMA_MINALIGN)
cache_data_count = roundup(length, ARCH_DMA_MINALIGN);
else
@@ -284,39 +283,47 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
tl = min(length, xfer_max_sz);
dp->cmd.data |=
- (tl << MXS_DMA_DESC_BYTES_OFFSET) |
- (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
+ ((tl & 0xffff) << MXS_DMA_DESC_BYTES_OFFSET) |
+ (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
MXS_DMA_DESC_HALT_ON_TERMINATE |
MXS_DMA_DESC_TERMINATE_FLUSH;
- dp->cmd.pio_words[0] = ctrl0;
data += tl;
length -= tl;
+ if (!length) {
+ dp->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM;
+
+ if (flags & SPI_XFER_END) {
+ ctrl0 &= ~SSP_CTRL0_LOCK_CS;
+ ctrl0 |= SSP_CTRL0_IGNORE_CRC;
+ }
+ }
+
+ /*
+ * Write CTRL0, CMD0, CMD1, XFER_SIZE registers. It is
+ * essential that the XFER_SIZE register is written on
+ * a per-descriptor basis with the same size as is the
+ * descriptor!
+ */
+ dp->cmd.pio_words[0] = ctrl0;
+ dp->cmd.pio_words[1] = 0;
+ dp->cmd.pio_words[2] = 0;
+ dp->cmd.pio_words[3] = tl;
+
mxs_dma_desc_append(dmach, dp);
dp++;
}
- dp->address = (dma_addr_t)dp;
- dp->cmd.address = (dma_addr_t)0;
- dp->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER |
- (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
- MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM;
- if (flags & SPI_XFER_END) {
- ctrl0 &= ~SSP_CTRL0_LOCK_CS;
- dp->cmd.pio_words[0] = ctrl0 | SSP_CTRL0_IGNORE_CRC;
- }
- mxs_dma_desc_append(dmach, dp);
-
if (mxs_dma_go(dmach))
- return -EINVAL;
+ ret = -EINVAL;
/* The data arrived into DRAM, invalidate cache over them */
if (!write)
invalidate_dcache_range(dstart, dstart + cache_data_count);
- return 0;
+ return ret;
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,