summaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-fsl-dspi.c
diff options
context:
space:
mode:
authorEsben Haabendal <eha@deif.com>2018-06-20 09:34:33 +0200
committerMark Brown <broonie@kernel.org>2018-06-20 14:45:46 +0100
commit9e1dc9bd099363760afdd2316fc057f9ca38b559 (patch)
tree8a666f612d5d272df013bf0467d02a89ce7401f9 /drivers/spi/spi-fsl-dspi.c
parent4779f23d1ac8694f7acc537fcadb750bff664ea5 (diff)
downloadblackbird-op-linux-9e1dc9bd099363760afdd2316fc057f9ca38b559.tar.gz
blackbird-op-linux-9e1dc9bd099363760afdd2316fc057f9ca38b559.zip
spi: spi-fsl-dspi: Fix per transfer cs_change handling
As of 92dc20d83adec565378254c0630e839ff5674e14, transfer->cs_change has been supported for non-last transfers, but not for last transfer. This change brings handling of cs_change in line with the specification in spi.h, implementing handling of transfer->cs_change for all transfers. The value for CMD FIFO is precalculated with transfer->cs_change field taken into account, allowing for CS de-activate between transfers and keeping CS activated after last transfer. Signed-off-by: Esben Haabendal <eha@deif.com> Acked-by: Martin Hundebøll <martin@geanix.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi-fsl-dspi.c')
-rw-r--r--drivers/spi/spi-fsl-dspi.c68
1 files changed, 40 insertions, 28 deletions
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 3bf135bf8b93..c0c3b8bf2781 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -84,11 +84,16 @@
#define SPI_RSER_TCFQE 0x80000000
#define SPI_PUSHR 0x34
-#define SPI_PUSHR_CONT (1 << 31)
-#define SPI_PUSHR_CTAS(x) (((x) & 0x00000003) << 28)
-#define SPI_PUSHR_EOQ (1 << 27)
-#define SPI_PUSHR_CTCNT (1 << 26)
-#define SPI_PUSHR_PCS(x) (((1 << x) & 0x0000003f) << 16)
+#define SPI_PUSHR_CMD_CONT (1 << 15)
+#define SPI_PUSHR_CONT (SPI_PUSHR_CMD_CONT << 16)
+#define SPI_PUSHR_CMD_CTAS(x) (((x) & 0x0003) << 12)
+#define SPI_PUSHR_CTAS(x) (SPI_PUSHR_CMD_CTAS(x) << 16)
+#define SPI_PUSHR_CMD_EOQ (1 << 11)
+#define SPI_PUSHR_EOQ (SPI_PUSHR_CMD_EOQ << 16)
+#define SPI_PUSHR_CMD_CTCNT (1 << 10)
+#define SPI_PUSHR_CTCNT (SPI_PUSHR_CMD_CTCNT << 16)
+#define SPI_PUSHR_CMD_PCS(x) ((1 << x) & 0x003f)
+#define SPI_PUSHR_PCS(x) (SPI_PUSHR_CMD_PCS(x) << 16)
#define SPI_PUSHR_TXDATA(x) ((x) & 0x0000ffff)
#define SPI_PUSHR_SLAVE 0x34
@@ -189,9 +194,8 @@ struct fsl_dspi {
void *rx;
void *rx_end;
char dataflags;
- u8 cs;
u16 void_write_data;
- u32 cs_change;
+ u16 tx_cmd;
const struct fsl_dspi_devtype_data *devtype_data;
wait_queue_head_t waitq;
@@ -254,8 +258,6 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
for (i = 0; i < dma->curr_xfer_len; i++) {
dspi->dma->tx_dma_buf[i] = dspi_data_to_pushr(dspi, tx_word);
- if ((dspi->cs_change) && (!dspi->len))
- dspi->dma->tx_dma_buf[i] &= ~SPI_PUSHR_CONT;
}
dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
@@ -534,21 +536,22 @@ static void ns_delay_scale(char *psc, char *sc, int delay_ns,
static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word)
{
- u16 d16;
+ u16 data, cmd;
if (dspi->tx) {
- d16 = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx;
+ data = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx;
dspi->tx += tx_word + 1;
} else {
- d16 = dspi->void_write_data;
+ data = dspi->void_write_data;
}
dspi->len -= tx_word + 1;
- return SPI_PUSHR_TXDATA(d16) |
- SPI_PUSHR_PCS(dspi->cs) |
- SPI_PUSHR_CTAS(0) |
- SPI_PUSHR_CONT;
+ cmd = dspi->tx_cmd;
+ if (dspi->len > 0)
+ cmd |= SPI_PUSHR_CMD_CONT;
+
+ return (cmd << 16) | SPI_PUSHR_TXDATA(data);
}
static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word)
@@ -587,12 +590,9 @@ static int dspi_eoq_write(struct fsl_dspi *dspi)
dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
- if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) {
- /* last transfer in the transfer */
+ if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1)
+ /* request EOQ flag for last transfer in queue */
dspi_pushr |= SPI_PUSHR_EOQ;
- if ((dspi->cs_change) && (!dspi->len))
- dspi_pushr &= ~SPI_PUSHR_CONT;
- }
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
@@ -635,9 +635,6 @@ static int dspi_tcfq_write(struct fsl_dspi *dspi)
dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
- if ((dspi->cs_change) && (!dspi->len))
- dspi_pushr &= ~SPI_PUSHR_CONT;
-
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
return tx_word + 1;
@@ -672,11 +669,26 @@ static int dspi_transfer_one_message(struct spi_master *master,
dspi->cur_transfer = transfer;
dspi->cur_msg = message;
dspi->cur_chip = spi_get_ctldata(spi);
- dspi->cs = spi->chip_select;
- dspi->cs_change = 0;
+ /* Prepare command word for CMD FIFO */
+ dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0) |
+ SPI_PUSHR_CMD_PCS(spi->chip_select);
if (list_is_last(&dspi->cur_transfer->transfer_list,
- &dspi->cur_msg->transfers) || transfer->cs_change)
- dspi->cs_change = 1;
+ &dspi->cur_msg->transfers)) {
+ /* Leave PCS activated after last transfer when
+ * cs_change is set.
+ */
+ if (transfer->cs_change)
+ dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
+ } else {
+ /* Keep PCS active between transfers in same message
+ * when cs_change is not set, and de-activate PCS
+ * between transfers in the same message when
+ * cs_change is set.
+ */
+ if (!transfer->cs_change)
+ dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
+ }
+
dspi->void_write_data = dspi->cur_chip->void_write_data;
dspi->dataflags = 0;
OpenPOWER on IntegriCloud