Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 59b6343f authored by Jerome Brunet's avatar Jerome Brunet Committed by Greg Kroah-Hartman
Browse files

i2c: meson: fix clock setting overwrite



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: 30021e37 ("i2c: add support for Amlogic Meson I2C controller")
Signed-off-by: default avatarJerome Brunet <jbrunet@baylibre.com>
Signed-off-by: default avatarWolfram Sang <wsa@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent eb13209e
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 * published by the Free Software Foundation.
 */

#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/i2c.h>
@@ -40,6 +41,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 {
@@ -149,6 +156,9 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
	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);
}
@@ -276,7 +286,10 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
	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);
}
@@ -435,6 +448,10 @@ static int meson_i2c_probe(struct platform_device *pdev)
		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;