i2c.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #include "i2c.h"
  2. volatile bool _i2c_locked;
  3. int i2c_send(uint8_t addr, const void *buf, size_t len)
  4. {
  5. return i2c_send_recv(addr, data, len, NULL, 0);
  6. }
  7. int i2c_recv(uint8_t addr, void *buf, size_t len)
  8. {
  9. return i2c_send_recv(addr, NULL, 0, buf, len);
  10. }
  11. static int i2c_send_byte_err(uint8_t byte, uint8_t ctl)
  12. {
  13. uint32_t wdata = (byte << 8) | I2C_NAK | ctl;
  14. uint32_t status = (wdata & ~I2C_NAK) | I2C_SCL | ((~ctl & 4) << 2);
  15. i2c_wait();
  16. I2C_WDATA = wdata;
  17. i2c_wait();
  18. status ^= I2C_RDATA & ~I2C_SDA;
  19. if (!status)
  20. return 0;
  21. else if (status & 0x7f)
  22. return I2C_ERR_IO;
  23. else if (status & I2C_NAK)
  24. return I2C_ERR_NAK;
  25. else
  26. return I2C_ERR_CONFLICT;
  27. }
  28. static int i2c_recv_byte_err(uint8_t ctl)
  29. {
  30. uint32_t status = I2C_SCL | (ctl & 6) | ((~ctl & 4) << 2);
  31. i2c_wait();
  32. I2C_WDATA = (0xff << 8) | ctl;
  33. i2c_wait();
  34. status ^= I2C_RDATA & ~I2C_SDA;
  35. if (status & 0x7f)
  36. return I2C_ERR_IO;
  37. else
  38. return status >> 8; /* Data byte (will be >= 0) */
  39. }
  40. int i2c_send_recv(uint8_t addr,
  41. const void *obuf, size_t olen,
  42. void *ibuf, size_t ilen)
  43. {
  44. int sda_retry_count = 16;
  45. int err = 0;
  46. uint8_t ctl = I2C_P;
  47. if (unlikely(!olen && !ilen))
  48. return 0;
  49. if (!i2c_lock())
  50. return I2C_BUSY;
  51. /* SDA held low? */
  52. while (unlikely(!(I2C_RDATA & I2C_SDA))) {
  53. i2c_send_byte(0xff, I2C_DUMMY);
  54. i2c_wait();
  55. if (!sda_retry_count--) {
  56. err = I2C_ERR_STUCK;
  57. goto done;
  58. }
  59. }
  60. if (olen) {
  61. const uint8_t wcmd = addr << 1;
  62. const uint8_t *p = obuf;
  63. ctl = 0;
  64. err = i2c_send_byte_err(wcmd, ctl);
  65. if (err) {
  66. if (err == I2C_ERR_NAK)
  67. err = I2C_ERR_NODEV;
  68. goto done;
  69. }
  70. while (olen--) {
  71. ctl = olen ? 0 : ilen ? I2C_SR : I2C_P;
  72. err = i2c_send_byte_err(*p++, ctl);
  73. if (err) {
  74. if (!(ctl & I2C_P))
  75. i2c_send_byte(0xff, I2C_P);
  76. goto done;
  77. }
  78. }
  79. }
  80. if (ilen) {
  81. const uint8_t rcmd = (addr << 1) + 1;
  82. uint8_t *q = ibuf;
  83. ctl = 0;
  84. err = i2c_send_byte_err(rcmd, ctl);
  85. if (err) {
  86. if (err == I2C_ERR_NAK)
  87. err = I2C_ERR_NODEV;
  88. goto done;
  89. }
  90. while (ilen--) {
  91. int data;
  92. ctl = ilen ? 0 : I2C_P;
  93. data = i2c_recv_byte_err(ctl);
  94. if (data < 0) {
  95. err = data;
  96. goto done;
  97. }
  98. *q++ = data;
  99. }
  100. }
  101. I2C_RESET = I2C_RESET_UNSTART; /* If transaction aborted */
  102. i2c_unlock();
  103. return err;
  104. }