From mboxrd@z Thu Jan 1 00:00:00 1970 From: Heiko Schocher Date: Wed, 28 Jan 2009 13:04:41 +0100 Subject: [U-Boot] [PATCH 19/31] i2c, mpc83xx: add CONFIG_SYS_I2C_INIT_BOARD for fsl_i2c In-Reply-To: References: <498027FB.9060709@denx.de> <4980395E.3020501@denx.de> Message-ID: <498049D9.9030605@denx.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hello Joakim, Joakim Tjernlund wrote: > Heiko Schocher 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 > * 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? bye Heiko -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany