From ac99709031b4e885052c48f779a2d697c442b877 Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 23 Jan 2023 18:33:51 +0100 Subject: [PATCH] libbase/i2c: fix i2c_poll Change made in 1989d85 was supposed to poll I2C devices using both writes and reads. Here is a sequence that was supposed to happen: - I2C start - start I2C write - start I2C read - I2C stop Unfortunately, the change worked differently: - I2C start - start I2C write - write byte of (slave_addr << 1 | 1) - I2C stop This way, not only did the read not happen, but a potentially harmful write was happening. This commit makes it so following sequence takes place: - I2C start - start I2C write - if (I2C write returned NACK) - start I2C read - if (I2C read returned ACK) - read 1 byte and NACK it - I2C stop An additional 1 byte read is happening, as some devices may be unable to process I2C stop after initiating I2C read. Signed-off-by: Michal Sieron --- litex/soc/software/libbase/i2c.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/litex/soc/software/libbase/i2c.c b/litex/soc/software/libbase/i2c.c index d8073e3e0..f21ae3fed 100644 --- a/litex/soc/software/libbase/i2c.c +++ b/litex/soc/software/libbase/i2c.c @@ -274,7 +274,12 @@ bool i2c_poll(unsigned char slave_addr) i2c_start(); result = i2c_transmit_byte(I2C_ADDR_WR(slave_addr)); - result |= i2c_transmit_byte(I2C_ADDR_RD(slave_addr)); + if (!result) { + i2c_start(); + result |= i2c_transmit_byte(I2C_ADDR_RD(slave_addr)); + if (result) + i2c_receive_byte(false); + } i2c_stop(); return result;