1 /*!
2 \file gd32l23x_pmu.c
3 \brief PMU driver
4
5 \version 2021-08-04, V1.0.0, firmware for GD32L23x
6 */
7
8 /*
9 Copyright (c) 2021, GigaDevice Semiconductor Inc.
10
11 Redistribution and use in source and binary forms, with or without modification,
12 are permitted provided that the following conditions are met:
13
14 1. Redistributions of source code must retain the above copyright notice, this
15 list of conditions and the following disclaimer.
16 2. Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 3. Neither the name of the copyright holder nor the names of its contributors
20 may be used to endorse or promote products derived from this software without
21 specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 OF SUCH DAMAGE.
33 */
34
35 #include "gd32l23x_pmu.h"
36
37 /* PMU register bit offset */
38 #define PAR_TWK_CORE1_OFFSET ((uint32_t)0x00000015U) /*!< bit offset of TWK_CORE1 in PMU_PAR */
39 #define PAR_TSW_IRC16MCNT_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of TSW_IRC16MCNT in PMU_PAR */
40 #define PAR_TWK_SRAM1_OFFSET ((uint32_t)0x00000008U) /*!< bit offset of TWK_SRAM1 in PMU_PAR */
41
42 /*!
43 \brief reset PMU
44 \param[in] none
45 \param[out] none
46 \retval none
47 */
pmu_deinit(void)48 void pmu_deinit(void)
49 {
50 /* reset PMU */
51 rcu_periph_reset_enable(RCU_PMURST);
52 rcu_periph_reset_disable(RCU_PMURST);
53 }
54
55 /*!
56 \brief select low voltage detector threshold
57 \param[in] lvdt_n: low voltage detector threshold
58 only one parameter can be selected which is shown as below:
59 \arg PMU_LVDT_0: voltage threshold is 2.1V
60 \arg PMU_LVDT_1: voltage threshold is 2.3V
61 \arg PMU_LVDT_2: voltage threshold is 2.4V
62 \arg PMU_LVDT_3: voltage threshold is 2.6V
63 \arg PMU_LVDT_4: voltage threshold is 2.7V
64 \arg PMU_LVDT_5: voltage threshold is 2.9V
65 \arg PMU_LVDT_6: voltage threshold is 3.0V
66 \arg PMU_LVDT_7: input analog voltage on PB7 (compared with 0.8V)
67 \param[out] none
68 \retval none
69 */
pmu_lvd_select(uint32_t lvdt_n)70 void pmu_lvd_select(uint32_t lvdt_n)
71 {
72 /* disable LVD */
73 PMU_CTL0 &= ~PMU_CTL0_LVDEN;
74 /* clear LVDT bits */
75 PMU_CTL0 &= ~PMU_CTL0_LVDT;
76 /* set LVDT bits according to lvdt_n */
77 PMU_CTL0 |= lvdt_n;
78 /* enable LVD */
79 PMU_CTL0 |= PMU_CTL0_LVDEN;
80 }
81
82 /*!
83 \brief disable PMU lvd
84 \param[in] none
85 \param[out] none
86 \retval none
87 */
pmu_lvd_disable(void)88 void pmu_lvd_disable(void)
89 {
90 PMU_CTL0 &= ~PMU_CTL0_LVDEN;
91 }
92
93 /*!
94 \brief select LDO output voltage
95 this bit set by software when the main PLL closed, before closing PLL, change the system clock to IRC16M or HXTAL
96 \param[in] ldo_output:
97 only one parameter can be selected which is shown as below:
98 \arg PMU_LDOVS_LOW: LDO output voltage low mode
99 \arg PMU_LDOVS_HIGH: LDO output voltage high mode
100 \param[out] none
101 \retval none
102 */
pmu_ldo_output_select(uint32_t ldo_output)103 void pmu_ldo_output_select(uint32_t ldo_output)
104 {
105 PMU_CTL0 &= ~PMU_CTL0_LDOVS;
106 PMU_CTL0 |= ldo_output;
107 }
108
109 /*!
110 \brief enable VBAT battery charging
111 \param[in] none
112 \param[out] none
113 \retval none
114 */
pmu_vc_enable(void)115 void pmu_vc_enable(void)
116 {
117 PMU_CTL0 |= PMU_CTL0_VCEN;
118 }
119
120 /*!
121 \brief disable VBAT battery charging
122 \param[in] none
123 \param[out] none
124 \retval none
125 */
pmu_vc_disable(void)126 void pmu_vc_disable(void)
127 {
128 PMU_CTL0 &= ~PMU_CTL0_VCEN;
129 }
130
131 /*!
132 \brief select PMU VBAT battery charging resistor
133 \param[in] resistor: VBAT battery charging resistor
134 only one parameter can be selected which is shown as below:
135 \arg PMU_VCRSEL_5K: 5 kOhms resistor is selected for charing VBAT battery
136 \arg PMU_VCRSEL_1P5K: 1.5 kOhms resistor is selected for charing VBAT battery
137 \param[out] none
138 \retval none
139 */
pmu_vcr_select(uint32_t resistor)140 void pmu_vcr_select(uint32_t resistor)
141 {
142 PMU_CTL0 &= ~PMU_CTL0_VCRSEL;
143 PMU_CTL0 |= resistor;
144 }
145
146 /*!
147 \brief enable low power in Run/Sleep mode
148 \param[in] none
149 \param[out] none
150 \retval none
151 */
pmu_low_power_enable(void)152 void pmu_low_power_enable(void)
153 {
154 PMU_CTL0 |= PMU_CTL0_LDNP;
155 }
156
157 /*!
158 \brief disable low power in Run/Sleep mode
159 \param[in] none
160 \param[out] none
161 \retval none
162 */
pmu_low_power_disable(void)163 void pmu_low_power_disable(void)
164 {
165 PMU_CTL0 &= ~PMU_CTL0_LDNP;
166 }
167
168 /*!
169 \brief PMU work at sleep mode
170 \param[in] lowdrive: low-driver mode when use normal power LDO in Run/Sleep mode.
171 only one parameter can be selected which is shown as below:
172 \arg PMU_LDNP_NORMALDRIVE: low-driver mode disable
173 \arg PMU_LDNP_LOWDRIVE: low-driver mode enable
174 \param[in] sleepmodecmd: sleep mode command
175 only one parameter can be selected which is shown as below:
176 \arg WFI_CMD: use WFI command
177 \arg WFE_CMD: use WFE command
178 \param[out] none
179 \retval none
180 */
pmu_to_sleepmode(uint32_t lowdrive,uint8_t sleepmodecmd)181 void pmu_to_sleepmode(uint32_t lowdrive, uint8_t sleepmodecmd)
182 {
183 /* clear sleepDeep bit of Cortex-M23 system control register */
184 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
185
186 /* clear lowpower mode and low drive bits */
187 PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_LPMOD | PMU_CTL0_LDNP));
188
189 /* configure low drive mode in Sleep mode */
190 if(PMU_LDNP_LOWDRIVE == lowdrive) {
191 PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDNP);
192 }
193
194 /* select WFI or WFE command to enter sleep mode */
195 if(WFI_CMD == sleepmodecmd) {
196 __WFI();
197 } else {
198 __WFE();
199 }
200 }
201
202 /*!
203 \brief PMU work at Deep-sleep mode
204 \param[in] lowdrive: low-driver mode when use normal power LDO in Deep-sleep mode
205 only one parameter can be selected which is shown as below:
206 \arg PMU_LDNPDSP_NORMALDRIVE: low-driver mode disable
207 \arg PMU_LDNPDSP_LOWDRIVE: low-driver mode enable
208 \param[in] deepsleepmodecmd: deepsleep mode command
209 only one parameter can be selected which is shown as below:
210 \arg WFI_CMD: use WFI command
211 \arg WFE_CMD: use WFE command
212 \param[in] deepsleepmode: deepsleep mode
213 only one parameter can be selected which is shown as below:
214 \arg PMU_DEEPSLEEP: Deep-sleep mode
215 \arg PMU_DEEPSLEEP1: Deep-sleep mode 1
216 \arg PMU_DEEPSLEEP2: Deep-sleep mode 2
217 \param[out] none
218 \retval none
219 */
pmu_to_deepsleepmode(uint32_t lowdrive,uint8_t deepsleepmodecmd,uint8_t deepsleepmode)220 void pmu_to_deepsleepmode(uint32_t lowdrive, uint8_t deepsleepmodecmd, uint8_t deepsleepmode)
221 {
222 /* clear lowpower mode and low drive bits */
223 PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_LPMOD | PMU_CTL0_LDNPDSP));
224
225 /* low drive mode config in Deep-sleep mode */
226 /* PMU_CTL0_LDNPDSP only useful in PMU_DEEPSLEEP */
227 if((PMU_LDNPDSP_LOWDRIVE == lowdrive) && (PMU_DEEPSLEEP == deepsleepmode)) {
228 PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDNPDSP);
229 }
230
231 /* configure Deep-sleep mode */
232 PMU_CTL0 |= deepsleepmode;
233
234 /* set sleepdeep bit of Cortex-M23 system control register */
235 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
236
237 /* select WFI or WFE command to enter Deep-sleep mode */
238 if(WFI_CMD == deepsleepmodecmd) {
239 __WFI();
240 } else {
241 __SEV();
242 __WFE();
243 __WFE();
244 }
245 /* reset sleepdeep bit of Cortex-M23 system control register */
246 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
247 }
248
249 /*!
250 \brief pmu work at standby mode
251 \param[in] standbymodecmd:
252 only one parameter can be selected which is shown as below:
253 \arg WFI_CMD: use WFI command
254 \arg WFE_CMD: use WFE command
255 \param[out] none
256 \retval none
257 */
pmu_to_standbymode(uint8_t standbymodecmd)258 void pmu_to_standbymode(uint8_t standbymodecmd)
259 {
260 /* set sleepdeep bit of Cortex-M23 system control register */
261 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
262
263 /* select the low-power mode to enter */
264 PMU_CTL0 |= PMU_STANDBY;
265
266 /* reset wakeup flag and standby flag */
267 PMU_CTL0 |= PMU_CTL0_WURST | PMU_CTL0_STBRST;
268
269 /* select WFI or WFE command to enter standby mode */
270 if(WFI_CMD == standbymodecmd) {
271 __WFI();
272 } else {
273 __WFE();
274 __WFE();
275 }
276 }
277
278 /*!
279 \brief enable wakeup pin
280 \param[in] wakeup_pin: wakeup pin
281 one or more parameters can be selected which are shown as below:
282 \arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
283 \arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
284 \arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PA2)
285 \arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PB2)
286 \arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC6)
287 \param[out] none
288 \retval none
289 */
pmu_wakeup_pin_enable(uint32_t wakeup_pin)290 void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
291 {
292 PMU_CS |= wakeup_pin;
293 }
294
295 /*!
296 \brief disable wakeup pin
297 \param[in] wakeup_pin: wakeup pin
298 one or more parameters can be selected which are shown as below:
299 \arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
300 \arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
301 \arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PA2)
302 \arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PB2)
303 \arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC6)
304 \param[out] none
305 \retval none
306 */
pmu_wakeup_pin_disable(uint32_t wakeup_pin)307 void pmu_wakeup_pin_disable(uint32_t wakeup_pin)
308 {
309 PMU_CS &= ~(wakeup_pin);
310 }
311
312 /*!
313 \brief enable backup domain write
314 \param[in] none
315 \param[out] none
316 \retval none
317 */
pmu_backup_write_enable(void)318 void pmu_backup_write_enable(void)
319 {
320 PMU_CTL0 |= PMU_CTL0_BKPWEN;
321 }
322
323 /*!
324 \brief disable backup domain write
325 \param[in] none
326 \param[out] none
327 \retval none
328 */
pmu_backup_write_disable(void)329 void pmu_backup_write_disable(void)
330 {
331 PMU_CTL0 &= ~PMU_CTL0_BKPWEN;
332 }
333
334 /*!
335 \brief configure power state of SRAM1
336 \param[in] state: power state of SRAM1
337 only one parameter can be selected which is shown as below:
338 \arg PMU_SRAM1_SLEEP: SRAM1 go to power-off
339 \arg PMU_SRAM1_WAKE: SRAM1 wakeup
340 \param[out] none
341 \retval none
342 */
pmu_sram_power_config(uint32_t state)343 void pmu_sram_power_config(uint32_t state)
344 {
345 PMU_CTL1 |= state;
346 }
347
348 /*!
349 \brief configure power state of COREOFF1 domain
350 \param[in] state: power state of COREOFF1 domain
351 only one parameter can be selected which is shown as below:
352 \arg PMU_CORE1_SLEEP: COREOFF1 domain go to power-off
353 \arg PMU_CORE1_WAKE: COREOFF1 domain wakeup
354 \param[out] none
355 \retval none
356 */
pmu_core1_power_config(uint32_t state)357 void pmu_core1_power_config(uint32_t state)
358 {
359 PMU_CTL1 |= state;
360 }
361
362 /*!
363 \brief have retention register in Deep-sleep 2
364 \param[in] none
365 \param[out] none
366 \retval none
367 */
pmu_deepsleep2_retention_enable(void)368 void pmu_deepsleep2_retention_enable(void)
369 {
370 PMU_CTL1 &= ~PMU_CTL1_NRRD2;
371 }
372
373 /*!
374 \brief no retention register in Deep-sleep 2
375 \param[in] none
376 \param[out] none
377 \retval none
378 */
pmu_deepsleep2_retention_disable(void)379 void pmu_deepsleep2_retention_disable(void)
380 {
381 PMU_CTL1 |= PMU_CTL1_NRRD2;
382 }
383
384 /*!
385 \brief configure SRAM1 power state when enter Deep-sleep 2
386 \param[in] state: power state of SRAM1 when enters Deep-sleep 2 mode
387 only one parameter can be selected which is shown as below:
388 \arg PMU_SRAM1_POWER_OFF: SRAM1 power-off
389 \arg PMU_SRAM1_POWER_REMAIN: SRAM1 power same as Run/Run1/Run2 mode
390 \param[out] none
391 \retval none
392 */
pmu_deepsleep2_sram_power_config(uint32_t state)393 void pmu_deepsleep2_sram_power_config(uint32_t state)
394 {
395 PMU_CTL1 &= ~PMU_CTL1_SRAM1PD2;
396 PMU_CTL1 |= state;
397 }
398
399 /*!
400 \brief configure IRC16M counter before enter Deep-sleep mode
401 \param[in] wait_time: 0x0~0x1F, IRC16M counter before enter Deep-sleep mode
402 \param[out] none
403 \retval none
404 */
pmu_deepsleep_wait_time_config(uint32_t wait_time)405 void pmu_deepsleep_wait_time_config(uint32_t wait_time)
406 {
407 PMU_PAR &= ~PMU_PAR_TSW_IRC16MCNT;
408 PMU_PAR |= (uint32_t)(wait_time << PAR_TSW_IRC16MCNT_OFFSET);
409 }
410
411 /*!
412 \brief use software value signal when wake up COREOFF1 domain
413 \param[in] wakeup_time: 0x0~0xFF, wakeup time of power switch of COREOFF1 domain. 4 IRC16M clock step and the max value is 64us.
414 \param[out] none
415 \retval none
416 */
pmu_wakeuptime_core1_software_enable(uint32_t wakeup_time)417 void pmu_wakeuptime_core1_software_enable(uint32_t wakeup_time)
418 {
419 PMU_PAR &= ~PMU_PAR_TWK_CORE1;
420 PMU_PAR |= (uint32_t)(wakeup_time << PAR_TWK_CORE1_OFFSET);
421 PMU_PAR |= PMU_PAR_TWKCORE1EN;
422 }
423
424 /*!
425 \brief use hardware ack signal when wake up COREOFF1 domain
426 \param[in] none
427 \param[out] none
428 \retval none
429 */
pmu_wakeuptime_core1_software_disable(void)430 void pmu_wakeuptime_core1_software_disable(void)
431 {
432 PMU_PAR &= ~PMU_PAR_TWKCORE1EN;
433 }
434
435 /*!
436 \brief use software value signal when wake up SRAM1
437 \param[in] wakeup_time: 0x0~0xFF, wakeup time of power switch of SRAM1. The step is 4 IRC16M clock and the max value is 64us.
438 \param[out] none
439 \retval none
440 */
pmu_wakeuptime_sram_software_enable(uint32_t wakeup_time)441 void pmu_wakeuptime_sram_software_enable(uint32_t wakeup_time)
442 {
443 PMU_PAR &= ~PMU_PAR_TWK_SRAM1;
444 PMU_PAR |= (uint32_t)(wakeup_time << PAR_TWK_SRAM1_OFFSET);
445 PMU_PAR |= PMU_PAR_TWKSRAM1EN;
446 }
447
448 /*!
449 \brief use hardware ack signal when wake up SRAM1
450 \param[in] none
451 \param[out] none
452 \retval none
453 */
pmu_wakeuptime_sram_software_disable(void)454 void pmu_wakeuptime_sram_software_disable(void)
455 {
456 PMU_PAR &= ~PMU_PAR_TWKSRAM1EN;
457 }
458
459 /*!
460 \brief use software value signal when wake up Deep-sleep 2
461 \param[in] wakeup_time: 0x0~0xFF, wakeup time of power switch of COREOFF0 domain. The step is 2 IRC16M clock and the max value is 32us.
462 \param[out] none
463 \retval none
464 */
pmu_wakeuptime_deepsleep2_software_enable(uint32_t wakeup_time)465 void pmu_wakeuptime_deepsleep2_software_enable(uint32_t wakeup_time)
466 {
467 PMU_PAR &= ~PMU_PAR_TWK_CORE0;
468 PMU_PAR |= wakeup_time;
469 PMU_PAR |= PMU_PAR_TWKEN;
470 }
471
472 /*!
473 \brief use hardware ack signal when wake up Deep-sleep 2
474 \param[in] none
475 \param[out] none
476 \retval none
477 */
pmu_wakeuptime_deepsleep2_software_disable(void)478 void pmu_wakeuptime_deepsleep2_software_disable(void)
479 {
480 PMU_PAR &= ~PMU_PAR_TWKEN;
481 }
482
483 /*!
484 \brief get PMU flag status
485 \param[in] flag: PMU flags
486 only one parameter can be selected which is shown as below:
487 \arg PMU_FLAG_WAKEUP: wakeup flag
488 \arg PMU_FLAG_STANDBY: standby flag
489 \arg PMU_FLAG_LVD: lvd flag
490 \arg PMU_FLAG_LDOVSRF: LDO voltage select ready flag
491 \arg PMU_FLAG_NPRDY: normal-power LDO ready flag
492 \arg PMU_FLAG_LPRDY: low-power LDO ready flag
493 \arg PMU_FLAG_SRAM1_SLEEP: SRAM1 is in sleep state flag
494 \arg PMU_FLAG_SRAM1_ACTIVE: SRAM1 is in active state flag
495 \arg PMU_FLAG_CORE1_SLEEP: COREOFF1 domain is in sleep state flag
496 \arg PMU_FLAG_CORE1_ACTIVE: COREOFF1 domain is in active state flag
497 \arg PMU_FLAG_DEEPSLEEP_2: Deep-sleep 2 mode status flag
498 \param[out] none
499 \retval FlagStatus: SET or RESET
500 */
pmu_flag_get(uint32_t flag)501 FlagStatus pmu_flag_get(uint32_t flag)
502 {
503 FlagStatus ret = RESET;
504
505 if(RESET != (flag & BIT(31))) {
506 flag &= ~BIT(31);
507 if(PMU_STAT & flag) {
508 ret = SET;
509 }
510 } else {
511 if(PMU_CS & flag) {
512 ret = SET;
513 }
514 }
515 return ret;
516 }
517
518 /*!
519 \brief clear PMU flag status
520 \param[in] flag: PMU flags
521 only one parameter can be selected which is shown as below:
522 \arg PMU_FLAG_WAKEUP: wakeup flag
523 \arg PMU_FLAG_STANDBY: standby flag
524 \arg PMU_FLAG_DEEPSLEEP_2: Deep-sleep 2 mode status flag
525 \param[out] none
526 \retval none
527 */
pmu_flag_clear(uint32_t flag)528 void pmu_flag_clear(uint32_t flag)
529 {
530 switch(flag) {
531 case PMU_FLAG_WAKEUP:
532 /* clear wakeup flag */
533 PMU_CTL0 |= PMU_CTL0_WURST;
534 break;
535 case PMU_FLAG_STANDBY:
536 /* clear standby flag */
537 PMU_CTL0 |= PMU_CTL0_STBRST;
538 break;
539 case PMU_FLAG_DEEPSLEEP_2:
540 /* clear Deep-sleep 2 mode status flag */
541 PMU_STAT &= ~PMU_STAT_DPF2;
542 break;
543 default :
544 break;
545 }
546 }
547