[U-Boot] [RFC v2] i2c, omap24xx: Fixup High Speed Initialization

Adam Ford aford173 at gmail.com
Sat Jan 27 16:48:40 UTC 2018


For devices running I2C over 400KHz, this needs to be in HS mode.
Currently, the code is only running in HS mode when the speed is
equal or greater than 3.4MHz.  At least on the OMAP3630/3730, this
fails when trying to configure at 2.6MHz

Using the Linux kernel setup as a reference, I used much of their
calculation for fsscll, fssclh, hsscll, and hssclh.  However, Linux
uses fclk = clk_get(omap->dev, "fck") and fclk_rate = clk_get_rate(fclk)

When dumping the data of fck, I got 96000000.  The U-Boot omap24xx I2C
driver sets the I2C_IP_CLK to SYSTEM_CLOCK_96 and I2C_INTERNAL_SAMPLING_CLK
to 19200000 except for arch/arm/include/asm/arch-am33xx/i2c.h which
defines I2C_INTERNAL_SAMPLING_CLK to 12000000 and I2C_IP_CLK 48000000.

I do not have this hardware, so I cannot test, but I compared the
values of psc=4, scll=4377, sclh=1803 for both U-Boot and Linux
and they match on an OMAP630/3730.

Signed-off-by: Adam Ford <aford173 at gmail.com>

diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 5d33815..eace748 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -205,8 +205,10 @@ static int __omap24_i2c_setspeed(struct i2c *i2c_base, uint speed,
 	int hsscll = 0, hssclh = 0;
 	u32 scll = 0, sclh = 0;
 
-	if (speed >= OMAP_I2C_HIGH_SPEED) {
+	if (speed > OMAP_I2C_FAST_MODE) {
 		/* High speed */
+		unsigned long scl;
+
 		psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
 		psc -= 1;
 		if (psc < I2C_PSC_MIN) {
@@ -215,12 +217,10 @@ static int __omap24_i2c_setspeed(struct i2c *i2c_base, uint speed,
 		}
 
 		/* For first phase of HS mode */
-		fsscll = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
+		scl = I2C_INTERNAL_SAMPLING_CLK / 400000;
+		fsscll = scl - (scl / 3) - 7;
+		fssclh = (scl / 3) - 5;
 
-		fssclh = fsscll;
-
-		fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM;
-		fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM;
 		if (((fsscll < 0) || (fssclh < 0)) ||
 		    ((fsscll > 255) || (fssclh > 255))) {
 			puts("Error : I2C initializing first phase clock\n");
@@ -228,10 +228,10 @@ static int __omap24_i2c_setspeed(struct i2c *i2c_base, uint speed,
 		}
 
 		/* For second phase of HS mode */
-		hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
+		scl = I2C_IP_CLK / speed;
+		hsscll = scl - (scl / 3) - 7;
+		hssclh = (scl / 3) - 5;
 
-		hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM;
-		hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM;
 		if (((fsscll < 0) || (fssclh < 0)) ||
 		    ((fsscll > 255) || (fssclh > 255))) {
 			puts("Error : I2C initializing second phase clock\n");
@@ -240,7 +240,6 @@ static int __omap24_i2c_setspeed(struct i2c *i2c_base, uint speed,
 
 		scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll;
 		sclh = (unsigned int)hssclh << 8 | (unsigned int)fssclh;
-
 	} else {
 		/* Standard and fast speed */
 		psc = omap24_i2c_findpsc(&scll, &sclh, speed);
-- 
2.7.4



More information about the U-Boot mailing list