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