]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
i2c: mediatek: fix potential incorrect use of I2C_MASTER_WRRD
authorLeilk.Liu <leilk.liu@mediatek.com>
Sat, 6 Sep 2025 08:24:06 +0000 (16:24 +0800)
committerWolfram Sang <wsa+renesas@sang-engineering.com>
Thu, 25 Sep 2025 21:14:59 +0000 (23:14 +0200)
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: b2ed11e224a2 ("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>
drivers/i2c/busses/i2c-mt65xx.c

index ab456c3717db18eef74226de0ee88c49228796f5..dee40704825cb45727757f2a8913e1676675c067 100644 (file)
@@ -1243,6 +1243,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);
@@ -1256,6 +1257,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;
                }
        }
 
@@ -1280,12 +1282,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. */
@@ -1293,7 +1293,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;