> From: Tony Lindgren [mailto:[email protected]]
> * [email protected] <[email protected]> [100419 07:59]:
> > From: Balaji T K <[email protected]>
> >
> > 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html