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 <msieron@antmicro.com>
This commit is contained in:
Michal Sieron 2023-01-23 18:33:51 +01:00
parent b85705351c
commit ac99709031
1 changed files with 6 additions and 1 deletions

View File

@ -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;