From: Jerome Brunet <jbru...@baylibre.com>

commit 28683e847e2f20eed22cdd24f185d7783db396d3 upstream.

When the slave address is written in do_start(), SLAVE_ADDR is written
completely. This may overwrite some setting related to the clock rate
or signal filtering.

Fix this by writing only the bits related to slave address. To avoid
causing unexpected changed, explicitly disable filtering or high/low
clock mode which may have been left over by the bootloader.

Fixes: 30021e3707a7 ("i2c: add support for Amlogic Meson I2C controller")
Signed-off-by: Jerome Brunet <jbru...@baylibre.com>
Signed-off-by: Wolfram Sang <w...@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/i2c/busses/i2c-meson.c |   19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

--- a/drivers/i2c/busses/i2c-meson.c
+++ b/drivers/i2c/busses/i2c-meson.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2014 Beniamino Galvani <b.galv...@gmail.com>
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/i2c.h>
@@ -37,6 +38,12 @@
 #define REG_CTRL_CLKDIVEXT_SHIFT 28
 #define REG_CTRL_CLKDIVEXT_MASK        GENMASK(29, 28)
 
+#define REG_SLV_ADDR           GENMASK(7, 0)
+#define REG_SLV_SDA_FILTER     GENMASK(10, 8)
+#define REG_SLV_SCL_FILTER     GENMASK(13, 11)
+#define REG_SLV_SCL_LOW                GENMASK(27, 16)
+#define REG_SLV_SCL_LOW_EN     BIT(28)
+
 #define I2C_TIMEOUT_MS         500
 
 enum {
@@ -146,6 +153,9 @@ static void meson_i2c_set_clk_div(struct
        meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
                           (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
 
+       /* Disable HIGH/LOW mode */
+       meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
+
        dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__,
                clk_rate, freq, div);
 }
@@ -273,7 +283,10 @@ static void meson_i2c_do_start(struct me
        token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ :
                TOKEN_SLAVE_ADDR_WRITE;
 
-       writel(msg->addr << 1, i2c->regs + REG_SLAVE_ADDR);
+
+       meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR,
+                          FIELD_PREP(REG_SLV_ADDR, msg->addr << 1));
+
        meson_i2c_add_token(i2c, TOKEN_START);
        meson_i2c_add_token(i2c, token);
 }
@@ -432,6 +445,10 @@ static int meson_i2c_probe(struct platfo
                return ret;
        }
 
+       /* Disable filtering */
+       meson_i2c_set_mask(i2c, REG_SLAVE_ADDR,
+                          REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0);
+
        meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);
 
        return 0;


Reply via email to