summaryrefslogtreecommitdiff
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
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>
-rw-r--r--Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt4
-rw-r--r--drivers/spi/spi-tegra114.c63
-rw-r--r--include/linux/spi/spi-tegra.h3
3 files changed, 64 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt b/Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt
index 2d961d8e3d69..04ed4dc8653c 100644
--- a/Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt
+++ b/Documentation/devicetree/bindings/spi/nvidia,spi-tegra114.txt
@@ -12,6 +12,10 @@ Recommended properties:
Documentation/devicetree/bindings/spi/spi-bus.txt
Optional properties:
- nvidia,clock-always-on: Enable clock of spi always.
+- 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
+ SPI at low frequencies with cpu based transfers. Default false.
spi-client device controller properties:
- nvidia,enable-hw-based-cs: (Boolean) Use the HW based CS if enabled.
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);
diff --git a/include/linux/spi/spi-tegra.h b/include/linux/spi/spi-tegra.h
index 4b9385d2c93d..10e773094ce8 100644
--- a/include/linux/spi/spi-tegra.h
+++ b/include/linux/spi/spi-tegra.h
@@ -1,7 +1,7 @@
/*
* spi-tegra.h: SPI interface for Nvidia Tegra20 SLINK controller.
*
- * Copyright (C) 2011 NVIDIA Corporation
+ * Copyright (c) 2011-2016, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@ struct tegra_spi_platform_data {
int dma_req_sel;
unsigned int spi_max_frequency;
bool is_clkon_always;
+ bool boost_reg_access;
};
/*