drv_pwm.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * Copyright (c) 2020-2021, Bluetrum Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-01-28 greedyhao first version
  9. */
  10. #include <board.h>
  11. #ifdef RT_USING_PWM
  12. #include "pwm_config.h"
  13. //#define DRV_DEBUG
  14. #define LOG_TAG "drv.pwm"
  15. #include <drv_log.h>
  16. #define MAX_PERIOD 65535
  17. #define MIN_PERIOD 3
  18. #define MIN_PULSE 2
  19. void hal_pwm_mspinit(void);
  20. enum
  21. {
  22. #ifdef BSP_USING_T3_PWM
  23. T3_PWM_INDEX,
  24. #endif
  25. #ifdef BSP_USING_T4_PWM
  26. T4_PWM_INDEX,
  27. #endif
  28. #ifdef BSP_USING_T5_PWM
  29. T5_PWM_INDEX,
  30. #endif
  31. #ifdef BSP_USING_LPWM0
  32. LPWM0_INDEX,
  33. #endif
  34. #ifdef BSP_USING_LPWM1
  35. LPWM1_INDEX,
  36. #endif
  37. #ifdef BSP_USING_LPWM2
  38. LPWM2_INDEX,
  39. #endif
  40. #ifdef BSP_USING_LPWM3
  41. LPWM3_INDEX,
  42. #endif
  43. };
  44. struct ab32_pwm
  45. {
  46. struct rt_device_pwm pwm_device;
  47. hal_sfr_t pwm_handle;
  48. char *name;
  49. rt_uint8_t channel;
  50. rt_uint32_t period;
  51. rt_uint32_t pulse;
  52. };
  53. static struct ab32_pwm ab32_pwm_obj[] =
  54. {
  55. #ifdef BSP_USING_T3_PWM
  56. T3_PWM_CONFIG,
  57. #endif
  58. #ifdef BSP_USING_T4_PWM
  59. T4_PWM_CONFIG,
  60. #endif
  61. #ifdef BSP_USING_T5_PWM
  62. T5_PWM_CONFIG,
  63. #endif
  64. #ifdef BSP_USING_LPWM0
  65. LPWM0_CONFIG,
  66. #endif
  67. #ifdef BSP_USING_LPWM1
  68. LPWM1_CONFIG,
  69. #endif
  70. #ifdef BSP_USING_LPWM2
  71. LPWM2_CONFIG,
  72. #endif
  73. #ifdef BSP_USING_LPWM3
  74. LPWM3_CONFIG,
  75. #endif
  76. };
  77. static rt_err_t drv_pwm_enable(hal_sfr_t pwm, char *name, struct rt_pwm_configuration *configuration, rt_bool_t enable)
  78. {
  79. rt_uint8_t channel = configuration->channel;
  80. rt_uint8_t pwm_num = 0;
  81. if (!configuration->complementary) {
  82. if (name[0] == 'l') {
  83. pwm[PWMxCON] &= ~BIT(5);
  84. }
  85. } else {
  86. if (name[0] == 'l') {
  87. pwm[PWMxCON] |= BIT(5);
  88. } else {
  89. LOG_W("Timer no support complementary PWM output!");
  90. }
  91. }
  92. if (!enable) {
  93. if (name[0] == 'l') {
  94. pwm_num = name[4] - '0';
  95. pwm[PWMxCON] &= ~(1 << (pwm_num));
  96. } else {
  97. if (channel & 0x1) { /* pwm0 */
  98. pwm[TMRxCON] &= ~(1 << (9 + 0));
  99. }
  100. if (channel & 0x2) { /* pwm1 */
  101. pwm[TMRxCON] &= ~(1 << (9 + 1));
  102. }
  103. if (channel & 0x4) { /* pwm2 */
  104. pwm[TMRxCON] &= ~(1 << (9 + 2));
  105. }
  106. }
  107. } else {
  108. if (name[0] == 'l') {
  109. pwm_num = name[4] - '0';
  110. pwm[PWMxCON] |= 1 << (pwm_num);
  111. } else {
  112. if (channel & 0x1) { /* pwm0 */
  113. pwm[TMRxCON] |= (1 << (9 + 0));
  114. }
  115. if (channel & 0x2) { /* pwm1 */
  116. pwm[TMRxCON] |= (1 << (9 + 1));
  117. }
  118. if (channel & 0x4) { /* pwm2 */
  119. pwm[TMRxCON] |= (1 << (9 + 2));
  120. }
  121. }
  122. }
  123. return RT_EOK;
  124. }
  125. static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  126. {
  127. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  128. struct ab32_pwm *pwm_obj = (struct ab32_pwm *)device->parent.user_data;
  129. hal_sfr_t pwm = pwm_obj->pwm_handle;
  130. char *name = pwm_obj->name;
  131. rt_uint8_t channel = configuration->channel;
  132. rt_uint32_t period, pulse;
  133. rt_uint64_t tim_clock, psc;
  134. if (name[0] == 'l') {
  135. tim_clock = 6500; /* lpwm clock is 6.5MHz */
  136. } else {
  137. tim_clock = get_sysclk_nhz() / 1000ul;
  138. }
  139. switch (cmd)
  140. {
  141. case PWMN_CMD_ENABLE:
  142. configuration->complementary = RT_TRUE;
  143. case PWM_CMD_ENABLE:
  144. return drv_pwm_enable(pwm, name, configuration, RT_TRUE);
  145. case PWMN_CMD_DISABLE:
  146. configuration->complementary = RT_FALSE;
  147. case PWM_CMD_DISABLE:
  148. return drv_pwm_enable(pwm, name, configuration, RT_FALSE);
  149. case PWM_CMD_SET:
  150. pwm_obj->pulse = configuration->pulse;
  151. pwm_obj->period = configuration->period;
  152. period = pwm_obj->period * tim_clock / 1000000ul;
  153. psc = period / MAX_PERIOD + 1;
  154. period = period / psc;
  155. if (period < MIN_PERIOD)
  156. {
  157. period = MIN_PERIOD;
  158. }
  159. pulse = pwm_obj->pulse * tim_clock / psc / 1000000ul;
  160. if (pulse < MIN_PULSE)
  161. {
  162. pulse = MIN_PULSE;
  163. }
  164. else if (pulse > period)
  165. {
  166. pulse = period;
  167. }
  168. if (name[0] == 'l') {
  169. pwm[PWMxPR] = period - 1;
  170. switch (name[4] - '0')
  171. {
  172. case 0: /* lpwm0 */
  173. pwm[PWMxxDUT] = pulse - 1;
  174. break;
  175. case 1: /* lpwm1 */
  176. pwm[PWMxxDUT] = (pulse - 1) << 16;
  177. break;
  178. case 2: /* lpwm2 */
  179. pwm[PWMyyDUT] = pulse - 1;
  180. break;
  181. case 3: /* lpwm3 */
  182. pwm[PWMyyDUT] = (pulse - 1) << 16;
  183. break;
  184. default:
  185. break;
  186. }
  187. } else {
  188. pwm[TMRxPR] = period - 1;
  189. if (channel & 0x1) { /* pwm0 */
  190. pwm[TMRxDUTY0] = pulse - 1;
  191. }
  192. if (channel & 0x2) { /* pwm1 */
  193. pwm[TMRxDUTY1] = pulse - 1;
  194. }
  195. if (channel & 0x4) { /* pwm2 */
  196. pwm[TMRxDUTY2] = pulse - 1;
  197. }
  198. }
  199. return RT_EOK;
  200. case PWM_CMD_GET:
  201. configuration->pulse = pwm_obj->pulse;
  202. configuration->period = pwm_obj->period;
  203. return RT_EOK;
  204. default:
  205. return -RT_EINVAL;
  206. }
  207. }
  208. static rt_err_t ab32_hw_pwm_init(struct ab32_pwm *device)
  209. {
  210. rt_err_t result = RT_EOK;
  211. hal_sfr_t pwm = RT_NULL;
  212. char *name = RT_NULL;
  213. RT_ASSERT(device != RT_NULL);
  214. pwm = (hal_sfr_t)device->pwm_handle;
  215. name = device->name;
  216. if (name[0] == 'l') {
  217. pwm[PWMxCON] = 0;
  218. } else {
  219. pwm[TMRxCON] &= ~(7 << 9);
  220. }
  221. return result;
  222. }
  223. static void pwm_get_channel(void)
  224. {
  225. #ifdef BSP_USING_T3_PWM0
  226. ab32_pwm_obj[T3_PWM_INDEX].channel |= 1 << 0;
  227. #endif
  228. #ifdef BSP_USING_T3_PWM1
  229. ab32_pwm_obj[T3_PWM_INDEX].channel |= 1 << 1;
  230. #endif
  231. #ifdef BSP_USING_T3_PWM2
  232. ab32_pwm_obj[T3_PWM_INDEX].channel |= 1 << 2;
  233. #endif
  234. #ifdef BSP_USING_T4_PWM0
  235. ab32_pwm_obj[T4_PWM_INDEX].channel |= 1 << 0;
  236. #endif
  237. #ifdef BSP_USING_T4_PWM1
  238. ab32_pwm_obj[T4_PWM_INDEX].channel |= 1 << 1;
  239. #endif
  240. #ifdef BSP_USING_T4_PWM2
  241. ab32_pwm_obj[T4_PWM_INDEX].channel |= 1 << 2;
  242. #endif
  243. #ifdef BSP_USING_T5_PWM0
  244. ab32_pwm_obj[T5_PWM_INDEX].channel |= 1 << 0;
  245. #endif
  246. #ifdef BSP_USING_T5_PWM1
  247. ab32_pwm_obj[T5_PWM_INDEX].channel |= 1 << 1;
  248. #endif
  249. #ifdef BSP_USING_T5_PWM2
  250. ab32_pwm_obj[T5_PWM_INDEX].channel |= 1 << 2;
  251. #endif
  252. #ifdef BSP_USING_LPWM0
  253. ab32_pwm_obj[LPWM0_INDEX].channel |= 1 << 0;
  254. #endif
  255. #ifdef BSP_USING_LPWM1
  256. ab32_pwm_obj[LPWM1_INDEX].channel |= 1 << 0;
  257. #endif
  258. #ifdef BSP_USING_LPWM2
  259. ab32_pwm_obj[LPWM2_INDEX].channel |= 1 << 0;
  260. #endif
  261. #ifdef BSP_USING_LPWM3
  262. ab32_pwm_obj[LPWM3_INDEX].channel |= 1 << 0;
  263. #endif
  264. }
  265. static struct rt_pwm_ops drv_ops =
  266. {
  267. drv_pwm_control
  268. };
  269. static int ab32_pwm_init(void)
  270. {
  271. int i = 0;
  272. int result = RT_EOK;
  273. pwm_get_channel();
  274. hal_pwm_mspinit();
  275. for (i = 0; i < sizeof(ab32_pwm_obj) / sizeof(ab32_pwm_obj[0]); i++)
  276. {
  277. /* pwm init */
  278. if (ab32_hw_pwm_init(&ab32_pwm_obj[i]) != RT_EOK)
  279. {
  280. LOG_E("%s init failed", ab32_pwm_obj[i].name);
  281. result = -RT_ERROR;
  282. goto __exit;
  283. }
  284. else
  285. {
  286. LOG_D("%s init success", ab32_pwm_obj[i].name);
  287. /* register pwm device */
  288. if (rt_device_pwm_register(&ab32_pwm_obj[i].pwm_device, ab32_pwm_obj[i].name, &drv_ops, (void *)&ab32_pwm_obj[i]) == RT_EOK)
  289. {
  290. LOG_D("%s register success", ab32_pwm_obj[i].name);
  291. }
  292. else
  293. {
  294. LOG_E("%s register failed", ab32_pwm_obj[i].name);
  295. result = -RT_ERROR;
  296. }
  297. }
  298. }
  299. __exit:
  300. return result;
  301. }
  302. INIT_DEVICE_EXPORT(ab32_pwm_init);
  303. #endif /* RT_USING_PWM */