In addition to modifying the init routine to follow the TRM
recommendations, this patch adds a retry count to two loops
to avoid the possibility of infinite loops.  It also corrects
error message typos in the i2c_write routine.

Signed-off-by:  Steve Sakoman <st...@sakoman.com>
---
 arch/arm/include/asm/arch-omap3/i2c.h |    4 ++-
 drivers/i2c/omap24xx_i2c.c            |   37 ++++++++++++++++++++++----------
 drivers/i2c/omap24xx_i2c.h            |    4 +++
 3 files changed, 32 insertions(+), 13 deletions(-)

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 @@ 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 */
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 3256133..a91fe55 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -41,6 +41,7 @@ void i2c_init (int speed, int slaveadd)
        int psc, fsscll, fssclh;
        int hsscll = 0, hssclh = 0;
        u32 scll, sclh;
+       int reset_timeout = 10;
 
        /* Only handle standard, fast and high speeds */
        if ((speed != OMAP_I2C_STANDARD) &&
@@ -102,15 +103,22 @@ 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) && reset_timeout--) {
+               if (reset_timeout <= 0)
+                       printf("ERROR: Timeout in soft-reset\n");
+               udelay(1000);
+       }
+
+       writew(0, &i2c_base->con);
        writew(psc, &i2c_base->psc);
        writew(scll, &i2c_base->scll);
        writew(sclh, &i2c_base->sclh);
@@ -134,6 +142,7 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * 
value)
 {
        int i2c_error = 0;
        u16 status;
+       u16 retries;
 
        /* wait until bus not busy */
        wait_for_bb ();
@@ -159,15 +168,16 @@ 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)) {
+               retries = 10;
+               while ((readw(&i2c_base->stat) & 0x14) ||
+                       (readw(&i2c_base->con) & I2C_CON_MST)) {
                        udelay (10000);
                        /* Have to clear pending interrupt to clear I2C_STAT */
                        writew (0xFFFF, &i2c_base->stat);
+                       if (!retries--)
+                               break;
                }
 
-               wait_for_bb ();
                /* set slave address */
                writew (devaddr, &i2c_base->sa);
                /* read one byte from slave */
@@ -190,11 +200,14 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * 
value)
                }
 
                if (!i2c_error) {
+                       retries = 10;
                        writew (I2C_CON_EN, &i2c_base->con);
                        while (readw (&i2c_base->stat)
                               || (readw (&i2c_base->con) & I2C_CON_MST)) {
                                udelay (10000);
                                writew (0xFFFF, &i2c_base->stat);
+                               if (!retries--)
+                                       break;
                        }
                }
        }
@@ -276,7 +289,7 @@ static void flush_fifo(void)
         * you get a bus error
         */
        while(1){
-               stat = readw(&i2c_base->stat);
+               stat = readw(&i2c_base->stat) & I2C_STAT_RRDY;
                if(stat == I2C_STAT_RRDY){
 #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
     defined(CONFIG_OMAP44XX)
@@ -357,18 +370,18 @@ int i2c_write (uchar chip, uint addr, int alen, uchar * 
buffer, int len)
        int i;
 
        if (alen > 1) {
-               printf ("I2C read: addr len %d not supported\n", alen);
+               printf("I2C write: addr len %d not supported\n", alen);
                return 1;
        }
 
        if (addr + len > 256) {
-               printf ("I2C read: address out of range\n");
+               printf("I2C write: address out of range\n");
                return 1;
        }
 
        for (i = 0; i < len; i++) {
                if (i2c_write_byte (chip, addr + i, buffer[i])) {
-                       printf ("I2C read: I/O error\n");
+                       printf("I2C write: I/O error\n");
                        i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
                        return 1;
                }
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
-- 
1.7.0.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to