
Toggling the scl line 9 clocks is the standard way of returning a locked up bus to idle condition.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com --- drivers/i2c/mxc_i2c.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index ec05798..339bb6f 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -246,6 +246,8 @@ static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs, return 0; }
+static void toggle_i2c(void *i2c_regs); + static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, uchar chip, uint addr, int alen) { @@ -264,6 +266,7 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, if (ret != -ERESTART) writeb(0, &i2c_regs->i2cr); /* Disable controller */ udelay(100); + toggle_i2c(i2c_regs); } printf("%s: give up i2c_regs=%p\n", __func__, i2c_regs); return ret; @@ -381,6 +384,29 @@ void *get_base(void) #endif }
+static struct i2c_parms *i2c_get_parms(void *base) +{ + int i = 0; + struct i2c_parms *p = g_parms; + while (i < ARRAY_SIZE(g_parms)) { + if (p->base == base) + return p; + p++; + i++; + } + printf("Invalid I2C base: %p\n", base); + return NULL; +} + +static void toggle_i2c(void *base) +{ + struct i2c_parms *p = i2c_get_parms(base); + if (!p) + return; + if (p->toggle_fn) + p->toggle_fn(p->toggle_data); +} + int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) { return bus_i2c_read(get_base(), chip, addr, alen, buf, len);