summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrishna Yarlagadda <kyarlagadda@nvidia.com>2015-11-17 19:31:22 +0530
committerMatthew Pedro <mapedro@nvidia.com>2016-08-24 09:18:37 -0700
commitd0080959ebe08f3b4a0f0453eaa8c8c9dff4ae9d (patch)
tree0790b3dc3b2a03f7b5e9632bb2a946a0e1302720
parente2f168a5d0232c5d90af07bdf9e544c1e326f6ca (diff)
spi: tegra: support polling mode
Added support to use polling mode instead of interrupts through a property in dt Bug 1679083 Change-Id: Ic82ab592822cc96bacda05124d38ddd913e09af9 Reviewed-on: http://git-master/r/840233 (cherry picked from commit cd1c4db5adc8317572106099da37fa434245e699) Reviewed-on: http://git-master/r/1009988 (cherry picked from commit b29ce03a6b7ebb306ff157640470dd5ab99c6f6b) Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com> Reviewed-on: http://git-master/r/1175213 Reviewed-by: Matthew Pedro <mapedro@nvidia.com> Tested-by: Matthew Pedro <mapedro@nvidia.com>
-rw-r--r--Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt1
-rw-r--r--drivers/spi/spi-tegra114.c84
-rw-r--r--include/linux/spi/spi-tegra.h1
3 files changed, 74 insertions, 12 deletions
diff --git a/Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt b/Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt
index 04ed4dc8653c..e3c264d90502 100644
--- a/Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt
+++ b/Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt
@@ -12,6 +12,7 @@ Recommended properties:
Documentation/devicetree/bindings/spi/spi-bus.txt
Optional properties:
- nvidia,clock-always-on: Enable clock of spi always.
+- nvidia,polling-mode: Use polling method instead of interrupts
- nvidia,boost-reg-access: In T210 and earlier chips SPI register access
is dependant on SPI clock frequency. Setting this option would
allow SPI clock frequency to be boosted. Benefitial when running
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 576bf2cef68c..736d6f68d757 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -174,6 +174,7 @@
#define SPI_SPEED_TAP_DELAY_MARGIN 35000000
#define SPI_DEFAULT_RX_TAP_DELAY 10
#endif
+#define SPI_POLL_TIMEOUT 10000
struct tegra_spi_data {
struct device *dev;
@@ -185,6 +186,7 @@ struct tegra_spi_data {
phys_addr_t phys;
unsigned irq;
bool clock_always_on;
+ bool polling_mode;
bool boost_reg_access;
u32 spi_max_frequency;
u32 cur_speed;
@@ -236,6 +238,7 @@ struct tegra_spi_data {
static int tegra_spi_runtime_suspend(struct device *dev);
static int tegra_spi_runtime_resume(struct device *dev);
+static int tegra_spi_status_poll(struct tegra_spi_data *tspi);
static int tegra_spi_set_clock_rate(struct tegra_spi_data *tspi, u32 speed);
static inline unsigned long tegra_spi_readl(struct tegra_spi_data *tspi,
@@ -554,11 +557,12 @@ static int tegra_spi_start_dma_based_transfer(
else
val |= SPI_TX_TRIG_8 | SPI_RX_TRIG_8;
- if (tspi->cur_direction & DATA_DIR_TX)
- val |= SPI_IE_TX;
-
- if (tspi->cur_direction & DATA_DIR_RX)
- val |= SPI_IE_RX;
+ if (!tspi->polling_mode) {
+ if (tspi->cur_direction & DATA_DIR_TX)
+ val |= SPI_IE_TX;
+ if (tspi->cur_direction & DATA_DIR_RX)
+ val |= SPI_IE_RX;
+ }
tegra_spi_writel(tspi, val, SPI_DMA_CTL);
tspi->dma_control_reg = val;
@@ -622,11 +626,12 @@ static int tegra_spi_start_cpu_based_transfer(
tegra_spi_writel(tspi, val, SPI_DMA_BLK);
val = 0;
- if (tspi->cur_direction & DATA_DIR_TX)
- val |= SPI_IE_TX;
-
- if (tspi->cur_direction & DATA_DIR_RX)
- val |= SPI_IE_RX;
+ if (!tspi->polling_mode) {
+ if (tspi->cur_direction & DATA_DIR_TX)
+ val |= SPI_IE_TX;
+ if (tspi->cur_direction & DATA_DIR_RX)
+ val |= SPI_IE_RX;
+ }
tegra_spi_writel(tspi, val, SPI_DMA_CTL);
tspi->dma_control_reg = val;
@@ -1042,8 +1047,11 @@ static int tegra_spi_wait_on_message_xfer(struct tegra_spi_data *tspi)
{
int ret;
- ret = wait_for_completion_timeout(&tspi->xfer_completion,
- SPI_DMA_TIMEOUT);
+ if (tspi->polling_mode)
+ ret = tegra_spi_status_poll(tspi);
+ else
+ ret = wait_for_completion_timeout(&tspi->xfer_completion,
+ SPI_DMA_TIMEOUT);
if (WARN_ON(ret == 0)) {
dev_err(tspi->dev,
"spi trasfer timeout, err %d\n", ret);
@@ -1278,6 +1286,9 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
{
struct tegra_spi_data *tspi = context_data;
+ if (tspi->polling_mode)
+ dev_warn(tspi->dev, "interrupt raised in polling mode\n");
+
tegra_spi_clear_status(tspi);
if (tspi->cur_direction & DATA_DIR_TX)
tspi->tx_status = tspi->status_reg &
@@ -1301,6 +1312,51 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
return IRQ_HANDLED;
}
+static int tegra_spi_status_poll(struct tegra_spi_data *tspi)
+{
+ unsigned int status;
+ unsigned long timeout;
+
+ timeout = SPI_POLL_TIMEOUT;
+ /*
+ * Read register would take between 1~3us and 1us delay added in loop
+ * Calculate timeout taking this into consideration
+ */
+ do {
+ status = tegra_spi_readl(tspi, SPI_TRANS_STATUS);
+ if (status & SPI_RDY)
+ break;
+ timeout--;
+ udelay(1);
+ } while (timeout);
+
+ if (!timeout) {
+ dev_err(tspi->dev, "transfer timeout (polling)\n");
+ return 0;
+ }
+
+ 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);
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ tspi->rx_status = tspi->status_reg &
+ (SPI_RX_FIFO_OVF | SPI_RX_FIFO_UNF);
+
+ if (!(tspi->cur_direction & DATA_DIR_TX) &&
+ !(tspi->cur_direction & DATA_DIR_RX))
+ dev_err(tspi->dev, "spurious interrupt, status_reg = 0x%x\n",
+ tspi->status_reg);
+
+ if (!tspi->is_curr_dma_xfer)
+ handle_cpu_based_err_xfer(tspi);
+ else
+ handle_dma_based_err_xfer(tspi);
+
+ return timeout;
+}
+
static struct tegra_spi_platform_data *tegra_spi_parse_dt(
struct platform_device *pdev)
{
@@ -1321,6 +1377,9 @@ static struct tegra_spi_platform_data *tegra_spi_parse_dt(
if (of_find_property(np, "nvidia,clock-always-on", NULL))
pdata->is_clkon_always = true;
+ if (of_find_property(np, "nvidia,polling-mode", NULL))
+ pdata->is_polling_mode = true;
+
if (of_find_property(np, "nvidia,boost-reg-access", NULL))
pdata->boost_reg_access = true;
@@ -1382,6 +1441,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
tspi = spi_master_get_devdata(master);
tspi->master = master;
tspi->clock_always_on = pdata->is_clkon_always;
+ tspi->polling_mode = pdata->is_polling_mode;
tspi->boost_reg_access = pdata->boost_reg_access;
tspi->dev = &pdev->dev;
spin_lock_init(&tspi->lock);
diff --git a/include/linux/spi/spi-tegra.h b/include/linux/spi/spi-tegra.h
index 10e773094ce8..3e0203c2a671 100644
--- a/include/linux/spi/spi-tegra.h
+++ b/include/linux/spi/spi-tegra.h
@@ -25,6 +25,7 @@ struct tegra_spi_platform_data {
int dma_req_sel;
unsigned int spi_max_frequency;
bool is_clkon_always;
+ bool is_polling_mode;
bool boost_reg_access;
};