diff mbox

[U-Boot,2/2,v2] Powerpc/i2c: Force i2c to become bus master out of reset

Message ID 1319695038-12804-1-git-send-email-Chang-Ming.huang@freescale.com
State Changes Requested
Delegated to: Heiko Schocher
Headers show

Commit Message

Jerry Huang Oct. 27, 2011, 5:57 a.m. UTC
From: Jerry Huang <Chang-Ming.Huang@freescale.com>

It is sometimes necessary to force the I2C module to become the I2C bus master
out of reset and drive SCL(even though SDA may already be driven,
which indicates that the bus is busy). This can occur when a system reset
does not cause all I2C devices to be reset. Thus, SDA can be driven low
by another I2C device while this I2C module is coming out of reset
and stays low indefinitely. The following procedure can be used to
force this I2C module to generate SCL so that the device driving SDA
can finish its transaction.

Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
---
changes for v2:
	- fix multilines comment error
	- add the 2011 copyright

 drivers/i2c/fsl_i2c.c |   22 +++++++++++++++++++++-
 1 files changed, 21 insertions(+), 1 deletions(-)
diff mbox

Patch

diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index 258be0a..c2be3cb 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -1,5 +1,5 @@ 
 /*
- * Copyright 2006,2009 Freescale Semiconductor, Inc.
+ * Copyright 2006,2009,2011 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -252,6 +252,26 @@  i2c_init(int speed, int slaveadd)
 		writeb(slaveadd << 1, &dev->adr);/* write slave address */
 		writeb(0x0, &dev->sr);		/* clear status register */
 		writeb(I2C_CR_MEN, &dev->cr);	/* start I2C controller */
+
+		/*
+		 * Force I2C module to become bus master which can occure when
+		 * a system reset does not cause all I2C devices to be reset.
+		 */
+		udelay(5);
+		if (readb(&dev->sr) & I2C_SR_MBB) {
+			writeb(I2C_CR_MSTA, &dev->cr);
+			udelay(5);
+			writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
+			udelay(5);
+			readb(&dev->dr);
+			udelay(5);
+			writeb(I2C_CR_MEN, &dev->cr);
+			udelay(5);
+			if (readb(&dev->sr) & I2C_SR_MBB)
+				debug("I2C%d: Drive SCL failed\n", i + 1);
+			else
+				debug("I2C%d: Drive SCL succeed\n", i + 1);
+		}
 	}
 
 #ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT