]> git.sur5r.net Git - u-boot/blobdiff - drivers/i2c/omap24xx_i2c.c
Merge branch 'master' of git://git.denx.de/u-boot-arm
[u-boot] / drivers / i2c / omap24xx_i2c.c
index 3256133dc2ebbf897524af0d48411a0a44c55252..fab49fd969eabb48487feb469c195612bedd2e1f 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "omap24xx_i2c.h"
 
+#define I2C_TIMEOUT    1000
+
 static void wait_for_bb (void);
 static u16 wait_for_pin (void);
 static void flush_fifo(void);
@@ -38,9 +40,11 @@ static unsigned int current_bus;
 
 void i2c_init (int speed, int slaveadd)
 {
+       DECLARE_GLOBAL_DATA_PTR;
        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 +106,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);
@@ -127,7 +140,8 @@ void i2c_init (int speed, int slaveadd)
        writew (0xFFFF, &i2c_base->stat);
        writew (0, &i2c_base->cnt);
 
-       bus_initialized[current_bus] = 1;
+       if (gd->flags & GD_FLG_RELOC)
+               bus_initialized[current_bus] = 1;
 }
 
 static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
@@ -145,59 +159,56 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
        /* no stop bit needed here */
        writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, &i2c_base->con);
 
-       status = wait_for_pin ();
-
-       if (status & I2C_STAT_XRDY) {
-               /* Important: have to use byte access */
-               writeb (regoffset, &i2c_base->data);
-               udelay (20000);
-               if (readw (&i2c_base->stat) & I2C_STAT_NACK) {
+       /* send register offset */
+       while (1) {
+               status = wait_for_pin();
+               if (status == 0 || status & I2C_STAT_NACK) {
                        i2c_error = 1;
+                       goto read_exit;
+               }
+               if (status & I2C_STAT_XRDY) {
+                       /* Important: have to use byte access */
+                       writeb(regoffset, &i2c_base->data);
+                       writew(I2C_STAT_XRDY, &i2c_base->stat);
+               }
+               if (status & I2C_STAT_ARDY) {
+                       writew(I2C_STAT_ARDY, &i2c_base->stat);
+                       break;
                }
-       } else {
-               i2c_error = 1;
        }
 
-       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)) {
-                       udelay (10000);
-                       /* Have to clear pending interrupt to clear I2C_STAT */
-                       writew (0xFFFF, &i2c_base->stat);
+       /* set slave address */
+       writew(devaddr, &i2c_base->sa);
+       /* read one byte from slave */
+       writew(1, &i2c_base->cnt);
+       /* need stop bit here */
+       writew(I2C_CON_EN | I2C_CON_MST |
+               I2C_CON_STT | I2C_CON_STP,
+               &i2c_base->con);
+
+       /* receive data */
+       while (1) {
+               status = wait_for_pin();
+               if (status == 0 || status & I2C_STAT_NACK) {
+                       i2c_error = 1;
+                       goto read_exit;
                }
-
-               wait_for_bb ();
-               /* set slave address */
-               writew (devaddr, &i2c_base->sa);
-               /* read one byte from slave */
-               writew (1, &i2c_base->cnt);
-               /* need stop bit here */
-               writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
-                       &i2c_base->con);
-
-               status = wait_for_pin ();
                if (status & I2C_STAT_RRDY) {
 #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
     defined(CONFIG_OMAP44XX)
-                       *value = readb (&i2c_base->data);
+                       *value = readb(&i2c_base->data);
 #else
-                       *value = readw (&i2c_base->data);
+                       *value = readw(&i2c_base->data);
 #endif
-                       udelay (20000);
-               } else {
-                       i2c_error = 1;
+                       writew(I2C_STAT_RRDY, &i2c_base->stat);
                }
-
-               if (!i2c_error) {
-                       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 (status & I2C_STAT_ARDY) {
+                       writew(I2C_STAT_ARDY, &i2c_base->stat);
+                       break;
                }
        }
+
+read_exit:
        flush_fifo();
        writew (0xFFFF, &i2c_base->stat);
        writew (0, &i2c_base->cnt);
@@ -207,7 +218,7 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
 static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
 {
        int i2c_error = 0;
-       u16 status, stat;
+       u16 status;
 
        /* wait until bus not busy */
        wait_for_bb ();
@@ -220,49 +231,55 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
        writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
                I2C_CON_STP, &i2c_base->con);
 
-       /* wait until state change */
-       status = wait_for_pin ();
-
-       if (status & I2C_STAT_XRDY) {
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-    defined(CONFIG_OMAP44XX)
-               /* send out 1 byte */
-               writeb (regoffset, &i2c_base->data);
-               writew (I2C_STAT_XRDY, &i2c_base->stat);
-
-               status = wait_for_pin ();
-               if ((status & I2C_STAT_XRDY)) {
-                       /* send out next 1 byte */
-                       writeb (value, &i2c_base->data);
-                       writew (I2C_STAT_XRDY, &i2c_base->stat);
-               } else {
+       while (1) {
+               status = wait_for_pin();
+               if (status == 0 || status & I2C_STAT_NACK) {
                        i2c_error = 1;
+                       goto write_exit;
                }
+               if (status & I2C_STAT_XRDY) {
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+    defined(CONFIG_OMAP44XX)
+                       /* send register offset */
+                       writeb(regoffset, &i2c_base->data);
+                       writew(I2C_STAT_XRDY, &i2c_base->stat);
+
+                       while (1) {
+                               status = wait_for_pin();
+                               if (status == 0 || status & I2C_STAT_NACK) {
+                                       i2c_error = 1;
+                                       goto write_exit;
+                               }
+                               if (status & I2C_STAT_XRDY) {
+                                       /* send data */
+                                       writeb(value, &i2c_base->data);
+                                       writew(I2C_STAT_XRDY, &i2c_base->stat);
+                               }
+                               if (status & I2C_STAT_ARDY) {
+                                       writew(I2C_STAT_ARDY, &i2c_base->stat);
+                                       break;
+                               }
+                       }
+                       break;
 #else
-               /* send out two bytes */
-               writew ((value << 8) + regoffset, &i2c_base->data);
+                       /* send out two bytes */
+                       writew((value << 8) + regoffset, &i2c_base->data);
+                       writew(I2C_STAT_XRDY, &i2c_base->stat);
 #endif
-               /* must have enough delay to allow BB bit to go low */
-               udelay (50000);
-               if (readw (&i2c_base->stat) & I2C_STAT_NACK) {
-                       i2c_error = 1;
                }
-       } else {
-               i2c_error = 1;
+               if (status & I2C_STAT_ARDY) {
+                       writew(I2C_STAT_ARDY, &i2c_base->stat);
+                       break;
+               }
        }
 
-       if (!i2c_error) {
-               int eout = 200;
+       wait_for_bb();
 
-               writew (I2C_CON_EN, &i2c_base->con);
-               while ((stat = readw (&i2c_base->stat)) || (readw (&i2c_base->con) & I2C_CON_MST)) {
-                       udelay (1000);
-                       /* have to read to clear intrrupt */
-                       writew (0xFFFF, &i2c_base->stat);
-                       if(--eout == 0) /* better leave with error than hang */
-                               break;
-               }
-       }
+       status = readw(&i2c_base->stat);
+       if (status & I2C_STAT_NACK)
+               i2c_error = 1;
+
+write_exit:
        flush_fifo();
        writew (0xFFFF, &i2c_base->stat);
        writew (0, &i2c_base->cnt);
@@ -293,6 +310,7 @@ static void flush_fifo(void)
 
 int i2c_probe (uchar chip)
 {
+       u16 status;
        int res = 1; /* default = fail */
 
        if (chip == readw (&i2c_base->oa)) {
@@ -308,19 +326,37 @@ int i2c_probe (uchar chip)
        writew (chip, &i2c_base->sa);
        /* stop bit needed here */
        writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con);
-       /* enough delay for the NACK bit set */
-       udelay (50000);
 
-       if (!(readw (&i2c_base->stat) & I2C_STAT_NACK)) {
-               res = 0;      /* success case */
-               flush_fifo();
-               writew(0xFFFF, &i2c_base->stat);
-       } else {
-               writew(0xFFFF, &i2c_base->stat);         /* failue, clear sources*/
-               writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con); /* finish up xfer */
-               udelay(20000);
-               wait_for_bb ();
+       while (1) {
+               status = wait_for_pin();
+               if (status == 0 || status & I2C_STAT_AL) {
+                       res = 1;
+                       goto probe_exit;
+               }
+               if (status & I2C_STAT_NACK) {
+                       res = 1;
+                       writew(0xff, &i2c_base->stat);
+                       writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con);
+                       wait_for_bb ();
+                       break;
+               }
+               if (status & I2C_STAT_ARDY) {
+                       writew(I2C_STAT_ARDY, &i2c_base->stat);
+                       break;
+               }
+               if (status & I2C_STAT_RRDY) {
+                       res = 0;
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+    defined(CONFIG_OMAP44XX)
+                       readb(&i2c_base->data);
+#else
+                       readw(&i2c_base->data);
+#endif
+                       writew(I2C_STAT_RRDY, &i2c_base->stat);
+               }
        }
+
+probe_exit:
        flush_fifo();
        writew (0, &i2c_base->cnt); /* don't allow any more data in...we don't want it.*/
        writew(0xFFFF, &i2c_base->stat);
@@ -379,13 +415,13 @@ int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
 
 static void wait_for_bb (void)
 {
-       int timeout = 10;
+       int timeout = I2C_TIMEOUT;
        u16 stat;
 
        writew(0xFFFF, &i2c_base->stat);         /* clear current interruts...*/
        while ((stat = readw (&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
                writew (stat, &i2c_base->stat);
-               udelay (50000);
+               udelay(1000);
        }
 
        if (timeout <= 0) {
@@ -398,7 +434,7 @@ static void wait_for_bb (void)
 static u16 wait_for_pin (void)
 {
        u16 status;
-       int timeout = 10;
+       int timeout = I2C_TIMEOUT;
 
        do {
                udelay (1000);
@@ -411,8 +447,10 @@ static u16 wait_for_pin (void)
        if (timeout <= 0) {
                printf ("timed out in wait_for_pin: I2C_STAT=%x\n",
                        readw (&i2c_base->stat));
-                       writew(0xFFFF, &i2c_base->stat);
-}
+               writew(0xFFFF, &i2c_base->stat);
+               status = 0;
+       }
+
        return status;
 }
 
@@ -445,4 +483,3 @@ int i2c_get_bus_num(void)
 {
        return (int) current_bus;
 }
-