[U-Boot] rockchip: i2c: fix >32 byte reads

Wadim Egorov w.egorov at phytec.de
Mon Aug 21 08:32:54 UTC 2017



Am 18.08.2017 um 15:06 schrieb Philipp Tomsich:
>
>
> On Thu, 3 Aug 2017, Wadim Egorov wrote:
>
>> The hw can read up to 32 bytes at a time. If we need
>> more than one chunk, we have to enter the plain RX mode.
>
> Why does this need to be in 'plain RX' mode for more than 32 bytes?

I am not sure why this need to be in receive only mode. Probably that's
how the I2C controller operates for more than 32 byte reads?
Anyway, if you try to read more than 32 bytes from an EEPROM, you will
get RXDATA registers filled with 0xFF in the following chunks without
this patch.
Same thing is done in the linux i2c driver:
 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/i2c/busses/i2c-rk3x.c?h=v4.13-rc5#n322


> What happens if someone wants to write/transmit more than 32 bytes?

Should not affect other operations as the I2C_CON_MODE will be set
properly in rk_i2c_read/write() calls before every I2C transmit.

Regards,
Wadim

>
>>
>> Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
>> Acked-by: Philipp Tomsich <philipp.tomsich at theobroma-systems.com>
>> ---
>> drivers/i2c/rk_i2c.c | 19 ++++++++++++++++---
>> 1 file changed, 16 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c
>> index 8bc045a..68e6653 100644
>> --- a/drivers/i2c/rk_i2c.c
>> +++ b/drivers/i2c/rk_i2c.c
>> @@ -164,6 +164,7 @@ static int rk_i2c_read(struct rk_i2c *i2c, uchar
>> chip, uint reg, uint r_len,
>>     uint rxdata;
>>     uint i, j;
>>     int err;
>> +    bool snd_chunk = false;
>>
>>     debug("rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
>>           chip, reg, r_len, b_len);
>> @@ -184,15 +185,26 @@ static int rk_i2c_read(struct rk_i2c *i2c,
>> uchar chip, uint reg, uint r_len,
>>
>>     while (bytes_remain_len) {
>>         if (bytes_remain_len > RK_I2C_FIFO_SIZE) {
>> -            con = I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TRX);
>> +            con = I2C_CON_EN;
>>             bytes_xferred = 32;
>>         } else {
>> -            con = I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TRX) |
>> -                I2C_CON_LASTACK;
>> +            /*
>> +             * The hw can read up to 32 bytes at a time. If we need
>> +             * more than one chunk, send an ACK after the last byte.
>> +             */
>> +            con = I2C_CON_EN | I2C_CON_LASTACK;
>>             bytes_xferred = bytes_remain_len;
>>         }
>>         words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
>>
>> +        /*
>> +         * make sure we are in plain RX mode if we read a second chunk
>> +         */
>> +        if (snd_chunk)
>> +            con |= I2C_CON_MOD(I2C_MODE_RX);
>> +        else
>> +            con |= I2C_CON_MOD(I2C_MODE_TRX);
>> +
>>         writel(con, &regs->con);
>>         writel(bytes_xferred, &regs->mrxcnt);
>>         writel(I2C_MBRFIEN | I2C_NAKRCVIEN, &regs->ien);
>> @@ -227,6 +239,7 @@ static int rk_i2c_read(struct rk_i2c *i2c, uchar
>> chip, uint reg, uint r_len,
>>         }
>>
>>         bytes_remain_len -= bytes_xferred;
>> +        snd_chunk = true;
>>         debug("I2C Read bytes_remain_len %d\n", bytes_remain_len);
>>     }
>>
>>



More information about the U-Boot mailing list