drv_pwm.c 8.1 KB

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