From 57127ec8fbdb77a946e3f362c172f6d2aa53fa23 Mon Sep 17 00:00:00 2001 From: Shardar Shariff Md Date: Wed, 4 Nov 2015 02:39:10 +0530 Subject: [PATCH] i2c: tegra: override slcg for Master core logic - override(disable) 2nd-level clock for I2C master core logic i.e keeping 2nd-level clock always ON when bus is operating in multi-master mode. Bug 200146630 Change-Id: I04840c2a0453ecbf5c10a9ea0e0f3d0523c5071a Signed-off-by: Shardar Shariff Md Reviewed-on: http://git-master/r/842347 (cherry picked from commit 115380a0fff228cb606e135e703d87c297070835) Reviewed-on: http://git-master/r/1190655 GVS: Gerrit_Virtual_Submit Reviewed-by: Laxman Dewangan --- drivers/i2c/busses/i2c-tegra.c | 21 +++++++++++++++++++++ include/linux/i2c-tegra.h | 1 + 2 files changed, 22 insertions(+) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 8da070b93c2..1fc688493e9 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -137,6 +137,9 @@ #define I2C_SLV_CONFIG_LOAD (1 << 1) #define I2C_TIMEOUT_CONFIG_LOAD (1 << 2) +#define I2C_CLKEN_OVERRIDE 0x090 +#define I2C_MST_CORE_CLKEN_OVR (1 << 0) + #define SL_ADDR1(addr) (addr & 0xff) #define SL_ADDR2(addr) ((addr >> 8) & 0xff) @@ -168,6 +171,7 @@ struct tegra_i2c_chipdata { int clk_multiplier_hs_mode; bool has_config_load_reg; bool has_multi_master_en_bit; + bool has_clk_override_reg; }; /** @@ -240,6 +244,7 @@ struct tegra_i2c_dev { bool is_shutdown; struct notifier_block pm_nb; struct tegra_prod_list *prod_list; + bool is_multimaster_mode; }; static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg) @@ -730,6 +735,9 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (tegra_i2c_flush_fifos(i2c_dev)) err = -ETIMEDOUT; + if (i2c_dev->is_multimaster_mode && i2c_dev->chipdata->has_clk_override_reg) + i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE); + if (i2c_dev->chipdata->has_config_load_reg) { i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD); timeout = jiffies + msecs_to_jiffies(1000); @@ -1480,6 +1488,12 @@ static struct tegra_i2c_platform_data *parse_i2c_tegra_dt( pdata->sda_gpio = of_get_named_gpio(np, "sda-gpio", 0); pdata->is_dvc = of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc"); + pdata->is_multimaster_mode = of_property_read_bool(np, + "nvidia,multimaster-mode"); + + if (pdata->is_multimaster_mode) + pdata->is_clkon_always = true; + /* Default configuration for device tree initiated driver */ pdata->slave_addr = 0xFC; return pdata; @@ -1497,6 +1511,7 @@ static struct tegra_i2c_chipdata tegra20_i2c_chipdata = { .clk_multiplier_hs_mode = 12, .has_config_load_reg = false, .has_multi_master_en_bit = false, + .has_clk_override_reg = false, }; static struct tegra_i2c_chipdata tegra30_i2c_chipdata = { @@ -1511,6 +1526,7 @@ static struct tegra_i2c_chipdata tegra30_i2c_chipdata = { .clk_multiplier_hs_mode = 12, .has_config_load_reg = false, .has_multi_master_en_bit = false, + .has_clk_override_reg = false, }; static struct tegra_i2c_chipdata tegra114_i2c_chipdata = { @@ -1526,6 +1542,7 @@ static struct tegra_i2c_chipdata tegra114_i2c_chipdata = { .clk_multiplier_hs_mode = 3, .has_config_load_reg = false, .has_multi_master_en_bit = false, + .has_clk_override_reg = false, }; static struct tegra_i2c_chipdata tegra148_i2c_chipdata = { @@ -1541,6 +1558,7 @@ static struct tegra_i2c_chipdata tegra148_i2c_chipdata = { .clk_multiplier_hs_mode = 13, .has_config_load_reg = true, .has_multi_master_en_bit = false, + .has_clk_override_reg = true, }; static struct tegra_i2c_chipdata tegra124_i2c_chipdata = { @@ -1556,6 +1574,7 @@ static struct tegra_i2c_chipdata tegra124_i2c_chipdata = { .clk_multiplier_hs_mode = 13, .has_config_load_reg = true, .has_multi_master_en_bit = false, + .has_clk_override_reg = true, }; static struct tegra_i2c_chipdata tegra210_i2c_chipdata = { @@ -1571,6 +1590,7 @@ static struct tegra_i2c_chipdata tegra210_i2c_chipdata = { .clk_multiplier_hs_mode = 13, .has_config_load_reg = true, .has_multi_master_en_bit = true, + .has_clk_override_reg = true, }; /* Match table for of_platform binding */ @@ -1739,6 +1759,7 @@ skip_pinctrl: i2c_dev->irq = irq; i2c_dev->dev = &pdev->dev; i2c_dev->is_clkon_always = pdata->is_clkon_always; + i2c_dev->is_multimaster_mode = pdata->is_multimaster_mode; i2c_dev->bus_clk_rate = pdata->bus_clk_rate ? pdata->bus_clk_rate: 100000; i2c_dev->is_high_speed_enable = pdata->is_high_speed_enable; i2c_dev->clk_divisor_non_hs_mode = diff --git a/include/linux/i2c-tegra.h b/include/linux/i2c-tegra.h index 8e7e30ed785..3b75ec1d34c 100644 --- a/include/linux/i2c-tegra.h +++ b/include/linux/i2c-tegra.h @@ -34,6 +34,7 @@ struct tegra_i2c_platform_data { bool needs_cl_dvfs_clock; bool bit_banging_xfer_after_shutdown; bool is_interruptable_xfer; + bool is_multimaster_mode; }; struct tegra_i2c_slave_platform_data { -- 2.39.2