AnsweredAssumed Answered

read i2c failure on u-boot-imx_2015.04

Question asked by Birger Bauch on Sep 15, 2016

Hello, there seams to be an error in the i2c read procedure inside u-boot-imx_2015.04.

 

We are using an security module connected via i2c. Read and write works well with the community based linux-fslc_4.4. But from u-boot we always got 0xFF reading the i2c device. A code analysis together with oscilloscope shows the difference.

  • In write direction it should be correct:

   bus_i2c_write()

   => ii2c_init_transfer(i2c_regs, chip, addr, alen)

   ===> i2c_init_transfer_(i2c_regs, chip, addr, alen)

   => i2c_write_data()

   The address will be set inside i2c_init_transfer_() with: tx_byte(i2c_regs, chip << 1)

  • In read direction we have a similar procedure:

   bus_i2c_read()

   => ii2c_init_transfer(i2c_regs, chip, addr, alen)

   ===> i2c_init_transfer_(i2c_regs, chip, addr, alen)

   => set address with tx_byte(i2c_regs, (chip << 1) | 1)

   => i2c_read_data()

   That means, the address will be set twice, first inside i2c_init_transfer_() with: tx_byte(i2c_regs, chip << 1) followed by tx_byte(i2c_regs, (chip << 1) | 1)

 

So the i2c device can't understand these wrong address setting and answer with 0xFF.

 

Following workaround works with our i2c security module. We are using an additional flag to distinguish between read and write.

   bus_i2c_write()

   => ii2c_init_transfer(i2c_regs, chip, addr, alen, 1)

   ===> i2c_init_transfer_(i2c_regs, chip, addr, alen, 1)

 

   bus_i2c_read()

   => ii2c_init_transfer(i2c_regs, chip, addr, alen, 0)

   ===> i2c_init_transfer_(i2c_regs, chip, addr, alen, 0)

 

static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs,
        uchar chip, uint addr, int alen, int flag)
{

...

    if (flag) {
        /* write slave address */
        ret = tx_byte(i2c_regs, chip << 1);
        if (ret < 0)
            return ret;

 

        while (alen--) {
            ret = tx_byte(i2c_regs, (addr >> (alen * 8)) & 0xff);
            if (ret < 0)
                return ret;
        }
    }
    return 0;

}

 

Now the address (with write request) will be only written inside i2c_init_transfer_() if the flag is set.

 

Regards,

Birger

Outcomes