1 /******************************************************************************
2  *
3  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4  * Analog Devices, Inc.),
5  * Copyright (C) 2023-2024 Analog Devices, Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************************/
20 
21 #include "mxc_device.h"
22 #include "mxc_assert.h"
23 #include "mxc_sys.h"
24 #include "gcr_regs.h"
25 #include "lp.h"
26 
MXC_LP_EnterSleepMode(void)27 void MXC_LP_EnterSleepMode(void)
28 {
29     MXC_LP_ClearWakeStatus();
30 
31     // set block detect bit
32     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_VCORE_DET_BYPASS;
33 
34     // Clear SLEEPDEEP bit
35     SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
36 
37     // Go into Sleep mode and wait for an interrupt to wake the processor
38     __WFI();
39 }
40 
MXC_LP_EnterDeepSleepMode(void)41 void MXC_LP_EnterDeepSleepMode(void)
42 {
43     MXC_LP_ClearWakeStatus();
44 
45     // set block detect bit
46     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_VCORE_DET_BYPASS;
47 
48     // Set SLEEPDEEP bit
49     SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
50 
51     // Go into Deepsleep mode and wait for an interrupt to wake the processor
52     __WFI();
53 }
54 
MXC_LP_EnterBackupMode(void)55 void MXC_LP_EnterBackupMode(void)
56 {
57     MXC_LP_ClearWakeStatus();
58 
59     // set block detect bit
60     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_VCORE_DET_BYPASS;
61 
62     MXC_GCR->pm &= ~MXC_F_GCR_PM_MODE;
63     MXC_GCR->pm |= MXC_S_GCR_PM_MODE_BACKUP;
64 
65     while (1) {}
66     // Should never reach this line - device will jump to backup vector on exit from background mode.
67 }
68 
MXC_LP_EnterStorageMode(void)69 void MXC_LP_EnterStorageMode(void)
70 {
71     MXC_LP_ClearWakeStatus();
72     /*set block detect bit */
73     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_VCORE_DET_BYPASS;
74 
75     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_STORAGE_EN;
76     MXC_GCR->pm &= ~MXC_F_GCR_PM_MODE;
77     MXC_GCR->pm |= MXC_S_GCR_PM_MODE_BACKUP;
78 
79     while (1) {}
80     // Should never reach this line - device will jump to backup vector on exit from background mode.
81 }
82 
MXC_LP_EnterShutDownMode(void)83 void MXC_LP_EnterShutDownMode(void)
84 {
85     MXC_GCR->pm &= ~MXC_F_GCR_PM_MODE;
86     MXC_GCR->pm |= MXC_S_GCR_PM_MODE_SHUTDOWN;
87 
88     while (1) {}
89     // Should never reach this line - device will reset on exit from shutdown mode.
90 }
91 
MXC_LP_SetOVR(mxc_lp_ovr_t ovr)92 void MXC_LP_SetOVR(mxc_lp_ovr_t ovr)
93 {
94     //TODO(all): not supported yet
95 }
96 
MXC_LP_RetentionRegEnable(void)97 void MXC_LP_RetentionRegEnable(void)
98 {
99     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_RETREG_EN;
100 }
101 
MXC_LP_RetentionRegDisable(void)102 void MXC_LP_RetentionRegDisable(void)
103 {
104     MXC_PWRSEQ->lpcn &= ~MXC_F_PWRSEQ_LPCN_RETREG_EN;
105 }
106 
MXC_LP_RetentionRegIsEnabled(void)107 int MXC_LP_RetentionRegIsEnabled(void)
108 {
109     return (MXC_PWRSEQ->lpcn & MXC_F_PWRSEQ_LPCN_RETREG_EN);
110 }
111 
MXC_LP_BandgapOn(void)112 void MXC_LP_BandgapOn(void)
113 {
114     MXC_PWRSEQ->lpcn &= ~MXC_F_PWRSEQ_LPCN_BG_DIS;
115 }
116 
MXC_LP_BandgapOff(void)117 void MXC_LP_BandgapOff(void)
118 {
119     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_BG_DIS;
120 }
121 
MXC_LP_BandgapIsOn(void)122 int MXC_LP_BandgapIsOn(void)
123 {
124     return (MXC_PWRSEQ->lpcn & MXC_F_PWRSEQ_LPCN_BG_DIS);
125 }
126 
MXC_LP_PORVCOREoreMonitorEnable(void)127 void MXC_LP_PORVCOREoreMonitorEnable(void)
128 {
129     MXC_PWRSEQ->lpcn &= ~MXC_F_PWRSEQ_LPCN_VCOREPOR_DIS;
130 }
131 
MXC_LP_PORVCOREoreMonitorDisable(void)132 void MXC_LP_PORVCOREoreMonitorDisable(void)
133 {
134     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_VCOREPOR_DIS;
135 }
136 
MXC_LP_PORVCOREoreMonitorIsEnabled(void)137 int MXC_LP_PORVCOREoreMonitorIsEnabled(void)
138 {
139     return (MXC_PWRSEQ->lpcn & MXC_F_PWRSEQ_LPCN_VCOREPOR_DIS);
140 }
141 
MXC_LP_LDOEnable(void)142 void MXC_LP_LDOEnable(void)
143 {
144     MXC_PWRSEQ->lpcn &= ~MXC_F_PWRSEQ_LPCN_LDO_DIS;
145 }
146 
MXC_LP_LDODisable(void)147 void MXC_LP_LDODisable(void)
148 {
149     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_LDO_DIS;
150 }
151 
MXC_LP_LDOIsEnabled(void)152 int MXC_LP_LDOIsEnabled(void)
153 {
154     return (MXC_PWRSEQ->lpcn & MXC_F_PWRSEQ_LPCN_LDO_DIS);
155 }
156 
MXC_LP_FastWakeupEnable(void)157 void MXC_LP_FastWakeupEnable(void)
158 {
159     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_FASTWK_EN;
160 }
161 
MXC_LP_FastWakeupDisable(void)162 void MXC_LP_FastWakeupDisable(void)
163 {
164     MXC_PWRSEQ->lpcn &= ~MXC_F_PWRSEQ_LPCN_FASTWK_EN;
165 }
166 
MXC_LP_FastWakeupIsEnabled(void)167 int MXC_LP_FastWakeupIsEnabled(void)
168 {
169     return (MXC_PWRSEQ->lpcn & MXC_F_PWRSEQ_LPCN_FASTWK_EN);
170 }
171 
MXC_LP_ClearWakeStatus(void)172 void MXC_LP_ClearWakeStatus(void)
173 {
174     // Write 1 to clear
175     MXC_PWRSEQ->lpwkst0 = 0xFFFFFFFF;
176     MXC_PWRSEQ->lpwkst1 = 0xFFFFFFFF;
177     MXC_PWRSEQ->lppwkst |= 0x0001001F;
178 }
179 
MXC_LP_EnableGPIOWakeup(mxc_gpio_cfg_t * wu_pins)180 void MXC_LP_EnableGPIOWakeup(mxc_gpio_cfg_t *wu_pins)
181 {
182     MXC_GCR->pm |= MXC_F_GCR_PM_GPIO_WE;
183 
184     switch (1 << MXC_GPIO_GET_IDX(wu_pins->port)) {
185     case MXC_GPIO_PORT_0:
186         MXC_PWRSEQ->lpwken0 |= wu_pins->mask;
187         break;
188 
189     case MXC_GPIO_PORT_1:
190         MXC_PWRSEQ->lpwken1 |= wu_pins->mask;
191     }
192 }
193 
MXC_LP_DisableGPIOWakeup(mxc_gpio_cfg_t * wu_pins)194 void MXC_LP_DisableGPIOWakeup(mxc_gpio_cfg_t *wu_pins)
195 {
196     switch (1 << MXC_GPIO_GET_IDX(wu_pins->port)) {
197     case MXC_GPIO_PORT_0:
198         MXC_PWRSEQ->lpwken0 &= ~wu_pins->mask;
199         break;
200 
201     case MXC_GPIO_PORT_1:
202         MXC_PWRSEQ->lpwken1 &= ~wu_pins->mask;
203     }
204 
205     if (MXC_PWRSEQ->lpwken1 == 0 && MXC_PWRSEQ->lpwken0 == 0) {
206         MXC_GCR->pm &= ~MXC_F_GCR_PM_GPIO_WE;
207     }
208 }
209 
MXC_LP_EnableRTCAlarmWakeup(void)210 void MXC_LP_EnableRTCAlarmWakeup(void)
211 {
212     MXC_GCR->pm |= MXC_F_GCR_PM_RTC_WE;
213 }
214 
MXC_LP_DisableRTCAlarmWakeup(void)215 void MXC_LP_DisableRTCAlarmWakeup(void)
216 {
217     MXC_GCR->pm &= ~MXC_F_GCR_PM_RTC_WE;
218 }
219 
MXC_LP_EnableTimerWakeup(mxc_tmr_regs_t * tmr)220 void MXC_LP_EnableTimerWakeup(mxc_tmr_regs_t *tmr)
221 {
222     MXC_ASSERT(MXC_TMR_GET_IDX(tmr) > 3);
223 
224     if (tmr == MXC_TMR4) {
225         MXC_GCR->pm |= MXC_F_GCR_PM_LPTMR0_WE;
226         MXC_PWRSEQ->lppwken |= MXC_F_PWRSEQ_LPPWKEN_LPTMR0;
227     } else {
228         MXC_GCR->pm |= MXC_F_GCR_PM_LPTMR1_WE;
229         MXC_PWRSEQ->lppwken |= MXC_F_PWRSEQ_LPPWKEN_LPTMR1;
230     }
231 }
232 
MXC_LP_DisableTimerWakeup(mxc_tmr_regs_t * tmr)233 void MXC_LP_DisableTimerWakeup(mxc_tmr_regs_t *tmr)
234 {
235     MXC_ASSERT(MXC_TMR_GET_IDX(tmr) > 3);
236 
237     if (tmr == MXC_TMR4) {
238         MXC_GCR->pm &= ~MXC_F_GCR_PM_LPTMR0_WE;
239         MXC_PWRSEQ->lppwken &= ~MXC_F_PWRSEQ_LPPWKEN_LPTMR0;
240     } else {
241         MXC_GCR->pm &= ~MXC_F_GCR_PM_LPTMR1_WE;
242         MXC_PWRSEQ->lppwken &= ~MXC_F_PWRSEQ_LPPWKEN_LPTMR1;
243     }
244 }
245 
MXC_LP_EnableComparatorWakeup(mxc_adc_comp_t comp)246 void MXC_LP_EnableComparatorWakeup(mxc_adc_comp_t comp)
247 {
248     switch (comp) {
249     case MXC_ADC_COMP_0:
250         MXC_PWRSEQ->lppwkst |= MXC_F_PWRSEQ_LPPWKST_AINCOMP0;
251         MXC_PWRSEQ->lppwken |= MXC_F_PWRSEQ_LPPWKEN_AINCOMP0;
252         break;
253     case MXC_ADC_COMP_1:
254         MXC_PWRSEQ->lppwkst |= MXC_F_PWRSEQ_LPPWKST_AINCOMP1;
255         MXC_PWRSEQ->lppwken |= MXC_F_PWRSEQ_LPPWKEN_AINCOMP1;
256         break;
257     default:
258         return;
259     }
260     MXC_GCR->pm |= MXC_F_GCR_PM_AINCOMP_WE;
261 }
262 
MXC_LP_DisableComparatorWakeup(mxc_adc_comp_t comp)263 void MXC_LP_DisableComparatorWakeup(mxc_adc_comp_t comp)
264 {
265     switch (comp) {
266     case MXC_ADC_COMP_0:
267         MXC_PWRSEQ->lppwken &= ~MXC_F_PWRSEQ_LPPWKEN_AINCOMP0;
268         break;
269     case MXC_ADC_COMP_1:
270         MXC_PWRSEQ->lppwken &= ~MXC_F_PWRSEQ_LPPWKEN_AINCOMP1;
271         break;
272     default:
273         return;
274     }
275     MXC_GCR->pm &= ~MXC_F_GCR_PM_AINCOMP_WE;
276 }
277 
278 // TODO(all): Add MXC_LP_Enable/DisableUARTWakeup functions for LP UARTs.
279 
MXC_LP_ConfigDeepSleepClocks(uint32_t mask)280 int MXC_LP_ConfigDeepSleepClocks(uint32_t mask)
281 {
282     if (!(mask & (MXC_F_GCR_PM_IBRO_PD | MXC_F_GCR_PM_IPO_PD | MXC_F_GCR_PM_ERFO_PD))) {
283         return E_BAD_PARAM;
284     }
285 
286     MXC_GCR->pm |= mask;
287     return E_NO_ERROR;
288 }
289 
MXC_LP_SysRam0LightSleepEnable(void)290 void MXC_LP_SysRam0LightSleepEnable(void)
291 {
292     MXC_GCR->memctrl |= MXC_F_GCR_MEMCTRL_RAM0LS_EN;
293 }
294 
MXC_LP_SysRam1LightSleepEnable(void)295 void MXC_LP_SysRam1LightSleepEnable(void)
296 {
297     MXC_GCR->memctrl |= MXC_F_GCR_MEMCTRL_RAM1LS_EN;
298 }
299 
MXC_LP_SysRam2LightSleepEnable(void)300 void MXC_LP_SysRam2LightSleepEnable(void)
301 {
302     MXC_GCR->memctrl |= MXC_F_GCR_MEMCTRL_RAM2LS_EN;
303 }
304 
MXC_LP_SysRam3LightSleepEnable(void)305 void MXC_LP_SysRam3LightSleepEnable(void)
306 {
307     MXC_GCR->memctrl |= MXC_F_GCR_MEMCTRL_RAM3LS_EN;
308 }
309 
MXC_LP_ICache0LightSleepEnable(void)310 void MXC_LP_ICache0LightSleepEnable(void)
311 {
312     MXC_GCR->memctrl |= MXC_F_GCR_MEMCTRL_ICC0LS_EN;
313 }
314 
MXC_LP_ROMLightSleepEnable(void)315 void MXC_LP_ROMLightSleepEnable(void)
316 {
317     MXC_GCR->memctrl |= MXC_F_GCR_MEMCTRL_ROMLS_EN;
318 }
319 
MXC_LP_SysRam0LightSleepDisable(void)320 void MXC_LP_SysRam0LightSleepDisable(void)
321 {
322     MXC_GCR->memctrl &= ~MXC_F_GCR_MEMCTRL_RAM0LS_EN;
323 }
324 
MXC_LP_SysRam1LightSleepDisable(void)325 void MXC_LP_SysRam1LightSleepDisable(void)
326 {
327     MXC_GCR->memctrl &= ~MXC_F_GCR_MEMCTRL_RAM1LS_EN;
328 }
329 
MXC_LP_SysRam2LightSleepDisable(void)330 void MXC_LP_SysRam2LightSleepDisable(void)
331 {
332     MXC_GCR->memctrl &= ~MXC_F_GCR_MEMCTRL_RAM2LS_EN;
333 }
334 
MXC_LP_SysRam3LightSleepDisable(void)335 void MXC_LP_SysRam3LightSleepDisable(void)
336 {
337     MXC_GCR->memctrl &= ~MXC_F_GCR_MEMCTRL_RAM3LS_EN;
338 }
339 
MXC_LP_ICache0LightSleepDisable(void)340 void MXC_LP_ICache0LightSleepDisable(void)
341 {
342     MXC_GCR->memctrl &= ~MXC_F_GCR_MEMCTRL_ICC0LS_EN;
343 }
344 
MXC_LP_ROMLightSleepDisable(void)345 void MXC_LP_ROMLightSleepDisable(void)
346 {
347     MXC_GCR->memctrl &= ~MXC_F_GCR_MEMCTRL_ROMLS_EN;
348 }
349 
MXC_LP_SysRam0Shutdown(void)350 void MXC_LP_SysRam0Shutdown(void)
351 {
352     MXC_PWRSEQ->lpmemsd |= MXC_F_PWRSEQ_LPMEMSD_RAM0;
353 }
354 
MXC_LP_SysRam0PowerUp(void)355 void MXC_LP_SysRam0PowerUp(void)
356 {
357     MXC_PWRSEQ->lpmemsd &= ~MXC_F_PWRSEQ_LPMEMSD_RAM0;
358 }
359 
MXC_LP_SysRam1Shutdown(void)360 void MXC_LP_SysRam1Shutdown(void)
361 {
362     MXC_PWRSEQ->lpmemsd |= MXC_F_PWRSEQ_LPMEMSD_RAM1;
363 }
364 
MXC_LP_SysRam1PowerUp(void)365 void MXC_LP_SysRam1PowerUp(void)
366 {
367     MXC_PWRSEQ->lpmemsd &= ~MXC_F_PWRSEQ_LPMEMSD_RAM1;
368 }
369 
MXC_LP_SysRam2Shutdown(void)370 void MXC_LP_SysRam2Shutdown(void)
371 {
372     MXC_PWRSEQ->lpmemsd |= MXC_F_PWRSEQ_LPMEMSD_RAM2;
373 }
374 
MXC_LP_SysRam2PowerUp(void)375 void MXC_LP_SysRam2PowerUp(void)
376 {
377     MXC_PWRSEQ->lpmemsd &= ~MXC_F_PWRSEQ_LPMEMSD_RAM2;
378 }
379 
MXC_LP_SysRam3Shutdown(void)380 void MXC_LP_SysRam3Shutdown(void)
381 {
382     MXC_PWRSEQ->lpmemsd |= MXC_F_PWRSEQ_LPMEMSD_RAM3;
383 }
384 
MXC_LP_SysRam3PowerUp(void)385 void MXC_LP_SysRam3PowerUp(void)
386 {
387     MXC_PWRSEQ->lpmemsd &= ~MXC_F_PWRSEQ_LPMEMSD_RAM3;
388 }
389