]> 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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 15 Oct 2025 09:56:29 +0000 (11:56 +0200)
[ 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: 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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/i2c/busses/i2c-mt65xx.c

index fc7bfd98156ba730ff781aea280f87e4e07962e7..38d3dff7a2614991865a9f374c2277e3066cbd44 100644 (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;