fdt_i2c_sifive.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2021 YADRO
  5. *
  6. * Authors:
  7. * Nikita Shubin <n.shubin@yadro.com>
  8. */
  9. #include <sbi/riscv_io.h>
  10. #include <sbi/sbi_error.h>
  11. #include <sbi/sbi_timer.h>
  12. #include <sbi_utils/fdt/fdt_helper.h>
  13. #include <sbi_utils/i2c/fdt_i2c.h>
  14. #define SIFIVE_I2C_ADAPTER_MAX 2
  15. #define SIFIVE_I2C_PRELO 0x00
  16. #define SIFIVE_I2C_PREHI 0x04
  17. #define SIFIVE_I2C_CTR 0x08
  18. #define SIFIVE_I2C_TXR 0x00c
  19. #define SIFIVE_I2C_RXR SIFIVE_I2C_TXR
  20. #define SIFIVE_I2C_CR 0x010
  21. #define SIFIVE_I2C_SR SIFIVE_I2C_CR
  22. #define SIFIVE_I2C_CTR_IEN (1 << 6)
  23. #define SIFIVE_I2C_CTR_EN (1 << 7)
  24. #define SIFIVE_I2C_CMD_IACK (1 << 0)
  25. #define SIFIVE_I2C_CMD_ACK (1 << 3)
  26. #define SIFIVE_I2C_CMD_WR (1 << 4)
  27. #define SIFIVE_I2C_CMD_RD (1 << 5)
  28. #define SIFIVE_I2C_CMD_STO (1 << 6)
  29. #define SIFIVE_I2C_CMD_STA (1 << 7)
  30. #define SIFIVE_I2C_STATUS_IF (1 << 0)
  31. #define SIFIVE_I2C_STATUS_TIP (1 << 1)
  32. #define SIFIVE_I2C_STATUS_AL (1 << 5)
  33. #define SIFIVE_I2C_STATUS_BUSY (1 << 6)
  34. #define SIFIVE_I2C_STATUS_RXACK (1 << 7)
  35. #define SIFIVE_I2C_WRITE_BIT (0 << 0)
  36. #define SIFIVE_I2C_READ_BIT (1 << 0)
  37. struct sifive_i2c_adapter {
  38. unsigned long addr;
  39. struct i2c_adapter adapter;
  40. };
  41. static unsigned int sifive_i2c_adapter_count;
  42. static struct sifive_i2c_adapter
  43. sifive_i2c_adapter_array[SIFIVE_I2C_ADAPTER_MAX];
  44. extern struct fdt_i2c_adapter fdt_i2c_adapter_sifive;
  45. static inline void sifive_i2c_setreg(struct sifive_i2c_adapter *adap,
  46. uint8_t reg, uint8_t value)
  47. {
  48. writel(value, (volatile char *)adap->addr + reg);
  49. }
  50. static inline uint8_t sifive_i2c_getreg(struct sifive_i2c_adapter *adap,
  51. uint8_t reg)
  52. {
  53. return readl((volatile char *)adap->addr + reg);
  54. }
  55. static int sifive_i2c_adapter_rxack(struct sifive_i2c_adapter *adap)
  56. {
  57. uint8_t val = sifive_i2c_getreg(adap, SIFIVE_I2C_SR);
  58. if (val & SIFIVE_I2C_STATUS_RXACK)
  59. return SBI_EIO;
  60. return 0;
  61. }
  62. static int sifive_i2c_adapter_poll(struct sifive_i2c_adapter *adap,
  63. uint32_t mask)
  64. {
  65. unsigned int timeout = 1; // [msec]
  66. int count = 0;
  67. uint8_t val;
  68. sbi_timer_udelay(80); // worst case if bus speed is 100 kHz
  69. do {
  70. val = sifive_i2c_getreg(adap, SIFIVE_I2C_SR);
  71. if (!(val & mask))
  72. return 0;
  73. sbi_timer_udelay(1);
  74. count += 1;
  75. if (count == (timeout * 1000))
  76. return SBI_ETIMEDOUT;
  77. } while (1);
  78. }
  79. #define sifive_i2c_adapter_poll_tip(adap) \
  80. sifive_i2c_adapter_poll(adap, SIFIVE_I2C_STATUS_TIP)
  81. #define sifive_i2c_adapter_poll_busy(adap) \
  82. sifive_i2c_adapter_poll(adap, SIFIVE_I2C_STATUS_BUSY)
  83. static int sifive_i2c_adapter_start(struct sifive_i2c_adapter *adap,
  84. uint8_t addr, uint8_t bit)
  85. {
  86. uint8_t val = (addr << 1) | bit;
  87. sifive_i2c_setreg(adap, SIFIVE_I2C_TXR, val);
  88. val = SIFIVE_I2C_CMD_STA | SIFIVE_I2C_CMD_WR | SIFIVE_I2C_CMD_IACK;
  89. sifive_i2c_setreg(adap, SIFIVE_I2C_CR, val);
  90. return sifive_i2c_adapter_poll_tip(adap);
  91. }
  92. static int sifive_i2c_adapter_write(struct i2c_adapter *ia, uint8_t addr,
  93. uint8_t reg, uint8_t *buffer, int len)
  94. {
  95. struct sifive_i2c_adapter *adap =
  96. container_of(ia, struct sifive_i2c_adapter, adapter);
  97. int rc = sifive_i2c_adapter_start(adap, addr, SIFIVE_I2C_WRITE_BIT);
  98. if (rc)
  99. return rc;
  100. rc = sifive_i2c_adapter_rxack(adap);
  101. if (rc)
  102. return rc;
  103. /* set register address */
  104. sifive_i2c_setreg(adap, SIFIVE_I2C_TXR, reg);
  105. sifive_i2c_setreg(adap, SIFIVE_I2C_CR, SIFIVE_I2C_CMD_WR |
  106. SIFIVE_I2C_CMD_IACK);
  107. rc = sifive_i2c_adapter_poll_tip(adap);
  108. if (rc)
  109. return rc;
  110. rc = sifive_i2c_adapter_rxack(adap);
  111. if (rc)
  112. return rc;
  113. /* set value */
  114. while (len) {
  115. sifive_i2c_setreg(adap, SIFIVE_I2C_TXR, *buffer);
  116. sifive_i2c_setreg(adap, SIFIVE_I2C_CR, SIFIVE_I2C_CMD_WR |
  117. SIFIVE_I2C_CMD_IACK);
  118. rc = sifive_i2c_adapter_poll_tip(adap);
  119. if (rc)
  120. return rc;
  121. rc = sifive_i2c_adapter_rxack(adap);
  122. if (rc)
  123. return rc;
  124. buffer++;
  125. len--;
  126. }
  127. sifive_i2c_setreg(adap, SIFIVE_I2C_CR, SIFIVE_I2C_CMD_STO |
  128. SIFIVE_I2C_CMD_IACK);
  129. /* poll BUSY instead of ACK*/
  130. rc = sifive_i2c_adapter_poll_busy(adap);
  131. if (rc)
  132. return rc;
  133. sifive_i2c_setreg(adap, SIFIVE_I2C_CR, SIFIVE_I2C_CMD_IACK);
  134. return 0;
  135. }
  136. static int sifive_i2c_adapter_read(struct i2c_adapter *ia, uint8_t addr,
  137. uint8_t reg, uint8_t *buffer, int len)
  138. {
  139. struct sifive_i2c_adapter *adap =
  140. container_of(ia, struct sifive_i2c_adapter, adapter);
  141. int rc;
  142. rc = sifive_i2c_adapter_start(adap, addr, SIFIVE_I2C_WRITE_BIT);
  143. if (rc)
  144. return rc;
  145. rc = sifive_i2c_adapter_rxack(adap);
  146. if (rc)
  147. return rc;
  148. sifive_i2c_setreg(adap, SIFIVE_I2C_TXR, reg);
  149. sifive_i2c_setreg(adap, SIFIVE_I2C_CR, SIFIVE_I2C_CMD_WR |
  150. SIFIVE_I2C_CMD_IACK);
  151. rc = sifive_i2c_adapter_poll_tip(adap);
  152. if (rc)
  153. return rc;
  154. rc = sifive_i2c_adapter_rxack(adap);
  155. if (rc)
  156. return rc;
  157. /* setting addr with high 0 bit */
  158. rc = sifive_i2c_adapter_start(adap, addr, SIFIVE_I2C_READ_BIT);
  159. if (rc)
  160. return rc;
  161. rc = sifive_i2c_adapter_rxack(adap);
  162. if (rc)
  163. return rc;
  164. while (len) {
  165. if (len == 1)
  166. sifive_i2c_setreg(adap, SIFIVE_I2C_CR,
  167. SIFIVE_I2C_CMD_ACK |
  168. SIFIVE_I2C_CMD_RD |
  169. SIFIVE_I2C_CMD_IACK);
  170. else
  171. sifive_i2c_setreg(adap, SIFIVE_I2C_CR,
  172. SIFIVE_I2C_CMD_RD |
  173. SIFIVE_I2C_CMD_IACK);
  174. rc = sifive_i2c_adapter_poll_tip(adap);
  175. if (rc)
  176. return rc;
  177. *buffer = sifive_i2c_getreg(adap, SIFIVE_I2C_RXR);
  178. buffer++;
  179. len--;
  180. }
  181. sifive_i2c_setreg(adap, SIFIVE_I2C_CR, SIFIVE_I2C_CMD_STO |
  182. SIFIVE_I2C_CMD_IACK);
  183. rc = sifive_i2c_adapter_poll_busy(adap);
  184. if (rc)
  185. return rc;
  186. sifive_i2c_setreg(adap, SIFIVE_I2C_CR, SIFIVE_I2C_CMD_IACK);
  187. return 0;
  188. }
  189. static int sifive_i2c_init(void *fdt, int nodeoff,
  190. const struct fdt_match *match)
  191. {
  192. int rc;
  193. struct sifive_i2c_adapter *adapter;
  194. uint64_t addr;
  195. if (sifive_i2c_adapter_count >= SIFIVE_I2C_ADAPTER_MAX)
  196. return SBI_ENOSPC;
  197. adapter = &sifive_i2c_adapter_array[sifive_i2c_adapter_count];
  198. rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
  199. if (rc)
  200. return rc;
  201. adapter->addr = addr;
  202. adapter->adapter.driver = &fdt_i2c_adapter_sifive;
  203. adapter->adapter.id = nodeoff;
  204. adapter->adapter.write = sifive_i2c_adapter_write;
  205. adapter->adapter.read = sifive_i2c_adapter_read;
  206. rc = i2c_adapter_add(&adapter->adapter);
  207. if (rc)
  208. return rc;
  209. sifive_i2c_adapter_count++;
  210. return 0;
  211. }
  212. static const struct fdt_match sifive_i2c_match[] = {
  213. { .compatible = "sifive,i2c0" },
  214. { },
  215. };
  216. struct fdt_i2c_adapter fdt_i2c_adapter_sifive = {
  217. .match_table = sifive_i2c_match,
  218. .init = sifive_i2c_init,
  219. };