summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorKrishna Yarlagadda <kyarlagadda@nvidia.com>2016-02-08 19:18:17 +0530
committerMatthew Pedro <mapedro@nvidia.com>2016-08-24 09:14:45 -0700
commite2f168a5d0232c5d90af07bdf9e544c1e326f6ca (patch)
tree93204cfc43774d3162cdb5216033afe52de09ebf /drivers
parent08590cd62f8b63776f54cb8ad1b2d329e45341e5 (diff)
spi: tegra: Reduce register access
Reduce register accesses to SPI as it is dependent on slow, variable SPI clock frequency. Bug 1675619 Change-Id: I5d638b8f95d9207fbad1e30e21234fc7433e03b3 Reviewed-on: http://git-master/r/1009503 (cherry picked from commit 890a422a7b75507c33b53f1ca4c512f7911d61c4) Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com> Reviewed-on: http://git-master/r/1174582 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/spi-tegra114.c62
1 files changed, 43 insertions, 19 deletions
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 252635e8ff0f..576bf2cef68c 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -161,13 +161,14 @@
#define SPI_DMA_TIMEOUT (msecs_to_jiffies(10000))
#define DEFAULT_SPI_DMA_BUF_LEN (16*1024)
-#define TX_FIFO_EMPTY_COUNT_MAX SPI_TX_FIFO_EMPTY_COUNT(0x40)
-#define RX_FIFO_FULL_COUNT_ZERO SPI_RX_FIFO_FULL_COUNT(0)
+#define TX_FIFO_EMPTY_COUNT_MAX (0x40)
+#define RX_FIFO_FULL_COUNT_ZERO (0)
#define MAX_HOLD_CYCLES 16
#define SPI_DEFAULT_SPEED 25000000
#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
@@ -203,6 +204,7 @@ struct tegra_spi_data {
unsigned max_buf_size;
bool is_curr_dma_xfer;
bool is_hw_based_cs;
+ bool transfer_in_progress;
struct completion rx_dma_complete;
struct completion tx_dma_complete;
@@ -248,7 +250,7 @@ static inline void tegra_spi_writel(struct tegra_spi_data *tspi,
writel(val, tspi->base + reg);
/* Read back register to make sure that register writes completed */
- if (reg != SPI_TX_FIFO)
+ if ((reg == SPI_COMMAND1) && (val & SPI_PIO))
readl(tspi->base + SPI_COMMAND1);
}
@@ -258,11 +260,12 @@ static void tegra_spi_clear_status(struct tegra_spi_data *tspi)
/* Write 1 to clear status register */
val = tegra_spi_readl(tspi, SPI_TRANS_STATUS);
- tegra_spi_writel(tspi, val, SPI_TRANS_STATUS);
+ if (val & SPI_RDY)
+ tegra_spi_writel(tspi, val, SPI_TRANS_STATUS);
/* Clear fifo status error if any */
- val = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
- if (val & SPI_ERR)
+ tspi->status_reg = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+ if (tspi->status_reg & SPI_ERR)
tegra_spi_writel(tspi, SPI_ERR | SPI_FIFO_ERROR,
SPI_FIFO_STATUS);
}
@@ -307,7 +310,6 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf(
{
unsigned nbytes;
unsigned tx_empty_count;
- unsigned long fifo_status;
unsigned max_n_32bit;
unsigned i, count;
unsigned long x;
@@ -315,8 +317,7 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf(
unsigned fifo_words_left;
u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos;
- fifo_status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
- tx_empty_count = SPI_TX_FIFO_EMPTY_COUNT(fifo_status);
+ tx_empty_count = TX_FIFO_EMPTY_COUNT_MAX;
if (tspi->is_packed) {
fifo_words_left = tx_empty_count * tspi->words_per_32bit;
@@ -356,7 +357,7 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf(
unsigned len;
u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_rx_pos;
- fifo_status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+ fifo_status = tspi->status_reg;
rx_full_count = SPI_RX_FIFO_FULL_COUNT(fifo_status);
if (tspi->is_packed) {
len = tspi->curr_dma_words * tspi->bytes_per_word;
@@ -498,22 +499,43 @@ 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_clear_fifo(struct tegra_spi_data *tspi)
{
- unsigned long val;
- unsigned int len;
- int ret = 0;
unsigned long status;
- u32 speed;
+ int cnt = SPI_FIFO_FLUSH_MAX_DELAY;
/* Make sure that Rx and Tx fifo are empty */
- status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+ status = tspi->status_reg;
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) {
+ tspi->status_reg = status;
+ 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 int len;
+ int ret = 0;
+ u32 speed;
+
+ ret = tegra_spi_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);
@@ -876,6 +898,8 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
dev_dbg(tspi->dev, "The def 0x%x and written 0x%lx\n",
tspi->def_command1_reg, command1);
+ tspi->status_reg = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+
if (total_fifo_words > SPI_FIFO_DEPTH)
ret = tegra_spi_start_dma_based_transfer(tspi, t);
else
@@ -1034,6 +1058,7 @@ static int tegra_spi_wait_on_message_xfer(struct tegra_spi_data *tspi)
}
if (tspi->tx_status || tspi->rx_status) {
dev_err(tspi->dev, "Error in Transfer\n");
+ tegra_spi_clear_fifo(tspi);
ret = -EIO;
}
@@ -1253,7 +1278,7 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
{
struct tegra_spi_data *tspi = context_data;
- tspi->status_reg = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+ tegra_spi_clear_status(tspi);
if (tspi->cur_direction & DATA_DIR_TX)
tspi->tx_status = tspi->status_reg &
(SPI_TX_FIFO_UNF | SPI_TX_FIFO_OVF);
@@ -1267,7 +1292,6 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
dev_err(tspi->dev, "spurious interrupt, status_reg = 0x%x\n",
tspi->status_reg);
- tegra_spi_clear_status(tspi);
if (!tspi->is_curr_dma_xfer)
handle_cpu_based_err_xfer(tspi);
else