drv_pm.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2019-04-08 wangyq the first version
  9. * 2019-11-01 wangyq adapt to the new power management interface
  10. */
  11. #include <rthw.h>
  12. #include <board.h>
  13. #include <rtdevice.h>
  14. #include <drv_lptim.h>
  15. #include <ald_cmu.h>
  16. #include <ald_pmu.h>
  17. #ifdef RT_USING_PM
  18. static void uart_console_reconfig(void)
  19. {
  20. struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
  21. rt_device_control(rt_console_get_device(), RT_DEVICE_CTRL_CONFIG, &config);
  22. }
  23. static void delay(void)
  24. {
  25. long i;
  26. rt_base_t level;
  27. level = rt_hw_interrupt_disable();
  28. i = 0;
  29. do{
  30. i++;
  31. }
  32. while (i < 10000);
  33. rt_hw_interrupt_enable(level);
  34. }
  35. /**
  36. * This function will put ES32F033x into sleep mode.
  37. *
  38. * @param pm pointer to power manage structure
  39. */
  40. static void sleep(struct rt_pm *pm, uint8_t mode)
  41. {
  42. switch (mode)
  43. {
  44. case PM_SLEEP_MODE_NONE:
  45. break;
  46. case PM_SLEEP_MODE_IDLE:
  47. //__WFI();
  48. break;
  49. case PM_SLEEP_MODE_LIGHT:
  50. if (pm->run_mode == PM_RUN_MODE_LOW_SPEED)
  51. {
  52. /* Enter LP SLEEP Mode, Enable low-power regulator */
  53. ald_pmu_lprun_config(PMU_LDO_LPMODE_OUTPUT_1_5, ENABLE);
  54. }
  55. else
  56. {
  57. /* Enter SLEEP Mode, Main regulator is ON */
  58. ald_pmu_stop1_enter();
  59. delay();
  60. }
  61. break;
  62. case PM_SLEEP_MODE_DEEP:
  63. /* Enter STOP 2 mode */
  64. ald_pmu_stop2_enter();
  65. delay();
  66. break;
  67. case PM_SLEEP_MODE_STANDBY:
  68. /* Enter STANDBY mode */
  69. ald_pmu_stop2_enter();
  70. delay();
  71. break;
  72. case PM_SLEEP_MODE_SHUTDOWN:
  73. /* Enter SHUTDOWNN mode */
  74. ald_pmu_stop2_enter();
  75. delay();
  76. break;
  77. default:
  78. RT_ASSERT(0);
  79. break;
  80. }
  81. }
  82. static uint8_t run_speed[PM_RUN_MODE_MAX][2] =
  83. {
  84. {48, 0},
  85. {48, 1},
  86. {24, 2},
  87. {2, 3},
  88. };
  89. static void run(struct rt_pm *pm, uint8_t mode)
  90. {
  91. static uint8_t last_mode;
  92. static char *run_str[] = PM_RUN_MODE_NAMES;
  93. extern uint32_t __system_clock;
  94. if (mode == last_mode)
  95. return;
  96. last_mode = mode;
  97. ald_cmu_clock_config_default();
  98. __system_clock = 24000000;
  99. switch (mode)
  100. {
  101. case PM_RUN_MODE_HIGH_SPEED:
  102. case PM_RUN_MODE_NORMAL_SPEED:
  103. /* hosc 12MHz, from hosc/3 pll to 48MHz */
  104. ald_cmu_pll1_config(CMU_PLL1_INPUT_HRC_6, CMU_PLL1_OUTPUT_48M);
  105. /* MCLK 48MHz */
  106. ald_cmu_clock_config(CMU_CLOCK_PLL1, 48000000);
  107. break;
  108. case PM_RUN_MODE_MEDIUM_SPEED:
  109. break;
  110. case PM_RUN_MODE_LOW_SPEED:
  111. ald_cmu_clock_config(CMU_CLOCK_HRC, 2000000);
  112. break;
  113. default:
  114. break;
  115. }
  116. /* 4. 更新外设时钟 */
  117. uart_console_reconfig();
  118. /* Re-Configure the Systick time */
  119. SysTick_Config(ald_cmu_get_sys_clock() / RT_TICK_PER_SECOND);
  120. rt_kprintf("switch to %s mode, frequency = %d MHz\n", run_str[mode], run_speed[mode][0]);
  121. }
  122. /**
  123. * This function caculate the PM tick from OS tick
  124. *
  125. * @param tick OS tick
  126. *
  127. * @return the PM tick
  128. */
  129. static rt_tick_t es32f0_pm_tick_from_os_tick(rt_tick_t tick)
  130. {
  131. rt_uint32_t freq = es32f0_lptim_get_countfreq();
  132. return (freq * tick / RT_TICK_PER_SECOND);
  133. }
  134. /**
  135. * This function caculate the OS tick from PM tick
  136. *
  137. * @param tick PM tick
  138. *
  139. * @return the OS tick
  140. */
  141. static rt_tick_t es32f0_os_tick_from_pm_tick(rt_uint32_t tick)
  142. {
  143. static rt_uint32_t os_tick_remain = 0;
  144. rt_uint32_t ret, freq;
  145. freq = es32f0_lptim_get_countfreq();
  146. ret = (tick * RT_TICK_PER_SECOND + os_tick_remain) / freq;
  147. os_tick_remain += (tick * RT_TICK_PER_SECOND);
  148. os_tick_remain %= freq;
  149. return ret;
  150. }
  151. /**
  152. * This function start the timer of pm
  153. *
  154. * @param pm Pointer to power manage structure
  155. * @param timeout How many OS Ticks that MCU can sleep
  156. */
  157. static void pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
  158. {
  159. RT_ASSERT(pm != RT_NULL);
  160. RT_ASSERT(timeout > 0);
  161. if (timeout != RT_TICK_MAX)
  162. {
  163. /* Convert OS Tick to pmtimer timeout value */
  164. timeout = es32f0_pm_tick_from_os_tick(timeout);
  165. /* MAX 0xFFFF */
  166. if (timeout > es32f0_lptim_get_tick_max())
  167. {
  168. timeout = es32f0_lptim_get_tick_max();
  169. }
  170. /* Enter PM_TIMER_MODE */
  171. es32f0_lptim_start(timeout);
  172. }
  173. }
  174. /**
  175. * This function stop the timer of pm
  176. *
  177. * @param pm Pointer to power manage structure
  178. */
  179. static void pm_timer_stop(struct rt_pm *pm)
  180. {
  181. RT_ASSERT(pm != RT_NULL);
  182. /* Reset pmtimer status */
  183. es32f0_lptim_stop();
  184. }
  185. /**
  186. * This function calculate how many OS Ticks that MCU have suspended
  187. *
  188. * @param pm Pointer to power manage structure
  189. *
  190. * @return OS Ticks
  191. */
  192. static rt_tick_t pm_timer_get_tick(struct rt_pm *pm)
  193. {
  194. rt_uint32_t timer_tick;
  195. RT_ASSERT(pm != RT_NULL);
  196. timer_tick = es32f0_lptim_get_current_tick();
  197. return es32f0_os_tick_from_pm_tick(timer_tick);
  198. }
  199. /**
  200. * This function initialize the power manager
  201. */
  202. int drv_pm_hw_init(void)
  203. {
  204. static const struct rt_pm_ops _ops =
  205. {
  206. sleep,
  207. run,
  208. pm_timer_start,
  209. pm_timer_stop,
  210. pm_timer_get_tick
  211. };
  212. rt_uint8_t timer_mask = 0;
  213. /* initialize timer mask */
  214. timer_mask = 1UL << PM_SLEEP_MODE_DEEP;
  215. /* initialize system pm module */
  216. rt_system_pm_init(&_ops, timer_mask, RT_NULL);
  217. return 0;
  218. }
  219. INIT_BOARD_EXPORT(drv_pm_hw_init);
  220. #endif