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