drv_pwm.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2019-04-28 tyustli first version
  9. *
  10. */
  11. #include <rtthread.h>
  12. #ifdef RT_USING_PWM
  13. #define LOG_TAG "drv.pwm"
  14. #include <drv_log.h>
  15. #include <rtdevice.h>
  16. #include <ioremap.h>
  17. #include "fsl_pwm.h"
  18. #include "drv_pwm.h"
  19. #include <drv_common.h>
  20. #include <drivers/rt_drv_pwm.h>
  21. #define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk)
  22. /* PWMPR register value of 0xffff has the same effect as 0xfffe */
  23. #define IMX_PWMPR_MAX 0xfffe
  24. #define NSEC_PER_MSEC 1000000
  25. #define NSEC_PER_SEC 1000
  26. #define MX3_PWMCR_SWR BIT(3)
  27. #define MX3_PWM_SWR_LOOP 5
  28. #define MX3_PWMSR_FIFOAV_EMPTY 0
  29. #define MX3_PWMSR_FIFOAV_1WORD 1
  30. #define MX3_PWMSR_FIFOAV_2WORDS 2
  31. #define MX3_PWMSR_FIFOAV_3WORDS 3
  32. #define MX3_PWMSR_FIFOAV_4WORDS 4
  33. #define MX3_PWMCR_STOPEN BIT(25)
  34. #define MX3_PWMCR_DOZEN BIT(24)
  35. #define MX3_PWMCR_WAITEN BIT(23)
  36. #define MX3_PWMCR_DBGEN BIT(22)
  37. #define MX3_PWMCR_BCTR BIT(21)
  38. #define MX3_PWMCR_HCTR BIT(20)
  39. #define MX3_PWMCR_CLKSRC BIT(17)
  40. #define MX3_PWMCR_EN BIT(0)
  41. static rt_err_t imx6ull_drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg);
  42. static struct rt_pwm_ops imxrt_drv_ops =
  43. {
  44. .control = imx6ull_drv_pwm_control
  45. };
  46. static void imx6ull_pwm_reset(PWM_Type *base)
  47. {
  48. int wait_count = 0;
  49. uint32_t cr = 0;
  50. base->PWMCR = MX3_PWMCR_SWR;
  51. do {
  52. rt_thread_mdelay(1);
  53. cr = base->PWMCR;
  54. } while ((cr & MX3_PWMCR_SWR) &&
  55. (wait_count++ < MX3_PWM_SWR_LOOP));
  56. if (cr & MX3_PWMCR_SWR)
  57. {
  58. LOG_E("software reset timeout\n");
  59. }
  60. }
  61. static void imx6ull_pwm_wait_fifo_slot(PWM_Type *base, struct rt_pwm_configuration *configuration)
  62. {
  63. unsigned int period_ms = 0;
  64. int fifoav = 0;
  65. uint32_t sr = 0;
  66. sr = base->PWMSR;
  67. fifoav = sr & 0x7;
  68. if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
  69. period_ms = configuration->period / NSEC_PER_MSEC;
  70. rt_thread_mdelay(period_ms);
  71. sr = base->PWMSR;
  72. if (fifoav == (sr & 0x7))
  73. {
  74. LOG_E("there is no free FIFO slot\n");
  75. }
  76. }
  77. }
  78. static rt_err_t imx6ull_pwm_enable(struct rt_device_pwm *device, rt_bool_t enable)
  79. {
  80. PWM_Type *base = (PWM_Type *)device->parent.user_data;
  81. if (!enable)
  82. {
  83. pwm_stop_timer(base);
  84. }
  85. else
  86. {
  87. pwm_start_timer(base);
  88. }
  89. return RT_EOK;
  90. }
  91. static rt_err_t imx6ull_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
  92. {
  93. uint32_t period = 0, prescaler = 0, val = 0;
  94. uint64_t tmp = 0;
  95. PWM_Type *base = (PWM_Type *)device->parent.user_data;
  96. uint32_t pwm_src_clk;
  97. pwm_src_clk = PWM_SRC_CLK_FREQ / 1000000;
  98. val = base->PWMCR;
  99. prescaler = ((val >> 4) & 0xfff)+1;
  100. val = base->PWMPR;
  101. period = val >= IMX_PWMPR_MAX ? IMX_PWMPR_MAX : val;
  102. tmp = NSEC_PER_SEC * (uint64_t)(period + 2) * prescaler;
  103. configuration->period = (tmp) / pwm_src_clk;
  104. val = base->PWMSAR;
  105. tmp = NSEC_PER_SEC * (uint64_t)(val) * prescaler;
  106. configuration->pulse = (tmp) / pwm_src_clk;
  107. return RT_EOK;
  108. }
  109. static rt_err_t imx6ull_pwm_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
  110. {
  111. RT_ASSERT(configuration->period > 0);
  112. RT_ASSERT(configuration->pulse <= configuration->period);
  113. PWM_Type *base = (PWM_Type *)device->parent.user_data;
  114. uint32_t period_cycles = 0, duty_cycles = 0, prescale = 0;
  115. uint32_t cr = 0;
  116. uint32_t pwm_src_clk = 0;
  117. pwm_src_clk = PWM_SRC_CLK_FREQ / 1000000;
  118. period_cycles = pwm_src_clk * configuration->period / NSEC_PER_SEC;
  119. prescale = period_cycles / 0x10000 + 1;
  120. period_cycles /= prescale;
  121. duty_cycles = configuration->pulse * pwm_src_clk / NSEC_PER_SEC ;
  122. duty_cycles /= prescale;
  123. /*
  124. * according to imx pwm RM, the real period value should be PERIOD
  125. * value in PWMPR plus 2.
  126. */
  127. if (period_cycles > 2)
  128. {
  129. period_cycles -= 2;
  130. }
  131. else
  132. {
  133. period_cycles = 0;
  134. }
  135. if (((base->PWMCR) & 0x1) == 1)
  136. {
  137. imx6ull_pwm_wait_fifo_slot(base, configuration);
  138. }
  139. else
  140. {
  141. pwm_start_timer(base);
  142. imx6ull_pwm_reset(base);
  143. }
  144. base->PWMSAR = duty_cycles;
  145. base->PWMPR = period_cycles;
  146. cr = ((prescale -1 ) << 4) |
  147. MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN | MX3_PWMCR_CLKSRC | MX3_PWMCR_DBGEN;
  148. cr |= MX3_PWMCR_EN;
  149. base->PWMCR = cr;
  150. return RT_EOK;
  151. }
  152. static rt_err_t imx6ull_drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  153. {
  154. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  155. switch (cmd)
  156. {
  157. case PWM_CMD_ENABLE:
  158. return imx6ull_pwm_enable(device, RT_TRUE);
  159. case PWM_CMD_DISABLE:
  160. return imx6ull_pwm_enable(device, RT_FALSE);
  161. case PWM_CMD_SET:
  162. return imx6ull_pwm_set(device, configuration);
  163. case PWM_CMD_GET:
  164. return imx6ull_pwm_get(device, configuration);
  165. default:
  166. return RT_EINVAL;
  167. }
  168. }
  169. static rt_err_t imx6ull_drv_pwm_init(PWM_Type *base)
  170. {
  171. pwm_config_t PwmConfig;
  172. pwm_get_default_config(&PwmConfig);
  173. if (pwm_init(base, &PwmConfig) == kStatus_Fail)
  174. {
  175. LOG_E("init pwm failed \n");
  176. return RT_ERROR;
  177. }
  178. return RT_EOK;
  179. }
  180. int imx6ull_pwm_gpio_init(void)
  181. {
  182. #ifdef BSP_USING_PWM1
  183. struct imx6ull_iomuxc gpio;
  184. gpio.muxRegister = 0x020E007C;
  185. gpio.muxMode = 0x0;
  186. gpio.inputRegister = 0x00000000;
  187. gpio.inputDaisy = 0x0;
  188. gpio.configRegister = 0x020E0308;
  189. gpio.inputOnfield = 0;
  190. gpio.configValue = IOMUXC_SW_PAD_CTL_PAD_DSE(2U) | IOMUXC_SW_PAD_CTL_PAD_SPEED(2U);
  191. imx6ull_gpio_init(&gpio);
  192. #endif
  193. return 0;
  194. }
  195. int rt_hw_pwm_init(void)
  196. {
  197. rt_err_t ret = RT_EOK;
  198. #ifdef BSP_USING_PWM1
  199. static struct rt_device_pwm pwm1_device;
  200. PWM_Type *pwm1_base;
  201. imx6ull_pwm_gpio_init();
  202. pwm1_base = (PWM_Type *)rt_ioremap((void*)PWM1, 0x1000);
  203. if (imx6ull_drv_pwm_init(pwm1_base) != RT_EOK)
  204. {
  205. LOG_E("init pwm1 failed\n");
  206. }
  207. ret = rt_device_pwm_register(&pwm1_device, "pwm1", &imxrt_drv_ops, pwm1_base);
  208. if (ret != RT_EOK)
  209. {
  210. LOG_E("%s register failed", "pwm1");
  211. }
  212. #endif /* BSP_USING_PWM1 */
  213. #ifdef BSP_USING_PWM2
  214. static struct rt_device_pwm pwm2_device;
  215. imx6ull_pwm_gpio_init();
  216. if (imx6ull_drv_pwm_init(PWM2) != RT_EOK)
  217. {
  218. LOG_E("init pwm2 failed\n");
  219. }
  220. ret = rt_device_pwm_register(&pwm2_device, "pwm2", &imxrt_drv_ops, PWM2);
  221. if (ret != RT_EOK)
  222. {
  223. LOG_E("%s register failed", "pwm2");
  224. }
  225. #endif /* BSP_USING_PWM2 */
  226. #ifdef BSP_USING_PWM3
  227. static struct rt_device_pwm pwm3_device;
  228. imx6ull_pwm_gpio_init();
  229. if (imx6ull_drv_pwm_init(PWM3) != RT_EOK)
  230. {
  231. LOG_E("init pwm3 failed\n");
  232. }
  233. ret = rt_device_pwm_register(&pwm3_device, "pwm3", &imxrt_drv_ops, PWM3);
  234. if (ret != RT_EOK)
  235. {
  236. LOG_E("%s register failed", "pwm3");
  237. }
  238. #endif /* BSP_USING_PWM3 */
  239. #ifdef BSP_USING_PWM4
  240. static struct rt_device_pwm pwm4_device;
  241. imx6ull_pwm_gpio_init();
  242. if (imx6ull_drv_pwm_init(PWM4) != RT_EOK)
  243. {
  244. LOG_E("init pwm4 failed\n");
  245. }
  246. ret = rt_device_pwm_register(&pwm4_device, "pwm4", &imxrt_drv_ops, PWM4);
  247. if (ret != RT_EOK)
  248. {
  249. LOG_E("%s register failed", "pwm4");
  250. }
  251. #endif /* BSP_USING_PWM4 */
  252. return ret;
  253. }
  254. INIT_DEVICE_EXPORT(rt_hw_pwm_init);
  255. int set_pwm_default(void)
  256. {
  257. int result = 0;
  258. struct rt_device_pwm *device = RT_NULL;
  259. device = (struct rt_device_pwm *)rt_device_find("pwm1");
  260. if (!device)
  261. {
  262. result = -RT_EIO;
  263. goto _exit;
  264. }
  265. result = rt_pwm_set(device, 1, 1000000, 500000);
  266. result = rt_pwm_enable(device, 1);
  267. _exit:
  268. return result;
  269. }
  270. INIT_APP_EXPORT(set_pwm_default);
  271. #endif /* BSP_USING_PWM */