[PATCH] i2c: rk3x: Disable the controller between transfers
Alexey Charkov
alchark at flipper.net
Thu Oct 15 07:00:34 PDT 2026
The driver leaves the controller enabled once a transfer completes, and
an enabled controller keeps tracking the bus. If the lines collapse under
it while idle, as happens when a target's supply is switched off while
its bus pull-ups stay powered, its state machine wedges driving SDA low.
Every later transfer then times out, since the timeout path only requests
a STOP and never disables the controller, and the stuck state even
survives a kexec.
Clear the enable bit once each transfer is done, successful or not, so
that the controller does not watch an idle bus and starts every transfer
from a clean state.
Signed-off-by: Alexey Charkov <alchark at flipper.net>
---
drivers/i2c/busses/i2c-rk3x.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index fcede9f6ed54..dbf1ed30fda6 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -1125,6 +1125,16 @@ static int rk3x_i2c_xfer_common(struct i2c_adapter *adap,
}
}
+ /*
+ * Do not leave the controller enabled between transfers. It keeps
+ * tracking the bus while enabled, and if the lines collapse under it,
+ * e.g. as an unpowered target clamps them, its state machine wedges
+ * driving SDA low until it is disabled. This also gets it out of
+ * whatever state it was stuck in when a transfer timed out.
+ */
+ val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+ i2c_writel(i2c, val, REG_CON);
+
clk_disable(i2c->pclk);
clk_disable(i2c->clk);
---
base-commit: d419d682257d813f6cb7a28e42b35d0edf4ad038
change-id: 20261015-i2c-rk3x-disable-24672d4f38bb
Best regards,
--
Alexey Charkov <alchark at flipper.net>
More information about the Linux-rockchip
mailing list