mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 11:19:37 +00:00
Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
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
This commit is contained in:
commit
da690031a5
2 changed files with 39 additions and 19 deletions
|
@ -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_MASK,
|
||||
(div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
|
||||
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
|
||||
FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue