All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v3 1/2] fsl_i2c: generate nine pulses on SCL if the I2C bus is hung
@ 2013-08-16  7:10 Chunhe Lan
  2013-08-16  7:10 ` [U-Boot] [PATCH v3 2/2] fsl_i2c: add workaround for the erratum I2C A004447 Chunhe Lan
  2013-08-20  9:20 ` [U-Boot] [PATCH v3 1/2] fsl_i2c: generate nine pulses on SCL if the I2C bus is hung Heiko Schocher
  0 siblings, 2 replies; 4+ messages in thread
From: Chunhe Lan @ 2013-08-16  7:10 UTC (permalink / raw)
  To: u-boot

When the code detected that the bus is hung (e.g. SDA stuck low),
send 9 pulses on SCL to try to fixup the bus.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Chunhe Lan <Chunhe.Lan@freescale.com>
Cc: Scott Wood <scottwood@freescale.com>
Cc: Heiko Schocher <hs@denx.de>
---
Changes for v2:
	- No change 
Changes for v3:
	- Rework codes for the newest mainline

 drivers/i2c/fsl_i2c.c |   59 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index 38455e1..44b08f7 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -206,9 +206,50 @@ static unsigned int get_i2c_clock(int bus)
 		return gd->arch.i2c1_clk;	/* I2C1 clock */
 }
 
+static int fsl_i2c_fixup(const struct fsl_i2c *dev)
+{
+	const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
+	unsigned long long timeval = 0;
+	int ret = -1;
+
+	writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
+
+	timeval = get_ticks();
+	while (!(readb(&dev->sr) & I2C_SR_MBB)) {
+		if ((get_ticks() - timeval) > timeout)
+			goto err;
+	}
+
+	if (readb(&dev->sr) & I2C_SR_MAL) {
+		/* SDA is stuck low */
+		writeb(0, &dev->cr);
+		udelay(100);
+		writeb(I2C_CR_MSTA, &dev->cr);
+		writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
+	}
+
+	readb(&dev->dr);
+
+	timeval = get_ticks();
+	while (!(readb(&dev->sr) & I2C_SR_MIF)) {
+		if ((get_ticks() - timeval) > timeout)
+			goto err;
+	}
+	ret = 0;
+
+err:
+	writeb(I2C_CR_MEN, &dev->cr);
+	writeb(0, &dev->sr);
+	udelay(100);
+
+	return ret;
+}
+
 static void fsl_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
 {
 	const struct fsl_i2c *dev;
+	const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
+	unsigned long long timeval;
 
 #ifdef CONFIG_SYS_I2C_INIT_BOARD
 	/* Call board specific i2c bus reset routine before accessing the
@@ -226,6 +267,18 @@ static void fsl_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
 	writeb(0x0, &dev->sr);		/* clear status register */
 	writeb(I2C_CR_MEN, &dev->cr);	/* start I2C controller */
 
+	timeval = get_ticks();
+	while (readb(&dev->sr) & I2C_SR_MBB) {
+		if ((get_ticks() - timeval) < timeout)
+			continue;
+
+		if (fsl_i2c_fixup(dev))
+			debug("i2c_init: BUS#%d failed to init\n",
+			      adap->hwadapnr);
+
+		break;
+	}
+
 #ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT
 	/* Call board specific i2c bus reset routine AFTER the bus has been
 	 * initialized. Use either this callpoint or i2c_init_board;
@@ -394,8 +447,10 @@ fsl_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, int alen,
 	int i = -1; /* signal error */
 	u8 *a = (u8*)&addr;
 
-	if (i2c_wait4bus(adap) >= 0 &&
-	    i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0 &&
+	if (i2c_wait4bus(adap) < 0)
+		return -1;
+
+	if (i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0 &&
 	    __i2c_write(adap, &a[4 - alen], alen) == alen) {
 		i = __i2c_write(adap, data, length);
 	}
-- 
1.7.6.5

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-08-20  9:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-16  7:10 [U-Boot] [PATCH v3 1/2] fsl_i2c: generate nine pulses on SCL if the I2C bus is hung Chunhe Lan
2013-08-16  7:10 ` [U-Boot] [PATCH v3 2/2] fsl_i2c: add workaround for the erratum I2C A004447 Chunhe Lan
2013-08-20  9:20   ` Heiko Schocher
2013-08-20  9:20 ` [U-Boot] [PATCH v3 1/2] fsl_i2c: generate nine pulses on SCL if the I2C bus is hung Heiko Schocher

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.