drv_soft_i2c.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Copyright (c) 2006-2019, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2019-03-22 balanceTWK first version
  9. */
  10. #include <board.h>
  11. #include "drv_soft_i2c.h"
  12. #include "wm_regs.h"
  13. #include "wm_gpio.h"
  14. #include "pin_map.h"
  15. #define DBG_SECTION_NAME "soft_i2c"
  16. #define DBG_COLOR
  17. #define DBG_LEVEL DBG_LOG
  18. #include <rtdbg.h>
  19. #ifdef BSP_USING_SOFT_I2C
  20. #if !defined(BSP_USING_SOFT_I2C1) && !defined(BSP_USING_SOFT_I2C2) && !defined(BSP_USING_SOFT_I2C3)
  21. #error "Please define at least one BSP_USING_SOFT_I2Cx"
  22. #endif
  23. static const struct w60x_soft_i2c_config soft_i2c_config[] =
  24. {
  25. #ifdef BSP_USING_SOFT_I2C1
  26. I2C1_BUS_CONFIG,
  27. #endif
  28. #ifdef BSP_USING_SOFT_I2C2
  29. I2C2_BUS_CONFIG,
  30. #endif
  31. #ifdef BSP_USING_SOFT_I2C3
  32. I2C3_BUS_CONFIG,
  33. #endif
  34. };
  35. static struct w60x_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
  36. /**
  37. * This function initializes the i2c pin.
  38. *
  39. * @param w60x i2c dirver class.
  40. */
  41. static void w60x_i2c_gpio_init(struct w60x_i2c *i2c)
  42. {
  43. struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)i2c->ops.data;
  44. rt_int16_t scl,sda;
  45. scl = wm_get_pin(cfg->scl);
  46. sda = wm_get_pin(cfg->sda);
  47. tls_gpio_cfg((enum tls_io_name)scl, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
  48. tls_gpio_cfg((enum tls_io_name)sda, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
  49. tls_gpio_write((enum tls_io_name)scl, 1);
  50. tls_gpio_write((enum tls_io_name)sda, 1);
  51. }
  52. /**
  53. * This function sets the sda pin.
  54. *
  55. * @param w60x config class.
  56. * @param The sda pin state.
  57. */
  58. static void w60x_set_sda(void *data, rt_int32_t state)
  59. {
  60. struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
  61. rt_int16_t sda;
  62. sda = wm_get_pin(cfg->sda);
  63. if (state)
  64. {
  65. tls_gpio_cfg((enum tls_io_name)sda, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_PULLHIGH);
  66. }
  67. else
  68. {
  69. tls_gpio_cfg((enum tls_io_name)sda, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING);
  70. tls_gpio_write((enum tls_io_name)sda, 0);
  71. }
  72. }
  73. /**
  74. * This function sets the scl pin.
  75. *
  76. * @param w60x config class.
  77. * @param The scl pin state.
  78. */
  79. static void w60x_set_scl(void *data, rt_int32_t state)
  80. {
  81. struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
  82. rt_int16_t scl;
  83. scl = wm_get_pin(cfg->scl);
  84. if (state)
  85. {
  86. tls_gpio_cfg((enum tls_io_name)scl, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_PULLHIGH);
  87. }
  88. else
  89. {
  90. tls_gpio_cfg((enum tls_io_name)scl, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING);
  91. tls_gpio_write((enum tls_io_name)scl, 0);
  92. }
  93. }
  94. /**
  95. * This function gets the sda pin state.
  96. *
  97. * @param The sda pin state.
  98. */
  99. static rt_int32_t w60x_get_sda(void *data)
  100. {
  101. struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
  102. rt_int16_t sda;
  103. sda = wm_get_pin(cfg->sda);
  104. return tls_gpio_read((enum tls_io_name)sda);
  105. }
  106. /**
  107. * This function gets the scl pin state.
  108. *
  109. * @param The scl pin state.
  110. */
  111. static rt_int32_t w60x_get_scl(void *data)
  112. {
  113. struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
  114. rt_int16_t scl;
  115. scl = wm_get_pin(cfg->scl);
  116. return tls_gpio_read((enum tls_io_name)scl);
  117. }
  118. /**
  119. * The time delay function.
  120. *
  121. * @param microseconds.
  122. */
  123. static void w60x_udelay(rt_uint32_t us)
  124. {
  125. rt_uint32_t ticks;
  126. rt_uint32_t told, tnow, tcnt = 0;
  127. rt_uint32_t reload = SysTick->LOAD;
  128. ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
  129. told = SysTick->VAL;
  130. while (1)
  131. {
  132. tnow = SysTick->VAL;
  133. if (tnow != told)
  134. {
  135. if (tnow < told)
  136. {
  137. tcnt += told - tnow;
  138. }
  139. else
  140. {
  141. tcnt += reload - tnow + told;
  142. }
  143. told = tnow;
  144. if (tcnt >= ticks)
  145. {
  146. break;
  147. }
  148. }
  149. }
  150. }
  151. static const struct rt_i2c_bit_ops w60x_bit_ops_default =
  152. {
  153. .data = RT_NULL,
  154. .set_sda = w60x_set_sda,
  155. .set_scl = w60x_set_scl,
  156. .get_sda = w60x_get_sda,
  157. .get_scl = w60x_get_scl,
  158. .udelay = w60x_udelay,
  159. .delay_us = 1,
  160. .timeout = 100
  161. };
  162. /**
  163. * if i2c is locked, this function will unlock it
  164. *
  165. * @param w60x config class
  166. *
  167. * @return RT_EOK indicates successful unlock.
  168. */
  169. static rt_err_t w60x_i2c_bus_unlock(const struct w60x_soft_i2c_config *cfg)
  170. {
  171. rt_int32_t i = 0;
  172. if (PIN_LOW == rt_pin_read(cfg->sda))
  173. {
  174. while (i++ < 9)
  175. {
  176. rt_pin_write(cfg->scl, PIN_HIGH);
  177. w60x_udelay(100);
  178. rt_pin_write(cfg->scl, PIN_LOW);
  179. w60x_udelay(100);
  180. }
  181. }
  182. if (PIN_LOW == rt_pin_read(cfg->sda))
  183. {
  184. return -RT_ERROR;
  185. }
  186. return RT_EOK;
  187. }
  188. /* I2C initialization function */
  189. int rt_soft_i2c_init(void)
  190. {
  191. rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct w60x_i2c);
  192. rt_err_t result;
  193. for (int i = 0; i < obj_num; i++)
  194. {
  195. i2c_obj[i].ops = w60x_bit_ops_default;
  196. i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
  197. i2c_obj[i].i2c2_bus.priv = &i2c_obj[i].ops;
  198. w60x_i2c_gpio_init(&i2c_obj[i]);
  199. result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c2_bus, soft_i2c_config[i].bus_name);
  200. RT_ASSERT(result == RT_EOK);
  201. w60x_i2c_bus_unlock(&soft_i2c_config[i]);
  202. LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
  203. soft_i2c_config[i].bus_name,
  204. soft_i2c_config[i].scl,
  205. soft_i2c_config[i].sda);
  206. }
  207. return RT_EOK;
  208. }
  209. INIT_DEVICE_EXPORT(rt_soft_i2c_init);
  210. #endif /* BSP_USING_SOFT_I2C */