Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

i2c: imx: fix emulated smbus block read

Acknowledge the byte count submitted by the target.
When I2C_SMBUS_BLOCK_DATA read operation is executed by
i2c_smbus_xfer_emulated(), the length of the second (read) message is set
to 1. Length of the block is supposed to be obtained from the target by the
underlying bus driver.
The i2c_imx_isr_read() function should emit the acknowledge on i2c bus
after reading the first byte (i.e., byte count) while processing such
message (as defined in Section 6.5.7 of System Management Bus
Specification [1]). Without this acknowledge, the target does not submit
subsequent bytes and the controller only reads 0xff's.

In addition, store the length of block data obtained from the target in
the buffer provided by i2c_smbus_xfer_emulated() - otherwise the first
byte of actual data is erroneously interpreted as length of the data
block.

[1] https://smbus.org/specs/SMBus_3_3_20240512.pdf

Fixes: 5f5c2d4579ca ("i2c: imx: prevent rescheduling in non dma mode")
Signed-off-by: Lukasz Kucharczyk <lukasz.kucharczyk@leica-geosystems.com>
Cc: <stable@vger.kernel.org> # v6.13+
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Stefan Eichenberger <eichest@gmail.com>
Reviewed-by: Carlos Song <carlos.song@nxp.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Link: https://lore.kernel.org/r/20250520122252.1475403-1-lukasz.kucharczyk@leica-geosystems.com

authored by

Lukasz Kucharczyk and committed by
Andi Shyti
a5d0b9e3 86731a2a

+2 -1
+2 -1
drivers/i2c/busses/i2c-imx.c
··· 1008 1008 /* setup bus to read data */ 1009 1009 temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 1010 1010 temp &= ~I2CR_MTX; 1011 - if (i2c_imx->msg->len - 1) 1011 + if ((i2c_imx->msg->len - 1) || (i2c_imx->msg->flags & I2C_M_RECV_LEN)) 1012 1012 temp &= ~I2CR_TXAK; 1013 1013 1014 1014 imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); ··· 1063 1063 wake_up(&i2c_imx->queue); 1064 1064 } 1065 1065 i2c_imx->msg->len += len; 1066 + i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = len; 1066 1067 } 1067 1068 1068 1069 static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status)