[U-Boot] [PATCH 3/8] ARMV7: Modify i2c driver for more reliable operation on OMAP4

Steve Sakoman
2010-07-21T19:25:24Z

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 <steve@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