]> nv-tegra.nvidia Code Review - linux-3.10.git/commitdiff
spi: tegra114: flush rx/tx fifo if not empty
authorYousuf A <yousufa@nvidia.com>
Mon, 28 Apr 2014 05:40:58 +0000 (11:10 +0530)
committerLaxman Dewangan <ldewangan@nvidia.com>
Mon, 19 May 2014 12:29:37 +0000 (05:29 -0700)
This fix flushes rx/tx fifo if they are not empty before a transfer

Bug 1506112
Change-Id: Ic43b33dfe9158533235c03d702265e4ee468c39d
Signed-off-by: Yousuf A <yousufa@nvidia.com>
Reviewed-on: http://git-master/r/400842
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Tested-by: Laxman Dewangan <ldewangan@nvidia.com>
drivers/spi/spi-tegra114.c

index 7a0a92521cf901304138aa200013e62d4ba322ec..744a04aa5ec2605ff8df7d3e9b82e7051b02f600 100644 (file)
 
 #define MAX_CHIP_SELECT                                4
 #define SPI_FIFO_DEPTH                         64
+#define SPI_FIFO_FLUSH_MAX_DELAY               2000
 
 #ifdef CONFIG_ARCH_TEGRA_12x_SOC
 #define SPI_SPEED_TAP_DELAY_MARGIN 35000000
@@ -523,22 +524,42 @@ static int tegra_spi_start_rx_dma(struct tegra_spi_data *tspi, int len)
        return 0;
 }
 
-static int tegra_spi_start_dma_based_transfer(
-               struct tegra_spi_data *tspi, struct spi_transfer *t)
+static int check_and_clear_fifo(struct tegra_spi_data *tspi)
 {
-       unsigned long val;
-       unsigned long intr_mask;
-       unsigned int len;
-       int ret = 0;
        unsigned long status;
+       int cnt = SPI_FIFO_FLUSH_MAX_DELAY;
 
        /* Make sure that Rx and Tx fifo are empty */
        status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
        if ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) {
+               /* flush the fifo */
+               status |= (SPI_RX_FIFO_FLUSH | SPI_TX_FIFO_FLUSH);
+               tegra_spi_writel(tspi, status, SPI_FIFO_STATUS);
+               do {
+                       status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+                       if ((status & SPI_FIFO_EMPTY) == SPI_FIFO_EMPTY)
+                               return 0;
+                       udelay(1);
+               } while (cnt--);
                dev_err(tspi->dev,
                        "Rx/Tx fifo are not empty status 0x%08lx\n", status);
                return -EIO;
        }
+       return 0;
+}
+
+static int tegra_spi_start_dma_based_transfer(
+               struct tegra_spi_data *tspi, struct spi_transfer *t)
+{
+       unsigned long val;
+       unsigned long intr_mask;
+       unsigned int len;
+       int ret = 0;
+
+       /* Make sure that Rx and Tx fifo are empty */
+       ret = check_and_clear_fifo(tspi);
+       if (ret != 0)
+               return ret;
 
        val = SPI_DMA_BLK_SET(tspi->curr_dma_words - 1);
        tegra_spi_writel(tspi, val, SPI_DMA_BLK);
@@ -616,6 +637,11 @@ static int tegra_spi_start_cpu_based_transfer(
        unsigned long val;
        unsigned long intr_mask;
        unsigned cur_words;
+       int ret;
+
+       ret = check_and_clear_fifo(tspi);
+       if (ret != 0)
+               return ret;
 
        if (tspi->cur_direction & DATA_DIR_TX)
                cur_words = tegra_spi_fill_tx_fifo_from_client_txbuf(tspi, t);
@@ -981,6 +1007,7 @@ static int tegra_spi_setup(struct spi_device *spi)
                val &= ~cs_pol_bit[spi->chip_select];
        else
                val |= cs_pol_bit[spi->chip_select];
+
        tspi->def_command1_reg = val;
        tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
        spin_unlock_irqrestore(&tspi->lock, flags);