hpm_smbus.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Copyright (c) 2023 HPMicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. */
  7. #include "hpm_smbus.h"
  8. static uint8_t hpm_smbus_pec_crc8(uint8_t *data, uint32_t len);
  9. hpm_stat_t hpm_smbus_master_write_byte(I2C_Type *ptr, uint8_t slave_address, uint8_t data)
  10. {
  11. hpm_stat_t stat;
  12. uint8_t buf[3];
  13. /* addr + rw bit*/
  14. buf[0] = slave_address << 1;
  15. buf[1] = data;
  16. buf[2] = hpm_smbus_pec_crc8(buf, 2);
  17. stat = i2c_master_write(ptr, (const uint16_t)slave_address, &buf[1], sizeof(buf) - 1);
  18. return stat;
  19. }
  20. hpm_stat_t hpm_smbus_master_read_byte(I2C_Type *ptr, uint8_t slave_address, uint8_t *data)
  21. {
  22. uint8_t buf[3];
  23. hpm_stat_t stat;
  24. uint8_t pec;
  25. /* addr + rw bit*/
  26. buf[0] = (slave_address << 1);
  27. stat = i2c_master_read(ptr, (const uint16_t)slave_address, &buf[1], sizeof(buf) - 1);
  28. if (stat == status_success) {
  29. pec = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
  30. if (pec == buf[2]) {
  31. *data = buf[1];
  32. } else {
  33. stat = status_fail;
  34. }
  35. }
  36. return stat;
  37. }
  38. hpm_stat_t hpm_smbus_master_write_byte_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t data)
  39. {
  40. hpm_stat_t stat;
  41. uint8_t buf[4];
  42. /* addr + rw bit*/
  43. buf[0] = slave_address << 1;
  44. buf[1] = command;
  45. buf[2] = data;
  46. buf[3] = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
  47. stat = i2c_master_write(ptr, (const uint16_t)slave_address, &buf[1], sizeof(buf) - 1);
  48. return stat;
  49. }
  50. hpm_stat_t hpm_smbus_master_write_word_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint16_t data)
  51. {
  52. hpm_stat_t stat;
  53. uint8_t buf[5];
  54. /* addr + rw bit*/
  55. buf[0] = slave_address << 1;
  56. buf[1] = command;
  57. *(uint16_t *)(&buf[2]) = data;
  58. buf[4] = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
  59. stat = i2c_master_write(ptr, (const uint16_t)slave_address, &buf[1], sizeof(buf) - 1);
  60. return stat;
  61. }
  62. hpm_stat_t hpm_smbus_master_read_byte_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data)
  63. {
  64. hpm_stat_t stat;
  65. uint8_t pec;
  66. uint8_t buf[5];
  67. /* addr + rw bit*/
  68. buf[0] = (slave_address << 1);
  69. buf[1] = command;
  70. /* write command code in smbus spec*/
  71. stat = i2c_master_seq_transmit(ptr, (const uint16_t)slave_address, &command, sizeof(uint8_t), i2c_frist_frame);
  72. if (stat == status_success) {
  73. /* read */
  74. buf[2] = (slave_address << 1) | 0x01;
  75. /* now change dir,restart, read the byte */
  76. stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[3], 1, i2c_frist_frame);
  77. /* read the pec */
  78. stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[4], 1, i2c_last_frame);
  79. if (stat == status_success) {
  80. pec = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
  81. if (pec == buf[4]) {
  82. *data = buf[3];
  83. } else {
  84. stat = status_fail;
  85. }
  86. }
  87. }
  88. return stat;
  89. }
  90. hpm_stat_t hpm_smbus_master_read_word_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint16_t *data)
  91. {
  92. hpm_stat_t stat;
  93. uint8_t pec;
  94. uint8_t buf[6];
  95. /* addr + rw bit*/
  96. buf[0] = (slave_address << 1);
  97. buf[1] = command;
  98. /* write command code in smbus spec*/
  99. stat = i2c_master_seq_transmit(ptr, (const uint16_t)slave_address, &command, sizeof(uint8_t), i2c_frist_frame);
  100. if (stat == status_success) {
  101. /* read */
  102. buf[2] = (slave_address << 1) | 0x01;
  103. /* now change dir,restart, read the word (16 bits)*/
  104. stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[3], 2, i2c_frist_frame);
  105. /* read the pec */
  106. stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[5], 1, i2c_last_frame);
  107. if (stat == status_success) {
  108. pec = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
  109. if (pec == buf[5]) {
  110. *data = *(uint16_t *)(&buf[3]);
  111. } else {
  112. stat = status_fail;
  113. }
  114. }
  115. }
  116. return stat;
  117. }
  118. hpm_stat_t hpm_smbus_master_write_block_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t size)
  119. {
  120. hpm_stat_t stat;
  121. uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
  122. uint16_t buf_size;
  123. /* frame included addr, command, data, and pec */
  124. assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 3));
  125. /* addr + rw bit*/
  126. buf[0] = slave_address << 1;
  127. buf[1] = command;
  128. buf[2] = size;
  129. memcpy(&buf[3], data, size);
  130. buf[size + 3] = hpm_smbus_pec_crc8(buf, size + 3);
  131. buf_size = size + 4;
  132. stat = i2c_master_write(ptr, (const uint16_t)slave_address, buf, buf_size);
  133. return stat;
  134. }
  135. hpm_stat_t hpm_smbus_master_read_block_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t size)
  136. {
  137. hpm_stat_t stat;
  138. uint8_t pec;
  139. uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
  140. /* frame included addr, command, data, and pec */
  141. assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 3));
  142. /* addr + rw bit*/
  143. buf[0] = (slave_address << 1);
  144. buf[1] = command;
  145. /* write command code in smbus spec*/
  146. stat = i2c_master_seq_transmit(ptr, (const uint16_t)slave_address, &command, sizeof(uint8_t), i2c_frist_frame);
  147. /* read */
  148. buf[2] = (slave_address << 1) | 0x01;
  149. if (stat == status_success) {
  150. /* now change dir,restart, read the block count*/
  151. stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[3], 1, i2c_frist_frame);
  152. /* read data*/
  153. stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[4], size, i2c_next_frame);
  154. /* read pec */
  155. stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[size + 4], 1, i2c_last_frame);
  156. if (stat == status_success) {
  157. pec = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
  158. if (pec == buf[size + 4]) {
  159. memcpy(data, &buf[4], size);
  160. } else {
  161. stat = status_fail;
  162. }
  163. }
  164. }
  165. return stat;
  166. }
  167. hpm_stat_t hpm_smbus_master_write(I2C_Type *ptr, uint8_t slave_address, uint8_t *data, uint32_t size)
  168. {
  169. hpm_stat_t stat;
  170. uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
  171. uint16_t buf_size;
  172. /* frame included addr, data, and pec */
  173. assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 1));
  174. /* addr + rw bit*/
  175. buf[0] = (slave_address << 1) | 0x01;
  176. memcpy(&buf[1], data, size);
  177. buf[size + 1] = hpm_smbus_pec_crc8(buf, size + 1);
  178. buf_size = size + 1;
  179. stat = i2c_master_write(ptr, (const uint16_t)slave_address, &buf[1], buf_size);
  180. return stat;
  181. }
  182. hpm_stat_t hpm_smbus_master_read(I2C_Type *ptr, uint8_t slave_address, uint8_t *data, uint32_t size)
  183. {
  184. hpm_stat_t stat;
  185. uint8_t pec;
  186. uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
  187. /* frame included addr, data, and pec */
  188. assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 2));
  189. buf[0] = (slave_address << 1);
  190. stat = i2c_master_read(ptr, slave_address, &buf[1], size + 1);
  191. if (stat == status_success) {
  192. pec = hpm_smbus_pec_crc8(buf, size + 1);
  193. if (pec == buf[size + 1]) {
  194. memcpy(data, &buf[1], size);
  195. } else {
  196. stat = status_fail;
  197. }
  198. }
  199. return stat;
  200. }
  201. hpm_stat_t hpm_smbus_slave_write(I2C_Type *ptr, uint8_t *data, uint32_t size)
  202. {
  203. hpm_stat_t stat;
  204. uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
  205. uint16_t buf_size;
  206. uint8_t slave_address;
  207. /* frame included addr, data, and pec */
  208. assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 1));
  209. slave_address = ptr->ADDR;
  210. /* addr + rw bit*/
  211. buf[0] = (slave_address << 1);
  212. memcpy(&buf[1], data, size);
  213. buf[size + 1] = hpm_smbus_pec_crc8(buf, size + 1);
  214. buf_size = size + 1;
  215. stat = i2c_slave_write(ptr, &buf[1], buf_size);
  216. return stat;
  217. }
  218. hpm_stat_t hpm_smbus_slave_read(I2C_Type *ptr, uint8_t *data, uint32_t size)
  219. {
  220. hpm_stat_t stat;
  221. uint8_t pec;
  222. uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
  223. uint8_t slave_address;
  224. /* frame included addr, data, and pec */
  225. assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 2));
  226. /* addr + rw bit*/
  227. slave_address = ptr->ADDR;
  228. buf[0] = (slave_address << 1) | 0x01;
  229. stat = i2c_slave_read(ptr, &buf[1], size + 1);
  230. if (stat == status_success) {
  231. pec = hpm_smbus_pec_crc8(buf, size + 1);
  232. if (pec == buf[size + 1]) {
  233. memcpy(data, &buf[1], size);
  234. } else {
  235. stat = status_fail;
  236. }
  237. }
  238. return stat;
  239. }
  240. static uint8_t hpm_smbus_pec_crc8(uint8_t *data, uint32_t len)
  241. {
  242. /* The PEC is a CRC-8 error-checking byte, calculated on all the message bytes (including addresses and read/write bits) */
  243. uint32_t i;
  244. uint8_t crc = 0x00;
  245. while (len--) {
  246. crc ^= *data++;
  247. for (i = 0; i < 8; i++) {
  248. if (crc & 0x80) {
  249. crc = (crc << 1) ^ 0x07;
  250. } else {
  251. crc <<= 1;
  252. }
  253. }
  254. }
  255. return crc;
  256. }