[U-Boot] [PATCH 19/31] i2c, mpc83xx: add CONFIG_SYS_I2C_INIT_BOARD for fsl_i2c

Heiko Schocher
2009-01-28T12:04:41Z

Hello Joakim,

Joakim Tjernlund wrote:
> Heiko Schocher <hs@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?

bye
Heiko