• Jarkko Nikula's avatar
    i2c: designware: Empty receive FIFO in slave interrupt handler · dcf1bf64
    Jarkko Nikula authored
    Writes from I2C bus often fail when testing the i2c-designware-slave.c
    with the slave-eeprom backend. The same writes work correctly when
    testing with a real 24c02 EEPROM chip.
    
    In the tests below an i2c-designware-slave.c instance with the
    slave-eeprom backend is configured to act as a simulated 24c02 at
    address 0x65 on an I2C host bus 6.
    
    1. i2cset -y 6 0x65 0x00 0x55
    
    Single byte 0x55 write into address 0x00. No data goes into simulated
    EEPROM. Debug prints from the i2c_dw_irq_handler_slave():
    
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x714 : INTR_STAT=0x204
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
    
    2. i2ctransfer -y 6 w9@0x65 0x00 0xff-
    
    Write 8 bytes with decrementing value starting from 0xff at address 0x00
    and forward. Only some of the data goes into arbitrary addresses.
    Content is something like below but varies:
    
    00000000  f9 f8 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    00000050  00 00 00 00 00 00 ff fe  00 00 00 00 00 00 00 00  |................|
    000000f0  00 00 00 00 00 00 00 00  00 00 00 00 00 fc fb fa  |................|
    
    In this case debug prints were:
    
    0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
    0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x714 : INTR_STAT=0x204
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
    0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x510 : INTR_STAT=0x0
    
    Both cases show there is more data coming from the receive FIFO still
    after detecting the STOP condition. This can be seen from interrupt
    status bits DW_IC_INTR_STOP_DET (0x200) and DW_IC_INTR_RX_FULL (0x4).
    
    Perhaps due interrupt latencies the receive FIFO is not read fast
    enough, STOP detection happens synchronously when it occurs on the I2C
    bus and the DW_IC_INTR_RX_FULL keeps coming as long as there are more
    bytes in the receive FIFO.
    
    Fix this by reading the receive FIFO completely empty whenever
    DW_IC_INTR_RX_FULL occurs. Use RFNE, Receive FIFO Not Empty bit in the
    DW_IC_STATUS register to loop through bytes in the FIFO.
    
    While at it do not test the return code from i2c_slave_event() for the
    I2C_SLAVE_WRITE_RECEIVED since to my understanding this hardware cannot
    generate NACK to incoming bytes and debug print itself does not have
    much value.
    Reported-by: default avatarTian Ye <tianye@sugon.com>
    Signed-off-by: default avatarJarkko Nikula <jarkko.nikula@linux.intel.com>
    Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
    Signed-off-by: default avatarWolfram Sang <wsa@kernel.org>
    dcf1bf64
i2c-designware-core.h 12.5 KB