Merge tag 'x86-apic-2021-06-28' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / spi / spi-rockchip.c
index 52d6259..540861c 100644 (file)
 #define CR0_OPM_MASTER                         0x0
 #define CR0_OPM_SLAVE                          0x1
 
+#define CR0_SOI_OFFSET                         23
+
 #define CR0_MTM_OFFSET                         0x21
 
 /* Bit fields in SER, 2bit */
 #define BAUDR_SCKDV_MIN                                2
 #define BAUDR_SCKDV_MAX                                65534
 
-/* Bit fields in SR, 5bit */
-#define SR_MASK                                                0x1f
+/* Bit fields in SR, 6bit */
+#define SR_MASK                                                0x3f
 #define SR_BUSY                                                (1 << 0)
 #define SR_TF_FULL                                     (1 << 1)
 #define SR_TF_EMPTY                                    (1 << 2)
 #define SR_RF_EMPTY                                    (1 << 3)
 #define SR_RF_FULL                                     (1 << 4)
+#define SR_SLAVE_TX_BUSY                               (1 << 5)
 
 /* Bit fields in ISR, IMR, ISR, RISR, 5bit */
 #define INT_MASK                                       0x1f
  */
 #define ROCKCHIP_SPI_MAX_TRANLEN               0xffff
 
-#define ROCKCHIP_SPI_MAX_CS_NUM                        2
+/* 2 for native cs, 2 for cs-gpio */
+#define ROCKCHIP_SPI_MAX_CS_NUM                        4
 #define ROCKCHIP_SPI_VER2_TYPE1                        0x05EC0002
 #define ROCKCHIP_SPI_VER2_TYPE2                        0x00110002
 
@@ -197,13 +201,19 @@ static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
        writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
 }
 
-static inline void wait_for_idle(struct rockchip_spi *rs)
+static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool slave_mode)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(5);
 
        do {
-               if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))
-                       return;
+               if (slave_mode) {
+                       if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_SLAVE_TX_BUSY) &&
+                           !((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)))
+                               return;
+               } else {
+                       if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))
+                               return;
+               }
        } while (!time_after(jiffies, timeout));
 
        dev_warn(rs->dev, "spi controller is in busy state!\n");
@@ -228,7 +238,7 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
 {
        struct spi_controller *ctlr = spi->controller;
        struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
-       bool cs_asserted = !enable;
+       bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable;
 
        /* Return immediately for no-op */
        if (cs_asserted == rs->cs_asserted[spi->chip_select])
@@ -238,11 +248,15 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
                /* Keep things powered as long as CS is asserted */
                pm_runtime_get_sync(rs->dev);
 
-               ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER,
-                                     BIT(spi->chip_select));
+               if (spi->cs_gpiod)
+                       ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, 1);
+               else
+                       ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select));
        } else {
-               ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER,
-                                     BIT(spi->chip_select));
+               if (spi->cs_gpiod)
+                       ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, 1);
+               else
+                       ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select));
 
                /* Drop reference from when we first asserted CS */
                pm_runtime_put(rs->dev);
@@ -383,7 +397,7 @@ static void rockchip_spi_dma_txcb(void *data)
                return;
 
        /* Wait until the FIFO data completely. */
-       wait_for_idle(rs);
+       wait_for_tx_idle(rs, ctlr->slave);
 
        spi_enable_chip(rs, false);
        spi_finalize_current_transfer(ctlr);
@@ -495,6 +509,8 @@ static int rockchip_spi_config(struct rockchip_spi *rs,
        cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
        if (spi->mode & SPI_LSB_FIRST)
                cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET;
+       if (spi->mode & SPI_CS_HIGH)
+               cr0 |= BIT(spi->chip_select) << CR0_SOI_OFFSET;
 
        if (xfer->rx_buf && xfer->tx_buf)
                cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
@@ -540,12 +556,12 @@ static int rockchip_spi_config(struct rockchip_spi *rs,
         * interrupt exactly when the fifo is full doesn't seem to work,
         * so we need the strict inequality here
         */
-       if (xfer->len < rs->fifo_len)
-               writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
+       if ((xfer->len / rs->n_bytes) < rs->fifo_len)
+               writel_relaxed(xfer->len / rs->n_bytes - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
        else
                writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
 
-       writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR);
+       writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
        writel_relaxed(rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes) - 1,
                       rs->regs + ROCKCHIP_SPI_DMARDLR);
        writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
@@ -783,6 +799,14 @@ static int rockchip_spi_probe(struct platform_device *pdev)
                ctlr->can_dma = rockchip_spi_can_dma;
        }
 
+       switch (readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION)) {
+       case ROCKCHIP_SPI_VER2_TYPE2:
+               ctlr->mode_bits |= SPI_CS_HIGH;
+               break;
+       default:
+               break;
+       }
+
        ret = devm_spi_register_controller(&pdev->dev, ctlr);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to register controller\n");
@@ -922,6 +946,7 @@ static const struct of_device_id rockchip_spi_dt_match[] = {
        { .compatible = "rockchip,rk3368-spi", },
        { .compatible = "rockchip,rk3399-spi", },
        { .compatible = "rockchip,rv1108-spi", },
+       { .compatible = "rockchip,rv1126-spi", },
        { },
 };
 MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);