i2c: mediatek: fix potential incorrect use of I2C_MASTER_WRRD

[ Upstream commit b492183652808e0f389272bf63dc836241b287ff ]

The old IC does not support the I2C_MASTER_WRRD (write-then-read)
function, but the current code’s handling of i2c->auto_restart may
potentially lead to entering the I2C_MASTER_WRRD software flow,
resulting in unexpected bugs.

Instead of repurposing the auto_restart flag, add a separate flag
to signal I2C_MASTER_WRRD operations.

Also fix handling of msgs. If the operation (i2c->op) is
I2C_MASTER_WRRD, then the msgs pointer is incremented by 2.
For all other operations, msgs is simply incremented by 1.

Fixes: b2ed11e224 ("I2C: mediatek: Add driver for MediaTek MT8173 I2C controller")
Signed-off-by: Leilk.Liu <leilk.liu@mediatek.com>
Suggested-by: Chen-Yu Tsai <wenst@chromium.org>
Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Leilk.Liu 2025-09-06 16:24:06 +08:00 committed by Greg Kroah-Hartman
parent e8de297fa4
commit 07f952d5d2

View File

@ -1218,6 +1218,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
{
int ret;
int left_num = num;
bool write_then_read_en = false;
struct mtk_i2c *i2c = i2c_get_adapdata(adap);
ret = clk_bulk_enable(I2C_MT65XX_CLK_MAX, i2c->clocks);
@ -1231,6 +1232,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
msgs[0].addr == msgs[1].addr) {
i2c->auto_restart = 0;
write_then_read_en = true;
}
}
@ -1255,12 +1257,10 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
else
i2c->op = I2C_MASTER_WR;
if (!i2c->auto_restart) {
if (num > 1) {
/* combined two messages into one transaction */
i2c->op = I2C_MASTER_WRRD;
left_num--;
}
if (write_then_read_en) {
/* combined two messages into one transaction */
i2c->op = I2C_MASTER_WRRD;
left_num--;
}
/* always use DMA mode. */
@ -1268,7 +1268,10 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
if (ret < 0)
goto err_exit;
msgs++;
if (i2c->op == I2C_MASTER_WRRD)
msgs += 2;
else
msgs++;
}
/* the return value is number of executed messages */
ret = num;