drv_pm.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-10-13 AisinoChip first add to bsp
  9. */
  10. #include "board.h"
  11. #include <rtdevice.h>
  12. #if defined(RT_USING_PM)
  13. #define IWDT_SRC_CLK 32000
  14. #define IWDT_CLK_PRESCALER IWDT_CLOCK_PRESCALER_32
  15. #define IWDT_CLK (IWDT_SRC_CLK / (4<<IWDT_CLK_PRESCALER))
  16. static IWDT_HandleTypeDef hiwdt;
  17. static rt_tick_t get_pm_tick_from_os_tick(rt_tick_t tick)
  18. {
  19. return (rt_tick_t)(IWDT_CLK * tick / RT_TICK_PER_SECOND);
  20. }
  21. static rt_tick_t get_os_tick_from_pm_tick(rt_tick_t tick)
  22. {
  23. static rt_uint32_t os_tick_remain = 0;
  24. rt_uint32_t ret;
  25. ret = (tick * RT_TICK_PER_SECOND + os_tick_remain) / IWDT_CLK;
  26. os_tick_remain += (tick * RT_TICK_PER_SECOND);
  27. os_tick_remain %= IWDT_CLK;
  28. return ret;
  29. }
  30. static void _pm_sleep(struct rt_pm *pm, rt_uint8_t mode)
  31. {
  32. RT_ASSERT(pm != RT_NULL);
  33. switch(mode)
  34. {
  35. case PM_SLEEP_MODE_NONE:
  36. break;
  37. case PM_SLEEP_MODE_IDLE:
  38. break;
  39. case PM_SLEEP_MODE_LIGHT:
  40. System_Enter_Sleep_Mode(SLEEPENTRY_WFI);
  41. break;
  42. case PM_SLEEP_MODE_DEEP:
  43. System_Enter_Stop_Mode(STOPENTRY_WFI);
  44. break;
  45. case PM_SLEEP_MODE_STANDBY:
  46. System_Enter_Standby_Mode();
  47. break;
  48. case PM_SLEEP_MODE_SHUTDOWN:
  49. break;
  50. default:
  51. return;
  52. }
  53. }
  54. static void _pm_run(struct rt_pm *pm, rt_uint8_t mode)
  55. {
  56. static rt_uint8_t prev_mode = 0;
  57. RT_ASSERT(pm != RT_NULL);
  58. if(prev_mode == mode)
  59. {
  60. return;
  61. }
  62. switch(mode)
  63. {
  64. case PM_RUN_MODE_HIGH_SPEED: /* 64Mhz */
  65. case PM_RUN_MODE_NORMAL_SPEED: /* 64Mhz */
  66. System_Clock_Init(64000000);
  67. break;
  68. case PM_RUN_MODE_MEDIUM_SPEED: /* 32Mhz */
  69. System_Clock_Init(32000000);
  70. break;
  71. case PM_RUN_MODE_LOW_SPEED: /* 8Mhz */
  72. System_Clock_Init(8000000);
  73. break;
  74. default:
  75. return;
  76. }
  77. SysTick_Config(System_Get_SystemClock() / RT_TICK_PER_SECOND);
  78. prev_mode = mode;
  79. }
  80. static void _pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
  81. {
  82. int tick;
  83. RT_ASSERT(pm != RT_NULL);
  84. IWDT_HandleTypeDef *phiwdt = (IWDT_HandleTypeDef *)(pm->parent.user_data);
  85. if(timeout != RT_TICK_MAX)
  86. {
  87. tick = get_pm_tick_from_os_tick(timeout);
  88. phiwdt->Instance = IWDT;
  89. phiwdt->Init.Prescaler = IWDT_CLK_PRESCALER;
  90. phiwdt->Init.Reload = tick;
  91. phiwdt->Init.Window = tick; /* window function disabled when window >= reload */
  92. phiwdt->Init.Wakeup = tick - 1; /* wakeup function disabled when wakeup >= reload */
  93. HAL_IWDT_Init(phiwdt);
  94. }
  95. }
  96. static void _pm_timer_stop(struct rt_pm *pm)
  97. {
  98. RT_ASSERT(pm != RT_NULL);
  99. IWDT_HandleTypeDef *phiwdt = (IWDT_HandleTypeDef *)(pm->parent.user_data);
  100. phiwdt->Instance->CMDR = 0xFFFF;
  101. }
  102. static rt_tick_t _pm_timer_get_tick(struct rt_pm *pm)
  103. {
  104. rt_tick_t tick;
  105. RT_ASSERT(pm != RT_NULL);
  106. tick = 1;
  107. return get_os_tick_from_pm_tick(tick);
  108. }
  109. static const struct rt_pm_ops _pm_ops =
  110. {
  111. _pm_sleep,
  112. _pm_run,
  113. _pm_timer_start,
  114. _pm_timer_stop,
  115. _pm_timer_get_tick
  116. };
  117. /**
  118. * This function initialize the power manager
  119. */
  120. int drv_pm_hw_init(void)
  121. {
  122. rt_uint8_t timer_mask = 0;
  123. /* initialize timer mask */
  124. timer_mask = (1UL << PM_SLEEP_MODE_DEEP) | (1UL << PM_SLEEP_MODE_STANDBY);
  125. /* initialize system pm module */
  126. rt_system_pm_init(&_pm_ops, timer_mask, &hiwdt);
  127. return 0;
  128. }
  129. INIT_BOARD_EXPORT(drv_pm_hw_init);
  130. #endif /* RT_USING_PM */