[PATCH V1] i2c: imx: Fix SMBus block read hang on zero length

Carlos Song carlos.song at nxp.com
Thu Jan 8 19:02:04 PST 2026



> -----Original Message-----
> From: LI Qingwu <Qing-wu.Li at leica-geosystems.com.cn>
> Sent: Monday, December 29, 2025 4:16 PM
> To: o.rempel at pengutronix.de; kernel at pengutronix.de; andi.shyti at kernel.org;
> shawnguo at kernel.org; s.hauer at pengutronix.de; festevam at gmail.com;
> linux-i2c at vger.kernel.org; imx at lists.linux.dev;
> linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org
> Cc: bsp-development.geo at leica-geosystems.com; LI Qingwu
> <Qing-wu.Li at leica-geosystems.com.cn>
> Subject: [EXT] [PATCH V1] i2c: imx: Fix SMBus block read hang on zero length
> 
> Caution: This is an external email. Please take care when clicking links or
> opening attachments. When in doubt, report the message using the 'Report
> this email' button
> 
> 
> SMBus block read transfers encode the payload length in the first data byte.
> When this first byte is zero, there is no payload and the transaction should
> terminate immediately.
> 
> On i.MX, if the first byte of an SMBus block read is zero, the driver
> unconditionally overwrites the state with IMX_I2C_STATE_READ_CONTINUE.
> This causes the state machine to enter an endless read loop, eventually
> overrunning internal buffers and leading to a crash.
> 
> At the same time, the controller remains in master receive mode and never
> generates a proper STOP condition, leaving the I2C bus permanently busy and
> preventing any further transfers on the bus.
> 
> Fix this by handling the zero-length case explicitly: when the first byte is zero,
> ensure that a clean STOP is generated. In this situation the controller is in
> master receive mode, so it must be switched to master transmit mode before
> stopping. This is done by draining the pending received byte from I2DR, setting
> I2CR_MTX to enter transmit mode, waiting briefly for the mode change, and
> then proceeding with the normal STOP sequence.
> 
> This change has been tested on i.MX 8M Plus platform.
> 
> Signed-off-by: LI Qingwu <Qing-wu.Li at leica-geosystems.com.cn>
> ---
>  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
> dcce882f3eba..f40deecf0f66 100644
> --- a/drivers/i2c/busses/i2c-imx.c
> +++ b/drivers/i2c/busses/i2c-imx.c
> @@ -735,6 +735,16 @@ static void i2c_imx_stop(struct imx_i2c_struct
> *i2c_imx, bool atomic)
>                 temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>                 if (!(temp & I2CR_MSTA))
>                         i2c_imx->stopped = 1;
> +               if ((temp & I2CR_MSTA) && !(temp & I2CR_MTX)) {
> +                       (void)imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
> +                       temp |= I2CR_MTX;
> +                       imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
> +                       if (atomic)
> +                               udelay(25);
> +                       else
> +                               usleep_range(25, 50);
> +                       temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
> +               }
Hi,

for fix a smbus block read stop, you added these codes to normal stop logic. Could you help check if it will effect stop in other path like i2c DMA/CPU read/write stop logic except for smbus block read?

And do you have mind to move this logic to smbus block read error path? This may be a minimal fix?

Carlos
>                 temp &= ~(I2CR_MSTA | I2CR_MTX);
>                 if (i2c_imx->dma)
>                         temp &= ~I2CR_DMAEN; @@ -1103,7 +1113,8
> @@ static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx,
> unsigned i
> 
>         case IMX_I2C_STATE_READ_BLOCK_DATA_LEN:
>                 i2c_imx_isr_read_block_data_len(i2c_imx);
> -               i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE;
> +               if (i2c_imx->state ==
> IMX_I2C_STATE_READ_BLOCK_DATA_LEN)
> +                       i2c_imx->state =
> IMX_I2C_STATE_READ_CONTINUE;
>                 break;
> 
>         case IMX_I2C_STATE_WRITE:
> --
> 2.43.0
> 




More information about the linux-arm-kernel mailing list