On Mon, Mar 14, 2016 at 02:14:33PM +0530, Shardar Shariff Md wrote: > Enable multi-master mode in I2C_CNFG reg based on hw features. > Using single/multi-master mode bit introduced for Tegra210, > whereas multi-master mode is enabled by default in HW for T124 and > earlier Tegra SOC. Enabling this bit doesn't explicitly start > treating the bus has having multiple masters, but will start > checking for arbitration lost and reporting when it occurs. > > The Tegra210 I2C controller supports single/multi master mode. > Add chipdata for Tegra210 and its compatibility string so that > Tegra210 will select data that enables multi master mode correctly. > > Add "nvidia,multimaster-mode" property to enable multimaster specific > prerequisites: Please check Documentation/devicetree/bindings/i2c/i2c.txt. There is a generic "multi-master" binding already. > 1. Enable 1st level clock always set. > 2. Disable 2nd level clock gating (slcg which is supported from > T124 SOC and later chips) > > Signed-off-by: Shardar Shariff Md <smohammed@xxxxxxxxxx> > --- > drivers/i2c/busses/i2c-tegra.c | 70 ++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 64 insertions(+), 6 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c > index efba1eb..ce99d02 100644 > --- a/drivers/i2c/busses/i2c-tegra.c > +++ b/drivers/i2c/busses/i2c-tegra.c > @@ -38,6 +38,7 @@ > #define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 > #define I2C_CNFG_PACKET_MODE_EN (1<<10) > #define I2C_CNFG_NEW_MASTER_FSM (1<<11) > +#define I2C_CNFG_MULTI_MASTER_MODE (1<<17) > #define I2C_STATUS 0x01C > #define I2C_SL_CNFG 0x020 > #define I2C_SL_CNFG_NACK (1<<1) > @@ -133,6 +134,8 @@ struct tegra_i2c_hw_feature { > bool has_single_clk_source; > int clk_divisor_hs_mode; > int clk_divisor_std_fast_mode; > + bool has_multi_master_mode; > + bool has_slcg_override_reg; > }; > > /** > @@ -173,6 +176,7 @@ struct tegra_i2c_dev { > int msg_read; > u32 bus_clk_rate; > bool is_suspended; > + bool is_multimaster_mode; > }; > > static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg) > @@ -185,6 +189,9 @@ static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg) > return readl(i2c_dev->base + reg); > } > > +#define I2C_CLKEN_OVERRIDE 0x090 > +#define I2C_MST_CORE_CLKEN_OVR (1 << 0) > + > /* > * i2c_writel and i2c_readl will offset the register if necessary to talk > * to the I2C block inside the DVC block > @@ -424,6 +431,10 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) > > val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN | > (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); > + > + if (i2c_dev->hw->has_multi_master_mode) > + val |= I2C_CNFG_MULTI_MASTER_MODE; > + > i2c_writel(i2c_dev, val, I2C_CNFG); > i2c_writel(i2c_dev, 0, I2C_INT_MASK); > > @@ -449,6 +460,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->hw->has_slcg_override_reg) > + i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE); > + > tegra_i2c_clock_disable(i2c_dev); > > if (i2c_dev->irq_disabled) { > @@ -660,6 +674,20 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap) > return ret; > } > > +static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) > +{ > + struct device_node *np = i2c_dev->dev->of_node; > + int ret; > + > + ret = of_property_read_u32(np, "clock-frequency", > + &i2c_dev->bus_clk_rate); > + if (ret) > + i2c_dev->bus_clk_rate = 100000; /* default clock rate */ > + > + i2c_dev->is_multimaster_mode = of_property_read_bool(np, > + "nvidia,multimaster-mode"); > +} > + > static const struct i2c_algorithm tegra_i2c_algo = { > .master_xfer = tegra_i2c_xfer, > .functionality = tegra_i2c_func, > @@ -671,6 +699,8 @@ 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, > + .has_multi_master_mode = false, > + .has_slcg_override_reg = false, > }; > > static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { > @@ -679,6 +709,8 @@ 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, > + .has_multi_master_mode = false, > + .has_slcg_override_reg = false, > }; > > static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { > @@ -687,10 +719,25 @@ 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, > + .has_multi_master_mode = false, > + .has_slcg_override_reg = false, > }; > > +static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { > + .has_continue_xfer_support = true, > + .has_per_pkt_xfer_complete_irq = true, > + .has_single_clk_source = true, > + .clk_divisor_hs_mode = 1, > + .clk_divisor_std_fast_mode = 0x19, > + .has_config_load_reg = true, > + .has_multi_master_mode = true, > + .has_slcg_override_reg = true, > +}; > + > + > /* Match table for of_platform binding */ > static const struct of_device_id tegra_i2c_of_match[] = { > + { .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, }, > { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, > { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, > { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, > @@ -745,10 +792,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) > return PTR_ERR(i2c_dev->rst); > } > > - ret = of_property_read_u32(i2c_dev->dev->of_node, "clock-frequency", > - &i2c_dev->bus_clk_rate); > - if (ret) > - i2c_dev->bus_clk_rate = 100000; /* default clock rate */ > + tegra_i2c_parse_dt(i2c_dev); > > i2c_dev->hw = &tegra20_i2c_hw; > > @@ -796,6 +840,13 @@ static int tegra_i2c_probe(struct platform_device *pdev) > goto unprepare_fast_clk; > } > > + if (i2c_dev->is_multimaster_mode) { > + ret = clk_enable(i2c_dev->div_clk); > + dev_err(i2c_dev->dev, "div_clk enable failed %d\n", > + ret); > + goto unprepare_div_clk; > + } > + > ret = tegra_i2c_init(i2c_dev); > if (ret) { > dev_err(&pdev->dev, "Failed to initialize i2c controller"); > @@ -806,7 +857,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) > tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev); > if (ret) { > dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq); > - goto unprepare_div_clk; > + goto disable_div_clk; > } > > i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); > @@ -822,11 +873,15 @@ static int tegra_i2c_probe(struct platform_device *pdev) > ret = i2c_add_numbered_adapter(&i2c_dev->adapter); > if (ret) { > dev_err(&pdev->dev, "Failed to add I2C adapter\n"); > - goto unprepare_div_clk; > + goto disable_div_clk; > } > > return 0; > > +disable_div_clk: > + if (i2c_dev->is_multimaster_mode) > + clk_disable(i2c_dev->div_clk); > + > unprepare_div_clk: > clk_unprepare(i2c_dev->div_clk); > > @@ -842,6 +897,9 @@ static int tegra_i2c_remove(struct platform_device *pdev) > struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); > i2c_del_adapter(&i2c_dev->adapter); > > + if (i2c_dev->is_multimaster_mode) > + clk_disable(i2c_dev->div_clk); > + > clk_unprepare(i2c_dev->div_clk); > if (!i2c_dev->hw->has_single_clk_source) > clk_unprepare(i2c_dev->fast_clk); > -- > 1.8.1.5 >
Attachment:
signature.asc
Description: PGP signature