Unverified Commit c4fc9e5b authored by Sowjanya Komatineni's avatar Sowjanya Komatineni Committed by Mark Brown
Browse files

spi: tegra114: flush fifos



Fixes: Flush TX and RX FIFOs before start of new transfer and on FIFO
overflow or underrun errors.

Signed-off-by: default avatarSowjanya Komatineni <skomatineni@nvidia.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 32bd1a95
Loading
Loading
Loading
Loading
+30 −9
Original line number Diff line number Diff line
@@ -499,22 +499,37 @@ 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 tegra_spi_flush_fifos(struct tegra_spi_data *tspi)
{
	u32 val;
	unsigned int len;
	int ret = 0;
	unsigned long timeout = jiffies + HZ;
	u32 status;

	/* 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) {
		dev_err(tspi->dev, "Rx/Tx fifo are not empty status 0x%08x\n",
			(unsigned)status);
		status |= SPI_RX_FIFO_FLUSH | SPI_TX_FIFO_FLUSH;
		tegra_spi_writel(tspi, status, SPI_FIFO_STATUS);
		while ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) {
			status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
			if (time_after(jiffies, timeout)) {
				dev_err(tspi->dev,
					"timeout waiting for fifo flush\n");
				return -EIO;
			}

			udelay(1);
		}
	}

	return 0;
}

static int tegra_spi_start_dma_based_transfer(
		struct tegra_spi_data *tspi, struct spi_transfer *t)
{
	u32 val;
	unsigned int len;
	int ret = 0;

	val = SPI_DMA_BLK_SET(tspi->curr_dma_words - 1);
	tegra_spi_writel(tspi, val, SPI_DMA_BLK);

@@ -779,6 +794,9 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
	dev_dbg(tspi->dev, "The def 0x%x and written 0x%x\n",
		tspi->def_command1_reg, (unsigned)command1);

	ret = tegra_spi_flush_fifos(tspi);
	if (ret < 0)
		return ret;
	if (total_fifo_words > SPI_FIFO_DEPTH)
		ret = tegra_spi_start_dma_based_transfer(tspi, t);
	else
@@ -876,6 +894,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
			    (tspi->cur_direction & DATA_DIR_RX))
				dmaengine_terminate_all(tspi->rx_dma_chan);
			ret = -EIO;
			tegra_spi_flush_fifos(tspi);
			reset_control_assert(tspi->rst);
			udelay(2);
			reset_control_deassert(tspi->rst);
@@ -929,6 +948,7 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi)
			tspi->status_reg);
		dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n",
			tspi->command1_reg, tspi->dma_control_reg);
		tegra_spi_flush_fifos(tspi);
		reset_control_assert(tspi->rst);
		udelay(2);
		reset_control_deassert(tspi->rst);
@@ -1001,6 +1021,7 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi)
			tspi->status_reg);
		dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n",
			tspi->command1_reg, tspi->dma_control_reg);
		tegra_spi_flush_fifos(tspi);
		reset_control_assert(tspi->rst);
		udelay(2);
		reset_control_deassert(tspi->rst);