diff mbox

[U-Boot,3/5] i2c: imx: Optimize the i2c device recovery solution

Message ID 1420712470-3656-1-git-send-email-Peng.Fan@freescale.com
State Superseded
Delegated to: Stefano Babic
Headers show

Commit Message

Peng Fan Jan. 8, 2015, 10:21 a.m. UTC
From: Fugang Duan <b38611@freescale.com>

From i2c spec, if device pull down the SDA line that causes
i2c bus dead, host can send out 9 clock to let device release
SDA.

But for some special device like pfuze100, it pull down SDA line
and the solution cannot take effort.

The patch just add NACK and STOP signal after 8 dummy clock, and pmic
can release SDA line after the recovery. Test case catch 375 times of
i2c hang, and all are recovered.

Signed-off-by: Peng Fan <Peng.Fan@freescale.com>
Signed-off-by: Fugang Duan <B38611@freescale.com>
---
 arch/arm/imx-common/i2c-mxv7.c | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/arch/arm/imx-common/i2c-mxv7.c b/arch/arm/imx-common/i2c-mxv7.c
index 1a632e7..b1d4ec4 100644
--- a/arch/arm/imx-common/i2c-mxv7.c
+++ b/arch/arm/imx-common/i2c-mxv7.c
@@ -33,13 +33,36 @@  static int force_idle_bus(void *priv)
 
 	printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__,
 		sda, scl, p->sda.gp, p->scl.gp);
+	gpio_direction_output(p->scl.gp, 1);
+	udelay(1000);
 	/* Send high and low on the SCL line */
 	for (i = 0; i < 9; i++) {
-		gpio_direction_output(p->scl.gp, 0);
+		gpio_direction_output(p->scl.gp, 1);
 		udelay(50);
-		gpio_direction_input(p->scl.gp);
+		gpio_direction_output(p->scl.gp, 0);
 		udelay(50);
 	}
+
+	/* Simulate the NACK */
+	gpio_direction_output(p->sda.gp, 1);
+	udelay(50);
+	gpio_direction_output(p->scl.gp, 1);
+	udelay(50);
+	gpio_direction_output(p->scl.gp, 0);
+	udelay(50);
+
+	/* Simulate the STOP signal */
+	gpio_direction_output(p->sda.gp, 0);
+	udelay(50);
+	gpio_direction_output(p->scl.gp, 1);
+	udelay(50);
+	gpio_direction_output(p->sda.gp, 1);
+	udelay(50);
+
+	/* Get the bus status */
+	gpio_direction_input(p->sda.gp);
+	gpio_direction_input(p->scl.gp);
+
 	start_time = get_timer(0);
 	for (;;) {
 		sda = gpio_get_value(p->sda.gp);