> Hello Joakim, > > Joakim Tjernlund wrote: > > Heiko Schocher <h...@denx.de> wrote on 28/01/2009 11:54:22: > >> Joakim Tjernlund wrote: > >>>> This patch adds the possibility to call a board specific > >>>> i2c bus reset routine for the fsl_i2c bus driver, and adds > >>>> this option for the keymile kmeter1 board. > >>>> > >> [...] > >>>> @@ -478,6 +480,17 @@ static int i2c_make_abort (void) > >>>> */ > >>>> void i2c_init_board(void) > >>>> { > >>>> +#if defined(CONFIG_KMETER1) > >>>> + struct fsl_i2c *dev; > >>>> + dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + > > CONFIG_SYS_I2C_OFFSET); > >>>> + uchar dummy; > >>>> + > >>>> + out_8 (&dev->cr, (I2C_CR_MSTA)); > >>>> + out_8 (&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA)); > >>>> + dummy = in_8(&dev->dr); > >>>> + out_8 (&dev->cr, (I2C_CR_MEN)); > >>> Are you sure this will generate a proper I2C reset sequence? We also > >>> use this controller and I tried to do it too but didn't find a way. I > > then > >>> asked > >>> Freescale and they could not come up with a solution either. > >> ? > >> This routine is decribed in the MPC8260ERM.pdf ยง15.5.7 on page 15-23 > >> from Freescale! > >> > >> 15.5.7 Generation of SCLn when SDAn is Negated > >> It is sometimes necessary to force the I2C module to become the I2C bus > > master out of reset and drive > >> SCLn (even though SDAn 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,
> > SDAn can be negated low by another > >> I2C device while this I2C module is coming out of reset and will stay > > low indefinitely. The following > >> procedure can be used to force this I2C module to generate SCLn so that > > the device driving SDAn can > >> finish its transaction: > >> 1. Disable the I2C module and set the master bit by setting I2CnCR to > > 0x20. > >> 2. Enable the I2C module by setting I2CnCR to 0xA0. > >> 3. Read I2CnDR. > >> 4. Return the I2C module to slave mode by setting I2CnCR to 0x80. > >> > >> And this worked fine on our Hardware ... > > > > Ahh, memory slowly returns. The problem is that this does not generate a > > reset > > sequence that will work in all cases. Consider the case when the > > CPU is reset half-way through writing or reading a byte from the device. > > > > I once researched this(can't remember the exact details now) but the > > only reset sequence that works in all cases is: > > > > static void send_start(void) > > { > > I2C_DELAY; > > I2C_TRISTATE; > > I2C_SDA(1); > > I2C_DELAY; > > I2C_SCL(1); > > I2C_DELAY; > > I2C_SDA(0); > > I2C_ACTIVE; > > I2C_DELAY; > > } > > > > static void send_stop(void) > > { > > I2C_SCL(0); > > I2C_DELAY; > > I2C_SDA(0); > > I2C_ACTIVE; > > I2C_DELAY; > > I2C_SCL(1); > > I2C_DELAY; > > I2C_TRISTATE; > > I2C_SDA(1); > > I2C_DELAY; > > } > > > > /*----------------------------------------------------------------------- > > * Send a reset sequence consisting of 9 clocks with the data signal high > > * to clock any confused device back into an idle state. Also send a > > * <stop> at the end of the sequence for belts & suspenders. > > */ > > void tm_i2c_reset(int bus) > > { > > int j; > > > > I2C_INIT; > > I2C_TRISTATE; > > for(j = 0; j < 9; j++) { > > if(I2C_READ) > > send_start(); > > I2C_SCL(0); > > I2C_DELAY; > > I2C_TRISTATE; > > I2C_SDA(1); > > I2C_DELAY; > > I2C_SCL(1); > > I2C_DELAY; > > I2C_DELAY; > > } > > send_stop(); > > if(!I2C_READ) > > printf("I2C SDA is low! I2C bus:%d is stuck!!!\n", bus); > > } > > I dont know if it is possible to make this with the 8360 ... > > Maybe we can do the following: > - make the reset Sequence suggested from Freescale > - checking the Status Register, if the Bus is now free (MBB Bit = 0) > If not, do again the reset Sequence. And this for max. 9 times. > > What do you think? It is better, but not complete I think. Looks similar to our old reset procedure that didn't handle the case when a slave was stuck writing a byte but without the STOP condition: I2C_INIT; I2C_SCL(1); I2C_SDA(1); I2C_INIT; I2C_TRISTATE; for(j = 0; j < 9; j++) { I2C_SCL(0); I2C_DELAY; I2C_DELAY; I2C_SCL(1); I2C_DELAY; I2C_DELAY; } send_stop(); if(!I2C_READ) printf("I2C SDA is low! I2C bus is stuck!!!\n"); You need to experiment and you probably need some help from Freescale. Jocke _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot