1 /*!
2 \file gd32e50x_pmu.c
3 \brief PMU driver
4
5 \version 2020-03-10, V1.0.0, firmware for GD32E50x
6 \version 2020-08-26, V1.1.0, firmware for GD32E50x
7 \version 2020-12-15, V1.1.1, firmware for GD32E50x
8 \version 2021-03-23, V1.2.0, firmware for GD32E50x
9 */
10
11 /*
12 Copyright (c) 2021, GigaDevice Semiconductor Inc.
13
14 Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
16
17 1. Redistributions of source code must retain the above copyright notice, this
18 list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright notice,
20 this list of conditions and the following disclaimer in the documentation
21 and/or other materials provided with the distribution.
22 3. Neither the name of the copyright holder nor the names of its contributors
23 may be used to endorse or promote products derived from this software without
24 specific prior written permission.
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 OF SUCH DAMAGE.
36 */
37
38 #include "gd32e50x_pmu.h"
39
40 /*!
41 \brief reset PMU registers
42 \param[in] none
43 \param[out] none
44 \retval none
45 */
pmu_deinit(void)46 void pmu_deinit(void)
47 {
48 /* reset PMU */
49 rcu_periph_reset_enable(RCU_PMURST);
50 rcu_periph_reset_disable(RCU_PMURST);
51 }
52
53 /*!
54 \brief select low voltage detector threshold
55 \param[in] lvdt_n:
56 only one parameter can be selected which is shown as below:
57 \arg PMU_LVDT_0: voltage threshold is 2.1V
58 \arg PMU_LVDT_1: voltage threshold is 2.3V
59 \arg PMU_LVDT_2: voltage threshold is 2.4V
60 \arg PMU_LVDT_3: voltage threshold is 2.6V
61 \arg PMU_LVDT_4: voltage threshold is 2.7V
62 \arg PMU_LVDT_5: voltage threshold is 2.9V
63 \arg PMU_LVDT_6: voltage threshold is 3.0V
64 \arg PMU_LVDT_7: voltage threshold is 3.1V
65 \param[out] none
66 \retval none
67 */
pmu_lvd_select(uint32_t lvdt_n)68 void pmu_lvd_select(uint32_t lvdt_n)
69 {
70 /* disable LVD */
71 PMU_CTL0 &= ~PMU_CTL0_LVDEN;
72 /* clear LVDT bits */
73 PMU_CTL0 &= ~PMU_CTL0_LVDT;
74 /* set LVDT bits according to lvdt_n */
75 PMU_CTL0 |= lvdt_n;
76 /* enable LVD */
77 PMU_CTL0 |= PMU_CTL0_LVDEN;
78 }
79
80 /*!
81 \brief disable PMU LVD
82 \param[in] none
83 \param[out] none
84 \retval none
85 */
pmu_lvd_disable(void)86 void pmu_lvd_disable(void)
87 {
88 /* disable LVD */
89 PMU_CTL0 &= ~PMU_CTL0_LVDEN;
90 }
91
92 /*!
93 \brief enable high-driver mode
94 this bit set by software only when IRC8M or HXTAL used as system clock
95 \param[in] none
96 \param[out] none
97 \retval none
98 */
pmu_highdriver_mode_enable(void)99 void pmu_highdriver_mode_enable(void)
100 {
101 PMU_CTL0 |= PMU_CTL0_HDEN;
102 }
103
104 /*!
105 \brief disable high-driver mode
106 \param[in] none
107 \param[out] none
108 \retval none
109 */
pmu_highdriver_mode_disable(void)110 void pmu_highdriver_mode_disable(void)
111 {
112 PMU_CTL0 &= ~PMU_CTL0_HDEN;
113 }
114
115 /*!
116 \brief switch high-driver mode
117 this bit set by software only when IRC8M or HXTAL used as system clock
118 \param[in] highdr_switch:
119 only one parameter can be selected which is shown as below:
120 \arg PMU_HIGHDR_SWITCH_NONE: disable high-driver mode switch
121 \arg PMU_HIGHDR_SWITCH_EN: enable high-driver mode switch
122 \param[out] none
123 \retval none
124 */
pmu_highdriver_switch_select(uint32_t highdr_switch)125 void pmu_highdriver_switch_select(uint32_t highdr_switch)
126 {
127 /* wait for HDRF flag set */
128 while(SET != pmu_flag_get(PMU_FLAG_HDRF)){
129 }
130 PMU_CTL0 &= ~PMU_CTL0_HDS;
131 PMU_CTL0 |= highdr_switch;
132 }
133
134 /*!
135 \brief enable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
136 \param[in] none
137 \param[out] none
138 \retval none
139 */
pmu_lowdriver_mode_enable(void)140 void pmu_lowdriver_mode_enable(void)
141 {
142 PMU_CTL0 |= PMU_CTL0_LDEN;
143 }
144
145 /*!
146 \brief disable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
147 \param[in] none
148 \param[out] none
149 \retval none
150 */
pmu_lowdriver_mode_disable(void)151 void pmu_lowdriver_mode_disable(void)
152 {
153 PMU_CTL0 &= ~PMU_CTL0_LDEN;
154 }
155
156 /*!
157 \brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use low power LDO
158 \param[in] mode:
159 only one parameter can be selected which is shown as below:
160 \arg PMU_NORMALDR_LOWPWR: normal driver when use low power LDO
161 \arg PMU_LOWDR_LOWPWR: low-driver mode enabled when LDEN is 11 and use low power LDO
162 \param[out] none
163 \retval none
164 */
pmu_lowpower_driver_config(uint32_t mode)165 void pmu_lowpower_driver_config(uint32_t mode)
166 {
167 PMU_CTL0 &= ~PMU_CTL0_LDLP;
168 PMU_CTL0 |= mode;
169 }
170
171 /*!
172 \brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use normal power LDO
173 \param[in] mode:
174 only one parameter can be selected which is shown as below:
175 \arg PMU_NORMALDR_NORMALPWR: normal driver when use normal power LDO
176 \arg PMU_LOWDR_NORMALPWR: low-driver mode enabled when LDEN is 11 and use normal power LDO
177 \param[out] none
178 \retval none
179 */
pmu_normalpower_driver_config(uint32_t mode)180 void pmu_normalpower_driver_config(uint32_t mode)
181 {
182 PMU_CTL0 &= ~PMU_CTL0_LDNP;
183 PMU_CTL0 |= mode;
184 }
185
186 /*!
187 \brief PMU work at sleep mode
188 \param[in] sleepmodecmd:
189 only one parameter can be selected which is shown as below:
190 \arg WFI_CMD: use WFI command
191 \arg WFE_CMD: use WFE command
192 \param[out] none
193 \retval none
194 */
pmu_to_sleepmode(uint8_t sleepmodecmd)195 void pmu_to_sleepmode(uint8_t sleepmodecmd)
196 {
197 /* clear sleepdeep bit of Cortex-M33 system control register */
198 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
199
200 /* select WFI or WFE command to enter sleep mode */
201 if(WFI_CMD == sleepmodecmd){
202 __WFI();
203 }else{
204 __WFE();
205 }
206 }
207
208 /*!
209 \brief PMU work at deepsleep mode
210 \param[in] ldo:
211 only one parameter can be selected which is shown as below:
212 \arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode
213 \arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
214 \param[in] lowdrive:
215 only one parameter can be selected which is shown as below:
216 \arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep mode
217 \arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep mode
218 \param[in] deepsleepmodecmd:
219 only one parameter can be selected which is shown as below:
220 \arg WFI_CMD: use WFI command
221 \arg WFE_CMD: use WFE command
222 \param[out] none
223 \retval none
224 */
pmu_to_deepsleepmode(uint32_t ldo,uint32_t lowdrive,uint8_t deepsleepmodecmd)225 void pmu_to_deepsleepmode(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmodecmd)
226 {
227 /* clear stbmod and ldolp bits and low drive bits */
228 PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
229 /* clear deep-sleep 1/2 mode enable bits */
230 PMU_CTL1 &= ~(PMU_CTL1_DPMOD1 | PMU_CTL1_DPMOD2);
231
232 /* set ldolp bit according to pmu_ldo */
233 PMU_CTL0 |= ldo;
234
235 /* low drive mode config in deep-sleep mode */
236 if(PMU_LOWDRIVER_ENABLE == lowdrive){
237 if(PMU_LDO_NORMAL == ldo){
238 PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
239 }else{
240 PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
241 }
242 }
243
244 /* set sleepdeep bit of Cortex-M33 system control register */
245 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
246
247 /* select WFI or WFE command to enter deepsleep mode */
248 if(WFI_CMD == deepsleepmodecmd){
249 __WFI();
250 }else{
251 __SEV();
252 __WFE();
253 __WFE();
254 }
255
256 /* reset sleepdeep bit of Cortex-M33 system control register */
257 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
258 }
259
260 /*!
261 \brief PMU work at deepsleep mode 1
262 \param[in] ldo:
263 only one parameter can be selected which is shown as below:
264 \arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 1
265 \arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 1
266 \param[in] lowdrive:
267 only one parameter can be selected which is shown as below:
268 \arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 1 mode
269 \arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 1 mode
270 \param[in] deepsleepmode1cmd:
271 only one parameter can be selected which is shown as below:
272 \arg WFI_CMD: use WFI command
273 \arg WFE_CMD: use WFE command
274 \param[out] none
275 \retval none
276 */
pmu_to_deepsleepmode_1(uint32_t ldo,uint32_t lowdrive,uint8_t deepsleepmode1cmd)277 void pmu_to_deepsleepmode_1(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode1cmd)
278 {
279 /* clear stbmod and ldolp bits and low drive bits */
280 PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
281 /* clear deep-sleep 2 mode enable bit */
282 PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
283 /* enable deep-sleep 1 mode */
284 PMU_CTL1 |= PMU_CTL1_DPMOD1;
285
286 /* set ldolp bit according to pmu_ldo */
287 PMU_CTL0 |= ldo;
288
289 /* low drive mode config in deep-sleep 1 mode */
290 if(PMU_LOWDRIVER_ENABLE == lowdrive){
291 if(PMU_LDO_NORMAL == ldo){
292 PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
293 }else{
294 PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
295 }
296 }
297
298 /* set sleepdeep bit of Cortex-M33 system control register */
299 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
300
301 /* select WFI or WFE command to enter deepsleep mode 1 */
302 if(WFI_CMD == deepsleepmode1cmd){
303 __WFI();
304 }else{
305 __SEV();
306 __WFE();
307 __WFE();
308 }
309
310 /* reset sleepdeep bit of Cortex-M33 system control register */
311 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
312 PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
313 }
314
315 /*!
316 \brief PMU work at deepsleep mode 2
317 \param[in] ldo:
318 only one parameter can be selected which is shown as below:
319 \arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 2
320 \arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 2
321 \param[in] lowdrive:
322 only one parameter can be selected which is shown as below:
323 \arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 2 mode
324 \arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 2 mode
325 \param[in] deepsleepmode2cmd:
326 only one parameter can be selected which is shown as below:
327 \arg WFI_CMD: use WFI command
328 \arg WFE_CMD: use WFE command
329 \param[out] none
330 \retval none
331 */
pmu_to_deepsleepmode_2(uint32_t ldo,uint32_t lowdrive,uint8_t deepsleepmode2cmd)332 void pmu_to_deepsleepmode_2(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode2cmd)
333 {
334 /* clear stbmod and ldolp bits and low drive bits */
335 PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
336 /* clear deep-sleep 1 mode enable bit */
337 PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
338 /* enable deep-sleep 2 mode */
339 PMU_CTL1 |= PMU_CTL1_DPMOD2;
340
341 /* set ldolp bit according to pmu_ldo */
342 PMU_CTL0 |= ldo;
343
344 /* low drive mode config in deep-sleep 2 mode */
345 if(PMU_LOWDRIVER_ENABLE == lowdrive){
346 if(PMU_LDO_NORMAL == ldo){
347 PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
348 }else{
349 PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
350 }
351 }
352
353 /* set sleepdeep bit of Cortex-M33 system control register */
354 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
355
356 /* select WFI or WFE command to enter deepsleep mode 2 */
357 if(WFI_CMD == deepsleepmode2cmd){
358 __WFI();
359 }else{
360 __SEV();
361 __WFE();
362 __WFE();
363 }
364
365 /* reset sleepdeep bit of Cortex-M33 system control register */
366 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
367 PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
368 }
369
370 /*!
371 \brief pmu work at standby mode
372 \param[in] standbymodecmd:
373 only one parameter can be selected which is shown as below:
374 \arg WFI_CMD: use WFI command
375 \arg WFE_CMD: use WFE command
376 \param[out] none
377 \retval none
378 */
pmu_to_standbymode(uint8_t standbymodecmd)379 void pmu_to_standbymode(uint8_t standbymodecmd)
380 {
381 /* set sleepdeep bit of Cortex-M33 system control register */
382 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
383
384 /* set stbmod bit */
385 PMU_CTL0 |= PMU_CTL0_STBMOD;
386
387 /* reset wakeup flag */
388 PMU_CTL0 |= PMU_CTL0_WURST;
389
390 /* select WFI or WFE command to enter standby mode */
391 if(WFI_CMD == standbymodecmd){
392 __WFI();
393 }else{
394 __WFE();
395 __WFE();
396 }
397 }
398
399 /*!
400 \brief enable PMU wakeup pin
401 \param[in] wakeup_pin:
402 one or more parameters can be selected which are shown as below:
403 \arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
404 \arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
405 \arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
406 \arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
407 \arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
408 \arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
409 \arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
410 \arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
411 \param[out] none
412 \retval none
413 */
pmu_wakeup_pin_enable(uint32_t wakeup_pin)414 void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
415 {
416 PMU_CS0 |= wakeup_pin;
417 }
418
419 /*!
420 \brief disable PMU wakeup pin
421 \param[in] wakeup_pin:
422 one or more parameters can be selected which are shown as below:
423 \arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
424 \arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
425 \arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
426 \arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
427 \arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
428 \arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
429 \arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
430 \arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
431 \param[out] none
432 \retval none
433 */
pmu_wakeup_pin_disable(uint32_t wakeup_pin)434 void pmu_wakeup_pin_disable(uint32_t wakeup_pin)
435 {
436 PMU_CS0 &= ~(wakeup_pin);
437 }
438
439 /*!
440 \brief enable backup domain write
441 \param[in] none
442 \param[out] none
443 \retval none
444 */
pmu_backup_write_enable(void)445 void pmu_backup_write_enable(void)
446 {
447 PMU_CTL0 |= PMU_CTL0_BKPWEN;
448 }
449
450 /*!
451 \brief disable backup domain write
452 \param[in] none
453 \param[out] none
454 \retval none
455 */
pmu_backup_write_disable(void)456 void pmu_backup_write_disable(void)
457 {
458 PMU_CTL0 &= ~PMU_CTL0_BKPWEN;
459 }
460
461 /*!
462 \brief get flag state
463 \param[in] flag:
464 only one parameter can be selected which is shown as below:
465 \arg PMU_FLAG_WAKEUP: wakeup flag
466 \arg PMU_FLAG_STANDBY: standby flag
467 \arg PMU_FLAG_LVD: lvd flag
468 \arg PMU_FLAG_HDRF: high-driver ready flag
469 \arg PMU_FLAG_HDSRF: high-driver switch ready flag
470 \arg PMU_FLAG_LDRF: low-driver mode ready flag
471 \arg PMU_FLAG_DEEPSLEEP_1: deep-sleep 1 mode status flag
472 \arg PMU_FLAG_DEEPSLEEP_2: deep-sleep 2 mode status flag
473 \param[out] none
474 \retval FlagStatus: SET or RESET
475 */
pmu_flag_get(uint32_t flag)476 FlagStatus pmu_flag_get(uint32_t flag)
477 {
478 FlagStatus ret = RESET;
479
480 if(RESET != (flag & BIT(31))){
481 flag &= ~BIT(31);
482 if(PMU_CS1 & flag){
483 ret = SET;
484 }
485 }else{
486 if(PMU_CS0 & flag){
487 ret = SET;
488 }
489 }
490 return ret;
491 }
492
493 /*!
494 \brief clear flag bit
495 \param[in] flag:
496 only one parameter can be selected which is shown as below:
497 \arg PMU_FLAG_RESET_WAKEUP: reset wakeup flag
498 \arg PMU_FLAG_RESET_STANDBY: reset standby flag
499 \arg PMU_FLAG_RESET_DEEPSLEEP_1: reset deep-sleep 1 mode status flag
500 \arg PMU_FLAG_RESET_DEEPSLEEP_2: reset deep-sleep 2 mode status flag
501 \param[out] none
502 \retval none
503 */
pmu_flag_clear(uint32_t flag)504 void pmu_flag_clear(uint32_t flag)
505 {
506 switch(flag){
507 case PMU_FLAG_RESET_WAKEUP:
508 /* reset wakeup flag */
509 PMU_CTL0 |= PMU_CTL0_WURST;
510 break;
511 case PMU_FLAG_RESET_STANDBY:
512 /* reset standby flag */
513 PMU_CTL0 |= PMU_CTL0_STBRST;
514 break;
515 case PMU_FLAG_RESET_DEEPSLEEP_1:
516 /* reset deep-sleep 1 mode status flag */
517 PMU_CS1 &= ~PMU_CS1_DPF1;
518 break;
519 case PMU_FLAG_RESET_DEEPSLEEP_2:
520 /* reset deep-sleep 2 mode status flag */
521 PMU_CS1 &= ~PMU_CS1_DPF2;
522 break;
523 default :
524 break;
525 }
526 }
527