1 /*
2 * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Change Logs:
19 * Date Author Notes
20 * 2019-04-08 wangyq the first version
21 * 2019-11-01 wangyq adapt to the new power management interface
22 * 2020-12-15 liuhy the first version
23 */
24
25 #include "drv_pm.h"
26
27 #ifdef RT_USING_PM
28
29
uart_console_reconfig(void)30 static void uart_console_reconfig(void)
31 {
32 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
33
34 rt_device_control(rt_console_get_device(), RT_DEVICE_CTRL_CONFIG, &config);
35 }
36
37 /**
38 * This function will put ES32F065x into sleep mode.
39 *
40 * @param pm pointer to power manage structure
41 */
42
43
44 /* 注意:进入睡眠前,如果有中断挂起(SYSTICK、PENDSV、UART、EXTI等),睡眠将被瞬间唤醒。*/
sleep(struct rt_pm * pm,uint8_t mode)45 static void sleep(struct rt_pm *pm, uint8_t mode)
46 {
47 switch (mode)
48 {
49 case PM_SLEEP_MODE_NONE:
50 break;
51
52 case PM_SLEEP_MODE_IDLE:
53 break;
54
55 case PM_SLEEP_MODE_LIGHT:
56 /* Enter SLEEP Mode, Main regulator is ON */
57 ald_pmu_stop1_enter();
58 break;
59
60 case PM_SLEEP_MODE_DEEP:
61 /* Enter STOP 2 mode */
62 ald_pmu_stop2_enter();
63 break;
64
65 case PM_SLEEP_MODE_STANDBY:
66 /* Enter STANDBY mode */
67 ald_pmu_stop2_enter();
68 break;
69
70 case PM_SLEEP_MODE_SHUTDOWN:
71 /* Enter SHUTDOWNN mode */
72 ald_pmu_stop2_enter();
73 break;
74
75 default:
76 RT_ASSERT(0);
77 break;
78 }
79 }
80
81 static uint8_t run_speed[PM_RUN_MODE_MAX][2] =
82 {
83 {48, 0},
84 {48, 1},
85 {24, 2},
86 {2, 3},
87 };
88
run(struct rt_pm * pm,uint8_t mode)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
95 if (mode == last_mode)
96 return;
97 last_mode = mode;
98
99 ald_cmu_clock_config_default();
100 __system_clock = 24000000;
101 switch (mode)
102 {
103 case PM_RUN_MODE_HIGH_SPEED:
104 case PM_RUN_MODE_NORMAL_SPEED:
105 /* hosc 12MHz, from hosc/3 pll to 48MHz */
106 ald_cmu_pll1_config(CMU_PLL1_INPUT_HRC_6, CMU_PLL1_OUTPUT_48M);
107 /* MCLK 48MHz */
108 ald_cmu_clock_config(CMU_CLOCK_PLL1, 48000000);
109 break;
110 case PM_RUN_MODE_MEDIUM_SPEED:
111 break;
112 case PM_RUN_MODE_LOW_SPEED:
113 ald_cmu_clock_config(CMU_CLOCK_HRC, 2000000);
114 break;
115 default:
116 break;
117 }
118
119 /* 4. 更新外设时钟 */
120 uart_console_reconfig();
121 /* Re-Configure the Systick time */
122 SysTick_Config(ald_cmu_get_sys_clock() / RT_TICK_PER_SECOND);
123
124 rt_kprintf("switch to %s mode, frequency = %d MHz\n", run_str[mode], run_speed[mode][0]);
125 }
126
127 /**
128 * This function caculate the PM tick from OS tick
129 *
130 * @param tick OS tick
131 *
132 * @return the PM tick
133 */
es32f0_pm_tick_from_os_tick(rt_tick_t tick)134 static rt_tick_t es32f0_pm_tick_from_os_tick(rt_tick_t tick)
135 {
136 rt_uint32_t freq = 1;
137
138 return (freq * tick / RT_TICK_PER_SECOND);
139 }
140
141 /**
142 * This function caculate the OS tick from PM tick
143 *
144 * @param tick PM tick
145 *
146 * @return the OS tick
147 */
es32f0_os_tick_from_pm_tick(rt_uint32_t tick)148 static rt_tick_t es32f0_os_tick_from_pm_tick(rt_uint32_t tick)
149 {
150 static rt_uint32_t os_tick_remain = 0;
151 rt_uint32_t ret, freq;
152
153 freq = 1;
154 ret = (tick * RT_TICK_PER_SECOND + os_tick_remain) / freq;
155
156 os_tick_remain += (tick * RT_TICK_PER_SECOND);
157 os_tick_remain %= freq;
158
159 return ret;
160 }
161
162 /**
163 * This function start the timer of pm
164 *
165 * @param pm Pointer to power manage structure
166 * @param timeout How many OS Ticks that MCU can sleep
167 */
pm_timer_start(struct rt_pm * pm,rt_uint32_t timeout)168 static void pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
169 {
170 RT_ASSERT(pm != RT_NULL);
171 RT_ASSERT(timeout > 0);
172
173 if (timeout != RT_TICK_MAX)
174 {
175 /* Convert OS Tick to pmtimer timeout value */
176 timeout = es32f0_pm_tick_from_os_tick(timeout);
177 /* MAX 0xFFFF */
178 if (timeout > 0xFFFF)
179 {
180 timeout = 0xFFFF;
181 }
182 }
183 }
184
185 /**
186 * This function stop the timer of pm
187 *
188 * @param pm Pointer to power manage structure
189 */
pm_timer_stop(struct rt_pm * pm)190 static void pm_timer_stop(struct rt_pm *pm)
191 {
192 RT_ASSERT(pm != RT_NULL);
193 }
194
195 /**
196 * This function calculate how many OS Ticks that MCU have suspended
197 *
198 * @param pm Pointer to power manage structure
199 *
200 * @return OS Ticks
201 */
pm_timer_get_tick(struct rt_pm * pm)202 static rt_tick_t pm_timer_get_tick(struct rt_pm *pm)
203 {
204 rt_uint32_t timer_tick;
205
206 RT_ASSERT(pm != RT_NULL);
207
208 timer_tick = 1;
209
210 return es32f0_os_tick_from_pm_tick(timer_tick);
211 }
212
213 /**
214 * This function initialize the power manager
215 */
drv_pm_hw_init(void)216 int drv_pm_hw_init(void)
217 {
218 static const struct rt_pm_ops _ops =
219 {
220 sleep,
221 run,
222 pm_timer_start,
223 pm_timer_stop,
224 pm_timer_get_tick
225 };
226
227 rt_uint8_t timer_mask = 0;
228
229 /* initialize timer mask */
230 timer_mask = 1UL << PM_SLEEP_MODE_DEEP;
231
232 /* initialize system pm module */
233 rt_system_pm_init(&_ops, timer_mask, RT_NULL);
234
235 return 0;
236 }
237 INIT_BOARD_EXPORT(drv_pm_hw_init);
238
239 #endif
240