Commit da690031 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull i2c fixes from Wolfram Sang:
 "Some more driver bugfixes for I2C. Including a revert - the updated
  series for it will come during the next merge window"

* 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: owl: Clear NACK and BUS error bits
  Revert "i2c: imx: Fix reset of I2SR_IAL flag"
  i2c: meson: fixup rate calculation with filter delay
  i2c: meson: keep peripheral clock enabled
  i2c: meson: fix clock setting overwrite
  i2c: imx: Fix reset of I2SR_IAL flag
parents 64b7f674 f5b3f433
Loading
Loading
Loading
Loading
+33 −19
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
 */

#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/i2c.h>
@@ -33,12 +34,17 @@
#define REG_CTRL_ACK_IGNORE	BIT(1)
#define REG_CTRL_STATUS		BIT(2)
#define REG_CTRL_ERROR		BIT(3)
#define REG_CTRL_CLKDIV_SHIFT	12
#define REG_CTRL_CLKDIV_MASK	GENMASK(21, 12)
#define REG_CTRL_CLKDIVEXT_SHIFT 28
#define REG_CTRL_CLKDIVEXT_MASK	GENMASK(29, 28)
#define REG_CTRL_CLKDIV		GENMASK(21, 12)
#define REG_CTRL_CLKDIVEXT	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
#define FILTER_DELAY		15

enum {
	TOKEN_END = 0,
@@ -133,19 +139,24 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
	unsigned long clk_rate = clk_get_rate(i2c->clk);
	unsigned int div;

	div = DIV_ROUND_UP(clk_rate, freq * i2c->data->div_factor);
	div = DIV_ROUND_UP(clk_rate, freq);
	div -= FILTER_DELAY;
	div = DIV_ROUND_UP(div, i2c->data->div_factor);

	/* clock divider has 12 bits */
	if (div >= (1 << 12)) {
	if (div > GENMASK(11, 0)) {
		dev_err(i2c->dev, "requested bus frequency too low\n");
		div = (1 << 12) - 1;
		div = GENMASK(11, 0);
	}

	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
			   (div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV,
			   FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0)));

	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
			   FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));

	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);
@@ -280,7 +291,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);
}
@@ -357,16 +371,12 @@ static int meson_i2c_xfer_messages(struct i2c_adapter *adap,
	struct meson_i2c *i2c = adap->algo_data;
	int i, ret = 0;

	clk_enable(i2c->clk);

	for (i = 0; i < num; i++) {
		ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1, atomic);
		if (ret)
			break;
	}

	clk_disable(i2c->clk);

	return ret ?: i;
}

@@ -435,7 +445,7 @@ static int meson_i2c_probe(struct platform_device *pdev)
		return ret;
	}

	ret = clk_prepare(i2c->clk);
	ret = clk_prepare_enable(i2c->clk);
	if (ret < 0) {
		dev_err(&pdev->dev, "can't prepare clock\n");
		return ret;
@@ -457,10 +467,14 @@ static int meson_i2c_probe(struct platform_device *pdev)

	ret = i2c_add_adapter(&i2c->adap);
	if (ret < 0) {
		clk_unprepare(i2c->clk);
		clk_disable_unprepare(i2c->clk);
		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;
@@ -471,7 +485,7 @@ static int meson_i2c_remove(struct platform_device *pdev)
	struct meson_i2c *i2c = platform_get_drvdata(pdev);

	i2c_del_adapter(&i2c->adap);
	clk_unprepare(i2c->clk);
	clk_disable_unprepare(i2c->clk);

	return 0;
}
+6 −0
Original line number Diff line number Diff line
@@ -176,6 +176,9 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
	fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT);
	if (fifostat & OWL_I2C_FIFOSTAT_RNB) {
		i2c_dev->err = -ENXIO;
		/* Clear NACK error bit by writing "1" */
		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
				   OWL_I2C_FIFOSTAT_RNB, true);
		goto stop;
	}

@@ -183,6 +186,9 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
	stat = readl(i2c_dev->base + OWL_I2C_REG_STAT);
	if (stat & OWL_I2C_STAT_BEB) {
		i2c_dev->err = -EIO;
		/* Clear BUS error bit by writing "1" */
		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
				   OWL_I2C_STAT_BEB, true);
		goto stop;
	}