diff options
author | Marek Vasut <marex@denx.de> | 2013-11-04 14:29:12 +0100 |
---|---|---|
committer | Heiko Schocher <hs@denx.de> | 2013-11-13 06:08:31 +0100 |
commit | 124913556c4b99909f40b4bf4ceaefe2b555d6f8 (patch) | |
tree | db5e072f22de6055075a620e21004ced7026e096 | |
parent | 2035d77d790044f389a18c0e6baa05e86d4b32a0 (diff) | |
download | u-boot-imx-124913556c4b99909f40b4bf4ceaefe2b555d6f8.zip u-boot-imx-124913556c4b99909f40b4bf4ceaefe2b555d6f8.tar.gz u-boot-imx-124913556c4b99909f40b4bf4ceaefe2b555d6f8.tar.bz2 |
i2c: mxs_i2c: Squash endless loop
The endless waiting for a bit to be set can cause a hang, add a timeout
so we prevent such situation. A testcase for such a hang is below. The
testcase assumes a device to be present at address 0x50 and a device to
NOT be present at address 0x42 . Also note that the "sleep 1" induced
delays are imperative for this bug to manifest .
i2c read 0x42 0x0.2 0x10 0x42000000 ; sleep 1 ; \
i2c read 0x50 0x0.2 0x10 0x42000000 ; sleep 1 ; \
i2c read 0x42 0x0.2 0x10 0x42000000
The expected result of the above command is:
Error reading the chip.
Error reading the chip.
While without this patch, we observe a hang in the last read from 0x42
precisely when waiting for this bit to be set.
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Heiko Schocher <hs@denx.de>
Cc: Stefano Babic <sbabic@denx.de>
-rw-r--r-- | drivers/i2c/mxs_i2c.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/i2c/mxs_i2c.c b/drivers/i2c/mxs_i2c.c index 46106b7..a298c95 100644 --- a/drivers/i2c/mxs_i2c.c +++ b/drivers/i2c/mxs_i2c.c @@ -150,6 +150,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; uint32_t tmp = 0; + int timeout = MXS_I2C_MAX_TIMEOUT; int ret; int i; @@ -169,9 +170,17 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) for (i = 0; i < len; i++) { if (!(i & 3)) { - while (readl(&i2c_regs->hw_i2c_queuestat) & - I2C_QUEUESTAT_RD_QUEUE_EMPTY) - ; + while (--timeout) { + tmp = readl(&i2c_regs->hw_i2c_queuestat); + if (!(tmp & I2C_QUEUESTAT_RD_QUEUE_EMPTY)) + break; + } + + if (!timeout) { + debug("MXS I2C: Failed receiving data!\n"); + return -ETIMEDOUT; + } + tmp = readl(&i2c_regs->hw_i2c_queuedata); } buffer[i] = tmp & 0xff; |