ARMV7: Modify i2c driver for more reliable operation on OMAP4
authorSteve Sakoman <steve@sakoman.com>
Tue, 20 Jul 2010 03:31:55 +0000 (20:31 -0700)
committerSandeep Paulraj <s-paulraj@ti.com>
Thu, 5 Aug 2010 14:11:24 +0000 (10:11 -0400)
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>
arch/arm/include/asm/arch-omap3/i2c.h
drivers/i2c/omap24xx_i2c.c
drivers/i2c/omap24xx_i2c.h

index 7a4a73aa913a6a1686a391f7dce4816e2d20e3e3..d2e7488fd1bd5bf2ab4ae4360b66442321531c80 100644 (file)
@@ -34,7 +34,9 @@ struct i2c {
        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 */
index 3256133dc2ebbf897524af0d48411a0a44c55252..7c98f150d74f3d27d0035077ca6f00952b133600 100644 (file)
@@ -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 @@ void i2c_init (int speed, int slaveadd)
        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 @@ void i2c_init (int speed, int slaveadd)
                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 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
        }
 
        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 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
 
                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);
                        }
index 92a3416e0e3582e0f699eb5c3217f7b986ba0cbc..650e33a8887fdfd6541d308f06a102c4f1f642c3 100644 (file)
 #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