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