summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
authorKrishna Yarlagadda <kyarlagadda@nvidia.com>2016-02-08 16:47:35 +0530
committerMatthew Pedro <mapedro@nvidia.com>2016-08-24 09:13:22 -0700
commit08590cd62f8b63776f54cb8ad1b2d329e45341e5 (patch)
tree6cf0b3bc6df832a15a563c29705cee0e1c4ad6ce /drivers/spi
parent64d410cfe6de23abfcc060de096f658a254fa870 (diff)
spi: tegra: option to boost register access
SPI register access for T210 and earlier chips depend on SPI clock frequency. Provided an option to set SPI clock at max frequency for register access. Bug 1675625 Change-Id: Ie52c83cd4602604822462d9f02ddf31ead83aafc Reviewed-on: http://git-master/r/1009782 (cherry picked from commit a2ccd28f2850538064668568432fee5d70a22e82) Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com> Reviewed-on: http://git-master/r/1174581 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-tegra114.c63
1 files changed, 58 insertions, 5 deletions
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 5f693d0ddfbc..252635e8ff0f 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -1,7 +1,7 @@
/*
* SPI driver for NVIDIA's Tegra114 SPI Controller.
*
- * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -184,6 +184,7 @@ struct tegra_spi_data {
phys_addr_t phys;
unsigned irq;
bool clock_always_on;
+ bool boost_reg_access;
u32 spi_max_frequency;
u32 cur_speed;
@@ -233,6 +234,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_set_clock_rate(struct tegra_spi_data *tspi, u32 speed);
static inline unsigned long tegra_spi_readl(struct tegra_spi_data *tspi,
unsigned long reg)
@@ -503,6 +505,7 @@ static int tegra_spi_start_dma_based_transfer(
unsigned int len;
int ret = 0;
unsigned long status;
+ u32 speed;
/* Make sure that Rx and Tx fifo are empty */
status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
@@ -562,6 +565,15 @@ static int tegra_spi_start_dma_based_transfer(
return ret;
}
}
+
+ if (tspi->boost_reg_access) {
+ speed = t->speed_hz ? t->speed_hz :
+ tspi->cur_spi->max_speed_hz;
+ ret = tegra_spi_set_clock_rate(tspi, speed);
+ if (ret < 0)
+ return ret;
+ }
+
tspi->is_curr_dma_xfer = true;
tspi->dma_control_reg = val;
@@ -575,6 +587,9 @@ static int tegra_spi_start_cpu_based_transfer(
{
unsigned long val;
unsigned cur_words;
+ int ret = 0;
+ u32 speed;
+
if (tspi->cur_direction & DATA_DIR_TX)
cur_words = tegra_spi_fill_tx_fifo_from_client_txbuf(tspi, t);
@@ -594,6 +609,14 @@ static int tegra_spi_start_cpu_based_transfer(
tegra_spi_writel(tspi, val, SPI_DMA_CTL);
tspi->dma_control_reg = val;
+ if (tspi->boost_reg_access) {
+ speed = t->speed_hz ? t->speed_hz :
+ tspi->cur_spi->max_speed_hz;
+ ret = tegra_spi_set_clock_rate(tspi, speed);
+ if (ret < 0)
+ return ret;
+ }
+
tspi->is_curr_dma_xfer = false;
val = tspi->command1_reg;
val |= SPI_PIO;
@@ -685,6 +708,22 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
dma_release_channel(dma_chan);
}
+static int tegra_spi_set_clock_rate(struct tegra_spi_data *tspi, u32 speed)
+{
+ int ret;
+
+ if (speed == tspi->cur_speed)
+ return 0;
+ ret = clk_set_rate(tspi->clk, speed);
+ if (ret) {
+ dev_err(tspi->dev, "Failed to set clk freq %d\n", ret);
+ return -EINVAL;
+ }
+ tspi->cur_speed = speed;
+
+ return 0;
+}
+
static int tegra_spi_start_transfer_one(struct spi_device *spi,
struct spi_transfer *t, bool is_first_of_msg,
bool is_single_xfer)
@@ -702,10 +741,13 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
if (!speed)
speed = tspi->spi_max_frequency;
- if (speed != tspi->cur_speed) {
- clk_set_rate(tspi->clk, speed);
- tspi->cur_speed = speed;
- }
+ /* set max clock for faster register access */
+ if (tspi->boost_reg_access)
+ ret = tegra_spi_set_clock_rate(tspi, tspi->spi_max_frequency);
+ else
+ ret = tegra_spi_set_clock_rate(tspi, speed);
+ if (ret < 0)
+ return ret;
tspi->cur_spi = spi;
tspi->cur_pos = 0;
@@ -1029,6 +1071,13 @@ static int tegra_spi_handle_message(struct tegra_spi_data *tspi,
int ret = 0;
long wait_status;
+ if (tspi->boost_reg_access) {
+ /* set max clock for faster register access */
+ ret = tegra_spi_set_clock_rate(tspi, tspi->spi_max_frequency);
+ if (ret < 0)
+ return ret;
+ }
+
if (!tspi->is_curr_dma_xfer) {
if (tspi->cur_direction & DATA_DIR_RX)
tegra_spi_read_rx_fifo_to_client_rxbuf(tspi, xfer);
@@ -1248,6 +1297,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,boost-reg-access", NULL))
+ pdata->boost_reg_access = true;
+
return pdata;
}
@@ -1306,6 +1358,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->boost_reg_access = pdata->boost_reg_access;
tspi->dev = &pdev->dev;
spin_lock_init(&tspi->lock);