Merge branch 'spi-4.18' into spi-4.19 for DSPI dep
[muen/linux.git] / drivers / spi / spi-fsl-dspi.c
index 1c1070114246dd787808c70f437b1313e3a7cd56..d83d3496d538b955178616e78dc9384fb35b1257 100644 (file)
 
 #define DRIVER_NAME "fsl-dspi"
 
-#define TRAN_STATE_RX_VOID             0x01
-#define TRAN_STATE_TX_VOID             0x02
-#define TRAN_STATE_WORD_ODD_NUM        0x04
-
 #define DSPI_FIFO_SIZE                 4
 #define DSPI_DMA_BUFSIZE               (DSPI_FIFO_SIZE * 1024)
 
 #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
 #define SPI_CS_ASSERT          0x02
 #define SPI_CS_DROP            0x04
 
-#define SPI_TCR_TCNT_MAX       0x10000
-
 #define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
 
 struct chip_data {
-       u32 mcr_val;
        u32 ctar_val;
        u16 void_write_data;
 };
@@ -186,32 +184,58 @@ struct fsl_dspi {
        struct spi_message      *cur_msg;
        struct chip_data        *cur_chip;
        size_t                  len;
-       void                    *tx;
-       void                    *tx_end;
+       const void              *tx;
        void                    *rx;
        void                    *rx_end;
-       char                    dataflags;
-       u8                      cs;
        u16                     void_write_data;
-       u32                     cs_change;
+       u16                     tx_cmd;
+       u8                      bits_per_word;
+       u8                      bytes_per_word;
        const struct fsl_dspi_devtype_data *devtype_data;
 
        wait_queue_head_t       waitq;
        u32                     waitflags;
 
-       u32                     spi_tcnt;
        struct fsl_dspi_dma     *dma;
 };
 
-static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word);
+static u16 dspi_pop_tx(struct fsl_dspi *dspi)
+{
+       u16 txdata = 0;
+
+       if (dspi->tx) {
+               if (dspi->bytes_per_word == 1)
+                       txdata = *(u8 *)dspi->tx;
+               else /* dspi->bytes_per_word == 2 */
+                       txdata = *(u16 *)dspi->tx;
+               dspi->tx += dspi->bytes_per_word;
+       }
+       dspi->len -= dspi->bytes_per_word;
+       return txdata;
+}
 
-static inline int is_double_byte_mode(struct fsl_dspi *dspi)
+static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
 {
-       unsigned int val;
+       u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
+
+       if (dspi->len > 0)
+               cmd |= SPI_PUSHR_CMD_CONT;
+       return cmd << 16 | data;
+}
 
-       regmap_read(dspi->regmap, SPI_CTAR(0), &val);
+static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
+{
+       if (!dspi->rx)
+               return;
 
-       return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
+       /* Mask of undefined bits */
+       rxdata &= (1 << dspi->bits_per_word) - 1;
+
+       if (dspi->bytes_per_word == 1)
+               *(u8 *)dspi->rx = rxdata;
+       else /* dspi->bytes_per_word == 2 */
+               *(u16 *)dspi->rx = rxdata;
+       dspi->rx += dspi->bytes_per_word;
 }
 
 static void dspi_tx_dma_callback(void *arg)
@@ -226,19 +250,11 @@ static void dspi_rx_dma_callback(void *arg)
 {
        struct fsl_dspi *dspi = arg;
        struct fsl_dspi_dma *dma = dspi->dma;
-       int rx_word;
        int i;
-       u16 d;
-
-       rx_word = is_double_byte_mode(dspi);
 
-       if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
-               for (i = 0; i < dma->curr_xfer_len; i++) {
-                       d = dspi->dma->rx_dma_buf[i];
-                       rx_word ? (*(u16 *)dspi->rx = d) :
-                                               (*(u8 *)dspi->rx = d);
-                       dspi->rx += rx_word + 1;
-               }
+       if (dspi->rx) {
+               for (i = 0; i < dma->curr_xfer_len; i++)
+                       dspi_push_rx(dspi, dspi->dma->rx_dma_buf[i]);
        }
 
        complete(&dma->cmd_rx_complete);
@@ -249,16 +265,10 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
        struct fsl_dspi_dma *dma = dspi->dma;
        struct device *dev = &dspi->pdev->dev;
        int time_left;
-       int tx_word;
        int i;
 
-       tx_word = is_double_byte_mode(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;
-       }
+       for (i = 0; i < dma->curr_xfer_len; i++)
+               dspi->dma->tx_dma_buf[i] = dspi_pop_tx_pushr(dspi);
 
        dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
                                        dma->tx_dma_phys,
@@ -329,16 +339,14 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
        struct device *dev = &dspi->pdev->dev;
        int curr_remaining_bytes;
        int bytes_per_buffer;
-       int word = 1;
        int ret = 0;
 
-       if (is_double_byte_mode(dspi))
-               word = 2;
        curr_remaining_bytes = dspi->len;
        bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE;
        while (curr_remaining_bytes) {
                /* Check if current transfer fits the DMA buffer */
-               dma->curr_xfer_len = curr_remaining_bytes / word;
+               dma->curr_xfer_len = curr_remaining_bytes
+                       / dspi->bytes_per_word;
                if (dma->curr_xfer_len > bytes_per_buffer)
                        dma->curr_xfer_len = bytes_per_buffer;
 
@@ -348,7 +356,8 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
                        goto exit;
 
                } else {
-                       curr_remaining_bytes -= dma->curr_xfer_len * word;
+                       curr_remaining_bytes -= dma->curr_xfer_len
+                               * dspi->bytes_per_word;
                        if (curr_remaining_bytes < 0)
                                curr_remaining_bytes = 0;
                }
@@ -534,125 +543,56 @@ 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 void fifo_write(struct fsl_dspi *dspi)
 {
-       u16 d16;
-
-       if (!(dspi->dataflags & TRAN_STATE_TX_VOID))
-               d16 = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx;
-       else
-               d16 = dspi->void_write_data;
-
-       dspi->tx += tx_word + 1;
-       dspi->len -= tx_word + 1;
-
-       return  SPI_PUSHR_TXDATA(d16) |
-               SPI_PUSHR_PCS(dspi->cs) |
-               SPI_PUSHR_CTAS(0) |
-               SPI_PUSHR_CONT;
+       regmap_write(dspi->regmap, SPI_PUSHR, dspi_pop_tx_pushr(dspi));
 }
 
-static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word)
+static void dspi_tcfq_write(struct fsl_dspi *dspi)
 {
-       u16 d;
-       unsigned int val;
-
-       regmap_read(dspi->regmap, SPI_POPR, &val);
-       d = SPI_POPR_RXDATA(val);
-
-       if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
-               rx_word ? (*(u16 *)dspi->rx = d) : (*(u8 *)dspi->rx = d);
-
-       dspi->rx += rx_word + 1;
+       /* Clear transfer count */
+       dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
+       /* Write one entry to both TX FIFO and CMD FIFO simultaneously */
+       fifo_write(dspi);
 }
 
-static int dspi_eoq_write(struct fsl_dspi *dspi)
+static u32 fifo_read(struct fsl_dspi *dspi)
 {
-       int tx_count = 0;
-       int tx_word;
-       u32 dspi_pushr = 0;
-
-       tx_word = is_double_byte_mode(dspi);
-
-       while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) {
-               /* If we are in word mode, only have a single byte to transfer
-                * switch to byte mode temporarily.  Will switch back at the
-                * end of the transfer.
-                */
-               if (tx_word && (dspi->len == 1)) {
-                       dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
-                       regmap_update_bits(dspi->regmap, SPI_CTAR(0),
-                                       SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
-                       tx_word = 0;
-               }
-
-               dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
-
-               if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) {
-                       /* last transfer in the transfer */
-                       dspi_pushr |= SPI_PUSHR_EOQ;
-                       if ((dspi->cs_change) && (!dspi->len))
-                               dspi_pushr &= ~SPI_PUSHR_CONT;
-               } else if (tx_word && (dspi->len == 1))
-                       dspi_pushr |= SPI_PUSHR_EOQ;
-
-               regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
+       u32 rxdata = 0;
 
-               tx_count++;
-       }
-
-       return tx_count * (tx_word + 1);
+       regmap_read(dspi->regmap, SPI_POPR, &rxdata);
+       return rxdata;
 }
 
-static int dspi_eoq_read(struct fsl_dspi *dspi)
+static void dspi_tcfq_read(struct fsl_dspi *dspi)
 {
-       int rx_count = 0;
-       int rx_word = is_double_byte_mode(dspi);
-
-       while ((dspi->rx < dspi->rx_end)
-                       && (rx_count < DSPI_FIFO_SIZE)) {
-               if (rx_word && (dspi->rx_end - dspi->rx) == 1)
-                       rx_word = 0;
-
-               dspi_data_from_popr(dspi, rx_word);
-               rx_count++;
-       }
-
-       return rx_count;
+       dspi_push_rx(dspi, fifo_read(dspi));
 }
 
-static int dspi_tcfq_write(struct fsl_dspi *dspi)
+static void dspi_eoq_write(struct fsl_dspi *dspi)
 {
-       int tx_word;
-       u32 dspi_pushr = 0;
-
-       tx_word = is_double_byte_mode(dspi);
-
-       if (tx_word && (dspi->len == 1)) {
-               dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
-               regmap_update_bits(dspi->regmap, SPI_CTAR(0),
-                               SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
-               tx_word = 0;
+       int fifo_size = DSPI_FIFO_SIZE;
+
+       /* Fill TX FIFO with as many transfers as possible */
+       while (dspi->len && fifo_size--) {
+               /* Request EOQF for last transfer in FIFO */
+               if (dspi->len == dspi->bytes_per_word || fifo_size == 0)
+                       dspi->tx_cmd |= SPI_PUSHR_CMD_EOQ;
+               /* Clear transfer count for first transfer in FIFO */
+               if (fifo_size == (DSPI_FIFO_SIZE - 1))
+                       dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
+               /* Write combined TX FIFO and CMD FIFO entry */
+               fifo_write(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;
 }
 
-static void dspi_tcfq_read(struct fsl_dspi *dspi)
+static void dspi_eoq_read(struct fsl_dspi *dspi)
 {
-       int rx_word = is_double_byte_mode(dspi);
-
-       if (rx_word && (dspi->rx_end - dspi->rx) == 1)
-               rx_word = 0;
+       int fifo_size = DSPI_FIFO_SIZE;
 
-       dspi_data_from_popr(dspi, rx_word);
+       /* Read one FIFO entry at and push to rx buffer */
+       while ((dspi->rx < dspi->rx_end) && fifo_size--)
+               dspi_push_rx(dspi, fifo_read(dspi));
 }
 
 static int dspi_transfer_one_message(struct spi_master *master,
@@ -663,10 +603,6 @@ static int dspi_transfer_one_message(struct spi_master *master,
        struct spi_transfer *transfer;
        int status = 0;
        enum dspi_trans_mode trans_mode;
-       u32 spi_tcr;
-
-       regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
-       dspi->spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
 
        message->actual_length = 0;
 
@@ -674,32 +610,45 @@ 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;
-               dspi->tx = (void *)transfer->tx_buf;
-               dspi->tx_end = dspi->tx + transfer->len;
+               dspi->tx = transfer->tx_buf;
                dspi->rx = transfer->rx_buf;
                dspi->rx_end = dspi->rx + transfer->len;
                dspi->len = transfer->len;
+               /* Validated transfer specific frame size (defaults applied) */
+               dspi->bits_per_word = transfer->bits_per_word;
+               if (transfer->bits_per_word <= 8)
+                       dspi->bytes_per_word = 1;
+               else
+                       dspi->bytes_per_word = 2;
 
-               if (!dspi->rx)
-                       dspi->dataflags |= TRAN_STATE_RX_VOID;
-
-               if (!dspi->tx)
-                       dspi->dataflags |= TRAN_STATE_TX_VOID;
-
-               regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
                regmap_update_bits(dspi->regmap, SPI_MCR,
-                               SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
-                               SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
+                                  SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
+                                  SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
                regmap_write(dspi->regmap, SPI_CTAR(0),
-                               dspi->cur_chip->ctar_val);
+                            dspi->cur_chip->ctar_val |
+                            SPI_FRAME_BITS(transfer->bits_per_word));
 
                trans_mode = dspi->devtype_data->trans_mode;
                switch (trans_mode) {
@@ -750,16 +699,9 @@ static int dspi_setup(struct spi_device *spi)
        struct fsl_dspi_platform_data *pdata;
        u32 cs_sck_delay = 0, sck_cs_delay = 0;
        unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
-       unsigned char pasc = 0, asc = 0, fmsz = 0;
+       unsigned char pasc = 0, asc = 0;
        unsigned long clkrate;
 
-       if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
-               fmsz = spi->bits_per_word - 1;
-       } else {
-               pr_err("Invalid wordsize\n");
-               return -ENODEV;
-       }
-
        /* Only alloc on first setup */
        chip = spi_get_ctldata(spi);
        if (chip == NULL) {
@@ -781,9 +723,6 @@ static int dspi_setup(struct spi_device *spi)
                sck_cs_delay = pdata->sck_cs_delay;
        }
 
-       chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
-               SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
-
        chip->void_write_data = 0;
 
        clkrate = clk_get_rate(dspi->clk);
@@ -795,8 +734,7 @@ static int dspi_setup(struct spi_device *spi)
        /* Set After SCK delay scale values */
        ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate);
 
-       chip->ctar_val =  SPI_CTAR_FMSZ(fmsz)
-               | SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
+       chip->ctar_val = SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
                | SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0)
                | SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0)
                | SPI_CTAR_PCSSCK(pcssck)
@@ -827,36 +765,20 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
        struct spi_message *msg = dspi->cur_msg;
        enum dspi_trans_mode trans_mode;
        u32 spi_sr, spi_tcr;
-       u32 spi_tcnt, tcnt_diff;
-       int tx_word;
+       u16 spi_tcnt;
 
        regmap_read(dspi->regmap, SPI_SR, &spi_sr);
        regmap_write(dspi->regmap, SPI_SR, spi_sr);
 
 
        if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)) {
-               tx_word = is_double_byte_mode(dspi);
-
+               /* Get transfer counter (in number of SPI transfers). It was
+                * reset to 0 when transfer(s) were started.
+                */
                regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
                spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
-               /*
-                * The width of SPI Transfer Counter in SPI_TCR is 16bits,
-                * so the max couner is 65535. When the counter reach 65535,
-                * it will wrap around, counter reset to zero.
-                * spi_tcnt my be less than dspi->spi_tcnt, it means the
-                * counter already wrapped around.
-                * SPI Transfer Counter is a counter of transmitted frames.
-                * The size of frame maybe two bytes.
-                */
-               tcnt_diff = ((spi_tcnt + SPI_TCR_TCNT_MAX) - dspi->spi_tcnt)
-                       % SPI_TCR_TCNT_MAX;
-               tcnt_diff *= (tx_word + 1);
-               if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
-                       tcnt_diff--;
-
-               msg->actual_length += tcnt_diff;
-
-               dspi->spi_tcnt = spi_tcnt;
+               /* Update total number of bytes that were transferred */
+               msg->actual_length += spi_tcnt * dspi->bytes_per_word;
 
                trans_mode = dspi->devtype_data->trans_mode;
                switch (trans_mode) {
@@ -873,14 +795,6 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
                }
 
                if (!dspi->len) {
-                       if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) {
-                               regmap_update_bits(dspi->regmap,
-                                                  SPI_CTAR(0),
-                                                  SPI_FRAME_BITS_MASK,
-                                                  SPI_FRAME_BITS(16));
-                               dspi->dataflags &= ~TRAN_STATE_WORD_ODD_NUM;
-                       }
-
                        dspi->waitflags = 1;
                        wake_up_interruptible(&dspi->waitq);
                } else {
@@ -964,6 +878,7 @@ static const struct regmap_config dspi_regmap_config = {
 
 static void dspi_init(struct fsl_dspi *dspi)
 {
+       regmap_write(dspi->regmap, SPI_MCR, SPI_MCR_MASTER | SPI_MCR_PCSIS);
        regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
 }
 
@@ -992,8 +907,7 @@ static int dspi_probe(struct platform_device *pdev)
 
        master->cleanup = dspi_cleanup;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
-       master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) |
-                                       SPI_BPW_MASK(16);
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
 
        pdata = dev_get_platdata(&pdev->dev);
        if (pdata) {