Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v10 0/7] I2C Mux per channel bus speed
@ 2026-07-08 12:16 Marcus Folkesson
  2026-07-08 12:16 ` [PATCH v10 1/7] i2c: core: add callback to change bus frequency Marcus Folkesson
                   ` (7 more replies)
  0 siblings, 8 replies; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-08 12:16 UTC (permalink / raw)
  To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson,
	Bartosz Golaszewski

This was a RFC on how to implement a feature to have different bus
speeds on different channels with an I2C multiplexer/switch.
As no major complaints on the design came up during the review, I
decided to submit the series without the RFC tag.

The benefit with this feature is that you may group devices after
the fastest bus speed they can handle.
A real-world example is that you could have e.g. a display running @400kHz
and a smart battery running @100kHz using the same I2C controller.

There are many corner cases where this may cause a problem for some
hardware topologies. I've tried to describe those I could think of
in the documentation, see Patch #5.

E.g. one risk is that if the mux driver does not disconnect channels
when Idle, this may cause a higher frequency to "leak" through to
devices that are supposed to run at lower bus speed.
This is not only a "problem" for changing bus speed but could also be
an issue for potential address conflicts.

This patchset has been used and tested heavily the last months
on a custom board based on a da850 (DaVinci) platform.

The implementation is split up into several patches:

Patch #1 Introduce a callback for the i2c controller to set bus speed
Patch #2 Introduce functionality to adjust bus speed depending on mux
         channel.
Patch #3 Cleanup i2c-davinci driver a bit to prepare it for set_clk_freq
Parch #4 Implement set_clk_freq for the i2c-davinci driver
Parch #5 Update documentation with this feature

Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
Changes in v10:

- Fix gramatics in documentation
- Move {__,}i2c_adapter_set_clk_freq() to i2c-mux.c
- Make set_clk_freq() return actual frequency
- Reimplement idle_state (from earlier version)
- Implement example on idle_state for ltc4306
- Link to v9: https://lore.kernel.org/r/20260324-i2c-mux-v9-0-5292b0608243@gmail.com

Changes in v9:
- Fix stray blank line
- Link to v8: https://lore.kernel.org/r/20260314-i2c-mux-v8-0-fb1738a4df0a@gmail.com

Changes in v8:
- Fix gramatics and change %d to %u were appropriate
- Link to v7: https://lore.kernel.org/r/20260223-i2c-mux-v7-0-ec75b214718a@gmail.com

Changes in v7:
- Remove code for finding first mux-locked ancestor
- Introduce a unlocked (i2c_adapter_set_clk_freq) and unlocked
  (__i2c_adapter_set_clk_freq) variant
- Let the locking be handled in __i2c_adapter_set_clk_freq
- Use I2C_MAX_STANDARD_MODE_FREQ instead of magic numbers where
  appropriate 
- Link to v6: https://lore.kernel.org/r/20260216-i2c-mux-v6-0-9be28ecfd7e3@gmail.com

Changes in v6:
- Change logic to find which ancestor to lock with I2C_LOCK_ROOT_ADAPTER
  It now find the first mux-locked ancestor and then lock its parent.

- Remove bus_freq_hz in i2c-davinci and only use clock_hz instead
- Mention in commit message that clock_hz can be used to store frequency in an uniform way

- Swap order for change freq/deselect to keep symmetry
- Only allow bus frequency to be lowered in select()
  This to not allow an intermediate frequency to be set when it is not
  supposed to

- check if(ret) instead of ret(<0) where appropriate
- Fix typos in documentation
- Change i2c_adapter.clock_hz from int to u32
- Simplify i2c_adapter_set_clk_freq() by removing 'ret'
- Link to v5: https://lore.kernel.org/r/20260213-i2c-mux-v5-0-fb2cbf9979b3@gmail.com

Changes in v5:
- Take the lock of the top-most mutex locked mux to make sure that the
  root is locked
- Link to v4: https://lore.kernel.org/r/20260128-i2c-mux-v4-0-dee49ce276c0@gmail.com

Changes in v4:
- Rebase on master
- Swap order for printing warning about "channel %u is slower than
  parent on a non parent-locked mux\n"
- Fix typo in comment, adaper->adapter
- Link to v3: https://lore.kernel.org/r/20251020-i2c-mux-v3-0-908ac5cf9223@gmail.com

Changes in v3:
- Return -EINVAL if channel is faster than parent (kernel test robot)
- Link to v2: https://lore.kernel.org/r/20251002-i2c-mux-v2-0-b698564cd956@gmail.com

Changes in v2:
- Changed bus_freq field to bus_freq_hz in davinci_i2c_dev (Bartosz Golaszewski)
- Removed idle_state from mux core (Peter Rosin)
- Link to v1: https://lore.kernel.org/r/20250922-i2c-mux-v1-0-28c94a610930@gmail.com

To: Andi Shyti <andi.shyti@kernel.org>
To: Peter Rosin <peda@lysator.liu.se>
To: Bartosz Golaszewski <brgl@kernel.org>
To: Michael Hennerich <michael.hennerich@analog.com>
Cc: linux-i2c@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org

---
Marcus Folkesson (7):
      i2c: core: add callback to change bus frequency
      i2c: mux: add idle_state property to i2c_mux_core
      i2c: mux: add support for per channel bus frequency
      i2c: davinci: calculate bus freq from Hz instead of kHz
      i2c: davinci: add support for setting bus frequency
      i2c: mux: ltc4306: set correct idle_state in i2c_mux_core
      docs: i2c: i2c-topology: add section about bus speed

 Documentation/i2c/i2c-topology.rst  | 178 ++++++++++++++++++++++++++++++++++++
 drivers/i2c/busses/i2c-davinci.c    |  39 +++++---
 drivers/i2c/i2c-mux.c               | 162 +++++++++++++++++++++++++++++---
 drivers/i2c/muxes/i2c-mux-ltc4306.c |   3 +
 include/linux/i2c-mux.h             |  26 ++++++
 include/linux/i2c.h                 |   5 +
 6 files changed, 389 insertions(+), 24 deletions(-)
---
base-commit: 50938ff6aa9a0e5d5a3e647f976286f4c5bd1b06
change-id: 20250913-i2c-mux-b0063de2ae4d

Best regards,
--  
Marcus Folkesson <marcus.folkesson@gmail.com>



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v10 1/7] i2c: core: add callback to change bus frequency
  2026-07-08 12:16 [PATCH v10 0/7] I2C Mux per channel bus speed Marcus Folkesson
@ 2026-07-08 12:16 ` Marcus Folkesson
  2026-07-08 12:16 ` [PATCH v10 2/7] i2c: mux: add idle_state property to i2c_mux_core Marcus Folkesson
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-08 12:16 UTC (permalink / raw)
  To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson

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 | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 20fd41b51d5c..c5ba07f03ada 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -729,6 +729,9 @@ struct i2c_adapter_quirks {
 /*
  * i2c_adapter is the structure used to identify a physical i2c bus along
  * with the access algorithms necessary to access it.
+ *
+ * @set_clk_freq: Set clock frequency for the adapter. Returns the actual set frequency.
+ *      This function is optional.
  */
 struct i2c_adapter {
 	struct module *owner;
@@ -742,6 +745,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 */

-- 
2.54.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v10 2/7] i2c: mux: add idle_state property to i2c_mux_core
  2026-07-08 12:16 [PATCH v10 0/7] I2C Mux per channel bus speed Marcus Folkesson
  2026-07-08 12:16 ` [PATCH v10 1/7] i2c: core: add callback to change bus frequency Marcus Folkesson
@ 2026-07-08 12:16 ` Marcus Folkesson
  2026-07-08 12:16 ` [PATCH v10 3/7] i2c: mux: add support for per channel bus frequency Marcus Folkesson
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-08 12:16 UTC (permalink / raw)
  To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson

Muxes treat their channels differently when idle.
Let the mux core have this information to make it available for
internal use.
Reuse the same state values used by CONFIG_MULTIPLEXER.

Possible idle states are:
- MUX_IDLE_AS_IS: Leave channels as is when idle
- MUX_IDLE_DISCONNECT: Disconnect channel (set HiZ when idle)
- <n>: Enable channel n when idle

Default value is set to MUX_IDLE_AS_IS.

Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
 drivers/i2c/i2c-mux.c   |  1 +
 include/linux/i2c-mux.h | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 681a201c239b..edf16683dc83 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -247,6 +247,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
 	muxc->select = select;
 	muxc->deselect = deselect;
 	muxc->max_adapters = max_adapters;
+	muxc->idle_state = MUX_IDLE_AS_IS;
 
 	return muxc;
 }
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 1784ac7afb11..624fadbaa703 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -13,6 +13,7 @@
 
 #ifdef __KERNEL__
 
+#include <dt-bindings/mux/mux.h>
 #include <linux/bitops.h>
 
 struct i2c_mux_core {
@@ -22,6 +23,17 @@ struct i2c_mux_core {
 	unsigned int arbitrator:1;
 	unsigned int gate:1;
 
+	/*
+	 * The mux controller state to use when inactive.
+	 * Possible idle states are:
+	 *  - MUX_IDLE_AS_IS: Leave channels as is when idle
+	 *  - MUX_IDLE_DISCONNECT: Disconnect channel (set HiZ when idle)
+	 *  - <n>: Enable channel n when idle
+	 *
+	 * Default value is set to MUX_IDLE_AS_IS.
+	 */
+	int idle_state;
+
 	void *priv;
 
 	int (*select)(struct i2c_mux_core *, u32 chan_id);
@@ -38,6 +50,20 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
 				   int (*select)(struct i2c_mux_core *, u32),
 				   int (*deselect)(struct i2c_mux_core *, u32));
 
+/*
+ * Mux drivers may only change idle_state, and may only do so
+ * between allocation and registration of the mux controller.
+ */
+static inline void i2c_mux_set_idle_state(struct i2c_mux_core *muxc, int state)
+{
+	muxc->idle_state = state;
+}
+
+static inline int i2c_mux_idle_state(struct i2c_mux_core *muxc)
+{
+	return muxc->idle_state;
+}
+
 /* flags for i2c_mux_alloc */
 #define I2C_MUX_LOCKED     BIT(0)
 #define I2C_MUX_ARBITRATOR BIT(1)

-- 
2.54.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v10 3/7] i2c: mux: add support for per channel bus frequency
  2026-07-08 12:16 [PATCH v10 0/7] I2C Mux per channel bus speed Marcus Folkesson
  2026-07-08 12:16 ` [PATCH v10 1/7] i2c: core: add callback to change bus frequency Marcus Folkesson
  2026-07-08 12:16 ` [PATCH v10 2/7] i2c: mux: add idle_state property to i2c_mux_core Marcus Folkesson
@ 2026-07-08 12:16 ` Marcus Folkesson
  2026-07-08 12:16 ` [PATCH v10 4/7] i2c: davinci: calculate bus freq from Hz instead of kHz Marcus Folkesson
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-08 12:16 UTC (permalink / raw)
  To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson

There may be several reasons why you may need to use a certain speed
on an I2C bus. E.g.

- When several devices are attached to the bus, the speed must be
  selected according to the slowest device.

- Electrical conditions may limit the usable speed on the bus for
  different reasons.

With an I2C multiplexer, it is possible to group the attached devices
after their preferred speed by e.g. putting all "slow" devices on a
separate channel on the multiplexer.

Consider the following topology:

                      .----------. 100kHz .--------.
    .--------. 400kHz |          |--------| dev D1 |
    |  root  |--+-----| I2C MUX  |        '--------'
    '--------'  |     |          |--. 400kHz .--------.
                |     '----------'  '-------| dev D2 |
                |  .--------.               '--------'
                '--| dev D3 |
                   '--------'

One requirement with this design is that a multiplexer may only use the
same or lower bus speed as its parent.
Otherwise, if the multiplexer would have to increase the bus frequency,
then all siblings (D3 in this case) would run into a clock speed it may
not support.

The bus frequency for each channel is set in the devicetree. As the
i2c-mux bindings import the i2c-controller schema, the clock-frequency
property is already allowed.
If no clock-frequency property is set, the channel inherits their parent
bus speed.

The following example uses dt bindings to illustrate the topology above:

    i2c {
	clock-frequency = <400000>;

        i2c-mux {
            i2c@0 {
                clock-frequency = <100000>;

                D1 {
                    ...
                };
            };

            i2c@1 {
                D2 {
                  ...
                };
            };
        };

        D3 {
            ...
        }
    };

Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
 drivers/i2c/i2c-mux.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 149 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index edf16683dc83..48ecb11f4a99 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -36,21 +36,118 @@ struct i2c_mux_priv {
 	u32 chan_id;
 };
 
+static inline int
+__i2c_adapter_set_clk_freq(struct i2c_adapter *adapter, u32 clock_hz)
+{
+	/* If the clock frequency is already set to the requested value, do nothing. */
+	if (adapter->clock_hz == clock_hz)
+		return 0;
+
+	if (adapter->set_clk_freq) {
+		adapter->clock_hz = adapter->set_clk_freq(adapter, clock_hz);
+		if (adapter->clock_hz != clock_hz)
+			dev_warn(&adapter->dev, "Could not set requested frequency. Requested %uHz, got %uHz\n",
+				 clock_hz, adapter->clock_hz);
+
+		return 0;
+	}
+
+	/*
+	 * 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;
+}
+
+static int i2c_mux_select_chan(struct i2c_adapter *adap, u32 chan_id, u32 *oldclock)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	if (priv->adap.clock_hz && priv->adap.clock_hz < parent->clock_hz) {
+		*oldclock = parent->clock_hz;
+
+		if (muxc->mux_locked)
+			ret = i2c_adapter_set_clk_freq(parent, priv->adap.clock_hz);
+		else
+			ret = __i2c_adapter_set_clk_freq(parent, priv->adap.clock_hz);
+
+		dev_dbg(&adap->dev, "Set clock frequency %uHz on %s\n",
+			priv->adap.clock_hz, parent->name);
+
+		if (ret)
+			dev_err(&adap->dev,
+				"Failed to set clock frequency %uHz on adapter %s: %d\n",
+				*oldclock, parent->name, ret);
+	}
+
+	return muxc->select(muxc, priv->chan_id);
+}
+
+static void i2c_mux_deselect_chan(struct i2c_adapter *adap, u32 chan_id, u32 oldclock)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+
+	if (oldclock && oldclock != priv->adap.clock_hz) {
+		if (muxc->mux_locked)
+			ret = i2c_adapter_set_clk_freq(parent, oldclock);
+		else
+			ret = __i2c_adapter_set_clk_freq(parent, oldclock);
+
+		dev_dbg(&adap->dev, "Restored clock frequency %uHz on %s\n",
+			oldclock, parent->name);
+
+		if (ret)
+			dev_err(&adap->dev,
+				"Failed to set clock frequency %uHz on adapter %s: %d\n",
+				oldclock, parent->name, ret);
+	}
+}
+
 static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
 				 struct i2c_msg msgs[], int num)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
 	struct i2c_mux_core *muxc = priv->muxc;
 	struct i2c_adapter *parent = muxc->parent;
+	u32 oldclock = 0;
 	int ret;
 
 	/* Switch to the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
 	if (ret >= 0)
 		ret = __i2c_transfer(parent, msgs, num);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
 
 	return ret;
 }
@@ -61,15 +158,16 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 	struct i2c_mux_priv *priv = adap->algo_data;
 	struct i2c_mux_core *muxc = priv->muxc;
 	struct i2c_adapter *parent = muxc->parent;
+	u32 oldclock = 0;
 	int ret;
 
 	/* Switch to the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
 	if (ret >= 0)
 		ret = i2c_transfer(parent, msgs, num);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
 
 	return ret;
 }
@@ -82,16 +180,17 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 	struct i2c_mux_priv *priv = adap->algo_data;
 	struct i2c_mux_core *muxc = priv->muxc;
 	struct i2c_adapter *parent = muxc->parent;
+	u32 oldclock = 0;
 	int ret;
 
 	/* Select the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
 	if (ret >= 0)
 		ret = __i2c_smbus_xfer(parent, addr, flags,
 				       read_write, command, size, data);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
 
 	return ret;
 }
@@ -104,16 +203,17 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 	struct i2c_mux_priv *priv = adap->algo_data;
 	struct i2c_mux_core *muxc = priv->muxc;
 	struct i2c_adapter *parent = muxc->parent;
+	u32 oldclock = 0;
 	int ret;
 
 	/* Select the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
 	if (ret >= 0)
 		ret = i2c_smbus_xfer(parent, addr, flags,
 				     read_write, command, size, data);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
 
 	return ret;
 }
@@ -363,6 +463,43 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
 			}
 		}
 
+		of_property_read_u32(child, "clock-frequency", &priv->adap.clock_hz);
+
+		/* If the mux adapter has no clock-frequency property, inherit from parent */
+		if (!priv->adap.clock_hz)
+			priv->adap.clock_hz = parent->clock_hz;
+
+		if (priv->adap.clock_hz < parent->clock_hz)
+			if (muxc->idle_state != MUX_IDLE_DISCONNECT ||
+			    muxc->idle_state == chan_id) {
+				dev_err(muxc->dev,
+					 "channel %u has improper idle state for this configuration\n",
+					 chan_id);
+				of_node_put(mux_node);
+				ret = -EINVAL;
+				goto err_free_priv;
+			}
+
+		/*
+		 * Warn if the mux adapter is not parent-locked as
+		 * this may cause issues for some hardware topologies.
+		 */
+		if ((priv->adap.clock_hz < parent->clock_hz) && muxc->mux_locked)
+			dev_warn(muxc->dev,
+				 "channel %u is slower than parent on a non parent-locked mux\n",
+				 chan_id);
+
+		/* We don't support mux adapters faster than their parent */
+		if (priv->adap.clock_hz > parent->clock_hz) {
+			dev_err(muxc->dev,
+				"channel (%u) is faster (%u) than parent (%u)\n",
+				chan_id, priv->adap.clock_hz, parent->clock_hz);
+
+			of_node_put(mux_node);
+			ret = -EINVAL;
+			goto err_free_priv;
+		}
+
 		priv->adap.dev.of_node = child;
 		of_node_put(mux_node);
 	}

-- 
2.54.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v10 4/7] i2c: davinci: calculate bus freq from Hz instead of kHz
  2026-07-08 12:16 [PATCH v10 0/7] I2C Mux per channel bus speed Marcus Folkesson
                   ` (2 preceding siblings ...)
  2026-07-08 12:16 ` [PATCH v10 3/7] i2c: mux: add support for per channel bus frequency Marcus Folkesson
@ 2026-07-08 12:16 ` Marcus Folkesson
  2026-07-08 19:30   ` Andy Shevchenko
  2026-07-08 12:16 ` [PATCH v10 5/7] i2c: davinci: add support for setting bus frequency Marcus Folkesson
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-08 12:16 UTC (permalink / raw)
  To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson,
	Bartosz Golaszewski

The bus frequency is unnecessarily converted between Hz and kHz in
several places.
This is probably an old legacy from the old times (pre-devicetrees)
when the davinci_i2c_platform_data took the bus_freq in kHz.

Stick to Hz.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
 drivers/i2c/busses/i2c-davinci.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 66c23535656b..549fb22cdf4f 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -117,8 +117,6 @@
 /* timeout for pm runtime autosuspend */
 #define DAVINCI_I2C_PM_TIMEOUT	1000	/* ms */
 
-#define DAVINCI_I2C_DEFAULT_BUS_FREQ	100000
-
 struct davinci_i2c_dev {
 	struct device           *dev;
 	void __iomem		*base;
@@ -134,8 +132,8 @@ struct davinci_i2c_dev {
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
 #endif
-	/* standard bus frequency (kHz) */
-	unsigned int		bus_freq;
+	/* standard bus frequency */
+	unsigned int		bus_freq_hz;
 	/* Chip has a ICPFUNC register */
 	bool			has_pfunc;
 };
@@ -209,16 +207,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 * 1000));
+	clk = (input_clock / (psc + 1)) / (dev->bus_freq_hz);
 	/* Avoid driving the bus too fast because of rounding errors above */
-	if (input_clock / (psc + 1) / clk > dev->bus_freq * 1000)
+	if (input_clock / (psc + 1) / clk > dev->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 > 100)
+	if (bus_freq_hz > I2C_MAX_STANDARD_MODE_FREQ)
 		clkl = (clk << 1) / 3;
 	else
 		clkl = (clk >> 1);
@@ -242,7 +240,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
 	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
 	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
 
-	dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
+	dev_dbg(dev->dev, "input_clock = %u, CLK = %u\n", input_clock, clk);
 }
 
 /*
@@ -269,7 +267,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 = %dkHz\n", dev->bus_freq);
+	dev_dbg(dev->dev, "bus_freq_hz = %dHz\n", dev->bus_freq_hz);
 
 
 	/* Take the I2C module out of reset: */
@@ -760,9 +758,9 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 
 	r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
 	if (r)
-		prop = DAVINCI_I2C_DEFAULT_BUS_FREQ;
+		prop = I2C_MAX_STANDARD_MODE_FREQ;
 
-	dev->bus_freq = prop / 1000;
+	dev->bus_freq_hz = prop;
 
 	dev->has_pfunc = device_property_present(&pdev->dev, "ti,has-pfunc");
 

-- 
2.54.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v10 5/7] i2c: davinci: add support for setting bus frequency
  2026-07-08 12:16 [PATCH v10 0/7] I2C Mux per channel bus speed Marcus Folkesson
                   ` (3 preceding siblings ...)
  2026-07-08 12:16 ` [PATCH v10 4/7] i2c: davinci: calculate bus freq from Hz instead of kHz Marcus Folkesson
@ 2026-07-08 12:16 ` Marcus Folkesson
  2026-07-08 12:16 ` [PATCH v10 6/7] i2c: mux: ltc4306: set correct idle_state in i2c_mux_core Marcus Folkesson
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-08 12:16 UTC (permalink / raw)
  To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson,
	Bartosz Golaszewski

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 | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 549fb22cdf4f..fd87dc661ecb 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,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



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v10 6/7] i2c: mux: ltc4306: set correct idle_state in i2c_mux_core
  2026-07-08 12:16 [PATCH v10 0/7] I2C Mux per channel bus speed Marcus Folkesson
                   ` (4 preceding siblings ...)
  2026-07-08 12:16 ` [PATCH v10 5/7] i2c: davinci: add support for setting bus frequency Marcus Folkesson
@ 2026-07-08 12:16 ` Marcus Folkesson
  2026-07-08 12:16 ` [PATCH v10 7/7] docs: i2c: i2c-topology: add section about bus speed Marcus Folkesson
  2026-07-08 19:37 ` [PATCH v10 0/7] I2C Mux per channel " Andy Shevchenko
  7 siblings, 0 replies; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-08 12:16 UTC (permalink / raw)
  To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson

Inform the core if we intend to disconnect channels during idle.

Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
 drivers/i2c/muxes/i2c-mux-ltc4306.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c
index 18228f5b80e8..d1bd59d73799 100644
--- a/drivers/i2c/muxes/i2c-mux-ltc4306.c
+++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c
@@ -232,6 +232,9 @@ static int ltc4306_probe(struct i2c_client *client)
 	data = i2c_mux_priv(muxc);
 	data->chip = chip;
 
+	if (idle_disc)
+		i2c_mux_set_idle_state(muxc, MUX_IDLE_DISCONNECT);
+
 	i2c_set_clientdata(client, muxc);
 
 	data->regmap = devm_regmap_init_i2c(client, &ltc4306_regmap_config);

-- 
2.54.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v10 7/7] docs: i2c: i2c-topology: add section about bus speed
  2026-07-08 12:16 [PATCH v10 0/7] I2C Mux per channel bus speed Marcus Folkesson
                   ` (5 preceding siblings ...)
  2026-07-08 12:16 ` [PATCH v10 6/7] i2c: mux: ltc4306: set correct idle_state in i2c_mux_core Marcus Folkesson
@ 2026-07-08 12:16 ` Marcus Folkesson
  2026-07-08 19:37 ` [PATCH v10 0/7] I2C Mux per channel " Andy Shevchenko
  7 siblings, 0 replies; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-08 12:16 UTC (permalink / raw)
  To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson

Describe what needs to be consideraed and taken into account
when using different bus speeds for different mux channels.

Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
 Documentation/i2c/i2c-topology.rst | 178 +++++++++++++++++++++++++++++++++++++
 1 file changed, 178 insertions(+)

diff --git a/Documentation/i2c/i2c-topology.rst b/Documentation/i2c/i2c-topology.rst
index 48fce0f7491b..1ee0de6dbcb4 100644
--- a/Documentation/i2c/i2c-topology.rst
+++ b/Documentation/i2c/i2c-topology.rst
@@ -367,6 +367,184 @@ When D1 or D2 are accessed, accesses to D3 and D4 are locked out while
 accesses to D5 may interleave. When D3 or D4 are accessed, accesses to
 all other devices are locked out.
 
+Bus Speed and I2C Multiplexers
+================================
+
+I2C bus multiplexers allow multiple downstream channels to be exposed
+as separate I2C adapters which also could set their own bus speed.
+
+The multiplexer itself cannot change the bus speed as it uses the upstream
+clock and data lines to communicate with the downstream devices. The speed
+is therefore changed in the root adapter resulting in that the whole bus is
+affected.
+
+This increases the complexity of the topology and some considerations must
+be taken into account.
+
+Bus speed
+----------
+
+Downstream channels of an I2C multiplexer can only operate at the same or
+lower bus speed as the upstream bus. This is because the upstream bus may
+have devices that cannot operate at higher speeds and those will be affected
+by the speed change.
+
+The example below illustrates the problem.
+The root adapter is operating at 100kHz. D2 can only operate with 100kHz,
+but D1 can operate at 400kHz. When D1 is selected, the bus speed of the
+root adapter would have to be set to 400kHz, a speed that D2 may not support.
+
+This topology is therefore not allowed: ::
+
+                          .----------. 400kHz .--------.
+        .--------. 100kHz |   mux-   |--------| dev D1 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'  |     |  mux M1  |
+                    |     '----------'
+                    |  .--------.
+                    '--| dev D2 |
+                       '--------'
+
+
+This topology is allowed: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D2 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'        |  mux M1  |--. 400kHz .--------.
+                          '----------'  '--------| dev D1 |
+                                                 '--------'
+
+Preferred topology
+-------------------
+
+The preferred topology when using different bus speeds is to have the multiplexer
+connected directly to the root adapter without any devices as siblings.
+By this arrangement, the bus speed can be changed without affecting any other devices
+and many of the caveats are avoided.
+
+Other multiplexers in parallel are still okay as those are locked out during transfers.
+
+This is the preferred topology: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D2 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'        |  mux M1  |--. 400kHz .--------.
+                          '----------'  '--------| dev D1 |
+                                                 '--------'
+
+Locking
+--------
+
+If the multiplexer is mux-locked, transfers to D3 may interleave between the
+select-transfer-deselect to D1 or D2.
+This results in a situation where the bus speed to D3 may be lower than it
+is supposed to be. This is usually not a problem.
+
+This topology is allowed but some transfers to D3 may be at 100kHz: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D1 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'  |     |  mux M1  |--. 400kHz .--------.
+                    |     '----------'  '--------| dev D2 |
+                    |  .--------.                '--------'
+                    '--| dev D3 |
+                       '--------'
+
+Multiple muxes in series
+--------------------------
+
+When multiple muxes are used in series the same rules apply.
+
+Transfers to D3 may interleave between select-transfer-deselect to D1, which
+results in that the bus speed to D2 or D3 will be at 100KHz.
+
+Transfers to D2 may interleave between select-transfer-deselect to D1, which
+results in that the bus speed to D1 may be at 400kHz as the transfer to D2
+will set the bus speed to before the transfer to D1 starts.
+
+This is probably a bad topology ::
+
+                     .----------. 400kHz .----------. 100kHz .--------.
+    .--------.400kHz |   mux-   |--------|   mux-   |--------| dev D1 |
+    |  root  |--+----|  locked  | 400kHz |  locked  |        '--------'
+    '--------'  |    |  mux M1  |--.     |  mux M2  |
+                |    '----------'  |     '----------'
+                |  .--------.      |  .--------.
+                '--| dev D3 |      '--| dev D2 |
+                   '--------'         '--------'
+
+Multiple muxes in parallel
+----------------------------
+
+When multiple muxes are used in parallel all access to other muxes are locked out
+so this is not a problem.
+
+If the muxes are mux-locked, access to D3 may still interleave though.
+
+In the example below, D3 may not interleave between select-transfer-deselect for D1
+or D2 as both muxes are parent-locked: ::
+
+
+                   .----------. 100kHz   .--------.
+                   |  parent- |----------| dev D1 |
+                .--|  locked  |          '--------'
+                |  |  mux M1  |
+                |  '----------'
+                |      .----------. 400KHz  .--------.
+    .--------. 400kHz  |  parent- |---------| dev D2 |
+    |  root  |--+------|  locked  |         '--------'
+    '--------'  |      |  mux M2  |
+                |      '----------'
+                |  .--------.
+                '--| dev D3 |
+                   '--------'
+
+Idle state
+-----------
+
+Muxes have an idle state, which is the state the channels are put into when no channel
+is active. The state is typically one of the following:
+
+- All channels are disconnected
+- The last selected channel is left as-is
+- A predefined channel is selected
+
+Muxes that support an idle state where all channels are disconnected are preferred when using
+different bus speeds. Otherwise high bus speeds may "leak" through to devices that
+may not support that higher speed.
+
+Consider the following example: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D1 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'  |     |  mux M1  |--. 400kHz .--------.
+                    |     '----------'  '--------| dev D2 |
+                    |  .--------.                '--------'
+                    '--| dev D3 |
+                       '--------'
+
+If the idle state of M1 is:
+
+- All channels disconnected: No problem, D1 and D2 are not affected by communication
+  to D3.
+- Last selected channel: Problem if D1 was the last selected channel. High speed
+  communication to D3 will be "leaked" to D1.
+- Predefined channel: Problem if the predefined channel is D1. Set predefined channel
+  to D2 as D2 may handle 400kHz.
+
+Supported controllers
+-----------------------
+
+Not all I2C controllers support setting the bus speed dynamically.
+At the time of writing, the following controllers have support:
+
+============================   =============================================
+i2c-davinci                    Supports dynamic bus speed
+============================   =============================================
 
 Mux type of existing device drivers
 ===================================

-- 
2.54.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v10 4/7] i2c: davinci: calculate bus freq from Hz instead of kHz
  2026-07-08 12:16 ` [PATCH v10 4/7] i2c: davinci: calculate bus freq from Hz instead of kHz Marcus Folkesson
@ 2026-07-08 19:30   ` Andy Shevchenko
  2026-07-09  8:34     ` Marcus Folkesson
  0 siblings, 1 reply; 13+ messages in thread
From: Andy Shevchenko @ 2026-07-08 19:30 UTC (permalink / raw)
  To: Marcus Folkesson
  Cc: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Bartosz Golaszewski, Peter Rosin, linux-i2c, linux-kernel,
	linux-arm-kernel

On Wed, Jul 08, 2026 at 02:16:16PM +0200, Marcus Folkesson wrote:
> The bus frequency is unnecessarily converted between Hz and kHz in
> several places.
> This is probably an old legacy from the old times (pre-devicetrees)
> when the davinci_i2c_platform_data took the bus_freq in kHz.
> 
> Stick to Hz.

...

> -#define DAVINCI_I2C_DEFAULT_BUS_FREQ	100000
> -

You need to rebase this on top of the i2c-next.

...

> +	/* standard bus frequency */
> +	unsigned int		bus_freq_hz;

While at it, I would dare to suggest _Hz as we started doing in IIO (id est
we start following more closely the SI units in the suffixes of constant
definitions and variables to be case sensitive).

...

>  	r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
>  	if (r)
> -		prop = DAVINCI_I2C_DEFAULT_BUS_FREQ;
> +		prop = I2C_MAX_STANDARD_MODE_FREQ;
>  

See above about rebase.

-- 
With Best Regards,
Andy Shevchenko




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v10 0/7] I2C Mux per channel bus speed
  2026-07-08 12:16 [PATCH v10 0/7] I2C Mux per channel bus speed Marcus Folkesson
                   ` (6 preceding siblings ...)
  2026-07-08 12:16 ` [PATCH v10 7/7] docs: i2c: i2c-topology: add section about bus speed Marcus Folkesson
@ 2026-07-08 19:37 ` Andy Shevchenko
  2026-07-09  8:33   ` Marcus Folkesson
  7 siblings, 1 reply; 13+ messages in thread
From: Andy Shevchenko @ 2026-07-08 19:37 UTC (permalink / raw)
  To: Marcus Folkesson
  Cc: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Bartosz Golaszewski, Peter Rosin, linux-i2c, linux-kernel,
	linux-arm-kernel

On Wed, Jul 08, 2026 at 02:16:12PM +0200, Marcus Folkesson wrote:
> This was a RFC on how to implement a feature to have different bus
> speeds on different channels with an I2C multiplexer/switch.
> As no major complaints on the design came up during the review, I
> decided to submit the series without the RFC tag.
> 
> The benefit with this feature is that you may group devices after
> the fastest bus speed they can handle.
> A real-world example is that you could have e.g. a display running @400kHz
> and a smart battery running @100kHz using the same I2C controller.
> 
> There are many corner cases where this may cause a problem for some
> hardware topologies. I've tried to describe those I could think of
> in the documentation, see Patch #5.
> 
> E.g. one risk is that if the mux driver does not disconnect channels
> when Idle, this may cause a higher frequency to "leak" through to
> devices that are supposed to run at lower bus speed.
> This is not only a "problem" for changing bus speed but could also be
> an issue for potential address conflicts.
> 
> This patchset has been used and tested heavily the last months
> on a custom board based on a da850 (DaVinci) platform.

...

> Changes in v10:
> 
> - Fix gramatics in documentation
> - Move {__,}i2c_adapter_set_clk_freq() to i2c-mux.c

Can you point to the discussion where it was suggested, please?
It was like ages ago (too many patches to review) and I probably
missed and/or forgot the rationale for that. Also if we move
to i2c-mux, why do we leave it in the adapter namespace?

> - Make set_clk_freq() return actual frequency
> - Reimplement idle_state (from earlier version)
> - Implement example on idle_state for ltc4306
> - Link to v9: https://lore.kernel.org/r/20260324-i2c-mux-v9-0-5292b0608243@gmail.com

FWIW, I briefly read the v9 discussion and haven't got the above move,
seems wasn't discussed there?

-- 
With Best Regards,
Andy Shevchenko




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v10 0/7] I2C Mux per channel bus speed
  2026-07-08 19:37 ` [PATCH v10 0/7] I2C Mux per channel " Andy Shevchenko
@ 2026-07-09  8:33   ` Marcus Folkesson
  2026-07-09 10:05     ` Andy Shevchenko
  0 siblings, 1 reply; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-09  8:33 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Bartosz Golaszewski, Peter Rosin, linux-i2c, linux-kernel,
	linux-arm-kernel

Hi Andy,

On Wed, Jul 08, 2026 at 10:37:14PM +0300, Andy Shevchenko wrote:
> On Wed, Jul 08, 2026 at 02:16:12PM +0200, Marcus Folkesson wrote:
> > This was a RFC on how to implement a feature to have different bus
> > speeds on different channels with an I2C multiplexer/switch.
> > As no major complaints on the design came up during the review, I
> > decided to submit the series without the RFC tag.
> > 
> > The benefit with this feature is that you may group devices after
> > the fastest bus speed they can handle.
> > A real-world example is that you could have e.g. a display running @400kHz
> > and a smart battery running @100kHz using the same I2C controller.
> > 
> > There are many corner cases where this may cause a problem for some
> > hardware topologies. I've tried to describe those I could think of
> > in the documentation, see Patch #5.
> > 
> > E.g. one risk is that if the mux driver does not disconnect channels
> > when Idle, this may cause a higher frequency to "leak" through to
> > devices that are supposed to run at lower bus speed.
> > This is not only a "problem" for changing bus speed but could also be
> > an issue for potential address conflicts.
> > 
> > This patchset has been used and tested heavily the last months
> > on a custom board based on a da850 (DaVinci) platform.
> 
> ...
> 
> > Changes in v10:
> > 
> > - Fix gramatics in documentation
> > - Move {__,}i2c_adapter_set_clk_freq() to i2c-mux.c
> 
> Can you point to the discussion where it was suggested, please?
> It was like ages ago (too many patches to review) and I probably
> missed and/or forgot the rationale for that. Also if we move
> to i2c-mux, why do we leave it in the adapter namespace?

Hrm, it seems like the mailing list wasn't CC:ed for that comment.
It was suggested by Peter and the rationale to remove it was:

"
I'not sure it's a good idea to expose {__,}i2c_adapter_set_clk_freq().

Do we really want to make it so simple for random (non-mux) I2C drivers
to muck about with the bus speed? Any bus speed changes not coordinated
with mux-locked bus speed changes are going to be problematic. This is
shown by the discussion about D2 for the multi-level mux-locked example
(patch 5/5) -> it is problematic even when the bus speed is changed by
the mux code itself.

I think these helpers should be moved from i2c.h to i2c-mux.c.
"

> 
> > - Make set_clk_freq() return actual frequency
> > - Reimplement idle_state (from earlier version)
> > - Implement example on idle_state for ltc4306
> > - Link to v9: https://lore.kernel.org/r/20260324-i2c-mux-v9-0-5292b0608243@gmail.com
> 
> FWIW, I briefly read the v9 discussion and haven't got the above move,
> seems wasn't discussed there?
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
> 

Best regards,
Marcus Folkesson


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v10 4/7] i2c: davinci: calculate bus freq from Hz instead of kHz
  2026-07-08 19:30   ` Andy Shevchenko
@ 2026-07-09  8:34     ` Marcus Folkesson
  0 siblings, 0 replies; 13+ messages in thread
From: Marcus Folkesson @ 2026-07-09  8:34 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Bartosz Golaszewski, Peter Rosin, linux-i2c, linux-kernel,
	linux-arm-kernel

On Wed, Jul 08, 2026 at 10:30:32PM +0300, Andy Shevchenko wrote:
> On Wed, Jul 08, 2026 at 02:16:16PM +0200, Marcus Folkesson wrote:
> > The bus frequency is unnecessarily converted between Hz and kHz in
> > several places.
> > This is probably an old legacy from the old times (pre-devicetrees)
> > when the davinci_i2c_platform_data took the bus_freq in kHz.
> > 
> > Stick to Hz.
> 
> ...
> 
> > -#define DAVINCI_I2C_DEFAULT_BUS_FREQ	100000
> > -
> 
> You need to rebase this on top of the i2c-next.

Thanks, will do.
> 
> ...
> 
> > +	/* standard bus frequency */
> > +	unsigned int		bus_freq_hz;
> 
> While at it, I would dare to suggest _Hz as we started doing in IIO (id est
> we start following more closely the SI units in the suffixes of constant
> definitions and variables to be case sensitive).

Sounds good, I will change to Hz.

> 
> ...
> 
> >  	r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
> >  	if (r)
> > -		prop = DAVINCI_I2C_DEFAULT_BUS_FREQ;
> > +		prop = I2C_MAX_STANDARD_MODE_FREQ;
> >  
> 
> See above about rebase.
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
Best regards,
Marcus Folkesson


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v10 0/7] I2C Mux per channel bus speed
  2026-07-09  8:33   ` Marcus Folkesson
@ 2026-07-09 10:05     ` Andy Shevchenko
  0 siblings, 0 replies; 13+ messages in thread
From: Andy Shevchenko @ 2026-07-09 10:05 UTC (permalink / raw)
  To: Marcus Folkesson
  Cc: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
	Bartosz Golaszewski, Peter Rosin, linux-i2c, linux-kernel,
	linux-arm-kernel

On Thu, Jul 09, 2026 at 10:33:46AM +0200, Marcus Folkesson wrote:
> On Wed, Jul 08, 2026 at 10:37:14PM +0300, Andy Shevchenko wrote:
> > On Wed, Jul 08, 2026 at 02:16:12PM +0200, Marcus Folkesson wrote:

...

> > > - Move {__,}i2c_adapter_set_clk_freq() to i2c-mux.c
> > 
> > Can you point to the discussion where it was suggested, please?
> > It was like ages ago (too many patches to review) and I probably
> > missed and/or forgot the rationale for that. Also if we move
> > to i2c-mux, why do we leave it in the adapter namespace?
> 
> Hrm, it seems like the mailing list wasn't CC:ed for that comment.

Please, be sure next time everything like this important will be available
to all.

> It was suggested by Peter and the rationale to remove it was:
> 
> "
> I'not sure it's a good idea to expose {__,}i2c_adapter_set_clk_freq().
> 
> Do we really want to make it so simple for random (non-mux) I2C drivers
> to muck about with the bus speed? Any bus speed changes not coordinated
> with mux-locked bus speed changes are going to be problematic. This is
> shown by the discussion about D2 for the multi-level mux-locked example
> (patch 5/5) -> it is problematic even when the bus speed is changed by
> the mux code itself.
> 
> I think these helpers should be moved from i2c.h to i2c-mux.c.
> "

Okay, let's assume I'm fine with this reasoning, I would still go with
the proper namespace. Otherwise it's inconsistent.

-- 
With Best Regards,
Andy Shevchenko




^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-07-09 10:05 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-08 12:16 [PATCH v10 0/7] I2C Mux per channel bus speed Marcus Folkesson
2026-07-08 12:16 ` [PATCH v10 1/7] i2c: core: add callback to change bus frequency Marcus Folkesson
2026-07-08 12:16 ` [PATCH v10 2/7] i2c: mux: add idle_state property to i2c_mux_core Marcus Folkesson
2026-07-08 12:16 ` [PATCH v10 3/7] i2c: mux: add support for per channel bus frequency Marcus Folkesson
2026-07-08 12:16 ` [PATCH v10 4/7] i2c: davinci: calculate bus freq from Hz instead of kHz Marcus Folkesson
2026-07-08 19:30   ` Andy Shevchenko
2026-07-09  8:34     ` Marcus Folkesson
2026-07-08 12:16 ` [PATCH v10 5/7] i2c: davinci: add support for setting bus frequency Marcus Folkesson
2026-07-08 12:16 ` [PATCH v10 6/7] i2c: mux: ltc4306: set correct idle_state in i2c_mux_core Marcus Folkesson
2026-07-08 12:16 ` [PATCH v10 7/7] docs: i2c: i2c-topology: add section about bus speed Marcus Folkesson
2026-07-08 19:37 ` [PATCH v10 0/7] I2C Mux per channel " Andy Shevchenko
2026-07-09  8:33   ` Marcus Folkesson
2026-07-09 10:05     ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox