From baf46b4e378d7950dff7ba30cfd50ff585987cb4 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 27 May 2009 17:54:45 +0300 Subject: i2c: OMAP2/3: Fix scll/sclh calculations Fix scll/sclh calculations for HS and fast modes. Currently the driver uses equal (roughly) low/high times which will result in too short low time. OMAP3430 TRM gives the following equations: F/S: tLow = (scll + 7) * internal_clk tHigh = (sclh + 5) * internal_clk HS: tLow = (scll + 7) * fclk tHigh = (sclh + 5) * fclk Furthermore, the I2C specification sets the following minimum values for HS tLow/tHigh for capacitive bus loads 100 pF (maximum speed 3400) and 400 pF (maximum speed 1700): speed tLow tHigh 3400 160 ns 60 ns 1700 320 ns 120 ns and for F/S: speed tLow tHigh 400 1300 ns 600 ns 100 4700 ns 4000 ns By using duty cycles 33/66 (HS, F) and 50/50 (S) we stay above these minimum values. Signed-off-by: Aaro Koskinen Acked-by: Tony Lindgren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-omap.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ece0125a1ee..a879e4bf512 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -343,17 +343,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) /* If configured for High Speed */ if (dev->speed > 400) { + unsigned long scl; + /* For first phase of HS mode */ - fsscll = internal_clk / (400 * 2) - 6; - fssclh = internal_clk / (400 * 2) - 6; + scl = internal_clk / 400; + fsscll = scl - (scl / 3) - 7; + fssclh = (scl / 3) - 5; /* For second phase of HS mode */ - hsscll = fclk_rate / (dev->speed * 2) - 6; - hssclh = fclk_rate / (dev->speed * 2) - 6; + scl = fclk_rate / dev->speed; + hsscll = scl - (scl / 3) - 7; + hssclh = (scl / 3) - 5; + } else if (dev->speed > 100) { + unsigned long scl; + + /* Fast mode */ + scl = internal_clk / dev->speed; + fsscll = scl - (scl / 3) - 7; + fssclh = (scl / 3) - 5; } else { - /* To handle F/S modes */ - fsscll = internal_clk / (dev->speed * 2) - 6; - fssclh = internal_clk / (dev->speed * 2) - 6; + /* Standard mode */ + fsscll = internal_clk / (dev->speed * 2) - 7; + fssclh = internal_clk / (dev->speed * 2) - 5; } scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll; sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh; -- cgit v1.2.3 From 84bf2c868f3ca996e5bbd3beb2ef502f457140f3 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 27 May 2009 17:54:46 +0300 Subject: i2c: OMAP3: Better noise suppression for fast/standard modes Use longer noise filter period for fast and standard mode. Based on an earlier patch by Eero Nurkkala. Signed-off-by: Aaro Koskinen Acked-by: Tony Lindgren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-omap.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/i2c/busses/i2c-omap.c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index a879e4bf512..c73475dd0fb 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -333,8 +333,18 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) if (cpu_is_omap2430() || cpu_is_omap34xx()) { - /* HSI2C controller internal clk rate should be 19.2 Mhz */ - internal_clk = 19200; + /* + * HSI2C controller internal clk rate should be 19.2 Mhz for + * HS and for all modes on 2430. On 34xx we can use lower rate + * to get longer filter period for better noise suppression. + * The filter is iclk (fclk for HS) period. + */ + if (dev->speed > 400 || cpu_is_omap_2430()) + internal_clk = 19200; + else if (dev->speed > 100) + internal_clk = 9600; + else + internal_clk = 4000; fclk_rate = clk_get_rate(dev->fclk) / 1000; /* Compute prescaler divisor */ -- cgit v1.2.3