1 // SPDX-License-Identifier: BSD-3-Clause
3 /******************************************************************************
5 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
7 ******************************************************************************/
11 #include "driverlib.h"
14 * Wrapper function for the CPSID instruction.
15 * Returns the state of PRIMASK on entry.
17 uint32_t __attribute__((naked)) cpu_cpsid(void)
21 /* Read PRIMASK and disable interrupts. */
22 __asm(" mrs r0, PRIMASK\n"
28 * The return is handled in the inline assembly, but the compiler will
29 * still complain if there is not an explicit return here (despite the fact
30 * that this does not result in any code being produced because of the
36 /* Wrapper function for the CPUWFI instruction. */
37 void __attribute__((naked)) cpu_wfi(void)
39 /* Wait for the next interrupt. */
44 /* Power Control Module APIs */
47 static bool __pcm_set_core_voltage_level_advanced(uint_fast8_t voltage_level,
48 uint32_t time_out, bool blocking)
51 uint8_t current_voltage_level;
55 /* Getting current power mode and level */
56 power_mode = pcm_get_power_mode();
57 current_voltage_level = pcm_get_core_voltage_level();
59 bool_timeout = time_out > 0 ? true : false;
61 /* If we are already at the power mode they requested, return */
62 if (current_voltage_level == voltage_level)
65 while (current_voltage_level != voltage_level) {
67 reg_value = PCM->CTL0;
69 switch (pcm_get_power_state()) {
70 case PCM_AM_LF_VCORE1:
71 case PCM_AM_DCDC_VCORE1:
72 case PCM_AM_LDO_VCORE0:
73 PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1)
74 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
76 case PCM_AM_LF_VCORE0:
77 case PCM_AM_DCDC_VCORE0:
78 case PCM_AM_LDO_VCORE1:
79 PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0)
80 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
87 while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) {
88 if (bool_timeout && !(--time_out))
94 current_voltage_level = pcm_get_core_voltage_level();
97 /* Changing the power mode if we are stuck in LDO mode */
98 if (power_mode != pcm_get_power_mode()) {
99 if (power_mode == PCM_DCDC_MODE)
100 return pcm_set_power_mode(PCM_DCDC_MODE);
102 return pcm_set_power_mode(PCM_LF_MODE);
108 bool pcm_set_core_voltage_level(uint_fast8_t voltage_level)
110 return __pcm_set_core_voltage_level_advanced(voltage_level, 0, true);
113 uint8_t pcm_get_power_mode(void)
115 uint8_t current_power_state;
117 current_power_state = pcm_get_power_state();
119 switch (current_power_state) {
120 case PCM_AM_LDO_VCORE0:
121 case PCM_AM_LDO_VCORE1:
122 case PCM_LPM0_LDO_VCORE0:
123 case PCM_LPM0_LDO_VCORE1:
126 case PCM_AM_DCDC_VCORE0:
127 case PCM_AM_DCDC_VCORE1:
128 case PCM_LPM0_DCDC_VCORE0:
129 case PCM_LPM0_DCDC_VCORE1:
130 return PCM_DCDC_MODE;
131 case PCM_LPM0_LF_VCORE0:
132 case PCM_LPM0_LF_VCORE1:
133 case PCM_AM_LF_VCORE1:
134 case PCM_AM_LF_VCORE0:
139 uint8_t pcm_get_core_voltage_level(void)
141 uint8_t current_power_state = pcm_get_power_state();
143 switch (current_power_state) {
144 case PCM_AM_LDO_VCORE0:
145 case PCM_AM_DCDC_VCORE0:
146 case PCM_AM_LF_VCORE0:
147 case PCM_LPM0_LDO_VCORE0:
148 case PCM_LPM0_DCDC_VCORE0:
149 case PCM_LPM0_LF_VCORE0:
152 case PCM_AM_LDO_VCORE1:
153 case PCM_AM_DCDC_VCORE1:
154 case PCM_AM_LF_VCORE1:
155 case PCM_LPM0_LDO_VCORE1:
156 case PCM_LPM0_DCDC_VCORE1:
157 case PCM_LPM0_LF_VCORE1:
160 return PCM_VCORELPM3;
164 static bool __pcm_set_power_mode_advanced(uint_fast8_t power_mode,
165 uint32_t time_out, bool blocking)
167 uint8_t current_power_mode;
168 uint8_t current_power_state;
172 /* Getting Current Power Mode */
173 current_power_mode = pcm_get_power_mode();
175 /* If the power mode being set it the same as the current mode, return */
176 if (power_mode == current_power_mode)
179 current_power_state = pcm_get_power_state();
181 bool_timeout = time_out > 0 ? true : false;
183 /* Go through the while loop while we haven't achieved the power mode */
184 while (current_power_mode != power_mode) {
186 reg_value = PCM->CTL0;
188 switch (current_power_state) {
189 case PCM_AM_DCDC_VCORE0:
190 case PCM_AM_LF_VCORE0:
191 PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0
192 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
194 case PCM_AM_LF_VCORE1:
195 case PCM_AM_DCDC_VCORE1:
196 PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1
197 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
199 case PCM_AM_LDO_VCORE1: {
200 if (power_mode == PCM_DCDC_MODE) {
201 PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1
202 | (reg_value & ~(PCM_CTL0_KEY_MASK
203 | PCM_CTL0_AMR_MASK)));
204 } else if (power_mode == PCM_LF_MODE) {
205 PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1
206 | (reg_value & ~(PCM_CTL0_KEY_MASK
207 | PCM_CTL0_AMR_MASK)));
212 case PCM_AM_LDO_VCORE0: {
213 if (power_mode == PCM_DCDC_MODE) {
214 PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0
215 | (reg_value & ~(PCM_CTL0_KEY_MASK
216 | PCM_CTL0_AMR_MASK)));
217 } else if (power_mode == PCM_LF_MODE) {
218 PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0
219 | (reg_value & ~(PCM_CTL0_KEY_MASK
220 | PCM_CTL0_AMR_MASK)));
230 while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) {
231 if (bool_timeout && !(--time_out))
237 current_power_mode = pcm_get_power_mode();
238 current_power_state = pcm_get_power_state();
244 bool pcm_set_power_mode(uint_fast8_t power_mode)
246 return __pcm_set_power_mode_advanced(power_mode, 0, true);
249 static bool __pcm_set_power_state_advanced(uint_fast8_t power_state,
250 uint32_t timeout, bool blocking)
252 uint8_t current_power_state;
253 current_power_state = pcm_get_power_state();
255 if (current_power_state == power_state)
258 switch (power_state) {
259 case PCM_AM_LDO_VCORE0:
260 return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
261 blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE,
263 case PCM_AM_LDO_VCORE1:
264 return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
265 blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE,
267 case PCM_AM_DCDC_VCORE0:
268 return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
269 blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE,
271 case PCM_AM_DCDC_VCORE1:
272 return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
273 blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE,
275 case PCM_AM_LF_VCORE0:
276 return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
277 blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE,
279 case PCM_AM_LF_VCORE1:
280 return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
281 blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE,
283 case PCM_LPM0_LDO_VCORE0:
284 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
285 blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE,
288 return pcm_goto_lpm0();
289 case PCM_LPM0_LDO_VCORE1:
290 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
291 blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE,
294 return pcm_goto_lpm0();
295 case PCM_LPM0_DCDC_VCORE0:
296 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
297 blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE,
300 return pcm_goto_lpm0();
301 case PCM_LPM0_DCDC_VCORE1:
302 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
303 blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE,
306 return pcm_goto_lpm0();
307 case PCM_LPM0_LF_VCORE0:
308 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
309 blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE,
312 return pcm_goto_lpm0();
313 case PCM_LPM0_LF_VCORE1:
314 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
315 blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE,
318 return pcm_goto_lpm0();
320 return pcm_goto_lpm3();
322 return pcm_goto_lpm4();
324 return pcm_shutdown_device(PCM_LPM45);
325 case PCM_LPM35_VCORE0:
326 return pcm_shutdown_device(PCM_LPM35_VCORE0);
334 bool pcm_set_power_state(uint_fast8_t power_state)
336 return __pcm_set_power_state_advanced(power_state, 0, true);
339 bool pcm_shutdown_device(uint32_t shutdown_mode)
341 uint32_t shutdown_mode_bits = (shutdown_mode == PCM_LPM45) ?
342 PCM_CTL0_LPMR_12 : PCM_CTL0_LPMR_10;
344 /* If a power transition is occurring, return false */
345 if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
348 /* Initiating the shutdown */
349 SCB->SCR |= SCB_SCR_SLEEPDEEP_MSK;
351 PCM->CTL0 = (PCM_KEY | shutdown_mode_bits
352 | (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)));
359 bool pcm_goto_lpm4(void)
361 /* Disabling RTC_C and WDT_A */
365 /* LPM4 is just LPM3 with WDT_A/RTC_C disabled... */
366 return pcm_goto_lpm3();
369 bool pcm_goto_lpm0(void)
371 /* If we are in the middle of a state transition, return false */
372 if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
375 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_MSK;
382 bool pcm_goto_lpm3(void)
384 uint_fast8_t current_power_state;
385 uint_fast8_t current_power_mode;
387 /* If we are in the middle of a state transition, return false */
388 if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
391 /* If we are in the middle of a shutdown, return false */
392 if ((PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_10
393 || (PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_12)
396 current_power_mode = pcm_get_power_mode();
397 current_power_state = pcm_get_power_state();
399 if (current_power_mode == PCM_DCDC_MODE)
400 pcm_set_power_mode(PCM_LDO_MODE);
402 /* Clearing the SDR */
404 (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)) | PCM_KEY;
406 /* Setting the sleep deep bit */
407 SCB->SCR |= SCB_SCR_SLEEPDEEP_MSK;
411 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_MSK;
413 return pcm_set_power_state(current_power_state);
416 uint8_t pcm_get_power_state(void)
418 return (PCM->CTL0 & PCM_CTL0_CPM_MASK) >> PCM_CTL0_CPM_OFS;
423 /* Real Time Clock APIs */
426 void rtc_c_hold_clock(void)
428 RTC_C->CTL0 = (RTC_C->CTL0 & ~RTC_C_CTL0_KEY_MASK) | RTC_C_KEY;
429 BITBAND_PERI(RTC_C->CTL13, RTC_C_CTL13_HOLD_OFS) = 1;
430 BITBAND_PERI(RTC_C->CTL0, RTC_C_CTL0_KEY_OFS) = 0;
435 /* Watch Dog Timer APIs */
438 void wdt_a_hold_timer(void)
441 uint8_t new_wdt_status = (WDT_A->CTL | WDT_A_CTL_HOLD);
443 WDT_A->CTL = WDT_A_CTL_PW + new_wdt_status;