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 <steve@sakoman.com>
Acked-by: Nishanth Menon <menon.nishanth@gmail.com>
Acked-by: Heiko Schocher <hs@denx.de>
Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com>
master
Steve Sakoman 14 years ago committed by Sandeep Paulraj
parent 674e0b217f
commit d708395d2f
  1. 4
      arch/arm/include/asm/arch-omap3/i2c.h
  2. 31
      drivers/i2c/omap24xx_i2c.c
  3. 4
      drivers/i2c/omap24xx_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 */

@ -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);
}

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

Loading…
Cancel
Save