diff mbox

[U-Boot,2/2] Powerpc/i2c: Force i2c to become bus master out of reset

Message ID 1319678979-23491-2-git-send-email-Chang-Ming.Huang@freescale.com
State Changes Requested
Delegated to: Heiko Schocher
Headers show

Commit Message

Jerry Huang Oct. 27, 2011, 1:29 a.m. UTC
From: Jerry Huang <Chang-Ming.Huang@freescale.com>

It is sometimes necessary to force the I2C module to become the I2C bus master
out of reset and drive SCL(even though SDA may already be driven,
which indicates that the bus is busy). This can occur when a system reset
does not cause all I2C devices to be reset. Thus, SDA can be driven low
by another I2C device while this I2C module is coming out of reset
and stays low indefinitely. The following procedure can be used to
force this I2C module to generate SCL so that the device driving SDA
can finish its transaction.

Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
---
 drivers/i2c/fsl_i2c.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

Comments

Heiko Schocher Oct. 27, 2011, 6:36 a.m. UTC | #1
Hello Chang-Ming,

Chang-Ming.Huang@freescale.com wrote:
> From: Jerry Huang <Chang-Ming.Huang@freescale.com>
> 
> It is sometimes necessary to force the I2C module to become the I2C bus master
> out of reset and drive SCL(even though SDA may already be driven,
> which indicates that the bus is busy). This can occur when a system reset
> does not cause all I2C devices to be reset. Thus, SDA can be driven low
> by another I2C device while this I2C module is coming out of reset
> and stays low indefinitely. The following procedure can be used to
> force this I2C module to generate SCL so that the device driving SDA
> can finish its transaction.
> 
> Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> ---
>  drivers/i2c/fsl_i2c.c |   18 ++++++++++++++++++
>  1 files changed, 18 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
> index 258be0a..007db70 100644
> --- a/drivers/i2c/fsl_i2c.c
> +++ b/drivers/i2c/fsl_i2c.c
> @@ -252,6 +252,24 @@ i2c_init(int speed, int slaveadd)
>  		writeb(slaveadd << 1, &dev->adr);/* write slave address */
>  		writeb(0x0, &dev->sr);		/* clear status register */
>  		writeb(I2C_CR_MEN, &dev->cr);	/* start I2C controller */
> +
> +		/* Force I2C module to become bus master which can occure when
> +		 * a system reset does not cause all I2C devices to be reset */

Checkpatch doesn't warn, but wrong comment style here, please
change.

[...]

bye,
Heiko
Joakim Tjernlund Oct. 27, 2011, 7:25 a.m. UTC | #2
> From: <Chang-Ming.Huang@freescale.com>
>
> From: Jerry Huang <Chang-Ming.Huang@freescale.com>
>
> It is sometimes necessary to force the I2C module to become the I2C bus master
> out of reset and drive SCL(even though SDA may already be driven,
> which indicates that the bus is busy). This can occur when a system reset
> does not cause all I2C devices to be reset. Thus, SDA can be driven low
> by another I2C device while this I2C module is coming out of reset
> and stays low indefinitely. The following procedure can be used to
> force this I2C module to generate SCL so that the device driving SDA
> can finish its transaction.
>
> Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> ---
>  drivers/i2c/fsl_i2c.c |   18 ++++++++++++++++++
>  1 files changed, 18 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
> index 258be0a..007db70 100644
> --- a/drivers/i2c/fsl_i2c.c
> +++ b/drivers/i2c/fsl_i2c.c
> @@ -252,6 +252,24 @@ i2c_init(int speed, int slaveadd)
>        writeb(slaveadd << 1, &dev->adr);/* write slave address */
>        writeb(0x0, &dev->sr);      /* clear status register */
>        writeb(I2C_CR_MEN, &dev->cr);   /* start I2C controller */
> +
> +      /* Force I2C module to become bus master which can occure when
> +       * a system reset does not cause all I2C devices to be reset */
> +      udelay(5);
> +      if (readb(&dev->sr) & I2C_SR_MBB) {

You need to the sequence unconditionally, the slave can be stuck without
driving SCL.

> +         writeb(I2C_CR_MSTA, &dev->cr);
> +         udelay(5);
> +         writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
> +         udelay(5);
> +         readb(&dev->dr);
> +         udelay(5);
> +         writeb(I2C_CR_MEN, &dev->cr);
> +         udelay(5);
> +         if (readb(&dev->sr) & I2C_SR_MBB)
> +            debug("I2C%d: Drive SCL failed\n", i + 1);
> +         else
> +            debug("I2C%d: Drive SCL succeed\n", i + 1);
> +      }

The above sequence is different than the kernel version, why?

Kernel version below:
static void mpc_i2c_fixup(struct mpc_i2c *i2c)
 {
         int k;
         u32 delay_val = 1000000 / i2c->real_clk + 1;

         if (delay_val < 2)
                 delay_val = 2;

         for (k = 9; k; k--) {
                 writeccr(i2c, 0);
                 writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
                 udelay(delay_val);
                 writeccr(i2c, CCR_MEN);
                 udelay(delay_val << 1);
         }
 }
Changming Huang Oct. 27, 2011, 7:40 a.m. UTC | #3
Thanks and Best Regards
Jerry Huang


> -----Original Message-----
> From: Joakim Tjernlund [mailto:joakim.tjernlund@transmode.se]
> Sent: Thursday, October 27, 2011 3:26 PM
> To: Huang Changming-R66093
> Cc: u-boot@lists.denx.de
> Subject: Re: [U-Boot] [PATCH 2/2] Powerpc/i2c: Force i2c to become bus
> master out of reset
> 
> > From: <Chang-Ming.Huang@freescale.com>
> >
> > From: Jerry Huang <Chang-Ming.Huang@freescale.com>
> >
> > It is sometimes necessary to force the I2C module to become the I2C
> > bus master out of reset and drive SCL(even though SDA may already be
> > driven, which indicates that the bus is busy). This can occur when a
> > system reset does not cause all I2C devices to be reset. Thus, SDA
> can
> > be driven low by another I2C device while this I2C module is coming
> > out of reset and stays low indefinitely. The following procedure can
> > be used to force this I2C module to generate SCL so that the device
> > driving SDA can finish its transaction.
> >
> > Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> > ---
> >  drivers/i2c/fsl_i2c.c |   18 ++++++++++++++++++
> >  1 files changed, 18 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index
> > 258be0a..007db70 100644
> > --- a/drivers/i2c/fsl_i2c.c
> > +++ b/drivers/i2c/fsl_i2c.c
> > @@ -252,6 +252,24 @@ i2c_init(int speed, int slaveadd)
> >        writeb(slaveadd << 1, &dev->adr);/* write slave address */
> >        writeb(0x0, &dev->sr);      /* clear status register */
> >        writeb(I2C_CR_MEN, &dev->cr);   /* start I2C controller */
> > +
> > +      /* Force I2C module to become bus master which can occure when
> > +       * a system reset does not cause all I2C devices to be reset
> */
> > +      udelay(5);
> > +      if (readb(&dev->sr) & I2C_SR_MBB) {
> 
> You need to the sequence unconditionally, the slave can be stuck
> without driving SCL.
> 
> > +         writeb(I2C_CR_MSTA, &dev->cr);
> > +         udelay(5);
> > +         writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
> > +         udelay(5);
> > +         readb(&dev->dr);
> > +         udelay(5);
> > +         writeb(I2C_CR_MEN, &dev->cr);
> > +         udelay(5);
> > +         if (readb(&dev->sr) & I2C_SR_MBB)
> > +            debug("I2C%d: Drive SCL failed\n", i + 1);
> > +         else
> > +            debug("I2C%d: Drive SCL succeed\n", i + 1);
> > +      }
> 
> The above sequence is different than the kernel version, why?

I don't know the kernel version, but I write the u-boot code according to the Reference Manual of PowerPC, e.g p1022:
11.5.6 Generation of SCL When SDA Low
It is sometimes necessary to force the I2C module to become the I2C bus master out of reset and drive SCL(even though SDA may already be driven, which indicates that the bus is busy). This can occur when a system reset does not cause all I2C devices to be reset. Thus, SDA can be driven low by another I2C device while this I2C module is coming out of reset and stays low indefinitely. The following procedure can be used to force this I2C module to generate SCL so that the device driving SDA can finish its transaction:
1. Disable the I2C module and set the master bit by setting I2CCR to 0x20
2. Enable the I2C module by setting I2CCR to 0xA0
3. Read the I2CDR
4. Return the I2C module to slave mode by setting I2CCR to 0x80
Changming Huang Oct. 27, 2011, 7:51 a.m. UTC | #4
Thanks and Best Regards
Jerry Huang


> -----Original Message-----
> From: u-boot-bounces@lists.denx.de [mailto:u-boot-bounces@lists.denx.de]
> On Behalf Of Huang Changming-R66093
> Sent: Thursday, October 27, 2011 3:40 PM
> To: Joakim Tjernlund
> Cc: u-boot@lists.denx.de
> Subject: Re: [U-Boot] [PATCH 2/2] Powerpc/i2c: Force i2c to become bus
> master out of reset
> 
> 
> 
> Thanks and Best Regards
> Jerry Huang
> 
> 
> > -----Original Message-----
> > From: Joakim Tjernlund [mailto:joakim.tjernlund@transmode.se]
> > Sent: Thursday, October 27, 2011 3:26 PM
> > To: Huang Changming-R66093
> > Cc: u-boot@lists.denx.de
> > Subject: Re: [U-Boot] [PATCH 2/2] Powerpc/i2c: Force i2c to become
> bus
> > master out of reset
> >
> > > From: <Chang-Ming.Huang@freescale.com>
> > >
> > > From: Jerry Huang <Chang-Ming.Huang@freescale.com>
> > >
> > > It is sometimes necessary to force the I2C module to become the I2C
> > > bus master out of reset and drive SCL(even though SDA may already
> be
> > > driven, which indicates that the bus is busy). This can occur when
> a
> > > system reset does not cause all I2C devices to be reset. Thus, SDA
> > can
> > > be driven low by another I2C device while this I2C module is coming
> > > out of reset and stays low indefinitely. The following procedure
> can
> > > be used to force this I2C module to generate SCL so that the device
> > > driving SDA can finish its transaction.
> > >
> > > Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> > > ---
> > >  drivers/i2c/fsl_i2c.c |   18 ++++++++++++++++++
> > >  1 files changed, 18 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index
> > > 258be0a..007db70 100644
> > > --- a/drivers/i2c/fsl_i2c.c
> > > +++ b/drivers/i2c/fsl_i2c.c
> > > @@ -252,6 +252,24 @@ i2c_init(int speed, int slaveadd)
> > >        writeb(slaveadd << 1, &dev->adr);/* write slave address */
> > >        writeb(0x0, &dev->sr);      /* clear status register */
> > >        writeb(I2C_CR_MEN, &dev->cr);   /* start I2C controller */
> > > +
> > > +      /* Force I2C module to become bus master which can occure
> when
> > > +       * a system reset does not cause all I2C devices to be reset
> > */
> > > +      udelay(5);
> > > +      if (readb(&dev->sr) & I2C_SR_MBB) {
> >
> > You need to the sequence unconditionally, the slave can be stuck
> > without driving SCL.
> >
> > > +         writeb(I2C_CR_MSTA, &dev->cr);
> > > +         udelay(5);
> > > +         writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
> > > +         udelay(5);
> > > +         readb(&dev->dr);
> > > +         udelay(5);
> > > +         writeb(I2C_CR_MEN, &dev->cr);
> > > +         udelay(5);
> > > +         if (readb(&dev->sr) & I2C_SR_MBB)
> > > +            debug("I2C%d: Drive SCL failed\n", i + 1);
> > > +         else
> > > +            debug("I2C%d: Drive SCL succeed\n", i + 1);
> > > +      }
> >
> > The above sequence is different than the kernel version, why?
> 
> I don't know the kernel version, but I write the u-boot code according
> to the Reference Manual of PowerPC, e.g p1022:
> 11.5.6 Generation of SCL When SDA Low
> It is sometimes necessary to force the I2C module to become the I2C bus
> master out of reset and drive SCL(even though SDA may already be driven,
> which indicates that the bus is busy). This can occur when a system
> reset does not cause all I2C devices to be reset. Thus, SDA can be
> driven low by another I2C device while this I2C module is coming out of
> reset and stays low indefinitely. The following procedure can be used
> to force this I2C module to generate SCL so that the device driving SDA
> can finish its transaction:
> 1. Disable the I2C module and set the master bit by setting I2CCR to
> 0x20
> 2. Enable the I2C module by setting I2CCR to 0xA0
> 3. Read the I2CDR
> 4. Return the I2C module to slave mode by setting I2CCR to 0x80
> 
Compare with kernel version, the difference is one line:
Uboot:  readb(&dev->dr);
Kernel has no any operation.
But, I check the comment of kernel, because the 9th clock pulse isn't generated, 
the sequence of function mpc_i2c_fixup is needed to generate 9th clock pulse.
Joakim Tjernlund Oct. 27, 2011, 8:04 a.m. UTC | #5
Huang Changming-R66093 <r66093@freescale.com> wrote on 2011/10/27 09:40:23:
>
>
> Thanks and Best Regards
> Jerry Huang
>
>
> > -----Original Message-----
> > From: Joakim Tjernlund [mailto:joakim.tjernlund@transmode.se]
> > Sent: Thursday, October 27, 2011 3:26 PM
> > To: Huang Changming-R66093
> > Cc: u-boot@lists.denx.de
> > Subject: Re: [U-Boot] [PATCH 2/2] Powerpc/i2c: Force i2c to become bus
> > master out of reset
> >
> > > From: <Chang-Ming.Huang@freescale.com>
> > >
> > > From: Jerry Huang <Chang-Ming.Huang@freescale.com>
> > >
> > > It is sometimes necessary to force the I2C module to become the I2C
> > > bus master out of reset and drive SCL(even though SDA may already be
> > > driven, which indicates that the bus is busy). This can occur when a
> > > system reset does not cause all I2C devices to be reset. Thus, SDA
> > can
> > > be driven low by another I2C device while this I2C module is coming
> > > out of reset and stays low indefinitely. The following procedure can
> > > be used to force this I2C module to generate SCL so that the device
> > > driving SDA can finish its transaction.
> > >
> > > Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> > > ---
> > >  drivers/i2c/fsl_i2c.c |   18 ++++++++++++++++++
> > >  1 files changed, 18 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index
> > > 258be0a..007db70 100644
> > > --- a/drivers/i2c/fsl_i2c.c
> > > +++ b/drivers/i2c/fsl_i2c.c
> > > @@ -252,6 +252,24 @@ i2c_init(int speed, int slaveadd)
> > >        writeb(slaveadd << 1, &dev->adr);/* write slave address */
> > >        writeb(0x0, &dev->sr);      /* clear status register */
> > >        writeb(I2C_CR_MEN, &dev->cr);   /* start I2C controller */
> > > +
> > > +      /* Force I2C module to become bus master which can occure when
> > > +       * a system reset does not cause all I2C devices to be reset
> > */
> > > +      udelay(5);
> > > +      if (readb(&dev->sr) & I2C_SR_MBB) {
> >
> > You need to the sequence unconditionally, the slave can be stuck
> > without driving SCL.
> >
> > > +         writeb(I2C_CR_MSTA, &dev->cr);
> > > +         udelay(5);
> > > +         writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
> > > +         udelay(5);
> > > +         readb(&dev->dr);
> > > +         udelay(5);
> > > +         writeb(I2C_CR_MEN, &dev->cr);
> > > +         udelay(5);
> > > +         if (readb(&dev->sr) & I2C_SR_MBB)
> > > +            debug("I2C%d: Drive SCL failed\n", i + 1);
> > > +         else
> > > +            debug("I2C%d: Drive SCL succeed\n", i + 1);
> > > +      }
> >
> > The above sequence is different than the kernel version, why?
>
> I don't know the kernel version, but I write the u-boot code according to the Reference Manual of PowerPC, e.g p1022:
> 11.5.6 Generation of SCL When SDA Low
> It is sometimes necessary to force the I2C module to become the I2C bus master out of reset and drive SCL(even though SDA may already be driven, which indicates that the bus is busy). This can occur when a system reset does not cause all I2C devices to be reset. Thus, SDA can be driven low by
another I2C device while this I2C module is coming out of reset and stays low indefinitely. The following procedure can be used to force this I2C module to generate SCL so that the device driving SDA can finish its transaction:
> 1. Disable the I2C module and set the master bit by setting I2CCR to 0x20
> 2. Enable the I2C module by setting I2CCR to 0xA0
> 3. Read the I2CDR
> 4. Return the I2C module to slave mode by setting I2CCR to 0x80
>

I think this is incomplete. Basically you need to generate 9 SCL pulses with a start condition in each,
then end with a stop to cover all cases.

 Jocke
Joakim Tjernlund Oct. 27, 2011, 8:10 a.m. UTC | #6
Huang Changming-R66093 <r66093@freescale.com> wrote on 2011/10/27 09:51:49:
>
>
>
> Thanks and Best Regards
> Jerry Huang
>
>
> > -----Original Message-----
> > From: u-boot-bounces@lists.denx.de [mailto:u-boot-bounces@lists.denx.de]
> > On Behalf Of Huang Changming-R66093
> > Sent: Thursday, October 27, 2011 3:40 PM
> > To: Joakim Tjernlund
> > Cc: u-boot@lists.denx.de
> > Subject: Re: [U-Boot] [PATCH 2/2] Powerpc/i2c: Force i2c to become bus
> > master out of reset
> >
> >
> >
> > Thanks and Best Regards
> > Jerry Huang
> >
> >
> > > -----Original Message-----
> > > From: Joakim Tjernlund [mailto:joakim.tjernlund@transmode.se]
> > > Sent: Thursday, October 27, 2011 3:26 PM
> > > To: Huang Changming-R66093
> > > Cc: u-boot@lists.denx.de
> > > Subject: Re: [U-Boot] [PATCH 2/2] Powerpc/i2c: Force i2c to become
> > bus
> > > master out of reset
> > >
> > > > From: <Chang-Ming.Huang@freescale.com>
> > > >
> > > > From: Jerry Huang <Chang-Ming.Huang@freescale.com>
> > > >
> > > > It is sometimes necessary to force the I2C module to become the I2C
> > > > bus master out of reset and drive SCL(even though SDA may already
> > be
> > > > driven, which indicates that the bus is busy). This can occur when
> > a
> > > > system reset does not cause all I2C devices to be reset. Thus, SDA
> > > can
> > > > be driven low by another I2C device while this I2C module is coming
> > > > out of reset and stays low indefinitely. The following procedure
> > can
> > > > be used to force this I2C module to generate SCL so that the device
> > > > driving SDA can finish its transaction.
> > > >
> > > > Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> > > > ---
> > > >  drivers/i2c/fsl_i2c.c |   18 ++++++++++++++++++
> > > >  1 files changed, 18 insertions(+), 0 deletions(-)
> > > >
> > > > diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index
> > > > 258be0a..007db70 100644
> > > > --- a/drivers/i2c/fsl_i2c.c
> > > > +++ b/drivers/i2c/fsl_i2c.c
> > > > @@ -252,6 +252,24 @@ i2c_init(int speed, int slaveadd)
> > > >        writeb(slaveadd << 1, &dev->adr);/* write slave address */
> > > >        writeb(0x0, &dev->sr);      /* clear status register */
> > > >        writeb(I2C_CR_MEN, &dev->cr);   /* start I2C controller */
> > > > +
> > > > +      /* Force I2C module to become bus master which can occure
> > when
> > > > +       * a system reset does not cause all I2C devices to be reset
> > > */
> > > > +      udelay(5);
> > > > +      if (readb(&dev->sr) & I2C_SR_MBB) {
> > >
> > > You need to the sequence unconditionally, the slave can be stuck
> > > without driving SCL.
> > >
> > > > +         writeb(I2C_CR_MSTA, &dev->cr);
> > > > +         udelay(5);
> > > > +         writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
> > > > +         udelay(5);
> > > > +         readb(&dev->dr);
> > > > +         udelay(5);
> > > > +         writeb(I2C_CR_MEN, &dev->cr);
> > > > +         udelay(5);
> > > > +         if (readb(&dev->sr) & I2C_SR_MBB)
> > > > +            debug("I2C%d: Drive SCL failed\n", i + 1);
> > > > +         else
> > > > +            debug("I2C%d: Drive SCL succeed\n", i + 1);
> > > > +      }
> > >
> > > The above sequence is different than the kernel version, why?
> >
> > I don't know the kernel version, but I write the u-boot code according
> > to the Reference Manual of PowerPC, e.g p1022:
> > 11.5.6 Generation of SCL When SDA Low
> > It is sometimes necessary to force the I2C module to become the I2C bus
> > master out of reset and drive SCL(even though SDA may already be driven,
> > which indicates that the bus is busy). This can occur when a system
> > reset does not cause all I2C devices to be reset. Thus, SDA can be
> > driven low by another I2C device while this I2C module is coming out of
> > reset and stays low indefinitely. The following procedure can be used
> > to force this I2C module to generate SCL so that the device driving SDA
> > can finish its transaction:
> > 1. Disable the I2C module and set the master bit by setting I2CCR to
> > 0x20
> > 2. Enable the I2C module by setting I2CCR to 0xA0
> > 3. Read the I2CDR
> > 4. Return the I2C module to slave mode by setting I2CCR to 0x80
> >
> Compare with kernel version, the difference is one line:
> Uboot:  readb(&dev->dr);
> Kernel has no any operation.
> But, I check the comment of kernel, because the 9th clock pulse isn't generated,
> the sequence of function mpc_i2c_fixup is needed to generate 9th clock pulse.

Not so, there is more than that if you look closer. The description in the kernel
is a bit misleading(or so I think). I prefer the kernel version for 2 reasons:
1) It has been there for quite some time so if there were something wrong with,
   it should have been noticed by now.
2) I have a vauge memory of checking it again the mpc8321 manual and I was happy
   with it.

 Jocke
Changming Huang Oct. 27, 2011, 9:10 a.m. UTC | #7
> > > >
> > > > The above sequence is different than the kernel version, why?
> > >
> > > I don't know the kernel version, but I write the u-boot code
> according
> > > to the Reference Manual of PowerPC, e.g p1022:
> > > 11.5.6 Generation of SCL When SDA Low
> > > It is sometimes necessary to force the I2C module to become the I2C
> bus
> > > master out of reset and drive SCL(even though SDA may already be
> driven,
> > > which indicates that the bus is busy). This can occur when a system
> > > reset does not cause all I2C devices to be reset. Thus, SDA can be
> > > driven low by another I2C device while this I2C module is coming
> out of
> > > reset and stays low indefinitely. The following procedure can be
> used
> > > to force this I2C module to generate SCL so that the device driving
> SDA
> > > can finish its transaction:
> > > 1. Disable the I2C module and set the master bit by setting I2CCR
> to
> > > 0x20
> > > 2. Enable the I2C module by setting I2CCR to 0xA0
> > > 3. Read the I2CDR
> > > 4. Return the I2C module to slave mode by setting I2CCR to 0x80
> > >
> > Compare with kernel version, the difference is one line:
> > Uboot:  readb(&dev->dr);
> > Kernel has no any operation.
> > But, I check the comment of kernel, because the 9th clock pulse isn't
> generated,
> > the sequence of function mpc_i2c_fixup is needed to generate 9th
> clock pulse.
> 
> Not so, there is more than that if you look closer. The description in
> the kernel
> is a bit misleading(or so I think). I prefer the kernel version for 2
> reasons:
> 1) It has been there for quite some time so if there were something
> wrong with,
>    it should have been noticed by now.
> 2) I have a vauge memory of checking it again the mpc8321 manual and I
> was happy
>    with it.
> 
These tow part codes are doing the different thing due to the different reason:
1. Kernel's code:
because Sometimes 9th clock pulse isn't generated, that code is to generate the 9th clock pulse.
It happens in the DATA transfer stage.
2. My code:
because the system reset does not cause all I2C devices to be reset, the code force the i2c to become the master and drive the SCL.
It happens in the i2c controller initialize stage
So, I think these code is reasonable.
 
BTW: My codes has been verified on Emerson's board.
Changming Huang Oct. 27, 2011, 9:26 a.m. UTC | #8
> > > > The above sequence is different than the kernel version, why?
> > >
> > > I don't know the kernel version, but I write the u-boot code
> according
> > > to the Reference Manual of PowerPC, e.g p1022:
> > > 11.5.6 Generation of SCL When SDA Low
> > > It is sometimes necessary to force the I2C module to become the I2C
> bus
> > > master out of reset and drive SCL(even though SDA may already be
> driven,
> > > which indicates that the bus is busy). This can occur when a system
> > > reset does not cause all I2C devices to be reset. Thus, SDA can be
> > > driven low by another I2C device while this I2C module is coming
> out of
> > > reset and stays low indefinitely. The following procedure can be
> used
> > > to force this I2C module to generate SCL so that the device driving
> SDA
> > > can finish its transaction:
> > > 1. Disable the I2C module and set the master bit by setting I2CCR
> to
> > > 0x20
> > > 2. Enable the I2C module by setting I2CCR to 0xA0
> > > 3. Read the I2CDR
> > > 4. Return the I2C module to slave mode by setting I2CCR to 0x80
> > >
> > Compare with kernel version, the difference is one line:
> > Uboot:  readb(&dev->dr);
> > Kernel has no any operation.
> > But, I check the comment of kernel, because the 9th clock pulse isn't
> generated,
> > the sequence of function mpc_i2c_fixup is needed to generate 9th
> clock pulse.
> 
> Not so, there is more than that if you look closer. The description in
> the kernel
> is a bit misleading(or so I think). I prefer the kernel version for 2
> reasons:
> 1) It has been there for quite some time so if there were something
> wrong with,
>    it should have been noticed by now.
> 2) I have a vauge memory of checking it again the mpc8321 manual and I
> was happy
>    with it.
> 
These tow part codes are doing the different thing due to the different reason:
1. Kernel's code:
because Sometimes 9th clock pulse isn't generated, that code is to generate the 9th clock pulse.
It happens in the DATA transfer stage.
2. My code:
because the system reset does not cause all I2C devices to be reset, the code force the i2c to become the master and drive the SCL.
It happens in the i2c controller initialize stage So, I think these code is reasonable.
 
BTW: My codes has been verified on Emerson's board.
Joakim Tjernlund Oct. 27, 2011, 10:21 a.m. UTC | #9
Huang Changming-R66093 <r66093@freescale.com> wrote on 2011/10/27 11:26:04:
>
> > > > > The above sequence is different than the kernel version, why?
> > > >
> > > > I don't know the kernel version, but I write the u-boot code
> > according
> > > > to the Reference Manual of PowerPC, e.g p1022:
> > > > 11.5.6 Generation of SCL When SDA Low
> > > > It is sometimes necessary to force the I2C module to become the I2C
> > bus
> > > > master out of reset and drive SCL(even though SDA may already be
> > driven,
> > > > which indicates that the bus is busy). This can occur when a system
> > > > reset does not cause all I2C devices to be reset. Thus, SDA can be
> > > > driven low by another I2C device while this I2C module is coming
> > out of
> > > > reset and stays low indefinitely. The following procedure can be
> > used
> > > > to force this I2C module to generate SCL so that the device driving
> > SDA
> > > > can finish its transaction:
> > > > 1. Disable the I2C module and set the master bit by setting I2CCR
> > to
> > > > 0x20
> > > > 2. Enable the I2C module by setting I2CCR to 0xA0
> > > > 3. Read the I2CDR
> > > > 4. Return the I2C module to slave mode by setting I2CCR to 0x80
> > > >
> > > Compare with kernel version, the difference is one line:
> > > Uboot:  readb(&dev->dr);
> > > Kernel has no any operation.
> > > But, I check the comment of kernel, because the 9th clock pulse isn't
> > generated,
> > > the sequence of function mpc_i2c_fixup is needed to generate 9th
> > clock pulse.
> >
> > Not so, there is more than that if you look closer. The description in
> > the kernel
> > is a bit misleading(or so I think). I prefer the kernel version for 2
> > reasons:
> > 1) It has been there for quite some time so if there were something
> > wrong with,
> >    it should have been noticed by now.
> > 2) I have a vauge memory of checking it again the mpc8321 manual and I
> > was happy
> >    with it.
> >
> These tow part codes are doing the different thing due to the different reason:
> 1. Kernel's code:
> because Sometimes 9th clock pulse isn't generated, that code is to generate the 9th clock pulse.

What code are you looking at? Are you just reading the comment?
Look at http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git;a=commit;h=0c2daaafcdec726e89cbccca61d576de8429c537
to get a clue.

Your code isn't complete, you cannot trust the manual to be the whole truth.

 Jocke
Changming Huang Oct. 28, 2011, 5:21 a.m. UTC | #10
> > >
> > These tow part codes are doing the different thing due to the
> different reason:
> > 1. Kernel's code:
> > because Sometimes 9th clock pulse isn't generated, that code is to
> generate the 9th clock pulse.
> 
> What code are you looking at? Are you just reading the comment?
> Look at http://git.kernel.org/?p=linux/kernel/git/next/linux-
> next.git;a=commit;h=0c2daaafcdec726e89cbccca61d576de8429c537
> to get a clue.
> 
> Your code isn't complete, you cannot trust the manual to be the whole
> truth.
> 
I am very confused, why do you always say my code isn't complete?
I have described I want to do detailed in comment.
"when a system reset does not cause all I2C devices to be reset", 
My codes will force the I2c module to become bus master and drive SCL,
which force this i2c module to generate SCL so that the device driving SDA can finish its transaction.
These codes have been used on Emerson's P1022 board and resolved his issue (board will hang when u-boot booting, with my codes, this issue is resolved and board can boot well)
This is one feature of FSL I2C almost cover all 85xx platform, and the code according to the RM has been verified, don't you think the manual can be trust?

Below is the description from your link:
This patch improves the recovery of the MPC's I2C bus from errors like bus
hangs resulting in timeouts:
1. make the bus timeout configurable, as it depends on the bus clock and
    the attached slave chip(s); default is still 1 second;
2. detect any of the cases indicated by the CF, BB and RXAK MSR flags if a
    timeout occurs, and add a missing (required) MAL reset;
3. use a more reliable method to fixup the bus if a hang has been detected.
    The sequence is sent 9 times which seems to be necessary if a slave
    "misses" more than one clock cycle.  For 400 kHz bus speed, the fixup is
    also ~70us (81us vs. 150us) faster.

This patch is created because a slave miss more than one clock cycle and can resolve this issue.

So, the kernel's patch and my patch is to resolve the different issue.
Heiko Schocher Oct. 28, 2011, 6:34 a.m. UTC | #11
Hello Huang Changming-R66093,

Huang Changming-R66093 wrote:
>>> These tow part codes are doing the different thing due to the
>> different reason:
>>> 1. Kernel's code:
>>> because Sometimes 9th clock pulse isn't generated, that code is to
>> generate the 9th clock pulse.
>>
>> What code are you looking at? Are you just reading the comment?
>> Look at http://git.kernel.org/?p=linux/kernel/git/next/linux-
>> next.git;a=commit;h=0c2daaafcdec726e89cbccca61d576de8429c537
>> to get a clue.
>>
>> Your code isn't complete, you cannot trust the manual to be the whole
>> truth.
>>
> I am very confused, why do you always say my code isn't complete?

Because it is not complete?

> I have described I want to do detailed in comment.
> "when a system reset does not cause all I2C devices to be reset", 

You wrote:
"So, the kernel's patch and my patch is to resolve the different issue."

Yes! There are more "problems" on i2c bus, as also Joakim described!
And if we try to fix them in the common driver (as you did), we should
fix all known problems -> so your patch is incomplete.

> My codes will force the I2c module to become bus master and drive SCL,
> which force this i2c module to generate SCL so that the device driving SDA can finish its transaction.
> These codes have been used on Emerson's P1022 board and resolved his issue (board will hang when u-boot booting, with my codes, this issue is resolved and board can boot well)

Then you maybe define CONFIG_SYS_I2C_BOARD_LATE_INIT for this
board and do this in board code.

> This is one feature of FSL I2C almost cover all 85xx platform, and the code according to the RM has been verified, don't you think the manual can be trust?

See (for example on a mpc83xx based board) board/keymile/common/common.c
functions i2c_write_start_seq() and i2c_make_abort() which solve also
a deblocked i2c bus ... and they started with the procedure noted
in the RM, but this didn't solved all issues for them.

> Below is the description from your link:
> This patch improves the recovery of the MPC's I2C bus from errors like bus
> hangs resulting in timeouts:
> 1. make the bus timeout configurable, as it depends on the bus clock and
>     the attached slave chip(s); default is still 1 second;
> 2. detect any of the cases indicated by the CF, BB and RXAK MSR flags if a
>     timeout occurs, and add a missing (required) MAL reset;
> 3. use a more reliable method to fixup the bus if a hang has been detected.
>     The sequence is sent 9 times which seems to be necessary if a slave
>     "misses" more than one clock cycle.  For 400 kHz bus speed, the fixup is
>     also ~70us (81us vs. 150us) faster.
> 
> This patch is created because a slave miss more than one clock cycle and can resolve this issue.
> 
> So, the kernel's patch and my patch is to resolve the different issue. 

Yes, and if editing a common driver, we should find a solution
which fit for all ... did you tried the linux driver code for your
board? Maybe it solves your problem too? So we can adapt it to u-boot
code?

bye,
Heiko
Changming Huang Oct. 28, 2011, 7:56 a.m. UTC | #12
Thanks and Best Regards
Jerry Huang


> -----Original Message-----
> From: Heiko Schocher [mailto:hs@denx.de]
> Sent: Friday, October 28, 2011 2:34 PM
> To: Huang Changming-R66093
> Cc: Joakim Tjernlund; u-boot@lists.denx.de
> Subject: Re: [U-Boot] [PATCH 2/2] Powerpc/i2c: Force i2c to become bus
> master out of reset
> 
> Hello Huang Changming-R66093,
> 
> Huang Changming-R66093 wrote:
> >>> These tow part codes are doing the different thing due to the
> >> different reason:
> >>> 1. Kernel's code:
> >>> because Sometimes 9th clock pulse isn't generated, that code is to
> >> generate the 9th clock pulse.
> >>
> >> What code are you looking at? Are you just reading the comment?
> >> Look at http://git.kernel.org/?p=linux/kernel/git/next/linux-
> >> next.git;a=commit;h=0c2daaafcdec726e89cbccca61d576de8429c537
> >> to get a clue.
> >>
> >> Your code isn't complete, you cannot trust the manual to be the
> whole
> >> truth.
> >>
> > I am very confused, why do you always say my code isn't complete?
> 
> Because it is not complete?
I don't think it is not complete, because this patch resolves my issue.


> > I have described I want to do detailed in comment.
> > "when a system reset does not cause all I2C devices to be reset",
> 
> You wrote:
> "So, the kernel's patch and my patch is to resolve the different
> issue."
> 
> Yes! There are more "problems" on i2c bus, as also Joakim described!
> And if we try to fix them in the common driver (as you did), we should
> fix all known problems -> so your patch is incomplete.

Yes, we should fix all known problems, but we should not hope one patch includes everything.
it make sense for one patch to resolve one thing, instead of all.

> > My codes will force the I2c module to become bus master and drive SCL,
> > which force this i2c module to generate SCL so that the device
> driving SDA can finish its transaction.
> > These codes have been used on Emerson's P1022 board and resolved his
> > issue (board will hang when u-boot booting, with my codes, this issue
> > is resolved and board can boot well)
> 
> Then you maybe define CONFIG_SYS_I2C_BOARD_LATE_INIT for this board and
> do this in board code.

I have pointed out, this is one feature of FSL I2C module and almost cover all 85xx platform,
we provides one solution to resolve the i2c bus "reset" issue.
So I think it is not necessary to define one macro for one special board. 

> > This is one feature of FSL I2C almost cover all 85xx platform, and
> the code according to the RM has been verified, don't you think the
> manual can be trust?
> 
> See (for example on a mpc83xx based board)
> board/keymile/common/common.c functions i2c_write_start_seq() and
> i2c_make_abort() which solve also a deblocked i2c bus ... and they
> started with the procedure noted in the RM, but this didn't solved all
> issues for them.
> 
> > Below is the description from your link:
> > This patch improves the recovery of the MPC's I2C bus from errors
> like
> > bus hangs resulting in timeouts:
> > 1. make the bus timeout configurable, as it depends on the bus clock
> and
> >     the attached slave chip(s); default is still 1 second; 2. detect
> > any of the cases indicated by the CF, BB and RXAK MSR flags if a
> >     timeout occurs, and add a missing (required) MAL reset; 3. use a
> > more reliable method to fixup the bus if a hang has been detected.
> >     The sequence is sent 9 times which seems to be necessary if a
> slave
> >     "misses" more than one clock cycle.  For 400 kHz bus speed, the
> fixup is
> >     also ~70us (81us vs. 150us) faster.
> >
> > This patch is created because a slave miss more than one clock cycle
> and can resolve this issue.
> >
> > So, the kernel's patch and my patch is to resolve the different issue.
> 
> Yes, and if editing a common driver, we should find a solution which
> fit for all ... did you tried the linux driver code for your board?
> Maybe it solves your problem too? So we can adapt it to u-boot code?
> 
I can't try the Linux driver on my boards, because all boards on my hand has not these two i2c issue.
These codes is generated according to FSL Reference Manual, if you check the RM of FSL, you will find out all 85xx chips(now I know) support this feature.
And these code can be work on Emerson's p1022 board, if the code according to the RM can work, I don't  think I have any reason to ask customer to use the other codes.
And the solution RM provide can resolve the issue, why don't we trust the RM?
diff mbox

Patch

diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index 258be0a..007db70 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -252,6 +252,24 @@  i2c_init(int speed, int slaveadd)
 		writeb(slaveadd << 1, &dev->adr);/* write slave address */
 		writeb(0x0, &dev->sr);		/* clear status register */
 		writeb(I2C_CR_MEN, &dev->cr);	/* start I2C controller */
+
+		/* Force I2C module to become bus master which can occure when
+		 * a system reset does not cause all I2C devices to be reset */
+		udelay(5);
+		if (readb(&dev->sr) & I2C_SR_MBB) {
+			writeb(I2C_CR_MSTA, &dev->cr);
+			udelay(5);
+			writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
+			udelay(5);
+			readb(&dev->dr);
+			udelay(5);
+			writeb(I2C_CR_MEN, &dev->cr);
+			udelay(5);
+			if (readb(&dev->sr) & I2C_SR_MBB)
+				debug("I2C%d: Drive SCL failed\n", i + 1);
+			else
+				debug("I2C%d: Drive SCL succeed\n", i + 1);
+		}
 	}
 
 #ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT