spi: spi-fsl-dspi: Fix per transfer cs_change handling

As of 92dc20d83a, 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>
This commit is contained in:
Esben Haabendal 2018-06-20 09:34:33 +02:00 committed by Mark Brown
parent 4779f23d1a
commit 9e1dc9bd09
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0

View file

@ -84,11 +84,16 @@
#define SPI_RSER_TCFQE 0x80000000 #define SPI_RSER_TCFQE 0x80000000
#define SPI_PUSHR 0x34 #define SPI_PUSHR 0x34
#define SPI_PUSHR_CONT (1 << 31) #define SPI_PUSHR_CMD_CONT (1 << 15)
#define SPI_PUSHR_CTAS(x) (((x) & 0x00000003) << 28) #define SPI_PUSHR_CONT (SPI_PUSHR_CMD_CONT << 16)
#define SPI_PUSHR_EOQ (1 << 27) #define SPI_PUSHR_CMD_CTAS(x) (((x) & 0x0003) << 12)
#define SPI_PUSHR_CTCNT (1 << 26) #define SPI_PUSHR_CTAS(x) (SPI_PUSHR_CMD_CTAS(x) << 16)
#define SPI_PUSHR_PCS(x) (((1 << x) & 0x0000003f) << 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_TXDATA(x) ((x) & 0x0000ffff)
#define SPI_PUSHR_SLAVE 0x34 #define SPI_PUSHR_SLAVE 0x34
@ -189,9 +194,8 @@ struct fsl_dspi {
void *rx; void *rx;
void *rx_end; void *rx_end;
char dataflags; char dataflags;
u8 cs;
u16 void_write_data; u16 void_write_data;
u32 cs_change; u16 tx_cmd;
const struct fsl_dspi_devtype_data *devtype_data; const struct fsl_dspi_devtype_data *devtype_data;
wait_queue_head_t waitq; 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++) { for (i = 0; i < dma->curr_xfer_len; i++) {
dspi->dma->tx_dma_buf[i] = dspi_data_to_pushr(dspi, tx_word); 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, 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) static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word)
{ {
u16 d16; u16 data, cmd;
if (dspi->tx) { 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; dspi->tx += tx_word + 1;
} else { } else {
d16 = dspi->void_write_data; data = dspi->void_write_data;
} }
dspi->len -= tx_word + 1; dspi->len -= tx_word + 1;
return SPI_PUSHR_TXDATA(d16) | cmd = dspi->tx_cmd;
SPI_PUSHR_PCS(dspi->cs) | if (dspi->len > 0)
SPI_PUSHR_CTAS(0) | cmd |= SPI_PUSHR_CMD_CONT;
SPI_PUSHR_CONT;
return (cmd << 16) | SPI_PUSHR_TXDATA(data);
} }
static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word) 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); dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) { if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1)
/* last transfer in the transfer */ /* request EOQ flag for last transfer in queue */
dspi_pushr |= SPI_PUSHR_EOQ; dspi_pushr |= SPI_PUSHR_EOQ;
if ((dspi->cs_change) && (!dspi->len))
dspi_pushr &= ~SPI_PUSHR_CONT;
}
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr); 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); 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); regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
return tx_word + 1; return tx_word + 1;
@ -672,11 +669,26 @@ static int dspi_transfer_one_message(struct spi_master *master,
dspi->cur_transfer = transfer; dspi->cur_transfer = transfer;
dspi->cur_msg = message; dspi->cur_msg = message;
dspi->cur_chip = spi_get_ctldata(spi); dspi->cur_chip = spi_get_ctldata(spi);
dspi->cs = spi->chip_select; /* Prepare command word for CMD FIFO */
dspi->cs_change = 0; dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0) |
SPI_PUSHR_CMD_PCS(spi->chip_select);
if (list_is_last(&dspi->cur_transfer->transfer_list, if (list_is_last(&dspi->cur_transfer->transfer_list,
&dspi->cur_msg->transfers) || transfer->cs_change) &dspi->cur_msg->transfers)) {
dspi->cs_change = 1; /* 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->void_write_data = dspi->cur_chip->void_write_data;
dspi->dataflags = 0; dspi->dataflags = 0;