> From: Tony Lindgren [mailto:t...@atomide.com]
> * balaj...@ti.com <balaj...@ti.com> [100419 07:59]:
> > From: Balaji T K <balaj...@ti.com>
> >
> > Errata ID: i535 - I2C1 to 3 SCL low period is shorter in FS mode
> > Due to IO cell influence, I2C1 to 3 SCL low period can be shorter than
> expected.
> > As a result, I2C AC timing (SCL minimum low period) in FS mode may not meet
> > the timing configured by software.
> >
> > I2C1 to 3, SCL low period is programmable and proper adjustments
> > to the SCLL/HSSCLL values can avoid the issue.
> >
> > This patch provides flexibility to control tLOW, tHIGH for different boards.
> > scll, sclh values are to be provide in board data
> > for differents modes (standard, fast and high speed mode)
> > as the scl rate (I2C bus speed) can be changed by bootargs.
> >
> > If scll, sclh values are not provided, scll and sclh values will be computed
> > for duty cycle tHIGH:tLOW of 1:2 (for HS, FS) and 1:1 for Standard as before
> 
> <snip>
> 
> > --- a/arch/arm/mach-omap2/board-3430sdp.c
> > +++ b/arch/arm/mach-omap2/board-3430sdp.c
> > @@ -594,6 +594,26 @@ static struct twl4030_platform_data sdp3430_twldata = {
> >     .vpll2          = &sdp3430_vpll2,
> >  };
> >
> > +static struct omap_i2c_scl_data __initdata sdp3430_i2c1_scl_data = {
> > +   .rate   = 2600,
> > +   .standard_scll  = 20,   /* For 100Khz */
> > +   .standard_sclh  = 20,   /* For 100Khz */

Scll and sclh calculation for other than omap1 and omap2420
from the given formula
                                fsscll = internal_clk / (dev->speed * 2);
                                fssclh = internal_clk / (dev->speed * 2);
where internal_clk is 4000KHz, dev-speed is 100Khz
and the assumption is 1:1 duty cycle, 50%tHIGH, 50%tLOW

> > +   .fast_mode_scll = 16,   /* For 400Khz */
> > +   .fast_mode_sclh = 8,    /* For 400Khz */

                        scl = internal_clk / dev->speed;
                                fsscll = scl - (scl / 3);
                                fssclh = (scl / 3);
internal_clk is 9600, dev->speed =400
and the assumption is 1:2 duty cycle, 33%tHIGH, 66%tLOW

> > +   .hs_phase1_scll = 32,   /* For 2600Khz */
> > +   .hs_phase1_sclh = 16,   /* For 2600Khz */

                                fsscll = scl - (scl / 3);
                                fssclh = (scl / 3);
internal_clk is 19200, dev->speed =400

> > +   .hs_phase2_scll = 24,   /* For 2600Khz */
> > +   .hs_phase2_sclh = 12,   /* For 2600Khz */

                        scl = fclk_rate / dev->speed;
                                hsscll = scl - (scl / 3);
                                hssclh = (scl / 3);
fclk_rate is 96000, dev->speed is 2600
and the assumption is 1:2 duty cycle, 33%tHIGH, 66%tLOW

> > +};
> 
> Can you please describe how you get these values for each board-*.c file?

Internal_clk is initialized to predefined value of 4000Khz, 9600, 19200
depending on i2c bus speed of 100, 400, or >400.
However fclk_rate varies between omap and needs to be determined by debug printk

> 
> > --- a/arch/arm/plat-omap/i2c.c
> > +++ b/arch/arm/plat-omap/i2c.c
> > @@ -70,14 +70,14 @@ static struct resource i2c_resources[][2] = {
> >             },                                      \
> >     }
> >
> > -static u32 i2c_rate[ARRAY_SIZE(i2c_resources)];
> > +static struct omap_i2c_platform_data i2c_pdata[ARRAY_SIZE(i2c_resources)];
> >  static struct platform_device omap_i2c_devices[] = {
> > -   I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]),
> > +   I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]),
> >  #if        defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
> > -   I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]),
> > +   I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_pdata[1]),
> >  #endif
> >  #if        defined(CONFIG_ARCH_OMAP3)
> > -   I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]),
> > +   I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_pdata[2]),
> >  #endif
> >  };
> >
> > @@ -146,8 +146,8 @@ static int __init omap_i2c_bus_setup(char *str)
> >     get_options(str, 3, ints);
> >     if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports)
> >             return 0;
> > -   i2c_rate[ints[1] - 1] = ints[2];
> > -   i2c_rate[ints[1] - 1] |= OMAP_I2C_CMDLINE_SETUP;
> > +   i2c_pdata[ints[1] - 1].rate = ints[2];
> > +   i2c_pdata[ints[1] - 1].rate |= OMAP_I2C_CMDLINE_SETUP;
> >
> >     return 1;
> >  }
> 
> FYI, the change from i2c_rate to i2c_pdata is needed also for
> "i2c-omap: add mpu wake up latency constraint in i2c" as that
> blocks some PM changes from going upstream. So once that's sorted
> out some minor rebasing of that patch is needed.

OK

> 
> > @@ -446,24 +453,47 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
> >
> >                     /* For first phase of HS mode */
> >                     scl = internal_clk / 400;
> > -                   fsscll = scl - (scl / 3) - 7;
> > -                   fssclh = (scl / 3) - 5;
> > +                   if ((pdata->hs_phase1.scll > 7) &&
> > +                                   (pdata->hs_phase1.sclh > 5)) {
> > +                           fsscll = pdata->hs_phase1.scll - 7;
> > +                           fssclh = pdata->hs_phase1.sclh - 5;
> > +                   } else {
> > +                           fsscll = scl - (scl / 3) - 7;
> > +                           fssclh = (scl / 3) - 5;
> > +                   }
> >
> >                     /* For second phase of HS mode */
> >                     scl = fclk_rate / dev->speed;
> > -                   hsscll = scl - (scl / 3) - 7;
> > -                   hssclh = (scl / 3) - 5;
> > +                   if ((pdata->hs_phase2.scll > 7) &&
> > +                                   (pdata->hs_phase2.sclh > 5)) {
> > +                           hsscll = pdata->hs_phase2.scll - 7;
> > +                           hssclh = pdata->hs_phase2.sclh - 5;
> > +                   } else {
> > +                           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;
> > +                   if ((pdata->fast.scll > 7) && (pdata->fast.sclh > 5)) {
> > +                           fsscll = pdata->fast.scll - 7;
> > +                           fssclh = pdata->fast.sclh - 5;
> > +                   } else {
> > +                           fsscll = scl - (scl / 3) - 7;
> > +                           fssclh = (scl / 3) - 5;
> > +                   }
> >             } else {
> >                     /* Standard mode */
> > -                   fsscll = internal_clk / (dev->speed * 2) - 7;
> > -                   fssclh = internal_clk / (dev->speed * 2) - 5;
> > +                   if ((pdata->standard.scll > 7) &&
> > +                                   (pdata->standard.sclh > 5)) {
> > +                           fsscll = pdata->standard.scll - 7;
> > +                           fssclh = pdata->standard.sclh - 5;
> > +                   } else {
> > +                           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;
> 
> To me it looks like you should not ignore the scl for these calculations
> as it can be different depending on the omap.

scl dependency is taken care when scll / sclh value is calculated for each 
board 
file.
For now, fine tuning through board data is only for omap2430+
And not for omap1 and omap2420, it can be add if needed.

In that case Should I split omap_register_i2c_bus as is for omap1 and 
Omap2_register_i2c_bus for omap2+ to pass board data?
Like:
int __init omap_plat_register_i2c_bus(int bus_id, u32 clkrate, ...

int __init omap2_register_i2c_bus(int bus_id, struct omap_i2c_scl_data *pdata, 
...

> 
> Also, this should be also posted to the i2c mailing list for review.

Sure

> 
> Regards,
> 
> Tony
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to