Contiki 3.x
lpm.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*---------------------------------------------------------------------------*/
31 /**
32  * \addtogroup cc26xx-lpm
33  * @{
34  *
35  * Implementation of CC13xx/CC26xx low-power operation functionality
36  *
37  * @{
38  *
39  * \file
40  * Driver for CC13xx/CC26xx low-power operation
41  */
42 /*---------------------------------------------------------------------------*/
43 #include "prcm.h"
44 #include "contiki-conf.h"
45 #include "ti-lib.h"
46 #include "lpm.h"
47 #include "sys/energest.h"
48 #include "lib/list.h"
49 #include "dev/aux-ctrl.h"
50 #include "dev/leds.h"
51 #include "dev/watchdog.h"
52 #include "dev/soc-rtc.h"
53 #include "dev/oscillators.h"
54 
55 #include <stdint.h>
56 #include <string.h>
57 #include <stdbool.h>
58 /*---------------------------------------------------------------------------*/
59 #if ENERGEST_CONF_ON
60 static unsigned long irq_energest = 0;
61 
62 #define ENERGEST_IRQ_SAVE(a) do { \
63  a = energest_type_time(ENERGEST_TYPE_IRQ); } while(0)
64 #define ENERGEST_IRQ_RESTORE(a) do { \
65  energest_type_set(ENERGEST_TYPE_IRQ, a); } while(0)
66 #else
67 #define ENERGEST_IRQ_SAVE(a) do {} while(0)
68 #define ENERGEST_IRQ_RESTORE(a) do {} while(0)
69 #endif
70 /*---------------------------------------------------------------------------*/
71 LIST(modules_list);
72 /*---------------------------------------------------------------------------*/
73 /* PDs that may stay on in deep sleep */
74 #define LOCKABLE_DOMAINS ((uint32_t)(PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH))
75 /*---------------------------------------------------------------------------*/
76 /*
77  * Don't consider standby mode if the next AON RTC event is scheduled to fire
78  * in less than STANDBY_MIN_DURATION rtimer ticks
79  */
80 #define STANDBY_MIN_DURATION (RTIMER_SECOND >> 11)
81 #define MINIMAL_SAFE_SCHEDUAL 8u
82 #define MAX_SLEEP_TIME RTIMER_SECOND
83 #define DEFAULT_SLEEP_TIME RTIMER_SECOND
84 /*---------------------------------------------------------------------------*/
85 #define CLK_TO_RT(c) ((c) * (RTIMER_SECOND / CLOCK_SECOND))
86 /*---------------------------------------------------------------------------*/
87 /* Prototype of a function in clock.c. Called every time we come out of DS */
88 void clock_update(void);
89 /*---------------------------------------------------------------------------*/
90 void
91 lpm_shutdown(uint32_t wakeup_pin, uint32_t io_pull, uint32_t wake_on)
92 {
93  lpm_registered_module_t *module;
94  int i;
95  uint32_t io_cfg = (IOC_STD_INPUT & ~IOC_IOPULL_M) | io_pull | wake_on;
96  aux_consumer_module_t aux = { .clocks = AUX_WUC_OSCCTRL_CLOCK };
97 
98  /* This procedure may not be interrupted */
99  ti_lib_int_master_disable();
100 
101  /* Disable the RTC */
102  ti_lib_aon_rtc_disable();
103  ti_lib_aon_rtc_event_clear(AON_RTC_CH0);
104  ti_lib_aon_rtc_event_clear(AON_RTC_CH1);
105  ti_lib_aon_rtc_event_clear(AON_RTC_CH2);
106 
107  /* Reset AON even fabric to default wakeup sources */
108  for(i = AON_EVENT_MCU_WU0; i <= AON_EVENT_MCU_WU3; i++) {
109  ti_lib_aon_event_mcu_wake_up_set(i, AON_EVENT_NONE);
110  }
111  for(i = AON_EVENT_AUX_WU0; i <= AON_EVENT_AUX_WU2; i++) {
112  ti_lib_aon_event_aux_wake_up_set(i, AON_EVENT_NONE);
113  }
114 
115  ti_lib_sys_ctrl_aon_sync();
116 
118 
119  /* Notify all modules that we're shutting down */
120  for(module = list_head(modules_list); module != NULL;
121  module = module->next) {
122  if(module->shutdown) {
123  module->shutdown(LPM_MODE_SHUTDOWN);
124  }
125  }
126 
127  /* Configure the wakeup trigger */
128  if(wakeup_pin != IOID_UNUSED) {
129  ti_lib_gpio_dir_mode_set((1 << wakeup_pin), GPIO_DIR_MODE_IN);
130  ti_lib_ioc_port_configure_set(wakeup_pin, IOC_PORT_GPIO, io_cfg);
131  }
132 
133  /* Freeze I/O latches in AON */
134  ti_lib_aon_ioc_freeze_enable();
135 
136  /* Turn off RFCORE, SERIAL and PERIPH PDs. This will happen immediately */
137  ti_lib_prcm_power_domain_off(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL |
138  PRCM_DOMAIN_PERIPH);
139 
140  /* Register an aux-ctrl consumer to avoid powercycling AUX twice in a row */
144 
145  /* Configure clock sources for MCU: No clock */
146  ti_lib_aon_wuc_mcu_power_down_config(AONWUC_NO_CLOCK);
147 
148  /* Disable SRAM retention */
149  ti_lib_aon_wuc_mcu_sram_config(0);
150 
151  /*
152  * Request CPU, SYSBYS and VIMS PD off.
153  * This will only happen when the CM3 enters deep sleep
154  */
155  ti_lib_prcm_power_domain_off(PRCM_DOMAIN_CPU | PRCM_DOMAIN_VIMS |
156  PRCM_DOMAIN_SYSBUS);
157 
158  /* Request JTAG domain power off */
159  ti_lib_aon_wuc_jtag_power_off();
160 
161  /* Turn off AUX */
162  aux_ctrl_power_down(true);
163  ti_lib_aon_wuc_domain_power_down_enable();
164 
165  /*
166  * Request MCU VD power off.
167  * This will only happen when the CM3 enters deep sleep
168  */
169  ti_lib_prcm_mcu_power_off();
170 
171  /* Set MCU wakeup to immediate and disable virtual power off */
172  ti_lib_aon_wuc_mcu_wake_up_config(MCU_IMM_WAKE_UP);
173  ti_lib_aon_wuc_mcu_power_off_config(MCU_VIRT_PWOFF_DISABLE);
174 
175  /* Latch the IOs in the padring and enable I/O pad sleep mode */
176  ti_lib_pwr_ctrl_io_freeze_enable();
177 
178  /* Turn off VIMS cache, CRAM and TRAM - possibly not required */
179  ti_lib_prcm_cache_retention_disable();
180  ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_OFF);
181 
182  /* Enable shutdown and sync AON */
183  ti_lib_aon_wuc_shut_down_enable();
184  ti_lib_sys_ctrl_aon_sync();
185 
186  /* Deep Sleep */
187  ti_lib_prcm_deep_sleep();
188 }
189 /*---------------------------------------------------------------------------*/
190 /*
191  * Notify all modules that we're back on and rely on them to restore clocks
192  * and power domains as required.
193  */
194 static void
195 wake_up(void)
196 {
197  lpm_registered_module_t *module;
198 
199  /* Remember IRQ energest for next pass */
200  ENERGEST_IRQ_SAVE(irq_energest);
201  ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU);
202 
203  /* Sync so that we get the latest values before adjusting recharge settings */
204  ti_lib_sys_ctrl_aon_sync();
205 
206  /* Adjust recharge settings */
207  ti_lib_sys_ctrl_adjust_recharge_after_power_down();
208 
209  /*
210  * Release the request to the uLDO
211  * This is likely not required, since the switch to GLDO/DCDC is automatic
212  * when coming back from deep sleep
213  */
214  ti_lib_prcm_mcu_uldo_configure(false);
215 
216  /* Turn on cache again */
217  ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED);
218  ti_lib_prcm_cache_retention_enable();
219 
220  ti_lib_aon_ioc_freeze_disable();
221  ti_lib_sys_ctrl_aon_sync();
222 
223  /* Check operating conditions, optimally choose DCDC versus GLDO */
224  ti_lib_sys_ctrl_dcdc_voltage_conditional_control();
225 
226  /* Fire up AUX is the user has requested this */
228 
229  /*
230  * We may or may not have been woken up by an AON RTC tick. If not, we need
231  * to adjust our software tick counter
232  */
233  clock_update();
234 
236 
237  /* Notify all registered modules that we've just woken up */
238  for(module = list_head(modules_list); module != NULL;
239  module = module->next) {
240  if(module->wakeup) {
241  module->wakeup();
242  }
243  }
244 }
245 /*---------------------------------------------------------------------------*/
246 static void
247 deep_sleep(void)
248 {
249  uint32_t domains = LOCKABLE_DOMAINS;
250  lpm_registered_module_t *module;
251 
252  /*
253  * Notify all registered modules that we are dropping to mode X. We do not
254  * need to do this for simple sleep.
255  *
256  * This is a chance for modules to delay us a little bit until an ongoing
257  * operation has finished (e.g. uart TX) or to configure themselves for
258  * deep sleep.
259  *
260  * At this stage, we also collect power domain locks, if any.
261  * The argument to PRCMPowerDomainOff() is a bitwise OR, so every time
262  * we encounter a lock we just clear the respective bits in the 'domains'
263  * variable as required by the lock. In the end the domains variable will
264  * just hold whatever has not been cleared
265  */
266  for(module = list_head(modules_list); module != NULL;
267  module = module->next) {
268  if(module->shutdown) {
269  module->shutdown(LPM_MODE_DEEP_SLEEP);
270  }
271 
272  /* Clear the bits specified in the lock */
273  domains &= ~module->domain_lock;
274  }
275 
276  /* Pat the dog: We don't want it to shout right after we wake up */
278 
279  /* Clear unacceptable bits, just in case a lock provided a bad value */
280  domains &= LOCKABLE_DOMAINS;
281 
282  /*
283  * Freeze the IOs on the boundary between MCU and AON. We only do this if
284  * PERIPH is not needed
285  */
286  if(domains & PRCM_DOMAIN_PERIPH) {
287  ti_lib_aon_ioc_freeze_enable();
288  }
289 
290  /*
291  * Among LOCKABLE_DOMAINS, turn off those that are not locked
292  *
293  * If domains is != 0, pass it as-is
294  */
295  if(domains) {
296  ti_lib_prcm_power_domain_off(domains);
297  }
298 
299  /*
300  * Before entering Deep Sleep, we must switch off the HF XOSC. The HF XOSC
301  * is predominantly controlled by the RF driver. In a build with radio
302  * cycling (e.g. ContikiMAC), the RF driver will request the XOSC before
303  * using the Freq. Synth, and switch back to the RC when it is about to
304  * turn back off.
305  *
306  * If the radio is on, we won't even reach here, and if it's off the HF
307  * clock source should already be the HF RC.
308  *
309  * Nevertheless, request the switch to the HF RC explicitly here.
310  */
312 
313  /* Shut Down the AUX if the user application is not using it */
314  aux_ctrl_power_down(false);
315 
316  /* Configure clock sources for MCU: No clock */
317  ti_lib_aon_wuc_mcu_power_down_config(AONWUC_NO_CLOCK);
318 
319  /* Full RAM retention. */
320  ti_lib_aon_wuc_mcu_sram_config(MCU_RAM0_RETENTION | MCU_RAM1_RETENTION |
321  MCU_RAM2_RETENTION | MCU_RAM3_RETENTION);
322 
323  /*
324  * Always turn off RFCORE, CPU, SYSBUS and VIMS. RFCORE should be off
325  * already
326  */
327  ti_lib_prcm_power_domain_off(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_CPU |
328  PRCM_DOMAIN_VIMS | PRCM_DOMAIN_SYSBUS);
329 
330  /* Request JTAG domain power off */
331  ti_lib_aon_wuc_jtag_power_off();
332 
333  /* Allow MCU and AUX powerdown */
334  ti_lib_aon_wuc_domain_power_down_enable();
335 
336  /* Configure the recharge controller */
337  ti_lib_sys_ctrl_set_recharge_before_power_down(XOSC_IN_HIGH_POWER_MODE);
338 
339  /*
340  * If both PERIPH and SERIAL PDs are off, request the uLDO as the power
341  * source while in deep sleep.
342  */
343  if(domains == LOCKABLE_DOMAINS) {
344  ti_lib_pwr_ctrl_source_set(PWRCTRL_PWRSRC_ULDO);
345  }
346 
347  /* We are only interested in IRQ energest while idle or in LPM */
348  ENERGEST_IRQ_RESTORE(irq_energest);
349  ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM);
350 
351  /* Sync the AON interface to ensure all writes have gone through. */
352  ti_lib_sys_ctrl_aon_sync();
353 
354  /*
355  * Explicitly turn off VIMS cache, CRAM and TRAM. Needed because of
356  * retention mismatch between VIMS logic and cache. We wait to do this
357  * until right before deep sleep to be able to use the cache for as long
358  * as possible.
359  */
360  ti_lib_prcm_cache_retention_disable();
361  ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_OFF);
362 
363  /* Deep Sleep */
364  ti_lib_prcm_deep_sleep();
365 
366  /*
367  * When we reach here, some interrupt woke us up. The global interrupt
368  * flag is off, hence we have a chance to run things here. We will wake up
369  * the chip properly, and then we will enable the global interrupt without
370  * unpending events so the handlers can fire
371  */
372  wake_up();
373 }
374 /*---------------------------------------------------------------------------*/
375 static void
376 safe_schedule_rtimer(rtimer_clock_t time, rtimer_clock_t now, int pm)
377 {
378  rtimer_clock_t min_sleep;
379  rtimer_clock_t max_sleep;
380 
381  min_sleep = now + MINIMAL_SAFE_SCHEDUAL;
382  max_sleep = now + MAX_SLEEP_TIME;
383 
384  if(RTIMER_CLOCK_LT(time, min_sleep)) {
385  /* ensure that we schedule sleep a minimal number of ticks into the
386  future */
387  soc_rtc_schedule_one_shot(AON_RTC_CH1, min_sleep);
388  } else if((pm == LPM_MODE_SLEEP) && RTIMER_CLOCK_LT(max_sleep, time)) {
389  /* if max_pm is LPM_MODE_SLEEP, we could trigger the watchdog if we slept
390  for too long. */
391  soc_rtc_schedule_one_shot(AON_RTC_CH1, max_sleep);
392  } else {
393  soc_rtc_schedule_one_shot(AON_RTC_CH1, time);
394  }
395 }
396 /*---------------------------------------------------------------------------*/
397 static int
398 setup_sleep_mode(void)
399 {
400  rtimer_clock_t et_distance = 0;
401 
402  lpm_registered_module_t *module;
403  int max_pm;
404  int module_pm;
405  int etimer_is_pending;
406  rtimer_clock_t now;
407  rtimer_clock_t et_time;
408  rtimer_clock_t next_trig;
409 
410  max_pm = LPM_MODE_MAX_SUPPORTED;
411  now = RTIMER_NOW();
412 
413  if((LPM_MODE_MAX_SUPPORTED == LPM_MODE_AWAKE) || process_nevents()) {
414  return LPM_MODE_AWAKE;
415  }
416 
417  etimer_is_pending = etimer_pending();
418 
419  if(etimer_is_pending) {
420  et_distance = CLK_TO_RT(etimer_next_expiration_time() - clock_time());
421 
422  if(RTIMER_CLOCK_LT(et_distance, 1)) {
423  /* there is an etimer which is already expired; we shouldn't go to
424  sleep at all */
425  return LPM_MODE_AWAKE;
426  }
427  }
428 
429  next_trig = soc_rtc_get_next_trigger();
430  if(RTIMER_CLOCK_LT(next_trig, now + STANDBY_MIN_DURATION)) {
431  return LPM_MODE_SLEEP;
432  }
433 
434  /* Collect max allowed PM permission from interested modules */
435  for(module = list_head(modules_list); module != NULL;
436  module = module->next) {
437  if(module->request_max_pm) {
438  module_pm = module->request_max_pm();
439  if(module_pm < max_pm) {
440  max_pm = module_pm;
441  }
442  }
443  }
444 
445  /* Reschedule AON RTC CH1 to fire just in time for the next etimer event */
446  if(etimer_is_pending) {
447  et_time = soc_rtc_last_isr_time() + et_distance;
448 
449  safe_schedule_rtimer(et_time, now, max_pm);
450  } else {
451  /* set a maximal sleep period if no etimers are queued */
452  soc_rtc_schedule_one_shot(AON_RTC_CH1, now + DEFAULT_SLEEP_TIME);
453  }
454 
455  return max_pm;
456 }
457 /*---------------------------------------------------------------------------*/
458 void
460 {
461  uint8_t max_pm;
462 
463  /* Critical. Don't get interrupted! */
464  ti_lib_int_master_disable();
465 
466  max_pm = setup_sleep_mode();
467 
468  /* Drop */
469  if(max_pm == LPM_MODE_SLEEP) {
470  lpm_sleep();
471  } else if(max_pm == LPM_MODE_DEEP_SLEEP) {
472  deep_sleep();
473  }
474 
475  ti_lib_int_master_enable();
476 }
477 /*---------------------------------------------------------------------------*/
478 void
480 {
481  ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM);
482 
483  /* We are only interested in IRQ energest while idle or in LPM */
484  ENERGEST_IRQ_RESTORE(irq_energest);
485 
486  /* Just to be on the safe side, explicitly disable Deep Sleep */
487  HWREG(NVIC_SYS_CTRL) &= ~(NVIC_SYS_CTRL_SLEEPDEEP);
488 
489  ti_lib_prcm_sleep();
490 
491  /* Remember IRQ energest for next pass */
492  ENERGEST_IRQ_SAVE(irq_energest);
493 
494  ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU);
495 }
496 /*---------------------------------------------------------------------------*/
497 void
498 lpm_register_module(lpm_registered_module_t *module)
499 {
500  list_add(modules_list, module);
501 }
502 /*---------------------------------------------------------------------------*/
503 void
504 lpm_unregister_module(lpm_registered_module_t *module)
505 {
506  list_remove(modules_list, module);
507 }
508 /*---------------------------------------------------------------------------*/
509 void
511 {
512  list_init(modules_list);
513 
514  /* Always wake up on any DIO edge detection */
515  ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU2, AON_EVENT_IO);
516 }
517 /*---------------------------------------------------------------------------*/
518 void
520 {
521  if(ioid == IOID_UNUSED) {
522  return;
523  }
524 
525  ti_lib_ioc_port_configure_set(ioid, IOC_PORT_GPIO, IOC_STD_OUTPUT);
526  ti_lib_gpio_dir_mode_set((1 << ioid), GPIO_DIR_MODE_IN);
527 }
528 /*---------------------------------------------------------------------------*/
529 /**
530  * @}
531  * @}
532  */
void aux_ctrl_register_consumer(aux_consumer_module_t *consumer)
Register a module that no longer requires access to the AUX power domain.
Definition: aux-ctrl.c:43
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
void soc_rtc_schedule_one_shot(uint32_t channel, uint32_t ticks)
Schedule an AON RTC channel 0 one-shot compare event.
Definition: soc-rtc.c:124
#define LIST(name)
Declare a linked list.
Definition: list.h:86
Header file with macros which rename TI CC26xxware functions.
Header file for the management of the CC13xx/CC26xx AUX domain.
void lpm_shutdown(uint32_t wakeup_pin, uint32_t io_pull, uint32_t wake_on)
Put the chip in shutdown power mode.
Definition: lpm.c:91
clock_time_t etimer_next_expiration_time(void)
Get next event timer expiration time.
Definition: etimer.c:237
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:135
int etimer_pending(void)
Check if there are any non-expired event timers.
Definition: etimer.c:231
void lpm_drop()
Drop the cortex to sleep / deep sleep and shut down peripherals.
Definition: lpm.c:459
CCIF clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:41
void lpm_sleep(void)
Enter sleep mode.
Definition: lpm.c:479
void aux_ctrl_power_down(bool force)
Power down the AUX power domain.
Definition: aux-ctrl.c:86
void lpm_init()
Initialise the low-power mode management module.
Definition: lpm.c:510
Header file for the CC13xx/CC26xx AON RTC driver.
Header file for the energy estimation mechanism
void lpm_register_module(lpm_registered_module_t *module)
Register a module for LPM notifications.
Definition: lpm.c:498
The data structure to be used for modules that require access to AUX.
Definition: aux-ctrl.h:62
void list_init(list_t list)
Initialize a list.
Definition: list.c:66
Header file for the management of CC13xx/CC26xx low-power operation.
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
void lpm_pin_set_default_state(uint32_t ioid)
Sets an IOID to a default state.
Definition: lpm.c:519
#define NULL
The null pointer.
void oscillators_switch_to_hf_rc(void)
Switches MF and HF clock source to be the HF RC OSC.
Definition: oscillators.c:134
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:64
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
Linked list manipulation routines.
void aux_ctrl_power_up()
Power-up the AUX power domain.
Definition: aux-ctrl.c:74
rtimer_clock_t soc_rtc_get_next_trigger()
Return the time of the next scheduled rtimer event.
Definition: soc-rtc.c:110
int process_nevents(void)
Number of events waiting to be processed.
Definition: process.c:316
Header file for the CC13xx/CC26xx oscillator control.
void lpm_unregister_module(lpm_registered_module_t *module)
Unregister a module from LPM notifications.
Definition: lpm.c:504
void oscillators_select_lf_rcosc(void)
Set the LF clock source to be the LF RCOSC.
Definition: oscillators.c:73