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 #include "mxc_device.h"
21 #include "mxc_assert.h"
22 #include "mxc_sys.h"
23 #include "gcr_regs.h"
24 #include "mcr_regs.h"
25 #include "lp.h"
26 #include "lpcmp.h"
27 
28 #ifndef __riscv
29 /* ARM */
30 #define SET_SLEEPDEEP(X) (SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk)
31 #define CLR_SLEEPDEEP(X) (SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk)
32 #else
33 /* RISCV */
34 /* These bits do not exist for RISCV core */
35 #define SET_SLEEPDEEP(X)
36 #define CLR_SLEEPDEEP(X)
37 #endif
38 
MXC_LP_EnterSleepMode(void)39 void MXC_LP_EnterSleepMode(void)
40 {
41     MXC_LP_ClearWakeStatus();
42 
43     /* Clear SLEEPDEEP bit */
44     CLR_SLEEPDEEP();
45 
46     /* Go into Sleep mode and wait for an interrupt to wake the processor */
47     __WFI();
48 }
49 
MXC_LP_EnterLowPowerMode(void)50 void MXC_LP_EnterLowPowerMode(void)
51 {
52     MXC_LP_ClearWakeStatus();
53     MXC_MCR->ctrl |= MXC_F_MCR_CTRL_ERTCO_EN; // Enabled for deep sleep mode
54 
55     /* Set SLEEPDEEP bit */
56     SET_SLEEPDEEP();
57 
58     /* Go into low power mode and wait for an interrupt to wake the processor */
59     MXC_GCR->pm |= MXC_S_GCR_PM_MODE_LPM;
60     __WFI();
61 }
62 
MXC_LP_EnterMicroPowerMode(void)63 void MXC_LP_EnterMicroPowerMode(void)
64 {
65     MXC_LP_ClearWakeStatus();
66     MXC_MCR->ctrl |= MXC_F_MCR_CTRL_ERTCO_EN; // Enabled for deep sleep mode
67 
68     /* Set SLEEPDEEP bit */
69     SET_SLEEPDEEP();
70 
71     /* Go into Deepsleep mode and wait for an interrupt to wake the processor */
72     MXC_GCR->pm |= MXC_S_GCR_PM_MODE_UPM; // UPM mode
73     __WFI();
74 }
75 
MXC_LP_EnterStandbyMode(void)76 void MXC_LP_EnterStandbyMode(void)
77 {
78     MXC_LP_ClearWakeStatus();
79     MXC_MCR->ctrl |= MXC_F_MCR_CTRL_ERTCO_EN; // Enabled for deep sleep mode
80 
81     /* Set SLEEPDEEP bit */
82     SET_SLEEPDEEP();
83 
84     /* Go into standby mode and wait for an interrupt to wake the processor */
85     MXC_GCR->pm |= MXC_S_GCR_PM_MODE_STANDBY; // standby mode
86     __WFI();
87 }
88 
MXC_LP_EnterBackupMode(void)89 void MXC_LP_EnterBackupMode(void)
90 {
91     MXC_LP_ClearWakeStatus();
92 
93     MXC_GCR->pm &= ~MXC_F_GCR_PM_MODE;
94     MXC_GCR->pm |= MXC_S_GCR_PM_MODE_BACKUP;
95 
96     while (1) {}
97     // Should never reach this line - device will jump to backup vector on exit from background mode.
98 }
99 
MXC_LP_EnterPowerDownMode(void)100 void MXC_LP_EnterPowerDownMode(void)
101 {
102     MXC_GCR->pm &= ~MXC_F_GCR_PM_MODE;
103     MXC_GCR->pm |= MXC_S_GCR_PM_MODE_POWERDOWN;
104 
105     while (1) {}
106     // Should never reach this line - device will reset on exit from shutdown mode.
107 }
108 
MXC_LP_SetOVR(mxc_lp_ovr_t ovr)109 void MXC_LP_SetOVR(mxc_lp_ovr_t ovr)
110 {
111     //not supported yet
112 }
113 
MXC_LP_BandgapOn(void)114 void MXC_LP_BandgapOn(void)
115 {
116     MXC_PWRSEQ->lpcn &= ~MXC_F_PWRSEQ_LPCN_BG_DIS;
117 }
118 
MXC_LP_BandgapOff(void)119 void MXC_LP_BandgapOff(void)
120 {
121     MXC_PWRSEQ->lpcn |= MXC_F_PWRSEQ_LPCN_BG_DIS;
122 }
123 
MXC_LP_BandgapIsOn(void)124 int MXC_LP_BandgapIsOn(void)
125 {
126     return (MXC_PWRSEQ->lpcn & MXC_F_PWRSEQ_LPCN_BG_DIS);
127 }
128 
MXC_LP_ClearWakeStatus(void)129 void MXC_LP_ClearWakeStatus(void)
130 {
131     /* Write 1 to clear */
132     MXC_PWRSEQ->lpwkst0 = 0xFFFFFFFF;
133     MXC_PWRSEQ->lpwkst1 = 0xFFFFFFFF;
134     MXC_PWRSEQ->lpwkst2 = 0xFFFFFFFF;
135     MXC_PWRSEQ->lpwkst3 = 0xFFFFFFFF;
136     MXC_PWRSEQ->lppwst = 0xFFFFFFFF;
137 }
138 
MXC_LP_EnableGPIOWakeup(mxc_gpio_cfg_t * wu_pins)139 void MXC_LP_EnableGPIOWakeup(mxc_gpio_cfg_t *wu_pins)
140 {
141     MXC_GCR->pm |= MXC_F_GCR_PM_GPIO_WE;
142 
143     switch (1 << MXC_GPIO_GET_IDX(wu_pins->port)) {
144     case MXC_GPIO_PORT_0:
145         MXC_PWRSEQ->lpwken0 |= wu_pins->mask;
146         break;
147 
148     case MXC_GPIO_PORT_1:
149         MXC_PWRSEQ->lpwken1 |= wu_pins->mask;
150         break;
151     case MXC_GPIO_PORT_2:
152         MXC_PWRSEQ->lpwken2 |= wu_pins->mask;
153         break;
154     case MXC_GPIO_PORT_3:
155         MXC_PWRSEQ->lpwken3 |= wu_pins->mask;
156         break;
157     }
158 }
159 
MXC_LP_DisableGPIOWakeup(mxc_gpio_cfg_t * wu_pins)160 void MXC_LP_DisableGPIOWakeup(mxc_gpio_cfg_t *wu_pins)
161 {
162     switch (1 << MXC_GPIO_GET_IDX(wu_pins->port)) {
163     case MXC_GPIO_PORT_0:
164         MXC_PWRSEQ->lpwken0 &= ~wu_pins->mask;
165         break;
166 
167     case MXC_GPIO_PORT_1:
168         MXC_PWRSEQ->lpwken1 &= ~wu_pins->mask;
169         break;
170     case MXC_GPIO_PORT_2:
171         MXC_PWRSEQ->lpwken2 &= ~wu_pins->mask;
172         break;
173     case MXC_GPIO_PORT_3:
174         MXC_PWRSEQ->lpwken3 &= ~wu_pins->mask;
175         break;
176     }
177 
178     if (MXC_PWRSEQ->lpwken3 == 0 && MXC_PWRSEQ->lpwken2 == 0 && MXC_PWRSEQ->lpwken1 == 0 &&
179         MXC_PWRSEQ->lpwken0 == 0) {
180         MXC_GCR->pm &= ~MXC_F_GCR_PM_GPIO_WE;
181     }
182 }
183 
MXC_LP_EnableRTCAlarmWakeup(void)184 void MXC_LP_EnableRTCAlarmWakeup(void)
185 {
186     MXC_GCR->pm |= MXC_F_GCR_PM_RTC_WE;
187 }
188 
MXC_LP_DisableRTCAlarmWakeup(void)189 void MXC_LP_DisableRTCAlarmWakeup(void)
190 {
191     MXC_GCR->pm &= ~MXC_F_GCR_PM_RTC_WE;
192 }
193 
MXC_LP_EnableTimerWakeup(mxc_tmr_regs_t * tmr)194 void MXC_LP_EnableTimerWakeup(mxc_tmr_regs_t *tmr)
195 {
196     MXC_ASSERT(MXC_TMR_GET_IDX(tmr) > 3);
197 
198     if (tmr == MXC_TMR4) {
199         MXC_PWRSEQ->lppwen |= MXC_F_PWRSEQ_LPPWEN_TMR4;
200     } else {
201         MXC_PWRSEQ->lppwen |= MXC_F_PWRSEQ_LPPWEN_TMR5;
202     }
203 }
204 
MXC_LP_DisableTimerWakeup(mxc_tmr_regs_t * tmr)205 void MXC_LP_DisableTimerWakeup(mxc_tmr_regs_t *tmr)
206 {
207     MXC_ASSERT(MXC_TMR_GET_IDX(tmr) > 3);
208 
209     if (tmr == MXC_TMR4) {
210         MXC_PWRSEQ->lppwen &= ~MXC_F_PWRSEQ_LPPWEN_TMR4;
211     } else {
212         MXC_PWRSEQ->lppwen &= ~MXC_F_PWRSEQ_LPPWEN_TMR5;
213     }
214 }
215 
MXC_LP_EnableWUTAlarmWakeup(void)216 void MXC_LP_EnableWUTAlarmWakeup(void)
217 {
218     MXC_GCR->pm |= MXC_F_GCR_PM_WUT_WE;
219 }
220 
MXC_LP_DisableWUTAlarmWakeup(void)221 void MXC_LP_DisableWUTAlarmWakeup(void)
222 {
223     MXC_GCR->pm &= ~MXC_F_GCR_PM_WUT_WE;
224 }
225 
MXC_LP_EnableLPCMPWakeup(mxc_lpcmp_cmpsel_t cmp)226 void MXC_LP_EnableLPCMPWakeup(mxc_lpcmp_cmpsel_t cmp)
227 {
228     MXC_ASSERT((cmp >= MXC_LPCMP_CMP0) && (cmp <= MXC_LPCMP_CMP3));
229 
230     if (cmp == MXC_LPCMP_CMP0) {
231         MXC_PWRSEQ->lppwen |= MXC_F_PWRSEQ_LPPWEN_AINCOMP0;
232     } else {
233         MXC_PWRSEQ->lppwen |= MXC_F_PWRSEQ_LPPWEN_LPCMP;
234     }
235 }
236 
MXC_LP_DisableLPCMPWakeup(mxc_lpcmp_cmpsel_t cmp)237 void MXC_LP_DisableLPCMPWakeup(mxc_lpcmp_cmpsel_t cmp)
238 {
239     MXC_ASSERT((cmp >= MXC_LPCMP_CMP0) && (cmp <= MXC_LPCMP_CMP3));
240 
241     if (cmp == MXC_LPCMP_CMP0) {
242         MXC_PWRSEQ->lppwen &= ~MXC_F_PWRSEQ_LPPWEN_AINCOMP0;
243     } else {
244         MXC_PWRSEQ->lppwen &= ~MXC_F_PWRSEQ_LPPWEN_LPCMP;
245     }
246 }
247 
MXC_LP_ConfigDeepSleepClocks(uint32_t mask)248 int MXC_LP_ConfigDeepSleepClocks(uint32_t mask)
249 {
250     if (!(mask & (MXC_F_GCR_PM_IBRO_PD | MXC_F_GCR_PM_IPO_PD))) {
251         return E_BAD_PARAM;
252     }
253 
254     MXC_GCR->pm |= mask;
255     return E_NO_ERROR;
256 }
257