i2c: i2c_cdns: fix write timeout on fifo boundary
authorMichael Auchter <michael.auchter@ni.com>
Mon, 9 Dec 2019 18:16:16 +0000 (18:16 +0000)
committerHeiko Schocher <hs@denx.de>
Wed, 11 Dec 2019 05:25:13 +0000 (06:25 +0100)
This fixes an issue that would cause I2C writes to timeout when the
number of bytes is a multiple of the FIFO depth (i.e. 16 bytes).

Within the transfer loop, after writing the data register with a new
byte to transfer, if the transfer size equals the FIFO depth, the loop
pauses until the INTERRUPT_COMP bit asserts to indicate data has been
sent. This same check is performed after the loop as well to ensure data
has been transferred prior to returning.

In the case where the amount of data to be written is a multiple of the
FIFO depth, the transfer loop would wait for the INTERRUPT_COMP bit to
assert after writing the final byte, and then wait for this bit to
assert once more. However, since the transfer has finished at this
point, no new data has been written to the data register, and hence
INTERRUPT_COMP will never assert.

Fix this by only waiting for INTERRUPT_COMP in the transfer loop if
there's still data to be written.

Signed-off-by: Michael Auchter <michael.auchter@ni.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/i2c/i2c-cdns.c

index 2c0301ad083a0dbc4b7146f9e3a3c640f314960b..ff3956d8c23d7e7f1f0d82467c888b5c305ee66c 100644 (file)
@@ -265,7 +265,7 @@ static int cdns_i2c_write_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
 
        while (len-- && !is_arbitration_lost(regs)) {
                writel(*(cur_data++), &regs->data);
-               if (readl(&regs->transfer_size) == CDNS_I2C_FIFO_DEPTH) {
+               if (len && readl(&regs->transfer_size) == CDNS_I2C_FIFO_DEPTH) {
                        ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
                                            CDNS_I2C_INTERRUPT_ARBLOST);
                        if (ret & CDNS_I2C_INTERRUPT_ARBLOST)