[PATCH v12 5/7] i2c: davinci: add support for setting bus frequency
Marcus Folkesson <[email protected]>
| Newsgroups | org.kernel.vger.linux-i2c,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Populate adapter with clock_Hz and .set_clk_freq() to enable support for dynamic bus frequency. Remove bus_freq_Hz entirely and only use clock_Hz instead. Acked-by: Bartosz Golaszewski <[email protected]> Signed-off-by: Marcus Folkesson <[email protected]> --- drivers/i2c/busses/i2c-davinci.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index f543997c31e9..87fef17bca55 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -132,8 +132,6 @@ struct davinci_i2c_dev { #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif - /* standard bus frequency */ - unsigned int bus_freq_Hz; /* Chip has a ICPFUNC register */ bool has_pfunc; }; @@ -171,6 +169,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) u32 clkh; u32 clkl; u32 input_clock = clk_get_rate(dev->clk); + u32 bus_freq_Hz = dev->adapter.clock_Hz; /* NOTE: I2C Clock divider programming info * As per I2C specs the following formulas provide prescaler @@ -207,16 +206,16 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) if (device_is_compatible(dev->dev, "ti,keystone-i2c")) d = 6; - clk = (input_clock / (psc + 1)) / (dev->bus_freq_Hz); + clk = (input_clock / (psc + 1)) / (bus_freq_Hz); /* Avoid driving the bus too fast because of rounding errors above */ - if (input_clock / (psc + 1) / clk > dev->bus_freq_Hz) + if (input_clock / (psc + 1) / clk > bus_freq_Hz) clk++; /* * According to I2C-BUS Spec 2.1, in FAST-MODE LOW period should be at * least 1.3uS, which is not the case with 50% duty cycle. Driving HIGH * to LOW ratio as 1 to 2 is more safe. */ - if (dev->bus_freq_Hz > I2C_MAX_STANDARD_MODE_FREQ) + if (bus_freq_Hz > I2C_MAX_STANDARD_MODE_FREQ) clkl = (clk << 1) / 3; else clkl = (clk >> 1); @@ -267,7 +266,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG)); dev_dbg(dev->dev, "CLKH = %d\n", davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG)); - dev_dbg(dev->dev, "bus_freq_Hz = %dHz\n", dev->bus_freq_Hz); + dev_dbg(dev->dev, "bus_freq_Hz = %dHz\n", dev->adapter.clock_Hz); /* Take the I2C module out of reset: */ @@ -279,6 +278,23 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) return 0; } +static int davinci_i2c_set_clk(struct i2c_adapter *adap, u32 clock_Hz) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + /* put I2C into reset */ + davinci_i2c_reset_ctrl(dev, 0); + + /* compute clock dividers */ + adap->clock_Hz = clock_Hz; + i2c_davinci_calc_clk_dividers(dev); + + /* Take the I2C module out of reset: */ + davinci_i2c_reset_ctrl(dev, 1); + + return clock_Hz; +} + /* * This routine does i2c bus recovery by using i2c_generic_scl_recovery * which is provided by I2C Bus recovery infrastructure. @@ -755,12 +771,13 @@ static int davinci_i2c_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->irq = irq; platform_set_drvdata(pdev, dev); + adap = &dev->adapter; r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop); if (r) prop = I2C_MAX_STANDARD_MODE_FREQ; - dev->bus_freq_Hz = prop; + adap->clock_Hz = prop; dev->has_pfunc = device_property_present(&pdev->dev, "ti,has-pfunc"); @@ -800,7 +817,6 @@ static int davinci_i2c_probe(struct platform_device *pdev) goto err_unuse_clocks; } - adap = &dev->adapter; i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; adap->class = I2C_CLASS_DEPRECATED; @@ -809,6 +825,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap->dev.parent = &pdev->dev; adap->timeout = DAVINCI_I2C_TIMEOUT; adap->dev.of_node = dev_of_node(&pdev->dev); + adap->set_clk_freq = davinci_i2c_set_clk; if (dev->has_pfunc) adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; -- 2.54.0