Heiko Schocher <h...@denx.de> wrote on 28/01/2009 11:54:22: > Hello Joakim, > > 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); } _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot