1 /***************************************************************************//**
2  * @file
3  * @brief Power Manager API implementation.
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "sl_power_manager.h"
32 #include "sl_power_manager_config.h"
33 #include "sli_power_manager_private.h"
34 #include "sli_power_manager.h"
35 #include "sli_sleeptimer.h"
36 #include "sl_assert.h"
37 #include "sl_atomic.h"
38 
39 #include "em_device.h"
40 #if !defined(_SILICON_LABS_32B_SERIES_3)
41 #include "em_emu.h"
42 #endif
43 
44 #include <stdlib.h>
45 #include <stdint.h>
46 #include <string.h>
47 
48 /*******************************************************************************
49  *********************************   DEFINES   *********************************
50  ******************************************************************************/
51 
52 // Default overhead value for the wake-up time used for the schedule wake-up
53 // functionality.
54 #define SCHEDULE_WAKEUP_DEFAULT_RESTORE_TIME_OVERHEAD_TICK  0
55 
56 // Determine if the device supports EM1P
57 #if !defined(SLI_DEVICE_SUPPORTS_EM1P) && defined(_SILICON_LABS_32B_SERIES_2_CONFIG) && _SILICON_LABS_32B_SERIES_2_CONFIG >= 2
58 #define SLI_DEVICE_SUPPORTS_EM1P
59 #endif
60 
61 /*******************************************************************************
62  ***************************  LOCAL VARIABLES   ********************************
63  ******************************************************************************/
64 
65 // Initialization flag.
66 static bool is_initialized = false;
67 
68 // Current active energy mode.
69 static sl_power_manager_em_t current_em = SL_POWER_MANAGER_EM0;
70 
71 // Events subscribers lists
72 static sl_slist_node_t *power_manager_em_transition_event_list = NULL;
73 
74 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
75 // Store the sleeptimer module clock frequency for conversion calculation
76 static uint32_t sleeptimer_frequency;
77 
78 // Table of energy modes counters. Each counter indicates the presence (not zero)
79 // or absence (zero) of requirements on a given energy mode. The table doesn't
80 // contain requirement on EM0.
81 static uint8_t requirement_em_table[SLI_POWER_MANAGER_EM_TABLE_SIZE] = {
82   0,  // EM1 requirement counter
83   0,  // EM2 requirement counter
84 };
85 
86 // Counter variable to save the number of High Accuracy HF clock requirements requested.
87 uint8_t requirement_high_accuracy_hf_clock_counter = 0;
88 
89 #ifdef SLI_DEVICE_SUPPORTS_EM1P
90 // Variable to indicate if the High Accuracy HF clock requirements count is back to zero.
91 bool requirement_high_accuracy_hf_clock_back_to_zero = false;
92 #endif
93 
94 // Saved energy mode we are coming from when waiting for HFXO ready.
95 static sl_power_manager_em_t waiting_clock_restore_from_em = SL_POWER_MANAGER_EM0;
96 
97 // Flag indicating if we are sleeping, waiting for the HF clock restore
98 static bool is_sleeping_waiting_for_clock_restore = false;
99 
100 // Flag indicating if the system states (clocks) are saved and should be restored
101 static bool is_states_saved = false;
102 
103 // Timer that it is used for enabling the clock for the scheduled wakeup
104 static sl_sleeptimer_timer_handle_t clock_wakeup_timer_handle = { 0 };
105 
106 // Store if requirement on EM1 has been added before sleeping;
107 // i.e. only possible if sleeping for less than minimum off time
108 static bool requirement_on_em1_added = false;
109 
110 // Threshold delay in sleeptimer ticks indicating the minimum time required
111 // to make the shut down of external high frequency oscillator worthwhile before
112 // the next synchronous high frequency oscillator requirement. Shorter than this
113 // delay, the power gain of shutting down is invalidated.
114 uint32_t high_frequency_min_offtime_tick = 0;
115 
116 // Store the configuration overhead value in sleeptimer tick to add/remove to the wake-up time.
117 int32_t wakeup_time_config_overhead_tick = 0;
118 
119 static bool is_hf_x_oscillator_not_preserved;
120 
121 // Store if we are currently waiting for HF clock restoration to finish
122 static bool is_actively_waiting_for_clock_restore = false;
123 
124 // Indicates if the clock restore was completed from the HFXO ISR
125 static bool is_restored_from_hfxo_isr = false;
126 static bool is_restored_from_hfxo_isr_internal = false;
127 #endif
128 
129 /*
130  *********************************************************************************************************
131  *                                           HOOK REFERENCES
132  *********************************************************************************************************
133  */
134 
135 bool sl_power_manager_sleep_on_isr_exit(void);
136 
137 // Callback to application after wakeup but before restoring interrupts.
138 // For internal Silicon Labs use only
139 __WEAK void sli_power_manager_on_wakeup(void);
140 
141 // Hook that can be used by the log outputer to suspend transmission of logs
142 // in case it would require energy mode changes while in the sleep loop.
143 __WEAK void sli_power_manager_suspend_log_transmission(void);
144 
145 // Hook that can be used by the log outputer to resume transmission of logs.
146 __WEAK void sli_power_manager_resume_log_transmission(void);
147 
148 // Callback to notify possible transition from EM1P to EM2.
149 // For internal Silicon Labs use only
150 #ifdef SLI_DEVICE_SUPPORTS_EM1P
151 __WEAK void sli_power_manager_em1p_to_em2_notification(void);
152 #endif
153 
154 /***************************************************************************//**
155  * Mandatory callback that allows to cancel sleeping action.
156  ******************************************************************************/
157 bool sl_power_manager_is_ok_to_sleep(void);
158 
159 /*******************************************************************************
160  **************************   LOCAL FUNCTIONS   ********************************
161  ******************************************************************************/
162 
163 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
164 static sl_power_manager_em_t get_lowest_em(void);
165 
166 static void evaluate_wakeup(sl_power_manager_em_t to);
167 
168 static void update_em1_requirement(bool add);
169 
170 static void on_clock_wakeup_timeout(sl_sleeptimer_timer_handle_t *handle,
171                                     void *data);
172 
173 static void clock_restore_and_wait(void);
174 
175 static void clock_restore(void);
176 #endif
177 
178 static void power_manager_notify_em_transition(sl_power_manager_em_t from,
179                                                sl_power_manager_em_t to);
180 
181 // Use PriMask to enter critical section by disabling interrupts.
182 static CORE_irqState_t enter_critical_with_primask();
183 
184 // Exit critical section by re-enabling interrupts in PriMask.
185 static void exit_critical_with_primask(CORE_irqState_t primask_state);
186 
187 /*******************************************************************************
188  **************************   GLOBAL FUNCTIONS   *******************************
189  ******************************************************************************/
190 
191 /***************************************************************************//**
192  * Initialize Power Manager module.
193  ******************************************************************************/
sl_power_manager_init(void)194 sl_status_t sl_power_manager_init(void)
195 {
196   CORE_DECLARE_IRQ_STATE;
197 
198   CORE_ENTER_CRITICAL();
199   if (!is_initialized) {
200     sl_status_t status = SL_STATUS_OK;
201 
202     // Initialize Sleeptimer module in case not already done.
203     status = sl_sleeptimer_init();
204     if (status != SL_STATUS_OK) {
205       CORE_EXIT_CRITICAL();
206       return status;
207     }
208 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT) \
209     && !defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
210     // Additional Sleeptimer HW configuration if the "power_manager_deepsleep" component is used
211     sli_sleeptimer_hal_power_manager_integration_init();
212 #endif
213 
214   #if (SL_POWER_MANAGER_DEBUG == 1)
215     sli_power_manager_debug_init();
216   #endif
217     sl_slist_init(&power_manager_em_transition_event_list);
218 
219 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
220     // If lowest energy mode is not restricted to EM1, determine and set lowest energy mode
221     #if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
222       sli_sleeptimer_set_pm_em_requirement();
223     #endif
224     // Set the default wake-up overhead value
225     wakeup_time_config_overhead_tick = SCHEDULE_WAKEUP_DEFAULT_RESTORE_TIME_OVERHEAD_TICK;
226 
227     // Get the sleeptimer frequency
228     sleeptimer_frequency = sl_sleeptimer_get_timer_frequency();
229 #endif
230   }
231 
232   // Do all necessary hardware initialization.
233   sli_power_manager_init_hardware();
234 
235 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
236   // Set the HF minimum offtime in sleeptimer ticks
237   high_frequency_min_offtime_tick = sli_power_manager_get_default_high_frequency_minimum_offtime();
238 #endif
239 
240   is_initialized = true;
241   CORE_EXIT_CRITICAL();
242 
243   return SL_STATUS_OK;
244 }
245 
246 /***************************************************************************//**
247  * Sleep at the lowest allowed energy mode.
248  ******************************************************************************/
sl_power_manager_sleep(void)249 void sl_power_manager_sleep(void)
250 {
251   CORE_irqState_t primask_state;
252 
253   primask_state = enter_critical_with_primask();
254 
255   sli_power_manager_suspend_log_transmission();
256 
257   if (sl_power_manager_is_ok_to_sleep() != true) {
258     sli_power_manager_resume_log_transmission();
259     exit_critical_with_primask(primask_state);
260     return;
261   }
262 
263 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
264   sl_power_manager_em_t lowest_em;
265 
266   // Go to another energy mode (same, higher to lower or lower to higher)
267   do {
268     // Remove any previous EM1 requirement added internally by the power manager itself
269     if (requirement_on_em1_added) {
270       update_em1_requirement(false);
271       requirement_on_em1_added = false;
272     }
273 
274     lowest_em = get_lowest_em();
275     evaluate_wakeup(lowest_em);
276     lowest_em = get_lowest_em();  // Reevaluate as a requirement can be added from evaluate_wakeup()
277 
278     if ((lowest_em >= SL_POWER_MANAGER_EM2)
279         && (is_states_saved == false)) {
280       sli_power_manager_save_states();
281     }
282 
283     // Notify listeners if transition to another energy mode
284     if (lowest_em != current_em) {
285 #ifdef SLI_DEVICE_SUPPORTS_EM1P
286       requirement_high_accuracy_hf_clock_back_to_zero = false;
287 #endif
288       if (is_sleeping_waiting_for_clock_restore == false) {
289         // But only notify if we are not in the process of waiting for the HF oscillators restore.
290         power_manager_notify_em_transition(current_em, lowest_em);
291       }
292       current_em = lowest_em;           // Keep new active energy mode
293     }
294 
295 #ifdef SLI_DEVICE_SUPPORTS_EM1P
296     // Notification for possible transition from EM1P to EM2
297     // For internal Silicon Labs use only
298     if (requirement_high_accuracy_hf_clock_back_to_zero
299         && current_em == SL_POWER_MANAGER_EM2) {
300       requirement_high_accuracy_hf_clock_back_to_zero = false;
301       sli_power_manager_em1p_to_em2_notification();
302     }
303 #endif
304 
305     // Pre-sleep operations if any are necessary
306     if ((lowest_em >= SL_POWER_MANAGER_EM2)
307         && (is_states_saved == false)) {
308       // Only do pre-sleep operations if there is no requirement on High Accuracy Clock.
309       // Else we must not touch the clock tree.
310       if (requirement_high_accuracy_hf_clock_counter == 0) {
311         sli_power_manager_handle_pre_deepsleep_operations();
312         is_hf_x_oscillator_not_preserved = true;
313       }
314       is_states_saved = true;
315     }
316 
317     // Apply lowest reachable energy mode
318     sli_power_manager_apply_em(current_em);
319 
320     // In case we are waiting for the restore from an early wake-up,
321     // we put back the current EM to the one before the early wake-up to do the next notification correctly.
322     if (is_sleeping_waiting_for_clock_restore == true) {
323       current_em = waiting_clock_restore_from_em;
324     }
325 
326     // Notify consumer of wakeup while interrupts are still off
327     // For internal Silicon Labs use only
328     sli_power_manager_on_wakeup();
329 
330     exit_critical_with_primask(primask_state);
331     primask_state = enter_critical_with_primask();
332 
333     // In case the HF restore was completed from the HFXO ISR,
334     // and notification not done elsewhere, do it here
335     if (is_restored_from_hfxo_isr_internal == true) {
336       is_restored_from_hfxo_isr_internal = false;
337       if (current_em == waiting_clock_restore_from_em) {
338         current_em = SL_POWER_MANAGER_EM1;
339         power_manager_notify_em_transition(waiting_clock_restore_from_em, SL_POWER_MANAGER_EM1);
340       }
341     }
342 
343     // Stop the internal power manager sleeptimer.
344     sl_sleeptimer_stop_timer(&clock_wakeup_timer_handle);
345   } while (sl_power_manager_sleep_on_isr_exit() == true);
346 
347 #ifdef SLI_DEVICE_SUPPORTS_EM1P
348   requirement_high_accuracy_hf_clock_back_to_zero = false;
349 #endif
350 
351   if (is_states_saved == true) {
352     is_sleeping_waiting_for_clock_restore = false;
353     // Restore clocks
354     if (is_hf_x_oscillator_not_preserved) {
355       sli_power_manager_restore_high_freq_accuracy_clk();
356       is_hf_x_oscillator_not_preserved = false;
357     }
358     // If possible, go back to sleep in EM1 while waiting for HF accuracy restore
359     while (!sli_power_manager_is_high_freq_accuracy_clk_ready(false)) {
360       sli_power_manager_apply_em(SL_POWER_MANAGER_EM1);
361       exit_critical_with_primask(primask_state);
362       primask_state = enter_critical_with_primask();
363     }
364     sli_power_manager_restore_states();
365     is_states_saved = false;
366   }
367 
368   evaluate_wakeup(SL_POWER_MANAGER_EM0);
369 #else
370   current_em = SL_POWER_MANAGER_EM1;
371 
372   // Notify listeners of transition to EM1
373   power_manager_notify_em_transition(SL_POWER_MANAGER_EM0, SL_POWER_MANAGER_EM1);
374   do {
375     // Apply EM1 energy mode
376     sli_power_manager_apply_em(SL_POWER_MANAGER_EM1);
377 
378     exit_critical_with_primask(primask_state);
379     primask_state = enter_critical_with_primask();
380   } while (sl_power_manager_sleep_on_isr_exit() == true);
381 #endif
382 
383   // Indicate back to EM0
384   power_manager_notify_em_transition(current_em, SL_POWER_MANAGER_EM0);
385   current_em = SL_POWER_MANAGER_EM0;
386 
387   sli_power_manager_resume_log_transmission();
388 
389   exit_critical_with_primask(primask_state);
390 }
391 
392 /***************************************************************************//**
393  * Updates requirement on the given energy mode.
394  *
395  * @param   em    Energy mode. Possible values are:
396  *                SL_POWER_MANAGER_EM1
397  *                SL_POWER_MANAGER_EM2
398  *
399  * @param   add   Flag indicating if requirement is added (true) or removed
400  *                (false).
401  *
402  * @note Need to be call inside a critical section.
403  *
404  * @note This function will do nothing when a project contains the
405  *       power_manager_no_deepsleep component, which configures the
406  *       lowest energy mode as EM1.
407  ******************************************************************************/
sli_power_manager_update_em_requirement(sl_power_manager_em_t em,bool add)408 void sli_power_manager_update_em_requirement(sl_power_manager_em_t em,
409                                              bool add)
410 {
411 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
412   // EM0 is not allowed
413   EFM_ASSERT((em > SL_POWER_MANAGER_EM0) && (em < SL_POWER_MANAGER_EM3));
414 
415   // Cannot increment above 255 (wraparound not allowed)
416   EFM_ASSERT(!((requirement_em_table[em - 1] == UINT8_MAX) && (add == true)));
417   // Cannot decrement below 0 (wraparound not allowed)
418   EFM_ASSERT(!((requirement_em_table[em - 1] == 0) && (add == false)));
419 
420   // Increment (add) or decrement (remove) energy mode counter.
421   requirement_em_table[em - 1] += (add) ? 1 : -1;
422 
423   if (add == true
424       && current_em >= SL_POWER_MANAGER_EM2) {  // if currently sleeping at a level that can require a clock restore; i.e. called from ISR
425     sl_power_manager_em_t lowest_em;
426     // If requirement added when sleeping, restore the clock before continuing the processing.
427     // Retrieve lowest reachable energy mode
428     lowest_em = get_lowest_em();
429 
430     if (lowest_em <= SL_POWER_MANAGER_EM1) {
431       // If new lowest requirement is greater than the current
432       // Restore clock; Everything is restored (HF and LF Clocks), the sleep loop will
433       // shutdown the clocks when returning sleeping
434       clock_restore_and_wait();
435     } else if (current_em == SL_POWER_MANAGER_EM3
436                && lowest_em == SL_POWER_MANAGER_EM2) {
437       // Restore LF clocks if we are transitioning from EM3 to EM2
438       sli_power_manager_low_frequency_restore();
439     }
440 
441     if (current_em != lowest_em) {
442       power_manager_notify_em_transition(current_em, lowest_em);
443       current_em = lowest_em;           // Keep new active energy mode
444     }
445   }
446 #else
447   (void)em;
448   (void)add;
449 #endif
450 }
451 
452 /***************************************************************************//**
453  * Updates requirement on preservation of High Frequency Clocks settings.
454  *
455  * @param   add   Flag indicating if requirement is added (true) or removed
456  *                (false).
457  ******************************************************************************/
sli_power_manager_update_hf_clock_settings_preservation_requirement(bool add)458 void sli_power_manager_update_hf_clock_settings_preservation_requirement(bool add)
459 {
460 #if (defined(SLI_DEVICE_SUPPORTS_EM1P) && !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT))
461   CORE_DECLARE_IRQ_STATE;
462 
463   CORE_ENTER_CRITICAL();
464   // Cannot increment above 255 (wraparound not allowed)
465   EFM_ASSERT(!((requirement_high_accuracy_hf_clock_counter == UINT8_MAX) && (add == true)));
466   // Cannot decrement below 0 (wraparound not allowed)
467   EFM_ASSERT(!((requirement_high_accuracy_hf_clock_counter == 0) && (add == false)));
468 
469   // Cannot add requirement if the "normal" clock settings are not currently applied
470   EFM_ASSERT(!((current_em > SL_POWER_MANAGER_EM2) && (add == true)));
471 
472   // Increment (add) or decrement (remove) energy mode counter.
473   requirement_high_accuracy_hf_clock_counter += (add) ? 1 : -1;
474 
475   // Save if the requirement is back to zero.
476   requirement_high_accuracy_hf_clock_back_to_zero = (requirement_high_accuracy_hf_clock_counter == 0) ? true : false;
477 
478   CORE_EXIT_CRITICAL();
479 #else
480   (void)add;
481 #endif
482 }
483 
484 /***************************************************************************//**
485  * Adds requirement on the preservation of the High Frequency Clocks settings.
486  *
487  * @note FOR INTERNAL USE ONLY.
488  *
489  * @note Must be used together with adding an EM2 requirement.
490  ******************************************************************************/
sli_power_manager_add_hf_clock_settings_preservation_requirement(void)491 void sli_power_manager_add_hf_clock_settings_preservation_requirement(void)
492 {
493 #if defined(SLI_DEVICE_SUPPORTS_EM1P)
494   sli_power_manager_update_hf_clock_settings_preservation_requirement(true);
495 #else
496   sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
497 #endif
498 }
499 
500 /***************************************************************************//**
501  * Removes requirement on the preservation of the High Frequency Clocks settings.
502  *
503  * @note FOR INTERNAL USE ONLY.
504  *
505  * @note Must be used together with removing an EM2 requirement.
506  ******************************************************************************/
sli_power_manager_remove_hf_clock_settings_preservation_requirement(void)507 void sli_power_manager_remove_hf_clock_settings_preservation_requirement(void)
508 {
509 #if defined(SLI_DEVICE_SUPPORTS_EM1P)
510   sli_power_manager_update_hf_clock_settings_preservation_requirement(false);
511 #else
512   sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
513 #endif
514 }
515 
516 /***************************************************************************//**
517  * Gets the wake-up restore process time.
518  * If we are not in the context of a deepsleep and therefore don't need to
519  * do a restore, the return value is 0.
520  *
521  * @return   Wake-up restore process time.
522  ******************************************************************************/
sli_power_manager_get_restore_delay(void)523 uint32_t sli_power_manager_get_restore_delay(void)
524 {
525 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
526   uint32_t wakeup_delay = 0;
527   CORE_DECLARE_IRQ_STATE;
528 
529   CORE_ENTER_CRITICAL();
530 
531   // If we are not currently in deepsleep, not need for any clock restore
532   if (current_em <= SL_POWER_MANAGER_EM1) {
533     CORE_EXIT_CRITICAL();
534     return wakeup_delay;
535   }
536 
537   // Get the clock restore delay
538   wakeup_delay = sl_power_manager_schedule_wakeup_get_restore_overhead_tick();
539   wakeup_delay += sli_power_manager_get_wakeup_process_time_overhead();
540 
541   CORE_EXIT_CRITICAL();
542 
543   return wakeup_delay;
544 #else
545   return 0;
546 #endif
547 }
548 
549 /***************************************************************************//**
550  * Initiates the wake-up restore process.
551  ******************************************************************************/
sli_power_manager_initiate_restore(void)552 void sli_power_manager_initiate_restore(void)
553 {
554 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
555   CORE_DECLARE_IRQ_STATE;
556 
557   CORE_ENTER_CRITICAL();
558 
559   // Start restore process
560   clock_restore();
561 
562   CORE_EXIT_CRITICAL();
563 #endif
564 }
565 
566 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
567 /*******************************************************************************
568  * Gets the status of power manager variable is_sleeping_waiting_for_clock_restore.
569  ******************************************************************************/
sli_power_manager_get_clock_restore_status(void)570 bool sli_power_manager_get_clock_restore_status(void)
571 {
572   return is_sleeping_waiting_for_clock_restore;
573 }
574 #endif
575 
576 /***************************************************************************//**
577  * Registers a callback to be called on given Energy Mode transition(s).
578  *
579  * @note Adding/Removing requirement(s) from the callback is not supported.
580  ******************************************************************************/
sl_power_manager_subscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t * event_handle,const sl_power_manager_em_transition_event_info_t * event_info)581 void sl_power_manager_subscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t *event_handle,
582                                                     const sl_power_manager_em_transition_event_info_t *event_info)
583 {
584   CORE_DECLARE_IRQ_STATE;
585 
586   event_handle->info = (sl_power_manager_em_transition_event_info_t *)event_info;
587   CORE_ENTER_CRITICAL();
588   sl_slist_push(&power_manager_em_transition_event_list, &event_handle->node);
589   CORE_EXIT_CRITICAL();
590 }
591 
592 /***************************************************************************//**
593  * Unregisters an event callback handle on Energy mode transition.
594  ******************************************************************************/
sl_power_manager_unsubscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t * event_handle)595 void sl_power_manager_unsubscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t *event_handle)
596 {
597   CORE_DECLARE_IRQ_STATE;
598 
599   CORE_ENTER_CRITICAL();
600   sl_slist_remove(&power_manager_em_transition_event_list, &event_handle->node);
601   CORE_EXIT_CRITICAL();
602 }
603 
604 /***************************************************************************//**
605  * Get configurable overhead value for early restore time in Sleeptimer ticks
606  * when a schedule wake-up is set.
607  *
608  * @return  Current overhead value for early wake-up time.
609  *
610  * @note This function will do nothing when a project contains the
611  *       power_manager_no_deepsleep component, which configures the
612  *       lowest energy mode as EM1.
613  ******************************************************************************/
sl_power_manager_schedule_wakeup_get_restore_overhead_tick(void)614 int32_t sl_power_manager_schedule_wakeup_get_restore_overhead_tick(void)
615 {
616 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
617   int32_t overhead_tick;
618 
619   sl_atomic_load(overhead_tick, wakeup_time_config_overhead_tick);
620   return overhead_tick;
621 #else
622   return 0;
623 #endif
624 }
625 
626 /***************************************************************************//**
627  * Set configurable overhead value for early restore time in Sleeptimer ticks
628  * used for schedule wake-up.
629  * Must be called after initialization else the value will be overwritten.
630  *
631  * @param overhead_tick Overhead value to set for early restore time.
632  *
633  * @note The overhead value can also be negative to remove time from the restore
634  *       process.
635  *
636  * @note This function will do nothing when a project contains the
637  *       power_manager_no_deepsleep component, which configures the
638  *       lowest energy mode as EM1.
639  ******************************************************************************/
sl_power_manager_schedule_wakeup_set_restore_overhead_tick(int32_t overhead_tick)640 void sl_power_manager_schedule_wakeup_set_restore_overhead_tick(int32_t overhead_tick)
641 {
642 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
643   sl_atomic_store(wakeup_time_config_overhead_tick, overhead_tick);
644 #else
645   (void)overhead_tick;
646 #endif
647 }
648 
649 /***************************************************************************//**
650  * Get configurable minimum off-time value for schedule wake-up in Sleeptimer
651  * ticks.
652  *
653  * @return  Current minimum off-time value for schedule wake-up.
654  *
655  * @note  Turning on external high frequency oscillator, such as HFXO, requires
656  *        more energy since we must supply higher current for the wake-up.
657  *        Therefore, when an 'external high frequency oscillator enable' is
658  *        scheduled in 'x' time, there is a threshold 'x' value where turning
659  *        off the oscillator is not worthwhile since the energy consumed by
660  *        taking into account the wake-up will be greater than if we just keep
661  *        the oscillator on until the next scheduled oscillator enabled. This
662  *        threshold value is what we refer as the minimum off-time.
663  *
664  * @note This function will do nothing when a project contains the
665  *       power_manager_no_deepsleep component, which configures the
666  *       lowest energy mode as EM1.
667  ******************************************************************************/
sl_power_manager_schedule_wakeup_get_minimum_offtime_tick(void)668 uint32_t sl_power_manager_schedule_wakeup_get_minimum_offtime_tick(void)
669 {
670 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
671   uint32_t offtime_tick;
672 
673   sl_atomic_load(offtime_tick, high_frequency_min_offtime_tick);
674   return offtime_tick;
675 #else
676   return 0;
677 #endif
678 }
679 
680 /***************************************************************************//**
681  * Set configurable minimum off-time value for schedule wake-up in Sleeptimer
682  * ticks.
683  *
684  * @param minimum_offtime_tick  minimum off-time value to set for schedule
685  *                              wake-up.
686  *
687  * @note  Turning on external high frequency oscillator, such as HFXO, requires
688  *        more energy since we must supply higher current for the wake-up.
689  *        Therefore, when an 'external high frequency oscillator enable' is
690  *        scheduled in 'x' time, there is a threshold 'x' value where turning
691  *        off the oscillator is not worthwhile since the energy consumed by
692  *        taking into account the wake-up will be greater than if we just keep
693  *        the oscillator on until the next scheduled oscillator enabled. This
694  *        threshold value is what we refer as the minimum off-time.
695  *
696  * @note This function will do nothing when a project contains the
697  *       power_manager_no_deepsleep component, which configures the
698  *       lowest energy mode as EM1.
699  ******************************************************************************/
sl_power_manager_schedule_wakeup_set_minimum_offtime_tick(uint32_t minimum_offtime_tick)700 void sl_power_manager_schedule_wakeup_set_minimum_offtime_tick(uint32_t minimum_offtime_tick)
701 {
702 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
703   sl_atomic_store(high_frequency_min_offtime_tick, minimum_offtime_tick);
704 #else
705   (void)minimum_offtime_tick;
706 #endif
707 }
708 
709 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
710 /*******************************************************************************
711  * Converts microseconds time in sleeptimer ticks.
712  ******************************************************************************/
sli_power_manager_convert_delay_us_to_tick(uint32_t time_us)713 uint32_t sli_power_manager_convert_delay_us_to_tick(uint32_t time_us)
714 {
715   return (((time_us * sleeptimer_frequency) + (1000000 - 1)) / 1000000);
716 }
717 #endif
718 
719 /***************************************************************************//**
720  * Last-chance check before sleep.
721  *
722  * @return  True, if the system should actually sleep.
723  *          False, if not.
724  *
725  * @note This is the fallback implementation of the callback, it can be
726  *       overridden by the application or other components.
727  ******************************************************************************/
sl_power_manager_is_ok_to_sleep(void)728 __WEAK bool sl_power_manager_is_ok_to_sleep(void)
729 {
730   return true;
731 }
732 
733 /***************************************************************************//**
734  * Check if the MCU can sleep after an interrupt.
735  *
736  * @return  True, if the system can sleep after the interrupt.
737  *          False, otherwise.
738  *
739  * @note This is the fallback implementation of the callback, it can be
740  *       overridden by the application or other components.
741  ******************************************************************************/
sl_power_manager_sleep_on_isr_exit(void)742 __WEAK bool sl_power_manager_sleep_on_isr_exit(void)
743 {
744   return false;
745 }
746 
747 /**************************************************************************//**
748  * Determines if the HFXO interrupt was part of the last wake-up and/or if
749  * the HFXO early wakeup expired during the last ISR
750  * and if it was the only timer to expire in that period.
751  *
752  * @return true if power manager sleep can return to sleep,
753  *         false otherwise.
754  *
755  * @note This function will always return false in case
756  *       a requirement is added on  SL_POWER_MANAGER_EM1,
757  *       since we will never sleep at a lower level than EM1.
758  *****************************************************************************/
sl_power_manager_is_latest_wakeup_internal(void)759 bool sl_power_manager_is_latest_wakeup_internal(void)
760 {
761 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
762   CORE_DECLARE_IRQ_STATE;
763   bool sleep;
764 
765   CORE_ENTER_CRITICAL();
766   sleep = is_restored_from_hfxo_isr;
767   is_restored_from_hfxo_isr = false;
768   CORE_EXIT_CRITICAL();
769 
770   sleep |= sl_sleeptimer_is_power_manager_early_restore_timer_latest_to_expire();
771   return sleep;
772 #else
773   return false;
774 #endif
775 }
776 
777 /*******************************************************************************
778  **************************   LOCAL FUNCTIONS   ********************************
779  ******************************************************************************/
780 
781 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
782 /***************************************************************************//**
783  * Get lowest energy mode to apply given the requirements on the different
784  * energy modes.
785  *
786  * @return  Lowest energy mode: EM1, EM2 or EM3.
787  *
788  * @note If no requirement for any energy mode (EM1 and EM2), lowest energy mode
789  * is EM3.
790  ******************************************************************************/
get_lowest_em(void)791 static sl_power_manager_em_t get_lowest_em(void)
792 {
793   uint32_t em_ix;
794   sl_power_manager_em_t em;
795 
796   // Retrieve lowest Energy mode allowed given the requirements
797   for (em_ix = 1; (em_ix < 3) && (requirement_em_table[em_ix - 1] == 0); em_ix++) {
798     ;
799   }
800 
801   em = (sl_power_manager_em_t)em_ix;
802 
803   return em;
804 }
805 #endif
806 
807 /***************************************************************************//**
808  * Notify subscribers about energy mode transition.
809  *
810  * @param  from  Energy mode from which CPU comes from.
811  *
812  * @param  to    Energy mode to which CPU is going to.
813  ******************************************************************************/
power_manager_notify_em_transition(sl_power_manager_em_t from,sl_power_manager_em_t to)814 static void power_manager_notify_em_transition(sl_power_manager_em_t from,
815                                                sl_power_manager_em_t to)
816 {
817   sl_power_manager_em_transition_event_handle_t *handle;
818   sl_power_manager_em_transition_event_t transition = 0;
819 
820   switch (to) {
821     case SL_POWER_MANAGER_EM0:
822       transition = SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM0;
823       break;
824 
825     case SL_POWER_MANAGER_EM1:
826       transition = SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM1;
827       break;
828 
829     case SL_POWER_MANAGER_EM2:
830       transition = SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM2;
831       break;
832 
833     case SL_POWER_MANAGER_EM3:
834       transition = SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM3;
835       break;
836 
837     default:
838       EFM_ASSERT(0);
839   }
840 
841   switch (from) {
842     case SL_POWER_MANAGER_EM0:
843       transition |= SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM0;
844       break;
845 
846     case SL_POWER_MANAGER_EM1:
847       transition |= SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM1;
848       break;
849 
850     case SL_POWER_MANAGER_EM2:
851       transition |= SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM2;
852       break;
853 
854     case SL_POWER_MANAGER_EM3:
855       transition |= SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM3;
856       break;
857 
858     default:
859       EFM_ASSERT(0);
860   }
861 
862   SL_SLIST_FOR_EACH_ENTRY(power_manager_em_transition_event_list, handle, sl_power_manager_em_transition_event_handle_t, node) {
863     if ((handle->info->event_mask & transition) > 0) {
864       handle->info->on_event(from, to);
865     }
866   }
867 }
868 
869 /***************************************************************************//**
870  * Enter critical section by disabling interrupts using PriMask.
871  *
872  * @return primask Initial primask state.
873  *
874  * @note @ref sl_power_manager_sleep() function should use PriMask to disable
875  *       interrupts.
876  ******************************************************************************/
enter_critical_with_primask(void)877 static CORE_irqState_t enter_critical_with_primask(void)
878 {
879   CORE_irqState_t irqState = __get_PRIMASK();
880   __disable_irq();
881 
882   return irqState;
883 }
884 
885 /***************************************************************************//**
886  * Exit critical section by re-enabling interrupts using PriMask.
887  *
888  * @param  primask_state  Initial primask state.
889  ******************************************************************************/
exit_critical_with_primask(CORE_irqState_t primask_state)890 static void exit_critical_with_primask(CORE_irqState_t primask_state)
891 {
892   if (primask_state == 0U) {
893     __enable_irq();
894   }
895 }
896 /***************************************************************************//**
897  * Evaluates scheduled wakeup and restart timer based on the wakeup time.
898  * If the remaining time is shorter than the wakeup time then add a requirement
899  * on EM1 for avoiding the wakeup delay time.
900  *
901  * @note Must be called in a critical section.
902  ******************************************************************************/
903 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
evaluate_wakeup(sl_power_manager_em_t to)904 static void evaluate_wakeup(sl_power_manager_em_t to)
905 {
906   sl_status_t status;
907   uint32_t tick_remaining;
908 
909   switch (to) {
910     case SL_POWER_MANAGER_EM0:
911       // Coming back from Sleep.
912       if (requirement_on_em1_added) {
913         update_em1_requirement(false);
914         requirement_on_em1_added = false;
915       }
916       break;
917 
918     case SL_POWER_MANAGER_EM1:
919       // External high frequency clock, such as HFXO, already enabled; No wakeup delay
920       break;
921 
922     case SL_POWER_MANAGER_EM2:
923     case SL_POWER_MANAGER_EM3:
924       // Get the time remaining until the next sleeptimer requiring early wake-up
925       status = sl_sleeptimer_get_remaining_time_of_first_timer(0, &tick_remaining);
926       if (status == SL_STATUS_OK) {
927         if (tick_remaining <= high_frequency_min_offtime_tick) {
928           // Add EM1 requirement if time remaining is to short to be energy efficient
929           // if going back to deepsleep.
930           update_em1_requirement(true);
931           requirement_on_em1_added = true;
932         } else {
933           int32_t wakeup_delay = 0;
934           int32_t cfg_overhead_tick = 0;
935 
936           // Calculate overall wake-up delay.
937           sl_atomic_load(cfg_overhead_tick, wakeup_time_config_overhead_tick);
938           wakeup_delay += cfg_overhead_tick;
939           wakeup_delay += sli_power_manager_get_wakeup_process_time_overhead();
940           EFM_ASSERT(wakeup_delay >= 0);
941           if (tick_remaining <= (uint32_t)wakeup_delay) {
942             // Add EM1 requirement if time remaining is smaller than wake-up delay.
943             update_em1_requirement(true);
944             requirement_on_em1_added = true;
945           } else {
946             uint16_t hf_accuracy_clk_flag = 0;
947             if (sli_power_manager_is_high_freq_accuracy_clk_used()) {
948               hf_accuracy_clk_flag = SLI_SLEEPTIMER_POWER_MANAGER_HF_ACCURACY_CLK_FLAG;
949             }
950             // Start internal sleeptimer to do the early wake-up.
951             sl_sleeptimer_restart_timer(&clock_wakeup_timer_handle,
952                                         (tick_remaining - (uint32_t)wakeup_delay),
953                                         on_clock_wakeup_timeout,
954                                         NULL,
955                                         0,
956                                         (SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG | hf_accuracy_clk_flag));
957           }
958         }
959       }
960       break;
961 
962     default:
963       EFM_ASSERT(false);
964   }
965 }
966 #endif
967 
968 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
969 /***************************************************************************//**
970  * Updates internal EM1 requirement.
971  * We add an internal EM1 requirement when we would usually go into EM2/EM3
972  * but there is not enough time before the next schedule event requiring a
973  * clock restore. So we just go to sleep in EM1.
974  * We remove this internal EM1 requirement next time we wake-up.
975  *
976  * @param   add  true, to add EM1 requirement,
977  *               false, to remove EM1 requirement.
978  *
979  * @note For internal use only.
980  *
981  * @note Need to be call inside a critical section.
982  ******************************************************************************/
update_em1_requirement(bool add)983 static void update_em1_requirement(bool add)
984 {
985   // Cannot increment above 255 (wraparound not allowed)
986   EFM_ASSERT(!((requirement_em_table[SL_POWER_MANAGER_EM1 - 1] == UINT8_MAX) && (add == true)));
987   // Cannot decrement below 0 (wraparound not allowed)
988   EFM_ASSERT(!((requirement_em_table[SL_POWER_MANAGER_EM1 - 1] == 0) && (add == false)));
989 
990 #if (SL_POWER_MANAGER_DEBUG == 1)
991   sli_power_manager_debug_log_em_requirement(SL_POWER_MANAGER_EM1, add, "PM_INTERNAL_EM1_REQUIREMENT");
992 #endif
993 
994   // Increment (add) or decrement (remove) energy mode counter.
995   requirement_em_table[SL_POWER_MANAGER_EM1 - 1] += (add) ? 1 : -1;
996 
997   // In rare occasions a clock restore must be started here:
998   // - An asynchronous event wake-up the system from deepsleep very near the early wake-up event,
999   //   When we re-enter the sleep loop, we delete the internal early wake-up timer, but during
1000   //   the evaluation before sleep, it is calculated that not enough time is remains to go to
1001   //   deepsleep. In that case, since we deleted the early wake-up timer we must start the
1002   //   restore process here.
1003   // - A synchronous event is added during an ISR, when we evaluate if the timeout is bigger
1004   //   than the clock restore time, it's barely bigger, so no clock restore process is started
1005   //   at that time. But when we do the evaluate before sleep, the remaining time is now smaller
1006   //   than the clock restore delay. So me must start the restore process here.
1007   if (add == true
1008       && current_em >= SL_POWER_MANAGER_EM2
1009       && is_sleeping_waiting_for_clock_restore == false) {
1010     clock_restore();
1011   }
1012 }
1013 #endif
1014 
1015 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
1016 /***************************************************************************//**
1017  * Do clock restore process and wait for it to be completed.
1018  ******************************************************************************/
clock_restore_and_wait(void)1019 static void clock_restore_and_wait(void)
1020 {
1021   CORE_DECLARE_IRQ_STATE;
1022 
1023   CORE_ENTER_CRITICAL();
1024   if (is_states_saved == true) {
1025     if (is_actively_waiting_for_clock_restore == false) {
1026       is_actively_waiting_for_clock_restore = true;
1027 
1028       // Since we will actively wait for clock restore, we cancel any current non-active wait.
1029       is_sleeping_waiting_for_clock_restore = false;
1030     }
1031 
1032     if (is_hf_x_oscillator_not_preserved) {
1033       sli_power_manager_restore_high_freq_accuracy_clk();
1034       is_hf_x_oscillator_not_preserved = false;
1035     }
1036 
1037     CORE_EXIT_CRITICAL();
1038     // We remove the critical section in case HFXO fails to startup and the HFXO Interrupt needs to run to handle the error.
1039     sli_power_manager_is_high_freq_accuracy_clk_ready(true);
1040     CORE_ENTER_CRITICAL();
1041     if (is_actively_waiting_for_clock_restore) {
1042       sli_power_manager_restore_states();
1043       is_actively_waiting_for_clock_restore = false;
1044     }
1045 
1046     is_states_saved = false;
1047   }
1048   CORE_EXIT_CRITICAL();
1049 }
1050 #endif
1051 
1052 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
1053 /***************************************************************************//**
1054  * Start clock restore process.
1055  *
1056  * @note Need to be call inside a critical section.
1057  ******************************************************************************/
clock_restore(void)1058 static void clock_restore(void)
1059 {
1060   // Check if we need to start the clock restore process
1061   if (is_states_saved == true) {
1062     if (is_hf_x_oscillator_not_preserved) {
1063       sli_power_manager_restore_high_freq_accuracy_clk();
1064       is_hf_x_oscillator_not_preserved = false;
1065     }
1066     if (sli_power_manager_is_high_freq_accuracy_clk_ready(false)) {
1067       // Do the clock restore if the HF oscillator is already ready
1068       sli_power_manager_restore_states();
1069       is_states_saved = false;
1070 
1071       // We do the notification only when the restore is completed.
1072       power_manager_notify_em_transition(current_em, SL_POWER_MANAGER_EM1);
1073       current_em = SL_POWER_MANAGER_EM1; // Keep new active energy mode
1074     } else {
1075       // If the HF oscillator is not yet ready, we will go back to sleep while waiting
1076       is_sleeping_waiting_for_clock_restore = true;
1077 
1078       // Save current EM to do the right notification later
1079       waiting_clock_restore_from_em = current_em;
1080     }
1081   }
1082 }
1083 #endif
1084 
1085 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
1086 /***************************************************************************//**
1087  * Callback for clock enable timer.
1088  *
1089  * @param   handle  Pointer to sleeptimer handle
1090  *
1091  * @param   data    Pointer to callback data
1092  *
1093  * @note We restore the HF clocks and go to EM1 here to be ready in time for the
1094  *       Application sleeptimer callback. But no EM1 requirement is added
1095  *       here. Since the time until the Application sleeptimer times out is <=
1096  *       than the wake-up delay, it protects us from going back to sleep lower
1097  *       than EM1. After that, it's up to the Application sleeptimer callback to
1098  *       put a EM1 requirement if still needed.
1099  ******************************************************************************/
on_clock_wakeup_timeout(sl_sleeptimer_timer_handle_t * handle,void * data)1100 static void on_clock_wakeup_timeout(sl_sleeptimer_timer_handle_t *handle,
1101                                     void *data)
1102 {
1103   (void)handle;
1104   (void)data;
1105   CORE_DECLARE_IRQ_STATE;
1106 
1107   CORE_ENTER_CRITICAL();
1108 
1109   if (is_actively_waiting_for_clock_restore) {
1110     // In case we are already actively waiting for HFXO ready in another ISR, just exit
1111     CORE_EXIT_CRITICAL();
1112     return;
1113   }
1114 
1115   // If needed start the clock restore process
1116   clock_restore();
1117 
1118   CORE_EXIT_CRITICAL();
1119 }
1120 #endif
1121 
1122 /***************************************************************************//**
1123  * HFXO ready notification callback for internal use with power manager
1124  *
1125  * @note Will only be used on series 2 devices when HFXO Manager is present.
1126  ******************************************************************************/
sli_hfxo_manager_notify_ready_for_power_manager(void)1127 void sli_hfxo_manager_notify_ready_for_power_manager(void)
1128 {
1129 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
1130   // Complete HF restore and change current Energy mode
1131   // The notification will be done once back in the sleep loop
1132   if (current_em != SL_POWER_MANAGER_EM0
1133       && (is_sleeping_waiting_for_clock_restore == true)) {
1134     sli_power_manager_restore_states();
1135     is_sleeping_waiting_for_clock_restore = false;
1136     is_states_saved = false;
1137     is_restored_from_hfxo_isr = true;
1138     is_restored_from_hfxo_isr_internal = true;
1139   }
1140 #endif
1141 }
1142 
1143 /***************************************************************************//**
1144  * HFXO PRS ready notification callback for internal use with power manager
1145  *
1146  * @note Will only be used on series 2 devices when HFXO Manager and SYSRTC
1147  * is present.
1148  ******************************************************************************/
sli_hfxo_notify_ready_for_power_manager_from_prs(void)1149 void sli_hfxo_notify_ready_for_power_manager_from_prs(void)
1150 {
1151 #if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
1152   // Set clock restore to true to indicate that HFXO has been restored from a
1153   // PRS interrupt unless already in EM0 indicating HFXO didn't need to be restored.
1154   if (current_em != SL_POWER_MANAGER_EM0) {
1155     is_sleeping_waiting_for_clock_restore = true;
1156   }
1157 #endif
1158 }
1159 
1160 /***************************************************************************//**
1161  * Enable or disable fast wake-up in EM2 and EM3
1162  *
1163  * @note Will also update the wake up time from EM2 to EM0.
1164  *
1165  * @note This function will do nothing when a project contains the
1166  *       power_manager_no_deepsleep component, which configures the
1167  *       lowest energy mode as EM1.
1168  ******************************************************************************/
sl_power_manager_em23_voltage_scaling_enable_fast_wakeup(bool enable)1169 void sl_power_manager_em23_voltage_scaling_enable_fast_wakeup(bool enable)
1170 {
1171 #if (defined(EMU_VSCALE_PRESENT) && !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT))
1172   CORE_DECLARE_IRQ_STATE;
1173 
1174   CORE_ENTER_CRITICAL();
1175 
1176   sli_power_manager_em23_voltage_scaling_enable_fast_wakeup(enable);
1177 
1178   CORE_EXIT_CRITICAL();
1179 #else
1180   (void)enable;
1181 #endif
1182 }
1183