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