drv_pwm.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024/02/19 flyingcys first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include "drv_pwm.h"
  13. #include "drv_pinmux.h"
  14. #define DBG_LEVEL DBG_LOG
  15. #include <rtdbg.h>
  16. #define LOG_TAG "DRV.PWM"
  17. struct cvi_pwm_dev
  18. {
  19. struct rt_device_pwm device;
  20. const char *name;
  21. rt_ubase_t reg_base;
  22. };
  23. static const uint64_t count_unit = 100000000; // 100M count per second
  24. static const uint64_t NSEC_COUNT = 1000000000; // ns
  25. static void cvi_pwm_set_config(rt_ubase_t reg_base, struct rt_pwm_configuration *cfg)
  26. {
  27. unsigned long long duty_clk, period_clk;
  28. cvi_pwm_set_polarity_high_ch(reg_base, (cfg->channel & PWM_MAX_CH));
  29. duty_clk = (cfg->pulse * count_unit) / NSEC_COUNT;
  30. cvi_pwm_set_high_period_ch(reg_base, (cfg->channel & PWM_MAX_CH), duty_clk);
  31. period_clk = (cfg->period * count_unit) / NSEC_COUNT;
  32. cvi_pwm_set_period_ch(reg_base, (cfg->channel & PWM_MAX_CH), period_clk);
  33. cvi_pwm_output_en_ch(reg_base, cfg->channel & PWM_MAX_CH);
  34. }
  35. static void cvi_pwm_get_config(rt_ubase_t reg_base, struct rt_pwm_configuration *cfg)
  36. {
  37. unsigned long long duty_clk, period_clk;
  38. duty_clk = cvi_pwm_get_high_period_ch(reg_base, (cfg->channel & PWM_MAX_CH));
  39. cfg->pulse = duty_clk * NSEC_COUNT / count_unit;
  40. period_clk = cvi_pwm_get_period_ch(reg_base, (cfg->channel & PWM_MAX_CH));
  41. cfg->period = period_clk * NSEC_COUNT / count_unit;
  42. }
  43. static rt_err_t _pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  44. {
  45. struct rt_pwm_configuration *cfg = (struct rt_pwm_configuration *)arg;
  46. struct cvi_pwm_dev *pwm_dev = (struct cvi_pwm_dev *)device->parent.user_data;
  47. unsigned long long duty_clk, period_clk;
  48. const uint64_t count_unit = 100000000; // 100M count per second
  49. const uint64_t NSEC_COUNT = 1000000000; // ns
  50. if (cfg->channel >= PWM_CHANNEL_NUM)
  51. return -RT_EINVAL;
  52. switch (cmd)
  53. {
  54. case PWM_CMD_ENABLE:
  55. cvi_pwm_start_en_ch(pwm_dev->reg_base, cfg->channel & PWM_MAX_CH);
  56. break;
  57. case PWM_CMD_DISABLE:
  58. cvi_pwm_start_dis_ch(pwm_dev->reg_base, cfg->channel & PWM_MAX_CH);
  59. break;
  60. case PWM_CMD_SET:
  61. cvi_pwm_set_config(pwm_dev->reg_base, cfg);
  62. break;
  63. case PWM_CMD_GET:
  64. cvi_pwm_get_config(pwm_dev->reg_base, cfg);
  65. break;
  66. case PWM_CMD_SET_PERIOD:
  67. period_clk = (cfg->period * count_unit) / NSEC_COUNT;
  68. cvi_pwm_set_period_ch(pwm_dev->reg_base, (cfg->channel & PWM_MAX_CH), period_clk);
  69. break;
  70. case PWM_CMD_SET_PULSE:
  71. duty_clk = (cfg->pulse * count_unit) / NSEC_COUNT;
  72. cvi_pwm_set_high_period_ch(pwm_dev->reg_base, (cfg->channel & PWM_MAX_CH), duty_clk);
  73. break;
  74. default:
  75. LOG_D("cmd: %x channel: %d period: %d pulse: %d", cmd, cfg->channel, cfg->period, cfg->pulse);
  76. break;
  77. }
  78. return RT_EOK;
  79. }
  80. const static struct rt_pwm_ops cvi_pwm_ops =
  81. {
  82. .control = &_pwm_control
  83. };
  84. static struct cvi_pwm_dev cvi_pwm[] =
  85. {
  86. #ifdef BSP_USING_PWM0
  87. {
  88. .name = "pwm0",
  89. .reg_base = CVI_PWM0_BASE,
  90. },
  91. #endif
  92. #ifdef BSP_USING_PWM1
  93. {
  94. .name = "pwm1",
  95. .reg_base = CVI_PWM1_BASE,
  96. },
  97. #endif
  98. #ifdef BSP_USING_PWM2
  99. {
  100. .name = "pwm2",
  101. .reg_base = CVI_PWM2_BASE,
  102. },
  103. #endif
  104. #ifdef BSP_USING_PWM3
  105. {
  106. .name = "pwm3",
  107. .reg_base = CVI_PWM3_BASE,
  108. },
  109. #endif
  110. };
  111. #if defined(BOARD_TYPE_MILKV_DUO) || defined(BOARD_TYPE_MILKV_DUO_SPINOR)
  112. #ifdef BSP_USING_PWM0
  113. static const char *pinname_whitelist_pwm0[] = {
  114. NULL,
  115. };
  116. static const char *pinname_whitelist_pwm1[] = {
  117. NULL,
  118. };
  119. static const char *pinname_whitelist_pwm2[] = {
  120. NULL,
  121. };
  122. static const char *pinname_whitelist_pwm3[] = {
  123. NULL,
  124. };
  125. #endif
  126. #ifdef BSP_USING_PWM1
  127. static const char *pinname_whitelist_pwm4[] = {
  128. "SD1_D3",
  129. "UART0_TX",
  130. NULL,
  131. };
  132. static const char *pinname_whitelist_pwm5[] = {
  133. "SD1_D2",
  134. "UART0_RX",
  135. NULL,
  136. };
  137. static const char *pinname_whitelist_pwm6[] = {
  138. "SD1_D1",
  139. NULL,
  140. };
  141. static const char *pinname_whitelist_pwm7[] = {
  142. "SD1_D0",
  143. NULL,
  144. };
  145. #endif
  146. #ifdef BSP_USING_PWM2
  147. static const char *pinname_whitelist_pwm8[] = {
  148. "SD1_CMD",
  149. NULL,
  150. };
  151. static const char *pinname_whitelist_pwm9[] = {
  152. "SD1_CLK",
  153. NULL,
  154. };
  155. static const char *pinname_whitelist_pwm10[] = {
  156. "SD1_GPIO1",
  157. NULL,
  158. };
  159. static const char *pinname_whitelist_pwm11[] = {
  160. "SD1_GPIO0",
  161. NULL,
  162. };
  163. #endif
  164. #ifdef BSP_USING_PWM3
  165. static const char *pinname_whitelist_pwm12[] = {
  166. NULL,
  167. };
  168. static const char *pinname_whitelist_pwm13[] = {
  169. NULL,
  170. };
  171. static const char *pinname_whitelist_pwm14[] = {
  172. NULL,
  173. };
  174. static const char *pinname_whitelist_pwm15[] = {
  175. NULL,
  176. };
  177. #endif
  178. #elif defined(BOARD_TYPE_MILKV_DUO256M) || defined(BOARD_TYPE_MILKV_DUO256M_SPINOR)
  179. #ifdef BSP_USING_PWM0
  180. static const char *pinname_whitelist_pwm0[] = {
  181. NULL,
  182. };
  183. static const char *pinname_whitelist_pwm1[] = {
  184. NULL,
  185. };
  186. static const char *pinname_whitelist_pwm2[] = {
  187. NULL,
  188. };
  189. static const char *pinname_whitelist_pwm3[] = {
  190. NULL,
  191. };
  192. #endif
  193. #ifdef BSP_USING_PWM1
  194. static const char *pinname_whitelist_pwm4[] = {
  195. "SD1_D3",
  196. "UART0_TX",
  197. NULL,
  198. };
  199. static const char *pinname_whitelist_pwm5[] = {
  200. "SD1_D2",
  201. "UART0_RX",
  202. NULL,
  203. };
  204. static const char *pinname_whitelist_pwm6[] = {
  205. "JTAG_CPU_TCK",
  206. "SD1_D1",
  207. NULL,
  208. };
  209. static const char *pinname_whitelist_pwm7[] = {
  210. "JTAG_CPU_TMS",
  211. "SD1_D0",
  212. NULL,
  213. };
  214. #endif
  215. #ifdef BSP_USING_PWM2
  216. static const char *pinname_whitelist_pwm8[] = {
  217. "SD1_CMD",
  218. NULL,
  219. };
  220. static const char *pinname_whitelist_pwm9[] = {
  221. "SD1_CLK",
  222. NULL,
  223. };
  224. static const char *pinname_whitelist_pwm10[] = {
  225. "PAD_MIPI_TXM1",
  226. NULL,
  227. };
  228. static const char *pinname_whitelist_pwm11[] = {
  229. "PAD_MIPI_TXP1",
  230. NULL,
  231. };
  232. #endif
  233. #ifdef BSP_USING_PWM3
  234. static const char *pinname_whitelist_pwm12[] = {
  235. NULL,
  236. };
  237. static const char *pinname_whitelist_pwm13[] = {
  238. NULL,
  239. };
  240. static const char *pinname_whitelist_pwm14[] = {
  241. NULL,
  242. };
  243. static const char *pinname_whitelist_pwm15[] = {
  244. NULL,
  245. };
  246. #endif
  247. #else
  248. #error "Unsupported board type!"
  249. #endif
  250. static void rt_hw_pwm_pinmux_config()
  251. {
  252. #ifdef BSP_USING_PWM0
  253. pinmux_config(BSP_PWM0_0_PINNAME, PWM_0, pinname_whitelist_pwm0);
  254. pinmux_config(BSP_PWM0_1_PINNAME, PWM_1, pinname_whitelist_pwm1);
  255. pinmux_config(BSP_PWM0_2_PINNAME, PWM_2, pinname_whitelist_pwm2);
  256. pinmux_config(BSP_PWM0_3_PINNAME, PWM_3, pinname_whitelist_pwm3);
  257. #endif /* BSP_USING_PWM0 */
  258. #ifdef BSP_USING_PWM1
  259. pinmux_config(BSP_PWM1_4_PINNAME, PWM_4, pinname_whitelist_pwm4);
  260. pinmux_config(BSP_PWM1_5_PINNAME, PWM_5, pinname_whitelist_pwm5);
  261. pinmux_config(BSP_PWM1_6_PINNAME, PWM_6, pinname_whitelist_pwm6);
  262. pinmux_config(BSP_PWM1_7_PINNAME, PWM_7, pinname_whitelist_pwm7);
  263. #endif /* BSP_USING_PWM1 */
  264. #ifdef BSP_USING_PWM2
  265. pinmux_config(BSP_PWM2_8_PINNAME, PWM_8, pinname_whitelist_pwm8);
  266. pinmux_config(BSP_PWM2_9_PINNAME, PWM_9, pinname_whitelist_pwm9);
  267. pinmux_config(BSP_PWM2_10_PINNAME, PWM_10, pinname_whitelist_pwm10);
  268. pinmux_config(BSP_PWM2_11_PINNAME, PWM_11, pinname_whitelist_pwm11);
  269. #endif /* BSP_USING_PWM2 */
  270. #ifdef BSP_USING_PWM3
  271. pinmux_config(BSP_PWM3_12_PINNAME, PWM_12, pinname_whitelist_pwm12);
  272. pinmux_config(BSP_PWM3_13_PINNAME, PWM_13, pinname_whitelist_pwm13);
  273. pinmux_config(BSP_PWM3_14_PINNAME, PWM_14, pinname_whitelist_pwm14);
  274. pinmux_config(BSP_PWM3_15_PINNAME, PWM_15, pinname_whitelist_pwm15);
  275. #endif /* BSP_USING_PWM3 */
  276. }
  277. int rt_hw_pwm_init(void)
  278. {
  279. int result = RT_EOK;
  280. uint8_t i;
  281. rt_hw_pwm_pinmux_config();
  282. for (i = 0; i < sizeof(cvi_pwm) / sizeof(cvi_pwm[0]); i++)
  283. {
  284. result = rt_device_pwm_register(&cvi_pwm[i].device, cvi_pwm[i].name, &cvi_pwm_ops, &cvi_pwm[i]);
  285. if (result != RT_EOK)
  286. {
  287. LOG_E("device %s register failed", cvi_pwm[i].name);
  288. return -RT_ERROR;
  289. }
  290. }
  291. return RT_EOK;
  292. }
  293. INIT_DEVICE_EXPORT(rt_hw_pwm_init);