[PATCH v9 1/5] i2c: core: add callback to change bus frequency

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

All devices on the same I2C bus share the same clock line and the bus
frequency has therefor be chosen so that all attached devices are able
to tolarate that clock rate. IOW, the bus speed must be set for the
slowest attached device.

With I2C multiplexers/switches on the other hand, it would be possible
to have different "domains" that runs with different speeds.

Prepare for such a feature by provide an optional callback function to
change bus frequency.

As a side effect, several bus drivers keep the bus speed in a
private structure and can now have this value stored in a uniform way
instead.

Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
include/linux/i2c.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)

diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 20fd41b51d5c..712f9608108e 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -742,6 +742,8 @@ struct i2c_adapter {
struct rt_mutex mux_lock;

int timeout; /* in jiffies */
+ u32 clock_hz; /* bus clock speed */
+ int (*set_clk_freq)(struct i2c_adapter *adap, u32 clock_hz); /* Optional */
int retries;
struct device dev; /* the adapter device */
unsigned long locked_flags; /* owned by the I2C core */
@@ -835,6 +837,39 @@ i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
adapter->lock_ops->unlock_bus(adapter, flags);
}

+static inline int
+__i2c_adapter_set_clk_freq(struct i2c_adapter *adapter, u32 clock_hz)
+{
+ if (adapter->set_clk_freq)
+ return adapter->set_clk_freq(adapter, clock_hz);
+
+ /*
+ * If the adapter is a root adapter without .set_clk_freq() implemented, this feature is not
+ * supported.
+ */
+ if (!i2c_parent_is_i2c_adapter(adapter))
+ return -EOPNOTSUPP;
+
+ /*
+ * Update the clock_hz for non-root adapters, even if .set_clk_freq() is not implemented,
+ * to allow the clock frequency to be propagated to root adapters that do support it.
+ */
+ adapter->clock_hz = clock_hz;
+ return 0;
+}
+
+static inline int
+i2c_adapter_set_clk_freq(struct i2c_adapter *adapter, u32 clock_hz)
+{
+ int ret;
+
+ i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
+ ret = __i2c_adapter_set_clk_freq(adapter, clock_hz);
+ i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
+
+ return ret;
+}
+
/**
* i2c_mark_adapter_suspended - Report suspended state of the adapter to the core
* @adap: Adapter to mark as suspended

--
2.53.0