[PATCH 1/2] i2c: imx: fix locked bus on SMBus block-read of 0 (atomic)
Vincent Jardin
vjardin at free.fr
Mon May 25 04:24:02 PDT 2026
SMBus 3.1 6.5.7 allows a Block Read byte count of 0, but the atomic
(polling) path rejects it as -EPROTO. Worse, it returns without a
NACK+STOP: the next receive cycle has already started, so the target
keeps holding SDA and the bus stays stuck until a power cycle for
this i2c controller.
Accept count=0: NACK the in-flight dummy byte (TXAK) and extend msgs->len
so the existing last-byte handling emits STOP. The dummy byte is
discarded; block-read callers only consume buf[0..count-1].
The interrupt-driven path has the same flaw from a later commit and is
fixed separately, as it carries a different Fixes:
Fixes: 8e8782c71595 ("i2c: imx: add SMBus block read support")
Cc: <stable at vger.kernel.org> # v3.16+
Signed-off-by: Vincent Jardin <vjardin at free.fr>
---
drivers/i2c/busses/i2c-imx.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a208fefd3c3b..0cd4f5892591 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -1436,8 +1436,19 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,
*/
if ((!i) && block_data) {
len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
- if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX))
+ if (len > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
+ if (len == 0) {
+ /*
+ * SMBus 3.1 6.5.7: support count byte of 0.
+ */
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_TXAK;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ msgs->buf[0] = 0;
+ msgs->len = 2;
+ continue;
+ }
dev_dbg(&i2c_imx->adapter.dev,
"<%s> read length: 0x%X\n",
__func__, len);
--
2.43.0
More information about the linux-arm-kernel
mailing list