From d708395d2f83295fba9d9b18823ce17046793590 Mon Sep 17 00:00:00 2001 From: Steve Sakoman Date: Mon, 19 Jul 2010 20:31:55 -0700 Subject: [PATCH] ARMV7: Modify i2c driver for more reliable operation on OMAP4 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 Acked-by: Nishanth Menon Acked-by: Heiko Schocher Signed-off-by: Sandeep Paulraj --- arch/arm/include/asm/arch-omap3/i2c.h | 4 +++- drivers/i2c/omap24xx_i2c.c | 31 +++++++++++++++++++++---------- drivers/i2c/omap24xx_i2c.h | 4 ++++ 3 files changed, 28 insertions(+), 11 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..7c98f15 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -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); } 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