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