i2c: tegra: add support for fast plus (FM+) mode clock rate
authorLaxman Dewangan <ldewangan@nvidia.com>
Tue, 30 Jun 2015 10:54:27 +0000 (16:24 +0530)
committerWolfram Sang <wsa@the-dreams.de>
Mon, 10 Aug 2015 06:37:33 +0000 (08:37 +0200)
Tegra I2C controller required to configure the clock divisor
register inside controller to different value based on the clock
speed. The recommended clock divisor for the I2C controller for
standard/fast mode is 0x19 and for fast-mode plus is 0x10.

Add support to configure clock divisor register of I2C controller
based on bus clock rate.

This clock divisor is supported form T114 onwards.

Signed-off-by: Chaitanya Bandi <bandik@nvidia.com>
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Tested-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
drivers/i2c/busses/i2c-tegra.c

index 348870acfef237ec064be7ae33d08eba9ec2bb83..b7e1a365542100c6b2bc6bf12184a4e8fd3d4103 100644 (file)
@@ -142,6 +142,7 @@ struct tegra_i2c_hw_feature {
        bool has_config_load_reg;
        int clk_divisor_hs_mode;
        int clk_divisor_std_fast_mode;
+       u16 clk_divisor_fast_plus_mode;
 };
 
 /**
@@ -181,6 +182,7 @@ struct tegra_i2c_dev {
        size_t msg_buf_remaining;
        int msg_read;
        u32 bus_clk_rate;
+       u16 clk_divisor_non_hs_mode;
        bool is_suspended;
 };
 
@@ -441,7 +443,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 
        /* Make sure clock divisor programmed correctly */
        clk_divisor = i2c_dev->hw->clk_divisor_hs_mode;
-       clk_divisor |= i2c_dev->hw->clk_divisor_std_fast_mode <<
+       clk_divisor |= i2c_dev->clk_divisor_non_hs_mode <<
                                        I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT;
        i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR);
 
@@ -703,6 +705,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
        .has_single_clk_source = false,
        .clk_divisor_hs_mode = 3,
        .clk_divisor_std_fast_mode = 0,
+       .clk_divisor_fast_plus_mode = 0,
        .has_config_load_reg = false,
 };
 
@@ -712,6 +715,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
        .has_single_clk_source = false,
        .clk_divisor_hs_mode = 3,
        .clk_divisor_std_fast_mode = 0,
+       .clk_divisor_fast_plus_mode = 0,
        .has_config_load_reg = false,
 };
 
@@ -721,6 +725,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
        .has_single_clk_source = true,
        .clk_divisor_hs_mode = 1,
        .clk_divisor_std_fast_mode = 0x19,
+       .clk_divisor_fast_plus_mode = 0x10,
        .has_config_load_reg = false,
 };
 
@@ -730,6 +735,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
        .has_single_clk_source = true,
        .clk_divisor_hs_mode = 1,
        .clk_divisor_std_fast_mode = 0x19,
+       .clk_divisor_fast_plus_mode = 0x10,
        .has_config_load_reg = true,
 };
 
@@ -828,7 +834,14 @@ static int tegra_i2c_probe(struct platform_device *pdev)
                }
        }
 
-       clk_multiplier *= (i2c_dev->hw->clk_divisor_std_fast_mode + 1);
+       i2c_dev->clk_divisor_non_hs_mode =
+                       i2c_dev->hw->clk_divisor_std_fast_mode;
+       if (i2c_dev->hw->clk_divisor_fast_plus_mode &&
+               (i2c_dev->bus_clk_rate == 1000000))
+               i2c_dev->clk_divisor_non_hs_mode =
+                       i2c_dev->hw->clk_divisor_fast_plus_mode;
+
+       clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1);
        ret = clk_set_rate(i2c_dev->div_clk,
                           i2c_dev->bus_clk_rate * clk_multiplier);
        if (ret) {