[PATCH v6 0/3] i2c: designware: Improve support of multi-messages transfer

Benoît Monin
2026-01-30T15:52:41Z

Add support for the I2C_M_STOP flag to the .xfer() function of
the designware driver. This allows grouping multiple accesses in a
single call and changing the target address after a STOP flag. This is
achieved by splitting i2c_dw_xfer_common() in two functions. The core
logic handling the transaction is now in __i2c_dw_xfer_one_part(),
while i2c_dw_xfer_common() loops over the messages to search for the
I2C_M_STOP flag and calls __i2c_dw_xfer_one_part().

Handle controllers that lack the ability to emit a RESTART when two
consecutive messages have the same address and direction by aborting
transfers that contain such a sequence of messages. For those controllers,
we also check that we do not get any unwanted STOP caused by a Tx FIFO
underrun, as they lack the ability to hold the clock during a transaction.
And we set the irq as non-threaded to prevent underrun on PREEMPT-RT
kernel when filling the FIFO.

The I2C controllers found in the EyeQ6Lplus and EyeQ7H SoCs from Mobileye
lack such capability, so a compatible string is added because this cannot
be detected at runtime. The corresponding DT bindings has already been
merged and is available in v6.19-rc2:

d9b85d296f3a ("dt-bindings: i2c: dw: Add Mobileye I2C controllers")

This patch series also simplifies runtime PM handling in
i2c_dw_xfer_common() and amd_i2c_dw_xfer_quirk() with PM_RUNTIME_* macros.

To test I2C_M_STOP and other message modifier flags, I posted a patch
series for i2c-tools[1]. With it, i2cdetect shows the support of the
protocol mangling and repeated start skipping functionalities, and
i2ctransfer can set the modifier flags to the I2C messages.

The series is now based on i2c-host tree and only contains the last three
patches that have not been merged yet. The first and last patches are
functionally identical to the one posted in the previous revision. Only
the second patch contains modified code to use PM_RUNTIME_* macros
instead of ACQUIRE()/ACQUIRE_ERR(). Thus I let Mika's Acked-by on the
first and third patch, and dropped it from the second patch. I hope it
was the correct thing to do.

[1]: https://lore.kernel.org/all/20260127-msg-flags-v3-0-e7539945db2b@bootlin.com/

Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
Changes in v6:
- Rebased on i2c-host tree.
- Drop the first three cleanup patches of the series: already merged in
i2c-host tree.
- Add/improve comments suggested by the last reviews.
- Use PM_RUNTIME_* macros instead of ACQUIRE()/ACQUIRE_ERR().
- Link to v5: https://lore.kernel.org/r/20260120-i2c-dw-v5-0-0e34d6d9455c@bootlin.com

Changes in v5:
- Rebased on v6.19-rc6 and fully retested on EyeQ6Lplus.
- Drop dt-binding patch: already merged upstream in v6.19-rc2.
- From Andi Shyti's review:
- __i2c_dw_xfer_one_part() now returns 0 on success instead
of the number of messages transferred.
- Drop inline keyword from i2c_dw_msg_is_valid() declaration.
- Link to v4: https://lore.kernel.org/r/20251126-i2c-dw-v4-0-b0654598e7c5@bootlin.com

Changes in v4:
- Use a boolean property instead of a flag for handling controllers
IC_EMPTYFIFO_HOLD_MASTER_EN.
- Reorder the patches so goto and runtime PM auto-cleanup are not mixed
in i2c_dw_xfer().
- Drop goto in __i2c_dw_xfer_one_part() and use return.
- Tidy up comments for i2c_dw_msg_is_valid() and irq_flags.
- Link to v3: https://lore.kernel.org/r/20251119-i2c-dw-v3-0-bc4bc2a2cbac@bootlin.com

Changes in v3:
- Add a compatible entry for Mobileye EyeQ7H i2c controllers.
- Use runtime PM macro for auto-cleanup in i2c_dw_xfer().
- Add a dedicated i2c_algorithm for AMD NAVI controllers.
- Rename __i2c_dw_xfer_unlocked() as it is not about locking at all.
- Rework the validity check of i2c_msg.
- Flag the irq as non-threaded for controllers that cannot hold the
clock to avoid underrun.
- Link to v2: https://lore.kernel.org/r/20251031-i2c-dw-v2-0-90416874fcc0@bootlin.com

Changes in v2:
- Add a single compatible for mobileye i2c controllers based in
DesignWare IP.
- Handle the I2C_M_STOP flag instead of emitting a STOP on target address
change.
- Abort transfer when it requires a RESTART on controller that cannot
emit them.
- Detect FIFO underrun instead of disabling threaded interrupt on
PREEMPT_RT kernel.
- Sort the compatible entries in a separate patch.
- Add a cleanup patch on flag reading in i2c_dw_read().
- Link to v1: https://lore.kernel.org/r/20251017-i2c-dw-v1-0-7b85b71c7a87@bootlin.com

---
Benoît Monin (3):
i2c: designware: Implement I2C_M_STOP support
i2c: designware: Use runtime PM macro for auto-cleanup
i2c: designware: Support of controller with IC_EMPTYFIFO_HOLD_MASTER disabled

drivers/i2c/busses/i2c-designware-common.c | 20 ++++
drivers/i2c/busses/i2c-designware-core.h | 3 +
drivers/i2c/busses/i2c-designware-master.c | 162 ++++++++++++++++++++--------
drivers/i2c/busses/i2c-designware-platdrv.c | 1 +
4 files changed, 141 insertions(+), 45 deletions(-)
---
base-commit: 51e8ce3630878fa6083e1eec84f58f49ec85089b
change-id: 20251014-i2c-dw-da315f758296

Best regards,
--
Benoît Monin, Bootlin
Embedded Linux and Kernel engineering