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