]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/spi/spi-fsl-lpspi.c
Merge branch 'for-5.0' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[linux.git] / drivers / spi / spi-fsl-lpspi.c
index 08dcc3c22e8836c0a2032d0f5fb963d811461879..3918639140436e16707f854d8a5a5b9725515ce7 100644 (file)
 #define CR_RTF         BIT(8)
 #define CR_RST         BIT(1)
 #define CR_MEN         BIT(0)
+#define SR_MBF         BIT(24)
 #define SR_TCF         BIT(10)
+#define SR_FCF         BIT(9)
 #define SR_RDF         BIT(1)
 #define SR_TDF         BIT(0)
 #define IER_TCIE       BIT(10)
+#define IER_FCIE       BIT(9)
 #define IER_RDIE       BIT(1)
 #define IER_TDIE       BIT(0)
 #define CFGR1_PCSCFG   BIT(27)
@@ -59,6 +62,7 @@
 #define CFGR1_PCSPOL   BIT(8)
 #define CFGR1_NOSTALL  BIT(3)
 #define CFGR1_MASTER   BIT(0)
+#define FSR_RXCOUNT    (BIT(16)|BIT(17)|BIT(18))
 #define RSR_RXEMPTY    BIT(1)
 #define TCR_CPOL       BIT(31)
 #define TCR_CPHA       BIT(30)
@@ -161,28 +165,10 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
        return 0;
 }
 
-static int fsl_lpspi_txfifo_empty(struct fsl_lpspi_data *fsl_lpspi)
-{
-       u32 txcnt;
-       unsigned long orig_jiffies = jiffies;
-
-       do {
-               txcnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff;
-
-               if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
-                       dev_dbg(fsl_lpspi->dev, "txfifo empty timeout\n");
-                       return -ETIMEDOUT;
-               }
-               cond_resched();
-
-       } while (txcnt);
-
-       return 0;
-}
-
 static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
 {
        u8 txfifo_cnt;
+       u32 temp;
 
        txfifo_cnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff;
 
@@ -193,9 +179,15 @@ static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
                txfifo_cnt++;
        }
 
-       if (!fsl_lpspi->remain && (txfifo_cnt < fsl_lpspi->txfifosize))
-               writel(0, fsl_lpspi->base + IMX7ULP_TDR);
-       else
+       if (txfifo_cnt < fsl_lpspi->txfifosize) {
+               if (!fsl_lpspi->is_slave) {
+                       temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
+                       temp &= ~TCR_CONTC;
+                       writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
+               }
+
+               fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE);
+       } else
                fsl_lpspi_intctrl(fsl_lpspi, IER_TDIE);
 }
 
@@ -276,10 +268,6 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
        u32 temp;
        int ret;
 
-       temp = CR_RST;
-       writel(temp, fsl_lpspi->base + IMX7ULP_CR);
-       writel(0, fsl_lpspi->base + IMX7ULP_CR);
-
        if (!fsl_lpspi->is_slave) {
                ret = fsl_lpspi_set_bitrate(fsl_lpspi);
                if (ret)
@@ -370,6 +358,24 @@ static int fsl_lpspi_wait_for_completion(struct spi_controller *controller)
        return 0;
 }
 
+static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi)
+{
+       u32 temp;
+
+       /* Disable all interrupt */
+       fsl_lpspi_intctrl(fsl_lpspi, 0);
+
+       /* W1C for all flags in SR */
+       temp = 0x3F << 8;
+       writel(temp, fsl_lpspi->base + IMX7ULP_SR);
+
+       /* Clear FIFO and disable module */
+       temp = CR_RRF | CR_RTF;
+       writel(temp, fsl_lpspi->base + IMX7ULP_CR);
+
+       return 0;
+}
+
 static int fsl_lpspi_transfer_one(struct spi_controller *controller,
                                  struct spi_device *spi,
                                  struct spi_transfer *t)
@@ -391,11 +397,7 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller,
        if (ret)
                return ret;
 
-       ret = fsl_lpspi_txfifo_empty(fsl_lpspi);
-       if (ret)
-               return ret;
-
-       fsl_lpspi_read_rx_fifo(fsl_lpspi);
+       fsl_lpspi_reset(fsl_lpspi);
 
        return 0;
 }
@@ -408,7 +410,6 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
        struct spi_device *spi = msg->spi;
        struct spi_transfer *xfer;
        bool is_first_xfer = true;
-       u32 temp;
        int ret = 0;
 
        msg->status = 0;
@@ -428,13 +429,6 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
        }
 
 complete:
-       if (!fsl_lpspi->is_slave) {
-               /* de-assert SS, then finalize current message */
-               temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
-               temp &= ~TCR_CONTC;
-               writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
-       }
-
        msg->status = ret;
        spi_finalize_current_message(controller);
 
@@ -443,20 +437,30 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 
 static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
 {
+       u32 temp_SR, temp_IER;
        struct fsl_lpspi_data *fsl_lpspi = dev_id;
-       u32 temp;
 
+       temp_IER = readl(fsl_lpspi->base + IMX7ULP_IER);
        fsl_lpspi_intctrl(fsl_lpspi, 0);
-       temp = readl(fsl_lpspi->base + IMX7ULP_SR);
+       temp_SR = readl(fsl_lpspi->base + IMX7ULP_SR);
 
        fsl_lpspi_read_rx_fifo(fsl_lpspi);
 
-       if (temp & SR_TDF) {
+       if ((temp_SR & SR_TDF) && (temp_IER & IER_TDIE)) {
                fsl_lpspi_write_tx_fifo(fsl_lpspi);
+               return IRQ_HANDLED;
+       }
 
-               if (!fsl_lpspi->remain)
-                       complete(&fsl_lpspi->xfer_done);
+       if (temp_SR & SR_MBF ||
+           readl(fsl_lpspi->base + IMX7ULP_FSR) & FSR_RXCOUNT) {
+               writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
+               fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE);
+               return IRQ_HANDLED;
+       }
 
+       if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) {
+               writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
+                       complete(&fsl_lpspi->xfer_done);
                return IRQ_HANDLED;
        }