ARMV7: Modify i2c driver for more reliable operation on OMAP4

This patch modifies the init routine to follow the TRM
recommendations. It also modifies the i2c_read_byte function
to reflect subtle differences between the i2c controller in
OMAP3 and OMAP4.

Signed-off-by:  Steve Sakoman <steve@sakoman.com>
Acked-by: Nishanth Menon <menon.nishanth@gmail.com>
Acked-by: Heiko Schocher <hs@denx.de>
Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com>
diff --git a/arch/arm/include/asm/arch-omap3/i2c.h b/arch/arm/include/asm/arch-omap3/i2c.h
index 7a4a73a..d2e7488 100644
--- a/arch/arm/include/asm/arch-omap3/i2c.h
+++ b/arch/arm/include/asm/arch-omap3/i2c.h
@@ -34,7 +34,9 @@
 	unsigned short stat;	/* 0x08 */
 	unsigned short res3;
 	unsigned short iv;	/* 0x0C */
-	unsigned short res4[3];
+	unsigned short res4;
+	unsigned short syss;	/* 0x10 */
+	unsigned short res4a;
 	unsigned short buf;	/* 0x14 */
 	unsigned short res5;
 	unsigned short cnt;	/* 0x18 */
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 3256133..7c98f15 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -27,6 +27,8 @@
 
 #include "omap24xx_i2c.h"
 
+#define I2C_TIMEOUT	10
+
 static void wait_for_bb (void);
 static u16 wait_for_pin (void);
 static void flush_fifo(void);
@@ -41,6 +43,7 @@
 	int psc, fsscll, fssclh;
 	int hsscll = 0, hssclh = 0;
 	u32 scll, sclh;
+	int timeout = I2C_TIMEOUT;
 
 	/* Only handle standard, fast and high speeds */
 	if ((speed != OMAP_I2C_STANDARD) &&
@@ -102,15 +105,24 @@
 		sclh = (unsigned int)fssclh;
 	}
 
-	writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */
-	udelay(1000);
-	writew(0x0, &i2c_base->sysc); /* will probably self clear but */
-
 	if (readw (&i2c_base->con) & I2C_CON_EN) {
 		writew (0, &i2c_base->con);
 		udelay (50000);
 	}
 
+	writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */
+	udelay(1000);
+
+	writew(I2C_CON_EN, &i2c_base->con);
+	while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) {
+		if (timeout <= 0) {
+			printf("ERROR: Timeout in soft-reset\n");
+			return;
+		}
+		udelay(1000);
+	}
+
+	writew(0, &i2c_base->con);
 	writew(psc, &i2c_base->psc);
 	writew(scll, &i2c_base->scll);
 	writew(sclh, &i2c_base->sclh);
@@ -159,15 +171,14 @@
 	}
 
 	if (!i2c_error) {
-		/* free bus, otherwise we can't use a combined transction */
-		writew (0, &i2c_base->con);
-		while (readw (&i2c_base->stat) || (readw (&i2c_base->con) & I2C_CON_MST)) {
+		writew (I2C_CON_EN, &i2c_base->con);
+		while (readw(&i2c_base->stat) &
+			(I2C_STAT_XRDY | I2C_STAT_ARDY)) {
 			udelay (10000);
 			/* Have to clear pending interrupt to clear I2C_STAT */
 			writew (0xFFFF, &i2c_base->stat);
 		}
 
-		wait_for_bb ();
 		/* set slave address */
 		writew (devaddr, &i2c_base->sa);
 		/* read one byte from slave */
@@ -191,8 +202,8 @@
 
 		if (!i2c_error) {
 			writew (I2C_CON_EN, &i2c_base->con);
-			while (readw (&i2c_base->stat)
-			       || (readw (&i2c_base->con) & I2C_CON_MST)) {
+			while (readw (&i2c_base->stat) &
+				(I2C_STAT_RRDY | I2C_STAT_ARDY)) {
 				udelay (10000);
 				writew (0xFFFF, &i2c_base->stat);
 			}
diff --git a/drivers/i2c/omap24xx_i2c.h b/drivers/i2c/omap24xx_i2c.h
index 92a3416..650e33a 100644
--- a/drivers/i2c/omap24xx_i2c.h
+++ b/drivers/i2c/omap24xx_i2c.h
@@ -85,6 +85,10 @@
 #define I2C_SYSTEST_SDA_I	(1 << 1)  /* SDA line sense input value */
 #define I2C_SYSTEST_SDA_O	(1 << 0)  /* SDA line drive output value */
 
+/* I2C System Status Register (I2C_SYSS): */
+
+#define I2C_SYSS_RDONE          (1 << 0)  /* Internel reset monitoring */
+
 #define I2C_SCLL_SCLL		0
 #define I2C_SCLL_SCLL_M		0xFF
 #define I2C_SCLL_HSSCLL		8