1 /**
2 * @file lp.c
3 * @brief Low power functions
4 */
5
6 /******************************************************************************
7 *
8 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
9 * Analog Devices, Inc.),
10 * Copyright (C) 2023-2024 Analog Devices, Inc.
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 ******************************************************************************/
25
26 /***** Includes *****/
27 #include "lp.h"
28 #include "pwrseq_regs.h"
29 #include "gcr_regs.h"
30 #include "mxc_device.h"
31 #include "mxc_errors.h"
32 #include "mxc_pins.h"
33 #include "mxc_sys.h"
34 #include "flc.h"
35 #include "mxc_delay.h"
36
37 /***** Functions *****/
MXC_LP_ClearWakeStatus(void)38 void MXC_LP_ClearWakeStatus(void)
39 {
40 MXC_PWRSEQ->lp_wakefl = 0xFFFFFFFF;
41
42 /* These flags are slow to clear, so block until they do */
43 while (MXC_PWRSEQ->lp_wakefl & (MXC_PWRSEQ->lpwk_en)) {}
44 }
45
MXC_LP_EnableSRAM3(void)46 void MXC_LP_EnableSRAM3(void)
47 {
48 MXC_PWRSEQ->lpmemsd &= ~MXC_F_PWRSEQ_LPMEMSD_SRAM3_OFF;
49 }
50
MXC_LP_DisableSRAM3(void)51 void MXC_LP_DisableSRAM3(void)
52 {
53 MXC_PWRSEQ->lpmemsd |= MXC_F_PWRSEQ_LPMEMSD_SRAM3_OFF;
54 }
55
MXC_LP_EnableSRAM2(void)56 void MXC_LP_EnableSRAM2(void)
57 {
58 MXC_PWRSEQ->lpmemsd &= ~MXC_F_PWRSEQ_LPMEMSD_SRAM2_OFF;
59 }
60
MXC_LP_DisableSRAM2(void)61 void MXC_LP_DisableSRAM2(void)
62 {
63 MXC_PWRSEQ->lpmemsd |= MXC_F_PWRSEQ_LPMEMSD_SRAM2_OFF;
64 }
65
MXC_LP_EnableSRAM1(void)66 void MXC_LP_EnableSRAM1(void)
67 {
68 MXC_PWRSEQ->lpmemsd &= ~MXC_F_PWRSEQ_LPMEMSD_SRAM1_OFF;
69 }
70
MXC_LP_DisableSRAM1(void)71 void MXC_LP_DisableSRAM1(void)
72 {
73 MXC_PWRSEQ->lpmemsd |= MXC_F_PWRSEQ_LPMEMSD_SRAM1_OFF;
74 }
75
MXC_LP_EnableSRAM0(void)76 void MXC_LP_EnableSRAM0(void)
77 {
78 MXC_PWRSEQ->lpmemsd &= ~MXC_F_PWRSEQ_LPMEMSD_SRAM0_OFF;
79 }
80
MXC_LP_DisableSRAM0(void)81 void MXC_LP_DisableSRAM0(void)
82 {
83 MXC_PWRSEQ->lpmemsd |= MXC_F_PWRSEQ_LPMEMSD_SRAM0_OFF;
84 }
85
MXC_LP_EnableICacheLightSleep(void)86 void MXC_LP_EnableICacheLightSleep(void)
87 {
88 MXC_GCR->mem_ctrl |= (MXC_F_GCR_MEM_CTRL_ICACHE_RET);
89 }
90
MXC_LP_DisableICacheLightSleep(void)91 void MXC_LP_DisableICacheLightSleep(void)
92 {
93 MXC_GCR->mem_ctrl &= ~(MXC_F_GCR_MEM_CTRL_ICACHE_RET);
94 }
95
MXC_LP_EnableSysRAM3LightSleep(void)96 void MXC_LP_EnableSysRAM3LightSleep(void)
97 {
98 MXC_GCR->mem_ctrl |= (MXC_F_GCR_MEM_CTRL_RAM3_LS);
99 }
100
MXC_LP_DisableSysRAM3LightSleep(void)101 void MXC_LP_DisableSysRAM3LightSleep(void)
102 {
103 MXC_GCR->mem_ctrl &= ~(MXC_F_GCR_MEM_CTRL_RAM3_LS);
104 }
105
MXC_LP_EnableSysRAM2LightSleep(void)106 void MXC_LP_EnableSysRAM2LightSleep(void)
107 {
108 MXC_GCR->mem_ctrl |= (MXC_F_GCR_MEM_CTRL_RAM2_LS);
109 }
110
MXC_LP_DisableSysRAM2LightSleep(void)111 void MXC_LP_DisableSysRAM2LightSleep(void)
112 {
113 MXC_GCR->mem_ctrl &= ~(MXC_F_GCR_MEM_CTRL_RAM2_LS);
114 }
115
MXC_LP_EnableSysRAM1LightSleep(void)116 void MXC_LP_EnableSysRAM1LightSleep(void)
117 {
118 MXC_GCR->mem_ctrl |= (MXC_F_GCR_MEM_CTRL_RAM1_LS);
119 }
120
MXC_LP_DisableSysRAM1LightSleep(void)121 void MXC_LP_DisableSysRAM1LightSleep(void)
122 {
123 MXC_GCR->mem_ctrl &= ~(MXC_F_GCR_MEM_CTRL_RAM1_LS);
124 }
125
MXC_LP_EnableSysRAM0LightSleep(void)126 void MXC_LP_EnableSysRAM0LightSleep(void)
127 {
128 MXC_GCR->mem_ctrl |= (MXC_F_GCR_MEM_CTRL_RAM0_LS);
129 }
130
MXC_LP_DisableSysRAM0LightSleep(void)131 void MXC_LP_DisableSysRAM0LightSleep(void)
132 {
133 MXC_GCR->mem_ctrl &= ~(MXC_F_GCR_MEM_CTRL_RAM0_LS);
134 }
135
MXC_LP_EnableRTCAlarmWakeup(void)136 void MXC_LP_EnableRTCAlarmWakeup(void)
137 {
138 MXC_GCR->pm |= MXC_F_GCR_PM_RTCWK_EN;
139 }
140
MXC_LP_DisableRTCAlarmWakeup(void)141 void MXC_LP_DisableRTCAlarmWakeup(void)
142 {
143 MXC_GCR->pm &= ~MXC_F_GCR_PM_RTCWK_EN;
144 }
145
MXC_LP_EnableGPIOWakeup(const mxc_gpio_cfg_t * wu_pins)146 void MXC_LP_EnableGPIOWakeup(const mxc_gpio_cfg_t *wu_pins)
147 {
148 MXC_GCR->pm |= MXC_F_GCR_PM_GPIOWK_EN;
149 //switch(wu_pins->port)
150 //{
151 /*case 0:*/ MXC_PWRSEQ->lpwk_en |= wu_pins->mask; //break;
152 //}
153 }
154
MXC_LP_DisableGPIOWakeup(const mxc_gpio_cfg_t * wu_pins)155 void MXC_LP_DisableGPIOWakeup(const mxc_gpio_cfg_t *wu_pins)
156 {
157 //switch(wu_pins->port)
158 //{
159 /* case 0:*/ MXC_PWRSEQ->lpwk_en &= ~wu_pins->mask; //break;
160 //}
161
162 if (MXC_PWRSEQ->lpwk_en == 0) {
163 MXC_GCR->pm &= ~MXC_F_GCR_PM_GPIOWK_EN;
164 }
165 }
166
MXC_LP_EnterSleepMode(void)167 void MXC_LP_EnterSleepMode(void)
168 {
169 // Clear SLEEPDEEP bit
170 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
171
172 // Go into Sleep mode and wait for an interrupt to wake the processor
173 __WFI();
174 }
175
MXC_LP_EnterDeepSleepMode(void)176 void MXC_LP_EnterDeepSleepMode(void)
177 {
178 // Set SLEEPDEEP bit
179 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
180
181 // Auto-powerdown 96 MHz oscillator when in deep sleep
182 MXC_GCR->pm |= MXC_F_GCR_PM_HFIOPD;
183 // Go into Deepsleep mode and wait for an interrupt to wake the processor
184 __WFI();
185 }
186
MXC_LP_EnterBackupMode(void)187 void MXC_LP_EnterBackupMode(void)
188 {
189 MXC_GCR->pm &= ~MXC_F_GCR_PM_MODE;
190 MXC_GCR->pm |= MXC_S_GCR_PM_MODE_BACKUP;
191 while (1) {}
192 }
193
MXC_LP_EnterShutDownMode(void)194 void MXC_LP_EnterShutDownMode(void)
195 {
196 MXC_GCR->pm &= ~MXC_F_GCR_PM_MODE;
197 MXC_GCR->pm |= MXC_S_GCR_PM_MODE_SHUTDOWN;
198 while (1) {}
199 }
200
MXC_LP_SetOperatingVoltage(mxc_lp_ovr_t ovr)201 int MXC_LP_SetOperatingVoltage(mxc_lp_ovr_t ovr)
202 {
203 uint32_t current_clock, div;
204 int error;
205
206 // Ensure part is operating from internal LDO for core power
207 if (MXC_PWRSEQ->lp_ctrl & MXC_F_PWRSEQ_LP_CTRL_LDO_DIS) {
208 return E_BAD_STATE;
209 }
210
211 // Select the 8KHz nanoring (no guarantee 32KHz is attached) as system clock source
212 current_clock = MXC_GCR->clk_ctrl & MXC_F_GCR_CLK_CTRL_CLKSEL;
213 if (current_clock == MXC_SYS_CLOCK_HIRC) {
214 error = MXC_SYS_Clock_Select(MXC_SYS_CLOCK_NANORING);
215 if (error != E_NO_ERROR) {
216 return error;
217 }
218 }
219
220 // Set flash wait state for any clock so its not to low after clock changes.
221 MXC_GCR->mem_ctrl = (MXC_GCR->mem_ctrl & ~(MXC_F_GCR_MEM_CTRL_FWS)) |
222 (0x5UL << MXC_F_GCR_MEM_CTRL_FWS_POS);
223
224 // Set the OVR bits
225 MXC_PWRSEQ->lp_ctrl &= ~(MXC_F_PWRSEQ_LP_CTRL_OVR);
226 MXC_PWRSEQ->lp_ctrl |= ovr;
227
228 // Set LVE bit
229 if (ovr == MXC_LP_OVR_0_9) {
230 MXC_FLC->ctrl |= MXC_F_FLC_CTRL_LVE;
231
232 } else {
233 MXC_FLC->ctrl &= ~(MXC_F_FLC_CTRL_LVE);
234 }
235
236 // Revert the clock to original state if it was HIRC
237 if (current_clock == MXC_SYS_CLOCK_HIRC) {
238 error = MXC_SYS_Clock_Select(MXC_SYS_CLOCK_HIRC);
239 if (error != E_NO_ERROR) {
240 return error;
241 }
242 }
243
244 // Update SystemCoreClock variable
245 SystemCoreClockUpdate();
246
247 // Get the clock divider
248 div = (MXC_GCR->clk_ctrl & MXC_F_GCR_CLK_CTRL_PSC) >> MXC_F_GCR_CLK_CTRL_PSC_POS;
249
250 // Set Flash Wait States
251 if (ovr == MXC_LP_OVR_0_9) {
252 if (div == 0) {
253 MXC_GCR->mem_ctrl = (MXC_GCR->mem_ctrl & ~(MXC_F_GCR_MEM_CTRL_FWS)) |
254 (0x2UL << MXC_F_GCR_MEM_CTRL_FWS_POS);
255
256 } else {
257 MXC_GCR->mem_ctrl = (MXC_GCR->mem_ctrl & ~(MXC_F_GCR_MEM_CTRL_FWS)) |
258 (0x1UL << MXC_F_GCR_MEM_CTRL_FWS_POS);
259 }
260
261 } else if (ovr == MXC_LP_OVR_1_0) {
262 if (div == 0) {
263 MXC_GCR->mem_ctrl = (MXC_GCR->mem_ctrl & ~(MXC_F_GCR_MEM_CTRL_FWS)) |
264 (0x2UL << MXC_F_GCR_MEM_CTRL_FWS_POS);
265
266 } else {
267 MXC_GCR->mem_ctrl = (MXC_GCR->mem_ctrl & ~(MXC_F_GCR_MEM_CTRL_FWS)) |
268 (0x1UL << MXC_F_GCR_MEM_CTRL_FWS_POS);
269 }
270
271 } else {
272 if (div == 0) {
273 MXC_GCR->mem_ctrl = (MXC_GCR->mem_ctrl & ~(MXC_F_GCR_MEM_CTRL_FWS)) |
274 (0x4UL << MXC_F_GCR_MEM_CTRL_FWS_POS);
275
276 } else if (div == 1) {
277 MXC_GCR->mem_ctrl = (MXC_GCR->mem_ctrl & ~(MXC_F_GCR_MEM_CTRL_FWS)) |
278 (0x2UL << MXC_F_GCR_MEM_CTRL_FWS_POS);
279
280 } else {
281 MXC_GCR->mem_ctrl = (MXC_GCR->mem_ctrl & ~(MXC_F_GCR_MEM_CTRL_FWS)) |
282 (0x1UL << MXC_F_GCR_MEM_CTRL_FWS_POS);
283 }
284 }
285
286 // Caller must perform peripheral reset
287
288 return E_NO_ERROR;
289 }
290
MXC_LP_EnableSRamRet0(void)291 void MXC_LP_EnableSRamRet0(void)
292 {
293 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_RAMRET_SEL0;
294 }
295
MXC_LP_DisableSRamRet0(void)296 void MXC_LP_DisableSRamRet0(void)
297 {
298 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_RAMRET_SEL0;
299 }
300
MXC_LP_EnableSRamRet1(void)301 void MXC_LP_EnableSRamRet1(void)
302 {
303 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_RAMRET_SEL1;
304 }
305
MXC_LP_DisableSRamRet1(void)306 void MXC_LP_DisableSRamRet1(void)
307 {
308 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_RAMRET_SEL1;
309 }
310
MXC_LP_EnableSRamRet2(void)311 void MXC_LP_EnableSRamRet2(void)
312 {
313 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_RAMRET_SEL2;
314 }
315
MXC_LP_DisableSRamRet2(void)316 void MXC_LP_DisableSRamRet2(void)
317 {
318 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_RAMRET_SEL2;
319 }
320
MXC_LP_EnableSRamRet3(void)321 void MXC_LP_EnableSRamRet3(void)
322 {
323 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_RAMRET_SEL3;
324 }
325
MXC_LP_DisableSRamRet3(void)326 void MXC_LP_DisableSRamRet3(void)
327 {
328 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_RAMRET_SEL3;
329 }
330
MXC_LP_EnableBlockDetect(void)331 void MXC_LP_EnableBlockDetect(void)
332 {
333 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_VCORE_DET_BYPASS;
334 }
335
MXC_LP_DisableBlockDetect(void)336 void MXC_LP_DisableBlockDetect(void)
337 {
338 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_VCORE_DET_BYPASS;
339 }
340
MXC_LP_EnableRamRetReg(void)341 void MXC_LP_EnableRamRetReg(void)
342 {
343 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_RETREG_EN;
344 }
345
MXC_LP_DisableRamRetReg(void)346 void MXC_LP_DisableRamRetReg(void)
347 {
348 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_RETREG_EN;
349 }
350
MXC_LP_EnableFastWk(void)351 void MXC_LP_EnableFastWk(void)
352 {
353 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_FAST_WK_EN;
354 }
355
MXC_LP_DisableFastWk(void)356 void MXC_LP_DisableFastWk(void)
357 {
358 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_FAST_WK_EN;
359 }
360
MXC_LP_EnableBandGap(void)361 void MXC_LP_EnableBandGap(void)
362 {
363 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_BG_OFF;
364 }
365
MXC_LP_DisableBandGap(void)366 void MXC_LP_DisableBandGap(void)
367 {
368 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_BG_OFF;
369 }
370
MXC_LP_EnableVCorePORSignal(void)371 void MXC_LP_EnableVCorePORSignal(void)
372 {
373 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_VCORE_POR_DIS;
374 }
375
MXC_LP_DisableVCorePORSignal(void)376 void MXC_LP_DisableVCorePORSignal(void)
377 {
378 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_VCORE_POR_DIS;
379 }
380
MXC_LP_EnableLDO(void)381 void MXC_LP_EnableLDO(void)
382 {
383 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_LDO_DIS;
384 }
385
MXC_LP_DisableLDO(void)386 void MXC_LP_DisableLDO(void)
387 {
388 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_LDO_DIS;
389 }
390
MXC_LP_EnableVCoreSVM(void)391 void MXC_LP_EnableVCoreSVM(void)
392 {
393 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_VCORE_SVM_DIS;
394 }
395
MXC_LP_DisableVCoreSVM(void)396 void MXC_LP_DisableVCoreSVM(void)
397 {
398 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_VCORE_SVM_DIS;
399 }
400
MXC_LP_EnableVDDIOPorMonitoF(void)401 void MXC_LP_EnableVDDIOPorMonitoF(void)
402 {
403 MXC_PWRSEQ->lp_ctrl &= ~MXC_F_PWRSEQ_LP_CTRL_VDDIO_POR_DIS;
404 }
405
MXC_LP_DisableVDDIOPorMonitor(void)406 void MXC_LP_DisableVDDIOPorMonitor(void)
407 {
408 MXC_PWRSEQ->lp_ctrl |= MXC_F_PWRSEQ_LP_CTRL_VDDIO_POR_DIS;
409 }
410