drv_ui2c.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2020-6-31 Hphuang First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_UI2C) && defined(RT_USING_I2C)
  14. #include <rtdevice.h>
  15. #include "NuMicro.h"
  16. /* Private define ---------------------------------------------------------------*/
  17. #define LOG_TAG "drv.ui2c"
  18. #define DBG_ENABLE
  19. #define DBG_SECTION_NAME LOG_TAG
  20. #define DBG_LEVEL DBG_INFO
  21. #define DBG_COLOR
  22. #include <rtdbg.h>
  23. #define SLV_10BIT_ADDR (0x1E<<2) //1111+0xx+r/w
  24. enum
  25. {
  26. UI2C_START = -1,
  27. #if defined(BSP_USING_UI2C0)
  28. UI2C0_IDX,
  29. #endif
  30. UI2C_CNT
  31. };
  32. /* Private typedef --------------------------------------------------------------*/
  33. struct nu_ui2c_bus
  34. {
  35. struct rt_i2c_bus_device parent;
  36. UI2C_T *UI2C;
  37. struct rt_i2c_msg *msg;
  38. char *device_name;
  39. };
  40. typedef struct nu_ui2c_bus *nu_ui2c_bus_t;
  41. /* Private variables ------------------------------------------------------------*/
  42. static struct nu_ui2c_bus nu_ui2c_arr [ ] =
  43. {
  44. #if defined(BSP_USING_UI2C0)
  45. {
  46. .UI2C = UI2C0, .device_name = "ui2c0",
  47. },
  48. #endif
  49. };
  50. /* Private functions ------------------------------------------------------------*/
  51. static rt_ssize_t nu_ui2c_mst_xfer(struct rt_i2c_bus_device *bus,
  52. struct rt_i2c_msg msgs[],
  53. rt_uint32_t num);
  54. static rt_err_t nu_ui2c_bus_control(struct rt_i2c_bus_device *bus,
  55. int cmd,
  56. void *args);
  57. static const struct rt_i2c_bus_device_ops nu_ui2c_ops =
  58. {
  59. .master_xfer = nu_ui2c_mst_xfer,
  60. .slave_xfer = NULL,
  61. .i2c_bus_control = nu_ui2c_bus_control,
  62. };
  63. static rt_err_t nu_ui2c_bus_control(struct rt_i2c_bus_device *bus, int cmd, void *args)
  64. {
  65. nu_ui2c_bus_t nu_ui2c;
  66. RT_ASSERT(bus);
  67. nu_ui2c = (nu_ui2c_bus_t) bus;
  68. switch (cmd)
  69. {
  70. case RT_I2C_DEV_CTRL_CLK:
  71. UI2C_SetBusClockFreq(nu_ui2c->UI2C, *(rt_uint32_t *)args);
  72. break;
  73. default:
  74. return -RT_EIO;
  75. }
  76. return RT_EOK;
  77. }
  78. static inline rt_err_t nu_ui2c_wait_ready_with_timeout(nu_ui2c_bus_t nu_ui2c)
  79. {
  80. rt_tick_t start = rt_tick_get();
  81. while (!(UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & (UI2C_PROTSTS_STARIF_Msk | UI2C_PROTSTS_ACKIF_Msk | UI2C_PROTSTS_NACKIF_Msk | UI2C_PROTSTS_STORIF_Msk)))
  82. {
  83. if ((rt_tick_get() - start) > nu_ui2c->parent.timeout)
  84. {
  85. LOG_E("\nui2c: timeout!\n");
  86. return -RT_ETIMEOUT;
  87. }
  88. }
  89. return RT_EOK;
  90. }
  91. static inline rt_err_t nu_ui2c_send_data(nu_ui2c_bus_t nu_ui2c, rt_uint8_t data)
  92. {
  93. UI2C_SET_DATA(nu_ui2c->UI2C, data);
  94. UI2C_SET_CONTROL_REG(nu_ui2c->UI2C, UI2C_CTL_PTRG);
  95. return nu_ui2c_wait_ready_with_timeout(nu_ui2c);
  96. }
  97. static rt_err_t nu_ui2c_send_address(nu_ui2c_bus_t nu_ui2c,
  98. struct rt_i2c_msg *msg)
  99. {
  100. rt_uint16_t flags = msg->flags;
  101. rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
  102. rt_uint8_t addr1, addr2;
  103. rt_err_t ret;
  104. if (flags & RT_I2C_ADDR_10BIT)
  105. {
  106. UI2C_ENABLE_10BIT_ADDR_MODE(nu_ui2c->UI2C);
  107. /* Init Send 10-bit Addr */
  108. addr1 = ((msg->addr >> 8) | SLV_10BIT_ADDR) << 1;
  109. addr2 = msg->addr & 0xff;
  110. LOG_D("addr1: %d, addr2: %d\n", addr1, addr2);
  111. ret = nu_ui2c_send_data(nu_ui2c, addr1);
  112. if (ret != RT_EOK) //for timeout condition
  113. return -RT_EIO;
  114. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_ACKIF_Msk) != UI2C_PROTSTS_ACKIF_Msk) && !ignore_nack)
  115. {
  116. LOG_E("NACK: sending first addr\n");
  117. return -RT_EIO;
  118. }
  119. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_ACKIF_Msk);
  120. ret = nu_ui2c_send_data(nu_ui2c, addr2);
  121. if (ret != RT_EOK) //for timeout condition
  122. return -RT_EIO;
  123. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_ACKIF_Msk) != UI2C_PROTSTS_ACKIF_Msk) && !ignore_nack)
  124. {
  125. LOG_E("NACK: sending second addr\n");
  126. return -RT_EIO;
  127. }
  128. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_ACKIF_Msk);
  129. if (flags & RT_I2C_RD)
  130. {
  131. LOG_D("send repeated start condition\n");
  132. UI2C_SET_CONTROL_REG(nu_ui2c->UI2C, (UI2C_CTL_PTRG | UI2C_CTL_STA));
  133. ret = nu_ui2c_wait_ready_with_timeout(nu_ui2c);
  134. if (ret != RT_EOK) //for timeout condition
  135. return -RT_EIO;
  136. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_STARIF_Msk) != UI2C_PROTSTS_STARIF_Msk) && !ignore_nack)
  137. {
  138. LOG_E("sending repeated START fail\n");
  139. return -RT_EIO;
  140. }
  141. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_STARIF_Msk);
  142. addr1 |= RT_I2C_RD;
  143. ret = nu_ui2c_send_data(nu_ui2c, addr1);
  144. if (ret != RT_EOK) //for timeout condition
  145. return -RT_EIO;
  146. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_ACKIF_Msk) != UI2C_PROTSTS_ACKIF_Msk) && !ignore_nack)
  147. {
  148. LOG_E("NACK: sending repeated addr\n");
  149. return -RT_EIO;
  150. }
  151. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_ACKIF_Msk);
  152. }
  153. }
  154. else
  155. {
  156. /* 7-bit addr */
  157. addr1 = msg->addr << 1;
  158. if (flags & RT_I2C_RD)
  159. addr1 |= RT_I2C_RD;
  160. /* Send device address */
  161. ret = nu_ui2c_send_data(nu_ui2c, addr1); /* Send Address */
  162. if (ret != RT_EOK) //for timeout condition
  163. return -RT_EIO;
  164. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_ACKIF_Msk) != UI2C_PROTSTS_ACKIF_Msk)
  165. && !ignore_nack)
  166. {
  167. LOG_E("sending addr fail\n");
  168. return -RT_EIO;
  169. }
  170. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_ACKIF_Msk);
  171. }
  172. return RT_EOK;
  173. }
  174. static rt_ssize_t nu_ui2c_mst_xfer(struct rt_i2c_bus_device *bus,
  175. struct rt_i2c_msg msgs[],
  176. rt_uint32_t num)
  177. {
  178. struct rt_i2c_msg *msg;
  179. nu_ui2c_bus_t nu_ui2c;
  180. rt_size_t i;
  181. rt_uint32_t cnt_data;
  182. rt_uint16_t ignore_nack;
  183. rt_err_t ret;
  184. RT_ASSERT(bus != RT_NULL);
  185. nu_ui2c = (nu_ui2c_bus_t) bus;
  186. nu_ui2c->msg = msgs;
  187. (nu_ui2c->UI2C)->PROTSTS = (nu_ui2c->UI2C)->PROTSTS;//Clear status
  188. UI2C_SET_CONTROL_REG(nu_ui2c->UI2C, UI2C_CTL_STA);
  189. ret = nu_ui2c_wait_ready_with_timeout(nu_ui2c);
  190. if (ret != RT_EOK) //for timeout condition
  191. {
  192. rt_set_errno(-RT_ETIMEOUT);
  193. return 0;
  194. }
  195. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_STARIF_Msk) != UI2C_PROTSTS_STARIF_Msk)) /* Check Send START */
  196. {
  197. i = 0;
  198. LOG_E("Send START Fail");
  199. return i;
  200. }
  201. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_STARIF_Msk);
  202. for (i = 0; i < num; i++)
  203. {
  204. msg = &msgs[i];
  205. ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
  206. if (!(msg->flags & RT_I2C_NO_START))
  207. {
  208. if (i)
  209. {
  210. UI2C_SET_CONTROL_REG(nu_ui2c->UI2C, (UI2C_CTL_PTRG | UI2C_CTL_STA));/* Send repeat START */
  211. ret = nu_ui2c_wait_ready_with_timeout(nu_ui2c);
  212. if (ret != RT_EOK) //for timeout condition
  213. break;
  214. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_STARIF_Msk) != UI2C_PROTSTS_STARIF_Msk)) /* Check Send repeat START */
  215. {
  216. i = 0;
  217. LOG_E("Send repeat START Fail");
  218. break;
  219. }
  220. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_STARIF_Msk);
  221. }
  222. if ((RT_EOK != nu_ui2c_send_address(nu_ui2c, msg))
  223. && !ignore_nack)
  224. {
  225. i = 0;
  226. LOG_E("Send Address Fail");
  227. break;
  228. }
  229. }
  230. if (nu_ui2c->msg[i].flags & RT_I2C_RD) /* Receive Bytes */
  231. {
  232. rt_uint32_t do_rd_nack = (i == (num - 1));
  233. for (cnt_data = 0 ; cnt_data < (nu_ui2c->msg[i].len) ; cnt_data++)
  234. {
  235. do_rd_nack += (cnt_data == (nu_ui2c->msg[i].len - 1)); /* NACK after last byte for hardware setting */
  236. if (do_rd_nack == 2)
  237. {
  238. UI2C_SET_CONTROL_REG(nu_ui2c->UI2C, UI2C_CTL_PTRG);
  239. }
  240. else
  241. {
  242. UI2C_SET_CONTROL_REG(nu_ui2c->UI2C, (UI2C_CTL_PTRG | UI2C_CTL_AA));
  243. }
  244. ret = nu_ui2c_wait_ready_with_timeout(nu_ui2c);
  245. if (ret != RT_EOK) //for timeout condition
  246. break;
  247. if (nu_ui2c->UI2C->PROTCTL & UI2C_CTL_AA)
  248. {
  249. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_ACKIF_Msk) != UI2C_PROTSTS_ACKIF_Msk)) /*Master Receive Data ACK*/
  250. {
  251. i = 0;
  252. break;
  253. }
  254. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_ACKIF_Msk);
  255. }
  256. else
  257. {
  258. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_NACKIF_Msk) != UI2C_PROTSTS_NACKIF_Msk)) /*Master Receive Data NACK*/
  259. {
  260. i = 0;
  261. break;
  262. }
  263. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_NACKIF_Msk);
  264. }
  265. nu_ui2c->msg[i].buf[cnt_data] = nu_ui2c->UI2C->RXDAT;
  266. }
  267. }
  268. else /* Send Bytes */
  269. {
  270. for (cnt_data = 0 ; cnt_data < (nu_ui2c->msg[i].len) ; cnt_data++)
  271. {
  272. /* Send register number and MSB of data */
  273. ret = nu_ui2c_send_data(nu_ui2c, (uint8_t)(nu_ui2c->msg[i].buf[cnt_data]));
  274. if (ret != RT_EOK) //for timeout condition
  275. break;
  276. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_ACKIF_Msk) != UI2C_PROTSTS_ACKIF_Msk)
  277. && !ignore_nack
  278. ) /* Send data and get Ack */
  279. {
  280. i = 0;
  281. break;
  282. }
  283. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_ACKIF_Msk);
  284. }
  285. }
  286. }
  287. UI2C_SET_CONTROL_REG(nu_ui2c->UI2C, (UI2C_CTL_PTRG | UI2C_CTL_STO)); /* Send STOP signal */
  288. ret = nu_ui2c_wait_ready_with_timeout(nu_ui2c);
  289. if (ret != RT_EOK) //for timeout condition
  290. {
  291. rt_set_errno(-RT_ETIMEOUT);
  292. return 0;
  293. }
  294. RT_ASSERT(((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_STORIF_Msk) == UI2C_PROTSTS_STORIF_Msk));
  295. if (((UI2C_GET_PROT_STATUS(nu_ui2c->UI2C) & UI2C_PROTSTS_STORIF_Msk) != UI2C_PROTSTS_STORIF_Msk)) /* Bus Free*/
  296. {
  297. i = 0;
  298. LOG_E("Send STOP Fail");
  299. }
  300. UI2C_CLR_PROT_INT_FLAG(nu_ui2c->UI2C, UI2C_PROTSTS_STORIF_Msk);
  301. UI2C_SET_CONTROL_REG(nu_ui2c->UI2C, UI2C_CTL_PTRG);
  302. UI2C_DISABLE_10BIT_ADDR_MODE(nu_ui2c->UI2C); /*clear all sub modes like 10 bit mode*/
  303. nu_ui2c->msg = RT_NULL;
  304. return i;
  305. }
  306. /* Public functions -------------------------------------------------------------*/
  307. int rt_hw_ui2c_init(void)
  308. {
  309. int i;
  310. rt_err_t ret = RT_EOK;
  311. for (i = (UI2C_START + 1); i < UI2C_CNT; i++)
  312. {
  313. /* Reset and initial IP engine. */
  314. UI2C_Close(nu_ui2c_arr[i].UI2C);
  315. UI2C_Open(nu_ui2c_arr[i].UI2C, 100000);
  316. nu_ui2c_arr[i].parent.ops = &nu_ui2c_ops;
  317. ret = rt_i2c_bus_device_register(&nu_ui2c_arr[i].parent, nu_ui2c_arr[i].device_name);
  318. RT_ASSERT(RT_EOK == ret);
  319. }
  320. return 0;
  321. }
  322. INIT_DEVICE_EXPORT(rt_hw_ui2c_init);
  323. #endif //#if defined(BSP_USING_UI2C)