diff options
author | Tom Rix <Tom.Rix@windriver.com> | 2009-06-28 12:52:27 -0500 |
---|---|---|
committer | Heiko Schocher <hs@denx.de> | 2009-07-28 08:52:33 +0200 |
commit | 7f79dfb48b7419d5caa1cf932fcff4e2fb7040af (patch) | |
tree | 41dbf9667325a5595cf4baa0994fc36934c10429 /drivers/i2c | |
parent | 4ce5a72851ff2960543b125866c6132e0094e1ee (diff) |
OMAP I2C Fix the sampling clock.
This problem is seen on Zoom1 and Zoom2 in the startup and
when i2c probe is used
Before :
In: serial
Out: serial
Err: serial
timed out in wait_for_bb: I2C_STAT=1000
timed out in wait_for_bb: I2C_STAT=1000
timed out in wait_for_bb: I2C_STAT=1000
timed out in wait_for_pin: I2C_STAT=1000
I2C read: I/O error
timed out in wait_for_bb: I2C_STAT=1000
timed out in wait_for_bb: I2C_STAT=1000
Die ID #327c00020000000004013ddd05026013
Hit any key to stop autoboot: 0
OMAP3 Zoom1# i2c probe
Valid chip addresses:timed out in wait_for_bb: I2C_STAT=1000
02 03 04 05 06 07 08 09 0A 0B 0C 0D <snip>
After :
In: serial
Out: serial
Err: serial
Die ID #327c00020000000004013ddd05026013
Hit any key to stop autoboot: 0
OMAP3 Zoom1# i2c probe
Valid chip addresses: 48 49 4A 4B
The addresses are for the twl4030.
The prescalar that converts the function clock to the sampling
clock is hardcoded to 0. The reference manual recommends 7
if the function clock is 96MHz.
Instead of just changing the hardcoded values, the prescalar
is calculated from the value I2C_IP_CLK.
The i2c #defines are in kHz. The speed passed into the
i2c init routine is in Hz. To be consistent, change the
defines to be in Hz.
The timing calculations are based on what is done in the
linux 2.6.30 kernel in drivers/i2c/buses/i2c_omap.c as
apposed to what is done in TRM.
The major variables in the timing caculations are
specified as #defines that can be overriden as required.
The variables and their defaults are
I2C_IP_CLK SYSTEM_CLOCK_96
I2C_INTERNAL_SAMPLING_CLK 19200000
I2C_FASTSPEED_SCLL_TRIM 6
I2C_FASTSPEED_SCLH_TRIM 6
I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
I2C_HIGHSPEED_PHASE_TWO_SCLH I2C_FASTSPEED_SCLH_TRIM
This was runtime verified on Zoom1, Zoom2, Beagle and Overo.
The 400kHz and 3.4M cases were verifed on test Zoom1,
Zoom2, Beagle and Overo configurations.
Testing for omap2 will be done in a second step as Nishanth
and Jean-Christophe commented.
Signed-off-by: Tom Rix <Tom.Rix@windriver.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Heiko Schocher <hs@denx.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/omap24xx_i2c.c | 74 |
1 files changed, 67 insertions, 7 deletions
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 678460325dd..1a4c8c9ad27 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -31,7 +31,69 @@ static void flush_fifo(void); void i2c_init (int speed, int slaveadd) { - u16 scl; + int psc, fsscll, fssclh; + int hsscll = 0, hssclh = 0; + u32 scll, sclh; + + /* Only handle standard, fast and high speeds */ + if ((speed != OMAP_I2C_STANDARD) && + (speed != OMAP_I2C_FAST_MODE) && + (speed != OMAP_I2C_HIGH_SPEED)) { + printf("Error : I2C unsupported speed %d\n", speed); + return; + } + + psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK; + psc -= 1; + if (psc < I2C_PSC_MIN) { + printf("Error : I2C unsupported prescalar %d\n", psc); + return; + } + + if (speed == OMAP_I2C_HIGH_SPEED) { + /* High speed */ + + /* For first phase of HS mode */ + fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / + (2 * OMAP_I2C_FAST_MODE); + + fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM; + fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM; + if (((fsscll < 0) || (fssclh < 0)) || + ((fsscll > 255) || (fssclh > 255))) { + printf("Error : I2C initializing first phase clock\n"); + return; + } + + /* For second phase of HS mode */ + hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed); + + hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM; + hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM; + if (((fsscll < 0) || (fssclh < 0)) || + ((fsscll > 255) || (fssclh > 255))) { + printf("Error : I2C initializing second phase clock\n"); + return; + } + + scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll; + sclh = (unsigned int)hssclh << 8 | (unsigned int)fssclh; + + } else { + /* Standard and fast speed */ + fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed); + + fsscll -= I2C_FASTSPEED_SCLL_TRIM; + fssclh -= I2C_FASTSPEED_SCLH_TRIM; + if (((fsscll < 0) || (fssclh < 0)) || + ((fsscll > 255) || (fssclh > 255))) { + printf("Error : I2C initializing clock\n"); + return; + } + + scll = (unsigned int)fsscll; + sclh = (unsigned int)fssclh; + } writew(0x2, I2C_SYSC); /* for ES2 after soft reset */ udelay(1000); @@ -42,12 +104,10 @@ void i2c_init (int speed, int slaveadd) udelay (50000); } - /* 12MHz I2C module clock */ - writew (0, I2C_PSC); - speed = speed/1000; /* 100 or 400 */ - scl = ((12000/(speed*2)) - 7); /* use 7 when PSC = 0 */ - writew (scl, I2C_SCLL); - writew (scl, I2C_SCLH); + writew(psc, I2C_PSC); + writew(scll, I2C_SCLL); + writew(sclh, I2C_SCLH); + /* own address */ writew (slaveadd, I2C_OA); writew (I2C_CON_EN, I2C_CON); |