1 /***************************************************************************//**
2  * @file
3  * @brief Energy Management Unit (EMU) Peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 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 <limits.h>
32 
33 #include "em_emu.h"
34 #if defined(EMU_PRESENT) && (EMU_COUNT > 0)
35 
36 #include "sl_assert.h"
37 #include "em_cmu.h"
38 #include "sl_common.h"
39 #include "em_core.h"
40 #include "em_system.h"
41 #include "em_ramfunc.h"
42 
43 #if defined(SL_CATALOG_METRIC_EM23_WAKE_PRESENT)
44 #include "sli_metric_em23_wake.h"
45 #include "sli_metric_em23_wake_config.h"
46 #endif
47 
48 #if defined(SL_CATALOG_METRIC_EM4_WAKE_PRESENT)
49 #include "sli_metric_em4_wake.h"
50 #endif
51 
52 #if defined(SYSCFG_PRESENT)
53 #include "em_syscfg.h"
54 #endif
55 /* Consistency check, since restoring assumes similar bit positions in */
56 /* CMU OSCENCMD and STATUS regs. */
57 #if defined(CMU_STATUS_AUXHFRCOENS) && (CMU_STATUS_AUXHFRCOENS != CMU_OSCENCMD_AUXHFRCOEN)
58 #error Conflict in AUXHFRCOENS and AUXHFRCOEN bitpositions
59 #endif
60 #if defined(CMU_STATUS_HFXOENS) && (CMU_STATUS_HFXOENS != CMU_OSCENCMD_HFXOEN)
61 #error Conflict in HFXOENS and HFXOEN bitpositions
62 #endif
63 #if defined(CMU_STATUS_LFRCOENS) && (CMU_STATUS_LFRCOENS != CMU_OSCENCMD_LFRCOEN)
64 #error Conflict in LFRCOENS and LFRCOEN bitpositions
65 #endif
66 #if defined(CMU_STATUS_LFXOENS) && (CMU_STATUS_LFXOENS != CMU_OSCENCMD_LFXOEN)
67 #error Conflict in LFXOENS and LFXOEN bitpositions
68 #endif
69 
70 /*******************************************************************************
71  ******************************   DEFINES   ************************************
72  ******************************************************************************/
73 #if defined(_SILICON_LABS_32B_SERIES_0)
74 /* Fix for errata EMU_E107 - non-WIC interrupt masks. */
75 #if defined(_EFM32_GECKO_FAMILY)
76 #define ERRATA_FIX_EMU_E107_ENABLE
77 #define NON_WIC_INT_MASK_0    (~(0x0dfc0323U))
78 #define NON_WIC_INT_MASK_1    (~(0x0U))
79 
80 #elif defined(_EFM32_TINY_FAMILY)
81 #define ERRATA_FIX_EMU_E107_ENABLE
82 #define NON_WIC_INT_MASK_0    (~(0x001be323U))
83 #define NON_WIC_INT_MASK_1    (~(0x0U))
84 
85 #elif defined(_EFM32_GIANT_FAMILY)
86 #define ERRATA_FIX_EMU_E107_ENABLE
87 #define NON_WIC_INT_MASK_0    (~(0xff020e63U))
88 #define NON_WIC_INT_MASK_1    (~(0x00000046U))
89 
90 #elif defined(_EFM32_WONDER_FAMILY)
91 #define ERRATA_FIX_EMU_E107_ENABLE
92 #define NON_WIC_INT_MASK_0    (~(0xff020e63U))
93 #define NON_WIC_INT_MASK_1    (~(0x00000046U))
94 
95 #elif defined(_EFM32_ZERO_FAMILY)
96 #define ERRATA_FIX_EMU_E107_ENABLE
97 #define NON_WIC_INT_MASK_0    (~(0x00005c6bU))
98 #define NON_WIC_INT_MASK_1    (~(0x00000000U))
99 
100 #elif defined(_EFM32_HAPPY_FAMILY)
101 #define ERRATA_FIX_EMU_E107_ENABLE
102 #define NON_WIC_INT_MASK_0    (~(0x00085c6bU))
103 #define NON_WIC_INT_MASK_1    (~(0x00000000U))
104 
105 #endif
106 #endif
107 
108 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_74) \
109   || (defined(_SILICON_LABS_32B_SERIES_0)         \
110   && (defined(_EFM32_HAPPY_FAMILY) || defined(_EFM32_ZERO_FAMILY)))
111 // Fix for errata EMU_E110 - Potential Hard Fault when Exiting EM2.
112 #define ERRATA_FIX_EMU_E110_ENABLE
113 #endif
114 
115 /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
116 #if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_HAPPY_FAMILY)
117 #define ERRATA_FIX_EMU_E108_ENABLE
118 #endif
119 
120 /* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H. */
121 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
122 #define ERRATA_FIX_EMU_E208_ENABLE
123 #endif
124 
125 /* Enable FETCNT tuning errata fix. */
126 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
127 #define ERRATA_FIX_DCDC_FETCNT_SET_ENABLE
128 #endif
129 
130 /* Enable LN handshake errata fix. */
131 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
132 #define ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE
133 typedef enum {
134   errataFixDcdcHsInit,
135   errataFixDcdcHsTrimSet,
136   errataFixDcdcHsBypassLn,
137   errataFixDcdcHsLnWaitDone
138 } errataFixDcdcHs_TypeDef;
139 static errataFixDcdcHs_TypeDef errataFixDcdcHsState = errataFixDcdcHsInit;
140 #endif
141 
142 /* Fix for errata for EFM32GG11 and EFM32TG11. If a device is entering EM4S
143  * while powering the analog peripherals from DVDD, firmware must switch
144  * over to powering the analog peripherals from AVDD and delay the EM4S entry
145  * with 30 us. */
146 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_100) \
147   || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_103)
148 #define ERRATA_FIX_EM4S_DELAY_ENTRY
149 #endif
150 
151 #if defined(_SILICON_LABS_32B_SERIES_1)             \
152   && !defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) \
153   && !defined(ERRATA_FIX_EMU_E220_DECBOD_IGNORE)
154 /* EMU_E220 DECBOD Errata fix. DECBOD Reset can occur
155  * during voltage scaling after EM2/3 wakeup. */
156 #define ERRATA_FIX_EMU_E220_DECBOD_ENABLE
157 #define EMU_PORBOD                   (*(volatile uint32_t *) (EMU_BASE + 0x14C))
158 #define EMU_PORBOD_GMC_CALIB_DISABLE (0x1UL << 31)
159 #endif
160 
161 /* Used to figure out if a memory address is inside or outside of a RAM block.
162  * A memory address is inside a RAM block if the address is greater than the
163  * RAM block address. */
164 #define ADDRESS_NOT_IN_BLOCK(addr, block)  ((addr) <= (block) ? 1UL : 0UL)
165 
166 /* RAM Block layout for various device families. Note that some devices
167  * have special layout in RAM0 and some devices have a special RAM block
168  * at the end of their block layout. */
169 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)
170 #define RAM1_BLOCKS            2U
171 #define RAM1_BLOCK_SIZE  0x10000U // 64 kB blocks
172 #define RAM2_BLOCKS            1U
173 #define RAM2_BLOCK_SIZE    0x800U // 2 kB block
174 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_89)
175 #define RAM0_BLOCKS            2U
176 #define RAM0_BLOCK_SIZE   0x4000U
177 #define RAM1_BLOCKS            2U
178 #define RAM1_BLOCK_SIZE   0x4000U // 16 kB blocks
179 #define RAM2_BLOCKS            1U
180 #define RAM2_BLOCK_SIZE    0x800U // 2 kB block
181 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_95)
182 #define RAM0_BLOCKS            1U
183 #define RAM0_BLOCK_SIZE   0x4000U // 16 kB block
184 #define RAM1_BLOCKS            1U
185 #define RAM1_BLOCK_SIZE   0x4000U // 16 kB block
186 #define RAM2_BLOCKS            1U
187 #define RAM2_BLOCK_SIZE    0x800U // 2 kB block
188 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_103)
189 #define RAM0_BLOCKS            4U
190 #define RAM0_BLOCK_SIZE   0x2000U //  8 kB blocks
191 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GIANT_FAMILY)
192 #define RAM0_BLOCKS            4U
193 #define RAM0_BLOCK_SIZE   0x8000U // 32 kB blocks
194 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GECKO_FAMILY)
195 #define RAM0_BLOCKS            4U
196 #define RAM0_BLOCK_SIZE   0x1000U //  4 kB blocks
197 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_100)
198 #define RAM0_BLOCKS            8U
199 #define RAM0_BLOCK_SIZE   0x4000U // 16 kB blocks
200 #define RAM1_BLOCKS            8U
201 #define RAM1_BLOCK_SIZE   0x4000U // 16 kB blocks
202 #define RAM2_BLOCKS            4U
203 #define RAM2_BLOCK_SIZE  0x10000U // 64 kB blocks
204 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_106)
205 #define RAM0_BLOCKS            4U
206 #define RAM0_BLOCK_SIZE   0x4000U // 16 kB blocks
207 #define RAM1_BLOCKS            4U
208 #define RAM1_BLOCK_SIZE   0x4000U // 16 kB blocks
209 #define RAM2_BLOCKS            4U
210 #define RAM2_BLOCK_SIZE   0x4000U // 16 kB blocks
211 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
212 #define RAM0_BLOCKS            6U
213 #define RAM0_BLOCK_SIZE   0x4000U // 16 kB blocks
214 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)
215 #define RAM0_BLOCKS            4U
216 #define RAM0_BLOCK_SIZE   0x4000U // 16 kB blocks
217 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)
218 #define RAM0_BLOCKS           16U
219 #define RAM0_BLOCK_SIZE   0x4000U // 16 kB blocks
220 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)
221 #define RAM0_BLOCKS           16U
222 #define RAM0_BLOCK_SIZE   0x8000U // 32 kB blocks
223 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
224 #define RAM0_BLOCKS           16U
225 #define RAM0_BLOCK_SIZE   0x4000U // 16 kB blocks
226 #endif
227 
228 #if defined(_SILICON_LABS_32B_SERIES_0)
229 /* RAM_MEM_END on Gecko devices have a value larger than the SRAM_SIZE. */
230 #define RAM0_END    (SRAM_BASE + SRAM_SIZE - 1)
231 #else
232 #define RAM0_END    RAM_MEM_END
233 #endif
234 
235 #if defined(CMU_STATUS_HFXOSHUNTOPTRDY)
236 #define HFXO_STATUS_READY_FLAGS  (CMU_STATUS_HFXOPEAKDETRDY | CMU_STATUS_HFXOSHUNTOPTRDY)
237 #elif defined(CMU_STATUS_HFXOPEAKDETRDY)
238 #define HFXO_STATUS_READY_FLAGS  (CMU_STATUS_HFXOPEAKDETRDY)
239 #endif
240 
241 #if defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
242 #if !defined(PWRCFG_DCDCTODVDD_VMIN)
243 /** DCDCTODVDD output range maximum. */
244 #define PWRCFG_DCDCTODVDD_VMIN          1800U
245 #endif
246 #if !defined(PWRCFG_DCDCTODVDD_VMAX)
247 /** DCDCTODVDD output range minimum. */
248 #define PWRCFG_DCDCTODVDD_VMAX          3000U
249 #endif
250 #endif
251 
252 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE) || defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
253 #define DCDC_LP_PFET_CNT        7
254 #define DCDC_LP_NFET_CNT        7
255 #endif
256 
257 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
258 #define EMU_DCDCSTATUS  (*(volatile uint32_t *)(EMU_BASE + 0x7C))
259 #endif
260 
261 #if defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
262 /* Translate fields with different names across platform generations to common names. */
263 #if defined(_EMU_DCDCMISCCTRL_LPCMPBIAS_MASK)
264 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK      _EMU_DCDCMISCCTRL_LPCMPBIAS_MASK
265 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT     _EMU_DCDCMISCCTRL_LPCMPBIAS_SHIFT
266 #elif defined(_EMU_DCDCMISCCTRL_LPCMPBIASEM234H_MASK)
267 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK      _EMU_DCDCMISCCTRL_LPCMPBIASEM234H_MASK
268 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT     _EMU_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT
269 #endif
270 #if defined(_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK)
271 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK      _EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK
272 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT     _EMU_DCDCLPCTRL_LPCMPHYSSEL_SHIFT
273 #elif defined(_EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK)
274 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK      _EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK
275 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT     _EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT
276 #endif
277 
278 /* Disable LP mode hysteresis in the state machine control. */
279 #define EMU_DCDCMISCCTRL_LPCMPHYSDIS (0x1UL << 1)
280 /* Comparator threshold on the high side. */
281 #define EMU_DCDCMISCCTRL_LPCMPHYSHI  (0x1UL << 2)
282 #define EMU_DCDCSMCTRL  (*(volatile uint32_t *)(EMU_BASE + 0x44))
283 
284 #define DCDC_TRIM_MODES ((uint8_t)dcdcTrimMode_LN + 1)
285 #endif
286 
287 #if defined(EMU_SERIES2_DCDC_BUCK_PRESENT) \
288   || defined(EMU_SERIES2_DCDC_BOOST_PRESENT)
289 /* EMU DCDC MODE set timeout. */
290 #define EMU_DCDC_MODE_SET_TIMEOUT           1000000
291 #endif
292 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
293 #define EMU_TESTLOCK         (*(volatile uint32_t *) (EMU_BASE + 0x190))
294 #define EMU_BIASCONF         (*(volatile uint32_t *) (EMU_BASE + 0x164))
295 #define EMU_BIASTESTCTRL     (*(volatile uint32_t *) (EMU_BASE + 0x19C))
296 #define CMU_ULFRCOCTRL       (*(volatile uint32_t *) (CMU_BASE + 0x03C))
297 #endif
298 
299 #if defined(_EMU_TEMP_TEMP_MASK)
300 /* As the energy mode at which a temperature measurement was taken at is
301  * not known, the chosen constant for the TEMPCO calculation is midway between
302  * the EM0/EM1 constant and the EM2/EM3/EM4 constant.
303  */
304 #define EMU_TEMPCO_CONST (0.273f)
305 #endif
306 
307 #define EMU_EM4_ENTRY_WAIT_LOOPS 200
308 
309 /*******************************************************************************
310  ***************************  LOCAL VARIABLES   ********************************
311  ******************************************************************************/
312 
313 /* Static user configuration. */
314 #if defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
315 static uint16_t dcdcMaxCurrent_mA;
316 static uint16_t dcdcEm01LoadCurrent_mA;
317 static EMU_DcdcLnReverseCurrentControl_TypeDef dcdcReverseCurrentControl;
318 #endif
319 #if defined(EMU_VSCALE_EM01_PRESENT)
320 static EMU_EM01Init_TypeDef vScaleEM01Config = { false };
321 #endif
322 
323 /*******************************************************************************
324  **************************   LOCAL FUNCTIONS   ********************************
325  ******************************************************************************/
326 
327 #if defined(EMU_VSCALE_EM01_PRESENT)
328 /* Convert from level to EM0/1 command bit */
vScaleEM01Cmd(EMU_VScaleEM01_TypeDef level)329 __STATIC_INLINE uint32_t vScaleEM01Cmd(EMU_VScaleEM01_TypeDef level)
330 {
331 #if defined(_SILICON_LABS_32B_SERIES_2)
332   return EMU_CMD_EM01VSCALE1 << ((uint32_t)level - _EMU_STATUS_VSCALE_VSCALE1);
333 #else
334   return EMU_CMD_EM01VSCALE0 << (_EMU_STATUS_VSCALE_VSCALE0 - (uint32_t)level);
335 #endif
336 }
337 #endif
338 
339 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205) \
340   || defined(ERRATA_FIX_EMU_E110_ENABLE)
341 SL_RAMFUNC_DECLARATOR static void __attribute__ ((noinline)) ramWFI(void);
342 SL_RAMFUNC_DEFINITION_BEGIN
ramWFI(void)343 static void __attribute__ ((noinline)) ramWFI(void)
344 {
345 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205)
346   __WFI();                      // Enter EM2 or EM3
347   if (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) {
348     for (volatile int i = 0; i < 6; i++) {
349     }                           // Dummy wait loop ...
350   }
351 
352 #else
353   __WFI();                      // Enter EM2 or EM3
354 #if defined(__GNUC__)
355 #pragma GCC diagnostic push
356 #pragma GCC diagnostic ignored "-Warray-bounds"
357 #endif
358   *(volatile uint32_t*)4;       // Clear faulty read data after wakeup
359 #if defined(__GNUC__)
360 #pragma GCC diagnostic pop
361 #endif
362 #endif
363 }
364 SL_RAMFUNC_DEFINITION_END
365 #endif
366 
367 #if defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
368 SL_RAMFUNC_DECLARATOR static void __attribute__ ((noinline)) ramWFI(void);
369 SL_RAMFUNC_DEFINITION_BEGIN
ramWFI(void)370 static void __attribute__ ((noinline)) ramWFI(void)
371 {
372   /* Second part of EMU_E220 DECBOD Errata fix. Calibration needs to be disabled
373    * quickly when coming out of EM2/EM3. Ram execution is needed to meet timing.
374    * Calibration is re-enabled after voltage scaling completes. */
375   uint32_t temp = EMU_PORBOD | EMU_PORBOD_GMC_CALIB_DISABLE;
376   __WFI();
377   EMU_PORBOD = temp;
378 }
379 SL_RAMFUNC_DEFINITION_END
380 #endif
381 
382 #if (_SILICON_LABS_32B_SERIES < 2)
383 /***************************************************************************//**
384  * @brief
385  *   Save/restore/update oscillator, core clock and voltage scaling configuration on
386  *   EM2 or EM3 entry/exit.
387  *
388  * @details
389  *   Hardware may automatically change the oscillator and the voltage scaling configuration
390  *   when going into or out of an energy mode. Static data in this function keeps track of
391  *   such configuration bits and is used to restore state if needed.
392  *
393  ******************************************************************************/
394 typedef enum {
395   emState_Save,         /* Save EMU and CMU state. */
396   emState_Restore,      /* Restore and unlock.     */
397 } emState_TypeDef;
398 
emState(emState_TypeDef action)399 static void emState(emState_TypeDef action)
400 {
401   uint32_t oscEnCmd;
402   uint32_t cmuLocked;
403   static uint32_t cmuStatus;
404   static CMU_Select_TypeDef hfClock;
405 #if defined(EMU_VSCALE_PRESENT)
406   static uint8_t vScaleStatus;
407   static uint32_t hfrcoCtrl;
408 #endif
409 
410   /* Save or update state. */
411   if (action == emState_Save) {
412     /* Save configuration. */
413     cmuStatus = CMU->STATUS;
414     hfClock = CMU_ClockSelectGet(cmuClock_HF);
415 #if defined(EMU_VSCALE_PRESENT)
416     /* Save vscale. */
417     EMU_VScaleWait();
418     vScaleStatus = (uint8_t)((EMU->STATUS & _EMU_STATUS_VSCALE_MASK)
419                              >> _EMU_STATUS_VSCALE_SHIFT);
420     hfrcoCtrl = CMU->HFRCOCTRL;
421 #endif
422   } else { /* Restore state. */
423     /* Apply saved configuration. */
424 #if defined(EMU_VSCALE_PRESENT)
425 #if defined(_SILICON_LABS_32B_SERIES_1)
426     if (EMU_LDOStatusGet() == true)
427     /* Restore voltage scaling level if LDO regulator is on. */
428 #endif
429     {
430       /* Restore EM0 and 1 voltage scaling level.
431          @ref EMU_VScaleWait() is called later,
432          just before HF clock select is set. */
433       EMU->CMD = vScaleEM01Cmd((EMU_VScaleEM01_TypeDef)vScaleStatus);
434     }
435 #endif
436     /* CMU registers may be locked. */
437     cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
438     CMU_Unlock();
439 
440 #if defined(_CMU_OSCENCMD_MASK)
441     /* AUXHFRCO are automatically disabled (except if using debugger). */
442     /* HFRCO, USHFRCO and HFXO are automatically disabled. */
443     /* LFRCO/LFXO may be disabled by SW in EM3. */
444     /* Restore according to status prior to entering energy mode. */
445     oscEnCmd = 0;
446     oscEnCmd |= (cmuStatus & CMU_STATUS_HFRCOENS) != 0U
447                 ? CMU_OSCENCMD_HFRCOEN : 0U;
448     oscEnCmd |= (cmuStatus & CMU_STATUS_AUXHFRCOENS) != 0U
449                 ? CMU_OSCENCMD_AUXHFRCOEN : 0U;
450     oscEnCmd |= (cmuStatus & CMU_STATUS_LFRCOENS) != 0U
451                 ? CMU_OSCENCMD_LFRCOEN : 0U;
452     oscEnCmd |= (cmuStatus & CMU_STATUS_HFXOENS) != 0U
453                 ? CMU_OSCENCMD_HFXOEN : 0U;
454     oscEnCmd |= (cmuStatus & CMU_STATUS_LFXOENS) != 0U
455                 ? CMU_OSCENCMD_LFXOEN : 0U;
456 #if defined(_CMU_STATUS_USHFRCOENS_MASK)
457     oscEnCmd |= (cmuStatus & CMU_STATUS_USHFRCOENS) != 0U
458                 ? CMU_OSCENCMD_USHFRCOEN : 0U;
459 #endif
460     CMU->OSCENCMD = oscEnCmd;
461 #endif
462 
463 #if defined(_EMU_STATUS_VSCALE_MASK)
464     /* Wait for upscale to complete and then restore selected clock. */
465     EMU_VScaleWait();
466     if ((EMU->CTRL & _EMU_CTRL_EM23VSCALEAUTOWSEN_MASK) != 0U) {
467       /* Restore HFRCO frequency which was automatically adjusted by hardware. */
468       while ((CMU->SYNCBUSY & CMU_SYNCBUSY_HFRCOBSY) != 0U) {
469       }
470       CMU->HFRCOCTRL = hfrcoCtrl;
471       if (hfClock == cmuSelect_HFRCO) {
472         /* Optimize wait state after EM2/EM3 wakeup because hardware has
473          * modified them. */
474         CMU_UpdateWaitStates(SystemHfrcoFreq, (int)EMU_VScaleGet());
475       }
476     }
477 #endif
478 
479     switch (hfClock) {
480       case cmuSelect_LFXO:
481         CMU_CLOCK_SELECT_SET(HF, LFXO);
482         break;
483       case cmuSelect_LFRCO:
484         CMU_CLOCK_SELECT_SET(HF, LFRCO);
485         break;
486       case cmuSelect_HFXO:
487         CMU_CLOCK_SELECT_SET(HF, HFXO);
488         break;
489 #if defined(CMU_CMD_HFCLKSEL_USHFRCODIV2)
490       case cmuSelect_USHFRCODIV2:
491         CMU_CLOCK_SELECT_SET(HF, USHFRCODIV2);
492         break;
493 #endif
494 #if defined(CMU_HFCLKSTATUS_SELECTED_HFRCODIV2)
495       case cmuSelect_HFRCODIV2:
496         CMU_CLOCK_SELECT_SET(HF, HFRCODIV2);
497         break;
498 #endif
499 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
500       case cmuSelect_CLKIN0:
501         CMU_CLOCK_SELECT_SET(HF, CLKIN0);
502         break;
503 #endif
504 #if defined(CMU_HFCLKSTATUS_SELECTED_USHFRCO)
505       case cmuSelect_USHFRCO:
506         CMU_CLOCK_SELECT_SET(HF, USHFRCO);
507         break;
508 #endif
509     }
510 
511 #if defined(_CMU_OSCENCMD_MASK)
512     /* If HFRCO was disabled before entering Energy Mode, turn it off again */
513     /* as it is automatically enabled by wake up */
514     if ((cmuStatus & CMU_STATUS_HFRCOENS) == 0U) {
515       CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
516     }
517 #endif
518 
519     /* Restore CMU register locking */
520     if (cmuLocked != 0U) {
521       CMU_Lock();
522     }
523   }
524 }
525 #endif
526 
527 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
528 /* Get enable conditions for errata EMU_E107 fix. */
getErrataFixEmuE107En(void)529 __STATIC_INLINE bool getErrataFixEmuE107En(void)
530 {
531 #if defined(_EFM32_HAPPY_FAMILY)   \
532   || defined(_EFM32_TINY_FAMILY)   \
533   || defined(_EFM32_WONDER_FAMILY) \
534   || defined(_EFM32_ZERO_FAMILY)
535   // all revisions have the errata
536   return true;
537 #else
538   /* SYSTEM_ChipRevisionGet() could have been used here, but a faster implementation
539    * would be needed in this case.
540    */
541   uint16_t majorMinorRev;
542 
543   /* CHIP MAJOR bit [3:0]. */
544   majorMinorRev = ((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
545                    >> _ROMTABLE_PID0_REVMAJOR_SHIFT)
546                   << 8;
547   /* CHIP MINOR bit [7:4]. */
548   majorMinorRev |= ((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
549                     >> _ROMTABLE_PID2_REVMINORMSB_SHIFT)
550                    << 4;
551   /* CHIP MINOR bit [3:0]. */
552   majorMinorRev |= (ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
553                    >> _ROMTABLE_PID3_REVMINORLSB_SHIFT;
554 
555 #if defined(_EFM32_GECKO_FAMILY)
556   // all GECKO revisions except Revision E have the errata
557   return (majorMinorRev <= 0x0103);
558 #elif defined(_EFM32_GIANT_FAMILY)
559   // all LEOPARD GECKO (Major = 0x01 Or 0x02) revisions have the errata
560   // all GIANT GECKO (Major = 0x01) revisions except Revision E have the errata
561   return (majorMinorRev <= 0x0103) || (majorMinorRev == 0x0204) || (majorMinorRev == 0x0205);
562 #else
563   /* Invalid configuration. */
564   EFM_ASSERT(false);
565   /* Return when assertions are disabled. */
566   return false;
567 #endif
568 #endif /* #if defined(_EFM32_ZERO_FAMILY) || defined(_EFM32_HAPPY_FAMILY) #else */
569 }
570 #endif /* #if defined(ERRATA_FIX_EMU_E107_ENABLE) */
571 
572 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
573 /* Get enable conditions for errata EMU_E110 fix. */
getErrataFixEmuE110En(void)574 __STATIC_INLINE bool getErrataFixEmuE110En(void)
575 {
576   /* SYSTEM_ChipRevisionGet() could have been used here, but a faster implementation
577    * would be needed in this case.
578    */
579   uint16_t majorMinorRev;
580 
581   /* CHIP MAJOR bit [3:0]. */
582   majorMinorRev = ((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
583                    >> _ROMTABLE_PID0_REVMAJOR_SHIFT)
584                   << 8;
585   /* CHIP MINOR bit [7:4]. */
586   majorMinorRev |= ((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
587                     >> _ROMTABLE_PID2_REVMINORMSB_SHIFT)
588                    << 4;
589   /* CHIP MINOR bit [3:0]. */
590   majorMinorRev |= (ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
591                    >> _ROMTABLE_PID3_REVMINORLSB_SHIFT;
592 
593 #if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_ZERO_FAMILY)
594   return (majorMinorRev == 0x0100);
595 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_HAPPY_FAMILY)
596   return ((majorMinorRev == 0x0100 || majorMinorRev == 0x0101));
597 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_WONDER_FAMILY)
598   return (majorMinorRev == 0x0100);
599 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GIANT_FAMILY)
600   return (majorMinorRev == 0x0204);
601 #else
602   /* Invalid configuration. */
603   EFM_ASSERT(false);
604   /* Return when assertions are disabled. */
605   return false;
606 #endif
607 }
608 #endif /* #if defined(ERRATA_FIX_EMU_E110_ENABLE) */
609 
610 /* LP prepare / LN restore P/NFET count. */
611 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
612 static void currentLimitersUpdate(void);
dcdcFetCntSet(bool lpModeSet)613 static void dcdcFetCntSet(bool lpModeSet)
614 {
615   uint32_t tmp;
616   static uint32_t emuDcdcMiscCtrlReg;
617 
618   if (lpModeSet) {
619     emuDcdcMiscCtrlReg = EMU->DCDCMISCCTRL;
620     tmp  = EMU->DCDCMISCCTRL
621            & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK | _EMU_DCDCMISCCTRL_NFETCNT_MASK);
622     tmp |= (DCDC_LP_PFET_CNT << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT)
623            | (DCDC_LP_NFET_CNT << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
624     EMU->DCDCMISCCTRL = tmp;
625     currentLimitersUpdate();
626   } else {
627     EMU->DCDCMISCCTRL = emuDcdcMiscCtrlReg;
628     currentLimitersUpdate();
629   }
630 }
631 #endif
632 
633 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
dcdcHsFixLnBlock(void)634 static void dcdcHsFixLnBlock(void)
635 {
636   if ((errataFixDcdcHsState == errataFixDcdcHsTrimSet)
637       || (errataFixDcdcHsState == errataFixDcdcHsBypassLn)) {
638     /* Wait for LNRUNNING */
639     if ((EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK) == EMU_DCDCCTRL_DCDCMODE_LOWNOISE) {
640       while (!(EMU_DCDCSTATUS & (0x1 << 16))) {
641       }
642     }
643     errataFixDcdcHsState = errataFixDcdcHsLnWaitDone;
644   }
645 }
646 #endif
647 
648 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
649 /* Configure EMU and CMU for EM2 and 3 voltage downscale. */
vScaleDownEM23Setup(void)650 static void vScaleDownEM23Setup(void)
651 {
652 #if defined(_SILICON_LABS_32B_SERIES_1)
653   if (EMU_LDOStatusGet() == false) {
654     /* Skip voltage scaling if the LDO regulator is turned off. */
655     return;
656   }
657 #endif
658 
659   /* Wait until previous scaling is done. */
660   EMU_VScaleWait();
661 
662   uint32_t em23vs = (EMU->CTRL & _EMU_CTRL_EM23VSCALE_MASK) >> _EMU_CTRL_EM23VSCALE_SHIFT;
663   uint32_t em01vs = (EMU->STATUS & _EMU_STATUS_VSCALE_MASK) >> _EMU_STATUS_VSCALE_SHIFT;
664 
665   /* Inverse coding. */
666   if (em23vs > em01vs) {
667     EMU->CTRL |= EMU_CTRL_EM23VSCALEAUTOWSEN;
668 #if defined(_MSC_RAMCTRL_RAMWSEN_MASK)
669     /* Set RAM wait states for safe EM2 wakeup. */
670     BUS_RegMaskedSet(&MSC->RAMCTRL, (MSC_RAMCTRL_RAMWSEN
671                                      | MSC_RAMCTRL_RAM1WSEN
672                                      | MSC_RAMCTRL_RAM2WSEN));
673 #endif
674   } else {
675     EMU->CTRL &= ~EMU_CTRL_EM23VSCALEAUTOWSEN;
676   }
677 }
678 
679 /* Handle automatic HFRCO adjustment that may have occurred during EM2/EM3. */
vScaleAfterWakeup(void)680 static void vScaleAfterWakeup(void)
681 {
682   if ((EMU->CTRL & EMU_CTRL_EM23VSCALEAUTOWSEN) != 0U) {
683     /* The hardware may have updated the HFRCOCTRL register during EM2/EM3
684      * entry if voltage scaling in EM2/EM3 is enabled. The hardware would
685      * then update the HFRCO frequency to 19 MHz automatically. */
686     uint32_t freqRange = (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_FREQRANGE_MASK)
687                          >> _CMU_HFRCOCTRL_FREQRANGE_SHIFT;
688     if (freqRange == 0x08U) {
689       SystemHfrcoFreq = 19000000;
690     }
691   }
692 }
693 #endif
694 
695 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
696 typedef enum {
697   dpllState_Save,         /* Save DPLL state. */
698   dpllState_Restore,      /* Restore DPLL.    */
699 } dpllState_TypeDef;
700 
701 /***************************************************************************//**
702  * @brief
703  *   Save or restore DPLL state.
704  *
705  * @param[in] action
706  *    Value to indicate saving DPLL state or restoring its state.
707  *
708  * @note
709  *   The function is used in EMU_Save() and EMU_Restore() to handle the
710  *   DPLL state before entering EM2 or EM3 and after exiting EM2 or EM3.
711  *   The function is required for the EFR32xG22 and EFR32xG27 families.
712  *   On those families devices, the DPLL is disabled automatically when
713  *   entering EM2, EM3. But exiting EM2, EM3 won't re-enable automatically
714  *   the DPLL. Hence, the software needs to re-enable the DPLL upon EM2/3
715  *   exit.
716  ******************************************************************************/
dpllState(dpllState_TypeDef action)717 static void dpllState(dpllState_TypeDef action)
718 {
719   CMU_ClkDiv_TypeDef div;
720   static uint32_t dpllRefClk = CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED;
721 
722   if (action == dpllState_Save) {
723     dpllRefClk = CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED;
724     CMU->CLKEN0_SET = CMU_CLKEN0_DPLL0;
725     if (DPLL0->EN == DPLL_EN_EN) {
726       /* DPLL is in use, save reference clock selection. */
727       dpllRefClk = CMU->DPLLREFCLKCTRL;
728     }
729   } else { /* Restore */
730     if ((dpllRefClk != CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED)
731         && (DPLL0->EN != DPLL_EN_EN)) {
732       /* Restore DPLL reference clock selection. */
733       CMU->DPLLREFCLKCTRL = dpllRefClk;
734       /* Only wait for DPLL lock if HFRCODPLL is used as SYSCLK. */
735       if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
736         /* Set HCLK prescaler to safe value to avoid overclocking while locking. */
737         div = CMU_ClockDivGet(cmuClock_HCLK);
738         if (div == 1U) {
739           CMU_ClockDivSet(cmuClock_HCLK, 2U);
740         }
741 
742         /* Relock DPLL and wait for ready. */
743         DPLL0->IF_CLR = DPLL_IF_LOCK | DPLL_IF_LOCKFAILLOW | DPLL_IF_LOCKFAILHIGH;
744         DPLL0->EN_SET = DPLL_EN_EN;
745         while ((DPLL0->IF & DPLL_IF_LOCK) == 0U) {
746         }
747 
748         /* Restore HCLK prescaler. */
749         if (div == 1U) {
750           CMU_ClockDivSet(cmuClock_HCLK, 1U);
751         }
752       } else {
753         /* Relock DPLL and exit without waiting for ready. */
754         DPLL0->EN_SET = DPLL_EN_EN;
755       }
756     }
757   }
758 }
759 #endif
760 
761 /*******************************************************************************
762  **************************   GLOBAL FUNCTIONS   *******************************
763  ******************************************************************************/
764 
765 /***************************************************************************//**
766  * @addtogroup emu EMU - Energy Management Unit
767  * @brief Energy Management Unit (EMU) Peripheral API
768  * @details
769  *  This module contains functions to control the EMU peripheral of Silicon
770  *  Labs 32-bit MCUs and SoCs. The EMU handles the different low energy modes
771  *  in Silicon Labs microcontrollers.
772  * @{
773  ******************************************************************************/
774 
775 #if defined(EMU_VSCALE_EM01_PRESENT)
776 /***************************************************************************//**
777  * @brief
778  *   Update the EMU module with Energy Mode 0 and 1 configuration.
779  *
780  * @param[in] em01Init
781  *    Energy Mode 0 and 1 configuration structure.
782  ******************************************************************************/
EMU_EM01Init(const EMU_EM01Init_TypeDef * em01Init)783 void EMU_EM01Init(const EMU_EM01Init_TypeDef *em01Init)
784 {
785   vScaleEM01Config.vScaleEM01LowPowerVoltageEnable =
786     em01Init->vScaleEM01LowPowerVoltageEnable;
787   EMU_VScaleEM01ByClock(0, true);
788 }
789 #endif
790 
791 /***************************************************************************//**
792  * @brief
793  *   Update the EMU module with Energy Mode 2 and 3 configuration.
794  *
795  * @param[in] em23Init
796  *    Energy Mode 2 and 3 configuration structure.
797  ******************************************************************************/
EMU_EM23Init(const EMU_EM23Init_TypeDef * em23Init)798 void EMU_EM23Init(const EMU_EM23Init_TypeDef *em23Init)
799 {
800 #if defined(_EMU_CTRL_EMVREG_MASK)
801   EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EMVREG)
802               : (EMU->CTRL & ~EMU_CTRL_EMVREG);
803 #elif defined(_EMU_CTRL_EM23VREG_MASK)
804   EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EM23VREG)
805               : (EMU->CTRL & ~EMU_CTRL_EM23VREG);
806 #else
807   (void)em23Init;
808 #endif
809 
810 #if defined(EMU_VSCALE_PRESENT)
811   EMU->CTRL = (EMU->CTRL & ~_EMU_CTRL_EM23VSCALE_MASK)
812               | ((uint32_t)em23Init->vScaleEM23Voltage << _EMU_CTRL_EM23VSCALE_SHIFT);
813 #if defined(CMU_HFXOCTRL_AUTOSTARTSELEM0EM1)
814   if (em23Init->vScaleEM23Voltage == emuVScaleEM23_LowPower) {
815     /* Voltage scaling is not compatible with HFXO auto start and select. */
816     EFM_ASSERT((CMU->HFXOCTRL & CMU_HFXOCTRL_AUTOSTARTSELEM0EM1) == 0U);
817   }
818 #endif
819 #endif
820 }
821 
822 /***************************************************************************//**
823  * @brief
824  *   Energy mode 2/3 pre-sleep hook function.
825  *
826  * @details
827  *   This function is called by EMU_EnterEM2() and EMU_EnterEM3() functions
828  *   just prior to execution of the WFI instruction. The function implementation
829  *   does not perform anything, but it is SL_WEAK so that it can be re-
830  *   implemented in application code if actions are needed.
831  ******************************************************************************/
EMU_EM23PresleepHook(void)832 SL_WEAK void EMU_EM23PresleepHook(void)
833 {
834 }
835 
836 /***************************************************************************//**
837  * @brief
838  *   EFP's Energy mode 2/3 pre-sleep hook function.
839  *
840  * @details
841  *   This function is similar to @ref EMU_EM23PresleepHook() but is reserved
842  *   for EFP usage.
843  *
844  * @note
845  *   The function is primarily meant to be used in systems with EFP circuitry.
846  *   (EFP = Energy Friendly Pmic (PMIC = Power Management IC)).
847  *   In such systems there is a need to drive certain signals to EFP pins to
848  *   notify about energy mode transitions.
849  ******************************************************************************/
EMU_EFPEM23PresleepHook(void)850 SL_WEAK void EMU_EFPEM23PresleepHook(void)
851 {
852 }
853 
854 /***************************************************************************//**
855  * @brief
856  *   Energy mode 2/3 post-sleep hook function.
857  *
858  * @details
859  *   This function is called by EMU_EnterEM2() and EMU_EnterEM3() functions
860  *   just after wakeup from the WFI instruction. The function implementation
861  *   does not perform anything, but it is SL_WEAK so that it can be re-
862  *   implemented in application code if actions are needed.
863  ******************************************************************************/
EMU_EM23PostsleepHook(void)864 SL_WEAK void EMU_EM23PostsleepHook(void)
865 {
866 }
867 
868 /***************************************************************************//**
869  * @brief
870  *   EFP's Energy mode 2/3 post-sleep hook function.
871  *
872  * @details
873  *   This function is similar to @ref EMU_EM23PostsleepHook() but is reserved
874  *   for EFP usage.
875  *
876  * @note
877  *   The function is primarily meant to be used in systems with EFP circuitry.
878  *   (EFP = Energy Friendly Pmic (PMIC = Power Management IC)).
879  *   In such systems there is a need to drive certain signals to EFP pins to
880  *   notify about energy mode transitions.
881  ******************************************************************************/
EMU_EFPEM23PostsleepHook(void)882 SL_WEAK void EMU_EFPEM23PostsleepHook(void)
883 {
884 }
885 
886 /***************************************************************************//**
887  * @brief
888  *   Enter energy mode 2 (EM2).
889  *
890  * @details
891  *   When entering EM2, high-frequency clocks are disabled, i.e., HFXO, HFRCO
892  *   and AUXHFRCO (for AUXHFRCO, see exception note below). When re-entering
893  *   EM0, HFRCO is re-enabled and the core will be clocked by the configured
894  *   HFRCO band. This ensures a quick wakeup from EM2.
895  *
896  *   However, prior to entering EM2, the core may have been using another
897  *   oscillator than HFRCO. The @p restore parameter gives the user the option
898  *   to restore all HF oscillators according to state prior to entering EM2,
899  *   as well as the clock used to clock the core. This restore procedure is
900  *   handled by SW. However, since handled by SW, it will not be restored
901  *   before completing the interrupt function(s) waking up the core!
902  *
903  * @note
904  *   If restoring core clock to use the HFXO oscillator, which has been
905  *   disabled during EM2 mode, this function will stall until the oscillator
906  *   has stabilized. Stalling time can be reduced by adding interrupt
907  *   support detecting stable oscillator, and an asynchronous switch to the
908  *   original oscillator. See CMU documentation. Such a feature is however
909  *   outside the scope of the implementation in this function.
910  * @note
911  *   If ERRATA_FIX_EMU_E110_ENABLE is active, the core's SLEEPONEXIT feature
912  *   can not be used.
913  * @note
914  *   This function is incompatible with the Power Manager module. When the
915  *   Power Manager module is present, it must be the one deciding at which
916  *   EM level the device sleeps to ensure the application properly works. Using
917  *   both at the same time could lead to undefined behavior in the application.
918  * @par
919  *   If HFXO is re-enabled by this function, and NOT used to clock the core,
920  *   this function will not wait for HFXO to stabilize. This must be considered
921  *   by the application if trying to use features relying on that oscillator
922  *   upon return.
923  * @par
924  *   If a debugger is attached, the AUXHFRCO will not be disabled if enabled
925  *   upon entering EM2. It will thus remain enabled when returning to EM0
926  *   regardless of the @p restore parameter.
927  * @par
928  *   If HFXO autostart and select is enabled by using CMU_HFXOAutostartEnable(),
929  *   the automatic starting and selecting of the core clocks will be done,
930  *   regardless of the @p restore parameter, when waking up on the wakeup
931  *   sources corresponding to the autostart and select setting.
932  * @par
933  *   If voltage scaling is supported, the restore parameter is true and the EM0
934  *   voltage scaling level is set higher than the EM2 level, then the EM0 level is
935  *   also restored.
936  * @par
937  *   On Series 2 Config 2 devices (EFRxG22), this function will also relock the
938  *   DPLL if the DPLL is used and @p restore is true.
939  *
940  *   Note that the hardware will automatically update the HFRCO frequency in the
941  *   case where voltage scaling is used in EM2/EM3 and not in EM0/EM1. When the
942  *   restore argument to this function is true then software will restore the
943  *   original HFRCO frequency after EM2/EM3 wake up. If the restore argument is
944  *   false then the HFRCO frequency is 19 MHz when coming out of EM2/EM3 and
945  *   all wait states are at a safe value.
946  *
947  * @param[in] restore
948  *   @li true - save and restore oscillators, clocks and voltage scaling, see
949  *   function details.
950  *   @li false - do not save and restore oscillators and clocks, see function
951  *   details.
952  * @par
953  *   The @p restore option should only be used if all clock control is done
954  *   via the CMU API.
955  ******************************************************************************/
EMU_EnterEM2(bool restore)956 void EMU_EnterEM2(bool restore)
957 {
958 #if defined(SLI_METRIC_EM2_HOOK)
959   sli_metric_em23_wake_init(SLI_INIT_EM2_WAKE);
960 #endif
961 
962 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
963   bool errataFixEmuE107En;
964   uint32_t nonWicIntEn[2];
965 #endif
966 
967 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
968   bool errataFixEmuE110En;
969 #endif
970 
971 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
972   if (restore) {
973     dpllState(dpllState_Save);
974   }
975 #endif
976 
977 #if (_SILICON_LABS_32B_SERIES < 2)
978   /* Only save EMU and CMU state if restored on wake-up. */
979   if (restore) {
980     emState(emState_Save);
981   }
982 #endif
983 
984 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
985   vScaleDownEM23Setup();
986 #endif
987 
988   /* Enter Cortex deep sleep mode. */
989   SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
990 
991   /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
992      Disable the enabled non-WIC interrupts. */
993 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
994   errataFixEmuE107En = getErrataFixEmuE107En();
995   if (errataFixEmuE107En) {
996     nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
997     NVIC->ICER[0] = nonWicIntEn[0];
998 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
999     nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
1000     NVIC->ICER[1] = nonWicIntEn[1];
1001 #endif
1002   }
1003 #endif
1004 
1005 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
1006   dcdcFetCntSet(true);
1007 #endif
1008 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
1009   dcdcHsFixLnBlock();
1010 #endif
1011 
1012   EMU_EM23PresleepHook();
1013   EMU_EFPEM23PresleepHook();
1014 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205) \
1015   || defined(ERRATA_FIX_EMU_E110_ENABLE)
1016 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
1017   errataFixEmuE110En = getErrataFixEmuE110En();
1018   if (errataFixEmuE110En) {
1019 #endif
1020   CORE_CRITICAL_SECTION(ramWFI(); )
1021 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
1022 } else {
1023   __WFI();
1024 }
1025 #endif
1026 #elif defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
1027   // Apply errata fix if voltage scaling in EM2 is used.
1028   if ((EMU->CTRL & EMU_CTRL_EM23VSCALEAUTOWSEN) != 0U) {
1029     CORE_CRITICAL_SECTION(ramWFI(); )
1030   } else {
1031     __WFI();
1032   }
1033 #else
1034   __WFI();
1035 #endif
1036   EMU_EFPEM23PostsleepHook();
1037   EMU_EM23PostsleepHook();
1038 
1039 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
1040   dcdcFetCntSet(false);
1041 #endif
1042 
1043   /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
1044 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
1045   if (errataFixEmuE107En) {
1046     NVIC->ISER[0] = nonWicIntEn[0];
1047 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
1048     NVIC->ISER[1] = nonWicIntEn[1];
1049 #endif
1050   }
1051 #endif
1052 
1053 #if (_SILICON_LABS_32B_SERIES < 2)
1054   /* Restore oscillators/clocks and voltage scaling if supported. */
1055   if (restore) {
1056     emState(emState_Restore);
1057   }
1058 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
1059   else {
1060     vScaleAfterWakeup();
1061   }
1062 #if defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
1063   /* Third part of EMU_E220 DECBOD Errata fix. Calibration needs to be enabled
1064    * after voltage scaling completes. */
1065   EMU_PORBOD &= ~(EMU_PORBOD_GMC_CALIB_DISABLE);
1066 #endif
1067 #endif
1068 #endif
1069 
1070 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
1071   if (restore) {
1072     dpllState(dpllState_Restore);
1073   }
1074 #endif
1075 
1076   if (!restore) {
1077     /* If not restoring, and the original clock was not HFRCO, the CMSIS */
1078     /* core clock variable must be updated since HF clock has changed */
1079     /* to HFRCO. */
1080     SystemCoreClockUpdate();
1081   }
1082 }
1083 
1084 /***************************************************************************//**
1085  * @brief
1086  *   Enter energy mode 3 (EM3).
1087  *
1088  * @details
1089  *   When entering EM3, the high-frequency clocks are disabled by hardware, i.e., HFXO,
1090  *   HFRCO, and AUXHFRCO (for AUXHFRCO, see exception note below). In addition,
1091  *   the low-frequency clocks, i.e., LFXO and LFRCO are disabled by software. When
1092  *   re-entering EM0, HFRCO is re-enabled and the core will be clocked by the
1093  *   configured HFRCO band. This ensures a quick wakeup from EM3.
1094  *
1095  *   However, prior to entering EM3, the core may have been using an
1096  *   oscillator other than HFRCO. The @p restore parameter gives the user the option
1097  *   to restore all HF/LF oscillators according to state prior to entering EM3,
1098  *   as well as the clock used to clock the core. This restore procedure is
1099  *   handled by software. However, since it is handled by software, it will not be restored
1100  *   before completing the interrupt function(s) waking up the core!
1101  *
1102  * @note
1103  *   If restoring core clock to use an oscillator other than HFRCO, this
1104  *   function will stall until the oscillator has stabilized. Stalling time
1105  *   can be reduced by adding interrupt support detecting stable oscillator,
1106  *   and an asynchronous switch to the original oscillator. See CMU
1107  *   documentation. This feature is, however, outside the scope of the
1108  *   implementation in this function.
1109  * @note
1110  *   If ERRATA_FIX_EMU_E110_ENABLE is active, the core's SLEEPONEXIT feature
1111  *   can't be used.
1112  * @note
1113  *   This function is incompatible with the Power Manager module. When the
1114  *   Power Manager module is present, it must be the one deciding at which
1115  *   EM level the device sleeps to ensure the application properly works. Using
1116  *   both at the same time could lead to undefined behavior in the application.
1117  * @par
1118  *   If HFXO/LFXO/LFRCO are re-enabled by this function, and NOT used to clock
1119  *   the core, this function will not wait for those oscillators to stabilize.
1120  *   This must be considered by the application if trying to use features
1121  *   relying on those oscillators upon return.
1122  * @par
1123  *   If a debugger is attached, the AUXHFRCO will not be disabled if enabled
1124  *   upon entering EM3. It will, therefore, remain enabled when returning to EM0
1125  *   regardless of the @p restore parameter.
1126  * @par
1127  *   If voltage scaling is supported, the restore parameter is true and the EM0
1128  *   voltage scaling level is set higher than the EM3 level, then the EM0 level is
1129  *   also restored.
1130  * @par
1131  *   On Series 2 Config 2 devices (EFRxG22), this function will also relock the
1132  *   DPLL if the DPLL is used and @p restore is true.
1133  *
1134  * @param[in] restore
1135  *   @li true - save and restore oscillators, clocks and voltage scaling, see
1136  *   function details.
1137  *   @li false - do not save and restore oscillators and clocks, see function
1138  *   details.
1139  * @par
1140  *   The @p restore option should only be used if all clock control is done
1141  *   via the CMU API.
1142  ******************************************************************************/
EMU_EnterEM3(bool restore)1143 void EMU_EnterEM3(bool restore)
1144 {
1145 #if defined(SLI_METRIC_EM3_HOOK)
1146   sli_metric_em23_wake_init(SLI_INIT_EM3_WAKE);
1147 #endif
1148 
1149 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
1150   bool errataFixEmuE107En;
1151   uint32_t nonWicIntEn[2];
1152 #endif
1153 
1154 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
1155   bool errataFixEmuE110En;
1156 #endif
1157 
1158 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
1159   if (restore) {
1160     dpllState(dpllState_Save);
1161   }
1162 #endif
1163 
1164 #if (_SILICON_LABS_32B_SERIES < 2)
1165   /* Only save EMU and CMU state if restored on wake-up. */
1166   if (restore) {
1167     emState(emState_Save);
1168   }
1169 #endif
1170 
1171 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
1172   vScaleDownEM23Setup();
1173 #endif
1174 
1175 #if defined(_CMU_OSCENCMD_MASK)
1176   uint32_t cmuLocked;
1177   cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
1178   CMU_Unlock();
1179 
1180   /* Disable LF oscillators. */
1181   CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS | CMU_OSCENCMD_LFRCODIS;
1182 
1183   /* Restore CMU register locking. */
1184   if (cmuLocked != 0U) {
1185     CMU_Lock();
1186   }
1187 #endif
1188 
1189   /* Enter Cortex deep sleep mode. */
1190   SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
1191 
1192   /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
1193      Disable the enabled non-WIC interrupts. */
1194 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
1195   errataFixEmuE107En = getErrataFixEmuE107En();
1196   if (errataFixEmuE107En) {
1197     nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
1198     NVIC->ICER[0] = nonWicIntEn[0];
1199 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
1200     nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
1201     NVIC->ICER[1] = nonWicIntEn[1];
1202 #endif
1203   }
1204 #endif
1205 
1206 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
1207   dcdcFetCntSet(true);
1208 #endif
1209 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
1210   dcdcHsFixLnBlock();
1211 #endif
1212 
1213   EMU_EM23PresleepHook();
1214 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205) \
1215   || defined(ERRATA_FIX_EMU_E110_ENABLE)
1216 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
1217   errataFixEmuE110En = getErrataFixEmuE110En();
1218   if (errataFixEmuE110En) {
1219 #endif
1220   CORE_CRITICAL_SECTION(ramWFI(); )
1221 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
1222 } else {
1223   __WFI();
1224 }
1225 #endif
1226 #elif defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
1227   // Apply errata fix if voltage scaling in EM2 is used.
1228   if ((EMU->CTRL & EMU_CTRL_EM23VSCALEAUTOWSEN) != 0U) {
1229     CORE_CRITICAL_SECTION(ramWFI(); )
1230   } else {
1231     __WFI();
1232   }
1233 #else
1234   __WFI();
1235 #endif
1236   EMU_EM23PostsleepHook();
1237 
1238 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
1239   dcdcFetCntSet(false);
1240 #endif
1241 
1242   /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
1243 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
1244   if (errataFixEmuE107En) {
1245     NVIC->ISER[0] = nonWicIntEn[0];
1246 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
1247     NVIC->ISER[1] = nonWicIntEn[1];
1248 #endif
1249   }
1250 #endif
1251 
1252 #if (_SILICON_LABS_32B_SERIES < 2)
1253   /* Restore oscillators/clocks and voltage scaling if supported. */
1254   if (restore) {
1255     emState(emState_Restore);
1256   }
1257 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
1258   else {
1259     vScaleAfterWakeup();
1260   }
1261 #if defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
1262   /* Third part of EMU_E220 DECBOD Errata fix. Calibration needs to be enabled
1263    * after voltage scaling completes. */
1264   EMU_PORBOD &= ~(EMU_PORBOD_GMC_CALIB_DISABLE);
1265 #endif
1266 #endif
1267 #endif
1268 
1269 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
1270   if (restore) {
1271     dpllState(dpllState_Restore);
1272   }
1273 #endif
1274 
1275   if (!restore) {
1276     /* If not restoring, and the original clock was not HFRCO, the CMSIS */
1277     /* core clock variable must be updated since HF clock has changed */
1278     /* to HFRCO. */
1279     SystemCoreClockUpdate();
1280   }
1281 }
1282 
1283 /***************************************************************************//**
1284  * @brief
1285  *   Save the CMU HF clock select state, oscillator enable, and voltage scaling
1286  *   (if available) before @ref EMU_EnterEM2() or @ref EMU_EnterEM3() are called
1287  *   with the restore parameter set to false. Calling this function is
1288  *   equivalent to calling @ref EMU_EnterEM2() or @ref EMU_EnterEM3() with the
1289  *   restore parameter set to true, but it allows the state to be saved without
1290  *   going to sleep. The state can be restored manually by calling
1291  *   @ref EMU_Restore().
1292  ******************************************************************************/
EMU_Save(void)1293 void EMU_Save(void)
1294 {
1295 #if (_SILICON_LABS_32B_SERIES < 2)
1296   emState(emState_Save);
1297 #endif
1298 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
1299   dpllState(dpllState_Save);
1300 #endif
1301 }
1302 
1303 /***************************************************************************//**
1304  * @brief
1305  *   Restore CMU HF clock select state, oscillator enable, and voltage scaling
1306  *   (if available) after @ref EMU_EnterEM2() or @ref EMU_EnterEM3() are called
1307  *   with the restore parameter set to false. Calling this function is
1308  *   equivalent to calling @ref EMU_EnterEM2() or @ref EMU_EnterEM3() with the
1309  *   restore parameter set to true, but it allows the application to evaluate the
1310  *   wakeup reason before restoring state.
1311  ******************************************************************************/
EMU_Restore(void)1312 void EMU_Restore(void)
1313 {
1314 #if (_SILICON_LABS_32B_SERIES < 2)
1315   emState(emState_Restore);
1316 #endif
1317 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
1318   dpllState(dpllState_Restore);
1319 #endif
1320 }
1321 
1322 #if defined(_EMU_EM4CONF_MASK) || defined(_EMU_EM4CTRL_MASK)
1323 /***************************************************************************//**
1324  * @brief
1325  *   Update the EMU module with Energy Mode 4 configuration.
1326  *
1327  * @param[in] em4Init
1328  *    Energy Mode 4 configuration structure.
1329  ******************************************************************************/
EMU_EM4Init(const EMU_EM4Init_TypeDef * em4Init)1330 void EMU_EM4Init(const EMU_EM4Init_TypeDef *em4Init)
1331 {
1332 #if defined(_EMU_EM4CONF_MASK)
1333   /* Initialization for platforms with EMU->EM4CONF register. */
1334   uint32_t em4conf = EMU->EM4CONF;
1335 
1336   /* Clear fields that will be reconfigured. */
1337   em4conf &= ~(_EMU_EM4CONF_LOCKCONF_MASK
1338                | _EMU_EM4CONF_OSC_MASK
1339                | _EMU_EM4CONF_BURTCWU_MASK
1340                | _EMU_EM4CONF_VREGEN_MASK
1341                | _EMU_EM4CONF_BUBODRSTDIS_MASK);
1342 
1343   /* Configure new settings. */
1344   em4conf |= (em4Init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT)
1345              | (em4Init->osc)
1346              | (em4Init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT)
1347              | (em4Init->vreg << _EMU_EM4CONF_VREGEN_SHIFT)
1348              | (em4Init->buBodRstDis << _EMU_EM4CONF_BUBODRSTDIS_SHIFT);
1349 
1350   /* Apply configuration. Note that lock can be set after this stage. */
1351   EMU->EM4CONF = em4conf;
1352 
1353 #elif defined(_EMU_EM4CTRL_EM4STATE_MASK)
1354   /* Initialization for platforms with EMU->EM4CTRL register and EM4H and EM4S. */
1355 
1356   uint32_t em4ctrl = EMU->EM4CTRL;
1357 
1358   em4ctrl &= ~(_EMU_EM4CTRL_RETAINLFXO_MASK
1359                | _EMU_EM4CTRL_RETAINLFRCO_MASK
1360                | _EMU_EM4CTRL_RETAINULFRCO_MASK
1361                | _EMU_EM4CTRL_EM4STATE_MASK
1362                | _EMU_EM4CTRL_EM4IORETMODE_MASK);
1363 
1364   em4ctrl |= (em4Init->retainLfxo     ? EMU_EM4CTRL_RETAINLFXO : 0U)
1365              | (em4Init->retainLfrco  ? EMU_EM4CTRL_RETAINLFRCO : 0U)
1366              | (em4Init->retainUlfrco ? EMU_EM4CTRL_RETAINULFRCO : 0U)
1367              | (em4Init->em4State == emuEM4Hibernate
1368                 ? EMU_EM4CTRL_EM4STATE_EM4H : 0U)
1369              | ((uint32_t)em4Init->pinRetentionMode);
1370 
1371   EMU->EM4CTRL = em4ctrl;
1372 #elif defined(_EMU_EM4CTRL_MASK)
1373   EMU->EM4CTRL = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4IORETMODE_MASK)
1374                  | (uint32_t)em4Init->pinRetentionMode;
1375 #endif
1376 
1377 #if defined(_EMU_CTRL_EM4HVSCALE_MASK)
1378   EMU->CTRL = (EMU->CTRL & ~_EMU_CTRL_EM4HVSCALE_MASK)
1379               | ((uint32_t)em4Init->vScaleEM4HVoltage << _EMU_CTRL_EM4HVSCALE_SHIFT);
1380 #endif
1381 }
1382 #endif
1383 
1384 /***************************************************************************//**
1385  * @brief
1386  *   Energy mode 4 pre-sleep hook function.
1387  *
1388  * @details
1389  *   This function is called by @ref EMU_EnterEM4() just prior to the sequence
1390  *   of writes to put the device in EM4. The function implementation does not
1391  *   perform anything, but it is SL_WEAK so that it can be re-implemented in
1392  *   application code if actions are needed.
1393  ******************************************************************************/
EMU_EM4PresleepHook(void)1394 SL_WEAK void EMU_EM4PresleepHook(void)
1395 {
1396 }
1397 
1398 /***************************************************************************//**
1399  * @brief
1400  *   EFP's Energy mode 4 pre-sleep hook function.
1401  *
1402  * @details
1403  *   This function is similar to @ref EMU_EM4PresleepHook() but is reserved for
1404  *   EFP usage.
1405  *
1406  * @note
1407  *   The function is primarily meant to be used in systems with EFP circuitry.
1408  *   (EFP = Energy Friendly Pmic (PMIC = Power Management IC)).
1409  *   In such systems there is a need to drive certain signals to EFP pins to
1410  *   notify about energy mode transitions.
1411  ******************************************************************************/
EMU_EFPEM4PresleepHook(void)1412 SL_WEAK void EMU_EFPEM4PresleepHook(void)
1413 {
1414 }
1415 
1416 /***************************************************************************//**
1417  * @brief
1418  *   Enter energy mode 4 (EM4).
1419  *
1420  * @note
1421  *   Only a power on reset or external reset pin can wake the device from EM4.
1422  ******************************************************************************/
EMU_EnterEM4(void)1423 void EMU_EnterEM4(void)
1424 {
1425 #if defined(SL_CATALOG_METRIC_EM4_WAKE_PRESENT)
1426   sli_metric_em4_wake_init();
1427 #endif
1428   int i;
1429 
1430 #if defined(_EMU_EM4CTRL_EM4ENTRY_SHIFT)
1431   uint32_t em4seq2 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
1432                      | (2U << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
1433   uint32_t em4seq3 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
1434                      | (3U << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
1435 #else
1436   uint32_t em4seq2 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
1437                      | (2U << _EMU_CTRL_EM4CTRL_SHIFT);
1438   uint32_t em4seq3 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
1439                      | (3U << _EMU_CTRL_EM4CTRL_SHIFT);
1440 #endif
1441 
1442   /* Make sure that the register write lock is disabled. */
1443   EMU_Unlock();
1444 
1445 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
1446   /* The DCDC is not supported in EM4S. EFM32xG1 and EFR32xG1 devices should
1447    * switch to bypass mode before entering EM4S. Other devices handle this
1448    * automatically at the hardware level. */
1449   if ((EMU->EM4CTRL & _EMU_EM4CTRL_EM4STATE_MASK) == EMU_EM4CTRL_EM4STATE_EM4S) {
1450     uint32_t dcdcMode = EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK;
1451     if (dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWNOISE
1452         || dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWPOWER) {
1453       EMU_DCDCModeSet(emuDcdcMode_Bypass);
1454     }
1455   }
1456 #endif
1457 
1458 #if defined(_DCDC_IF_EM4ERR_MASK)
1459   /* Make sure DCDC Mode is not modified, from this point forward,
1460    * by another code section. */
1461   CORE_DECLARE_IRQ_STATE;
1462   CORE_ENTER_CRITICAL();
1463 
1464   /* Workaround for bug that may cause a Hard Fault on EM4 entry */
1465   CMU_CLOCK_SELECT_SET(SYSCLK, FSRCO);
1466   /* The buck DC-DC is available in all energy modes except for EM4.
1467    * The DC-DC converter must first be turned off and switched over to bypass mode. */
1468 #if defined(EMU_SERIES1_DCDC_BUCK_PRESENT)   \
1469   || (defined(EMU_SERIES2_DCDC_BUCK_PRESENT) \
1470   || defined(EMU_SERIES2_DCDC_BOOST_PRESENT))
1471   EMU_DCDCModeSet(emuDcdcMode_Bypass);
1472 #endif
1473 #endif
1474 
1475 #if defined(_EMU_EM4CTRL_MASK) && defined(ERRATA_FIX_EMU_E208_ENABLE)
1476   if (EMU->EM4CTRL & EMU_EM4CTRL_EM4STATE_EM4H) {
1477     /* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H.
1478      * Full description of errata fix can be found in the errata document. */
1479     __disable_irq();
1480     *(volatile uint32_t *)(EMU_BASE + 0x190UL)  = 0x0000ADE8UL;
1481     *(volatile uint32_t *)(EMU_BASE + 0x198UL) |= (0x1UL << 7);
1482     *(volatile uint32_t *)(EMU_BASE + 0x88UL)  |= (0x1UL << 8);
1483   }
1484 #endif
1485 
1486 #if defined(ERRATA_FIX_EMU_E108_ENABLE)
1487   /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
1488   __disable_irq();
1489   *(volatile uint32_t *)0x400C80E4 = 0;
1490 #endif
1491 
1492 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
1493   dcdcFetCntSet(true);
1494 #endif
1495 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
1496   dcdcHsFixLnBlock();
1497 #endif
1498 
1499 #if defined(ERRATA_FIX_EM4S_DELAY_ENTRY)
1500   /* Fix for errata where firmware must clear ANASW and delay EM4S entry by 30 us. */
1501   if ((EMU->EM4CTRL & _EMU_EM4CTRL_EM4STATE_MASK) == EMU_EM4CTRL_EM4STATE_EM4S) {
1502     if ((EMU->PWRCTRL & _EMU_PWRCTRL_ANASW_MASK) == EMU_PWRCTRL_ANASW_DVDD) {
1503       BUS_RegMaskedClear(&EMU->PWRCTRL, _EMU_PWRCTRL_ANASW_MASK);
1504       /* Switch to 1 MHz HFRCO. This delays enough to meet the 30 us requirement
1505        * before entering EM4. */
1506       uint32_t freqCal = (DEVINFO->HFRCOCAL0 & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
1507                          | CMU_HFRCOCTRL_CLKDIV_DIV4;
1508       while ((CMU->SYNCBUSY & CMU_SYNCBUSY_HFRCOBSY) != 0UL) {
1509       }
1510       CMU->HFRCOCTRL = freqCal;
1511       CMU->OSCENCMD = CMU_OSCENCMD_HFRCOEN;
1512       while ((CMU->STATUS & CMU_STATUS_HFRCORDY) == 0U) {
1513       }
1514       CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCO;
1515       __NOP();
1516     }
1517   }
1518 #endif
1519 
1520   EMU_EM4PresleepHook();
1521   EMU_EFPEM4PresleepHook();
1522 
1523   for (i = 0; i < 4; i++) {
1524 #if defined(_EMU_EM4CTRL_EM4ENTRY_SHIFT)
1525     EMU->EM4CTRL = em4seq2;
1526     EMU->EM4CTRL = em4seq3;
1527   }
1528   EMU->EM4CTRL = em4seq2;
1529 #else
1530     EMU->CTRL = em4seq2;
1531     EMU->CTRL = em4seq3;
1532   }
1533   EMU->CTRL = em4seq2;
1534 #endif
1535 
1536 #if defined(_DCDC_IF_EM4ERR_MASK)
1537   EFM_ASSERT((DCDC->IF & _DCDC_IF_EM4ERR_MASK) == 0);
1538   CORE_EXIT_CRITICAL();
1539 #endif
1540 }
1541 
1542 /***************************************************************************//**
1543  * @brief
1544  *   Enter energy mode 4 (EM4).
1545  *
1546  * @details
1547  *   This function waits after the EM4 entry request to make sure the CPU
1548  *   is properly shutdown or the EM4 entry failed.
1549  *
1550  * @note
1551  *   Only a power on reset or external reset pin can wake the device from EM4.
1552  ******************************************************************************/
EMU_EnterEM4Wait(void)1553 void EMU_EnterEM4Wait(void)
1554 {
1555   EMU_EnterEM4();
1556 
1557   // The EM4 entry waiting loop should take 4 cycles by loop minimally (Compiler dependent).
1558   // We would then wait for (EMU_EM4_ENTRY_WAIT_LOOPS * 4) clock cycles.
1559   for (uint16_t i = 0; i < EMU_EM4_ENTRY_WAIT_LOOPS; i++) {
1560     __NOP();
1561   }
1562 }
1563 
1564 #if defined(_EMU_EM4CTRL_MASK)
1565 /***************************************************************************//**
1566  * @brief
1567  *   Enter energy mode 4 hibernate (EM4H).
1568  *
1569  * @note
1570  *   Retention of clocks and GPIO in EM4 can be configured using
1571  *   @ref EMU_EM4Init before calling this function.
1572  ******************************************************************************/
EMU_EnterEM4H(void)1573 void EMU_EnterEM4H(void)
1574 {
1575 #if defined(_EMU_EM4CTRL_EM4STATE_MASK)
1576   BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 1);
1577 #endif
1578   EMU_EnterEM4();
1579 }
1580 
1581 /***************************************************************************//**
1582  * @brief
1583  *   Enter energy mode 4 shutoff (EM4S).
1584  *
1585  * @note
1586  *   Retention of clocks and GPIO in EM4 can be configured using
1587  *   @ref EMU_EM4Init before calling this function.
1588  ******************************************************************************/
EMU_EnterEM4S(void)1589 void EMU_EnterEM4S(void)
1590 {
1591 #if defined(_EMU_EM4CTRL_EM4STATE_MASK)
1592   BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 0);
1593 #endif
1594   EMU_EnterEM4();
1595 }
1596 #endif
1597 
1598 /***************************************************************************//**
1599  * @brief
1600  *   Power down memory block.
1601  *
1602  * @param[in] blocks
1603  *   Specifies a logical OR of bits indicating memory blocks to power down.
1604  *   Bit 0 selects block 1, bit 1 selects block 2, and so on. Memory block 0 cannot
1605  *   be disabled. See the reference manual for available
1606  *   memory blocks for a device.
1607  *
1608  * @note
1609  *   Only a POR reset can power up the specified memory block(s) after power down.
1610  *
1611  * @deprecated
1612  *   This function is deprecated, use @ref EMU_RamPowerDown() instead which
1613  *   maps a user provided memory range into RAM blocks to power down.
1614  ******************************************************************************/
EMU_MemPwrDown(uint32_t blocks)1615 void EMU_MemPwrDown(uint32_t blocks)
1616 {
1617 #if defined(_EMU_MEMCTRL_MASK)
1618   EMU->MEMCTRL = blocks & _EMU_MEMCTRL_MASK;
1619 #elif defined(_EMU_RAM0CTRL_MASK)
1620   EMU->RAM0CTRL = blocks & _EMU_RAM0CTRL_MASK;
1621 #else
1622   (void)blocks;
1623 #endif
1624 }
1625 
1626 /***************************************************************************//**
1627  * @brief
1628  *   Power down RAM memory blocks.
1629  *
1630  * @details
1631  *   This function will power down all the RAM blocks that are within a given
1632  *   range. The RAM block layout is different between device families, so this
1633  *   function can be used in a generic way to power down a RAM memory region
1634  *   which is known to be unused.
1635  *
1636  *   This function will only power down blocks which are completely enclosed
1637  *   by the memory range given by [start, end).
1638  *
1639  *   This is an example to power down all RAM blocks except the first
1640  *   one. The first RAM block is special in that it cannot be powered down
1641  *   by the hardware. The size of the first RAM block is device-specific.
1642  *   See the reference manual to find the RAM block sizes.
1643  *
1644  * @code
1645  *   EMU_RamPowerDown(SRAM_BASE, SRAM_BASE + SRAM_SIZE);
1646  * @endcode
1647  *
1648  * @note
1649  *   Only a reset can power up the specified memory block(s) after power down
1650  *   on a series 0 device. The specified memory block(s) will stay off
1651  *   until a call to EMU_RamPowerUp() is done on series 1/2.
1652  *
1653  * @param[in] start
1654  *   The start address of the RAM region to power down. This address is
1655  *   inclusive.
1656  *
1657  * @param[in] end
1658  *   The end address of the RAM region to power down. This address is
1659  *   exclusive. If this parameter is 0, all RAM blocks contained in the
1660  *   region from start to the upper RAM address will be powered down.
1661  ******************************************************************************/
EMU_RamPowerDown(uint32_t start,uint32_t end)1662 void EMU_RamPowerDown(uint32_t start, uint32_t end)
1663 {
1664   uint32_t mask = 0;
1665   (void) start;
1666 
1667   if (end == 0U) {
1668     end = SRAM_BASE + SRAM_SIZE;
1669   }
1670 
1671   // Check to see if something in RAM0 can be powered down.
1672   if (end > RAM0_END) {
1673 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84) // EFM32xG12 and EFR32xG12
1674     // Block 0 is 16 kB and cannot be powered off.
1675     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20004000UL) << 0; // Block 1, 16 kB
1676     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20008000UL) << 1; // Block 2, 16 kB
1677     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x2000C000UL) << 2; // Block 3, 16 kB
1678     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20010000UL) << 3; // Block 4, 64 kB
1679 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) // EFM32xG1 and EFR32xG1
1680     // Block 0 is 4 kB and cannot be powered off.
1681     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20001000UL) << 0; // Block 1, 4 kB
1682     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20002000UL) << 1; // Block 2, 8 kB
1683     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20004000UL) << 2; // Block 3, 8 kB
1684     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20006000UL) << 3; // Block 4, 7 kB
1685 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1686     // Lynx has 2 blocks. We do no shut off block 0 because we dont want to disable all RAM0
1687     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20006000UL) << 1; // Block 1, 8 kB
1688 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
1689     // Leopard has 3 blocks. We do no shut off block 0 because we dont want to disable all RAM0
1690     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20006000UL) << 1; // Block 1, 8 kB
1691     mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20008000UL) << 2; // Block 2, 32 kB
1692 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
1693     // These platforms have equally-sized RAM blocks and block 0 can be powered down but should not.
1694     // This condition happens when the block 0 disable bit flag is available in the retention control register.
1695     for (unsigned i = 1; i < RAM0_BLOCKS; i++) {
1696       mask |= ADDRESS_NOT_IN_BLOCK(start, RAM_MEM_BASE + (i * RAM0_BLOCK_SIZE)) << (i);
1697     }
1698 #elif defined(RAM0_BLOCKS)
1699     // These platforms have equally-sized RAM blocks and block 0 cannot be powered down.
1700     for (unsigned i = 1; i < RAM0_BLOCKS; i++) {
1701       mask |= ADDRESS_NOT_IN_BLOCK(start, RAM_MEM_BASE + (i * RAM0_BLOCK_SIZE)) << (i - 1U);
1702     }
1703 #endif
1704   }
1705 
1706   // Power down the selected blocks.
1707 #if defined(_EMU_MEMCTRL_MASK)
1708   EMU->MEMCTRL = EMU->MEMCTRL   | mask;
1709 #elif defined(_EMU_RAM0CTRL_MASK)
1710   EMU->RAM0CTRL = EMU->RAM0CTRL | mask;
1711 #elif defined(_SILICON_LABS_32B_SERIES_2)
1712 #if defined(CMU_CLKEN0_SYSCFG)
1713   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1714 #endif
1715   SYSCFG_maskDmem0RetnCtrl(mask);
1716 #else
1717   // These devices are unable to power down RAM blocks.
1718   (void) mask;
1719   (void) start;
1720 #endif
1721 
1722 #if defined(RAM1_MEM_END)
1723   mask = 0;
1724   if (end > RAM1_MEM_END) {
1725     for (unsigned i = 0; i < RAM1_BLOCKS; i++) {
1726       mask |= ADDRESS_NOT_IN_BLOCK(start, RAM1_MEM_BASE + (i * RAM1_BLOCK_SIZE)) << i;
1727     }
1728   }
1729   EMU->RAM1CTRL |= mask;
1730 #endif
1731 
1732 #if defined(RAM2_MEM_END)
1733   mask = 0;
1734   if (end > RAM2_MEM_END) {
1735     for (unsigned i = 0; i < RAM2_BLOCKS; i++) {
1736       mask |= ADDRESS_NOT_IN_BLOCK(start, RAM2_MEM_BASE + (i * RAM2_BLOCK_SIZE)) << i;
1737     }
1738   }
1739   EMU->RAM2CTRL |= mask;
1740 #endif
1741 }
1742 
1743 /***************************************************************************//**
1744  * @brief
1745  *   Power up all available RAM memory blocks.
1746  *
1747  * @details
1748  *   This function will power up all the RAM blocks on a device, this means
1749  *   that the RAM blocks are retained in EM2/EM3. Note that this functionality
1750  *   is not supported on Series 0 devices. Only a reset will power up the RAM
1751  *   blocks on a series 0 device.
1752  ******************************************************************************/
EMU_RamPowerUp(void)1753 void EMU_RamPowerUp(void)
1754 {
1755 #if defined(_EMU_RAM0CTRL_MASK)
1756   EMU->RAM0CTRL = 0x0UL;
1757 #endif
1758 #if defined(_EMU_RAM1CTRL_MASK)
1759   EMU->RAM1CTRL = 0x0UL;
1760 #endif
1761 #if defined(_EMU_RAM2CTRL_MASK)
1762   EMU->RAM2CTRL = 0x0UL;
1763 #endif
1764 #if defined(_SYSCFG_DMEM0RETNCTRL_MASK)
1765 #if defined(CMU_CLKEN0_SYSCFG)
1766   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1767 #endif
1768   SYSCFG_zeroDmem0RetnCtrl();
1769 #endif
1770 }
1771 
1772 #if defined(_EMU_EM23PERNORETAINCTRL_MASK)
1773 /***************************************************************************//**
1774  * @brief
1775  *   Set EM2 3 peripheral retention control.
1776  *
1777  * @param[in] periMask
1778  *  A peripheral select mask. Use | operator to select multiple peripherals, for example
1779  *  @ref emuPeripheralRetention_LEUART0 | @ref emuPeripheralRetention_VDAC0.
1780  * @param[in] enable
1781  *  Peripheral retention enable (true) or disable (false).
1782  *
1783  *
1784  * @note
1785  *   Only peripheral retention disable is currently supported. Peripherals are
1786  *   enabled by default and can only be disabled.
1787  ******************************************************************************/
EMU_PeripheralRetention(EMU_PeripheralRetention_TypeDef periMask,bool enable)1788 void EMU_PeripheralRetention(EMU_PeripheralRetention_TypeDef periMask, bool enable)
1789 {
1790   EFM_ASSERT(!enable);
1791   EMU->EM23PERNORETAINCTRL = (uint32_t)periMask
1792                              & (uint32_t)emuPeripheralRetention_ALL;
1793 }
1794 #endif
1795 
1796 /***************************************************************************//**
1797  * @brief
1798  *   Update EMU module with CMU oscillator selection/enable status.
1799  *
1800  * @deprecated
1801  *   Oscillator status is saved in @ref EMU_EnterEM2() and @ref EMU_EnterEM3().
1802  ******************************************************************************/
EMU_UpdateOscConfig(void)1803 void EMU_UpdateOscConfig(void)
1804 {
1805 #if (_SILICON_LABS_32B_SERIES < 2)
1806   emState(emState_Save);
1807 #endif
1808 }
1809 
1810 #if defined(_SILICON_LABS_32B_SERIES_2) && defined(EMU_VSCALE_EM01_PRESENT)
1811 /***************************************************************************//**
1812  * @brief
1813  *   Energy mode 01 voltage scaling hook function.
1814  *
1815  * @param[in] voltage
1816  *   Voltage scaling level requested.
1817  *
1818  * @details
1819  *   This function is called by EMU_VScaleEM01 to let EFP know that voltage scaling
1820  *   is requested.
1821  ******************************************************************************/
EMU_EFPEM01VScale(EMU_VScaleEM01_TypeDef voltage)1822 SL_WEAK void EMU_EFPEM01VScale(EMU_VScaleEM01_TypeDef voltage)
1823 {
1824   (void)voltage;
1825 }
1826 #endif
1827 
1828 #if defined(EMU_VSCALE_EM01_PRESENT)
1829 /***************************************************************************//**
1830  * @brief
1831  *   Voltage scale in EM0 and 1 by clock frequency.
1832  *
1833  * @param[in] clockFrequency
1834  *   Use CMSIS HF clock if 0 or override to custom clock. Providing a
1835  *   custom clock frequency is required if using a non-standard HFXO
1836  *   frequency.
1837  * @param[in] wait
1838  *   Wait for scaling to complete.
1839  *
1840  * @note
1841  *   This function is primarily needed by the @ref cmu.
1842  ******************************************************************************/
EMU_VScaleEM01ByClock(uint32_t clockFrequency,bool wait)1843 void EMU_VScaleEM01ByClock(uint32_t clockFrequency, bool wait)
1844 {
1845   uint32_t hfSrcClockFrequency;
1846 
1847 #if defined(_SILICON_LABS_32B_SERIES_1)
1848   if (EMU_LDOStatusGet() == false) {
1849     /* Skip voltage scaling if the LDO regulator is turned off. */
1850     return;
1851   }
1852 #endif
1853 
1854   /* VSCALE frequency is HFSRCCLK. */
1855   if (clockFrequency == 0U) {
1856 #if defined(_SILICON_LABS_32B_SERIES_2)
1857     hfSrcClockFrequency = SystemSYSCLKGet();
1858 #else
1859     uint32_t hfPresc = 1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
1860                              >> _CMU_HFPRESC_PRESC_SHIFT);
1861     hfSrcClockFrequency = SystemHFClockGet() * hfPresc;
1862 #endif
1863   } else {
1864     hfSrcClockFrequency = clockFrequency;
1865   }
1866 
1867   /* Apply EM0 and 1 voltage scaling command. */
1868   if (vScaleEM01Config.vScaleEM01LowPowerVoltageEnable
1869       && (hfSrcClockFrequency <= CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
1870     EMU_VScaleEM01(emuVScaleEM01_LowPower, wait);
1871   } else {
1872     EMU_VScaleEM01(emuVScaleEM01_HighPerformance, wait);
1873   }
1874 }
1875 #endif
1876 
1877 #if defined(EMU_VSCALE_EM01_PRESENT)
1878 /***************************************************************************//**
1879  * @brief
1880  *   Force voltage scaling in EM0 and 1 to a specific voltage level.
1881  *
1882  * @param[in] voltage
1883  *   Target VSCALE voltage level.
1884  * @param[in] wait
1885  *   Wait for scaling to complete.
1886  *
1887  * @note
1888  *   This function is useful for upscaling before programming Flash from @ref msc
1889  *   and downscaling after programming is done. Flash programming is only supported
1890  *   at @ref emuVScaleEM01_HighPerformance.
1891  *
1892  * @note
1893  *  This function ignores vScaleEM01LowPowerVoltageEnable set from @ref
1894  *  EMU_EM01Init().
1895  ******************************************************************************/
EMU_VScaleEM01(EMU_VScaleEM01_TypeDef voltage,bool wait)1896 void EMU_VScaleEM01(EMU_VScaleEM01_TypeDef voltage, bool wait)
1897 {
1898   uint32_t hfFreq;
1899   uint32_t hfSrcClockFrequency;
1900 
1901 #if defined(_SILICON_LABS_32B_SERIES_1)
1902   if (EMU_LDOStatusGet() == false) {
1903     /* Skip voltage scaling if the LDO regulator is turned off. */
1904     return;
1905   }
1906 #endif
1907 
1908   if (EMU_VScaleGet() == voltage) {
1909     /* Voltage is already at the correct level. */
1910     return;
1911   }
1912 
1913 #if defined(_SILICON_LABS_32B_SERIES_2)
1914   (void)wait;
1915   CORE_DECLARE_IRQ_STATE;
1916 
1917   hfFreq = SystemSYSCLKGet();
1918   hfSrcClockFrequency = hfFreq;
1919 
1920   if (voltage == emuVScaleEM01_LowPower) {
1921     EFM_ASSERT(hfSrcClockFrequency <= CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX);
1922     /* Update wait states before scaling down voltage. */
1923     CMU_UpdateWaitStates(hfFreq, VSCALE_EM01_LOW_POWER);
1924   }
1925 
1926   CORE_ENTER_CRITICAL();
1927   EMU->IF_CLR = EMU_IF_VSCALEDONE;
1928   EMU_EFPEM01VScale(voltage);
1929   EMU->CMD = vScaleEM01Cmd(voltage);
1930 
1931   // Note that VSCALEDONE interrupt flag must be used instead of VSCALEBUSY
1932   // because hardware does not set the VSCALEBUSY flag immediately.
1933   while (((EMU->IF & EMU_IF_VSCALEDONE) == 0U)
1934          && ((EMU->STATUS & EMU_STATUS_VSCALEFAILED) == 0U)) {
1935     EFM_ASSERT((EMU->STATUS & EMU_STATUS_VSCALEFAILED) == 0U);
1936     // Wait for VSCALE completion.
1937     // SRAM accesses will fault the core while scaling.
1938   }
1939   CORE_EXIT_CRITICAL();
1940 
1941 #else
1942   uint32_t hfPresc = 1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
1943                            >> _CMU_HFPRESC_PRESC_SHIFT);
1944   hfFreq = SystemHFClockGet();
1945   hfSrcClockFrequency = hfFreq * hfPresc;
1946 
1947   if (voltage == emuVScaleEM01_LowPower) {
1948     EFM_ASSERT(hfSrcClockFrequency <= CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX);
1949     /* Update wait states before scaling down voltage. */
1950     CMU_UpdateWaitStates(hfFreq, VSCALE_EM01_LOW_POWER);
1951   }
1952 
1953   EMU->CMD = vScaleEM01Cmd(voltage);
1954 
1955   if (wait) {
1956     EMU_VScaleWait();
1957   }
1958 #endif
1959 
1960   if (voltage == emuVScaleEM01_HighPerformance) {
1961     /* Update wait states after scaling up voltage. */
1962     CMU_UpdateWaitStates(hfFreq, VSCALE_EM01_HIGH_PERFORMANCE);
1963   }
1964 }
1965 #endif
1966 
1967 #if defined(BU_PRESENT) && defined(_SILICON_LABS_32B_SERIES_0)
1968 /***************************************************************************//**
1969  * @brief
1970  *   Configure Backup Power Domain settings.
1971  *
1972  * @param[in] bupdInit
1973  *   Backup power domain initialization structure.
1974  ******************************************************************************/
EMU_BUPDInit(const EMU_BUPDInit_TypeDef * bupdInit)1975 void EMU_BUPDInit(const EMU_BUPDInit_TypeDef *bupdInit)
1976 {
1977   uint32_t reg;
1978 
1979   /* Set the power connection configuration. */
1980   reg = EMU->PWRCONF & ~(_EMU_PWRCONF_PWRRES_MASK
1981                          | _EMU_PWRCONF_VOUTSTRONG_MASK
1982                          | _EMU_PWRCONF_VOUTMED_MASK
1983                          | _EMU_PWRCONF_VOUTWEAK_MASK);
1984 
1985   reg |= bupdInit->resistor
1986          | (bupdInit->voutStrong << _EMU_PWRCONF_VOUTSTRONG_SHIFT)
1987          | (bupdInit->voutMed    << _EMU_PWRCONF_VOUTMED_SHIFT)
1988          | (bupdInit->voutWeak   << _EMU_PWRCONF_VOUTWEAK_SHIFT);
1989 
1990   EMU->PWRCONF = reg;
1991 
1992   /* Set the backup domain inactive mode configuration. */
1993   reg = EMU->BUINACT & ~(_EMU_BUINACT_PWRCON_MASK);
1994   reg |= (bupdInit->inactivePower);
1995   EMU->BUINACT = reg;
1996 
1997   /* Set the backup domain active mode configuration. */
1998   reg = EMU->BUACT & ~(_EMU_BUACT_PWRCON_MASK);
1999   reg |= (bupdInit->activePower);
2000   EMU->BUACT = reg;
2001 
2002   /* Set the power control configuration */
2003   reg = EMU->BUCTRL & ~(_EMU_BUCTRL_PROBE_MASK
2004                         | _EMU_BUCTRL_BODCAL_MASK
2005                         | _EMU_BUCTRL_STATEN_MASK
2006                         | _EMU_BUCTRL_EN_MASK);
2007 
2008   /* Note the use of ->enable to enable BUPD. Use BU_VIN pin input and
2009      release reset. */
2010   reg |= bupdInit->probe
2011          | (bupdInit->bodCal          << _EMU_BUCTRL_BODCAL_SHIFT)
2012          | (bupdInit->statusPinEnable << _EMU_BUCTRL_STATEN_SHIFT)
2013          | (bupdInit->enable          << _EMU_BUCTRL_EN_SHIFT);
2014 
2015   /* Enable configuration. */
2016   EMU->BUCTRL = reg;
2017 
2018   /* If enable is true, enable BU_VIN input power pin. If not, disable it.  */
2019   EMU_BUPinEnable(bupdInit->enable);
2020 
2021   /* If enable is true, release BU reset. If not, keep reset asserted. */
2022   BUS_RegBitWrite(&(RMU->CTRL), _RMU_CTRL_BURSTEN_SHIFT, !bupdInit->enable);
2023 }
2024 
2025 /***************************************************************************//**
2026  * @brief
2027  *   Configure the Backup Power Domain BOD Threshold value.
2028  * @note
2029  *   These values are precalibrated.
2030  * @param[in] mode Active or Inactive mode
2031  * @param[in] value
2032  ******************************************************************************/
EMU_BUThresholdSet(EMU_BODMode_TypeDef mode,uint32_t value)2033 void EMU_BUThresholdSet(EMU_BODMode_TypeDef mode, uint32_t value)
2034 {
2035   EFM_ASSERT(value < 8);
2036   EFM_ASSERT(value <= (_EMU_BUACT_BUEXTHRES_MASK >> _EMU_BUACT_BUEXTHRES_SHIFT));
2037 
2038   switch (mode) {
2039     case emuBODMode_Active:
2040       EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXTHRES_MASK)
2041                    | (value << _EMU_BUACT_BUEXTHRES_SHIFT);
2042       break;
2043     case emuBODMode_Inactive:
2044       EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENTHRES_MASK)
2045                      | (value << _EMU_BUINACT_BUENTHRES_SHIFT);
2046       break;
2047   }
2048 }
2049 
2050 /***************************************************************************//**
2051  * @brief
2052  *  Configure the Backup Power Domain BOD Threshold Range.
2053  * @note
2054  *  These values are precalibrated.
2055  * @param[in] mode Active or Inactive mode
2056  * @param[in] value
2057  ******************************************************************************/
EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode,uint32_t value)2058 void EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode, uint32_t value)
2059 {
2060   EFM_ASSERT(value < 4);
2061   EFM_ASSERT(value <= (_EMU_BUACT_BUEXRANGE_MASK >> _EMU_BUACT_BUEXRANGE_SHIFT));
2062 
2063   switch (mode) {
2064     case emuBODMode_Active:
2065       EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXRANGE_MASK)
2066                    | (value << _EMU_BUACT_BUEXRANGE_SHIFT);
2067       break;
2068     case emuBODMode_Inactive:
2069       EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENRANGE_MASK)
2070                      | (value << _EMU_BUINACT_BUENRANGE_SHIFT);
2071       break;
2072   }
2073 }
2074 #endif
2075 
2076 #if defined(BU_PRESENT) && defined(_SILICON_LABS_32B_SERIES_1)
2077 /***************************************************************************//**
2078  * @brief
2079  *   Configure Backup Power Domain settings.
2080  *
2081  * @param[in] buInit
2082  *   Backup power domain initialization structure.
2083  ******************************************************************************/
EMU_BUInit(const EMU_BUInit_TypeDef * buInit)2084 void EMU_BUInit(const EMU_BUInit_TypeDef *buInit)
2085 {
2086   uint32_t reg = 0;
2087 
2088   /* Set the backup power configuration. */
2089   reg |= (buInit->disMaxComp << _EMU_BUCTRL_DISMAXCOMP_SHIFT);
2090   reg |= (uint32_t)(buInit->inactivePwrCon);
2091   reg |= (uint32_t)(buInit->activePwrCon);
2092   reg |= (uint32_t)(buInit->pwrRes);
2093   reg |= (uint32_t)(buInit->voutRes);
2094   reg |= (buInit->buVinProbeEn << _EMU_BUCTRL_BUVINPROBEEN_SHIFT);
2095   reg |= (buInit->staEn << _EMU_BUCTRL_STATEN_SHIFT);
2096   reg |= (buInit->enable << _EMU_BUCTRL_EN_SHIFT);
2097   EMU->BUCTRL = reg;
2098 }
2099 #endif
2100 
2101 #if defined(_EMU_BUCTRL_DISMAXCOMP_MASK)
2102 /***************************************************************************//**
2103  * @brief
2104  *   Disable Main Backup Power Domain comparator.
2105  *
2106  * @param[in] disableMainBuComparator
2107  *   True to disable main BU comparator.
2108  ******************************************************************************/
EMU_BUDisMaxCompSet(bool disableMainBuComparator)2109 void EMU_BUDisMaxCompSet(bool disableMainBuComparator)
2110 {
2111   uint32_t reg;
2112 
2113   reg = EMU->BUCTRL & ~(_EMU_BUCTRL_DISMAXCOMP_MASK);
2114   reg |= (disableMainBuComparator << _EMU_BUCTRL_DISMAXCOMP_SHIFT);
2115   EMU->BUCTRL = reg;
2116 }
2117 #endif
2118 
2119 #if defined(_EMU_BUCTRL_BUINACTPWRCON_MASK)
2120 /***************************************************************************//**
2121  * @brief
2122  *   Configure power connection configuration when not in Backup mode.
2123  *
2124  * @param[in] inactPwrCon
2125  *   Inactive power configuration.
2126  ******************************************************************************/
EMU_BUBuInactPwrConSet(EMU_BUBuInactPwrCon_TypeDef inactPwrCon)2127 void EMU_BUBuInactPwrConSet(EMU_BUBuInactPwrCon_TypeDef inactPwrCon)
2128 {
2129   uint32_t reg;
2130 
2131   reg = EMU->BUCTRL & ~(_EMU_BUCTRL_BUINACTPWRCON_MASK);
2132   reg |= (uint32_t)(inactPwrCon);
2133   EMU->BUCTRL = reg;
2134 }
2135 #endif
2136 
2137 #if defined(_EMU_BUCTRL_BUACTPWRCON_MASK)
2138 /***************************************************************************//**
2139  * @brief
2140  *   Configure power connection configuration when in Backup mode.
2141  *
2142  * @param[in] actPwrCon
2143  *   Active power configuration.
2144  ******************************************************************************/
EMU_BUBuActPwrConSet(EMU_BUBuActPwrCon_TypeDef actPwrCon)2145 void EMU_BUBuActPwrConSet(EMU_BUBuActPwrCon_TypeDef actPwrCon)
2146 {
2147   uint32_t reg;
2148 
2149   reg = EMU->BUCTRL & ~(_EMU_BUCTRL_BUACTPWRCON_MASK);
2150   reg |= (uint32_t)(actPwrCon);
2151   EMU->BUCTRL = reg;
2152 }
2153 #endif
2154 
2155 #if defined(_EMU_BUCTRL_PWRRES_MASK)
2156 /***************************************************************************//**
2157  * @brief
2158  *   Power domain resistor selection.
2159  *
2160  * @param[in] pwrRes
2161  *   Resistor selection.
2162  ******************************************************************************/
EMU_BUPwrResSet(EMU_BUPwrRes_TypeDef pwrRes)2163 void EMU_BUPwrResSet(EMU_BUPwrRes_TypeDef pwrRes)
2164 {
2165   uint32_t reg;
2166 
2167   reg = EMU->BUCTRL & ~(_EMU_BUCTRL_PWRRES_MASK);
2168   reg |= (uint32_t)(pwrRes);
2169   EMU->BUCTRL = reg;
2170 }
2171 #endif
2172 
2173 #if defined(_EMU_BUCTRL_VOUTRES_MASK)
2174 /***************************************************************************//**
2175  * @brief
2176  *   B_VOUT resistor select.
2177  *
2178  * @param[in] resistorSel
2179  *   Resistor selection.
2180  ******************************************************************************/
EMU_BUVoutResSet(EMU_BUVoutRes_TypeDef resistorSel)2181 void EMU_BUVoutResSet(EMU_BUVoutRes_TypeDef resistorSel)
2182 {
2183   uint32_t reg;
2184 
2185   reg = EMU->BUCTRL & ~(_EMU_BUCTRL_VOUTRES_MASK);
2186   reg |= (uint32_t)(resistorSel);
2187   EMU->BUCTRL = reg;
2188 }
2189 #endif
2190 
2191 #if defined(_EMU_BUCTRL_BUVINPROBEEN_MASK)
2192 /***************************************************************************//**
2193  * @brief
2194  *   Enable BU_VIN probing
2195  *
2196  * @param[in] enable
2197  *   True to enable BU_VIN probing. False to disable.
2198  ******************************************************************************/
EMU_BUBuVinProbeEnSet(bool enable)2199 void EMU_BUBuVinProbeEnSet(bool enable)
2200 {
2201   uint32_t reg;
2202 
2203   reg = EMU->BUCTRL & ~(_EMU_BUCTRL_BUVINPROBEEN_MASK);
2204   reg |= (enable << _EMU_BUCTRL_BUVINPROBEEN_SHIFT);
2205   EMU->BUCTRL = reg;
2206 }
2207 #endif
2208 
2209 #if defined(_EMU_BUCTRL_STATEN_MASK)
2210 /***************************************************************************//**
2211  * @brief
2212  *   Enable backup mode status export.
2213  *
2214  * @param[in] enable
2215  *   True to enable status export. False to disable.
2216  ******************************************************************************/
EMU_BUStatEnSet(bool enable)2217 void EMU_BUStatEnSet(bool enable)
2218 {
2219   uint32_t reg;
2220 
2221   reg = EMU->BUCTRL & ~(_EMU_BUCTRL_STATEN_MASK);
2222   reg |= (enable << _EMU_BUCTRL_STATEN_SHIFT);
2223   EMU->BUCTRL = reg;
2224 }
2225 #endif
2226 
2227 #if defined(_EMU_BUCTRL_EN_MASK)
2228 /***************************************************************************//**
2229  * @brief
2230  *   Enable backup mode.
2231  *
2232  * @param[in] enable
2233  *   True to enable backup mode. False to disable.
2234  ******************************************************************************/
EMU_BUEnableSet(bool enable)2235 void EMU_BUEnableSet(bool enable)
2236 {
2237   uint32_t reg;
2238 
2239   reg = EMU->BUCTRL & ~(_EMU_BUCTRL_EN_MASK);
2240   reg |= (enable << _EMU_BUCTRL_EN_SHIFT);
2241   EMU->BUCTRL = reg;
2242 }
2243 #endif
2244 
2245 #if defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
2246 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
2247 /* Internal DCDC trim modes. */
2248 typedef enum {
2249   dcdcTrimMode_EM234H_LP = 0,
2250 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
2251   dcdcTrimMode_EM01_LP,
2252 #endif
2253   dcdcTrimMode_LN,
2254 } dcdcTrimMode_TypeDef;
2255 
2256 /** @endcond */
2257 
2258 /***************************************************************************//**
2259  * @brief
2260  *   Load DCDC calibration constants from the DI page. A constant means that calibration
2261  *   data that does not change depending on other configuration parameters.
2262  *
2263  * @return
2264  *   False if calibration registers are locked.
2265  ******************************************************************************/
dcdcConstCalibrationLoad(void)2266 static bool dcdcConstCalibrationLoad(void)
2267 {
2268 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2269   uint32_t val;
2270   volatile uint32_t *reg;
2271 
2272   /* DI calibration data in Flash. */
2273   volatile uint32_t* const diCal_EMU_DCDCLNFREQCTRL =  (volatile uint32_t *)(0x0FE08038);
2274   volatile uint32_t* const diCal_EMU_DCDCLNVCTRL =     (volatile uint32_t *)(0x0FE08040);
2275   volatile uint32_t* const diCal_EMU_DCDCLPCTRL =      (volatile uint32_t *)(0x0FE08048);
2276   volatile uint32_t* const diCal_EMU_DCDCLPVCTRL =     (volatile uint32_t *)(0x0FE08050);
2277   volatile uint32_t* const diCal_EMU_DCDCTRIM0 =       (volatile uint32_t *)(0x0FE08058);
2278   volatile uint32_t* const diCal_EMU_DCDCTRIM1 =       (volatile uint32_t *)(0x0FE08060);
2279 
2280   if (DEVINFO->DCDCLPVCTRL0 != UINT_MAX) {
2281     val = *(diCal_EMU_DCDCLNFREQCTRL + 1);
2282     reg = (volatile uint32_t *)*diCal_EMU_DCDCLNFREQCTRL;
2283     *reg = val;
2284 
2285     val = *(diCal_EMU_DCDCLNVCTRL + 1);
2286     reg = (volatile uint32_t *)*diCal_EMU_DCDCLNVCTRL;
2287     *reg = val;
2288 
2289     val = *(diCal_EMU_DCDCLPCTRL + 1);
2290     reg = (volatile uint32_t *)*diCal_EMU_DCDCLPCTRL;
2291     *reg = val;
2292 
2293     val = *(diCal_EMU_DCDCLPVCTRL + 1);
2294     reg = (volatile uint32_t *)*diCal_EMU_DCDCLPVCTRL;
2295     *reg = val;
2296 
2297     val = *(diCal_EMU_DCDCTRIM0 + 1);
2298     reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM0;
2299     *reg = val;
2300 
2301     val = *(diCal_EMU_DCDCTRIM1 + 1);
2302     reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM1;
2303     *reg = val;
2304 
2305     return true;
2306   }
2307   EFM_ASSERT(false);
2308   /* Return when assertions are disabled. */
2309   return false;
2310 
2311 #else
2312   return true;
2313 #endif
2314 }
2315 
2316 /***************************************************************************//**
2317  * @brief
2318  *   Set recommended and validated current optimization and timing settings.
2319  *
2320  ******************************************************************************/
dcdcValidatedConfigSet(void)2321 static void dcdcValidatedConfigSet(void)
2322 {
2323   uint32_t lnForceCcm;
2324 
2325 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2326   uint32_t dcdcTiming;
2327   SYSTEM_ChipRevision_TypeDef rev;
2328 #endif
2329 
2330   /* Enable duty cycling of the bias. */
2331   EMU->DCDCLPCTRL |= EMU_DCDCLPCTRL_LPVREFDUTYEN;
2332 
2333   /* Set low-noise RCO for LNFORCECCM configuration.
2334    * LNFORCECCM is default 1 for EFR32
2335    * LNFORCECCM is default 0 for EFM32
2336    */
2337   lnForceCcm = BUS_RegBitRead(&EMU->DCDCMISCCTRL, _EMU_DCDCMISCCTRL_LNFORCECCM_SHIFT);
2338   if (lnForceCcm != 0U) {
2339     /* 7 MHz is recommended for LNFORCECCM = 1. */
2340     EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_7MHz);
2341   } else {
2342     /* 3 MHz is recommended for LNFORCECCM = 0. */
2343     EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_3MHz);
2344   }
2345 
2346 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2347   EMU->DCDCTIMING &= ~_EMU_DCDCTIMING_DUTYSCALE_MASK;
2348   EMU->DCDCMISCCTRL |= EMU_DCDCMISCCTRL_LPCMPHYSDIS
2349                        | EMU_DCDCMISCCTRL_LPCMPHYSHI;
2350 
2351   SYSTEM_ChipRevisionGet(&rev);
2352   if ((rev.major == 1)
2353       && (rev.minor < 3)
2354       && (errataFixDcdcHsState == errataFixDcdcHsInit)) {
2355     /* LPCMPWAITDIS = 1 */
2356     EMU_DCDCSMCTRL |= 1;
2357 
2358     dcdcTiming = EMU->DCDCTIMING;
2359     dcdcTiming &= ~(_EMU_DCDCTIMING_LPINITWAIT_MASK
2360                     | _EMU_DCDCTIMING_LNWAIT_MASK
2361                     | _EMU_DCDCTIMING_BYPWAIT_MASK);
2362 
2363     dcdcTiming |= ((180 << _EMU_DCDCTIMING_LPINITWAIT_SHIFT)
2364                    | (12 << _EMU_DCDCTIMING_LNWAIT_SHIFT)
2365                    | (180 << _EMU_DCDCTIMING_BYPWAIT_SHIFT));
2366     EMU->DCDCTIMING = dcdcTiming;
2367 
2368     errataFixDcdcHsState = errataFixDcdcHsTrimSet;
2369   }
2370 #endif
2371 }
2372 
2373 /***************************************************************************//**
2374  * @brief
2375  *   Compute current limiters:
2376  *     LNCLIMILIMSEL: LN current limiter threshold
2377  *     LPCLIMILIMSEL: LP current limiter threshold
2378  *     DCDCZDETCTRL:  zero detector limiter threshold
2379  ******************************************************************************/
currentLimitersUpdate(void)2380 static void currentLimitersUpdate(void)
2381 {
2382   uint32_t lncLimSel;
2383   uint32_t zdetLimSel;
2384   uint32_t pFetCnt;
2385   uint16_t maxReverseCurrent_mA;
2386 
2387   /* 80 mA as recommended peak in Application Note AN0948.
2388      The peak current is the average current plus 50% of the current ripple.
2389      Hence, a 14 mA average current is recommended in LP mode. Since LP PFETCNT is also
2390      a constant, lpcLimImSel = 1. The following calculation is provided
2391      for documentation only. */
2392   const uint32_t lpcLim = (((14 + 40) + ((14 + 40) / 2))
2393                            / (5 * (DCDC_LP_PFET_CNT + 1)))
2394                           - 1;
2395   const uint32_t lpcLimSel = lpcLim << _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_SHIFT;
2396 
2397   /* Get enabled PFETs. */
2398   pFetCnt = (EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_PFETCNT_MASK)
2399             >> _EMU_DCDCMISCCTRL_PFETCNT_SHIFT;
2400 
2401   /* Compute the LN current limiter threshold from the nominal user input current and
2402      LN PFETCNT as described in the register description for
2403      EMU_DCDCMISCCTRL_LNCLIMILIMSEL. */
2404   lncLimSel = ((((uint32_t)dcdcMaxCurrent_mA + 40U)
2405                 + (((uint32_t)dcdcMaxCurrent_mA + 40U) / 2U))
2406                / (5U * (pFetCnt + 1U)))
2407               - 1U;
2408 
2409   /* Saturate the register field value. */
2410   lncLimSel = SL_MIN(lncLimSel,
2411                      _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK
2412                      >> _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT);
2413 
2414   lncLimSel <<= _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT;
2415 
2416   /* Check for overflow. */
2417   EFM_ASSERT((lncLimSel & ~_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK) == 0x0U);
2418   EFM_ASSERT((lpcLimSel & ~_EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK) == 0x0U);
2419 
2420   EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK
2421                                              | _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK))
2422                       | (lncLimSel | lpcLimSel);
2423 
2424   /* Compute the reverse current limit threshold for the zero detector from the user input
2425      maximum reverse current and LN PFETCNT as described in the register description
2426      for EMU_DCDCZDETCTRL_ZDETILIMSEL. */
2427   if (dcdcReverseCurrentControl >= 0) {
2428     /* If dcdcReverseCurrentControl < 0, EMU_DCDCZDETCTRL_ZDETILIMSEL is "don't care". */
2429     maxReverseCurrent_mA = (uint16_t)dcdcReverseCurrentControl;
2430 
2431     zdetLimSel = ((((uint32_t)maxReverseCurrent_mA + 40U)
2432                    + (((uint32_t)maxReverseCurrent_mA + 40U) / 2U))
2433                   / ((2U * (pFetCnt + 1U)) + ((pFetCnt + 1U) / 2U)));
2434     /* Saturate the register field value. */
2435     zdetLimSel = SL_MIN(zdetLimSel,
2436                         _EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK
2437                         >> _EMU_DCDCZDETCTRL_ZDETILIMSEL_SHIFT);
2438 
2439     zdetLimSel <<= _EMU_DCDCZDETCTRL_ZDETILIMSEL_SHIFT;
2440 
2441     /* Check for overflow. */
2442     EFM_ASSERT((zdetLimSel & ~_EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK) == 0x0U);
2443 
2444     EMU->DCDCZDETCTRL = (EMU->DCDCZDETCTRL & ~_EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK)
2445                         | zdetLimSel;
2446   }
2447 }
2448 
2449 /***************************************************************************//**
2450  * @brief
2451  *   Set static variables that hold the user set maximum peak current
2452  *   and reverse current. Update limiters.
2453  *
2454  * @param[in] maxCurrent_mA
2455  *   Set the maximum peak current that the DCDC can draw from the power source.
2456  * @param[in] reverseCurrentControl
2457  *   Reverse the current control as defined by
2458  *   @ref EMU_DcdcLnReverseCurrentControl_TypeDef. Positive values have unit mA.
2459  ******************************************************************************/
userCurrentLimitsSet(uint32_t maxCurrent_mA,EMU_DcdcLnReverseCurrentControl_TypeDef reverseCurrentControl)2460 static void userCurrentLimitsSet(uint32_t maxCurrent_mA,
2461                                  EMU_DcdcLnReverseCurrentControl_TypeDef reverseCurrentControl)
2462 {
2463   dcdcMaxCurrent_mA = (uint16_t)maxCurrent_mA;
2464   dcdcReverseCurrentControl = reverseCurrentControl;
2465 }
2466 
2467 /***************************************************************************//**
2468  * @brief
2469  *   Set DCDC low noise compensator control register.
2470  *
2471  * @param[in] comp
2472  *   Low-noise mode compensator trim setpoint.
2473  ******************************************************************************/
compCtrlSet(EMU_DcdcLnCompCtrl_TypeDef comp)2474 static void compCtrlSet(EMU_DcdcLnCompCtrl_TypeDef comp)
2475 {
2476   switch (comp) {
2477     case emuDcdcLnCompCtrl_1u0F:
2478       EMU->DCDCLNCOMPCTRL = 0x57204077UL;
2479       break;
2480 
2481     case emuDcdcLnCompCtrl_4u7F:
2482       EMU->DCDCLNCOMPCTRL = 0xB7102137UL;
2483       break;
2484 
2485     default:
2486       EFM_ASSERT(false);
2487       break;
2488   }
2489 }
2490 
2491 /***************************************************************************//**
2492  * @brief
2493  *   Load EMU_DCDCLPCTRL_LPCMPHYSSEL depending on LP bias, LP feedback
2494  *   attenuation, and DEVINFOREV.
2495  *
2496  * @param[in] lpAttenuation
2497  *   LP feedback attenuation.
2498  * @param[in] lpCmpBias
2499  *   lpCmpBias selection.
2500  * @param[in] trimMode
2501  *   DCDC trim mode.
2502  ******************************************************************************/
lpCmpHystCalibrationLoad(bool lpAttenuation,uint8_t lpCmpBias,dcdcTrimMode_TypeDef trimMode)2503 static bool lpCmpHystCalibrationLoad(bool lpAttenuation,
2504                                      uint8_t lpCmpBias,
2505                                      dcdcTrimMode_TypeDef trimMode)
2506 {
2507   uint32_t lpcmpHystSel;
2508 #if !defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2509   (void)lpAttenuation;
2510 #endif
2511 
2512   /* Get calibration data revision. */
2513 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2514   uint8_t devinfoRev = SYSTEM_GetDevinfoRev();
2515 
2516   /* Load LPATT indexed calibration data. */
2517   if (devinfoRev < 4) {
2518     lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL0;
2519 
2520     if (lpAttenuation) {
2521       lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_MASK)
2522                      >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_SHIFT;
2523     } else {
2524       lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_MASK)
2525                      >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_SHIFT;
2526     }
2527   } else
2528 #endif
2529   {
2530     /* devinfoRev >= 4: load LPCMPBIAS indexed calibration data. */
2531     lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL1;
2532     switch (lpCmpBias) {
2533       case 0:
2534         lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_MASK)
2535                        >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_SHIFT;
2536         break;
2537 
2538       case 1:
2539         lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_MASK)
2540                        >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_SHIFT;
2541         break;
2542 
2543       case 2:
2544         lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_MASK)
2545                        >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_SHIFT;
2546         break;
2547 
2548       case 3:
2549         lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_MASK)
2550                        >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_SHIFT;
2551         break;
2552 
2553       default:
2554         EFM_ASSERT(false);
2555         /* Return when assertions are disabled. */
2556         return false;
2557     }
2558   }
2559 
2560   /* Set trims. */
2561   if (trimMode == dcdcTrimMode_EM234H_LP) {
2562     /* Make sure the sel value is within the field range. */
2563     lpcmpHystSel <<= _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT;
2564     if ((lpcmpHystSel & ~_GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK) != 0U) {
2565       EFM_ASSERT(false);
2566       /* Return when assertions are disabled. */
2567       return false;
2568     }
2569     EMU->DCDCLPCTRL = (EMU->DCDCLPCTRL & ~_GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK) | lpcmpHystSel;
2570   }
2571 
2572 #if defined(_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK)
2573   if (trimMode == dcdcTrimMode_EM01_LP) {
2574     /* Make sure the sel value is within the field range. */
2575     lpcmpHystSel <<= _EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_SHIFT;
2576     if ((lpcmpHystSel & ~_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK) != 0U) {
2577       EFM_ASSERT(false);
2578       /* Return when assertions are disabled. */
2579       return false;
2580     }
2581     EMU->DCDCLPEM01CFG = (EMU->DCDCLPEM01CFG & ~_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK) | lpcmpHystSel;
2582   }
2583 #endif
2584 
2585   return true;
2586 }
2587 
2588 /***************************************************************************//**
2589  * @brief
2590  *   Load LPVREF low and high from DEVINFO.
2591  *
2592  * @param[out] vrefL
2593  *   LPVREF low from DEVINFO.
2594  * @param[out] vrefH
2595  *   LPVREF high from DEVINFO.
2596  * @param[in] lpAttenuation
2597  *   LP feedback attenuation.
2598  * @param[in] lpcmpBias
2599  *   lpcmpBias to look up in DEVINFO.
2600  ******************************************************************************/
lpGetDevinfoVrefLowHigh(uint32_t * vrefL,uint32_t * vrefH,bool lpAttenuation,uint8_t lpcmpBias)2601 static void lpGetDevinfoVrefLowHigh(uint32_t *vrefL,
2602                                     uint32_t *vrefH,
2603                                     bool lpAttenuation,
2604                                     uint8_t lpcmpBias)
2605 {
2606   uint32_t vrefLow = 0;
2607   uint32_t vrefHigh = 0;
2608 
2609   /* Find VREF high and low in DEVINFO indexed by LPCMPBIAS (lpcmpBias)
2610      and LPATT (lpAttenuation) */
2611   uint32_t switchVal = ((uint32_t)lpcmpBias << 8) | (lpAttenuation ? 1U : 0U);
2612   switch (switchVal) {
2613     case ((0 << 8) | 1):
2614       vrefLow  = DEVINFO->DCDCLPVCTRL2;
2615       vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_MASK)
2616                  >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_SHIFT;
2617       vrefLow  = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_MASK)
2618                  >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_SHIFT;
2619       break;
2620 
2621     case ((1 << 8) | 1):
2622       vrefLow  = DEVINFO->DCDCLPVCTRL2;
2623       vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_MASK)
2624                  >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_SHIFT;
2625       vrefLow  = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_MASK)
2626                  >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_SHIFT;
2627       break;
2628 
2629     case ((2 << 8) | 1):
2630       vrefLow  = DEVINFO->DCDCLPVCTRL3;
2631       vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_MASK)
2632                  >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_SHIFT;
2633       vrefLow  = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_MASK)
2634                  >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_SHIFT;
2635       break;
2636 
2637     case ((3 << 8) | 1):
2638       vrefLow  = DEVINFO->DCDCLPVCTRL3;
2639       vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_MASK)
2640                  >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_SHIFT;
2641       vrefLow  = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_MASK)
2642                  >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_SHIFT;
2643       break;
2644 
2645     case ((0 << 8) | 0):
2646       vrefLow  = DEVINFO->DCDCLPVCTRL0;
2647       vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_MASK)
2648                  >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_SHIFT;
2649       vrefLow  = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_MASK)
2650                  >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_SHIFT;
2651       break;
2652 
2653     case ((1 << 8) | 0):
2654       vrefLow  = DEVINFO->DCDCLPVCTRL0;
2655       vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_MASK)
2656                  >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_SHIFT;
2657       vrefLow  = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_MASK)
2658                  >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_SHIFT;
2659       break;
2660 
2661     case ((2 << 8) | 0):
2662       vrefLow  = DEVINFO->DCDCLPVCTRL1;
2663       vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_MASK)
2664                  >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_SHIFT;
2665       vrefLow  = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_MASK)
2666                  >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_SHIFT;
2667       break;
2668 
2669     case ((3 << 8) | 0):
2670       vrefLow  = DEVINFO->DCDCLPVCTRL1;
2671       vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_MASK)
2672                  >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_SHIFT;
2673       vrefLow  = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_MASK)
2674                  >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_SHIFT;
2675       break;
2676 
2677     default:
2678       EFM_ASSERT(false);
2679       break;
2680   }
2681   *vrefL = vrefLow;
2682   *vrefH = vrefHigh;
2683 }
2684 
2685 /***************************************************************************//**
2686  * @brief
2687  *   Configure the DCDC regulator.
2688  *
2689  * @note
2690  * Do not call this function if the power circuit is configured for NODCDC as
2691  * described in the Power Configurations section of the Reference Manual.
2692  * Instead, call @ref EMU_DCDCPowerOff().
2693  *
2694  * @param[in] dcdcInit
2695  *  The DCDC initialization structure.
2696  *
2697  * @return
2698  *   True if initialization parameters are valid.
2699  ******************************************************************************/
EMU_DCDCInit(const EMU_DCDCInit_TypeDef * dcdcInit)2700 bool EMU_DCDCInit(const EMU_DCDCInit_TypeDef *dcdcInit)
2701 {
2702   uint32_t lpCmpBiasSelEM234H;
2703 
2704 #if defined(_EMU_PWRCFG_MASK)
2705   /* Set the external power configuration. This enables writing to the other
2706      DCDC registers. */
2707   EMU->PWRCFG = EMU_PWRCFG_PWRCFG_DCDCTODVDD;
2708 
2709   /* EMU->PWRCFG is write-once and POR reset only. Check that
2710      the desired power configuration was set. */
2711   if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != EMU_PWRCFG_PWRCFG_DCDCTODVDD) {
2712     /* If this assert triggers unexpectedly, power cycle the
2713        kit to reset the power configuration. */
2714     EFM_ASSERT(false);
2715     /* Return when assertions are disabled. */
2716     return false;
2717   }
2718 #endif
2719 
2720   /* Load DCDC calibration data from the DI page. */
2721   (void)dcdcConstCalibrationLoad();
2722 
2723   /* Check current parameters */
2724   EFM_ASSERT(dcdcInit->maxCurrent_mA <= 200U);
2725   EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= dcdcInit->maxCurrent_mA);
2726   EFM_ASSERT(dcdcInit->reverseCurrentControl <= 200);
2727 
2728   if (dcdcInit->dcdcMode == emuDcdcMode_LowNoise) {
2729     /* DCDC low-noise supports max 200 mA. */
2730     EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 200U);
2731   }
2732 #if (_SILICON_LABS_GECKO_INTERNAL_SDID != 80)
2733   else if (dcdcInit->dcdcMode == emuDcdcMode_LowPower) {
2734     /* Up to 10 mA is supported for EM01-LP mode. */
2735     EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 10U);
2736   }
2737 #endif
2738   else {
2739     /* No need to check the EM01 load limit. */
2740   }
2741 
2742   /* EM2/3/4 current above 10 mA is not supported. */
2743   EFM_ASSERT(dcdcInit->em234LoadCurrent_uA <= 10000U);
2744 
2745   if (dcdcInit->em234LoadCurrent_uA < 75U) {
2746     lpCmpBiasSelEM234H  = 0;
2747   } else if (dcdcInit->em234LoadCurrent_uA < 500U) {
2748     lpCmpBiasSelEM234H  = 1U << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
2749   } else if (dcdcInit->em234LoadCurrent_uA < 2500U) {
2750     lpCmpBiasSelEM234H  = 2U << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
2751   } else {
2752     lpCmpBiasSelEM234H  = 3U << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
2753   }
2754 
2755   /* ==== THESE NEXT STEPS ARE STRONGLY ORDER DEPENDENT ==== */
2756 
2757   /* Set DCDC low-power mode comparator bias selection. */
2758 
2759   /* 1. Set DCDC low-power mode comparator bias selection and forced CCM.
2760         => Updates DCDCMISCCTRL_LNFORCECCM */
2761   EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK
2762                                              | _EMU_DCDCMISCCTRL_LNFORCECCM_MASK))
2763                       | ((uint32_t)lpCmpBiasSelEM234H
2764                          | (dcdcInit->reverseCurrentControl >= 0
2765                             ? EMU_DCDCMISCCTRL_LNFORCECCM : 0U));
2766 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
2767   /* Only 10 mA EM01-LP current is supported. */
2768   EMU->DCDCLPEM01CFG = (EMU->DCDCLPEM01CFG & ~_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
2769                        | EMU_DCDCLPEM01CFG_LPCMPBIASEM01_BIAS3;
2770 #endif
2771 
2772   /* 2. Set recommended and validated current optimization settings.
2773         <= Depends on LNFORCECCM
2774         => Updates DCDCLNFREQCTRL_RCOBAND */
2775   dcdcEm01LoadCurrent_mA = dcdcInit->em01LoadCurrent_mA;
2776   dcdcValidatedConfigSet();
2777 
2778   /* 3. Updated static currents and limits user data.
2779         Limiters are updated in @ref EMU_DCDCOptimizeSlice(). */
2780   userCurrentLimitsSet(dcdcInit->maxCurrent_mA,
2781                        dcdcInit->reverseCurrentControl);
2782 
2783   /* 4. Optimize LN slice based on the given user input load current.
2784         <= Depends on DCDCMISCCTRL_LNFORCECCM and DCDCLNFREQCTRL_RCOBAND
2785         <= Depends on dcdcInit->maxCurrent_mA and dcdcInit->reverseCurrentControl
2786         => Updates DCDCMISCCTRL_P/NFETCNT
2787         => Updates DCDCMISCCTRL_LNCLIMILIMSEL and DCDCMISCCTRL_LPCLIMILIMSEL
2788         => Updates DCDCZDETCTRL_ZDETILIMSEL */
2789   EMU_DCDCOptimizeSlice(dcdcInit->em01LoadCurrent_mA);
2790 
2791   /* ======================================================= */
2792 
2793   /* Set DCDC low noise mode compensator control register. */
2794   compCtrlSet(dcdcInit->dcdcLnCompCtrl);
2795 
2796   /* Set DCDC output voltage. */
2797   if (!EMU_DCDCOutputVoltageSet(dcdcInit->mVout, true, true)) {
2798     EFM_ASSERT(false);
2799     /* Return when assertions are disabled. */
2800     return false;
2801   }
2802 
2803 #if (_SILICON_LABS_GECKO_INTERNAL_SDID == 80)
2804   /* Select analog peripheral power supply. This must be done before
2805      DCDC mode is set for all EFM32xG1 and EFR32xG1 devices. */
2806   BUS_RegBitWrite(&EMU->PWRCTRL,
2807                   _EMU_PWRCTRL_ANASW_SHIFT,
2808                   dcdcInit->anaPeripheralPower ? 1 : 0);
2809 #endif
2810 
2811 #if defined(_EMU_PWRCTRL_REGPWRSEL_MASK)
2812   /* Select DVDD as input to the digital regulator. The switch to DVDD will take
2813      effect once the DCDC output is stable. */
2814   EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD;
2815 #endif
2816 
2817   /* Set EM0 DCDC operating mode. Output voltage set in
2818      @ref EMU_DCDCOutputVoltageSet() above takes effect if mode
2819      is changed from bypass/off mode. */
2820   EMU_DCDCModeSet(dcdcInit->dcdcMode);
2821 
2822 #if (_SILICON_LABS_GECKO_INTERNAL_SDID != 80)
2823   /* Select the analog peripheral power supply. This must be done after
2824      DCDC mode is set for all devices other than EFM32xG1 and EFR32xG1. */
2825   BUS_RegBitWrite(&EMU->PWRCTRL,
2826                   _EMU_PWRCTRL_ANASW_SHIFT,
2827                   dcdcInit->anaPeripheralPower
2828                   == emuDcdcAnaPeripheralPower_DCDC ? 1U : 0U);
2829 #endif
2830 
2831   return true;
2832 }
2833 
2834 /***************************************************************************//**
2835  * @brief
2836  *   Set DCDC regulator operating mode.
2837  *
2838  * @param[in] dcdcMode
2839  *   DCDC mode.
2840  ******************************************************************************/
EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)2841 void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)
2842 {
2843   bool dcdcLocked;
2844   uint32_t currentDcdcMode;
2845 
2846   dcdcLocked = (EMU->PWRLOCK == EMU_PWRLOCK_LOCKKEY_LOCKED);
2847   EMU_PowerUnlock();
2848 
2849   /* Wait for any previous write sync to complete and read DCDC mode. */
2850   while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
2851   }
2852   currentDcdcMode = (EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK);
2853 
2854   /* Enable bypass current limiter when not in bypass mode to prevent
2855      excessive current between VREGVDD and DVDD supplies when reentering bypass mode.  */
2856   if (currentDcdcMode != EMU_DCDCCTRL_DCDCMODE_BYPASS) {
2857     BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, 1);
2858   }
2859 
2860   if ((EMU_DcdcMode_TypeDef)currentDcdcMode == dcdcMode) {
2861     /* Mode already set. If already in bypass, make sure the bypass current limiter
2862        is disabled. */
2863     if (dcdcMode == emuDcdcMode_Bypass) {
2864       BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, 0);
2865     }
2866     return;
2867   }
2868 
2869 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2870 
2871   /* Fix for errata DCDC_E203. */
2872   if ((currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_BYPASS)
2873       && (dcdcMode == emuDcdcMode_LowNoise)) {
2874     errataFixDcdcHsState = errataFixDcdcHsBypassLn;
2875   }
2876 #endif // (_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2877 
2878 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)
2879 
2880   /* Fix for errata DCDC_E204. */
2881   if (((currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_OFF) || (currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_BYPASS))
2882       && ((dcdcMode == emuDcdcMode_LowPower) || (dcdcMode == emuDcdcMode_LowNoise))) {
2883     /* Always start in LOWNOISE. Switch to LOWPOWER mode once LOWNOISE startup is complete. */
2884     EMU_IntClear(EMU_IFC_DCDCLNRUNNING);
2885     while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
2886     }
2887     EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) | EMU_DCDCCTRL_DCDCMODE_LOWNOISE;
2888     while ((EMU_IntGet() & EMU_IF_DCDCLNRUNNING) == 0U) {
2889     }
2890   }
2891 #endif // (_SILICON_LABS_GECKO_INTERNAL_SDID_84)
2892 
2893   /* Set user-requested mode. */
2894   while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0UL) {
2895   }
2896   EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK)
2897                   | (uint32_t)dcdcMode;
2898 
2899   /* Disable bypass current limiter after bypass mode is entered.
2900      Enable the limiter if any other mode is entered. */
2901   while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
2902   }
2903   BUS_RegBitWrite(&EMU->DCDCCLIMCTRL,
2904                   _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT,
2905                   dcdcMode == emuDcdcMode_Bypass ? 0U : 1U);
2906 
2907   if (dcdcLocked) {
2908     EMU_PowerLock();
2909   }
2910 }
2911 
2912 #if defined(EMU_DCDCCTRL_DCDCMODEEM23)
2913 /***************************************************************************//**
2914  * @brief
2915  *   Set DCDC Mode EM23 operating mode.
2916  *
2917  * @param[in] dcdcModeEM23
2918  *   DCDC mode EM23.
2919  ******************************************************************************/
EMU_DCDCModeEM23Set(EMU_DcdcModeEM23_TypeDef dcdcModeEM23)2920 void EMU_DCDCModeEM23Set(EMU_DcdcModeEM23_TypeDef dcdcModeEM23)
2921 {
2922   bool dcdcLocked;
2923 
2924   dcdcLocked = (EMU->PWRLOCK == EMU_PWRLOCK_LOCKKEY_LOCKED);
2925   EMU_PowerUnlock();
2926 
2927   /* Set user-requested mode. */
2928   while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0UL) {
2929   }
2930   EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODEEM23_MASK)
2931                   | (uint32_t)dcdcModeEM23;
2932 
2933   if (dcdcLocked) {
2934     EMU_PowerLock();
2935   }
2936 }
2937 #endif
2938 
2939 /***************************************************************************//**
2940  * @brief
2941  *   Power off the DCDC regulator.
2942  *
2943  * @details
2944  *   This function powers off the DCDC controller. This function should only be
2945  *   used if the external power circuit is wired for no DCDC. If the external power
2946  *   circuit is wired for DCDC usage, use @ref EMU_DCDCInit() and set the
2947  *   DCDC in bypass mode to disable DCDC.
2948  *
2949  * @return
2950  *   Return false if the DCDC could not be disabled.
2951  ******************************************************************************/
EMU_DCDCPowerOff(void)2952 bool EMU_DCDCPowerOff(void)
2953 {
2954   bool dcdcModeSet;
2955 
2956 #if defined(_EMU_PWRCFG_MASK)
2957   /* Set DCDCTODVDD only to enable write access to EMU->DCDCCTRL. */
2958   EMU->PWRCFG = EMU_PWRCFG_PWRCFG_DCDCTODVDD;
2959 #endif
2960 
2961   /* Select DVDD as input to the digital regulator. */
2962 #if defined(EMU_PWRCTRL_IMMEDIATEPWRSWITCH)
2963   EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD | EMU_PWRCTRL_IMMEDIATEPWRSWITCH;
2964 #elif defined(EMU_PWRCTRL_REGPWRSEL_DVDD)
2965   EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD;
2966 #endif
2967 
2968   /* Set DCDC to OFF and disable LP in EM2/3/4. Verify that the required
2969      mode could be set. */
2970   while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
2971   }
2972   EMU->DCDCCTRL = EMU_DCDCCTRL_DCDCMODE_OFF;
2973 
2974   dcdcModeSet = (EMU->DCDCCTRL == EMU_DCDCCTRL_DCDCMODE_OFF);
2975   EFM_ASSERT(dcdcModeSet);
2976 
2977   return dcdcModeSet;
2978 }
2979 
2980 /***************************************************************************//**
2981  * @brief
2982  *   Set DCDC LN regulator conduction mode.
2983  *
2984  * @param[in] conductionMode
2985  *   DCDC LN conduction mode.
2986  * @param[in] rcoDefaultSet
2987  *   The default DCDC RCO band for the conductionMode will be used if true.
2988  *   Otherwise, the current RCO configuration is used.
2989  ******************************************************************************/
EMU_DCDCConductionModeSet(EMU_DcdcConductionMode_TypeDef conductionMode,bool rcoDefaultSet)2990 void EMU_DCDCConductionModeSet(EMU_DcdcConductionMode_TypeDef conductionMode,
2991                                bool rcoDefaultSet)
2992 {
2993   EMU_DcdcMode_TypeDef currentDcdcMode
2994     = (EMU_DcdcMode_TypeDef)((uint32_t)
2995                              (EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK));
2996   EMU_DcdcLnRcoBand_TypeDef rcoBand
2997     = (EMU_DcdcLnRcoBand_TypeDef)((uint32_t)
2998                                   ((EMU->DCDCLNFREQCTRL
2999                                     & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
3000                                    >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT));
3001 
3002   /* Set bypass mode and wait for bypass mode to settle before
3003      EMU_DCDCMISCCTRL_LNFORCECCM is set. Restore current DCDC mode. */
3004   EMU_IntClear(EMU_IFC_DCDCINBYPASS);
3005   EMU_DCDCModeSet(emuDcdcMode_Bypass);
3006   while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
3007   }
3008   while ((EMU_IntGet() & EMU_IF_DCDCINBYPASS) == 0U) {
3009   }
3010   if (conductionMode == emuDcdcConductionMode_DiscontinuousLN) {
3011     EMU->DCDCMISCCTRL &= ~EMU_DCDCMISCCTRL_LNFORCECCM;
3012     if (rcoDefaultSet) {
3013       EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_3MHz);
3014     } else {
3015       /* emuDcdcConductionMode_DiscontinuousLN supports up to 4MHz LN RCO. */
3016       EFM_ASSERT(rcoBand <= emuDcdcLnRcoBand_4MHz);
3017     }
3018   } else {
3019     EMU->DCDCMISCCTRL |= EMU_DCDCMISCCTRL_LNFORCECCM;
3020     if (rcoDefaultSet) {
3021       EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_7MHz);
3022     }
3023   }
3024   EMU_DCDCModeSet(currentDcdcMode);
3025   /* Update slice configuration as it depends on conduction mode and RCO band.*/
3026   EMU_DCDCOptimizeSlice(dcdcEm01LoadCurrent_mA);
3027 }
3028 
3029 /***************************************************************************//**
3030  * @brief
3031  *   Set the DCDC output voltage.
3032  *
3033  * @note
3034  *   The DCDC is not characterized for the entire valid output voltage range.
3035  *   For that reason an upper limit of 3.0V output voltage is enforced.
3036  *
3037  * @param[in] mV
3038  *   Target DCDC output voltage in mV.
3039  *
3040  * @param[in] setLpVoltage
3041  *   Update LP voltage
3042  *
3043  * @param[in] setLnVoltage
3044  *   Update LN voltage
3045  *
3046  * @return
3047  *   True if the mV parameter is valid.
3048  ******************************************************************************/
EMU_DCDCOutputVoltageSet(uint32_t mV,bool setLpVoltage,bool setLnVoltage)3049 bool EMU_DCDCOutputVoltageSet(uint32_t mV,
3050                               bool setLpVoltage,
3051                               bool setLnVoltage)
3052 {
3053 #if defined(_DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK)
3054 
3055   bool validOutVoltage;
3056   bool attenuationSet;
3057   uint32_t mVlow = 0;
3058   uint32_t mVhigh = 0;
3059   uint32_t mVdiff;
3060   uint32_t vrefVal[DCDC_TRIM_MODES] = { 0 };
3061   uint32_t vrefLow[DCDC_TRIM_MODES] = { 0 };
3062   uint32_t vrefHigh[DCDC_TRIM_MODES] = { 0 };
3063   uint8_t lpcmpBias[DCDC_TRIM_MODES] = { 0 };
3064 
3065   /* Check that the set voltage is within valid range.
3066      Voltages are obtained from the data sheet. */
3067   validOutVoltage = (mV >= PWRCFG_DCDCTODVDD_VMIN)
3068                     && (mV <= PWRCFG_DCDCTODVDD_VMAX);
3069 
3070   if (!validOutVoltage) {
3071     EFM_ASSERT(false);
3072     /* Return when assertions are disabled. */
3073     return false;
3074   }
3075 
3076   /* Set attenuation to use and low/high range. */
3077   attenuationSet = mV > 1800U;
3078   if (attenuationSet) {
3079     mVlow = 1800;
3080     mVhigh = 3000;
3081     mVdiff = mVhigh - mVlow;
3082   } else {
3083     mVlow = 1200;
3084     mVhigh = 1800;
3085     mVdiff = mVhigh - mVlow;
3086   }
3087 
3088   /* Get 2-point calibration data from DEVINFO. */
3089 
3090   /* LN mode */
3091   if (attenuationSet) {
3092     vrefLow[dcdcTrimMode_LN]  = DEVINFO->DCDCLNVCTRL0;
3093     vrefHigh[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK)
3094                                 >> _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_SHIFT;
3095     vrefLow[dcdcTrimMode_LN]  = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_MASK)
3096                                 >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_SHIFT;
3097   } else {
3098     vrefLow[dcdcTrimMode_LN]  = DEVINFO->DCDCLNVCTRL0;
3099     vrefHigh[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_MASK)
3100                                 >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_SHIFT;
3101     vrefLow[dcdcTrimMode_LN]  = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_MASK)
3102                                 >> _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_SHIFT;
3103   }
3104 
3105   /* LP EM234H mode */
3106   lpcmpBias[dcdcTrimMode_EM234H_LP] = (uint8_t)
3107                                       ((EMU->DCDCMISCCTRL & _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK)
3108                                        >> _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT);
3109   lpGetDevinfoVrefLowHigh(&vrefLow[dcdcTrimMode_EM234H_LP],
3110                           &vrefHigh[dcdcTrimMode_EM234H_LP],
3111                           attenuationSet,
3112                           lpcmpBias[dcdcTrimMode_EM234H_LP]);
3113 
3114 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3115   /* LP EM01 mode */
3116   lpcmpBias[dcdcTrimMode_EM01_LP] = (uint8_t)
3117                                     ((EMU->DCDCLPEM01CFG & _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3118                                      >> _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_SHIFT);
3119   lpGetDevinfoVrefLowHigh(&vrefLow[dcdcTrimMode_EM01_LP],
3120                           &vrefHigh[dcdcTrimMode_EM01_LP],
3121                           attenuationSet,
3122                           lpcmpBias[dcdcTrimMode_EM01_LP]);
3123 #endif
3124 
3125   /* Calculate output voltage trims. */
3126   vrefVal[dcdcTrimMode_LN]         = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_LN] - vrefLow[dcdcTrimMode_LN]))
3127                                      / mVdiff;
3128   vrefVal[dcdcTrimMode_LN]        += vrefLow[dcdcTrimMode_LN];
3129 
3130   vrefVal[dcdcTrimMode_EM234H_LP]  = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_EM234H_LP] - vrefLow[dcdcTrimMode_EM234H_LP]))
3131                                      / mVdiff;
3132   vrefVal[dcdcTrimMode_EM234H_LP] += vrefLow[dcdcTrimMode_EM234H_LP];
3133 
3134 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3135   vrefVal[dcdcTrimMode_EM01_LP]    = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_EM01_LP] - vrefLow[dcdcTrimMode_EM01_LP]))
3136                                      / mVdiff;
3137   vrefVal[dcdcTrimMode_EM01_LP]   += vrefLow[dcdcTrimMode_EM01_LP];
3138 #endif
3139 
3140   /* Range checks */
3141   if ((vrefVal[dcdcTrimMode_LN] > vrefHigh[dcdcTrimMode_LN])
3142       || (vrefVal[dcdcTrimMode_LN] < vrefLow[dcdcTrimMode_LN])
3143 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3144       || (vrefVal[dcdcTrimMode_EM01_LP] > vrefHigh[dcdcTrimMode_EM01_LP])
3145       || (vrefVal[dcdcTrimMode_EM01_LP] < vrefLow[dcdcTrimMode_EM01_LP])
3146 #endif
3147       || (vrefVal[dcdcTrimMode_EM234H_LP] > vrefHigh[dcdcTrimMode_EM234H_LP])
3148       || (vrefVal[dcdcTrimMode_EM234H_LP] < vrefLow[dcdcTrimMode_EM234H_LP])) {
3149     EFM_ASSERT(false);
3150     /* Return when assertions are disabled. */
3151     return false;
3152   }
3153 
3154   /* Update output voltage tuning for LN and LP modes. */
3155   if (setLnVoltage) {
3156     EMU->DCDCLNVCTRL = (EMU->DCDCLNVCTRL & ~(_EMU_DCDCLNVCTRL_LNVREF_MASK | _EMU_DCDCLNVCTRL_LNATT_MASK))
3157                        | (vrefVal[dcdcTrimMode_LN] << _EMU_DCDCLNVCTRL_LNVREF_SHIFT)
3158                        | (attenuationSet ? EMU_DCDCLNVCTRL_LNATT : 0U);
3159   }
3160 
3161   if (setLpVoltage) {
3162     /* Load LP EM234H comparator hysteresis calibration. */
3163     if (!(lpCmpHystCalibrationLoad(attenuationSet, lpcmpBias[dcdcTrimMode_EM234H_LP], dcdcTrimMode_EM234H_LP))) {
3164       EFM_ASSERT(false);
3165       /* Return when assertions are disabled. */
3166       return false;
3167     }
3168 
3169 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3170     /* Load LP EM234H comparator hysteresis calibration. */
3171     if (!(lpCmpHystCalibrationLoad(attenuationSet, lpcmpBias[dcdcTrimMode_EM01_LP], dcdcTrimMode_EM01_LP))) {
3172       EFM_ASSERT(false);
3173       /* Return when assertions are disabled. */
3174       return false;
3175     }
3176 
3177     /* LP VREF is that maximum of trims for EM01 and EM234H. */
3178     vrefVal[dcdcTrimMode_EM234H_LP] = SL_MAX(vrefVal[dcdcTrimMode_EM234H_LP], vrefVal[dcdcTrimMode_EM01_LP]);
3179 #endif
3180 
3181     /* Don't exceed the maximum available code as specified in the reference manual for EMU_DCDCLPVCTRL. */
3182     vrefVal[dcdcTrimMode_EM234H_LP] = SL_MIN(vrefVal[dcdcTrimMode_EM234H_LP], 0xE7U);
3183     EMU->DCDCLPVCTRL = (EMU->DCDCLPVCTRL & ~(_EMU_DCDCLPVCTRL_LPVREF_MASK | _EMU_DCDCLPVCTRL_LPATT_MASK))
3184                        | (vrefVal[dcdcTrimMode_EM234H_LP] << _EMU_DCDCLPVCTRL_LPVREF_SHIFT)
3185                        | (attenuationSet ? EMU_DCDCLPVCTRL_LPATT : 0U);
3186   }
3187 #endif
3188   return true;
3189 }
3190 
3191 /***************************************************************************//**
3192  * @brief
3193  *   Optimize the DCDC slice count based on the estimated average load current
3194  *   in EM0.
3195  *
3196  * @param[in] em0LoadCurrentmA
3197  *   Estimated average EM0 load current in mA.
3198  ******************************************************************************/
EMU_DCDCOptimizeSlice(uint32_t em0LoadCurrentmA)3199 void EMU_DCDCOptimizeSlice(uint32_t em0LoadCurrentmA)
3200 {
3201   uint32_t sliceCount = 0;
3202   uint32_t rcoBand = (EMU->DCDCLNFREQCTRL & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
3203                      >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT;
3204 
3205   /* Set the recommended slice count. */
3206   if (((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) != 0U)
3207       && (rcoBand >= (uint32_t)emuDcdcLnRcoBand_5MHz)) {
3208     if (em0LoadCurrentmA < 20U) {
3209       sliceCount = 4;
3210     } else if ((em0LoadCurrentmA >= 20U) && (em0LoadCurrentmA < 40U)) {
3211       sliceCount = 8;
3212     } else {
3213       sliceCount = 16;
3214     }
3215   } else if (((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) == 0U)
3216              && (rcoBand <= (uint32_t)emuDcdcLnRcoBand_4MHz)) {
3217     if (em0LoadCurrentmA < 10U) {
3218       sliceCount = 4;
3219     } else if ((em0LoadCurrentmA >= 10U) && (em0LoadCurrentmA < 20U)) {
3220       sliceCount = 8;
3221     } else {
3222       sliceCount = 16;
3223     }
3224   } else if (((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) != 0U)
3225              && (rcoBand <= (uint32_t)emuDcdcLnRcoBand_4MHz)) {
3226     if (em0LoadCurrentmA < 40U) {
3227       sliceCount = 8;
3228     } else {
3229       sliceCount = 16;
3230     }
3231   } else {
3232     /* This configuration is not recommended. @ref EMU_DCDCInit() applies a recommended
3233        configuration. */
3234     EFM_ASSERT(false);
3235   }
3236 
3237   /* The selected slices are PSLICESEL + 1. */
3238   sliceCount--;
3239 
3240   /* Apply slice count to both N and P slice. */
3241   sliceCount = (sliceCount << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT
3242                 | sliceCount << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
3243   EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK
3244                                              | _EMU_DCDCMISCCTRL_NFETCNT_MASK))
3245                       | sliceCount;
3246 
3247   /* Update the current limiters. */
3248   currentLimitersUpdate();
3249 }
3250 
3251 /***************************************************************************//**
3252  * @brief
3253  *   Set DCDC Low-noise RCO band.
3254  *
3255  * @param[in] band
3256  *   RCO band to set.
3257  ******************************************************************************/
EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band)3258 void EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band)
3259 {
3260   uint32_t forcedCcm;
3261   forcedCcm = BUS_RegBitRead(&EMU->DCDCMISCCTRL, _EMU_DCDCMISCCTRL_LNFORCECCM_SHIFT);
3262 
3263   /* DCM mode supports up to 4 MHz LN RCO. */
3264   EFM_ASSERT(((forcedCcm == 0U) && band <= emuDcdcLnRcoBand_4MHz)
3265              || (forcedCcm != 0U));
3266 
3267   EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
3268                         | ((uint32_t)band << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);
3269 
3270   /* Update slice configuration as this depends on the RCO band. */
3271   EMU_DCDCOptimizeSlice(dcdcEm01LoadCurrent_mA);
3272 }
3273 #endif /* EMU_SERIES1_DCDC_BUCK_PRESENT */
3274 
3275 #if defined(EMU_SERIES2_DCDC_BOOST_PRESENT)
3276 /***************************************************************************//**
3277  * @brief
3278  *   Configure the DCDC Boost regulator.
3279  *
3280  * @param[in] dcdcBoostInit
3281  *  The DCDC initialization structure.
3282  *
3283  * @return
3284  *   True if initialization parameters are valid.
3285  ******************************************************************************/
EMU_DCDCBoostInit(const EMU_DCDCBoostInit_TypeDef * dcdcBoostInit)3286 bool EMU_DCDCBoostInit(const EMU_DCDCBoostInit_TypeDef *dcdcBoostInit)
3287 {
3288   bool dcdcLocked;
3289 
3290   CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3291 #if defined(_DCDC_EN_EN_MASK)
3292   DCDC->EN_SET    = DCDC_EN_EN;
3293 #endif
3294   dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3295   EMU_DCDCUnlock();
3296 
3297 #if defined(_DCDC_SYNCBUSY_MASK)
3298   EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3299 #endif
3300 
3301   DCDC->BSTCTRL = (DCDC->BSTCTRL & ~(_DCDC_BSTCTRL_IPKTMAXCTRL_MASK))
3302                   | ((uint32_t)dcdcBoostInit->tonMax << _DCDC_BSTCTRL_IPKTMAXCTRL_SHIFT);
3303   DCDC->BSTEM01CTRL = ((uint32_t)dcdcBoostInit->driveSpeedEM01 << _DCDC_BSTEM01CTRL_DRVSPEED_SHIFT)
3304                       | ((uint32_t)dcdcBoostInit->peakCurrentEM01 << _DCDC_BSTEM01CTRL_IPKVAL_SHIFT);
3305   DCDC->BSTEM23CTRL = ((uint32_t)dcdcBoostInit->driveSpeedEM23 << _DCDC_BSTEM23CTRL_DRVSPEED_SHIFT)
3306                       | ((uint32_t)dcdcBoostInit->peakCurrentEM23 << _DCDC_BSTEM23CTRL_IPKVAL_SHIFT);
3307 
3308   EMU_BoostExternalShutdownEnable(dcdcBoostInit->externalShutdownEn);
3309 
3310   EMU_DCDCModeSet(emuDcdcMode_Regulation);
3311 
3312   if (dcdcLocked) {
3313     EMU_DCDCLock();
3314   }
3315 
3316   EMU_DCDCUpdatedHook();
3317 
3318   return true;
3319 }
3320 
3321 /***************************************************************************//**
3322  * @brief
3323  *   Set EM01 mode Boost Peak Current setting.
3324  *
3325  * @param[in] boostPeakCurrentEM01
3326  *  Boost Peak load current coefficient in EM01 mode.
3327  ******************************************************************************/
EMU_EM01BoostPeakCurrentSet(const EMU_DcdcBoostEM01PeakCurrent_TypeDef boostPeakCurrentEM01)3328 void EMU_EM01BoostPeakCurrentSet(const EMU_DcdcBoostEM01PeakCurrent_TypeDef boostPeakCurrentEM01)
3329 {
3330   bool dcdcLocked = false;
3331   bool dcdcClkWasEnabled = false;
3332 
3333   dcdcClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) != 0);
3334   CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3335 
3336   dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3337   EMU_DCDCUnlock();
3338 
3339   /* Wait for synchronization before writing new value */
3340 #if defined(_DCDC_SYNCBUSY_MASK)
3341   EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3342 #endif
3343 
3344   BUS_RegMaskedWrite(&DCDC->BSTEM01CTRL,
3345                      _DCDC_BSTEM01CTRL_IPKVAL_MASK,
3346                      ((uint32_t)boostPeakCurrentEM01 << _DCDC_BSTEM01CTRL_IPKVAL_SHIFT));
3347 
3348   if (dcdcLocked) {
3349     EMU_DCDCLock();
3350   }
3351 
3352   if (!dcdcClkWasEnabled) {
3353     CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
3354   }
3355 
3356   EMU_DCDCUpdatedHook();
3357 }
3358 
3359 /***************************************************************************//**
3360  * @brief
3361  *   Enable/disable Boost External Shutdown Mode.
3362  *
3363  * @param[in] enable
3364  *   The boost DC-DC converter can be activated or deactivated
3365  *   from a dedicated BOOST_EN pin on the device if enable is true.
3366  ******************************************************************************/
EMU_BoostExternalShutdownEnable(bool enable)3367 void EMU_BoostExternalShutdownEnable(bool enable)
3368 {
3369   if (enable) {
3370     EMU->BOOSTCTRL_CLR = EMU_BOOSTCTRL_BOOSTENCTRL;
3371   } else {
3372     EMU->BOOSTCTRL_SET = EMU_BOOSTCTRL_BOOSTENCTRL;
3373   }
3374 }
3375 #endif /* EMU_SERIES2_DCDC_BOOST_PRESENT */
3376 
3377 #if defined(EMU_SERIES2_DCDC_BUCK_PRESENT) \
3378   || defined(EMU_SERIES2_DCDC_BOOST_PRESENT)
3379 /***************************************************************************//**
3380  * @brief
3381  *   Indicate that the DCDC peripheral bus clock enable has changed allowing
3382  *   RAIL to react accordingly.
3383  *
3384  * @details
3385  *   This function is called after DCDC has been enabled or disabled.
3386  *   The function implementation does not perform anything, but it is SL_WEAK
3387  *   so that it can use the RAIL version if needed.
3388  ******************************************************************************/
EMU_DCDCUpdatedHook(void)3389 SL_WEAK void EMU_DCDCUpdatedHook(void)
3390 {
3391 }
3392 
3393 /***************************************************************************//**
3394  * @brief
3395  *   Set DCDC regulator operating mode.
3396  *
3397  * @param[in] dcdcMode
3398  *   DCDC mode.
3399  * @return
3400  *   Returns the status of the DCDC mode set operation.
3401  * @verbatim
3402  *   SL_STATUS_OK - Operation completed successfully.
3403  *   SL_STATUS_TIMEOUT - Operation EMU DCDC set mode timeout.
3404  * @endverbatim
3405  ******************************************************************************/
EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)3406 sl_status_t EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)
3407 {
3408   bool dcdcLocked;
3409   uint32_t currentDcdcMode;
3410   sl_status_t error = SL_STATUS_OK;
3411   uint32_t timeout = 0;
3412   CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3413 #if defined(_DCDC_EN_EN_MASK)
3414   DCDC->EN_SET = DCDC_EN_EN;
3415 #endif
3416   dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3417   EMU_DCDCUnlock();
3418 
3419   if (dcdcMode == emuDcdcMode_Bypass) {
3420 #if defined(_DCDC_SYNCBUSY_MASK)
3421 #if defined(_DCDC_SYNCBUSY_CTRL_MASK)
3422     EMU_DCDCSync(DCDC_SYNCBUSY_CTRL);
3423 #else
3424     EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3425 #endif
3426 #endif
3427     currentDcdcMode = (DCDC->CTRL & _DCDC_CTRL_MODE_MASK) >> _DCDC_CTRL_MODE_SHIFT;
3428 
3429     if (currentDcdcMode != emuDcdcMode_Bypass) {
3430       /* Switch to BYPASS mode if it is not the current mode */
3431       DCDC->CTRL_CLR = DCDC_CTRL_MODE;
3432       while (((DCDC->STATUS & DCDC_STATUS_BYPSW) == 0U) && (timeout < EMU_DCDC_MODE_SET_TIMEOUT)) {
3433         /* Wait for BYPASS switch enable. */
3434         timeout++;
3435       }
3436       if (timeout >= EMU_DCDC_MODE_SET_TIMEOUT) {
3437         error = SL_STATUS_TIMEOUT;
3438       }
3439     }
3440 #if defined(_DCDC_EN_EN_MASK)
3441     DCDC->EN_CLR = DCDC_EN_EN;
3442 #endif
3443   } else {
3444     while (((DCDC->STATUS & DCDC_STATUS_VREGIN) != 0U) && (timeout < EMU_DCDC_MODE_SET_TIMEOUT)) {
3445       /* Wait for VREGIN voltage to rise above threshold. */
3446       timeout++;
3447     }
3448     if (timeout >= EMU_DCDC_MODE_SET_TIMEOUT) {
3449       error = SL_STATUS_TIMEOUT;
3450     } else {
3451       DCDC->IF_CLR = DCDC_IF_REGULATION;
3452       DCDC->CTRL_SET = DCDC_CTRL_MODE;
3453       timeout = 0;
3454       while (((DCDC->IF & DCDC_IF_REGULATION) == 0U) && (timeout < EMU_DCDC_MODE_SET_TIMEOUT)) {
3455         /* Wait for DCDC to complete it's startup. */
3456         timeout++;
3457       }
3458       if (timeout >= EMU_DCDC_MODE_SET_TIMEOUT) {
3459         error = SL_STATUS_TIMEOUT;
3460       }
3461     }
3462   }
3463 
3464   if (dcdcLocked) {
3465     EMU_DCDCLock();
3466   }
3467 
3468   EMU_DCDCUpdatedHook();
3469   return error;
3470 }
3471 #endif /* EMU_SERIES2_DCDC_BUCK_PRESENT || EMU_SERIES2_DCDC_BOOST_PRESENT */
3472 
3473 #if defined(EMU_SERIES2_DCDC_BUCK_PRESENT)
3474 /***************************************************************************//**
3475  * @brief
3476  *   Configure the DCDC regulator.
3477  *
3478  * @param[in] dcdcInit
3479  *  The DCDC initialization structure.
3480  *
3481  * @return
3482  *   True if initialization parameters are valid.
3483  ******************************************************************************/
EMU_DCDCInit(const EMU_DCDCInit_TypeDef * dcdcInit)3484 bool EMU_DCDCInit(const EMU_DCDCInit_TypeDef *dcdcInit)
3485 {
3486   bool dcdcLocked;
3487 
3488   CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3489 #if defined(_DCDC_EN_EN_MASK)
3490   DCDC->EN_SET    = DCDC_EN_EN;
3491 #endif
3492   dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3493   EMU_DCDCUnlock();
3494 
3495   EMU->VREGVDDCMPCTRL = ((uint32_t)dcdcInit->cmpThreshold
3496                          << _EMU_VREGVDDCMPCTRL_THRESSEL_SHIFT)
3497                         | EMU_VREGVDDCMPCTRL_VREGINCMPEN;
3498 
3499 #if defined(_DCDC_SYNCBUSY_MASK)
3500 #if defined(_DCDC_SYNCBUSY_CTRL_MASK)
3501   EMU_DCDCSync(DCDC_SYNCBUSY_CTRL | DCDC_SYNCBUSY_EM01CTRL0 | DCDC_SYNCBUSY_EM23CTRL0);
3502 #else
3503   EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3504 #endif
3505 #endif
3506 #if defined(_DCDC_CTRL_DCMONLYEN_MASK)
3507   DCDC->CTRL = (DCDC->CTRL & ~(_DCDC_CTRL_IPKTMAXCTRL_MASK
3508                                | _DCDC_CTRL_DCMONLYEN_MASK))
3509                | ((uint32_t)dcdcInit->tonMax << _DCDC_CTRL_IPKTMAXCTRL_SHIFT)
3510                | ((uint32_t)(dcdcInit->dcmOnlyEn ? 1U : 0U) << _DCDC_CTRL_DCMONLYEN_SHIFT);
3511 #else
3512   DCDC->CTRL = (DCDC->CTRL & ~(_DCDC_CTRL_IPKTMAXCTRL_MASK))
3513                | ((uint32_t)dcdcInit->tonMax << _DCDC_CTRL_IPKTMAXCTRL_SHIFT);
3514 #endif
3515   DCDC->EM01CTRL0 = ((uint32_t)dcdcInit->driveSpeedEM01 << _DCDC_EM01CTRL0_DRVSPEED_SHIFT)
3516                     | ((uint32_t)dcdcInit->peakCurrentEM01 << _DCDC_EM01CTRL0_IPKVAL_SHIFT);
3517   DCDC->EM23CTRL0 = ((uint32_t)dcdcInit->driveSpeedEM23 << _DCDC_EM23CTRL0_DRVSPEED_SHIFT)
3518                     | ((uint32_t)dcdcInit->peakCurrentEM23 << _DCDC_EM23CTRL0_IPKVAL_SHIFT);
3519 
3520   EMU_DCDCModeSet(dcdcInit->mode);
3521 
3522   if (dcdcLocked) {
3523     EMU_DCDCLock();
3524   }
3525 
3526   EMU_DCDCUpdatedHook();
3527 
3528   return true;
3529 }
3530 
3531 /***************************************************************************//**
3532  * @brief
3533  *   Power off the DCDC regulator.
3534  *
3535  * @return
3536  *   Returns true.
3537  ******************************************************************************/
EMU_DCDCPowerOff(void)3538 bool EMU_DCDCPowerOff(void)
3539 {
3540   EMU_DCDCModeSet(emuDcdcMode_Bypass);
3541   return true;
3542 }
3543 
3544 /***************************************************************************//**
3545  * @brief
3546  *   Set EMO1 mode Peak Current setting.
3547  *
3548  * @param[in] peakCurrentEM01
3549  *  Peak load current coefficient in EM01 mode.
3550  ******************************************************************************/
EMU_EM01PeakCurrentSet(const EMU_DcdcPeakCurrent_TypeDef peakCurrentEM01)3551 void EMU_EM01PeakCurrentSet(const EMU_DcdcPeakCurrent_TypeDef peakCurrentEM01)
3552 {
3553   bool dcdcLocked = false;
3554   bool dcdcClkWasEnabled = false;
3555 
3556   dcdcClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) != 0);
3557   CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3558 
3559 #if defined(_DCDC_EN_EN_MASK)
3560   bool dcdcWasEnabled = ((DCDC->EN & DCDC_EN_EN) != 0);
3561   DCDC->EN_SET = DCDC_EN_EN;
3562 #endif
3563 
3564   dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3565   EMU_DCDCUnlock();
3566 
3567   /* Wait for synchronization before writing new value */
3568 #if defined(_DCDC_SYNCBUSY_MASK)
3569 #if defined(_DCDC_SYNCBUSY_EM01CTRL0_MASK)
3570   EMU_DCDCSync(DCDC_SYNCBUSY_EM01CTRL0);
3571 #else
3572   EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3573 #endif
3574 #endif
3575 
3576   BUS_RegMaskedWrite(&DCDC->EM01CTRL0,
3577                      _DCDC_EM01CTRL0_IPKVAL_MASK,
3578                      ((uint32_t)peakCurrentEM01 << _DCDC_EM01CTRL0_IPKVAL_SHIFT));
3579 
3580 #if defined(_DCDC_EN_EN_MASK)
3581   if (!dcdcWasEnabled) {
3582     DCDC->EN_CLR = DCDC_EN_EN;
3583   }
3584 #endif
3585 
3586   if (dcdcLocked) {
3587     EMU_DCDCLock();
3588   }
3589 
3590   if (!dcdcClkWasEnabled) {
3591     CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
3592   }
3593 
3594   EMU_DCDCUpdatedHook();
3595 }
3596 
3597 #if defined(_DCDC_PFMXCTRL_IPKVAL_MASK)
3598 /***************************************************************************//**
3599  * @brief
3600  *   Set PFMX mode Peak Current setting.
3601  *
3602  * @param[in] value
3603  *  Peak load current coefficient in PFMX mode.
3604  ******************************************************************************/
EMU_DCDCSetPFMXModePeakCurrent(uint32_t value)3605 void EMU_DCDCSetPFMXModePeakCurrent(uint32_t value)
3606 {
3607   bool dcdcLocked = false;
3608   bool dcdcClkWasEnabled = false;
3609 
3610   /* Verification that the parameter is in range. */
3611   /* if not, restrict value to maximum allowed.   */
3612   EFM_ASSERT(value <= (_DCDC_PFMXCTRL_IPKVAL_MASK >> _DCDC_PFMXCTRL_IPKVAL_SHIFT));
3613   if (value > (_DCDC_PFMXCTRL_IPKVAL_MASK >> _DCDC_PFMXCTRL_IPKVAL_SHIFT)) {
3614     value = (_DCDC_PFMXCTRL_IPKVAL_MASK >> _DCDC_PFMXCTRL_IPKVAL_SHIFT);
3615   }
3616 
3617   dcdcClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) != 0);
3618   CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3619 
3620   dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3621   EMU_DCDCUnlock();
3622 
3623 #if defined(_DCDC_SYNCBUSY_MASK)
3624   /* Wait for synchronization before writing new value */
3625   EMU_DCDCSync(DCDC_SYNCBUSY_PFMXCTRL);
3626 #endif
3627 
3628   DCDC->PFMXCTRL = ((DCDC->PFMXCTRL & ~_DCDC_PFMXCTRL_IPKVAL_MASK)
3629                     | value << _DCDC_PFMXCTRL_IPKVAL_SHIFT);
3630 
3631   if (dcdcLocked) {
3632     EMU_DCDCLock();
3633   }
3634 
3635   if (!dcdcClkWasEnabled) {
3636     CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
3637   }
3638 
3639   EMU_DCDCUpdatedHook();
3640 }
3641 #endif /* _DCDC_PFMXCTRL_IPKVAL_MASK */
3642 
3643 #if defined(_DCDC_PFMXCTRL_IPKTMAXCTRL_MASK)
3644 /***************************************************************************//**
3645  * @brief
3646  *   Set Ton_max timeout control.
3647  *
3648  * @param[in] value
3649  *  Maximum time for peak current detection.
3650  ******************************************************************************/
EMU_DCDCSetPFMXTimeoutMaxCtrl(EMU_DcdcTonMaxTimeout_TypeDef value)3651 void EMU_DCDCSetPFMXTimeoutMaxCtrl(EMU_DcdcTonMaxTimeout_TypeDef value)
3652 {
3653   bool dcdcLocked = false;
3654   bool dcdcClkWasEnabled = false;
3655 
3656   dcdcClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) != 0);
3657   CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3658 
3659   dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3660   EMU_DCDCUnlock();
3661 
3662 #if defined(_DCDC_SYNCBUSY_MASK)
3663   /* Wait for synchronization before writing new value */
3664   EMU_DCDCSync(DCDC_SYNCBUSY_PFMXCTRL);
3665 #endif
3666 
3667   DCDC->PFMXCTRL = ((DCDC->PFMXCTRL & ~_DCDC_PFMXCTRL_IPKTMAXCTRL_MASK)
3668                     | value << _DCDC_PFMXCTRL_IPKTMAXCTRL_SHIFT);
3669 
3670   if (dcdcLocked) {
3671     EMU_DCDCLock();
3672   }
3673 
3674   if (!dcdcClkWasEnabled) {
3675     CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
3676   }
3677 
3678   EMU_DCDCUpdatedHook();
3679 }
3680 #endif /* _DCDC_PFMXCTRL_IPKTMAXCTRL_MASK */
3681 #endif /* EMU_SERIES2_DCDC_BUCK_PRESENT */
3682 
3683 #if defined(EMU_STATUS_VMONRDY)
3684 
3685 /***************************************************************************//**
3686  * @brief
3687  *   Get the calibrated threshold value.
3688  *
3689  * @details
3690  *   All VMON channels have two calibration fields in the DI page that
3691  *   describes the threshold at 1.86 V and 2.98 V. This function will convert
3692  *   the uncalibrated input voltage threshold in millivolts into a calibrated
3693  *   threshold.
3694  *
3695  * @param[in] channel
3696  *   A VMON channel.
3697  *
3698  * @param[in] threshold
3699  *   A desired threshold in millivolts.
3700  *
3701  * @return
3702  *   A calibrated threshold value to use. The first digit of the return value is placed
3703  *   in the "fine" register fields while the next digits are placed in the
3704  *   "coarse" register fields.
3705  ******************************************************************************/
vmonCalibratedThreshold(EMU_VmonChannel_TypeDef channel,int threshold)3706 static uint32_t vmonCalibratedThreshold(EMU_VmonChannel_TypeDef channel,
3707                                         int threshold)
3708 {
3709   uint32_t tDiff = 0;
3710   uint32_t tLow = 0;
3711   uint32_t tHigh = 0;
3712   uint32_t calReg;
3713 
3714   /* Get calibration values for 1.86 V and 2.98 V */
3715   switch (channel) {
3716     case emuVmonChannel_AVDD:
3717       calReg = DEVINFO->VMONCAL0;
3718       tLow = (10U * ((calReg & _DEVINFO_VMONCAL0_AVDD1V86THRESCOARSE_MASK)
3719                      >> _DEVINFO_VMONCAL0_AVDD1V86THRESCOARSE_SHIFT))
3720              + ((calReg & _DEVINFO_VMONCAL0_AVDD1V86THRESFINE_MASK)
3721                 >> _DEVINFO_VMONCAL0_AVDD1V86THRESFINE_SHIFT);
3722       tHigh = (10U * ((calReg & _DEVINFO_VMONCAL0_AVDD2V98THRESCOARSE_MASK)
3723                       >> _DEVINFO_VMONCAL0_AVDD2V98THRESCOARSE_SHIFT))
3724               + ((calReg & _DEVINFO_VMONCAL0_AVDD2V98THRESFINE_MASK)
3725                  >> _DEVINFO_VMONCAL0_AVDD2V98THRESFINE_SHIFT);
3726       break;
3727     case emuVmonChannel_ALTAVDD:
3728       calReg = DEVINFO->VMONCAL0;
3729       tLow = (10U * ((calReg & _DEVINFO_VMONCAL0_ALTAVDD1V86THRESCOARSE_MASK)
3730                      >> _DEVINFO_VMONCAL0_ALTAVDD1V86THRESCOARSE_SHIFT))
3731              + ((calReg & _DEVINFO_VMONCAL0_ALTAVDD1V86THRESFINE_MASK)
3732                 >> _DEVINFO_VMONCAL0_ALTAVDD1V86THRESFINE_SHIFT);
3733       tHigh = (10U * ((calReg & _DEVINFO_VMONCAL0_ALTAVDD2V98THRESCOARSE_MASK)
3734                       >> _DEVINFO_VMONCAL0_ALTAVDD2V98THRESCOARSE_SHIFT))
3735               + ((calReg & _DEVINFO_VMONCAL0_ALTAVDD2V98THRESFINE_MASK)
3736                  >> _DEVINFO_VMONCAL0_ALTAVDD2V98THRESFINE_SHIFT);
3737       break;
3738     case emuVmonChannel_DVDD:
3739       calReg = DEVINFO->VMONCAL1;
3740       tLow = (10U * ((calReg & _DEVINFO_VMONCAL1_DVDD1V86THRESCOARSE_MASK)
3741                      >> _DEVINFO_VMONCAL1_DVDD1V86THRESCOARSE_SHIFT))
3742              + ((calReg & _DEVINFO_VMONCAL1_DVDD1V86THRESFINE_MASK)
3743                 >> _DEVINFO_VMONCAL1_DVDD1V86THRESFINE_SHIFT);
3744       tHigh = (10U * ((calReg & _DEVINFO_VMONCAL1_DVDD2V98THRESCOARSE_MASK)
3745                       >> _DEVINFO_VMONCAL1_DVDD2V98THRESCOARSE_SHIFT))
3746               + ((calReg & _DEVINFO_VMONCAL1_DVDD2V98THRESFINE_MASK)
3747                  >> _DEVINFO_VMONCAL1_DVDD2V98THRESFINE_SHIFT);
3748       break;
3749     case emuVmonChannel_IOVDD0:
3750       calReg = DEVINFO->VMONCAL1;
3751       tLow = (10U * ((calReg & _DEVINFO_VMONCAL1_IO01V86THRESCOARSE_MASK)
3752                      >> _DEVINFO_VMONCAL1_IO01V86THRESCOARSE_SHIFT))
3753              + ((calReg & _DEVINFO_VMONCAL1_IO01V86THRESFINE_MASK)
3754                 >> _DEVINFO_VMONCAL1_IO01V86THRESFINE_SHIFT);
3755       tHigh = (10U * ((calReg & _DEVINFO_VMONCAL1_IO02V98THRESCOARSE_MASK)
3756                       >> _DEVINFO_VMONCAL1_IO02V98THRESCOARSE_SHIFT))
3757               + ((calReg & _DEVINFO_VMONCAL1_IO02V98THRESFINE_MASK)
3758                  >> _DEVINFO_VMONCAL1_IO02V98THRESFINE_SHIFT);
3759       break;
3760 #if defined(_EMU_VMONIO1CTRL_EN_MASK)
3761     case emuVmonChannel_IOVDD1:
3762       calReg = DEVINFO->VMONCAL2;
3763       tLow = (10U * ((calReg & _DEVINFO_VMONCAL2_IO11V86THRESCOARSE_MASK)
3764                      >> _DEVINFO_VMONCAL2_IO11V86THRESCOARSE_SHIFT))
3765              + ((calReg & _DEVINFO_VMONCAL2_IO11V86THRESFINE_MASK)
3766                 >> _DEVINFO_VMONCAL2_IO11V86THRESFINE_SHIFT);
3767       tHigh = (10U * ((calReg & _DEVINFO_VMONCAL2_IO12V98THRESCOARSE_MASK)
3768                       >> _DEVINFO_VMONCAL2_IO12V98THRESCOARSE_SHIFT))
3769               + ((calReg & _DEVINFO_VMONCAL2_IO12V98THRESFINE_MASK)
3770                  >> _DEVINFO_VMONCAL2_IO12V98THRESFINE_SHIFT);
3771       break;
3772 #endif
3773 #if defined(_EMU_VMONBUVDDCTRL_EN_MASK)
3774     case emuVmonChannel_BUVDD:
3775       calReg = DEVINFO->VMONCAL2;
3776       tLow = (10U * ((calReg & _DEVINFO_VMONCAL2_BUVDD1V86THRESCOARSE_MASK)
3777                      >> _DEVINFO_VMONCAL2_BUVDD1V86THRESCOARSE_SHIFT))
3778              + ((calReg & _DEVINFO_VMONCAL2_BUVDD1V86THRESFINE_MASK)
3779                 >> _DEVINFO_VMONCAL2_BUVDD1V86THRESFINE_SHIFT);
3780       tHigh = (10U * ((calReg & _DEVINFO_VMONCAL2_BUVDD2V98THRESCOARSE_MASK)
3781                       >> _DEVINFO_VMONCAL2_BUVDD2V98THRESCOARSE_SHIFT))
3782               + ((calReg & _DEVINFO_VMONCAL2_BUVDD2V98THRESFINE_MASK)
3783                  >> _DEVINFO_VMONCAL2_BUVDD2V98THRESFINE_SHIFT);
3784       break;
3785 #endif
3786     default:
3787       EFM_ASSERT(false);
3788       break;
3789   }
3790 
3791   tDiff = tHigh - tLow;
3792   if (tDiff > 0) {
3793     /* Calculate threshold.
3794      *
3795      * Note that volt is used in the reference manual. However, the results
3796      * should be in millivolts. The precision of Va and Vb are increased in the
3797      * calculation instead of using floating points.
3798      */
3799     uint32_t va = (1120U * 100U) / (tDiff);
3800     uint32_t vb = (1860U * 100U) - (va * tLow);
3801     // If (tHigh - tLow) is large, Va could be zero. Caught by CSTAT.
3802     if (va != 0) {
3803       /* Round the threshold to the nearest integer value. */
3804       return (((uint32_t)threshold * 100U) - vb + (va / 2U)) / va;
3805     }
3806   }
3807 
3808   /* Uncalibrated device guard. */
3809   return (uint32_t)threshold;
3810 }
3811 
3812 /***************************************************************************//**
3813  * @brief
3814  *   Initialize a VMON channel.
3815  *
3816  * @details
3817  *   Initialize a VMON channel without hysteresis. If the channel supports
3818  *   separate rise and fall triggers, both thresholds will be set to the same
3819  *   value. The threshold will be converted to a register field value based
3820  *   on calibration values from the DI page.
3821  *
3822  * @param[in] vmonInit
3823  *   The VMON initialization structure.
3824  ******************************************************************************/
EMU_VmonInit(const EMU_VmonInit_TypeDef * vmonInit)3825 void EMU_VmonInit(const EMU_VmonInit_TypeDef *vmonInit)
3826 {
3827   uint32_t thresholdCoarse, thresholdFine;
3828   uint32_t threshold;
3829 
3830   EFM_ASSERT((vmonInit->threshold >= 1620) && (vmonInit->threshold <= 3400));
3831 
3832   threshold = vmonCalibratedThreshold(vmonInit->channel, vmonInit->threshold);
3833   thresholdFine = threshold % 10U;
3834   thresholdCoarse = threshold / 10U;
3835 
3836   /* Saturate the threshold to maximum values. */
3837   if (thresholdCoarse > 0xFU) {
3838     thresholdCoarse = 0xF;
3839     thresholdFine = 9;
3840   }
3841 
3842   switch (vmonInit->channel) {
3843     case emuVmonChannel_AVDD:
3844       EMU->VMONAVDDCTRL = (thresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
3845                           | (thresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
3846                           | (thresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
3847                           | (thresholdFine << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
3848                           | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0U)
3849                           | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0U)
3850                           | (vmonInit->enable     ? EMU_VMONAVDDCTRL_EN     : 0U);
3851       break;
3852     case emuVmonChannel_ALTAVDD:
3853       EMU->VMONALTAVDDCTRL = (thresholdCoarse << _EMU_VMONALTAVDDCTRL_THRESCOARSE_SHIFT)
3854                              | (thresholdFine << _EMU_VMONALTAVDDCTRL_THRESFINE_SHIFT)
3855                              | (vmonInit->riseWakeup ? EMU_VMONALTAVDDCTRL_RISEWU : 0U)
3856                              | (vmonInit->fallWakeup ? EMU_VMONALTAVDDCTRL_FALLWU : 0U)
3857                              | (vmonInit->enable     ? EMU_VMONALTAVDDCTRL_EN     : 0U);
3858       break;
3859     case emuVmonChannel_DVDD:
3860       EMU->VMONDVDDCTRL = (thresholdCoarse << _EMU_VMONDVDDCTRL_THRESCOARSE_SHIFT)
3861                           | (thresholdFine << _EMU_VMONDVDDCTRL_THRESFINE_SHIFT)
3862                           | (vmonInit->riseWakeup ? EMU_VMONDVDDCTRL_RISEWU : 0U)
3863                           | (vmonInit->fallWakeup ? EMU_VMONDVDDCTRL_FALLWU : 0U)
3864                           | (vmonInit->enable     ? EMU_VMONDVDDCTRL_EN     : 0U);
3865       break;
3866     case emuVmonChannel_IOVDD0:
3867       EMU->VMONIO0CTRL = (thresholdCoarse << _EMU_VMONIO0CTRL_THRESCOARSE_SHIFT)
3868                          | (thresholdFine << _EMU_VMONIO0CTRL_THRESFINE_SHIFT)
3869                          | (vmonInit->retDisable ? EMU_VMONIO0CTRL_RETDIS : 0U)
3870                          | (vmonInit->riseWakeup ? EMU_VMONIO0CTRL_RISEWU : 0U)
3871                          | (vmonInit->fallWakeup ? EMU_VMONIO0CTRL_FALLWU : 0U)
3872                          | (vmonInit->enable     ? EMU_VMONIO0CTRL_EN     : 0U);
3873       break;
3874 #if defined(_EMU_VMONIO1CTRL_EN_MASK)
3875     case emuVmonChannel_IOVDD1:
3876       EMU->VMONIO1CTRL = (thresholdCoarse << _EMU_VMONIO1CTRL_THRESCOARSE_SHIFT)
3877                          | (thresholdFine << _EMU_VMONIO1CTRL_THRESFINE_SHIFT)
3878                          | (vmonInit->retDisable ? EMU_VMONIO1CTRL_RETDIS : 0U)
3879                          | (vmonInit->riseWakeup ? EMU_VMONIO1CTRL_RISEWU : 0U)
3880                          | (vmonInit->fallWakeup ? EMU_VMONIO1CTRL_FALLWU : 0U)
3881                          | (vmonInit->enable     ? EMU_VMONIO1CTRL_EN     : 0U);
3882       break;
3883 #endif
3884 #if defined(_EMU_VMONBUVDDCTRL_EN_MASK)
3885     case emuVmonChannel_BUVDD:
3886       EMU->VMONBUVDDCTRL = (thresholdCoarse << _EMU_VMONBUVDDCTRL_THRESCOARSE_SHIFT)
3887                            | (thresholdFine << _EMU_VMONBUVDDCTRL_THRESFINE_SHIFT)
3888                            | (vmonInit->riseWakeup ? EMU_VMONBUVDDCTRL_RISEWU : 0U)
3889                            | (vmonInit->fallWakeup ? EMU_VMONBUVDDCTRL_FALLWU : 0U)
3890                            | (vmonInit->enable     ? EMU_VMONBUVDDCTRL_EN     : 0U);
3891       break;
3892 #endif
3893     default:
3894       EFM_ASSERT(false);
3895       return;
3896   }
3897 }
3898 
3899 /***************************************************************************//**
3900  * @brief
3901  *   Initialize a VMON channel with hysteresis (separate rise and fall triggers).
3902  *
3903  * @details
3904  *   Initialize a VMON channel which supports hysteresis. The AVDD channel is
3905  *   the only channel to support separate rise and fall triggers. The rise and
3906  *   fall thresholds will be converted to a register field value based on the
3907  *   calibration values from the DI page.
3908  *
3909  * @param[in] vmonInit
3910  *   The VMON hysteresis initialization structure.
3911  ******************************************************************************/
EMU_VmonHystInit(const EMU_VmonHystInit_TypeDef * vmonInit)3912 void EMU_VmonHystInit(const EMU_VmonHystInit_TypeDef *vmonInit)
3913 {
3914   uint32_t riseThreshold;
3915   uint32_t fallThreshold;
3916 
3917   /* VMON supports voltages between 1620 mV and 3400 mV (inclusive). */
3918   EFM_ASSERT((vmonInit->riseThreshold >= 1620) && (vmonInit->riseThreshold <= 3400));
3919   EFM_ASSERT((vmonInit->fallThreshold >= 1620) && (vmonInit->fallThreshold <= 3400));
3920   /* The fall threshold has to be lower than rise threshold. */
3921   EFM_ASSERT(vmonInit->fallThreshold <= vmonInit->riseThreshold);
3922 
3923   riseThreshold = vmonCalibratedThreshold(vmonInit->channel, vmonInit->riseThreshold);
3924   fallThreshold = vmonCalibratedThreshold(vmonInit->channel, vmonInit->fallThreshold);
3925 
3926   switch (vmonInit->channel) {
3927     case emuVmonChannel_AVDD:
3928       EMU->VMONAVDDCTRL = ((riseThreshold / 10U) << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
3929                           | ((riseThreshold % 10U) << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
3930                           | ((fallThreshold / 10U) << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
3931                           | ((fallThreshold % 10U) << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
3932                           | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0U)
3933                           | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0U)
3934                           | (vmonInit->enable     ? EMU_VMONAVDDCTRL_EN     : 0U);
3935       break;
3936     default:
3937       EFM_ASSERT(false);
3938       return;
3939   }
3940 }
3941 
3942 /***************************************************************************//**
3943  * @brief
3944  *   Enable or disable a VMON channel.
3945  *
3946  * @param[in] channel
3947  *   A VMON channel to enable/disable.
3948  *
3949  * @param[in] enable
3950  *   Indicates whether to enable or disable.
3951  ******************************************************************************/
EMU_VmonEnable(EMU_VmonChannel_TypeDef channel,bool enable)3952 void EMU_VmonEnable(EMU_VmonChannel_TypeDef channel, bool enable)
3953 {
3954   uint32_t volatile * reg;
3955   uint32_t bit;
3956 
3957   switch (channel) {
3958     case emuVmonChannel_AVDD:
3959       reg = &(EMU->VMONAVDDCTRL);
3960       bit = _EMU_VMONAVDDCTRL_EN_SHIFT;
3961       break;
3962     case emuVmonChannel_ALTAVDD:
3963       reg = &(EMU->VMONALTAVDDCTRL);
3964       bit = _EMU_VMONALTAVDDCTRL_EN_SHIFT;
3965       break;
3966     case emuVmonChannel_DVDD:
3967       reg = &(EMU->VMONDVDDCTRL);
3968       bit = _EMU_VMONDVDDCTRL_EN_SHIFT;
3969       break;
3970     case emuVmonChannel_IOVDD0:
3971       reg = &(EMU->VMONIO0CTRL);
3972       bit = _EMU_VMONIO0CTRL_EN_SHIFT;
3973       break;
3974 #if defined(_EMU_VMONIO1CTRL_EN_MASK)
3975     case emuVmonChannel_IOVDD1:
3976       reg = &(EMU->VMONIO1CTRL);
3977       bit = _EMU_VMONIO1CTRL_EN_SHIFT;
3978       break;
3979 #endif
3980 #if defined(_EMU_VMONBUVDDCTRL_EN_MASK)
3981     case emuVmonChannel_BUVDD:
3982       reg = &(EMU->VMONBUVDDCTRL);
3983       bit = _EMU_VMONBUVDDCTRL_EN_SHIFT;
3984       break;
3985 #endif
3986     default:
3987       EFM_ASSERT(false);
3988       return;
3989   }
3990 
3991   BUS_RegBitWrite(reg, bit, (uint32_t)enable);
3992 }
3993 
3994 /***************************************************************************//**
3995  * @brief
3996  *   Get the status of a voltage monitor channel.
3997  *
3998  * @param[in] channel
3999  *   A VMON channel to get the status for.
4000  *
4001  * @return
4002  *   A status of the selected VMON channel. True if the channel is triggered.
4003  ******************************************************************************/
EMU_VmonChannelStatusGet(EMU_VmonChannel_TypeDef channel)4004 bool EMU_VmonChannelStatusGet(EMU_VmonChannel_TypeDef channel)
4005 {
4006   uint32_t bit;
4007   switch (channel) {
4008     case emuVmonChannel_AVDD:
4009       bit = _EMU_STATUS_VMONAVDD_SHIFT;
4010       break;
4011     case emuVmonChannel_ALTAVDD:
4012       bit = _EMU_STATUS_VMONALTAVDD_SHIFT;
4013       break;
4014     case emuVmonChannel_DVDD:
4015       bit = _EMU_STATUS_VMONDVDD_SHIFT;
4016       break;
4017     case emuVmonChannel_IOVDD0:
4018       bit = _EMU_STATUS_VMONIO0_SHIFT;
4019       break;
4020 #if defined(_EMU_VMONIO1CTRL_EN_MASK)
4021     case emuVmonChannel_IOVDD1:
4022       bit = _EMU_STATUS_VMONIO1_SHIFT;
4023       break;
4024 #endif
4025 #if defined(_EMU_VMONBUVDDCTRL_EN_MASK)
4026     case emuVmonChannel_BUVDD:
4027       bit = _EMU_STATUS_VMONBUVDD_SHIFT;
4028       break;
4029 #endif
4030     default:
4031       bit = 0;
4032       EFM_ASSERT(false);
4033       break;
4034   }
4035 
4036   return BUS_RegBitRead(&EMU->STATUS, bit) != 0U;
4037 }
4038 #endif /* EMU_STATUS_VMONRDY */
4039 
4040 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
4041 /***************************************************************************//**
4042  * @brief
4043  *   Adjust the bias refresh rate.
4044  *
4045  * @details
4046  *   This function is only meant to be used under high-temperature operation on
4047  *   EFR32xG1 and EFM32xG1 devices. Adjusting the bias mode will
4048  *   increase the typical current consumption. See application note 1027
4049  *   and errata documents for more details.
4050  *
4051  * @param [in] mode
4052  *   The new bias refresh rate.
4053  ******************************************************************************/
EMU_SetBiasMode(EMU_BiasMode_TypeDef mode)4054 void EMU_SetBiasMode(EMU_BiasMode_TypeDef mode)
4055 {
4056   uint32_t freq = 0x2u;
4057   bool emuTestLocked = false;
4058 
4059   if (mode == emuBiasMode_1KHz) {
4060     freq = 0x0u;
4061   }
4062 
4063   if (EMU_TESTLOCK == 0x1u) {
4064     emuTestLocked = true;
4065     EMU_TESTLOCK = 0xADE8u;
4066   }
4067 
4068   if (mode == emuBiasMode_Continuous) {
4069     EMU_BIASCONF &= ~0x74u;
4070   } else {
4071     EMU_BIASCONF |= 0x74u;
4072   }
4073 
4074   EMU_BIASTESTCTRL |= 0x8u;
4075   CMU_ULFRCOCTRL    = (CMU_ULFRCOCTRL & ~0xC00u)
4076                       | ((freq & 0x3u) << 10u);
4077   EMU_BIASTESTCTRL &= ~0x8u;
4078 
4079   if (emuTestLocked) {
4080     EMU_TESTLOCK = 0u;
4081   }
4082 }
4083 #endif
4084 
4085 #if defined(_EMU_TEMP_TEMP_MASK)
4086 /***************************************************************************//**
4087  * @brief
4088  *   Get temperature in degrees Celsius
4089  *
4090  * @return
4091  *   Temperature in degrees Celsius
4092  ******************************************************************************/
EMU_TemperatureGet(void)4093 float EMU_TemperatureGet(void)
4094 {
4095 #if defined(_EMU_TEMP_TEMPLSB_MASK)
4096   return ((float) ((EMU->TEMP & (_EMU_TEMP_TEMP_MASK | _EMU_TEMP_TEMPLSB_MASK) )
4097                    >> _EMU_TEMP_TEMPLSB_SHIFT)
4098           ) / 4.0f - EMU_TEMP_ZERO_C_IN_KELVIN;
4099 #else
4100   uint32_t val1;
4101   uint32_t val2;
4102   float tempCo;
4103   uint32_t diTemp, diEmu;
4104 
4105   // Calculate calibration temp based on DI page values
4106   diTemp = ((DEVINFO->CAL & _DEVINFO_CAL_TEMP_MASK) >> _DEVINFO_CAL_TEMP_SHIFT);
4107   diEmu = ((DEVINFO->EMUTEMP & _DEVINFO_EMUTEMP_EMUTEMPROOM_MASK) >> _DEVINFO_EMUTEMP_EMUTEMPROOM_SHIFT);
4108   tempCo = EMU_TEMPCO_CONST + (diEmu / 100.0f);
4109 
4110   // Read temperature twice to ensure a stable value
4111   do {
4112     val1 = (EMU->TEMP & _EMU_TEMP_TEMP_MASK)
4113            >> _EMU_TEMP_TEMP_SHIFT;
4114     val2 = (EMU->TEMP & _EMU_TEMP_TEMP_MASK)
4115            >> _EMU_TEMP_TEMP_SHIFT;
4116   } while (val1 != val2);
4117 
4118   return diTemp + tempCo * ((int) diEmu - (int) val1);
4119 #endif
4120 }
4121 #endif // defined(_EMU_TEMP_TEMP_MASK)
4122 
4123 #if defined(EMU_CTRL_EFPDIRECTMODEEN)
4124 /***************************************************************************//**
4125  * @brief
4126  *   Enable/disable EFP Direct Mode.
4127  *
4128  * @param[in] enable
4129  *   True to enable direct mode.
4130  ******************************************************************************/
EMU_EFPDirectModeEnable(bool enable)4131 void EMU_EFPDirectModeEnable(bool enable)
4132 {
4133   if (enable) {
4134     EMU->CTRL_SET = EMU_CTRL_EFPDIRECTMODEEN;
4135   } else {
4136     EMU->CTRL_CLR = EMU_CTRL_EFPDIRECTMODEEN;
4137   }
4138 }
4139 #endif
4140 
4141 #if defined(EMU_CTRL_EFPDRVDECOUPLE)
4142 /***************************************************************************//**
4143  * @brief
4144  *   Set to enable EFP to drive Decouple voltage.
4145  *
4146  * @details
4147  *   Once set, internal LDO will be disabled, and the EMU will control EFP for
4148  *   voltage-scaling. Note that because this bit disables the internal LDO
4149  *   powering the core, it should not be set until after EFP's DECOUPLE output has
4150  *   been configured and enabled.
4151  *
4152  * @param[in] enable
4153  *   True to enable EFP to drive Decouple voltage.
4154  ******************************************************************************/
EMU_EFPDriveDecoupleSet(bool enable)4155 void EMU_EFPDriveDecoupleSet(bool enable)
4156 {
4157   if (enable) {
4158     EMU->CTRL_SET = EMU_CTRL_EFPDRVDECOUPLE;
4159   } else {
4160     EMU->CTRL_CLR = EMU_CTRL_EFPDRVDECOUPLE;
4161   }
4162 }
4163 #endif
4164 
4165 #if defined(EMU_CTRL_EFPDRVDVDD)
4166 /***************************************************************************//**
4167  * @brief
4168  *   Set to enable EFP to drive DVDD voltage.
4169  *
4170  * @details
4171  *   Set this if EFP's DCDC output is powering DVDD supply. This mode assumes that
4172  *   internal DCDC is not being used.
4173  *
4174  * @param[in] enable
4175  *   True to enable EFP to drive DVDD voltage.
4176  ******************************************************************************/
EMU_EFPDriveDvddSet(bool enable)4177 void EMU_EFPDriveDvddSet(bool enable)
4178 {
4179   if (enable) {
4180     EMU->CTRL_SET = EMU_CTRL_EFPDRVDVDD;
4181   } else {
4182     EMU->CTRL_CLR = EMU_CTRL_EFPDRVDVDD;
4183   }
4184 }
4185 #endif
4186 
4187 /** @} (end addtogroup emu) */
4188 #endif /* __EM_EMU_H */
4189