123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- #include "i2c.h"
- volatile bool _i2c_locked;
- int i2c_send(uint8_t addr, const void *buf, size_t len)
- {
- return i2c_send_recv(addr, data, len, NULL, 0);
- }
- int i2c_recv(uint8_t addr, void *buf, size_t len)
- {
- return i2c_send_recv(addr, NULL, 0, buf, len);
- }
- static int i2c_send_byte_err(uint8_t byte, uint8_t ctl)
- {
- uint32_t wdata = (byte << 8) | I2C_NAK | ctl;
- uint32_t status = (wdata & ~I2C_NAK) | I2C_SCL | ((~ctl & 4) << 2);
- i2c_wait();
- I2C_WDATA = wdata;
- i2c_wait();
- status ^= I2C_RDATA & ~I2C_SDA;
- if (!status)
- return 0;
- else if (status & 0x7f)
- return I2C_ERR_IO;
- else if (status & I2C_NAK)
- return I2C_ERR_NAK;
- else
- return I2C_ERR_CONFLICT;
- }
- static int i2c_recv_byte_err(uint8_t ctl)
- {
- uint32_t status = I2C_SCL | (ctl & 6) | ((~ctl & 4) << 2);
-
- i2c_wait();
- I2C_WDATA = (0xff << 8) | ctl;
- i2c_wait();
- status ^= I2C_RDATA & ~I2C_SDA;
- if (status & 0x7f)
- return I2C_ERR_IO;
- else
- return status >> 8; /* Data byte (will be >= 0) */
- }
- int i2c_send_recv(uint8_t addr,
- const void *obuf, size_t olen,
- void *ibuf, size_t ilen)
- {
- int sda_retry_count = 16;
- int err = 0;
- uint8_t ctl = I2C_P;
- if (unlikely(!olen && !ilen))
- return 0;
-
- if (!i2c_lock())
- return I2C_BUSY;
- /* SDA held low? */
- while (unlikely(!(I2C_RDATA & I2C_SDA))) {
- i2c_send_byte(0xff, I2C_DUMMY);
- i2c_wait();
- if (!sda_retry_count--) {
- err = I2C_ERR_STUCK;
- goto done;
- }
- }
- if (olen) {
- const uint8_t wcmd = addr << 1;
- const uint8_t *p = obuf;
- ctl = 0;
- err = i2c_send_byte_err(wcmd, ctl);
- if (err) {
- if (err == I2C_ERR_NAK)
- err = I2C_ERR_NODEV;
- goto done;
- }
- while (olen--) {
- ctl = olen ? 0 : ilen ? I2C_SR : I2C_P;
- err = i2c_send_byte_err(*p++, ctl);
- if (err) {
- if (!(ctl & I2C_P))
- i2c_send_byte(0xff, I2C_P);
- goto done;
- }
- }
- }
- if (ilen) {
- const uint8_t rcmd = (addr << 1) + 1;
- uint8_t *q = ibuf;
- ctl = 0;
- err = i2c_send_byte_err(rcmd, ctl);
- if (err) {
- if (err == I2C_ERR_NAK)
- err = I2C_ERR_NODEV;
- goto done;
- }
- while (ilen--) {
- int data;
-
- ctl = ilen ? 0 : I2C_P;
- data = i2c_recv_byte_err(ctl);
- if (data < 0) {
- err = data;
- goto done;
- }
- *q++ = data;
- }
- }
- I2C_RESET = I2C_RESET_UNSTART; /* If transaction aborted */
- i2c_unlock();
- return err;
- }
|