1 /*!
2 \file gd32e10x_pmu.c
3 \brief PMU driver
4
5 \version 2017-12-26, V1.0.0, firmware for GD32E10x
6 \version 2020-09-30, V1.1.0, firmware for GD32E10x
7 \version 2020-12-31, V1.2.0, firmware for GD32E10x
8 \version 2021-05-31, V1.2.1, firmware for GD32E10x
9 \version 2022-06-30, V1.3.0, firmware for GD32E10x
10 */
11
12 /*
13 Copyright (c) 2022, GigaDevice Semiconductor Inc.
14
15 Redistribution and use in source and binary forms, with or without modification,
16 are permitted provided that the following conditions are met:
17
18 1. Redistributions of source code must retain the above copyright notice, this
19 list of conditions and the following disclaimer.
20 2. Redistributions in binary form must reproduce the above copyright notice,
21 this list of conditions and the following disclaimer in the documentation
22 and/or other materials provided with the distribution.
23 3. Neither the name of the copyright holder nor the names of its contributors
24 may be used to endorse or promote products derived from this software without
25 specific prior written permission.
26
27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
31 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36 OF SUCH DAMAGE.
37 */
38
39 #include "gd32e10x_pmu.h"
40
41 /*!
42 \brief reset PMU register
43 \param[in] none
44 \param[out] none
45 \retval none
46 */
pmu_deinit(void)47 void pmu_deinit(void)
48 {
49 /* reset PMU */
50 rcu_periph_reset_enable(RCU_PMURST);
51 rcu_periph_reset_disable(RCU_PMURST);
52 }
53
54 /*!
55 \brief select low voltage detector threshold
56 \param[in] lvdt_n:
57 only one parameter can be selected which is shown as below:
58 \arg PMU_LVDT_0: voltage threshold is 2.1V
59 \arg PMU_LVDT_1: voltage threshold is 2.3V
60 \arg PMU_LVDT_2: voltage threshold is 2.4V
61 \arg PMU_LVDT_3: voltage threshold is 2.6V
62 \arg PMU_LVDT_4: voltage threshold is 2.7V
63 \arg PMU_LVDT_5: voltage threshold is 2.9V
64 \arg PMU_LVDT_6: voltage threshold is 3.0V
65 \arg PMU_LVDT_7: voltage threshold is 3.1V
66 \param[out] none
67 \retval none
68 */
pmu_lvd_select(uint32_t lvdt_n)69 void pmu_lvd_select(uint32_t lvdt_n)
70 {
71 /* disable LVD */
72 PMU_CTL &= ~PMU_CTL_LVDEN;
73 /* clear LVDT bits */
74 PMU_CTL &= ~PMU_CTL_LVDT;
75 /* set LVDT bits according to lvdt_n */
76 PMU_CTL |= lvdt_n;
77 /* enable LVD */
78 PMU_CTL |= PMU_CTL_LVDEN;
79 }
80
81 /*!
82 \brief select LDO output voltage
83 this bit set by software when the main PLL closed, before closing PLL, change the system clock to IRC16M or HXTAL
84 \param[in] ldo_output:
85 only one parameter can be selected which is shown as below:
86 \arg PMU_LDOVS_LOW: LDO output voltage select low mode
87 \arg PMU_LDOVS_NORMAL: LDO output voltage select normal mode
88 \param[out] none
89 \retval none
90 */
pmu_ldo_output_select(uint32_t ldo_output)91 void pmu_ldo_output_select(uint32_t ldo_output)
92 {
93 PMU_CTL &= ~PMU_CTL_LDOVS;
94 PMU_CTL |= ldo_output;
95 }
96
97 /*!
98 \brief disable PMU lvd
99 \param[in] none
100 \param[out] none
101 \retval none
102 */
pmu_lvd_disable(void)103 void pmu_lvd_disable(void)
104 {
105 /* disable LVD */
106 PMU_CTL &= ~PMU_CTL_LVDEN;
107 }
108
109 /*!
110 \brief PMU work at sleep mode
111 \param[in] sleepmodecmd:
112 only one parameter can be selected which is shown as below:
113 \arg WFI_CMD: use WFI command
114 \arg WFE_CMD: use WFE command
115 \param[out] none
116 \retval none
117 */
pmu_to_sleepmode(uint8_t sleepmodecmd)118 void pmu_to_sleepmode(uint8_t sleepmodecmd)
119 {
120 /* clear sleepdeep bit of Cortex-M4 system control register */
121 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
122
123 /* select WFI or WFE command to enter sleep mode */
124 if(WFI_CMD == sleepmodecmd){
125 __WFI();
126 }else{
127 __SEV();
128 __WFE();
129 __WFE();
130 }
131 }
132
133 /*!
134 \brief PMU work at deepsleep mode
135 \param[in] ldo:
136 only one parameter can be selected which is shown as below:
137 \arg PMU_LDO_NORMAL: LDO work at normal power mode when pmu enter deepsleep mode
138 \arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
139 \param[in] deepsleepmodecmd:
140 only one parameter can be selected which is shown as below:
141 \arg WFI_CMD: use WFI command
142 \arg WFE_CMD: use WFE command
143 \param[out] none
144 \retval none
145 */
pmu_to_deepsleepmode(uint32_t ldo,uint8_t deepsleepmodecmd)146 void pmu_to_deepsleepmode(uint32_t ldo,uint8_t deepsleepmodecmd)
147 {
148 static uint32_t reg_snap[ 4 ];
149 /* clear stbmod and ldolp bits */
150 PMU_CTL &= ~((uint32_t)(PMU_CTL_STBMOD | PMU_CTL_LDOLP));
151
152 /* set ldolp bit according to pmu_ldo */
153 PMU_CTL |= ldo;
154
155 /* set sleepdeep bit of Cortex-M4 system control register */
156 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
157
158 reg_snap[ 0 ] = REG32( 0xE000E010U );
159 reg_snap[ 1 ] = REG32( 0xE000E100U );
160 reg_snap[ 2 ] = REG32( 0xE000E104U );
161 reg_snap[ 3 ] = REG32( 0xE000E108U );
162
163 REG32( 0xE000E010U ) &= 0x00010004U;
164 REG32( 0xE000E180U ) = 0XFF7FF83DU;
165 REG32( 0xE000E184U ) = 0XFFFFF8FFU;
166 REG32( 0xE000E188U ) = 0xFFFFFFFFU;
167
168 /* select WFI or WFE command to enter deepsleep mode */
169 if(WFI_CMD == deepsleepmodecmd){
170 __WFI();
171 }else{
172 __SEV();
173 __WFE();
174 __WFE();
175 }
176
177 REG32( 0xE000E010U ) = reg_snap[ 0 ] ;
178 REG32( 0xE000E100U ) = reg_snap[ 1 ] ;
179 REG32( 0xE000E104U ) = reg_snap[ 2 ] ;
180 REG32( 0xE000E108U ) = reg_snap[ 3 ] ;
181
182 /* reset sleepdeep bit of Cortex-M4 system control register */
183 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
184 }
185
186 /*!
187 \brief pmu work at standby mode
188 \param[in] none
189 \param[out] none
190 \retval none
191 */
pmu_to_standbymode(void)192 void pmu_to_standbymode(void)
193 {
194 /* set stbmod bit */
195 PMU_CTL |= PMU_CTL_STBMOD;
196
197 /* reset wakeup flag */
198 PMU_CTL |= PMU_CTL_WURST;
199
200 /* set sleepdeep bit of Cortex-M4 system control register */
201 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
202
203 REG32( 0xE000E010U ) &= 0x00010004U;
204 REG32( 0xE000E180U ) = 0XFFFFFFF7U;
205 REG32( 0xE000E184U ) = 0XFFFFFDFFU;
206 REG32( 0xE000E188U ) = 0xFFFFFFFFU;
207
208 /* select WFI or WFE command to enter standby mode */
209 __WFI();
210 }
211
212 /*!
213 \brief enable wakeup pin
214 \param[in] none
215 \param[out] none
216 \retval none
217 */
pmu_wakeup_pin_enable(void)218 void pmu_wakeup_pin_enable(void)
219 {
220 PMU_CS |= PMU_CS_WUPEN;
221 }
222
223 /*!
224 \brief disable wakeup pin
225 \param[in] none
226 \param[out] none
227 \retval none
228 */
pmu_wakeup_pin_disable(void)229 void pmu_wakeup_pin_disable(void)
230 {
231 PMU_CS &= ~PMU_CS_WUPEN;
232 }
233
234 /*!
235 \brief enable write access to the registers in backup domain
236 \param[in] none
237 \param[out] none
238 \retval none
239 */
pmu_backup_write_enable(void)240 void pmu_backup_write_enable(void)
241 {
242 PMU_CTL |= PMU_CTL_BKPWEN;
243 }
244
245 /*!
246 \brief disable write access to the registers in backup domain
247 \param[in] none
248 \param[out] none
249 \retval none
250 */
pmu_backup_write_disable(void)251 void pmu_backup_write_disable(void)
252 {
253 PMU_CTL &= ~PMU_CTL_BKPWEN;
254 }
255
256 /*!
257 \brief get flag state
258 \param[in] flag:
259 only one parameter can be selected which is shown as below:
260 \arg PMU_FLAG_WAKEUP: wakeup flag
261 \arg PMU_FLAG_STANDBY: standby flag
262 \arg PMU_FLAG_LVD: lvd flag
263 \param[out] none
264 \retval FlagStatus: SET or RESET
265 */
pmu_flag_get(uint32_t flag)266 FlagStatus pmu_flag_get(uint32_t flag)
267 {
268 if(RESET != (PMU_CS & flag)){
269 return SET;
270 }else{
271 return RESET;
272 }
273 }
274
275 /*!
276 \brief clear flag bit
277 \param[in] flag:
278 only one parameter can be selected which is shown as below:
279 \arg PMU_FLAG_RESET_WAKEUP: reset wakeup flag
280 \arg PMU_FLAG_RESET_STANDBY: reset standby flag
281 \param[out] none
282 \retval none
283 */
pmu_flag_clear(uint32_t flag)284 void pmu_flag_clear(uint32_t flag)
285 {
286 switch(flag){
287 case PMU_FLAG_RESET_WAKEUP:
288 /* reset wakeup flag */
289 PMU_CTL |= PMU_CTL_WURST;
290 break;
291 case PMU_FLAG_RESET_STANDBY:
292 /* reset standby flag */
293 PMU_CTL |= PMU_CTL_STBRST;
294 break;
295 default:
296 break;
297 }
298 }
299