[PATCH v9 4/5] i2c: davinci: add support for setting bus frequency

Marcus Folkesson
2026-03-24T13:54:50Z

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 <bartosz.golaszewski@linaro.org>
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
drivers/i2c/busses/i2c-davinci.c | 35 ++++++++++++++++++++++++++++-------
1 file changed, 28 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 549fb22cdf4f..d87172408445 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,9 +206,9 @@ 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
@@ -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,27 @@ 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);
+
+ if (adap->clock_hz == clock_hz)
+ return 0;
+
+ adap->clock_hz = clock_hz;
+
+ /* put I2C into reset */
+ davinci_i2c_reset_ctrl(dev, 0);
+
+ /* compute clock dividers */
+ i2c_davinci_calc_clk_dividers(dev);
+
+ /* Take the I2C module out of reset: */
+ davinci_i2c_reset_ctrl(dev, 1);
+
+ return 0;
+}
+
/*
* This routine does i2c bus recovery by using i2c_generic_scl_recovery
* which is provided by I2C Bus recovery infrastructure.
@@ -755,12 +775,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 +821,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 +829,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.53.0