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