1 /***************************************************************************//**
2  * @file
3  * @brief Clock management unit (CMU) 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 #include "em_cmu.h"
31 #if defined(CMU_PRESENT)
32 
33 #include <stddef.h>
34 #include <limits.h>
35 #include "sl_assert.h"
36 #include "em_bus.h"
37 #include "sl_common.h"
38 #include "em_emu.h"
39 #include "em_gpio.h"
40 #include "em_system.h"
41 #if defined(SYSCFG_PRESENT)
42 #include "em_syscfg.h"
43 #endif
44 #include "em_msc.h"
45 
46 /***************************************************************************//**
47  * @addtogroup cmu CMU - Clock Management Unit
48  * @brief Clock management unit (CMU) Peripheral API
49  * @details
50  *  This module contains functions for the CMU peripheral of Silicon Labs 32-bit
51  *  MCUs and SoCs. The CMU module controls oscillators, clocks gates, clock
52  *  multiplexers, pre-scalers, calibration modules and wait-states.
53  * @{
54  ******************************************************************************/
55 #if defined(_SILICON_LABS_32B_SERIES_2)
56 
57 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
58 
59 /*******************************************************************************
60  ******************************   DEFINES   ************************************
61  ******************************************************************************/
62 
63 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
64 // Maximum allowed core frequency vs. wait-states on flash accesses.
65 #define CMU_MAX_FREQ_0WS_1V1              40000000UL
66 
67 #define CMU_MAX_FREQ_0WS_1V0              40000000UL
68 
69 // Maximum allowed core frequency vs. wait-states on sram accesses.
70 #define CMU_MAX_SRAM_FREQ_0WS             50000000UL
71 #define CMU_MAX_SRAM_FREQ_1WS             80000000UL
72 
73 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) \
74   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
75 #define CMU_MAX_FREQ_0WS_1V1              40000000UL
76 
77 #define CMU_MAX_FREQ_0WS_1V0              40000000UL
78 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3) \
79   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)  \
80   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
81 // Maximum allowed core frequency vs. wait-states and vscale on flash accesses.
82 #define CMU_MAX_FREQ_0WS_1V1              40000000UL
83 
84 #define CMU_MAX_FREQ_0WS_1V0              20000000UL
85 #elif (_SILICON_LABS_32B_SERIES_2_CONFIG == 5)
86 #define CMU_MAX_FREQ_0WS_1V1              25000000UL
87 #define CMU_MAX_FREQ_1WS_1V1              50000000UL
88 #define CMU_MAX_FREQ_2WS_1V1              75000000UL
89 #else
90       #warning "MCU flash wait states not supported"
91 #endif
92 
93 // Maximum allowed PCLK frequency.
94 #define CMU_MAX_PCLK_FREQ                 50000000UL
95 
96 // Maximum allowed RHCLK frequency.
97 #define CMU_MAX_RHCLK_FREQ                40000000UL
98 
99 #if defined(EMU_VSCALE_EM01_PRESENT)
100 // This macro is intended to be used as input to CMU_UpdateWaitStates()
101 #define VSCALE_DEFAULT    (2 - (int)EMU_VScaleGet())
102 #else
103 #define VSCALE_DEFAULT    VSCALE_EM01_HIGH_PERFORMANCE
104 #endif
105 
106 #if defined(PLFRCO_PRESENT)
107 // Typical frequency for HFXO as recommanded in the datasheets.
108 // see AN0016: Oscillator Design Considerations
109 //
110 // Recommended for most wireless applications
111 // to meet transceiver electrical specifications
112 #define XTAL_38M4                         38400000UL
113 // Recommended for implementing Z-Wave devices
114 #define XTAL_39M0                         39000000UL
115 // High Precision mode calibration Counts for 38.4MHz
116 #define LFRCO_NOMCAL_XTAL_38M4            _LFRCO_NOMCAL_RESETVALUE
117 #define LFRCO_NOMCALINV_XTAL_38M4         _LFRCO_NOMCALINV_RESETVALUE
118 // High Precision mode calibration Counts for 39.0MHz.
119 #define LFRCO_NOMCAL_XTAL_39M0            0x0005CFBBUL
120 #define LFRCO_NOMCALINV_XTAL_39M0         0x0000581AUL
121 #endif
122 
123 #define PLL0_USB_OUTPUT_FREQ              48000000UL
124 
125 /*******************************************************************************
126  **************************   LOCAL VARIABLES   ********************************
127  ******************************************************************************/
128 
129 // Table of HFRCOCAL values and their associated min/max frequencies and
130 // optional band enumerator.
131 static const struct hfrcoCalTableElement{
132   uint32_t  minFreq;
133   uint32_t  maxFreq;
134   uint32_t  value;
135   CMU_HFRCODPLLFreq_TypeDef band;
136 } hfrcoCalTable[] =
137 {
138   //  minFreq   maxFreq    HFRCOCAL value  band
139   {  900000UL, 1080000UL, 0x82401F00UL, cmuHFRCODPLLFreq_1M0Hz         },
140   { 1080000UL, 1300000UL, 0xA2411F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
141   { 1300000UL, 1530000UL, 0xA2421F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
142   { 1530000UL, 1800000UL, 0xB6439F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
143   { 1800000UL, 2150000UL, 0x81401F00UL, cmuHFRCODPLLFreq_2M0Hz         },
144   { 2150000UL, 2600000UL, 0xA1411F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
145   { 2600000UL, 3050000UL, 0xA1421F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
146   { 3050000UL, 3600000UL, 0xB5439F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
147   { 3600000UL, 4300000UL, 0x80401F00UL, cmuHFRCODPLLFreq_4M0Hz         },
148   { 4300000UL, 5200000UL, 0xA0411F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
149   { 5200000UL, 6100000UL, 0xA0421F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
150   { 6100000UL, 7800000UL, 0xB4439F00UL, cmuHFRCODPLLFreq_7M0Hz         },
151   { 7800000UL, 9800000UL, 0xB4449F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
152   { 9800000UL, 11800000UL, 0xB4459F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0  },
153   { 11800000UL, 14400000UL, 0xB4669F00UL, cmuHFRCODPLLFreq_13M0Hz      },
154   { 14400000UL, 17200000UL, 0xB4679F00UL, cmuHFRCODPLLFreq_16M0Hz      },
155   { 17200000UL, 19700000UL, 0xA8689F00UL, cmuHFRCODPLLFreq_19M0Hz      },
156   { 19700000UL, 23800000UL, 0xB8899F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0 },
157   { 23800000UL, 28700000UL, 0xB88A9F00UL, cmuHFRCODPLLFreq_26M0Hz      },
158   { 28700000UL, 34800000UL, 0xB8AB9F00UL, cmuHFRCODPLLFreq_32M0Hz      },
159   { 34800000UL, 42800000UL, 0xA8CC9F00UL, cmuHFRCODPLLFreq_38M0Hz      },
160   { 42800000UL, 51600000UL, 0xACED9F00UL, cmuHFRCODPLLFreq_48M0Hz      },
161   { 51600000UL, 60500000UL, 0xBCEE9F00UL, cmuHFRCODPLLFreq_56M0Hz      },
162   { 60500000UL, 72600000UL, 0xBCEF9F00UL, cmuHFRCODPLLFreq_64M0Hz      },
163   { 72600000UL, 80000000UL, 0xCCF09F00UL, cmuHFRCODPLLFreq_80M0Hz      },
164 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)
165   { 80000000UL, 100000000UL, 0xCCF19F00UL, cmuHFRCODPLLFreq_100M0Hz   }
166 #endif
167 };
168 
169 static uint16_t lfxo_precision = 0xFFFF;
170 
171 #define HFRCOCALTABLE_ENTRIES (sizeof(hfrcoCalTable) \
172                                / sizeof(struct hfrcoCalTableElement))
173 
174 // CTUNE delta needed for some series 2 chips. This delta is added to the tuning capacitance on XO.
175 // The inter-chip buffered crystal sharing feature added from the EFR32xG23 creates an imbalance
176 // between XI and XO capacitance load internally on the chip. The delta allows to compensate for
177 // the difference.
178 #if defined(_SILICON_LABS_32B_SERIES_2)
179 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)  \
180   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4) \
181   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5) \
182   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
183 static int8_t ctuneDelta = 40; // Recommendation from analog team to counter the internal chip imbalance.
184 #else
185 static int8_t ctuneDelta = 0;
186 #endif
187 #endif
188 
189 /*******************************************************************************
190  **************************   LOCAL PROTOTYPES   *******************************
191  ******************************************************************************/
192 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
193 #if defined(PDM_PRESENT)
194 static void     em01GrpbClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
195 #endif
196 #if defined(EUART_PRESENT)
197 static void     euart0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
198 #endif
199 #if defined(EUSART_PRESENT)
200 static void     eusart0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
201 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
202 static void     em01GrpcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
203 #endif
204 #endif
205 #if defined(LCD_PRESENT)
206 static void     lcdClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
207 #endif
208 #if defined(VDAC_PRESENT)
209 static void     vdac0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
210 #if (VDAC_COUNT > 1)
211 static void     vdac1ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
212 #endif
213 #endif
214 #if defined(PCNT_PRESENT)
215 static void     pcnt0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
216 #endif
217 #if defined(LESENSE_PRESENT)
218 static void     lesenseHFClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
219 #endif
220 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
221   && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
222 static void     rhclkPrescMax(void);
223 static void     rhclkPrescOptimize(void);
224 #endif
225 #endif
226 
227 #if defined(HFRCOEM23_PRESENT)
228 static uint32_t HFRCOEM23DevinfoGet(CMU_HFRCOEM23Freq_TypeDef freq);
229 #endif
230 static void     traceClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
231 static void     dpllRefClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
232 static void     em01GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
233 static void     em23GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
234 static void     em4GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
235 __STATIC_INLINE uint32_t getWaitStatesByFrequencyAndVScale(uint32_t freq, int vscale);
236 static void     flashWaitStateControl(uint32_t coreFreq, int vscale);
237 static uint32_t HFRCODPLLDevinfoGet(CMU_HFRCODPLLFreq_TypeDef freq);
238 #if defined(IADC_PRESENT)
239 static void     iadcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
240 #endif
241 static void     pclkDivMax(void);
242 static void     pclkDivOptimize(void);
243 #if defined(RTCC_PRESENT)
244 static void     rtccClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
245 #elif defined(SYSRTC_PRESENT)
246 static void     sysrtcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
247 #endif
248 static void     waitStateMax(void);
249 static void     wdog0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
250 #if WDOG_COUNT > 1
251 static void     wdog1ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
252 #endif
253 static void     sysTickClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
254 #if defined(USB_PRESENT)
255 static void     usbClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
256 #endif
257 /** @endcond */
258 
259 // The following code is common for all SERIES_2 configurations.
260 
261 /*******************************************************************************
262  **************************   GLOBAL FUNCTIONS   *******************************
263  ******************************************************************************/
264 
265 /***************************************************************************//**
266  * @brief
267  *   Calibrate an oscillator.
268  *
269  * @details
270  *   Run a calibration of a selectable reference clock againt HCLK. Please
271  *   refer to the reference manual, CMU chapter, for further details.
272  *
273  * @note
274  *   This function will not return until calibration measurement is completed.
275  *
276  * @param[in] cycles
277  *   The number of HCLK cycles to run calibration. Increasing this number
278  *   increases precision, but the calibration will take more time.
279  *
280  * @param[in] ref
281  *   The reference clock used to compare against HCLK.
282  *
283  * @return
284  *   The number of ticks the selected reference clock ticked while running
285  *   cycles ticks of the HCLK clock.
286  ******************************************************************************/
CMU_Calibrate(uint32_t cycles,CMU_Select_TypeDef ref)287 uint32_t CMU_Calibrate(uint32_t cycles, CMU_Select_TypeDef ref)
288 {
289   // Check for cycle count overflow
290 #if defined(_CMU_CALCTRL_CALTOP_MASK)
291   EFM_ASSERT(cycles <= (_CMU_CALCTRL_CALTOP_MASK
292                         >> _CMU_CALCTRL_CALTOP_SHIFT));
293 #elif defined(_CMU_CALTOP_CALTOP_MASK)
294   EFM_ASSERT(cycles <= (_CMU_CALTOP_CALTOP_MASK
295                         >> _CMU_CALTOP_CALTOP_SHIFT));
296 #endif
297 
298   CMU_CalibrateConfig(cycles, cmuSelect_HCLK, ref);
299   CMU_CalibrateStart();
300   return CMU_CalibrateCountGet();
301 }
302 
303 /***************************************************************************//**
304  * @brief
305  *   Configure clock calibration.
306  *
307  * @details
308  *   Configure a calibration for a selectable clock source against another
309  *   selectable reference clock.
310  *   Refer to the reference manual, CMU chapter, for further details.
311  *
312  * @note
313  *   After configuration, a call to @ref CMU_CalibrateStart() is required, and
314  *   the resulting calibration value can be read with the
315  *   @ref CMU_CalibrateCountGet() function call.
316  *
317  * @param[in] downCycles
318  *   The number of downSel clock cycles to run calibration. Increasing this
319  *   number increases precision, but the calibration will take more time.
320  *
321  * @param[in] downSel
322  *   The clock which will be counted down downCycles cycles.
323  *
324  * @param[in] upSel
325  *   The reference clock, the number of cycles generated by this clock will
326  *   be counted and added up, the result can be given with the
327  *   @ref CMU_CalibrateCountGet() function call.
328  ******************************************************************************/
CMU_CalibrateConfig(uint32_t downCycles,CMU_Select_TypeDef downSel,CMU_Select_TypeDef upSel)329 void CMU_CalibrateConfig(uint32_t downCycles, CMU_Select_TypeDef downSel,
330                          CMU_Select_TypeDef upSel)
331 {
332   // Keep untouched configuration settings
333   uint32_t calCtrl = CMU->CALCTRL
334                      & ~(_CMU_CALCTRL_UPSEL_MASK
335                          | _CMU_CALCTRL_DOWNSEL_MASK
336 #if defined(_CMU_CALCTRL_CALTOP_MASK)
337                          | _CMU_CALCTRL_CALTOP_MASK
338 #endif
339                          );
340 
341   // Check for cycle count overflow
342 #if defined(_CMU_CALCTRL_CALTOP_MASK)
343   EFM_ASSERT(downCycles <= (_CMU_CALCTRL_CALTOP_MASK
344                             >> _CMU_CALCTRL_CALTOP_SHIFT));
345   calCtrl |= downCycles;
346 #elif defined(_CMU_CALTOP_CALTOP_MASK)
347   EFM_ASSERT(downCycles <= (_CMU_CALTOP_CALTOP_MASK >> _CMU_CALTOP_CALTOP_SHIFT));
348   CMU->CALTOP = downCycles << _CMU_CALTOP_CALTOP_SHIFT;
349 #endif
350 
351   // Set down counting clock source selector
352   switch (downSel) {
353     case cmuSelect_HCLK:
354       calCtrl |= CMU_CALCTRL_DOWNSEL_HCLK;
355       break;
356 
357     case cmuSelect_PRS:
358       calCtrl |= CMU_CALCTRL_DOWNSEL_PRS;
359       break;
360 
361     case cmuSelect_HFXO:
362       calCtrl |= CMU_CALCTRL_DOWNSEL_HFXO;
363       break;
364 
365     case cmuSelect_LFXO:
366       calCtrl |= CMU_CALCTRL_DOWNSEL_LFXO;
367       break;
368 
369     case cmuSelect_HFRCODPLL:
370       calCtrl |= CMU_CALCTRL_DOWNSEL_HFRCODPLL;
371       break;
372 
373 #if defined(HFRCOEM23_PRESENT)
374     case cmuSelect_HFRCOEM23:
375       calCtrl |= CMU_CALCTRL_DOWNSEL_HFRCOEM23;
376       break;
377 #endif
378 
379     case cmuSelect_FSRCO:
380       calCtrl |= CMU_CALCTRL_DOWNSEL_FSRCO;
381       break;
382 
383     case cmuSelect_LFRCO:
384 #if defined(PLFRCO_PRESENT)
385     case cmuSelect_PLFRCO:
386 #endif
387       calCtrl |= CMU_CALCTRL_DOWNSEL_LFRCO;
388       break;
389 
390     case cmuSelect_ULFRCO:
391       calCtrl |= CMU_CALCTRL_DOWNSEL_ULFRCO;
392       break;
393 
394     case cmuSelect_Disabled:
395       break;
396 
397     default:
398       EFM_ASSERT(false);
399       break;
400   }
401 
402   // Set up counting clock source selector
403   switch (upSel) {
404     case cmuSelect_PRS:
405       calCtrl |= CMU_CALCTRL_UPSEL_PRS;
406       break;
407 
408     case cmuSelect_HFXO:
409       calCtrl |= CMU_CALCTRL_UPSEL_HFXO;
410       break;
411 
412     case cmuSelect_LFXO:
413       calCtrl |= CMU_CALCTRL_UPSEL_LFXO;
414       break;
415 
416     case cmuSelect_HFRCODPLL:
417       calCtrl |= CMU_CALCTRL_UPSEL_HFRCODPLL;
418       break;
419 
420 #if defined(HFRCOEM23_PRESENT)
421     case cmuSelect_HFRCOEM23:
422       calCtrl |= CMU_CALCTRL_UPSEL_HFRCOEM23;
423       break;
424 #endif
425 
426     case cmuSelect_FSRCO:
427       calCtrl |= CMU_CALCTRL_UPSEL_FSRCO;
428       break;
429 
430     case cmuSelect_LFRCO:
431 #if defined(PLFRCO_PRESENT)
432     case cmuSelect_PLFRCO:
433 #endif
434       calCtrl |= CMU_CALCTRL_UPSEL_LFRCO;
435       break;
436 
437     case cmuSelect_ULFRCO:
438       calCtrl |= CMU_CALCTRL_UPSEL_ULFRCO;
439       break;
440 
441     case cmuSelect_Disabled:
442       break;
443 
444     default:
445       EFM_ASSERT(false);
446       break;
447   }
448 
449   CMU->CALCTRL = calCtrl;
450 }
451 
452 /***************************************************************************//**
453  * @brief
454  *    Get calibration count value.
455  *
456  * @note
457  *    If continuous calibration mode is active, calibration busy will almost
458  *    always be off, and reading the value will be just needed, where the normal
459  *    case would be that this function call has been triggered by the CALRDY
460  *    interrupt flag.
461  *
462  * @return
463  *    Calibration count, the number of UPSEL clocks (see @ref CMU_CalibrateConfig())
464  *    in the period of DOWNSEL oscillator clock cycles configured by a previous
465  *    write operation to CMU->CALCNT.
466  ******************************************************************************/
CMU_CalibrateCountGet(void)467 uint32_t CMU_CalibrateCountGet(void)
468 {
469   // Wait until calibration completes, UNLESS continuous calibration mode is on
470   if ((CMU->CALCTRL & CMU_CALCTRL_CONT) == 0UL) {
471     // Wait until calibration completes
472     while ((CMU->STATUS & CMU_STATUS_CALRDY) == 0UL) {
473     }
474   }
475   return CMU->CALCNT;
476 }
477 
478 /***************************************************************************//**
479  * @brief
480  *    Direct a clock to a GPIO pin.
481  *
482  * @param[in] clkNo
483  *   Selects between CLKOUT0, CLKOUT1 or CLKOUT2 outputs. Use values 0,1or 2.
484  *
485  * @param[in] sel
486  *   Select clock source.
487  *
488  * @param[in] clkDiv
489  *   Select a clock divisor (1..32). Only applicable when cmuSelect_EXPCLK is
490  *   slexted as clock source.
491  *
492  * @param[in] port
493  *   GPIO port.
494  *
495  * @param[in] pin
496  *   GPIO pin.
497  *
498  * @note
499  *    Refer to the reference manual and the datasheet for details on which
500  *    GPIO port/pins that are available.
501  ******************************************************************************/
CMU_ClkOutPinConfig(uint32_t clkNo,CMU_Select_TypeDef sel,CMU_ClkDiv_TypeDef clkDiv,GPIO_Port_TypeDef port,unsigned int pin)502 void CMU_ClkOutPinConfig(uint32_t           clkNo,
503                          CMU_Select_TypeDef sel,
504                          CMU_ClkDiv_TypeDef clkDiv,
505                          GPIO_Port_TypeDef  port,
506                          unsigned int       pin)
507 {
508   uint32_t tmp = 0U, mask;
509 
510   EFM_ASSERT(clkNo <= 2U);
511   EFM_ASSERT(clkDiv <= 32U);
512   EFM_ASSERT(port <= 3U);
513   EFM_ASSERT(pin <= 15U);
514 
515   switch (sel) {
516     case cmuSelect_Disabled:
517       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_DISABLED;
518       break;
519 
520     case cmuSelect_FSRCO:
521       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_FSRCO;
522       break;
523 
524     case cmuSelect_HFXO:
525       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HFXO;
526       break;
527 
528     case cmuSelect_HFRCODPLL:
529       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HFRCODPLL;
530       break;
531 
532 #if defined(HFRCOEM23_PRESENT)
533     case cmuSelect_HFRCOEM23:
534       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HFRCOEM23;
535       break;
536 #endif
537 
538     case cmuSelect_EXPCLK:
539       tmp  = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HFEXPCLK;
540       break;
541 
542     case cmuSelect_LFXO:
543       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_LFXO;
544       break;
545 
546     case cmuSelect_LFRCO:
547 #if defined(PLFRCO_PRESENT)
548     case cmuSelect_PLFRCO:
549 #endif
550       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_LFRCO;
551       break;
552 
553     case cmuSelect_ULFRCO:
554       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_ULFRCO;
555       break;
556 
557     case cmuSelect_HCLK:
558       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HCLK;
559       break;
560 
561     default:
562       EFM_ASSERT(false);
563       break;
564   }
565 
566   mask  = _CMU_EXPORTCLKCTRL_CLKOUTSEL0_MASK
567           << (clkNo * _CMU_EXPORTCLKCTRL_CLKOUTSEL1_SHIFT);
568   tmp <<= clkNo * _CMU_EXPORTCLKCTRL_CLKOUTSEL1_SHIFT;
569 
570   if (sel == cmuSelect_EXPCLK) {
571     tmp  |= (clkDiv - 1U) << _CMU_EXPORTCLKCTRL_PRESC_SHIFT;
572     mask |= _CMU_EXPORTCLKCTRL_PRESC_MASK;
573   }
574 
575   CMU->EXPORTCLKCTRL = (CMU->EXPORTCLKCTRL & ~mask) | tmp;
576 
577   if (sel == cmuSelect_Disabled) {
578     GPIO->CMUROUTE_CLR.ROUTEEN = GPIO_CMU_ROUTEEN_CLKOUT0PEN << clkNo;
579     GPIO_PinModeSet(port, pin, gpioModeDisabled, 0);
580   } else {
581     GPIO->CMUROUTE_SET.ROUTEEN = GPIO_CMU_ROUTEEN_CLKOUT0PEN << clkNo;
582     if (clkNo == 0U) {
583       GPIO->CMUROUTE.CLKOUT0ROUTE = (port << _GPIO_CMU_CLKOUT0ROUTE_PORT_SHIFT)
584                                     | (pin << _GPIO_CMU_CLKOUT0ROUTE_PIN_SHIFT);
585     } else if (clkNo == 1) {
586       GPIO->CMUROUTE.CLKOUT1ROUTE = (port << _GPIO_CMU_CLKOUT1ROUTE_PORT_SHIFT)
587                                     | (pin << _GPIO_CMU_CLKOUT1ROUTE_PIN_SHIFT);
588     } else {
589       GPIO->CMUROUTE.CLKOUT2ROUTE = (port << _GPIO_CMU_CLKOUT2ROUTE_PORT_SHIFT)
590                                     | (pin << _GPIO_CMU_CLKOUT2ROUTE_PIN_SHIFT);
591     }
592     GPIO_PinModeSet(port, pin, gpioModePushPull, 0);
593   }
594 }
595 
596 /***************************************************************************//**
597  * @brief
598  *   Get clock divisor.
599  *
600  * @param[in] clock
601  *   Clock point to get divisor for. Notice that not all clock points
602  *   have a divisors. Please refer to CMU overview in reference manual.
603  *
604  * @return
605  *   The current clock point divisor. 1 is returned
606  *   if @p clock specifies a clock point without divisor.
607  ******************************************************************************/
CMU_ClockDivGet(CMU_Clock_TypeDef clock)608 CMU_ClkDiv_TypeDef CMU_ClockDivGet(CMU_Clock_TypeDef clock)
609 {
610   uint32_t ret = 0U;
611 
612   switch (clock) {
613     case cmuClock_HCLK:
614     case cmuClock_CORE:
615       ret = (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_HCLKPRESC_MASK)
616             >> _CMU_SYSCLKCTRL_HCLKPRESC_SHIFT;
617 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
618       if (ret == 2U ) {   // Unused value, illegal prescaler
619         EFM_ASSERT(false);
620       }
621 #elif (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
622       if (!((ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV1)
623             || (ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV2)
624             || (ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV4)
625             || (ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV8)
626             || (ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV16))) {
627         // Illegal prescaler
628         EFM_ASSERT(false);
629       }
630 #endif
631       break;
632 
633 #if defined(_CMU_TRACECLKCTRL_PRESC_MASK)
634     case cmuClock_TRACECLK:
635       ret = (CMU->TRACECLKCTRL & _CMU_TRACECLKCTRL_PRESC_MASK)
636             >> _CMU_TRACECLKCTRL_PRESC_SHIFT;
637       if (!((ret == _CMU_TRACECLKCTRL_PRESC_DIV1)
638             || (ret == _CMU_TRACECLKCTRL_PRESC_DIV2)
639 #if defined(_CMU_TRACECLKCTRL_PRESC_DIV3)
640             || (ret == _CMU_TRACECLKCTRL_PRESC_DIV3)
641 #endif
642             || (ret == _CMU_TRACECLKCTRL_PRESC_DIV4))) {
643         // Illegal prescaler
644         EFM_ASSERT(false);
645       }
646       break;
647 #endif
648 
649     case cmuClock_EXPCLK:
650       ret = (CMU->EXPORTCLKCTRL & _CMU_EXPORTCLKCTRL_PRESC_MASK)
651             >> _CMU_EXPORTCLKCTRL_PRESC_SHIFT;
652       break;
653 
654     case cmuClock_PCLK:
655       ret = (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_PCLKPRESC_MASK)
656             >> _CMU_SYSCLKCTRL_PCLKPRESC_SHIFT;
657       break;
658 
659     default:
660       break;
661   }
662   return 1U + ret;
663 }
664 
665 /***************************************************************************//**
666  * @brief
667  *   Set clock divisor.
668  *
669  * @param[in] clock
670  *   Clock point to set divisor for. Notice that not all clock points
671  *   have a divisor, please refer to CMU overview in the reference
672  *   manual.
673  *
674  * @param[in] div
675  *   The clock divisor to use.
676  ******************************************************************************/
CMU_ClockDivSet(CMU_Clock_TypeDef clock,CMU_ClkDiv_TypeDef div)677 void CMU_ClockDivSet(CMU_Clock_TypeDef clock, CMU_ClkDiv_TypeDef div)
678 {
679 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)  \
680   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
681   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
682   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)) \
683   && defined(CoreDebug_DEMCR_TRCENA_Msk)
684   bool restoreTrace;
685 #endif
686 
687   switch (clock) {
688     case cmuClock_HCLK:
689     case cmuClock_CORE:
690 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
691       EFM_ASSERT((div == 1U) || (div == 2U) || (div == 4U));
692 #elif (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
693       EFM_ASSERT((div == 1U) || (div == 2U) || (div == 4U)
694                  || (div == 8U) || (div == 16U));
695 #endif
696 
697       // Set max wait-states and PCLK divisor while changing core clock
698       waitStateMax();
699       pclkDivMax();
700 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
701       && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
702       // Set largest prescaler for radio clock tree
703       rhclkPrescMax();
704 #endif
705 
706       // Set new divisor
707       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_HCLKPRESC_MASK)
708                         | ((div - 1U) << _CMU_SYSCLKCTRL_HCLKPRESC_SHIFT);
709 
710       // Update CMSIS core clock variable and set optimum wait-states
711       CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
712 
713       // Set optimal PCLK divisor
714       pclkDivOptimize();
715 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
716       && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
717       // Set optimal RHCLK prescaler
718       rhclkPrescOptimize();
719 #endif
720       break;
721 
722 #if defined(_CMU_TRACECLKCTRL_PRESC_MASK)
723     case cmuClock_TRACECLK:
724 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)      \
725       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
726       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
727       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)) \
728       && defined(CoreDebug_DEMCR_TRCENA_Msk)
729       restoreTrace = CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk;
730       if (restoreTrace) {
731         CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
732       }
733 #endif
734 #if defined(_CMU_TRACECLKCTRL_PRESC_DIV3)
735       EFM_ASSERT((div == 1U) || (div == 2U) || (div == 3U) || (div == 4U));
736 #else
737       EFM_ASSERT((div == 1U) || (div == 2U) || (div == 4U));
738 #endif
739       CMU->TRACECLKCTRL = (CMU->TRACECLKCTRL & ~_CMU_TRACECLKCTRL_PRESC_MASK)
740                           | ((div - 1U) << _CMU_TRACECLKCTRL_PRESC_SHIFT);
741 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)      \
742       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
743       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
744       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)) \
745       && defined(CoreDebug_DEMCR_TRCENA_Msk)
746       if (restoreTrace) {
747         CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
748       }
749 #endif
750       break;
751 #endif
752 
753     case cmuClock_EXPCLK:
754       EFM_ASSERT((div >= 1U) && (div <= 32U));
755       CMU->EXPORTCLKCTRL = (CMU->EXPORTCLKCTRL & ~_CMU_EXPORTCLKCTRL_PRESC_MASK)
756                            | ((div - 1U) << _CMU_EXPORTCLKCTRL_PRESC_SHIFT);
757       break;
758 
759     case cmuClock_PCLK:
760       EFM_ASSERT((div == 1U) || (div == 2U));
761       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_PCLKPRESC_MASK)
762                         | ((div - 1U) << _CMU_SYSCLKCTRL_PCLKPRESC_SHIFT);
763       break;
764 
765     default:
766       EFM_ASSERT(false);
767       break;
768   }
769 }
770 
771 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
772 /***************************************************************************//**
773  * @brief
774  *   Enable/disable a clock.
775  *
776  * @details
777  *   Module clocks sre disabled after reset. If a module clock is disabled, the
778  *   registers of that module are not accessible and accessing such registers
779  *   will hardfault the Cortex core.
780  *
781  * @param[in] clock
782  *   The clock to enable/disable.
783  *
784  * @param[in] enable
785  *   @li true - enable specified clock.
786  *   @li false - disable specified clock.
787  ******************************************************************************/
CMU_ClockEnable(CMU_Clock_TypeDef clock,bool enable)788 void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
789 {
790   volatile uint32_t *reg = NULL;
791   uint32_t          bit;
792 
793   /* Identify the enable register. */
794   if (((unsigned)clock >> CMU_EN_REG_POS) == CMU_NO_EN_REG) {
795     EFM_ASSERT(false);                      /* No enable for this clock. */
796   } else if (((unsigned)clock >> CMU_EN_REG_POS) == CMU_CLKEN0_EN_REG) {
797     reg = &CMU->CLKEN0;
798   } else if (((unsigned)clock >> CMU_EN_REG_POS) == CMU_CLKEN1_EN_REG) {
799     reg = &CMU->CLKEN1;
800   } else {
801 #if defined(CRYPTOACC_PRESENT)
802     reg = &CMU->CRYPTOACCCLKCTRL;
803 #else
804     // No register to enable clock. Possible hard fault exception.
805     EFM_ASSERT(false);
806 #endif
807   }
808 
809   /* Get the bit position used to enable/disable. */
810   bit = ((unsigned)clock >> CMU_EN_BIT_POS) & CMU_EN_BIT_MASK;
811 
812   /* Set/clear bit as requested. */
813   BUS_RegBitWrite(reg, bit, (uint32_t)enable);
814 }
815 #endif // (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
816 
817 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
818 /***************************************************************************//**
819  * @brief
820  *   Get clock frequency for a clock point.
821  *
822  * @param[in] clock
823  *   Clock point to fetch frequency for.
824  *
825  * @return
826  *   The current frequency in Hz.
827  ******************************************************************************/
CMU_ClockFreqGet(CMU_Clock_TypeDef clock)828 uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
829 {
830   uint32_t ret = 0U;
831 
832   switch (clock) {
833     case cmuClock_SYSCLK:
834       ret = SystemSYSCLKGet();
835       break;
836 
837     case cmuClock_CORE:
838     case cmuClock_HCLK:
839     case cmuClock_LDMA:
840     case cmuClock_GPCRC:
841       ret = SystemHCLKGet();
842       break;
843 
844     case cmuClock_EXPCLK:
845       ret = SystemSYSCLKGet() / CMU_ClockDivGet(cmuClock_EXPCLK);
846       break;
847 
848     case cmuClock_I2C1:
849     case cmuClock_PRS:
850     case cmuClock_PCLK:
851     case cmuClock_GPIO:
852     case cmuClock_USART0:
853     case cmuClock_USART1:
854     case cmuClock_USART2:
855       ret = SystemHCLKGet() / CMU_ClockDivGet(cmuClock_PCLK);
856       break;
857 
858     case cmuClock_I2C0:
859     case cmuClock_LSPCLK:
860       ret = SystemHCLKGet() / CMU_ClockDivGet(cmuClock_PCLK) / 2U;
861       break;
862 
863 #if defined(IADC_PRESENT)
864     case cmuClock_IADC0:
865     case cmuClock_IADCCLK:
866       iadcClkGet(&ret, NULL);
867       break;
868 #endif
869 
870     case cmuClock_TIMER0:
871     case cmuClock_TIMER1:
872     case cmuClock_TIMER2:
873     case cmuClock_TIMER3:
874     case cmuClock_EM01GRPACLK:
875       em01GrpaClkGet(&ret, NULL);
876       break;
877 
878     case cmuClock_SYSTICK:
879       sysTickClkGet(&ret, NULL);
880       break;
881 
882     case cmuClock_LETIMER0:
883     case cmuClock_EM23GRPACLK:
884       em23GrpaClkGet(&ret, NULL);
885       break;
886 
887     case cmuClock_BURTC:
888     case cmuClock_EM4GRPACLK:
889       em4GrpaClkGet(&ret, NULL);
890       break;
891 
892     case cmuClock_WDOG0:
893     case cmuClock_WDOG0CLK:
894       wdog0ClkGet(&ret, NULL);
895       break;
896 
897     case cmuClock_WDOG1:
898     case cmuClock_WDOG1CLK:
899       wdog1ClkGet(&ret, NULL);
900       break;
901 
902     case cmuClock_DPLLREFCLK:
903       dpllRefClkGet(&ret, NULL);
904       break;
905 
906     case cmuClock_TRACECLK:
907       traceClkGet(&ret, NULL);
908       break;
909 
910     case cmuClock_RTCC:
911     case cmuClock_RTCCCLK:
912       rtccClkGet(&ret, NULL);
913       break;
914 
915     default:
916       EFM_ASSERT(false);
917       break;
918   }
919   return ret;
920 }
921 #endif // defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
922 
923 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
924 /***************************************************************************//**
925  * @brief
926  *   Get clock frequency for a clock point.
927  *
928  * @param[in] clock
929  *   Clock point to fetch frequency for.
930  *
931  * @return
932  *   The current frequency in Hz.
933  ******************************************************************************/
CMU_ClockFreqGet(CMU_Clock_TypeDef clock)934 uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
935 {
936   uint32_t ret = 0U;
937   uint32_t freq = 0U;
938 
939   switch (clock) {
940     case cmuClock_SYSCLK:
941       ret = SystemSYSCLKGet();
942       break;
943 
944     case cmuClock_HCLK:
945     case cmuClock_CORE:
946     case cmuClock_ICACHE:
947     case cmuClock_MSC:
948     case cmuClock_LDMA:
949     case cmuClock_SMU:
950 #if defined(RADIOAES_PRESENT)
951     case cmuClock_RADIOAES:
952 #endif
953 #if defined(CRYPTOACC_PRESENT)
954     case cmuClock_CRYPTOACC:
955     case cmuClock_CRYPTOAES:
956     case cmuClock_CRYPTOPK:
957 #endif
958 #if defined(MVP_PRESENT)
959     case cmuClock_MVP:
960 #endif
961       ret = SystemHCLKGet();
962       break;
963 
964     case cmuClock_EXPCLK:
965       ret = SystemSYSCLKGet() / CMU_ClockDivGet(cmuClock_EXPCLK);
966       break;
967 
968     case cmuClock_PCLK:
969 #if defined(USART_PRESENT)
970     case cmuClock_USART0:
971 #if USART_COUNT > 1
972     case cmuClock_USART1:
973 #endif
974 #endif
975     case cmuClock_I2C1:
976     case cmuClock_PRS:
977     case cmuClock_GPIO:
978     case cmuClock_GPCRC:
979     case cmuClock_LDMAXBAR:
980     case cmuClock_SYSCFG:
981     case cmuClock_DCDC:
982     case cmuClock_BURAM:
983     case cmuClock_DPLL0:
984       ret = SystemHCLKGet() / CMU_ClockDivGet(cmuClock_PCLK);
985       break;
986 
987     case cmuClock_LSPCLK:
988     case cmuClock_I2C0:
989     case cmuClock_AMUXCP0:
990 #if defined(ACMP_PRESENT)
991     case cmuClock_ACMP0:
992 #if ACMP_COUNT > 1
993     case cmuClock_ACMP1:
994 #endif
995 #endif
996       ret = SystemHCLKGet() / CMU_ClockDivGet(cmuClock_PCLK) / 2U;
997       break;
998 
999     case cmuClock_TRACECLK:
1000       traceClkGet(&freq, NULL);
1001       ret = freq / CMU_ClockDivGet(cmuClock_TRACECLK);
1002       break;
1003 
1004     case cmuClock_TIMER0:
1005     case cmuClock_TIMER1:
1006     case cmuClock_TIMER2:
1007     case cmuClock_TIMER3:
1008 #if TIMER_COUNT > 4
1009     case cmuClock_TIMER4:
1010 #endif
1011 #if TIMER_COUNT > 7
1012     case cmuClock_TIMER5:
1013     case cmuClock_TIMER6:
1014     case cmuClock_TIMER7:
1015 #endif
1016 #if defined(KEYSCAN_PRESENT)
1017     case cmuClock_KEYSCAN:
1018 #endif
1019     case cmuClock_EM01GRPACLK:
1020       em01GrpaClkGet(&ret, NULL);
1021       break;
1022 #if defined(PDM_PRESENT)
1023     case cmuClock_PDM:
1024     case cmuClock_EM01GRPBCLK:
1025       em01GrpbClkGet(&ret, NULL);
1026       break;
1027 #endif
1028 #if defined(EUART_PRESENT)
1029     case cmuClock_EUART0:
1030     case cmuClock_EUART0CLK:
1031       euart0ClkGet(&ret, NULL);
1032       break;
1033 #endif
1034 #if defined(EUSART_PRESENT) && EUSART_COUNT > 0
1035     case cmuClock_EUSART0:
1036     case cmuClock_EUSART0CLK:
1037       eusart0ClkGet(&ret, NULL);
1038       break;
1039 #if defined(EUSART_PRESENT) && EUSART_COUNT > 1
1040     case cmuClock_EUSART1:
1041 #endif
1042 #if defined(EUSART_PRESENT) && EUSART_COUNT > 2
1043     case cmuClock_EUSART2:
1044 #endif
1045 #if defined(EUSART_PRESENT) && EUSART_COUNT > 3
1046     case cmuClock_EUSART3:
1047 #endif
1048 #if defined(EUSART_PRESENT) && EUSART_COUNT > 4
1049     case cmuClock_EUSART4:
1050 #endif
1051 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
1052     case cmuClock_EM01GRPCCLK:
1053       em01GrpcClkGet(&ret, NULL);
1054       break;
1055 #endif
1056 #endif
1057 
1058 #if defined(IADC_PRESENT)
1059     case cmuClock_IADC0:
1060     case cmuClock_IADCCLK:
1061       iadcClkGet(&ret, NULL);
1062       break;
1063 #endif
1064 
1065     case cmuClock_SYSTICK:
1066       sysTickClkGet(&ret, NULL);
1067       break;
1068 
1069     case cmuClock_LETIMER0:
1070     case cmuClock_EM23GRPACLK:
1071 #if defined(LESENSE_PRESENT)
1072     case cmuClock_LESENSE:
1073     case cmuClock_LESENSECLK:
1074 #endif
1075       em23GrpaClkGet(&ret, NULL);
1076       break;
1077 
1078     case cmuClock_WDOG0:
1079     case cmuClock_WDOG0CLK:
1080       wdog0ClkGet(&ret, NULL);
1081       break;
1082 #if WDOG_COUNT > 1
1083     case cmuClock_WDOG1:
1084     case cmuClock_WDOG1CLK:
1085       wdog1ClkGet(&ret, NULL);
1086       break;
1087 #endif
1088 #if defined(RTCC_PRESENT)
1089     case cmuClock_RTCC:
1090     case cmuClock_RTCCCLK:
1091       rtccClkGet(&ret, NULL);
1092       break;
1093 #endif
1094 #if defined(SYSRTC_PRESENT)
1095     case cmuClock_SYSRTC:
1096     case cmuClock_SYSRTCCLK:
1097       sysrtcClkGet(&ret, NULL);
1098       break;
1099 #endif
1100 #if defined(LCD_PRESENT)
1101     case cmuClock_LCD:
1102     case cmuClock_LCDCLK:
1103       lcdClkGet(&ret, NULL);
1104       break;
1105 #endif
1106 #if defined(VDAC_PRESENT)
1107     case cmuClock_VDAC0:
1108     case cmuClock_VDAC0CLK:
1109       vdac0ClkGet(&ret, NULL);
1110       break;
1111 #if (VDAC_COUNT > 1)
1112     case cmuClock_VDAC1:
1113     case cmuClock_VDAC1CLK:
1114       vdac1ClkGet(&ret, NULL);
1115       break;
1116 #endif
1117 #endif /* VDAC_PRESENT */
1118 #if defined(PCNT_PRESENT)
1119     case cmuClock_PCNT0:
1120     case cmuClock_PCNT0CLK:
1121       pcnt0ClkGet(&ret, NULL);
1122       break;
1123 #endif
1124 #if defined(LESENSE_PRESENT)
1125     case cmuClock_LESENSEHFCLK:
1126       lesenseHFClkGet(&ret, NULL);
1127       break;
1128 #endif
1129     case cmuClock_BURTC:
1130     case cmuClock_EM4GRPACLK:
1131 #if defined(ETAMPDET_PRESENT)
1132     case cmuClock_ETAMPDET:
1133 #endif
1134       em4GrpaClkGet(&ret, NULL);
1135       break;
1136 
1137 #if defined(USB_PRESENT)
1138     case cmuClock_USB:
1139       usbClkGet(&ret, NULL);
1140       break;
1141 #endif
1142 
1143     default:
1144       EFM_ASSERT(false);
1145       break;
1146   }
1147 
1148   return ret;
1149 }
1150 #endif // (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
1151 
1152 /***************************************************************************//**
1153  * @brief
1154  *   Get currently selected reference clock used for a clock branch.
1155  *
1156  * @param[in] clock
1157  *   Clock branch to fetch selected ref. clock for.
1158  *
1159  * @return
1160  *   Reference clock used for clocking selected branch, #cmuSelect_Error if
1161  *   invalid @p clock provided.
1162  ******************************************************************************/
CMU_ClockSelectGet(CMU_Clock_TypeDef clock)1163 CMU_Select_TypeDef CMU_ClockSelectGet(CMU_Clock_TypeDef clock)
1164 {
1165   CMU_Select_TypeDef ret = cmuSelect_Error;
1166 
1167   switch (clock) {
1168 // -----------------------------------------------------------------------------
1169     case cmuClock_SYSCLK:
1170       switch (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_CLKSEL_MASK) {
1171         case CMU_SYSCLKCTRL_CLKSEL_HFRCODPLL:
1172           ret = cmuSelect_HFRCODPLL;
1173           break;
1174 
1175         case CMU_SYSCLKCTRL_CLKSEL_HFXO:
1176           ret = cmuSelect_HFXO;
1177           break;
1178 
1179         case CMU_SYSCLKCTRL_CLKSEL_CLKIN0:
1180           ret = cmuSelect_CLKIN0;
1181           break;
1182 
1183         case CMU_SYSCLKCTRL_CLKSEL_FSRCO:
1184           ret = cmuSelect_FSRCO;
1185           break;
1186 
1187 #if defined(RFFPLL_PRESENT)
1188         case CMU_SYSCLKCTRL_CLKSEL_RFFPLL0SYS:
1189           ret = cmuSelect_RFFPLLSYS;
1190           break;
1191 #endif
1192         default:
1193           ret = cmuSelect_Error;
1194           EFM_ASSERT(false);
1195           break;
1196       }
1197       break;
1198 
1199 // -----------------------------------------------------------------------------
1200 #if defined(IADC_PRESENT)
1201     case cmuClock_IADC0:
1202     case cmuClock_IADCCLK:
1203       iadcClkGet(NULL, &ret);
1204       break;
1205 #endif
1206 // -----------------------------------------------------------------------------
1207     case cmuClock_TIMER0:
1208     case cmuClock_TIMER1:
1209     case cmuClock_TIMER2:
1210     case cmuClock_TIMER3:
1211 #if TIMER_COUNT > 4
1212     case cmuClock_TIMER4:
1213 #endif
1214 #if TIMER_COUNT > 7
1215     case cmuClock_TIMER5:
1216     case cmuClock_TIMER6:
1217     case cmuClock_TIMER7:
1218 #endif
1219 #if defined(KEYSCAN_PRESENT)
1220     case cmuClock_KEYSCAN:
1221 #endif
1222     case cmuClock_EM01GRPACLK:
1223       em01GrpaClkGet(NULL, &ret);
1224       break;
1225 
1226 // -----------------------------------------------------------------------------
1227     case cmuClock_SYSTICK:
1228       sysTickClkGet(NULL, &ret);
1229       break;
1230 
1231     case cmuClock_LETIMER0:
1232     case cmuClock_EM23GRPACLK:
1233 #if defined(LESENSE_PRESENT)
1234     case cmuClock_LESENSE:
1235     case cmuClock_LESENSECLK:
1236 #endif
1237       em23GrpaClkGet(NULL, &ret);
1238       break;
1239 
1240 // -----------------------------------------------------------------------------
1241     case cmuClock_BURTC:
1242     case cmuClock_EM4GRPACLK:
1243 #if defined(ETAMPDET_PRESENT)
1244     case cmuClock_ETAMPDET:
1245 #endif
1246       em4GrpaClkGet(NULL, &ret);
1247       break;
1248 
1249 // -----------------------------------------------------------------------------
1250 #if defined(_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK)
1251     case cmuClock_PDMREF:
1252     case cmuClock_EM01GRPBCLK:
1253       em01GrpbClkGet(NULL, &ret);
1254       break;
1255 #endif
1256 
1257 // -----------------------------------------------------------------------------
1258     case cmuClock_WDOG0:
1259     case cmuClock_WDOG0CLK:
1260       wdog0ClkGet(NULL, &ret);
1261       break;
1262 
1263 // -----------------------------------------------------------------------------
1264 #if defined(_CMU_WDOG1CLKCTRL_CLKSEL_MASK)
1265     case cmuClock_WDOG1:
1266     case cmuClock_WDOG1CLK:
1267       wdog1ClkGet(NULL, &ret);
1268       break;
1269 #endif
1270 
1271 // -----------------------------------------------------------------------------
1272     case cmuClock_DPLLREFCLK:
1273       dpllRefClkGet(NULL, &ret);
1274       break;
1275 
1276 // -----------------------------------------------------------------------------
1277 #if defined(_CMU_TRACECLKCTRL_CLKSEL_MASK)
1278     case cmuClock_TRACECLK:
1279       traceClkGet(NULL, &ret);
1280       break;
1281 #endif
1282 
1283 // -----------------------------------------------------------------------------
1284 #if defined(_CMU_EUART0CLKCTRL_CLKSEL_MASK)
1285     case cmuClock_EUART0:
1286     case cmuClock_EUART0CLK:
1287       euart0ClkGet(NULL, &ret);
1288       break;
1289 #elif defined(EUSART_PRESENT)
1290     case cmuClock_EUSART0:
1291     case cmuClock_EUSART0CLK:
1292       eusart0ClkGet(NULL, &ret);
1293       break;
1294 
1295 #if defined(EUSART_PRESENT) && EUSART_COUNT > 1
1296     case cmuClock_EUSART1:
1297 #endif
1298 #if defined(EUSART_PRESENT) && EUSART_COUNT > 2
1299     case cmuClock_EUSART2:
1300 #endif
1301 #if defined(EUSART_PRESENT) && EUSART_COUNT > 3
1302     case cmuClock_EUSART3:
1303 #endif
1304 #if defined(EUSART_PRESENT) && EUSART_COUNT > 4
1305     case cmuClock_EUSART4:
1306 #endif
1307 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
1308     case cmuClock_EM01GRPCCLK:
1309       em01GrpcClkGet(NULL, &ret);
1310       break;
1311 #endif
1312  #endif
1313 
1314 // -----------------------------------------------------------------------------
1315 #if defined(RTCC_PRESENT)
1316     case cmuClock_RTCC:
1317     case cmuClock_RTCCCLK:
1318       rtccClkGet(NULL, &ret);
1319       break;
1320 #endif
1321 // -----------------------------------------------------------------------------
1322 #if defined(SYSRTC_PRESENT)
1323     case cmuClock_SYSRTC:
1324     case cmuClock_SYSRTCCLK:
1325       sysrtcClkGet(NULL, &ret);
1326       break;
1327 #endif
1328 // -----------------------------------------------------------------------------
1329 #if defined(LCD_PRESENT)
1330     case cmuClock_LCD:
1331     case cmuClock_LCDCLK:
1332       lcdClkGet(NULL, &ret);
1333       break;
1334 #endif
1335 // -----------------------------------------------------------------------------
1336 #if defined(VDAC_PRESENT)
1337     case cmuClock_VDAC0:
1338     case cmuClock_VDAC0CLK:
1339       vdac0ClkGet(NULL, &ret);
1340       break;
1341 #if (VDAC_COUNT > 1)
1342     case cmuClock_VDAC1:
1343     case cmuClock_VDAC1CLK:
1344       vdac1ClkGet(NULL, &ret);
1345       break;
1346 #endif
1347 #endif
1348 // -----------------------------------------------------------------------------
1349 #if defined(PCNT_PRESENT)
1350     case cmuClock_PCNT0:
1351     case cmuClock_PCNT0CLK:
1352       pcnt0ClkGet(NULL, &ret);
1353       break;
1354 #endif
1355 // -----------------------------------------------------------------------------
1356 #if defined(LESENSE_PRESENT)
1357     case cmuClock_LESENSEHFCLK:
1358       lesenseHFClkGet(NULL, &ret);
1359       break;
1360 #endif
1361 // -----------------------------------------------------------------------------
1362 #if defined(USB_PRESENT)
1363     case cmuClock_USB:
1364       usbClkGet(NULL, &ret);
1365       break;
1366 #endif
1367 // -----------------------------------------------------------------------------
1368     default:
1369       EFM_ASSERT(false);
1370       break;
1371   }
1372   return ret;
1373 }
1374 
1375 /***************************************************************************//**
1376  * @brief Performs pre-clock-selection operations to initialize the system clock.
1377  *
1378  * @note FOR INTERNAL USE ONLY.
1379  *
1380  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1381  *       the clock is SYSCLK.
1382  ******************************************************************************/
sli_em_cmu_SYSCLKInitPreClockSelect(void)1383 void sli_em_cmu_SYSCLKInitPreClockSelect(void)
1384 {
1385 #if defined(EMU_VSCALE_EM01_PRESENT)
1386   // VSCALE up before changing clock.
1387   EMU_VScaleEM01(emuVScaleEM01_HighPerformance, true);
1388 #endif
1389 
1390   // Set max wait-states and PCLK divisor while changing core clock.
1391   waitStateMax();
1392   pclkDivMax();
1393 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
1394   && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
1395   // Set largest prescaler for radio clock tree
1396   rhclkPrescMax();
1397 #endif
1398 }
1399 
1400 /***************************************************************************//**
1401  * @brief Performs post-clock-selection operations to initialize the system clock.
1402  *
1403  * @note FOR INTERNAL USE ONLY.
1404  *
1405  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1406  *       the clock is SYSCLK.
1407  ******************************************************************************/
sli_em_cmu_SYSCLKInitPostClockSelect(void)1408 void sli_em_cmu_SYSCLKInitPostClockSelect(void)
1409 {
1410   // Update CMSIS core clock variable and set optimum wait-states.
1411   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
1412 
1413 #if defined(EMU_VSCALE_EM01_PRESENT)
1414   // Check if possible to downscale VSCALE setting.
1415   EMU_VScaleEM01ByClock(0, true);
1416 #endif
1417 
1418   // Set optimal PCLK divisor
1419   pclkDivOptimize();
1420 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
1421   && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
1422   // Set optimal RHCLK prescaler
1423   rhclkPrescOptimize();
1424 #endif
1425 }
1426 
1427 /***************************************************************************//**
1428  * @brief Sets the HFXO0 FORCEEN bit.
1429  *
1430  * @note FOR INTERNAL USE ONLY.
1431  *
1432  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1433  *       the clock is SYSCLK and the selected clock source is HFXO.
1434  ******************************************************************************/
sli_em_cmu_HFXOSetForceEnable(void)1435 void sli_em_cmu_HFXOSetForceEnable(void)
1436 {
1437 #if defined(_CMU_CLKEN0_MASK) && defined(CMU_CLKEN0_HFXO0)
1438   CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
1439 #endif
1440   HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
1441 }
1442 
1443 /***************************************************************************//**
1444  * @brief This function will set the SYSCFG->CFGSYSTIC<SYSTICEXTCLKEN> bit.
1445  *
1446  * @note FOR INTERNAL USE ONLY.
1447  *
1448  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1449  *       the clock is SYSTICK.
1450  ******************************************************************************/
sli_em_cmu_SYSTICEXTCLKENSet(void)1451 void sli_em_cmu_SYSTICEXTCLKENSet(void)
1452 {
1453 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1454   bool syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
1455   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1456 #endif
1457 
1458   SYSCFG_setSysTicExtClkEnCfgSysTic();
1459 
1460 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1461   if (syscfgClkIsOff) {
1462     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
1463   }
1464 #endif
1465 }
1466 
1467 /***************************************************************************//**
1468  * @brief This function will clear the SYSCFG->CFGSYSTIC<SYSTICEXTCLKEN> bit.
1469  *
1470  * @note FOR INTERNAL USE ONLY.
1471  *
1472  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1473  *       the clock is SYSTICK.
1474  ******************************************************************************/
sli_em_cmu_SYSTICEXTCLKENClear(void)1475 void sli_em_cmu_SYSTICEXTCLKENClear(void)
1476 {
1477 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1478   bool syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
1479   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1480 #endif
1481 
1482   SYSCFG_clearSysTicExtClkEnCfgSysTic();
1483 
1484 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1485   if (syscfgClkIsOff) {
1486     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
1487   }
1488 #endif
1489 }
1490 
1491 /***************************************************************************//**
1492  * @brief
1493  *   Select reference clock/oscillator used for a clock branch.
1494  *
1495  * @param[in] clock
1496  *   Clock branch to select reference clock for.
1497  *
1498  * @param[in] ref
1499  *   Reference selected for clocking, please refer to reference manual for
1500  *   for details on which reference is available for a specific clock branch.
1501  ******************************************************************************/
CMU_ClockSelectSet(CMU_Clock_TypeDef clock,CMU_Select_TypeDef ref)1502 void CMU_ClockSelectSet(CMU_Clock_TypeDef clock, CMU_Select_TypeDef ref)
1503 {
1504   uint32_t tmp = 0U;
1505   bool oscForceEnStatus = false;
1506 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
1507   bool syscfgClkIsOff = false;
1508 #endif
1509 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)  \
1510   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
1511   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
1512   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)) \
1513   && defined(CoreDebug_DEMCR_TRCENA_Msk)
1514   bool restoreTrace;
1515 #endif
1516 
1517   switch (clock) {
1518 // -----------------------------------------------------------------------------
1519     case cmuClock_SYSCLK:
1520       switch (ref) {
1521         case cmuSelect_HFRCODPLL:
1522           tmp = CMU_SYSCLKCTRL_CLKSEL_HFRCODPLL;
1523           break;
1524 
1525         case cmuSelect_HFXO:
1526           tmp = CMU_SYSCLKCTRL_CLKSEL_HFXO;
1527 #if defined(_CMU_CLKEN0_MASK)
1528 #if defined(CMU_CLKEN0_HFXO0)
1529           CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
1530 #endif
1531 #endif
1532           // Make sure HFXO is enabled.
1533           oscForceEnStatus = (HFXO0->CTRL & HFXO_CTRL_DISONDEMAND) != 0;
1534           HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
1535           break;
1536 
1537         case cmuSelect_CLKIN0:
1538           tmp = CMU_SYSCLKCTRL_CLKSEL_CLKIN0;
1539           break;
1540 
1541         case cmuSelect_FSRCO:
1542           tmp = CMU_SYSCLKCTRL_CLKSEL_FSRCO;
1543           break;
1544 
1545 #if defined(RFFPLL_PRESENT)
1546         case cmuSelect_RFFPLLSYS:
1547           tmp = CMU_SYSCLKCTRL_CLKSEL_RFFPLL0SYS;
1548           break;
1549 #endif
1550 
1551         default:
1552           EFM_ASSERT(false);
1553           break;
1554       }
1555 
1556 #if defined(EMU_VSCALE_EM01_PRESENT)
1557       // VSCALE up before changing clock.
1558       EMU_VScaleEM01(emuVScaleEM01_HighPerformance, true);
1559 #endif
1560 
1561       // Set max wait-states and PCLK divisor while changing core clock.
1562       waitStateMax();
1563       pclkDivMax();
1564 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
1565       && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
1566       // Set largest prescaler for radio clock tree
1567       rhclkPrescMax();
1568 #endif
1569 
1570       // Switch to selected oscillator.
1571       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | tmp;
1572 
1573       // Update CMSIS core clock variable and set optimum wait-states.
1574       CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
1575 
1576 #if defined(EMU_VSCALE_EM01_PRESENT)
1577       // Check if possible to downscale VSCALE setting.
1578       EMU_VScaleEM01ByClock(0, true);
1579 #endif
1580 
1581       // Set optimal PCLK divisor
1582       pclkDivOptimize();
1583 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
1584       && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
1585       // Set optimal RHCLK prescaler
1586       rhclkPrescOptimize();
1587 #endif
1588 
1589       if (oscForceEnStatus == false) {
1590         switch (ref) {
1591           case cmuSelect_HFXO:
1592             HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
1593             break;
1594 
1595           default:
1596             break;
1597         }
1598       }
1599       break;
1600 
1601 // -----------------------------------------------------------------------------
1602 #if defined(IADC_PRESENT)
1603     case cmuClock_IADC0:
1604     case cmuClock_IADCCLK:
1605       switch (ref) {
1606         case cmuSelect_EM01GRPACLK:
1607           tmp = CMU_IADCCLKCTRL_CLKSEL_EM01GRPACLK;
1608           break;
1609 
1610 #if defined(HFRCOEM23_PRESENT)
1611         case cmuSelect_HFRCOEM23:
1612           tmp = CMU_IADCCLKCTRL_CLKSEL_HFRCOEM23;
1613           break;
1614 #endif
1615 
1616         case cmuSelect_FSRCO:
1617           tmp = CMU_IADCCLKCTRL_CLKSEL_FSRCO;
1618           break;
1619 
1620         default:
1621           EFM_ASSERT(false);
1622           break;
1623       }
1624       CMU->IADCCLKCTRL = (CMU->IADCCLKCTRL & ~_CMU_IADCCLKCTRL_CLKSEL_MASK)
1625                          | tmp;
1626       break;
1627 #endif
1628 
1629 // -----------------------------------------------------------------------------
1630     case cmuClock_TIMER0:
1631     case cmuClock_TIMER1:
1632     case cmuClock_TIMER2:
1633     case cmuClock_TIMER3:
1634 #if TIMER_COUNT > 4
1635     case cmuClock_TIMER4:
1636 #endif
1637 #if TIMER_COUNT > 7
1638     case cmuClock_TIMER5:
1639     case cmuClock_TIMER6:
1640     case cmuClock_TIMER7:
1641 #endif
1642 #if defined(KEYSCAN_PRESENT)
1643     case cmuClock_KEYSCAN:
1644 #endif
1645     case cmuClock_EM01GRPACLK:
1646       switch (ref) {
1647         case cmuSelect_HFRCODPLL:
1648           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLL;
1649           break;
1650 
1651         case cmuSelect_HFXO:
1652           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFXO;
1653           break;
1654 
1655 #if defined(HFRCOEM23_PRESENT)
1656         case cmuSelect_HFRCOEM23:
1657           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFRCOEM23;
1658           break;
1659 #endif
1660 
1661         case cmuSelect_FSRCO:
1662           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_FSRCO;
1663           break;
1664 
1665 #if defined(CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLLRT)
1666         case cmuSelect_HFRCODPLLRT:
1667           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLLRT;
1668           break;
1669 #endif
1670 #if defined(CMU_EM01GRPACLKCTRL_CLKSEL_HFXORT)
1671         case cmuSelect_HFXORT:
1672           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFXORT;
1673           break;
1674 #endif
1675         default:
1676           EFM_ASSERT(false);
1677           break;
1678       }
1679       CMU->EM01GRPACLKCTRL = (CMU->EM01GRPACLKCTRL
1680                               & ~_CMU_EM01GRPACLKCTRL_CLKSEL_MASK) | tmp;
1681       break;
1682 
1683 // -----------------------------------------------------------------------------
1684     case cmuClock_SYSTICK:
1685       switch (ref) {
1686         case cmuSelect_EM23GRPACLK:
1687         case cmuSelect_LFXO:
1688         case cmuSelect_LFRCO:
1689         case cmuSelect_ULFRCO:
1690 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1691           SYSCFG_setSysTicExtClkEnCfgSysTic();
1692 #else
1693           syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
1694           CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1695           SYSCFG_setSysTicExtClkEnCfgSysTic();
1696           if (syscfgClkIsOff) {
1697             CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
1698           }
1699 #endif
1700           SysTick->CTRL = (SysTick->CTRL & ~SysTick_CTRL_CLKSOURCE_Msk);
1701           break;
1702         case cmuSelect_HCLK:
1703 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1704           SYSCFG_clearSysTicExtClkEnCfgSysTic();
1705 #else
1706           syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
1707           CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1708           SYSCFG_clearSysTicExtClkEnCfgSysTic();
1709           if (syscfgClkIsOff) {
1710             CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
1711           }
1712 #endif
1713           SysTick->CTRL = (SysTick->CTRL | SysTick_CTRL_CLKSOURCE_Msk);
1714           break;
1715         default:
1716           EFM_ASSERT(false);
1717           break;
1718       }
1719       break;
1720 
1721     case cmuClock_LETIMER0:
1722     case cmuClock_EM23GRPACLK:
1723 #if defined(LESENSE_PRESENT)
1724     case cmuClock_LESENSE:
1725     case cmuClock_LESENSECLK:
1726 #endif
1727       switch (ref) {
1728         case cmuSelect_LFRCO:
1729 #if defined(PLFRCO_PRESENT)
1730         case cmuSelect_PLFRCO:
1731 #endif
1732           tmp = CMU_EM23GRPACLKCTRL_CLKSEL_LFRCO;
1733           break;
1734 
1735         case cmuSelect_LFXO:
1736           tmp = CMU_EM23GRPACLKCTRL_CLKSEL_LFXO;
1737           break;
1738 
1739         case cmuSelect_ULFRCO:
1740           tmp = CMU_EM23GRPACLKCTRL_CLKSEL_ULFRCO;
1741           break;
1742 
1743         default:
1744           EFM_ASSERT(false);
1745           break;
1746       }
1747       CMU->EM23GRPACLKCTRL = (CMU->EM23GRPACLKCTRL
1748                               & ~_CMU_EM23GRPACLKCTRL_CLKSEL_MASK) | tmp;
1749       break;
1750 
1751 // -----------------------------------------------------------------------------
1752     case cmuClock_BURTC:
1753 #if defined(ETAMPDET_PRESENT)
1754     case cmuClock_ETAMPDET:
1755 #endif
1756     case cmuClock_EM4GRPACLK:
1757       switch (ref) {
1758         case cmuSelect_LFRCO:
1759 #if defined(PLFRCO_PRESENT)
1760         case cmuSelect_PLFRCO:
1761 #endif
1762           tmp = CMU_EM4GRPACLKCTRL_CLKSEL_LFRCO;
1763           break;
1764 
1765         case cmuSelect_LFXO:
1766           tmp = CMU_EM4GRPACLKCTRL_CLKSEL_LFXO;
1767           break;
1768 
1769         case cmuSelect_ULFRCO:
1770           tmp = CMU_EM4GRPACLKCTRL_CLKSEL_ULFRCO;
1771           break;
1772 
1773         default:
1774           EFM_ASSERT(false);
1775           break;
1776       }
1777       CMU->EM4GRPACLKCTRL = (CMU->EM4GRPACLKCTRL
1778                              & ~_CMU_EM4GRPACLKCTRL_CLKSEL_MASK) | tmp;
1779       break;
1780 
1781 #if defined(_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK)
1782 // -----------------------------------------------------------------------------
1783     case cmuClock_PDMREF:
1784     case cmuClock_EM01GRPBCLK:
1785       switch (ref) {
1786         case cmuSelect_HFRCODPLL:
1787           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_HFRCODPLL;
1788           break;
1789 
1790         case cmuSelect_HFXO:
1791           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO;
1792           break;
1793 
1794         case cmuSelect_FSRCO:
1795           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_FSRCO;
1796           break;
1797 
1798         case cmuSelect_CLKIN0:
1799           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_CLKIN0;
1800           break;
1801 
1802         case cmuSelect_HFRCODPLLRT:
1803           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_HFRCODPLLRT;
1804           break;
1805 
1806         case cmuSelect_HFXORT:
1807           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_HFXORT;
1808           break;
1809 
1810         default:
1811           EFM_ASSERT(false);
1812           break;
1813       }
1814       CMU->EM01GRPBCLKCTRL = (CMU->EM01GRPBCLKCTRL
1815                               & ~_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK) | tmp;
1816       break;
1817 #endif
1818 
1819 // -----------------------------------------------------------------------------
1820     case cmuClock_WDOG0:
1821     case cmuClock_WDOG0CLK:
1822       switch (ref) {
1823         case cmuSelect_LFRCO:
1824 #if defined(PLFRCO_PRESENT)
1825         case cmuSelect_PLFRCO:
1826 #endif
1827           tmp = CMU_WDOG0CLKCTRL_CLKSEL_LFRCO;
1828           break;
1829 
1830         case cmuSelect_LFXO:
1831           tmp = CMU_WDOG0CLKCTRL_CLKSEL_LFXO;
1832           break;
1833 
1834         case cmuSelect_ULFRCO:
1835           tmp = CMU_WDOG0CLKCTRL_CLKSEL_ULFRCO;
1836           break;
1837 
1838         case cmuSelect_HCLKDIV1024:
1839           tmp = CMU_WDOG0CLKCTRL_CLKSEL_HCLKDIV1024;
1840           break;
1841 
1842         default:
1843           EFM_ASSERT(false);
1844           break;
1845       }
1846       CMU->WDOG0CLKCTRL = (CMU->WDOG0CLKCTRL & ~_CMU_WDOG0CLKCTRL_CLKSEL_MASK)
1847                           | tmp;
1848       break;
1849 
1850 #if defined(_CMU_WDOG1CLKCTRL_CLKSEL_MASK)
1851 // -----------------------------------------------------------------------------
1852     case cmuClock_WDOG1:
1853     case cmuClock_WDOG1CLK:
1854       switch (ref) {
1855         case cmuSelect_LFRCO:
1856 #if defined(PLFRCO_PRESENT)
1857         case cmuSelect_PLFRCO:
1858 #endif
1859           tmp = CMU_WDOG1CLKCTRL_CLKSEL_LFRCO;
1860           break;
1861 
1862         case cmuSelect_LFXO:
1863           tmp = CMU_WDOG1CLKCTRL_CLKSEL_LFXO;
1864           break;
1865 
1866         case cmuSelect_ULFRCO:
1867           tmp = CMU_WDOG1CLKCTRL_CLKSEL_ULFRCO;
1868           break;
1869 
1870         case cmuSelect_HCLKDIV1024:
1871           tmp = CMU_WDOG1CLKCTRL_CLKSEL_HCLKDIV1024;
1872           break;
1873 
1874         default:
1875           EFM_ASSERT(false);
1876           break;
1877       }
1878       CMU->WDOG1CLKCTRL = (CMU->WDOG1CLKCTRL & ~_CMU_WDOG1CLKCTRL_CLKSEL_MASK)
1879                           | tmp;
1880       break;
1881 #endif
1882 
1883 // -----------------------------------------------------------------------------
1884     case cmuClock_DPLLREFCLK:
1885       switch (ref) {
1886         case cmuSelect_HFXO:
1887           tmp = CMU_DPLLREFCLKCTRL_CLKSEL_HFXO;
1888           break;
1889 
1890         case cmuSelect_LFXO:
1891           tmp = CMU_DPLLREFCLKCTRL_CLKSEL_LFXO;
1892           break;
1893 
1894         case cmuSelect_CLKIN0:
1895           tmp = CMU_DPLLREFCLKCTRL_CLKSEL_CLKIN0;
1896           break;
1897 
1898         case cmuSelect_Disabled:
1899           tmp = CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED;
1900           break;
1901 
1902         default:
1903           EFM_ASSERT(false);
1904           break;
1905       }
1906       CMU->DPLLREFCLKCTRL = (CMU->DPLLREFCLKCTRL
1907                              & ~_CMU_DPLLREFCLKCTRL_CLKSEL_MASK) | tmp;
1908       break;
1909 
1910 #if defined(_CMU_TRACECLKCTRL_CLKSEL_MASK)
1911 // -----------------------------------------------------------------------------
1912     case cmuClock_TRACECLK:
1913 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)      \
1914       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
1915       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
1916       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)) \
1917       && defined(CoreDebug_DEMCR_TRCENA_Msk)
1918       restoreTrace = CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk;
1919       if (restoreTrace) {
1920         CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
1921       }
1922 #endif
1923       switch (ref) {
1924 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1925         case cmuSelect_HCLK:
1926           tmp = CMU_TRACECLKCTRL_CLKSEL_HCLK;
1927           break;
1928 #endif
1929 
1930 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)        \
1931         || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5) \
1932         || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7) \
1933         || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
1934         case cmuSelect_SYSCLK:
1935           tmp = CMU_TRACECLKCTRL_CLKSEL_SYSCLK;
1936           break;
1937 
1938         case cmuSelect_HFRCODPLLRT:
1939           tmp = CMU_TRACECLKCTRL_CLKSEL_HFRCODPLLRT;
1940           break;
1941 #endif
1942 
1943 #if defined(CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23)
1944         case cmuSelect_HFRCOEM23:
1945           tmp = CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23;
1946           break;
1947 #endif
1948 
1949         default:
1950           EFM_ASSERT(false);
1951           break;
1952       }
1953       CMU->TRACECLKCTRL = (CMU->TRACECLKCTRL & ~_CMU_TRACECLKCTRL_CLKSEL_MASK)
1954                           | tmp;
1955 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)      \
1956       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
1957       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
1958       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)) \
1959       && defined(CoreDebug_DEMCR_TRCENA_Msk)
1960       if (restoreTrace) {
1961         CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
1962       }
1963 #endif
1964       break;
1965 #endif
1966 
1967 #if defined(_CMU_EUART0CLKCTRL_CLKSEL_MASK)
1968 // -----------------------------------------------------------------------------
1969     case cmuClock_EUART0:
1970     case cmuClock_EUART0CLK:
1971       switch (ref) {
1972         case cmuSelect_EM01GRPACLK:
1973           tmp = _CMU_EUART0CLKCTRL_CLKSEL_EM01GRPACLK;
1974           break;
1975 
1976         case cmuSelect_EM23GRPACLK:
1977           tmp = _CMU_EUART0CLKCTRL_CLKSEL_EM23GRPACLK;
1978           break;
1979 
1980         default:
1981           EFM_ASSERT(false);
1982           break;
1983       }
1984       CMU->EUART0CLKCTRL = (CMU->EUART0CLKCTRL & ~_CMU_EUART0CLKCTRL_CLKSEL_MASK)
1985                            | tmp;
1986       break;
1987 #elif defined(EUSART_PRESENT)
1988     case cmuClock_EUSART0:
1989     case cmuClock_EUSART0CLK:
1990       switch (ref) {
1991 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPACLK)
1992         case cmuSelect_EM01GRPACLK:
1993           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPACLK;
1994           break;
1995 #endif
1996 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK)
1997         case cmuSelect_EM01GRPCCLK:
1998           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK;
1999           break;
2000 #endif
2001 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_EM23GRPACLK)
2002         case cmuSelect_EM23GRPACLK:
2003           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_EM23GRPACLK;
2004           break;
2005 #endif
2006 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_FSRCO)
2007         case cmuSelect_FSRCO:
2008           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_FSRCO;
2009           break;
2010 #endif
2011 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_HFRCOEM23)
2012         case cmuSelect_HFRCOEM23:
2013           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_HFRCOEM23;
2014           break;
2015 #endif
2016 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_LFRCO)
2017         case cmuSelect_LFRCO:
2018 #if defined(PLFRCO_PRESENT)
2019         case cmuSelect_PLFRCO:
2020 #endif
2021           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_LFRCO;
2022           break;
2023 #endif
2024 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_LFXO)
2025         case cmuSelect_LFXO:
2026           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_LFXO;
2027           break;
2028 #endif
2029 
2030         default:
2031           EFM_ASSERT(false);
2032           break;
2033       }
2034       CMU->EUSART0CLKCTRL = (CMU->EUSART0CLKCTRL & ~_CMU_EUSART0CLKCTRL_CLKSEL_MASK)
2035                             | tmp;
2036       break;
2037 
2038 #if defined(EUSART_PRESENT) && EUSART_COUNT > 1
2039     case cmuClock_EUSART1:
2040 #endif
2041 #if defined(EUSART_PRESENT) && EUSART_COUNT > 2
2042     case cmuClock_EUSART2:
2043 #endif
2044 #if defined(EUSART_PRESENT) && EUSART_COUNT > 3
2045     case cmuClock_EUSART3:
2046 #endif
2047 #if defined(EUSART_PRESENT) && EUSART_COUNT > 4
2048     case cmuClock_EUSART4:
2049 #endif
2050 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
2051     case cmuClock_EM01GRPCCLK:
2052       switch (ref) {
2053         case cmuSelect_HFRCODPLL:
2054           tmp = _CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLL;
2055           break;
2056 
2057 #if defined(CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLLRT)
2058         case cmuSelect_HFRCODPLLRT:
2059           tmp = CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLLRT;
2060           break;
2061 #endif
2062         case cmuSelect_HFRCOEM23:
2063           tmp = _CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCOEM23;
2064           break;
2065 
2066         case cmuSelect_FSRCO:
2067           tmp = _CMU_EM01GRPCCLKCTRL_CLKSEL_FSRCO;
2068           break;
2069 
2070         case cmuSelect_HFXO:
2071           tmp = _CMU_EM01GRPCCLKCTRL_CLKSEL_HFXO;
2072           break;
2073 
2074 #if defined(CMU_EM01GRPCCLKCTRL_CLKSEL_HFXORT)
2075         case cmuSelect_HFXORT:
2076           tmp = CMU_EM01GRPCCLKCTRL_CLKSEL_HFXORT;
2077           break;
2078 #endif
2079         default:
2080           EFM_ASSERT(false);
2081           break;
2082       }
2083       CMU->EM01GRPCCLKCTRL = (CMU->EM01GRPCCLKCTRL & ~_CMU_EM01GRPCCLKCTRL_CLKSEL_MASK)
2084                              | tmp;
2085       break;
2086 #endif
2087 #endif
2088 
2089 // -----------------------------------------------------------------------------
2090 #if defined (RTCC_PRESENT)
2091     case cmuClock_RTCC:
2092     case cmuClock_RTCCCLK:
2093       switch (ref) {
2094         case cmuSelect_LFRCO:
2095 #if defined(PLFRCO_PRESENT)
2096         case cmuSelect_PLFRCO:
2097 #endif
2098           tmp = CMU_RTCCCLKCTRL_CLKSEL_LFRCO;
2099           break;
2100 
2101         case cmuSelect_LFXO:
2102           tmp = CMU_RTCCCLKCTRL_CLKSEL_LFXO;
2103           break;
2104 
2105         case cmuSelect_ULFRCO:
2106           tmp = CMU_RTCCCLKCTRL_CLKSEL_ULFRCO;
2107           break;
2108 
2109         default:
2110           EFM_ASSERT(false);
2111           break;
2112       }
2113       CMU->RTCCCLKCTRL = (CMU->RTCCCLKCTRL & ~_CMU_RTCCCLKCTRL_CLKSEL_MASK)
2114                          | tmp;
2115       break;
2116 #endif
2117 // -----------------------------------------------------------------------------
2118 #if defined (SYSRTC_PRESENT)
2119     case cmuClock_SYSRTC:
2120     case cmuClock_SYSRTCCLK:
2121       switch (ref) {
2122         case cmuSelect_LFRCO:
2123 #if defined(PLFRCO_PRESENT)
2124         case cmuSelect_PLFRCO:
2125 #endif
2126           tmp = CMU_SYSRTC0CLKCTRL_CLKSEL_LFRCO;
2127           break;
2128 
2129         case cmuSelect_LFXO:
2130           tmp = CMU_SYSRTC0CLKCTRL_CLKSEL_LFXO;
2131           break;
2132 
2133         case cmuSelect_ULFRCO:
2134           tmp = CMU_SYSRTC0CLKCTRL_CLKSEL_ULFRCO;
2135           break;
2136 
2137         default:
2138           EFM_ASSERT(false);
2139           break;
2140       }
2141       CMU->SYSRTC0CLKCTRL = (CMU->SYSRTC0CLKCTRL & ~_CMU_SYSRTC0CLKCTRL_CLKSEL_MASK)
2142                             | tmp;
2143       break;
2144 #endif
2145 // -----------------------------------------------------------------------------
2146 #if defined(LCD_PRESENT)
2147     case cmuClock_LCD:
2148     case cmuClock_LCDCLK:
2149       switch (ref) {
2150         case cmuSelect_LFRCO:
2151 #if defined(PLFRCO_PRESENT)
2152         case cmuSelect_PLFRCO:
2153 #endif
2154           tmp = CMU_LCDCLKCTRL_CLKSEL_LFRCO;
2155           break;
2156 
2157         case cmuSelect_LFXO:
2158           tmp = CMU_LCDCLKCTRL_CLKSEL_LFXO;
2159           break;
2160 
2161         case cmuSelect_ULFRCO:
2162           tmp = CMU_LCDCLKCTRL_CLKSEL_ULFRCO;
2163           break;
2164 
2165         default:
2166           EFM_ASSERT(false);
2167           break;
2168       }
2169       CMU->LCDCLKCTRL =  (CMU->LCDCLKCTRL  & ~_CMU_LCDCLKCTRL_CLKSEL_MASK)
2170                         | tmp;
2171       break;
2172 #endif
2173 // -----------------------------------------------------------------------------
2174 #if defined(VDAC_PRESENT)
2175     case cmuClock_VDAC0:
2176     case cmuClock_VDAC0CLK:
2177       switch (ref) {
2178         case cmuSelect_FSRCO:
2179           tmp = CMU_VDAC0CLKCTRL_CLKSEL_FSRCO;
2180           break;
2181         case cmuSelect_HFRCOEM23:
2182           tmp = CMU_VDAC0CLKCTRL_CLKSEL_HFRCOEM23;
2183           break;
2184         case cmuSelect_EM01GRPACLK:
2185           tmp = CMU_VDAC0CLKCTRL_CLKSEL_EM01GRPACLK;
2186           break;
2187         case cmuSelect_EM23GRPACLK:
2188           tmp = CMU_VDAC0CLKCTRL_CLKSEL_EM23GRPACLK;
2189           break;
2190 
2191         default:
2192           EFM_ASSERT(false);
2193           break;
2194       }
2195       CMU->VDAC0CLKCTRL = (CMU->VDAC0CLKCTRL & ~_CMU_VDAC0CLKCTRL_CLKSEL_MASK)
2196                           | tmp;
2197       break;
2198 #if (VDAC_COUNT > 1)
2199     case cmuClock_VDAC1:
2200     case cmuClock_VDAC1CLK:
2201       switch (ref) {
2202         case cmuSelect_FSRCO:
2203           tmp = CMU_VDAC1CLKCTRL_CLKSEL_FSRCO;
2204           break;
2205         case cmuSelect_HFRCOEM23:
2206           tmp = CMU_VDAC1CLKCTRL_CLKSEL_HFRCOEM23;
2207           break;
2208         case cmuSelect_EM01GRPACLK:
2209           tmp = CMU_VDAC1CLKCTRL_CLKSEL_EM01GRPACLK;
2210           break;
2211         case cmuSelect_EM23GRPACLK:
2212           tmp = CMU_VDAC1CLKCTRL_CLKSEL_EM23GRPACLK;
2213           break;
2214 
2215         default:
2216           EFM_ASSERT(false);
2217           break;
2218       }
2219       CMU->VDAC1CLKCTRL = (CMU->VDAC1CLKCTRL & ~_CMU_VDAC1CLKCTRL_CLKSEL_MASK)
2220                           | tmp;
2221       break;
2222 #endif
2223 #endif /* VDAC_PRESENT */
2224 // -----------------------------------------------------------------------------
2225 #if defined(PCNT_PRESENT)
2226     case cmuClock_PCNT0:
2227     case cmuClock_PCNT0CLK:
2228       switch (ref) {
2229         case cmuSelect_EM23GRPACLK:
2230           tmp = CMU_PCNT0CLKCTRL_CLKSEL_EM23GRPACLK;
2231           break;
2232 
2233         case cmuSelect_PCNTEXTCLK:
2234           tmp = CMU_PCNT0CLKCTRL_CLKSEL_PCNTS0;
2235           break;
2236 
2237         default:
2238           EFM_ASSERT(false);
2239           break;
2240       }
2241       CMU->PCNT0CLKCTRL = (CMU->PCNT0CLKCTRL & ~_CMU_PCNT0CLKCTRL_CLKSEL_MASK)
2242                           | tmp;
2243       break;
2244 #endif
2245 // -----------------------------------------------------------------------------
2246 #if defined(LESENSE_PRESENT)
2247     case cmuClock_LESENSEHFCLK:
2248       switch (ref) {
2249         case cmuSelect_FSRCO:
2250           tmp = CMU_LESENSEHFCLKCTRL_CLKSEL_FSRCO;
2251           break;
2252         case cmuSelect_HFRCOEM23:
2253           tmp = CMU_LESENSEHFCLKCTRL_CLKSEL_HFRCOEM23;
2254           break;
2255 
2256         default:
2257           EFM_ASSERT(false);
2258           break;
2259       }
2260       CMU->LESENSEHFCLKCTRL = (CMU->LESENSEHFCLKCTRL & ~_CMU_LESENSEHFCLKCTRL_CLKSEL_MASK)
2261                               | tmp;
2262       break;
2263 #endif
2264 // -----------------------------------------------------------------------------
2265 #if defined(USB_PRESENT)
2266     case cmuClock_USB:
2267       switch (ref) {
2268         case cmuSelect_USBPLL0:
2269           tmp = CMU_USB0CLKCTRL_CLKSEL_USBPLL0;
2270           break;
2271         case cmuSelect_LFXO:
2272           tmp = CMU_USB0CLKCTRL_CLKSEL_LFXO;
2273           break;
2274         case cmuSelect_LFRCO:
2275           tmp = CMU_USB0CLKCTRL_CLKSEL_LFRCO;
2276           break;
2277 
2278         default:
2279           EFM_ASSERT(false);
2280           break;
2281       }
2282       CMU->USB0CLKCTRL = (CMU->USB0CLKCTRL & ~_CMU_USB0CLKCTRL_CLKSEL_MASK)
2283                          | tmp;
2284       break;
2285 #endif
2286 // -----------------------------------------------------------------------------
2287     default:
2288       EFM_ASSERT(false);
2289       break;
2290   }
2291 }
2292 
2293 /***************************************************************************//**
2294  * @brief
2295  *   Gets the precision (in PPM) of the specified low frequency clock branch.
2296  *
2297  * @param[in] clock
2298  *   Clock branch.
2299  *
2300  * @return
2301  *   Precision, in PPM, of the specified clock branch.
2302  *
2303  * @note
2304  *   This function is only for internal usage.
2305  *
2306  * @note
2307  *   The current implementation of this function is used to determine if the
2308  *   clock has a precision <= 500 ppm or not (which is the minimum required
2309  *   for BLE). Future version of this function should provide more accurate
2310  *   precision numbers to allow for further optimizations from the stacks.
2311  ******************************************************************************/
CMU_LF_ClockPrecisionGet(CMU_Clock_TypeDef clock)2312 uint16_t CMU_LF_ClockPrecisionGet(CMU_Clock_TypeDef clock)
2313 {
2314   CMU_Select_TypeDef src = CMU_ClockSelectGet(clock);
2315   uint16_t precision;
2316 
2317   switch (src) {
2318     case cmuSelect_LFXO:
2319       precision = lfxo_precision;
2320       break;
2321 
2322 #if defined(PLFRCO_PRESENT)
2323 #if defined(LFRCO_CFG_HIGHPRECEN)
2324     case cmuSelect_LFRCO:
2325     case cmuSelect_PLFRCO:
2326 
2327       CMU->CLKEN0_SET = CMU_CLKEN0_LFRCO;
2328 
2329       if (LFRCO->CFG & _LFRCO_CFG_HIGHPRECEN_MASK) {
2330         precision = 500;
2331       } else {
2332         precision = 0xFFFF;
2333       }
2334       break;
2335 #endif
2336 #endif
2337 
2338     default:
2339       precision = 0xFFFF;
2340       break;
2341   }
2342 
2343   return precision;
2344 }
2345 
2346 /***************************************************************************//**
2347  * @brief
2348  *   Get HFRCODPLL band in use.
2349  *
2350  * @return
2351  *   HFRCODPLL band in use.
2352  ******************************************************************************/
CMU_HFRCODPLLBandGet(void)2353 CMU_HFRCODPLLFreq_TypeDef CMU_HFRCODPLLBandGet(void)
2354 {
2355   return (CMU_HFRCODPLLFreq_TypeDef)SystemHFRCODPLLClockGet();
2356 }
2357 
2358 /***************************************************************************//**
2359  * @brief
2360  *   Set HFRCODPLL band and the tuning value based on the value in the
2361  *   calibration table made during production.
2362  *
2363  * @param[in] freq
2364  *   HFRCODPLL frequency band to activate.
2365  ******************************************************************************/
CMU_HFRCODPLLBandSet(CMU_HFRCODPLLFreq_TypeDef freq)2366 void CMU_HFRCODPLLBandSet(CMU_HFRCODPLLFreq_TypeDef freq)
2367 {
2368   uint32_t hfrcoFreqRangeExpected;
2369   uint32_t hfrcoFreqRangeActual;
2370   uint32_t hfrcoCalCurrent;
2371   uint32_t freqCal, sysFreq;
2372 #if defined(EMU_VSCALE_EM01_PRESENT)
2373   uint32_t prevFreq;
2374 #endif
2375 
2376   // Get calibration data from DEVINFO
2377   freqCal = HFRCODPLLDevinfoGet(freq);
2378   EFM_ASSERT((freqCal != 0UL) && (freqCal != UINT_MAX));
2379 
2380 #if defined(CMU_CLKEN0_DPLL0)
2381   CMU->CLKEN0_SET = CMU_CLKEN0_DPLL0 | CMU_CLKEN0_HFRCO0;
2382 #endif
2383 
2384   // Make sure DPLL is disabled before configuring
2385   if (DPLL0->EN == DPLL_EN_EN) {
2386     DPLL0->EN_CLR = DPLL_EN_EN;
2387 #if defined(DPLL_EN_DISABLING)
2388     while (DPLL0->EN & DPLL_EN_DISABLING) {
2389     }
2390 #else
2391     while ((DPLL0->STATUS & (DPLL_STATUS_ENS | DPLL_STATUS_RDY)) != 0UL) {
2392     }
2393 #endif
2394   }
2395 
2396   // Set max wait-states and PCLK divisor while changing core clock
2397   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
2398     waitStateMax();
2399     pclkDivMax();
2400 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
2401     && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
2402     // Set largest prescaler for radio clock tree
2403     rhclkPrescMax();
2404 #endif
2405   }
2406 
2407   // Set divider for 1, 2 and 4MHz bands
2408   freqCal &= ~_HFRCO_CAL_CLKDIV_MASK;
2409   switch (freq) {
2410     case cmuHFRCODPLLFreq_1M0Hz:
2411       freqCal |= HFRCO_CAL_CLKDIV_DIV4;
2412       break;
2413 
2414     case cmuHFRCODPLLFreq_2M0Hz:
2415       freqCal |= HFRCO_CAL_CLKDIV_DIV2;
2416       break;
2417 
2418     default:
2419       break;
2420   }
2421 
2422 #if defined(EMU_VSCALE_EM01_PRESENT)
2423   prevFreq = SystemHFRCODPLLClockGet();
2424 
2425   if ((uint32_t)freq > prevFreq) {
2426     /* When increasing frequency voltage scale must be done before the change. */
2427     EMU_VScaleEM01ByClock((uint32_t)freq, true);
2428   }
2429 #endif
2430 
2431   // updates to the CAL register are deferred if FREQBSY is high, so wait
2432   // until HFRCO is not busy to keep going
2433   while (HFRCO0->STATUS & (HFRCO_STATUS_SYNCBUSY | HFRCO_STATUS_FREQBSY)) {
2434   }
2435 
2436   /*
2437    * Some devices have clamped frequency ranges, so instead of the usual [0:16]
2438    * interval, the upper limit is 12. Hardware takes care of clamping the value,
2439    * but a situation might occur where tuning and frequency range are not
2440    * in sync. So try to detect if the value has been clamped, and if it happened
2441    * revert back to the previous value.
2442    */
2443   hfrcoCalCurrent = HFRCO0->CAL;
2444   HFRCO0->CAL = freqCal;
2445 
2446   // values are not shifted, not necessary for comparison
2447   hfrcoFreqRangeExpected = (freqCal     & _HFRCO_CAL_FREQRANGE_MASK);
2448   hfrcoFreqRangeActual   = (HFRCO0->CAL & _HFRCO_CAL_FREQRANGE_MASK);
2449 
2450   EFM_ASSERT(hfrcoFreqRangeExpected == hfrcoFreqRangeActual);
2451   if (hfrcoFreqRangeExpected == hfrcoFreqRangeActual) {
2452     // Update CMSIS HFRCODPLL frequency.
2453     SystemHFRCODPLLClockSet(freq);
2454   } else {
2455     // revert back to previous value
2456     HFRCO0->CAL = hfrcoCalCurrent;
2457 #if defined(EMU_VSCALE_EM01_PRESENT)
2458     freq = (CMU_HFRCODPLLFreq_TypeDef)prevFreq;
2459 #endif
2460   }
2461 
2462   // If HFRCODPLL is selected as SYSCLK (and HCLK), optimize flash access
2463   // wait-state configuration and PCLK divisor for this frequency.
2464   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
2465     // Call @ref SystemCoreClockGet() to update CMSIS core clock variable.
2466     sysFreq = SystemCoreClockGet();
2467     EFM_ASSERT(sysFreq <= (uint32_t)freq);
2468     CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
2469     pclkDivOptimize();
2470 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
2471     && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
2472     // Set optimal RHCLK prescaler
2473     rhclkPrescOptimize();
2474 #endif
2475   }
2476 
2477 #if defined(EMU_VSCALE_EM01_PRESENT)
2478   if ((uint32_t)freq <= prevFreq) {
2479     /* When decreasing frequency voltage scale must be done after the change. */
2480     EMU_VScaleEM01ByClock(0, true);
2481   }
2482 #endif
2483 }
2484 
2485 /**************************************************************************//**
2486  * @brief
2487  *   Lock the DPLL to a given frequency.
2488  *   The frequency is given by: Fout = Fref * (N+1) / (M+1).
2489  *
2490  * @note
2491  *   This function does not check if the given N & M values will actually
2492  *   produce the desired target frequency. @n
2493  *   N & M limitations: @n
2494  *     300 < N <= 4095 @n
2495  *     0 <= M <= 4095 @n
2496  *   Any peripheral running off HFRCODPLL should be switched to a lower
2497  *   frequency clock (if possible) prior to calling this function to avoid
2498  *   over-clocking.
2499  *
2500  * @param[in] init
2501  *    DPLL setup parameter struct.
2502  *
2503  * @return
2504  *   Returns false on invalid target frequency or DPLL locking error.
2505  *****************************************************************************/
CMU_DPLLLock(const CMU_DPLLInit_TypeDef * init)2506 bool CMU_DPLLLock(const CMU_DPLLInit_TypeDef *init)
2507 {
2508   int index = 0;
2509   unsigned int i;
2510   bool hclkDivIncreased = false;
2511   uint32_t hfrcoCalVal, lockStatus = 0, hclkDiv = 0, sysFreq;
2512   uint32_t hfrcoFreqRangeExpected;
2513   uint32_t hfrcoFreqRangeActual;
2514   uint32_t hfrcoCalCurrent;
2515   bool hfrcoClamped = false;
2516   bool restoreDpll;
2517 
2518 #if defined(CMU_CLKEN0_DPLL0)
2519   CMU->CLKEN0_SET = CMU_CLKEN0_DPLL0 | CMU_CLKEN0_HFRCO0;
2520 #endif
2521 
2522   restoreDpll = DPLL0->EN & _DPLL_EN_EN_MASK;
2523 
2524   // Make sure DPLL is disabled before configuring
2525   DPLL0->EN_CLR = DPLL_EN_EN;
2526 #if defined(DPLL_EN_DISABLING)
2527   while (DPLL0->EN & DPLL_EN_DISABLING) {
2528   }
2529 #else
2530   while ((DPLL0->STATUS & (DPLL_STATUS_ENS | DPLL_STATUS_RDY)) != 0UL) {
2531   }
2532 #endif
2533   EFM_ASSERT(init->frequency >= hfrcoCalTable[0].minFreq);
2534   EFM_ASSERT(init->frequency
2535              <= hfrcoCalTable[HFRCOCALTABLE_ENTRIES - 1U].maxFreq);
2536 
2537   EFM_ASSERT(init->n > 300U);
2538   EFM_ASSERT(init->n <= (_DPLL_CFG1_N_MASK >> _DPLL_CFG1_N_SHIFT));
2539   EFM_ASSERT(init->m <= (_DPLL_CFG1_M_MASK >> _DPLL_CFG1_M_SHIFT));
2540 
2541 #if defined(EMU_VSCALE_EM01_PRESENT)
2542   if ((EMU_VScaleGet() == emuVScaleEM01_LowPower)
2543       && (init->frequency > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
2544     EFM_ASSERT(false);
2545     return false;
2546   }
2547 #endif
2548 
2549   // Find correct HFRCODPLL band, and retrieve a HFRCOCAL value.
2550   for (i = 0; i < HFRCOCALTABLE_ENTRIES; i++) {
2551     if ((init->frequency    >= hfrcoCalTable[i].minFreq)
2552         && (init->frequency <= hfrcoCalTable[i].maxFreq)) {
2553       index = (int)i;                       // Correct band found
2554       break;
2555     }
2556   }
2557   if ((uint32_t)index == HFRCOCALTABLE_ENTRIES) {
2558     EFM_ASSERT(false);
2559     return false;                           // Target frequency out of spec.
2560   }
2561   hfrcoCalVal = hfrcoCalTable[index].value;
2562 
2563   // Check if a calibrated HFRCOCAL.TUNING value is present in device DI page.
2564   if (hfrcoCalTable[index].band != (CMU_HFRCODPLLFreq_TypeDef)0) {
2565     uint32_t tuning;
2566 
2567     tuning = (HFRCODPLLDevinfoGet(hfrcoCalTable[index].band)
2568               & _HFRCO_CAL_TUNING_MASK)
2569              >> _HFRCO_CAL_TUNING_SHIFT;
2570     hfrcoCalVal |= tuning << _HFRCO_CAL_TUNING_SHIFT;
2571   }
2572 
2573   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
2574     // Set max wait-states and PCLK divisor while changing core clock
2575     waitStateMax();
2576     pclkDivMax();
2577 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
2578     && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
2579     // Set largest prescaler for radio clock tree
2580     rhclkPrescMax();
2581 #endif
2582 
2583     // Increase HCLK divider value (if possible) while locking DPLL to
2584     // avoid over-clocking.
2585     hclkDiv = CMU_ClockDivGet(cmuClock_HCLK);
2586     hclkDivIncreased = true;
2587     if (hclkDiv == 1U) {
2588       CMU_ClockDivSet(cmuClock_HCLK, 2U);
2589     } else if (hclkDiv == 2U) {
2590       CMU_ClockDivSet(cmuClock_HCLK, 4U);
2591     } else {
2592       hclkDivIncreased = false;
2593     }
2594   }
2595 
2596   // updates to the CAL register are deferred if FREQBSY is high, so wait
2597   // until HFRCO is not busy to keep going
2598   while (HFRCO0->STATUS & (HFRCO_STATUS_SYNCBUSY | HFRCO_STATUS_FREQBSY)) {
2599   }
2600 
2601   /*
2602    * Some devices have clamped frequency ranges, so instead of the usual [0:16]
2603    * interval, the upper limit is 12. Hardware takes care of clamping the value,
2604    * but a situation might occur where tuning and frequency range are not
2605    * in sync. So try to detect if the value has been clamped, and if it happened
2606    * revert back to the previous value.
2607    */
2608   hfrcoCalCurrent = HFRCO0->CAL;
2609   HFRCO0->CAL = hfrcoCalVal;
2610 
2611   // values are not shifted, not necessary for comparison
2612   hfrcoFreqRangeExpected = (hfrcoCalVal & _HFRCO_CAL_FREQRANGE_MASK);
2613   hfrcoFreqRangeActual   = (HFRCO0->CAL & _HFRCO_CAL_FREQRANGE_MASK);
2614 
2615   EFM_ASSERT(hfrcoFreqRangeExpected == hfrcoFreqRangeActual);
2616   if (hfrcoFreqRangeExpected == hfrcoFreqRangeActual) {
2617     DPLL0->CFG1   = ((uint32_t)init->n   << _DPLL_CFG1_N_SHIFT)
2618                     | ((uint32_t)init->m << _DPLL_CFG1_M_SHIFT);
2619 
2620     /* For series 2 silicon, macro expansion is used to select clock
2621      * sources since it results in less code size when compared to the legacy
2622      * CMU_ClockSelectSet function.
2623      */
2624     if (init->refClk == cmuSelect_HFXO) {
2625       CMU_CLOCK_SELECT_SET(DPLLREFCLK, HFXO);
2626     } else if (init->refClk == cmuSelect_LFXO) {
2627       CMU_CLOCK_SELECT_SET(DPLLREFCLK, LFXO);
2628     } else if (init->refClk == cmuSelect_CLKIN0) {
2629       CMU_CLOCK_SELECT_SET(DPLLREFCLK, CLKIN0);
2630     }
2631 
2632     DPLL0->CFG = ((init->autoRecover ? 1UL : 0UL) << _DPLL_CFG_AUTORECOVER_SHIFT)
2633                  | ((init->ditherEn ? 1UL : 0UL)  << _DPLL_CFG_DITHEN_SHIFT)
2634                  | ((uint32_t)init->edgeSel  << _DPLL_CFG_EDGESEL_SHIFT)
2635                  | ((uint32_t)init->lockMode << _DPLL_CFG_MODE_SHIFT);
2636 
2637     // Update CMSIS HFRCODPLL frequency.
2638     SystemHFRCODPLLClockSet(init->frequency);
2639   } else {
2640     hfrcoClamped = true;
2641     HFRCO0->CAL = hfrcoCalCurrent;
2642   }
2643 
2644   /*
2645    * if HFRCO frequency range has been clamped, re-enable DPLL only if it was
2646    * previously enabled
2647    */
2648   if (!hfrcoClamped || restoreDpll) {
2649     DPLL0->IF_CLR = DPLL_IF_LOCK | DPLL_IF_LOCKFAILLOW | DPLL_IF_LOCKFAILHIGH;
2650 
2651     // Lock DPLL
2652     DPLL0->EN_SET = DPLL_EN_EN;
2653     while ((lockStatus = (DPLL0->IF & (DPLL_IF_LOCK
2654                                        | DPLL_IF_LOCKFAILLOW
2655                                        | DPLL_IF_LOCKFAILHIGH))) == 0UL) {
2656     }
2657   }
2658 
2659   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
2660     if (hclkDivIncreased) {
2661       // Restore original HCLK divider
2662       CMU_ClockDivSet(cmuClock_HCLK, hclkDiv);
2663     }
2664 
2665     // Call @ref SystemCoreClockGet() to update CMSIS core clock variable.
2666     sysFreq = SystemCoreClockGet();
2667     EFM_ASSERT(sysFreq <= init->frequency);
2668     EFM_ASSERT(sysFreq <= SystemHFRCODPLLClockGet());
2669     EFM_ASSERT(init->frequency == SystemHFRCODPLLClockGet());
2670 
2671     // Set optimal wait-states and PCLK divisor
2672     CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
2673     pclkDivOptimize();
2674 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
2675     && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
2676     // Set optimal RHCLK prescaler
2677     rhclkPrescOptimize();
2678 #endif
2679   }
2680 
2681   if (hfrcoClamped) {
2682     return false;
2683   } else if (lockStatus == DPLL_IF_LOCK) {
2684     return true;
2685   }
2686   return false;
2687 }
2688 
2689 #if defined(USBPLL_PRESENT)
2690 /***************************************************************************//**
2691  * @brief
2692  *   Initialize the USB PLL control registers.
2693  *
2694  * @note
2695  *  The HFXO reference frequency must be updated if crystal value is
2696  *  different from default value.
2697  *
2698  * @param[in] pllInit
2699  *   USB PLL parameters
2700  ******************************************************************************/
CMU_USBPLLInit(const CMU_USBPLL_Init_TypeDef * pllInit)2701 void CMU_USBPLLInit(const CMU_USBPLL_Init_TypeDef *pllInit)
2702 {
2703   CMU->CLKEN1_SET = CMU_CLKEN1_USB;
2704 
2705   USBPLL0->LOCK = USBPLL_LOCK_LOCKKEY_UNLOCK;
2706 
2707   // Stop the PLL for configuration purposes
2708   USBPLL0->CTRL_SET = USBPLL_CTRL_DISONDEMAND;
2709   USBPLL0->CTRL_CLR = USBPLL_CTRL_FORCEEN;
2710 
2711   while (USBPLL0->STATUS & USBPLL_STATUS_PLLLOCK) ;
2712 
2713   if (pllInit->hfxoRefFreq == cmuHFXORefFreq_39M0Hz) {
2714     // Set DCO in low frequency mode for 39 MHz crystal.
2715     USBPLL0->DCOCTRL_SET = _USBPLL_DCOCTRL_DCOBIASHALF_MASK;
2716   } else {
2717     USBPLL0->DCOCTRL_CLR = _USBPLL_DCOCTRL_DCOBIASHALF_MASK;
2718   }
2719 
2720   while (USBPLL0->STATUS & USBPLL_STATUS_SYNCBUSY) ;
2721 
2722   USBPLL0->CTRL = (USBPLL0->CTRL & ~(_USBPLL_CTRL_SHUNTREGLPEN_MASK
2723                                      | _USBPLL_CTRL_DIVR_MASK
2724                                      | _USBPLL_CTRL_DIVX_MASK
2725                                      | _USBPLL_CTRL_DIVN_MASK
2726                                      | _USBPLL_CTRL_DISONDEMAND_MASK
2727                                      | _USBPLL_CTRL_FORCEEN_MASK))
2728                   | pllInit->hfxoRefFreq
2729                   | pllInit->shuntRegEn  << _USBPLL_CTRL_SHUNTREGLPEN_SHIFT
2730                   | pllInit->disOnDemand << _USBPLL_CTRL_DISONDEMAND_SHIFT
2731                   | pllInit->forceEn     << _USBPLL_CTRL_FORCEEN_SHIFT;
2732 
2733   while (USBPLL0->STATUS & USBPLL_STATUS_SYNCBUSY) ;
2734 
2735   if (pllInit->forceEn) {
2736     CMU_WaitUSBPLLLock();
2737   }
2738 
2739   if (pllInit->regLock) {
2740     USBPLL0->LOCK = ~USBPLL_LOCK_LOCKKEY_UNLOCK;
2741   }
2742 }
2743 #endif
2744 
2745 #if defined(RFFPLL_PRESENT)
2746 /***************************************************************************//**
2747  * @brief
2748  *   Initialize the RFFPLL control registers.
2749  *
2750  * @param[in] pllInit
2751  *   RFF PLL parameters
2752  ******************************************************************************/
CMU_RFFPLLInit(const CMU_RFFPLL_Init_TypeDef * pllInit)2753 void CMU_RFFPLLInit(const CMU_RFFPLL_Init_TypeDef *pllInit)
2754 {
2755   EFM_ASSERT(CMU_ClockSelectGet(cmuClock_SYSCLK) != cmuSelect_RFFPLLSYS);
2756   EFM_ASSERT(pllInit->dividerY >= 8 && pllInit->dividerY <= 31);
2757   EFM_ASSERT(pllInit->dividerX >= 4 && pllInit->dividerX <= 15);
2758   EFM_ASSERT(pllInit->dividerN >= 32 && pllInit->dividerN <= 127);
2759 
2760   CMU->CLKEN1_SET = CMU_CLKEN1_RFFPLL0;
2761 
2762   RFFPLL0->LOCK = RFFPLL_LOCK_LOCKKEY_UNLOCK;
2763 
2764   RFFPLL0->CTRL = (RFFPLL0->CTRL & ~(_RFFPLL_CTRL_DISONDEMAND_MASK | _RFFPLL_CTRL_FORCEEN_MASK))
2765                   | (pllInit->disOnDemand << _RFFPLL_CTRL_DISONDEMAND_SHIFT)
2766                   | (pllInit->forceEn     << _RFFPLL_CTRL_FORCEEN_SHIFT);
2767 
2768   RFFPLL0->RFFPLLCTRL1 = (RFFPLL0->RFFPLLCTRL1 & ~(_RFFPLL_RFFPLLCTRL1_DIVY_MASK | _RFFPLL_RFFPLLCTRL1_DIVX_MASK | _RFFPLL_RFFPLLCTRL1_DIVN_MASK))
2769                          | (pllInit->dividerY << _RFFPLL_RFFPLLCTRL1_DIVY_SHIFT)
2770                          | (pllInit->dividerX << _RFFPLL_RFFPLLCTRL1_DIVX_SHIFT)
2771                          | (pllInit->dividerN << _RFFPLL_RFFPLLCTRL1_DIVN_SHIFT);
2772 
2773   // Update CMSIS RFFPLL frequency.
2774   SystemRFFPLLClockSet(pllInit->frequency);
2775 
2776   if (pllInit->forceEn) {
2777     CMU_WaitRFFPLLLock();
2778   }
2779 
2780   if (pllInit->regLock) {
2781     RFFPLL0->LOCK = ~USBPLL_LOCK_LOCKKEY_UNLOCK;
2782   }
2783 }
2784 #endif
2785 
2786 /**************************************************************************//**
2787  * @brief
2788  *   Initialize all HFXO control registers.
2789  *
2790  * @note
2791  *   HFXO configuration should be obtained from a configuration tool,
2792  *   app note or crystal datasheet. This function returns early if HFXO is
2793  *   already selected as SYSCLK.
2794  *
2795  * @param[in] hfxoInit
2796  *    HFXO setup parameters.
2797  *****************************************************************************/
CMU_HFXOInit(const CMU_HFXOInit_TypeDef * hfxoInit)2798 void CMU_HFXOInit(const CMU_HFXOInit_TypeDef *hfxoInit)
2799 {
2800   // Check all initialization structure members which may overflow target
2801   // bitfield.
2802   EFM_ASSERT(hfxoInit->timeoutCbLsb
2803              <= (_HFXO_XTALCFG_TIMEOUTCBLSB_MASK
2804                  >> _HFXO_XTALCFG_TIMEOUTCBLSB_SHIFT));
2805   EFM_ASSERT(hfxoInit->timeoutSteadyFirstLock
2806              <= (_HFXO_XTALCFG_TIMEOUTSTEADY_MASK
2807                  >> _HFXO_XTALCFG_TIMEOUTSTEADY_SHIFT));
2808   EFM_ASSERT(hfxoInit->timeoutSteady
2809              <= (_HFXO_XTALCFG_TIMEOUTSTEADY_MASK
2810                  >> _HFXO_XTALCFG_TIMEOUTSTEADY_SHIFT));
2811   EFM_ASSERT(hfxoInit->ctuneXoStartup
2812              <= (_HFXO_XTALCFG_CTUNEXOSTARTUP_MASK
2813                  >> _HFXO_XTALCFG_CTUNEXOSTARTUP_SHIFT));
2814   EFM_ASSERT(hfxoInit->ctuneXiStartup
2815              <= (_HFXO_XTALCFG_CTUNEXISTARTUP_MASK
2816                  >> _HFXO_XTALCFG_CTUNEXISTARTUP_SHIFT));
2817   EFM_ASSERT(hfxoInit->coreBiasStartup
2818              <= (_HFXO_XTALCFG_COREBIASSTARTUP_MASK
2819                  >> _HFXO_XTALCFG_COREBIASSTARTUP_SHIFT));
2820   EFM_ASSERT(hfxoInit->imCoreBiasStartup
2821              <= (_HFXO_XTALCFG_COREBIASSTARTUPI_MASK
2822                  >> _HFXO_XTALCFG_COREBIASSTARTUPI_SHIFT));
2823   EFM_ASSERT(hfxoInit->coreDegenAna
2824              <= (_HFXO_XTALCTRL_COREDGENANA_MASK
2825                  >> _HFXO_XTALCTRL_COREDGENANA_SHIFT));
2826   EFM_ASSERT(hfxoInit->ctuneFixAna
2827              <= (_HFXO_XTALCTRL_CTUNEFIXANA_MASK
2828                  >> _HFXO_XTALCTRL_CTUNEFIXANA_SHIFT));
2829   EFM_ASSERT(hfxoInit->mode
2830              <= (_HFXO_CFG_MODE_MASK >> _HFXO_CFG_MODE_SHIFT));
2831 
2832   // Return early if HFXO is already selected as SYSCLK.
2833   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFXO) {
2834     return;
2835   }
2836 
2837 #if defined(CMU_CLKEN0_HFXO0)
2838   // Enable HFXO module clock.
2839   CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
2840 #endif
2841 
2842   // Unlock register interface.
2843   HFXO0->LOCK = HFXO_LOCK_LOCKKEY_UNLOCK;
2844 
2845   // Disable HFXO.
2846   HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND
2847 #if defined(_HFXO_CTRL_DISONDEMANDBUFOUT_MASK)
2848                     | HFXO_CTRL_DISONDEMANDBUFOUT
2849 #endif
2850   ;
2851   HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
2852   while ((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0U) {
2853   }
2854 
2855 #if defined(_DEVINFO_HFXOCAL_VTRTRIMANA_MASK) && defined(_HFXO_BUFOUTTRIM_MASK) && defined(_HFXO_SWRST_MASK)
2856   {
2857     uint32_t tmp;
2858 
2859     tmp = BUS_RegMaskedRead(&DEVINFO->HFXOCAL,
2860                             _DEVINFO_HFXOCAL_VTRTRIMANA_MASK);
2861     tmp >>= _DEVINFO_HFXOCAL_VTRTRIMANA_SHIFT;
2862     BUS_RegMaskedWrite(&HFXO0->BUFOUTTRIM,
2863                        _HFXO_BUFOUTTRIM_VTRTRIMANA_MASK,
2864                        tmp << _HFXO_BUFOUTTRIM_VTRTRIMANA_SHIFT);
2865   }
2866 #endif
2867 
2868 #if defined(_DEVINFO_HFXOCAL_SHUNTBIASANA_MASK) && defined(_HFXO_LOWPWRCTRL_MASK) && defined(_HFXO_SWRST_MASK)
2869   {
2870     uint32_t tmp;
2871 
2872     tmp = BUS_RegMaskedRead(&DEVINFO->HFXOCAL,
2873                             _DEVINFO_HFXOCAL_SHUNTBIASANA_MASK);
2874     tmp >>= _DEVINFO_HFXOCAL_SHUNTBIASANA_SHIFT;
2875     BUS_RegMaskedWrite(&HFXO0->LOWPWRCTRL,
2876                        _HFXO_LOWPWRCTRL_SHUNTBIASANA_MASK,
2877                        tmp << _HFXO_LOWPWRCTRL_SHUNTBIASANA_SHIFT);
2878   }
2879 #endif
2880 
2881   // Configure HFXO as specified in initialization struct, use
2882   // timeoutSteadyFirstLock as TIMEOUTSTEADY value.
2883   HFXO0->XTALCFG =
2884     (uint32_t)((hfxoInit->timeoutCbLsb           << _HFXO_XTALCFG_TIMEOUTCBLSB_SHIFT)
2885                | (hfxoInit->timeoutSteadyFirstLock << _HFXO_XTALCFG_TIMEOUTSTEADY_SHIFT)
2886                | (hfxoInit->ctuneXoStartup         << _HFXO_XTALCFG_CTUNEXOSTARTUP_SHIFT)
2887                | (hfxoInit->ctuneXiStartup         << _HFXO_XTALCFG_CTUNEXISTARTUP_SHIFT)
2888                | (hfxoInit->coreBiasStartup        << _HFXO_XTALCFG_COREBIASSTARTUP_SHIFT)
2889                | (hfxoInit->imCoreBiasStartup      << _HFXO_XTALCFG_COREBIASSTARTUPI_SHIFT));
2890 
2891   HFXO0->XTALCTRL = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_SKIPCOREBIASOPT_MASK)
2892                     | (hfxoInit->coreDegenAna    << _HFXO_XTALCTRL_COREDGENANA_SHIFT)
2893                     | (hfxoInit->ctuneFixAna     << _HFXO_XTALCTRL_CTUNEFIXANA_SHIFT)
2894                     | (hfxoInit->ctuneXoAna      << _HFXO_XTALCTRL_CTUNEXOANA_SHIFT)
2895                     | (hfxoInit->ctuneXiAna      << _HFXO_XTALCTRL_CTUNEXIANA_SHIFT)
2896                     | (hfxoInit->coreBiasAna     << _HFXO_XTALCTRL_COREBIASANA_SHIFT);
2897 
2898 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3) \
2899   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
2900   // See [PM-2871] for details.
2901   BUS_RegMaskedWrite((volatile uint32_t*)(HFXO0_BASE + 0x38U),
2902                      0x00000C00U,
2903                      0x00000002U << 10);
2904 #endif
2905 
2906   HFXO0->CFG = (HFXO0->CFG & ~(_HFXO_CFG_SQBUFSCHTRGANA_MASK
2907                                | _HFXO_CFG_ENXIDCBIASANA_MASK
2908                                | _HFXO_CFG_MODE_MASK))
2909                | ((hfxoInit->mode == cmuHfxoOscMode_Crystal)
2910                   ? 0 : HFXO_CFG_SQBUFSCHTRGANA)
2911                | (hfxoInit->enXiDcBiasAna    << _HFXO_CFG_ENXIDCBIASANA_SHIFT)
2912                | (hfxoInit->mode             << _HFXO_CFG_MODE_SHIFT);
2913 
2914   if (hfxoInit->mode == cmuHfxoOscMode_Crystal) {
2915     // Lock HFXO with FORCEEN bit set and DISONDEMAND bit cleared.
2916     HFXO0->CTRL = (HFXO0->CTRL & ~(_HFXO_CTRL_FORCEXO2GNDANA_MASK
2917                                    | _HFXO_CTRL_FORCEXI2GNDANA_MASK
2918                                    | _HFXO_CTRL_DISONDEMAND_MASK
2919 #if defined(HFXO_CTRL_EM23ONDEMAND)
2920                                    | _HFXO_CTRL_EM23ONDEMAND_MASK
2921 #endif
2922                                    | _HFXO_CTRL_FORCEEN_MASK))
2923                   | (hfxoInit->forceXo2GndAna << _HFXO_CTRL_FORCEXO2GNDANA_SHIFT)
2924                   | (hfxoInit->forceXi2GndAna << _HFXO_CTRL_FORCEXI2GNDANA_SHIFT)
2925 #if defined(HFXO_CTRL_EM23ONDEMAND)
2926                   | (hfxoInit->em23OnDemand   << _HFXO_CTRL_EM23ONDEMAND_SHIFT)
2927 #endif
2928                   | HFXO_CTRL_FORCEEN;
2929 
2930     // Wait for HFXO lock and core bias algorithm to complete.
2931 #if defined(HFXO_STATUS_FSMLOCK)
2932     while ((HFXO0->STATUS & (HFXO_STATUS_RDY | HFXO_STATUS_COREBIASOPTRDY
2933                              | HFXO_STATUS_ENS | HFXO_STATUS_FSMLOCK))
2934            != (HFXO_STATUS_RDY | HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_ENS
2935                | HFXO_STATUS_FSMLOCK)) {
2936     }
2937 #else
2938     while ((HFXO0->STATUS & (HFXO_STATUS_RDY | HFXO_STATUS_COREBIASOPTRDY
2939                              | HFXO_STATUS_ENS))
2940            != (HFXO_STATUS_RDY | HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_ENS)) {
2941     }
2942 #endif
2943     // Set DISONDEMAND to be able to enter new values for use on subsequent locks.
2944     HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
2945 #if defined(HFXO_CMD_MANUALOVERRIDE)
2946     HFXO0->CMD = HFXO_CMD_MANUALOVERRIDE;
2947 #endif
2948 #if defined(HFXO_STATUS_FSMLOCK)
2949     while ((HFXO0->STATUS & HFXO_STATUS_FSMLOCK) != 0) {
2950     }
2951 #endif
2952     // Set new TIMEOUTSTEADY value for use on subsequent locks.
2953     HFXO0->XTALCFG = (HFXO0->XTALCFG & ~_HFXO_XTALCFG_TIMEOUTSTEADY_MASK)
2954                      | (hfxoInit->timeoutSteady
2955                         << _HFXO_XTALCFG_TIMEOUTSTEADY_SHIFT);
2956 
2957     // Skip core bias algorithm on subsequent locks.
2958     HFXO0->XTALCTRL_SET = HFXO_XTALCTRL_SKIPCOREBIASOPT;
2959 
2960     if (hfxoInit->disOnDemand == false) {
2961       HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
2962     }
2963 
2964     if (hfxoInit->forceEn == false) {
2965       HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
2966     }
2967   } else {
2968     // Lock HFXO in EXTERNAL SINE mode.
2969 
2970 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)    \
2971     || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4) \
2972     || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
2973     //See [PM-3665] for details.
2974     if (hfxoInit->mode == cmuHfxoOscMode_ExternalSinePkDet) {
2975       HFXO0->XTALCFG = 0;
2976       HFXO0->XTALCTRL = 0;
2977 
2978       const uint32_t PKDETTHSTARTUP_PARAMETER_1 = 2UL;
2979       BUS_RegMaskedWrite((volatile uint32_t *)(HFXO0_BASE + 0x34U),
2980                          0x0000F000U | 0x00000F00U,
2981                          (PKDETTHSTARTUP_PARAMETER_1 << 12) | (PKDETTHSTARTUP_PARAMETER_1 << 8));
2982     }
2983 #endif
2984 
2985     HFXO0->CTRL = (HFXO0->CTRL & ~(_HFXO_CTRL_FORCEXO2GNDANA_MASK
2986                                    | _HFXO_CTRL_FORCEXI2GNDANA_MASK
2987                                    | _HFXO_CTRL_DISONDEMAND_MASK
2988 #if defined(HFXO_CTRL_EM23ONDEMAND)
2989                                    | _HFXO_CTRL_EM23ONDEMAND_MASK
2990 #endif
2991                                    | _HFXO_CTRL_FORCEEN_MASK))
2992                   | (hfxoInit->forceXo2GndAna << _HFXO_CTRL_FORCEXO2GNDANA_SHIFT)
2993                   | (hfxoInit->disOnDemand    << _HFXO_CTRL_DISONDEMAND_SHIFT)
2994 #if defined(HFXO_CTRL_EM23ONDEMAND)
2995                   | (hfxoInit->em23OnDemand   << _HFXO_CTRL_EM23ONDEMAND_SHIFT)
2996 #endif
2997                   | (hfxoInit->forceEn        << _HFXO_CTRL_FORCEEN_SHIFT);
2998   }
2999 
3000   if (hfxoInit->regLock) {
3001     HFXO0->LOCK = ~HFXO_LOCK_LOCKKEY_UNLOCK;
3002   }
3003 }
3004 
3005 #if defined(HFXO0_BUFOUT)
3006 /**************************************************************************//**
3007  * @brief
3008  *   Initialize HFXO Bufout (Crystal sharing) leader control registers.
3009  *   Configure the bufout request input GPIO as a clock request signal
3010  *   to add the crystal sharing follower chip as a source of clock request.
3011  *
3012  * @warning
3013  *   If EM2 capabilities are needed, a GPIO that fully retains its
3014  *   capabilities while in EM2 must be selected.
3015  *
3016  * @param[in] bufoutInit
3017  *   Bufout setup parameters.
3018  *
3019  * @param[in] port
3020  *   Bufout request GPIO port.
3021  *
3022  * @param[in] pin
3023  *   Bufout request GPIO pin.
3024  *****************************************************************************/
CMU_HFXOStartCrystalSharingLeader(const CMU_BUFOUTLeaderInit_TypeDef * bufoutInit,GPIO_Port_TypeDef port,unsigned int pin)3025 void CMU_HFXOStartCrystalSharingLeader(const CMU_BUFOUTLeaderInit_TypeDef *bufoutInit,
3026                                        GPIO_Port_TypeDef                   port,
3027                                        unsigned int                        pin)
3028 {
3029   EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
3030 
3031   // Configure Bufout request GPIO.
3032   GPIO_PinModeSet(port, pin, gpioModeInput, 0U);
3033   GPIO->SYXOROUTE[0].BUFOUTREQINASYNCROUTE = pin    << _GPIO_SYXO_BUFOUTREQINASYNCROUTE_PIN_SHIFT
3034                                              | port << _GPIO_SYXO_BUFOUTREQINASYNCROUTE_PORT_SHIFT;
3035 
3036   bool wasLocked = HFXO0->STATUS & HFXO_STATUS_LOCK_LOCKED ? true : false;
3037 
3038   // Unlock register interface.
3039   HFXO0->LOCK = HFXO_LOCK_LOCKKEY_UNLOCK;
3040 
3041   HFXO0->CTRL_CLR = _HFXO_CTRL_BUFOUTFREEZE_MASK | _HFXO_CTRL_DISONDEMANDBUFOUT_MASK;
3042 
3043   BUS_RegMaskedWrite(&HFXO0->BUFOUTCTRL,
3044                      _HFXO_BUFOUTCTRL_MINIMUMSTARTUPDELAY_MASK
3045                      | _HFXO_BUFOUTCTRL_TIMEOUTSTARTUP_MASK,
3046                      bufoutInit->minimalStartupDelay  << _HFXO_BUFOUTCTRL_MINIMUMSTARTUPDELAY_SHIFT
3047                      | bufoutInit->timeoutStartup       << _HFXO_BUFOUTCTRL_TIMEOUTSTARTUP_SHIFT);
3048 
3049   if (wasLocked) {
3050     HFXO0->LOCK = ~HFXO_LOCK_LOCKKEY_UNLOCK;
3051   }
3052 }
3053 #endif
3054 
3055 #if defined(_HFXO_CTRL_PRSSTATUSSEL0_MASK)
3056 /**************************************************************************//**
3057  * @brief
3058  *   Initialize HFXO Bufout (Crystal sharing) follower control registers.
3059  *   Configure the clock request signal to a specified GPIO to automatically
3060  *   request the high frequency crystal oscillator sine wave clock.
3061  *   This function must be used in conjunction with CMU_HFXOInit() configured
3062  *   with EXTERNAL_SINE or EXTERNAL_SINEPKDET mode.
3063  *
3064  * @warning
3065  *   If EM2 capabilities are needed, a GPIO that fully retains its
3066  *   capabilities while in EM2 must be selected.
3067  *
3068  * @note
3069  *   This function can be emulated on XG21/XG22 chips by controlling the clock
3070  *   request GPIO to ask the crystal sharing leader clock when needed.
3071  *
3072  * @param[in] prsStatusSelectOutput
3073  *    Selected HFXO PRS signal output.
3074  *
3075  * @param[in] prsAsyncCh
3076  *    PRS producer asynchronous signal channel.
3077  *
3078  * @param[in] port
3079  *    Bufout request GPIO port.
3080  *
3081  * @param[in] pin
3082  *    Bufout request GPIO pin.
3083  *****************************************************************************/
CMU_HFXOCrystalSharingFollowerInit(CMU_PRS_Status_Output_Select_TypeDef prsStatusSelectOutput,unsigned int prsAsyncCh,GPIO_Port_TypeDef port,unsigned int pin)3084 void CMU_HFXOCrystalSharingFollowerInit(CMU_PRS_Status_Output_Select_TypeDef prsStatusSelectOutput,
3085                                         unsigned int                         prsAsyncCh,
3086                                         GPIO_Port_TypeDef                    port,
3087                                         unsigned int                         pin)
3088 {
3089   EFM_ASSERT(prsAsyncCh < PRS_ASYNC_CH_NUM);
3090   EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
3091 
3092   uint32_t mask = 0U, prsSignal = 0U, value = 0U;
3093 
3094   switch (prsStatusSelectOutput) {
3095     case PRS_Status_select_0:
3096       mask      = _HFXO_CTRL_PRSSTATUSSEL0_MASK;
3097       value     = _HFXO_CTRL_PRSSTATUSSEL0_ENS << _HFXO_CTRL_PRSSTATUSSEL0_SHIFT;
3098       prsSignal = _PRS_ASYNC_CH_CTRL_SIGSEL_HFXO0LSTATUS;
3099       break;
3100 
3101     case PRS_Status_select_1:
3102       mask      = _HFXO_CTRL_PRSSTATUSSEL1_MASK;
3103       value     = _HFXO_CTRL_PRSSTATUSSEL1_ENS << _HFXO_CTRL_PRSSTATUSSEL1_SHIFT;
3104       prsSignal = _PRS_ASYNC_CH_CTRL_SIGSEL_HFXO0LSTATUS1;
3105       break;
3106 
3107     default:
3108       EFM_ASSERT(false);
3109       break;
3110   }
3111 
3112   bool wasLocked = HFXO0->STATUS & HFXO_STATUS_LOCK_LOCKED ? true : false;
3113 
3114   // Unlock register interface.
3115   HFXO0->LOCK = HFXO_LOCK_LOCKKEY_UNLOCK;
3116 
3117   BUS_RegMaskedWrite(&HFXO0->CTRL, mask, value);
3118 
3119   if (wasLocked) {
3120     HFXO0->LOCK = ~HFXO_LOCK_LOCKKEY_UNLOCK;
3121   }
3122 
3123   value = _PRS_ASYNC_CH_CTRL_AUXSEL_DEFAULT     << _PRS_ASYNC_CH_CTRL_AUXSEL_SHIFT
3124           | _PRS_ASYNC_CH_CTRL_FNSEL_A          << _PRS_ASYNC_CH_CTRL_FNSEL_SHIFT
3125           | _PRS_ASYNC_CH_CTRL_SOURCESEL_HFXO0L << _PRS_ASYNC_CH_CTRL_SOURCESEL_SHIFT
3126           | prsSignal                           << _PRS_ASYNC_CH_CTRL_SIGSEL_SHIFT;
3127 
3128   mask = _PRS_ASYNC_CH_CTRL_AUXSEL_MASK
3129          | _PRS_ASYNC_CH_CTRL_FNSEL_MASK
3130          | _PRS_ASYNC_CH_CTRL_SOURCESEL_MASK
3131          | _PRS_ASYNC_CH_CTRL_SIGSEL_MASK;
3132 
3133   BUS_RegMaskedWrite(&(PRS->ASYNC_CH[prsAsyncCh].CTRL), mask, value);
3134 
3135   GPIO_PinModeSet(port, pin, gpioModeWiredOrPullDown, 0U);
3136 
3137   (&(GPIO->PRSROUTE[0].ASYNCH0ROUTE))[prsAsyncCh] = pin    << _GPIO_PRS_ASYNCH0ROUTE_PIN_SHIFT
3138                                                     | port << _GPIO_PRS_ASYNCH0ROUTE_PORT_SHIFT;
3139   GPIO->PRSROUTE[0].ROUTEEN = 1U << (_GPIO_PRS_ROUTEEN_ASYNCH0PEN_SHIFT + prsAsyncCh);
3140 }
3141 #endif
3142 
3143 /**************************************************************************//**
3144  * @brief
3145  *   Set the HFXO crystal tuning capacitance.
3146  *
3147  * @param[in] ctune
3148  *   The desired tuning capacitance value. Each step corresponds to
3149  *   approximately 80fF. Min value is 0. Max value is 255.
3150  *
3151  * @note
3152  *   While the oscillator is running in steady operation state, it may be
3153  *   desirable to modify the tuning capacitance via CTUNEXIANA and CTUNEXOANA
3154  *   fields in the HFXO_XTALCTRL register. When tuning, care should be taken to
3155  *   make small changes to the CTUNE registers. Ideally, change the CTUNE
3156  *   registers by one LSB at a time and alternate between the XI and XO
3157  *   registers. Sufficient wait time for settling, on the order of
3158  *   TIMEOUTSTEADY, should pass before new frequency measurement is taken.
3159  *****************************************************************************/
CMU_HFXOCTuneSet(uint32_t ctune)3160 void CMU_HFXOCTuneSet(uint32_t ctune)
3161 {
3162   uint32_t hfxoCtrlBkup;
3163 
3164   // Make sure the given CTUNE value is within the allowable range
3165   EFM_ASSERT(ctune <= (_HFXO_XTALCTRL_CTUNEXIANA_MASK >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT));
3166 
3167   hfxoCtrlBkup = HFXO0->CTRL;
3168 
3169   // These two bits need to be set to allow writing the ctune register
3170   HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
3171   while ((HFXO0->STATUS & HFXO_STATUS_COREBIASOPTRDY) == 0) {
3172     // Wait for crystal to startup
3173   }
3174 
3175   HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
3176 
3177 #if defined(HFXO_CMD_MANUALOVERRIDE)
3178   HFXO0->CMD_SET = HFXO_CMD_MANUALOVERRIDE;
3179 #endif
3180 
3181 #if defined(HFXO_STATUS_FSMLOCK)
3182   while ((HFXO0->STATUS & HFXO_STATUS_FSMLOCK) != 0) {
3183     // Wait for crystal to switch modes.
3184   }
3185 #endif
3186 
3187   int32_t ctuneXoana = ctune + CMU_HFXOCTuneDeltaGet();
3188   if (ctuneXoana < 0) {
3189     ctuneXoana = 0;
3190   } else if (ctuneXoana > (int32_t)(_HFXO_XTALCTRL_CTUNEXOANA_MASK >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT)) {
3191     ctuneXoana = (int32_t)(_HFXO_XTALCTRL_CTUNEXOANA_MASK >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT); // Max value
3192   }
3193 
3194   HFXO0->XTALCTRL = ((HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXOANA_MASK | _HFXO_XTALCTRL_CTUNEXIANA_MASK))
3195                      | ((uint32_t)ctuneXoana << _HFXO_XTALCTRL_CTUNEXOANA_SHIFT)
3196                      | ((ctune << _HFXO_XTALCTRL_CTUNEXIANA_SHIFT) & _HFXO_XTALCTRL_CTUNEXIANA_MASK));
3197 
3198   HFXO0->CTRL = hfxoCtrlBkup;
3199 }
3200 
3201 /**************************************************************************//**
3202  * @brief
3203  *   Get the HFXO crystal tuning capacitance.
3204  *
3205  * @return
3206  *   The HFXO crystal tuning capacitance.
3207  *
3208  * @note
3209      This function only returns the CTUNE XI value. The XO value can be
3210      different and can be found using the delta (difference between XI and XO).
3211      See @ref CMU_HFXOCTuneDeltaGet to retrieve the delta value.
3212  *****************************************************************************/
CMU_HFXOCTuneGet(void)3213 uint32_t CMU_HFXOCTuneGet(void)
3214 {
3215   return ((HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXIANA_MASK)
3216           >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT);
3217 }
3218 
3219 /**************************************************************************//**
3220  * @brief
3221  *   Set the HFXO crystal tuning delta.
3222  *
3223  * @param[in] delta
3224  *    Chip dependent crystal capacitor bank delta between HFXO XI and XO.
3225  *
3226  * @note
3227  *   The delta between XI and XO is applicable for the series 2 EFR32xG2x
3228  *   devices only.
3229  *****************************************************************************/
CMU_HFXOCTuneDeltaSet(int32_t delta)3230 void CMU_HFXOCTuneDeltaSet(int32_t delta)
3231 {
3232   ctuneDelta = (int8_t)delta;
3233 }
3234 
3235 /**************************************************************************//**
3236  * @brief
3237  *   Get the HFXO crystal tuning delta.
3238  *
3239  * @return
3240  *   Chip dependent crystal capacitor bank tuning delta.
3241  *****************************************************************************/
CMU_HFXOCTuneDeltaGet(void)3242 int32_t CMU_HFXOCTuneDeltaGet(void)
3243 {
3244   return (int32_t)ctuneDelta;
3245 }
3246 
3247 /**************************************************************************//**
3248  * @brief
3249  *   Initialize LFXO control registers.
3250  *
3251  * @note
3252  *   LFXO configuration should be obtained from a configuration tool,
3253  *   app note or crystal datasheet. This function disables the LFXO to ensure
3254  *   a valid state before update.
3255  *
3256  * @param[in] lfxoInit
3257  *    LFXO setup parameters
3258  *****************************************************************************/
CMU_LFXOInit(const CMU_LFXOInit_TypeDef * lfxoInit)3259 void CMU_LFXOInit(const CMU_LFXOInit_TypeDef *lfxoInit)
3260 {
3261   EFM_ASSERT(lfxoInit->timeout
3262              <= (_LFXO_CFG_TIMEOUT_MASK  >> _LFXO_CFG_TIMEOUT_SHIFT));
3263   EFM_ASSERT(lfxoInit->mode
3264              <= (_LFXO_CFG_MODE_MASK >> _LFXO_CFG_MODE_SHIFT));
3265   EFM_ASSERT(lfxoInit->gain
3266              <= (_LFXO_CAL_GAIN_MASK >> _LFXO_CAL_GAIN_SHIFT));
3267   EFM_ASSERT(lfxoInit->capTune
3268              <= (_LFXO_CAL_CAPTUNE_MASK >> _LFXO_CAL_CAPTUNE_SHIFT));
3269 
3270   // Max internal capacitance tuning value is 0x4F (20 pF)
3271   uint8_t ctune = (uint8_t) SL_MIN(0x4FU, lfxoInit->capTune);
3272 
3273 #if defined(CMU_CLKEN0_LFXO)
3274   // Enable LFXO module clock.
3275   CMU->CLKEN0_SET = CMU_CLKEN0_LFXO;
3276 #endif
3277 
3278   // Unlock register interface
3279   LFXO->LOCK = LFXO_LOCK_LOCKKEY_UNLOCK;
3280 
3281   // Disable LFXO
3282   LFXO->CTRL_SET = LFXO_CTRL_DISONDEMAND;
3283   LFXO->CTRL_CLR = LFXO_CTRL_FORCEEN;
3284   while ((LFXO->STATUS & _LFXO_STATUS_ENS_MASK) != 0U) {
3285   }
3286 
3287   // Configure LFXO as specified
3288   LFXO->CAL = ((uint32_t)lfxoInit->gain  << _LFXO_CAL_GAIN_SHIFT)
3289               | ((uint32_t)ctune         << _LFXO_CAL_CAPTUNE_SHIFT);
3290 
3291   LFXO->CFG = (uint32_t)((lfxoInit->timeout           << _LFXO_CFG_TIMEOUT_SHIFT)
3292                          | (lfxoInit->mode            << _LFXO_CFG_MODE_SHIFT)
3293                          | (lfxoInit->highAmplitudeEn << _LFXO_CFG_HIGHAMPL_SHIFT)
3294                          | (lfxoInit->agcEn           << _LFXO_CFG_AGC_SHIFT));
3295 
3296   LFXO->CTRL = (uint32_t)((lfxoInit->failDetEM4WUEn   << _LFXO_CTRL_FAILDETEM4WUEN_SHIFT)
3297                           | (lfxoInit->failDetEn      << _LFXO_CTRL_FAILDETEN_SHIFT)
3298                           | (lfxoInit->disOnDemand    << _LFXO_CTRL_DISONDEMAND_SHIFT)
3299                           | (lfxoInit->forceEn        << _LFXO_CTRL_FORCEEN_SHIFT));
3300 
3301   if (lfxoInit->regLock) {
3302     LFXO->LOCK = ~LFXO_LOCK_LOCKKEY_UNLOCK;
3303   }
3304 }
3305 
3306 /**************************************************************************//**
3307  * @brief
3308  *   Sets LFXO's crystal precision, in PPM.
3309  *
3310  * @note
3311  *   LFXO precision should be obtained from a crystal datasheet.
3312  *
3313  * @param[in] precision
3314  *    LFXO's crystal precision, in PPM.
3315  *****************************************************************************/
CMU_LFXOPrecisionSet(uint16_t precision)3316 void CMU_LFXOPrecisionSet(uint16_t precision)
3317 {
3318   lfxo_precision = precision;
3319 }
3320 
3321 /**************************************************************************//**
3322  * @brief
3323  *   Gets LFXO's crystal precision, in PPM.
3324  *
3325  * @param[in] precision
3326  *    LFXO's crystal precision, in PPM.
3327  *****************************************************************************/
CMU_LFXOPrecisionGet(void)3328 uint16_t CMU_LFXOPrecisionGet(void)
3329 {
3330   return lfxo_precision;
3331 }
3332 
3333 #if defined(PLFRCO_PRESENT)
3334 /**************************************************************************//**
3335  * @brief
3336  *   Configure the LFRCO precision.
3337  *
3338  * @details
3339  *   When enabling high precision mode on the LFRCO the hardware will tune
3340  *   the oscillator automatically using the HFXO as a reference.
3341  *
3342  * @note
3343  *   Refer to the reference manual and the datasheet for details about
3344  *   NOMCAL and NOMCALINV calibration count values.
3345  *
3346  * @param[in] precision
3347  *    LFRCO precision, this can be either high or default.
3348  *****************************************************************************/
CMU_LFRCOSetPrecision(CMU_Precision_TypeDef precision)3349 void CMU_LFRCOSetPrecision(CMU_Precision_TypeDef precision)
3350 {
3351   uint32_t ref = 0;
3352   uint32_t nomcal = 0;
3353   uint32_t nomcalinv = 0;
3354 
3355   CMU->CLKEN0_SET = CMU_CLKEN0_LFRCO;
3356 
3357   LFRCO->CTRL = LFRCO_CTRL_DISONDEMAND; // Force disable
3358   while ((LFRCO->STATUS & LFRCO_STATUS_ENS) != 0U) {
3359     // Wait for LFRCO to stop
3360   }
3361 
3362   if (precision == cmuPrecisionHigh) {
3363     ref = SystemHFXOClockGet();
3364     // Use precomputed value for HFXO typical frequencies
3365     if (ref == XTAL_38M4) {
3366       nomcal = LFRCO_NOMCAL_XTAL_38M4;
3367       nomcalinv = LFRCO_NOMCALINV_XTAL_38M4;
3368     } else if (ref == XTAL_39M0) {
3369       nomcal = LFRCO_NOMCAL_XTAL_39M0;
3370       nomcalinv = LFRCO_NOMCALINV_XTAL_39M0;
3371     } else {
3372       // Compute calibration count, based on HFXO frequency
3373       nomcal = (5 * ref) >> 9;
3374       nomcalinv = ((1UL << 31) / 5) << 2;
3375       nomcalinv /= (ref >> 9);
3376     }
3377 
3378     LFRCO->NOMCAL = nomcal;
3379     LFRCO->NOMCALINV = nomcalinv;
3380 
3381     LFRCO->CFG = LFRCO_CFG_HIGHPRECEN;
3382   } else {
3383     LFRCO->CFG = 0;
3384   }
3385   LFRCO->CTRL = _LFRCO_CTRL_RESETVALUE;
3386 }
3387 #endif
3388 
3389 /***************************************************************************//**
3390  * @brief
3391  *   Get oscillator frequency tuning setting.
3392  *
3393  * @param[in] osc
3394  *   Oscillator to get tuning value for.
3395  *
3396  * @return
3397  *   The oscillator frequency tuning setting in use.
3398  ******************************************************************************/
CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)3399 uint32_t CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)
3400 {
3401   uint32_t ret = 0U;
3402 
3403   switch (osc) {
3404 #if defined(_LFRCO_CAL_FREQTRIM_MASK)
3405     case cmuOsc_LFRCO:
3406 #if defined(CMU_CLKEN0_LFRCO)
3407       CMU->CLKEN0_SET = CMU_CLKEN0_LFRCO;
3408 #endif
3409       ret = (LFRCO->CAL & _LFRCO_CAL_FREQTRIM_MASK) >> _LFRCO_CAL_FREQTRIM_SHIFT;
3410       break;
3411 #endif
3412 
3413     case cmuOsc_HFRCODPLL:
3414 #if defined(CMU_CLKEN0_HFRCO0)
3415       CMU->CLKEN0_SET = CMU_CLKEN0_HFRCO0;
3416 #endif
3417       ret = (HFRCO0->CAL & _HFRCO_CAL_TUNING_MASK) >> _HFRCO_CAL_TUNING_SHIFT;
3418       break;
3419 
3420 #if defined(HFRCOEM23_PRESENT)
3421     case cmuOsc_HFRCOEM23:
3422       ret = (HFRCOEM23->CAL & _HFRCO_CAL_TUNING_MASK) >> _HFRCO_CAL_TUNING_SHIFT;
3423       break;
3424 #endif
3425 
3426     case cmuOsc_HFXO:
3427 #if defined(CMU_CLKEN0_HFXO0)
3428       CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
3429 #endif
3430       ret = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_COREBIASANA_MASK) >> _HFXO_XTALCTRL_COREBIASANA_SHIFT;
3431       break;
3432 
3433     default:
3434       EFM_ASSERT(false);
3435       break;
3436   }
3437 
3438   return ret;
3439 }
3440 
3441 /***************************************************************************//**
3442  * @brief
3443  *   Set the oscillator frequency tuning control.
3444  *
3445  * @note
3446  *   Oscillator tuning is done during production, and the tuning value is
3447  *   automatically loaded after a reset. Changing the tuning value from the
3448  *   calibrated value is for more advanced use. Certain oscillators also have
3449  *   build-in tuning optimization.
3450  *
3451  * @param[in] osc
3452  *   Oscillator to set tuning value for.
3453  *
3454  * @param[in] val
3455  *   The oscillator frequency tuning setting to use.
3456  ******************************************************************************/
CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc,uint32_t val)3457 void CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc, uint32_t val)
3458 {
3459   bool disondemand = false;
3460 
3461   switch (osc) {
3462 #if defined(_LFRCO_CAL_FREQTRIM_MASK)
3463     case cmuOsc_LFRCO:
3464 #if defined(CMU_CLKEN0_LFRCO)
3465       CMU->CLKEN0_SET = CMU_CLKEN0_LFRCO;
3466 #endif
3467       EFM_ASSERT(val <= (_LFRCO_CAL_FREQTRIM_MASK
3468                          >> _LFRCO_CAL_FREQTRIM_SHIFT));
3469       val &= _LFRCO_CAL_FREQTRIM_MASK >> _LFRCO_CAL_FREQTRIM_SHIFT;
3470       while (LFRCO->SYNCBUSY != 0U) {
3471       }
3472       LFRCO->CAL = (LFRCO->CAL & ~_LFRCO_CAL_FREQTRIM_MASK)
3473                    | (val << _LFRCO_CAL_FREQTRIM_SHIFT);
3474       break;
3475 #endif
3476 
3477     case cmuOsc_HFRCODPLL:
3478 #if defined(CMU_CLKEN0_HFRCO0)
3479       CMU->CLKEN0_SET = CMU_CLKEN0_HFRCO0;
3480 #endif
3481       EFM_ASSERT(val <= (_HFRCO_CAL_TUNING_MASK >> _HFRCO_CAL_TUNING_SHIFT));
3482       val &= _HFRCO_CAL_TUNING_MASK >> _HFRCO_CAL_TUNING_SHIFT;
3483       while ((HFRCO0->STATUS & HFRCO_STATUS_SYNCBUSY) != 0UL) {
3484       }
3485       HFRCO0->CAL = (HFRCO0->CAL & ~_HFRCO_CAL_TUNING_MASK)
3486                     | (val << _HFRCO_CAL_TUNING_SHIFT);
3487       break;
3488 
3489 #if defined(HFRCOEM23_PRESENT)
3490     case cmuOsc_HFRCOEM23:
3491       EFM_ASSERT(val <= (_HFRCO_CAL_TUNING_MASK >> _HFRCO_CAL_TUNING_SHIFT));
3492       val &= _HFRCO_CAL_TUNING_MASK >> _HFRCO_CAL_TUNING_SHIFT;
3493       while ((HFRCOEM23->STATUS & HFRCO_STATUS_SYNCBUSY) != 0UL) {
3494       }
3495       HFRCOEM23->CAL = (HFRCOEM23->CAL & ~_HFRCO_CAL_TUNING_MASK)
3496                        | (val << _HFRCO_CAL_TUNING_SHIFT);
3497       break;
3498 #endif
3499 
3500     case cmuOsc_HFXO:
3501 #if defined(CMU_CLKEN0_HFXO0)
3502       CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
3503 #endif
3504       EFM_ASSERT(val <= (_HFXO_XTALCTRL_COREBIASANA_MASK >> _HFXO_XTALCTRL_COREBIASANA_SHIFT));
3505       // Make sure HFXO is disable
3506       EFM_ASSERT((HFXO0->STATUS & HFXO_STATUS_ENS) == 0);
3507 
3508       // Set DISONDEMAND if not already set and wait for FSMLOCK to be clear so that
3509       // software can write to register
3510       disondemand = (HFXO0->CTRL & _HFXO_CTRL_DISONDEMAND_MASK) >> _HFXO_CTRL_DISONDEMAND_SHIFT;
3511       if (disondemand == false) {
3512         HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
3513       }
3514 #if defined(HFXO_STATUS_FSMLOCK)
3515       while ((HFXO0->STATUS & HFXO_STATUS_FSMLOCK) != 0) {
3516       }
3517 #endif
3518       // Update Core Bias Ana setting and enable Optimization skip
3519       HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK)
3520                         | (val << _HFXO_XTALCTRL_COREBIASANA_SHIFT)
3521                         | HFXO_XTALCTRL_SKIPCOREBIASOPT;
3522       // Clear back DISONDEMAND if needed
3523       if (disondemand == false) {
3524         HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
3525       }
3526       break;
3527 
3528     default:
3529       EFM_ASSERT(false);
3530       break;
3531   }
3532 }
3533 
3534 /***************************************************************************//**
3535  * @brief
3536  *   Configure wait state settings necessary to switch to a given core clock
3537  *   frequency at a certain voltage scale level.
3538  *
3539  * @details
3540  *   This function will set up the necessary flash wait states. Updating the
3541  *   wait state configuration must be done before increasing the clock
3542  *   frequency and it must be done after decreasing the clock frequency.
3543  *   Updating the wait state configuration must be done before core voltage is
3544  *   decreased and it must be done after a core voltage is increased.
3545  *
3546  * @param[in] freq
3547  *   The core clock frequency to configure wait-states.
3548  *
3549  * @param[in] vscale
3550  *   The voltage scale to configure wait-states. Expected values are
3551  *   0 or 1, higher number is lower voltage.
3552  *   @li 0 = 1.1 V (VSCALE2)
3553  *   @li 1 = 1.0 V (VSCALE1)
3554  ******************************************************************************/
CMU_UpdateWaitStates(uint32_t freq,int vscale)3555 void CMU_UpdateWaitStates(uint32_t freq, int vscale)
3556 {
3557   if (vscale > 0) {
3558     flashWaitStateControl(freq, VSCALE_EM01_LOW_POWER);
3559   } else {
3560     flashWaitStateControl(freq, VSCALE_EM01_HIGH_PERFORMANCE);
3561   }
3562 }
3563 
3564 /**************************************************************************//**
3565  * @brief
3566  *   Select the PCNTn clock.
3567  *
3568  * @param[in] instance
3569  *   PCNT instance number to set selected clock source for.
3570  *
3571  * @param[in] external
3572  *   Set to true to select the external clock, false to select EM23GRPACLK.
3573  *****************************************************************************/
CMU_PCNTClockExternalSet(unsigned int instance,bool external)3574 void CMU_PCNTClockExternalSet(unsigned int instance, bool external)
3575 {
3576   (void)instance;
3577 #if defined(PCNT_PRESENT)
3578   if (external) {
3579     CMU->PCNT0CLKCTRL = CMU_PCNT0CLKCTRL_CLKSEL_PCNTS0;
3580   } else {
3581     CMU->PCNT0CLKCTRL = CMU_PCNT0CLKCTRL_CLKSEL_EM23GRPACLK;
3582   }
3583 #else
3584   (void)external;
3585 #endif
3586 }
3587 
3588 #if defined(HFRCOEM23_PRESENT)
3589 /***************************************************************************//**
3590  * @brief
3591  *   Get HFRCOEM23 band in use.
3592  *
3593  * @return
3594  *   HFRCOEM23 band in use.
3595  ******************************************************************************/
CMU_HFRCOEM23BandGet(void)3596 CMU_HFRCOEM23Freq_TypeDef CMU_HFRCOEM23BandGet(void)
3597 {
3598   return (CMU_HFRCOEM23Freq_TypeDef)SystemHFRCOEM23ClockGet();
3599 }
3600 
3601 /***************************************************************************//**
3602  * @brief
3603  *   Set HFRCOEM23 band and the tuning value based on the value in the
3604  *   calibration table made during production.
3605  *
3606  * @param[in] freq
3607  *   HFRCOEM23 frequency band to activate.
3608  ******************************************************************************/
CMU_HFRCOEM23BandSet(CMU_HFRCOEM23Freq_TypeDef freq)3609 void CMU_HFRCOEM23BandSet(CMU_HFRCOEM23Freq_TypeDef freq)
3610 {
3611   uint32_t freqCal;
3612 
3613   // Get calibration data from DEVINFO
3614   freqCal = HFRCOEM23DevinfoGet(freq);
3615   EFM_ASSERT((freqCal != 0UL) && (freqCal != UINT_MAX));
3616 #if defined(CMU_CLKEN0_HFRCOEM23)
3617   CMU->CLKEN0_SET = CMU_CLKEN0_HFRCOEM23;
3618 #endif
3619 
3620   // Set divider for 1, 2 and 4MHz bands
3621   freqCal &= ~_HFRCO_CAL_CLKDIV_MASK;
3622   switch (freq) {
3623     case cmuHFRCOEM23Freq_1M0Hz:
3624       freqCal |= HFRCO_CAL_CLKDIV_DIV4;
3625       break;
3626 
3627     case cmuHFRCOEM23Freq_2M0Hz:
3628       freqCal |= HFRCO_CAL_CLKDIV_DIV2;
3629       break;
3630 
3631     default:
3632       break;
3633   }
3634 
3635   // Activate new band selection
3636   HFRCOEM23->CAL = freqCal;
3637 }
3638 #endif // defined(HFRCOEM23_PRESENT)
3639 
3640 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
3641 
3642 /*******************************************************************************
3643  **************************   LOCAL FUNCTIONS   ********************************
3644  ******************************************************************************/
3645 
3646 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
3647 #if defined(PDM_PRESENT)
3648 /***************************************************************************//**
3649  * @brief
3650  *   Get selected oscillator and frequency for @ref cmuClock_EM01GRPBCLK
3651  *   clock tree.
3652  *
3653  * @param[out] freq
3654  *   The frequency.
3655  *
3656  * @param[out] sel
3657  *   The selected oscillator.
3658  ******************************************************************************/
em01GrpbClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)3659 static void em01GrpbClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
3660 {
3661   uint32_t f = 0U;
3662   CMU_Select_TypeDef s;
3663   switch (CMU->EM01GRPBCLKCTRL & _CMU_EM01GRPBCLKCTRL_CLKSEL_MASK) {
3664     case CMU_EM01GRPBCLKCTRL_CLKSEL_HFRCODPLL:
3665       f = SystemHFRCODPLLClockGet();
3666       s = cmuSelect_HFRCODPLL;
3667       break;
3668 
3669     case CMU_EM01GRPBCLKCTRL_CLKSEL_HFRCODPLLRT:
3670       f = SystemHFRCODPLLClockGet();
3671       s = cmuSelect_HFRCODPLLRT;
3672       break;
3673 
3674     case CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO:
3675       f = SystemHFXOClockGet();
3676       s = cmuSelect_HFXO;
3677       break;
3678 
3679     case CMU_EM01GRPBCLKCTRL_CLKSEL_HFXORT:
3680       f = SystemHFXOClockGet();
3681       s = cmuSelect_HFXORT;
3682       break;
3683 
3684     case CMU_EM01GRPBCLKCTRL_CLKSEL_FSRCO:
3685       f = SystemFSRCOClockGet();
3686       s = cmuSelect_FSRCO;
3687       break;
3688 
3689     case CMU_EM01GRPBCLKCTRL_CLKSEL_CLKIN0:
3690       f = SystemCLKIN0Get();
3691       s = cmuSelect_CLKIN0;
3692       break;
3693 
3694     default:
3695       s = cmuSelect_Error;
3696       EFM_ASSERT(false);
3697       break;
3698   }
3699   if (freq != NULL) {
3700     *freq = f;
3701   }
3702   if (sel != NULL) {
3703     *sel = s;
3704   }
3705 }
3706 #endif
3707 
3708 #if defined(EUART_PRESENT)
3709 /***************************************************************************//**
3710  * @brief
3711  *   Get selected oscillator and frequency for @ref cmuClock_EUART0CLK
3712  *   clock tree.
3713  *
3714  * @param[out] freq
3715  *   The frequency.
3716  *
3717  * @param[out] sel
3718  *   The selected oscillator.
3719  ******************************************************************************/
euart0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)3720 static void euart0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
3721 {
3722   switch (CMU->EUART0CLKCTRL & _CMU_EUART0CLKCTRL_CLKSEL_MASK) {
3723     case CMU_EUART0CLKCTRL_CLKSEL_EM01GRPACLK:
3724       em01GrpaClkGet(freq, sel);
3725       break;
3726 
3727     case CMU_EUART0CLKCTRL_CLKSEL_EM23GRPACLK:
3728       em23GrpaClkGet(freq, sel);
3729       break;
3730 
3731     default:
3732       if (freq != NULL) {
3733         *freq = 0U;
3734       }
3735       if (sel != NULL) {
3736         *sel = cmuSelect_Error;
3737       }
3738       EFM_ASSERT(false);
3739       break;
3740   }
3741 }
3742 #endif
3743 
3744 #if defined(EUSART_PRESENT)
3745 /***************************************************************************//**
3746  * @brief
3747  *   Get selected oscillator and frequency for @ref cmuClock_EUSART0CLK
3748  *   clock tree.
3749  *
3750  * @param[out] freq
3751  *   The frequency.
3752  *
3753  * @param[out] sel
3754  *   The selected oscillator.
3755  ******************************************************************************/
eusart0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)3756 static void eusart0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
3757 {
3758   uint32_t f = 0U;
3759   CMU_Select_TypeDef s;
3760 
3761   switch (CMU->EUSART0CLKCTRL & _CMU_EUSART0CLKCTRL_CLKSEL_MASK) {
3762 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPACLK)
3763     case CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPACLK:
3764       em01GrpaClkGet(&f, NULL);
3765       s = cmuSelect_EM01GRPACLK;
3766       break;
3767 #endif
3768 
3769 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK)
3770     case CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK:
3771       em01GrpcClkGet(&f, NULL);
3772       s = cmuSelect_EM01GRPCCLK;
3773       break;
3774 #endif
3775 
3776 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_EM23GRPACLK)
3777     case CMU_EUSART0CLKCTRL_CLKSEL_EM23GRPACLK:
3778       em23GrpaClkGet(&f, NULL);
3779       s = cmuSelect_EM23GRPACLK;
3780       break;
3781 #endif
3782 
3783 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_FSRCO)
3784     case CMU_EUSART0CLKCTRL_CLKSEL_FSRCO:
3785       f = SystemFSRCOClockGet();
3786       s = cmuSelect_FSRCO;
3787       break;
3788 #endif
3789 
3790 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_HFRCOEM23)
3791     case CMU_EUSART0CLKCTRL_CLKSEL_HFRCOEM23:
3792       f = SystemHFRCOEM23ClockGet();
3793       s = cmuSelect_HFRCOEM23;
3794       break;
3795 #endif
3796 
3797 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_LFRCO)
3798     case CMU_EUSART0CLKCTRL_CLKSEL_LFRCO:
3799       f = SystemLFRCOClockGet();
3800       s = cmuSelect_LFRCO;
3801       break;
3802 #endif
3803 
3804 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_LFXO)
3805     case CMU_EUSART0CLKCTRL_CLKSEL_LFXO:
3806       f = SystemLFXOClockGet();
3807       s = cmuSelect_LFXO;
3808       break;
3809 #endif
3810 
3811     default:
3812       s = cmuSelect_Error;
3813       EFM_ASSERT(false);
3814       break;
3815   }
3816   if (freq != NULL) {
3817     *freq = f;
3818   }
3819   if (sel != NULL) {
3820     *sel = s;
3821   }
3822 }
3823 
3824 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
3825 /**************************************************************************//**
3826 * @brief
3827 *   Get selected oscillator and frequency for @ref cmuClock_EM01GRPCCLK
3828 *   clock tree.
3829 *
3830 * @param[out] freq
3831 *   The frequency.
3832 *
3833 * @param[out] sel
3834 *   The selected oscillator.
3835 ******************************************************************************/
em01GrpcClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)3836 static void em01GrpcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
3837 {
3838   uint32_t f = 0U;
3839   CMU_Select_TypeDef s;
3840 
3841   switch (CMU->EM01GRPCCLKCTRL & _CMU_EM01GRPCCLKCTRL_CLKSEL_MASK) {
3842     case CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLL:
3843       f = SystemHFRCODPLLClockGet();
3844       s = cmuSelect_HFRCODPLL;
3845       break;
3846 
3847 #if defined(CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLLRT)
3848     case CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLLRT:
3849       f = SystemHFRCODPLLClockGet();
3850       s = cmuSelect_HFRCODPLLRT;
3851       break;
3852 #endif
3853 
3854     case _CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCOEM23:
3855       f = SystemHFRCOEM23ClockGet();
3856       s = cmuSelect_HFRCOEM23;
3857       break;
3858 
3859     case CMU_EM01GRPCCLKCTRL_CLKSEL_HFXO:
3860       f = SystemHFXOClockGet();
3861       s = cmuSelect_HFXO;
3862       break;
3863 
3864 #if defined(CMU_EM01GRPCCLKCTRL_CLKSEL_HFXORT)
3865     case CMU_EM01GRPCCLKCTRL_CLKSEL_HFXORT:
3866       f = SystemHFXOClockGet();
3867       s = cmuSelect_HFXORT;
3868       break;
3869 #endif
3870 
3871     case _CMU_EM01GRPCCLKCTRL_CLKSEL_FSRCO:
3872       f = SystemFSRCOClockGet();
3873       s = cmuSelect_FSRCO;
3874       break;
3875 
3876     default:
3877       s = cmuSelect_Error;
3878       EFM_ASSERT(false);
3879       break;
3880   }
3881   if (freq != NULL) {
3882     *freq = f;
3883   }
3884   if (sel != NULL) {
3885     *sel = s;
3886   }
3887 }
3888 #endif // defined(_CMU_EM01GRPCCLKCTRL_MASK)
3889 #endif // defined(EUSART_PRESENT)
3890 
3891 #if defined(LCD_PRESENT)
3892 /***************************************************************************//**
3893  * @brief
3894  *   Get selected oscillator and frequency for @ref cmuClock_LCDCLK
3895  *   clock tree.
3896  *
3897  * @param[out] freq
3898  *   The frequency.
3899  *
3900  * @param[out] sel
3901  *   The selected oscillator.
3902  ******************************************************************************/
lcdClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)3903 static void lcdClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
3904 {
3905   uint32_t f = 0U;
3906   CMU_Select_TypeDef s;
3907 
3908   switch (CMU->LCDCLKCTRL & _CMU_LCDCLKCTRL_CLKSEL_MASK) {
3909     case CMU_LCDCLKCTRL_CLKSEL_ULFRCO:
3910       f = SystemULFRCOClockGet();
3911       s = cmuSelect_ULFRCO;
3912       break;
3913 
3914     case CMU_LCDCLKCTRL_CLKSEL_LFRCO:
3915       f = SystemLFRCOClockGet();
3916       s = cmuSelect_LFRCO;
3917       break;
3918 
3919     case CMU_LCDCLKCTRL_CLKSEL_LFXO:
3920       f = SystemLFXOClockGet();
3921       s = cmuSelect_LFXO;
3922       break;
3923 
3924     default:
3925       s = cmuSelect_Error;
3926       EFM_ASSERT(false);
3927       break;
3928   }
3929   if (freq != NULL) {
3930     *freq = f;
3931   }
3932   if (sel != NULL) {
3933     *sel = s;
3934   }
3935 }
3936 #endif // defined(LCD_PRESENT)
3937 
3938 #if defined(VDAC_PRESENT)
3939 /***************************************************************************//**
3940  * @brief
3941  *   Get selected oscillator and frequency for @ref cmuClock_VDAC0CLK
3942  *   clock tree.
3943  *
3944  * @param[out] freq
3945  *   The frequency.
3946  *
3947  * @param[out] sel
3948  *   The selected oscillator.
3949  ******************************************************************************/
vdac0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)3950 static void vdac0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
3951 {
3952   uint32_t f = 0U;
3953   CMU_Select_TypeDef s;
3954 
3955   switch (CMU->VDAC0CLKCTRL & _CMU_VDAC0CLKCTRL_CLKSEL_MASK) {
3956     case CMU_VDAC0CLKCTRL_CLKSEL_EM01GRPACLK:
3957       em01GrpaClkGet(&f, NULL);
3958       s = cmuSelect_EM01GRPACLK;
3959       break;
3960 
3961     case CMU_VDAC0CLKCTRL_CLKSEL_EM23GRPACLK:
3962       em23GrpaClkGet(&f, NULL);
3963       s = cmuSelect_EM23GRPACLK;
3964       break;
3965 
3966     case CMU_VDAC0CLKCTRL_CLKSEL_HFRCOEM23:
3967       f = SystemHFRCOEM23ClockGet();
3968       s = cmuSelect_HFRCOEM23;
3969       break;
3970 
3971     case CMU_VDAC0CLKCTRL_CLKSEL_FSRCO:
3972       f = SystemFSRCOClockGet();
3973       s = cmuSelect_FSRCO;
3974       break;
3975 
3976     default:
3977       s = cmuSelect_Error;
3978       EFM_ASSERT(false);
3979       break;
3980   }
3981   if (freq != NULL) {
3982     *freq = f;
3983   }
3984   if (sel != NULL) {
3985     *sel = s;
3986   }
3987 }
3988 
3989 #if (VDAC_COUNT > 1)
3990 /***************************************************************************//**
3991  * @brief
3992  *   Get selected oscillator and frequency for @ref cmuClock_VDAC1CLK
3993  *   clock tree.
3994  *
3995  * @param[out] freq
3996  *   The frequency.
3997  *
3998  * @param[out] sel
3999  *   The selected oscillator.
4000  ******************************************************************************/
vdac1ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4001 static void vdac1ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4002 {
4003   uint32_t f = 0U;
4004   CMU_Select_TypeDef s;
4005 
4006   switch (CMU->VDAC1CLKCTRL & _CMU_VDAC1CLKCTRL_CLKSEL_MASK) {
4007     case CMU_VDAC1CLKCTRL_CLKSEL_EM01GRPACLK:
4008       em01GrpaClkGet(&f, NULL);
4009       s = cmuSelect_EM01GRPACLK;
4010       break;
4011 
4012     case CMU_VDAC1CLKCTRL_CLKSEL_EM23GRPACLK:
4013       em23GrpaClkGet(&f, NULL);
4014       s = cmuSelect_EM23GRPACLK;
4015       break;
4016 
4017     case CMU_VDAC1CLKCTRL_CLKSEL_HFRCOEM23:
4018       f = SystemHFRCOEM23ClockGet();
4019       s = cmuSelect_HFRCOEM23;
4020       break;
4021 
4022     case CMU_VDAC1CLKCTRL_CLKSEL_FSRCO:
4023       f = SystemFSRCOClockGet();
4024       s = cmuSelect_FSRCO;
4025       break;
4026 
4027     default:
4028       s = cmuSelect_Error;
4029       EFM_ASSERT(false);
4030       break;
4031   }
4032   if (freq != NULL) {
4033     *freq = f;
4034   }
4035   if (sel != NULL) {
4036     *sel = s;
4037   }
4038 }
4039 #endif
4040 #endif /* VDAC_PRESENT */
4041 
4042 #if defined(PCNT_PRESENT)
4043 /***************************************************************************//**
4044  * @brief
4045  *   Get selected oscillator and frequency for @ref cmuClock_PCNT0CLK
4046  *   clock tree.
4047  *
4048  * @param[out] freq
4049  *   The frequency.
4050  *
4051  * @param[out] sel
4052  *   The selected oscillator.
4053  ******************************************************************************/
pcnt0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4054 static void pcnt0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4055 {
4056   uint32_t f = 0U;
4057   CMU_Select_TypeDef s;
4058 
4059   switch (CMU->PCNT0CLKCTRL & _CMU_PCNT0CLKCTRL_CLKSEL_MASK) {
4060     case CMU_PCNT0CLKCTRL_CLKSEL_EM23GRPACLK:
4061       em23GrpaClkGet(&f, NULL);
4062       s = cmuSelect_EM23GRPACLK;
4063       break;
4064 
4065     case CMU_PCNT0CLKCTRL_CLKSEL_PCNTS0:
4066       f = 0U; // external or PRS source so the frequency is undefined.
4067       s = cmuSelect_PCNTEXTCLK;
4068       break;
4069 
4070     default:
4071       s = cmuSelect_Error;
4072       EFM_ASSERT(false);
4073       break;
4074   }
4075   if (freq != NULL) {
4076     *freq = f;
4077   }
4078   if (sel != NULL) {
4079     *sel = s;
4080   }
4081 }
4082 #endif
4083 
4084 #if defined(LESENSE_PRESENT)
4085 /***************************************************************************//**
4086  * @brief
4087  *   Get selected oscillator and frequency for @ref cmuClock_LESENSEHFCLK
4088  *   clock tree.
4089  *
4090  * @param[out] freq
4091  *   The frequency.
4092  *
4093  * @param[out] sel
4094  *   The selected oscillator.
4095  ******************************************************************************/
lesenseHFClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4096 static void lesenseHFClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4097 {
4098   uint32_t f = 0U;
4099   CMU_Select_TypeDef s;
4100 
4101   switch (CMU->LESENSEHFCLKCTRL & _CMU_LESENSEHFCLKCTRL_CLKSEL_MASK) {
4102     case CMU_LESENSEHFCLKCTRL_CLKSEL_HFRCOEM23:
4103       f = SystemHFRCOEM23ClockGet();
4104       s = cmuSelect_HFRCOEM23;
4105       break;
4106 
4107     case CMU_LESENSEHFCLKCTRL_CLKSEL_FSRCO:
4108       f = SystemFSRCOClockGet();
4109       s = cmuSelect_FSRCO;
4110       break;
4111 
4112     default:
4113       s = cmuSelect_Error;
4114       EFM_ASSERT(false);
4115       break;
4116   }
4117   if (freq != NULL) {
4118     *freq = f;
4119   }
4120   if (sel != NULL) {
4121     *sel = s;
4122   }
4123 }
4124 #endif
4125 
4126 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
4127   && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
4128 /***************************************************************************//**
4129  * @brief
4130  *   Set maximum allowed prescaler for radio clock tree (RHCLK).
4131  ******************************************************************************/
rhclkPrescMax(void)4132 static void rhclkPrescMax(void)
4133 {
4134   // Set largest prescaler (DIV2).
4135   CMU->SYSCLKCTRL_SET = CMU_SYSCLKCTRL_RHCLKPRESC;
4136 }
4137 
4138 /***************************************************************************//**
4139  * @brief
4140  *   Set radio clock tree prescaler to achieve highest possible frequency
4141  *   and still be within spec.
4142  ******************************************************************************/
rhclkPrescOptimize(void)4143 static void rhclkPrescOptimize(void)
4144 {
4145   if (CMU_ClockFreqGet(cmuClock_SYSCLK) <= CMU_MAX_RHCLK_FREQ) {
4146     // Set smallest prescaler (DIV1).
4147     CMU->SYSCLKCTRL_CLR = CMU_SYSCLKCTRL_RHCLKPRESC;
4148   }
4149 }
4150 #endif // ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
4151 #endif // #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
4152 
4153 #if defined(HFRCOEM23_PRESENT)
4154 /***************************************************************************//**
4155  * @brief
4156  *   Get calibrated HFRCOEM23 tuning value from Device information (DI) page
4157  *   for a given frequency. Calibration value is not available for all frequency
4158  *   bands.
4159  *
4160  * @param[in] freq
4161  *   HFRCOEM23 frequency band
4162  ******************************************************************************/
HFRCOEM23DevinfoGet(CMU_HFRCOEM23Freq_TypeDef freq)4163 static uint32_t HFRCOEM23DevinfoGet(CMU_HFRCOEM23Freq_TypeDef freq)
4164 {
4165   uint32_t ret = 0U;
4166 
4167   switch (freq) {
4168     // 1, 2 and 4MHz share the same calibration word
4169     case cmuHFRCOEM23Freq_1M0Hz:
4170     case cmuHFRCOEM23Freq_2M0Hz:
4171     case cmuHFRCOEM23Freq_4M0Hz:
4172       ret = DEVINFO->HFRCOEM23CAL[0].HFRCOEM23CAL;
4173       break;
4174 
4175     case cmuHFRCOEM23Freq_13M0Hz:
4176       ret = DEVINFO->HFRCOEM23CAL[6].HFRCOEM23CAL;
4177       break;
4178 
4179     case cmuHFRCOEM23Freq_16M0Hz:
4180       ret = DEVINFO->HFRCOEM23CAL[7].HFRCOEM23CAL;
4181       break;
4182 
4183     case cmuHFRCOEM23Freq_19M0Hz:
4184       ret = DEVINFO->HFRCOEM23CAL[8].HFRCOEM23CAL;
4185       break;
4186 
4187     case cmuHFRCOEM23Freq_26M0Hz:
4188       ret = DEVINFO->HFRCOEM23CAL[10].HFRCOEM23CAL;
4189       break;
4190 
4191     case cmuHFRCOEM23Freq_32M0Hz:
4192       ret = DEVINFO->HFRCOEM23CAL[11].HFRCOEM23CAL;
4193       break;
4194 
4195     case cmuHFRCOEM23Freq_40M0Hz:
4196       ret = DEVINFO->HFRCOEM23CAL[12].HFRCOEM23CAL;
4197       break;
4198 
4199     case cmuHFRCOEM23Freq_UserDefined:
4200       break;
4201 
4202     default:
4203       EFM_ASSERT(false);
4204       break;
4205   }
4206   return ret;
4207 }
4208 #endif // defined(HFRCOEM23_PRESENT)
4209 
4210 /***************************************************************************//**
4211  * @brief
4212  *   Get selected oscillator and frequency for @ref cmuClock_TRACECLK
4213  *   clock tree.
4214  *
4215  * @param[out] freq
4216  *   The frequency.
4217  *
4218  * @param[out] sel
4219  *   The selected oscillator.
4220  ******************************************************************************/
traceClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4221 static void traceClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4222 {
4223   uint32_t f = 0U;
4224   CMU_Select_TypeDef s;
4225 
4226 #if defined(_CMU_TRACECLKCTRL_CLKSEL_MASK)
4227   switch (CMU->TRACECLKCTRL & _CMU_TRACECLKCTRL_CLKSEL_MASK) {
4228 #if defined(_CMU_TRACECLKCTRL_CLKSEL_HCLK)
4229     case CMU_TRACECLKCTRL_CLKSEL_HCLK:
4230       f = SystemHCLKGet();
4231       s = cmuSelect_HCLK;
4232       break;
4233 #endif
4234 #if defined(_CMU_TRACECLKCTRL_CLKSEL_SYSCLK)
4235     case CMU_TRACECLKCTRL_CLKSEL_SYSCLK:
4236       f = SystemSYSCLKGet();
4237       s = cmuSelect_SYSCLK;
4238       break;
4239 #endif
4240 
4241 #if defined(CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23)
4242     case CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23:
4243       f = SystemHFRCOEM23ClockGet();
4244       s = cmuSelect_HFRCOEM23;
4245       break;
4246 #endif
4247 
4248 #if defined(CMU_TRACECLKCTRL_CLKSEL_HFRCODPLLRT)
4249     case CMU_TRACECLKCTRL_CLKSEL_HFRCODPLLRT:
4250       f = SystemHFRCODPLLClockGet();
4251       s = cmuSelect_HFRCODPLLRT;
4252       break;
4253 #endif
4254 
4255     default:
4256       s = cmuSelect_Error;
4257       EFM_ASSERT(false);
4258       break;
4259   }
4260 #else
4261   f = SystemSYSCLKGet();
4262   s = cmuSelect_SYSCLK;
4263 #endif
4264 
4265   if (freq != NULL) {
4266     *freq = f;
4267   }
4268   if (sel != NULL) {
4269     *sel = s;
4270   }
4271 }
4272 
4273 /***************************************************************************//**
4274  * @brief
4275  *   Get selected oscillator and frequency for @ref cmuClock_DPLLREFCLK
4276  *   clock tree.
4277  *
4278  * @param[out] freq
4279  *   The frequency.
4280  *
4281  * @param[out] sel
4282  *   The selected oscillator.
4283  ******************************************************************************/
dpllRefClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4284 static void dpllRefClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4285 {
4286   uint32_t f = 0U;
4287   CMU_Select_TypeDef s;
4288 
4289   switch (CMU->DPLLREFCLKCTRL & _CMU_DPLLREFCLKCTRL_CLKSEL_MASK) {
4290     case CMU_DPLLREFCLKCTRL_CLKSEL_HFXO:
4291       f = SystemHFXOClockGet();
4292       s = cmuSelect_HFXO;
4293       break;
4294 
4295     case CMU_DPLLREFCLKCTRL_CLKSEL_LFXO:
4296       f = SystemLFXOClockGet();
4297       s = cmuSelect_LFXO;
4298       break;
4299 
4300     case CMU_DPLLREFCLKCTRL_CLKSEL_CLKIN0:
4301       f = SystemCLKIN0Get();
4302       s = cmuSelect_CLKIN0;
4303       break;
4304 
4305     case CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED:
4306       s = cmuSelect_Disabled;
4307       break;
4308 
4309     default:
4310       s = cmuSelect_Error;
4311       EFM_ASSERT(false);
4312       break;
4313   }
4314 
4315   if (freq != NULL) {
4316     *freq = f;
4317   }
4318   if (sel != NULL) {
4319     *sel = s;
4320   }
4321 }
4322 
4323 /***************************************************************************//**
4324  * @brief
4325  *   Get selected oscillator and frequency for @ref cmuClock_EM01GRPACLK
4326  *   clock tree.
4327  *
4328  * @param[out] freq
4329  *   The frequency.
4330  *
4331  * @param[out] sel
4332  *   The selected oscillator.
4333  ******************************************************************************/
em01GrpaClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4334 static void em01GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4335 {
4336   uint32_t f = 0U;
4337   CMU_Select_TypeDef s;
4338 
4339   switch (CMU->EM01GRPACLKCTRL & _CMU_EM01GRPACLKCTRL_CLKSEL_MASK) {
4340     case CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLL:
4341       f = SystemHFRCODPLLClockGet();
4342       s = cmuSelect_HFRCODPLL;
4343       break;
4344 
4345     case CMU_EM01GRPACLKCTRL_CLKSEL_HFXO:
4346       f = SystemHFXOClockGet();
4347       s = cmuSelect_HFXO;
4348       break;
4349 
4350 #if defined(HFRCOEM23_PRESENT)
4351     case CMU_EM01GRPACLKCTRL_CLKSEL_HFRCOEM23:
4352       f = SystemHFRCOEM23ClockGet();
4353       s = cmuSelect_HFRCOEM23;
4354       break;
4355 #endif
4356 
4357     case CMU_EM01GRPACLKCTRL_CLKSEL_FSRCO:
4358       f = SystemFSRCOClockGet();
4359       s = cmuSelect_FSRCO;
4360       break;
4361 
4362 #if defined(CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLLRT)
4363     case CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLLRT:
4364       f = SystemHFRCODPLLClockGet();
4365       s = cmuSelect_HFRCODPLLRT;
4366       break;
4367 #endif
4368 
4369 #if defined(CMU_EM01GRPACLKCTRL_CLKSEL_HFXORT)
4370     case CMU_EM01GRPACLKCTRL_CLKSEL_HFXORT:
4371       f = SystemHFXOClockGet();
4372       s = cmuSelect_HFXORT;
4373       break;
4374 #endif
4375 
4376     default:
4377       s = cmuSelect_Error;
4378       EFM_ASSERT(false);
4379       break;
4380   }
4381 
4382   if (freq != NULL) {
4383     *freq = f;
4384   }
4385   if (sel != NULL) {
4386     *sel = s;
4387   }
4388 }
4389 
4390 /***************************************************************************//**
4391  * @brief
4392  *   Get selected oscillator and frequency for @ref cmuClock_EM23GRPACLK
4393  *   clock tree.
4394  *
4395  * @param[out] freq
4396  *   The frequency.
4397  *
4398  * @param[out] sel
4399  *   The selected oscillator.
4400  ******************************************************************************/
em23GrpaClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4401 static void em23GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4402 {
4403   uint32_t f = 0U;
4404   CMU_Select_TypeDef s;
4405 
4406   switch (CMU->EM23GRPACLKCTRL & _CMU_EM23GRPACLKCTRL_CLKSEL_MASK) {
4407     case CMU_EM23GRPACLKCTRL_CLKSEL_LFRCO:
4408       f = SystemLFRCOClockGet();
4409       s = cmuSelect_LFRCO;
4410       break;
4411 
4412     case CMU_EM23GRPACLKCTRL_CLKSEL_LFXO:
4413       f = SystemLFXOClockGet();
4414       s = cmuSelect_LFXO;
4415       break;
4416 
4417     case CMU_EM23GRPACLKCTRL_CLKSEL_ULFRCO:
4418       f = SystemULFRCOClockGet();
4419       s = cmuSelect_ULFRCO;
4420       break;
4421 
4422     default:
4423       s = cmuSelect_Error;
4424       EFM_ASSERT(false);
4425       break;
4426   }
4427 
4428   if (freq != NULL) {
4429     *freq = f;
4430   }
4431   if (sel != NULL) {
4432     *sel = s;
4433   }
4434 }
4435 
4436 /***************************************************************************//**
4437  * @brief
4438  *   Get selected oscillator and frequency for @ref cmuClock_EM4GRPACLK
4439  *   clock tree.
4440  *
4441  * @param[out] freq
4442  *   The frequency.
4443  *
4444  * @param[out] sel
4445  *   The selected oscillator.
4446  ******************************************************************************/
em4GrpaClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4447 static void em4GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4448 {
4449   uint32_t f = 0U;
4450   CMU_Select_TypeDef s;
4451 
4452   switch (CMU->EM4GRPACLKCTRL & _CMU_EM4GRPACLKCTRL_CLKSEL_MASK) {
4453     case CMU_EM4GRPACLKCTRL_CLKSEL_LFRCO:
4454       f = SystemLFRCOClockGet();
4455       s = cmuSelect_LFRCO;
4456       break;
4457 
4458     case CMU_EM4GRPACLKCTRL_CLKSEL_LFXO:
4459       f = SystemLFXOClockGet();
4460       s = cmuSelect_LFXO;
4461       break;
4462 
4463     case CMU_EM4GRPACLKCTRL_CLKSEL_ULFRCO:
4464       f = SystemULFRCOClockGet();
4465       s = cmuSelect_ULFRCO;
4466       break;
4467 
4468     default:
4469       s = cmuSelect_Error;
4470       EFM_ASSERT(false);
4471       break;
4472   }
4473 
4474   if (freq != NULL) {
4475     *freq = f;
4476   }
4477   if (sel != NULL) {
4478     *sel = s;
4479   }
4480 }
4481 
getWaitStatesByFrequencyAndVScale(uint32_t freq,int vscale)4482 __STATIC_INLINE uint32_t getWaitStatesByFrequencyAndVScale(uint32_t freq, int vscale)
4483 {
4484   uint32_t flashWs = MSC_READCTRL_MODE_WS3;
4485 
4486   if (vscale == 0) {
4487     // VScale 1.1V core frequency ranges for wait-states configurations.
4488     if (0) {
4489     }
4490 #if defined(CMU_MAX_FREQ_2WS_1V1)
4491     else if (freq > CMU_MAX_FREQ_2WS_1V1) {
4492       flashWs = MSC_READCTRL_MODE_WS3;
4493     }
4494 #endif
4495 #if defined(CMU_MAX_FREQ_1WS_1V1)
4496     else if (freq > CMU_MAX_FREQ_1WS_1V1) {
4497       flashWs = MSC_READCTRL_MODE_WS2;
4498     }
4499 #endif
4500 #if defined(CMU_MAX_FREQ_0WS_1V1)
4501     else if (freq > CMU_MAX_FREQ_0WS_1V1) {
4502       flashWs = MSC_READCTRL_MODE_WS1;
4503     }
4504 #endif
4505     else {
4506       flashWs = MSC_READCTRL_MODE_WS0;
4507     }
4508   } else if (vscale >= 1) {
4509     // VScale 1.0V core frequency ranges for wait-states configurations.
4510     if (0) {
4511     }
4512 #if defined(CMU_MAX_FREQ_2WS_1V0)
4513     else if (freq > CMU_MAX_FREQ_2WS_1V0) {
4514       flashWs = MSC_READCTRL_MODE_WS3;
4515     }
4516 #endif
4517 #if defined(CMU_MAX_FREQ_1WS_1V0)
4518     else if (freq > CMU_MAX_FREQ_1WS_1V0) {
4519       flashWs = MSC_READCTRL_MODE_WS2;
4520     }
4521 #endif
4522 #if defined(CMU_MAX_FREQ_0WS_1V0)
4523     else if (freq > CMU_MAX_FREQ_0WS_1V0) {
4524       flashWs = MSC_READCTRL_MODE_WS1;
4525     }
4526 #endif
4527     else {
4528       flashWs = MSC_READCTRL_MODE_WS0;
4529     }
4530   }
4531   return flashWs;
4532 }
4533 
4534 /***************************************************************************//**
4535  * @brief
4536  *   Configure flash access wait states to support the given core clock
4537  *   frequency and vscale level.
4538  *
4539  * @note Current implementation sets wait states depending on frequency only.
4540  *   This assumes that applications running on Vscale enabled microcontrollers
4541  *   never attemtps to set core frequency above 40MHz at VSCALE1 (1.0V).
4542  *   Series 2 Config 1 devices does not support vscale.
4543  *
4544  * @param[in] coreFreq
4545  *   The core clock frequency to configure flash wait-states.
4546  *
4547  * @param[in] vscale
4548  *   Voltage Scale level. Supported levels are 0 and 1 where 0 is the default.
4549  *   @li 0 = 1.1 V (VSCALE2)
4550  *   @li 1 = 1.0 V (VSCALE1)
4551  ******************************************************************************/
flashWaitStateControl(uint32_t coreFreq,int vscale)4552 static void flashWaitStateControl(uint32_t coreFreq, int vscale)
4553 {
4554   (void)vscale;
4555 
4556   uint32_t mode;
4557   bool mscLocked;
4558 
4559 #if defined(CMU_CLKEN1_MSC)
4560   CMU->CLKEN1_SET = CMU_CLKEN1_MSC;
4561 #endif
4562 
4563 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
4564   coreFreq *= CMU_ClockDivGet(cmuClock_CORE);
4565 #endif
4566 
4567   // Make sure the MSC is unlocked
4568   mscLocked = MSC_LockGetLocked();
4569   MSC_LockSetUnlocked();
4570 
4571   // Get current flash read setting
4572   mode = MSC_ReadCTRLGet() & ~_MSC_READCTRL_MODE_MASK;
4573 
4574   // Set new mode based on the core clock frequency
4575   mode |= getWaitStatesByFrequencyAndVScale(coreFreq, vscale);
4576 
4577   MSC_ReadCTRLSet(mode);
4578 
4579   // Set sram wait states for config 1 mcu.
4580 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
4581   // Set new mode based on the core clock frequency
4582   if (coreFreq > CMU_MAX_SRAM_FREQ_0WS) {
4583     SYSCFG_setDmem0RamCtrlRamwsenBit();
4584   } else {
4585     SYSCFG_clearDmem0RamCtrlRamwsenBit();
4586   }
4587 #endif
4588   if (mscLocked) {
4589     MSC_LockSetLocked();
4590   }
4591 }
4592 
4593 /***************************************************************************//**
4594  * @brief
4595  *   Get calibrated HFRCODPLL tuning value from Device information (DI) page
4596  *   for a given frequency. Calibration value is not available for all frequency
4597  *   bands.
4598  *
4599  * @param[in] freq
4600  *   HFRCODPLL frequency band
4601  ******************************************************************************/
HFRCODPLLDevinfoGet(CMU_HFRCODPLLFreq_TypeDef freq)4602 static uint32_t HFRCODPLLDevinfoGet(CMU_HFRCODPLLFreq_TypeDef freq)
4603 {
4604   uint32_t ret = 0U;
4605 
4606   switch (freq) {
4607     // 1, 2 and 4MHz share the same calibration word
4608     case cmuHFRCODPLLFreq_1M0Hz:
4609     case cmuHFRCODPLLFreq_2M0Hz:
4610     case cmuHFRCODPLLFreq_4M0Hz:
4611       ret = DEVINFO->HFRCODPLLCAL[0].HFRCODPLLCAL;
4612       break;
4613 
4614     case cmuHFRCODPLLFreq_7M0Hz:
4615       ret = DEVINFO->HFRCODPLLCAL[3].HFRCODPLLCAL;
4616       break;
4617 
4618     case cmuHFRCODPLLFreq_13M0Hz:
4619       ret = DEVINFO->HFRCODPLLCAL[6].HFRCODPLLCAL;
4620       break;
4621 
4622     case cmuHFRCODPLLFreq_16M0Hz:
4623       ret = DEVINFO->HFRCODPLLCAL[7].HFRCODPLLCAL;
4624       break;
4625 
4626     case cmuHFRCODPLLFreq_19M0Hz:
4627       ret = DEVINFO->HFRCODPLLCAL[8].HFRCODPLLCAL;
4628       break;
4629 
4630     case cmuHFRCODPLLFreq_26M0Hz:
4631       ret = DEVINFO->HFRCODPLLCAL[10].HFRCODPLLCAL;
4632       break;
4633 
4634     case cmuHFRCODPLLFreq_32M0Hz:
4635       ret = DEVINFO->HFRCODPLLCAL[11].HFRCODPLLCAL;
4636       break;
4637 
4638     case cmuHFRCODPLLFreq_38M0Hz:
4639       ret = DEVINFO->HFRCODPLLCAL[12].HFRCODPLLCAL;
4640       break;
4641 
4642     case cmuHFRCODPLLFreq_48M0Hz:
4643       ret = DEVINFO->HFRCODPLLCAL[13].HFRCODPLLCAL;
4644       break;
4645 
4646     case cmuHFRCODPLLFreq_56M0Hz:
4647       ret = DEVINFO->HFRCODPLLCAL[14].HFRCODPLLCAL;
4648       break;
4649 
4650     case cmuHFRCODPLLFreq_64M0Hz:
4651       ret = DEVINFO->HFRCODPLLCAL[15].HFRCODPLLCAL;
4652       break;
4653 
4654     case cmuHFRCODPLLFreq_80M0Hz:
4655       ret = DEVINFO->HFRCODPLLCAL[16].HFRCODPLLCAL;
4656       break;
4657 
4658 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)
4659     case cmuHFRCODPLLFreq_100M0Hz:
4660       ret = DEVINFO->HFRCODPLLCAL[17].HFRCODPLLCAL;
4661       break;
4662 #endif
4663 
4664     case cmuHFRCODPLLFreq_UserDefined:
4665       break;
4666 
4667     default:
4668       EFM_ASSERT(false);
4669       break;
4670   }
4671   return ret;
4672 }
4673 
4674 #if defined(IADC_PRESENT)
4675 /***************************************************************************//**
4676  * @brief
4677  *   Get selected oscillator and frequency for @ref cmuClock_IADCCLK
4678  *   clock tree.
4679  *
4680  * @param[out] freq
4681  *   The frequency.
4682  *
4683  * @param[out] sel
4684  *   The selected oscillator.
4685  ******************************************************************************/
iadcClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4686 static void iadcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4687 {
4688   uint32_t f = 0U;
4689   CMU_Select_TypeDef s;
4690 
4691   switch (CMU->IADCCLKCTRL & _CMU_IADCCLKCTRL_CLKSEL_MASK) {
4692     case CMU_IADCCLKCTRL_CLKSEL_EM01GRPACLK:
4693       em01GrpaClkGet(&f, NULL);
4694       s = cmuSelect_EM01GRPACLK;
4695       break;
4696 
4697 #if defined(HFRCOEM23_PRESENT)
4698     case CMU_IADCCLKCTRL_CLKSEL_HFRCOEM23:
4699       f = SystemHFRCOEM23ClockGet();
4700       s = cmuSelect_HFRCOEM23;
4701       break;
4702 #endif
4703 
4704     case CMU_IADCCLKCTRL_CLKSEL_FSRCO:
4705       f = SystemFSRCOClockGet();
4706       s = cmuSelect_FSRCO;
4707       break;
4708 
4709     default:
4710       s = cmuSelect_Error;
4711       EFM_ASSERT(false);
4712       break;
4713   }
4714 
4715   if (freq != NULL) {
4716     *freq = f;
4717   }
4718   if (sel != NULL) {
4719     *sel = s;
4720   }
4721 }
4722 #endif
4723 
4724 /***************************************************************************//**
4725  * @brief
4726  *   Set maximum allowed divisor for @ref cmuClock_PCLK clock tree.
4727  ******************************************************************************/
pclkDivMax(void)4728 static void pclkDivMax(void)
4729 {
4730   // Set largest divisor for PCLK clock tree.
4731   CMU_ClockDivSet(cmuClock_PCLK, 2U);
4732 }
4733 
4734 /***************************************************************************//**
4735  * @brief
4736  *   Set @ref cmuClock_PCLK clock tree divisor to achieve highest possible
4737  *  frequency and still be within spec.
4738  ******************************************************************************/
pclkDivOptimize(void)4739 static void pclkDivOptimize(void)
4740 {
4741   CMU_ClkDiv_TypeDef div = 2U;
4742 
4743   if (CMU_ClockFreqGet(cmuClock_HCLK) <= CMU_MAX_PCLK_FREQ) {
4744     div = 1U;
4745   }
4746   CMU_ClockDivSet(cmuClock_PCLK, div);
4747 }
4748 
4749 #if defined(RTCC_PRESENT)
4750 /***************************************************************************//**
4751  * @brief
4752  *   Get selected oscillator and frequency for @ref cmuClock_RTCCCLK
4753  *   clock tree.
4754  *
4755  * @param[out] freq
4756  *   The frequency.
4757  *
4758  * @param[out] sel
4759  *   The selected oscillator.
4760  ******************************************************************************/
rtccClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4761 static void rtccClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4762 {
4763   uint32_t f = 0U;
4764   CMU_Select_TypeDef s;
4765 
4766   switch (CMU->RTCCCLKCTRL & _CMU_RTCCCLKCTRL_CLKSEL_MASK) {
4767     case CMU_RTCCCLKCTRL_CLKSEL_LFRCO:
4768       f = SystemLFRCOClockGet();
4769       s = cmuSelect_LFRCO;
4770       break;
4771 
4772     case CMU_RTCCCLKCTRL_CLKSEL_LFXO:
4773       f = SystemLFXOClockGet();
4774       s = cmuSelect_LFXO;
4775       break;
4776 
4777     case CMU_RTCCCLKCTRL_CLKSEL_ULFRCO:
4778       f = SystemULFRCOClockGet();
4779       s = cmuSelect_ULFRCO;
4780       break;
4781 
4782     default:
4783       s = cmuSelect_Error;
4784       EFM_ASSERT(false);
4785       break;
4786   }
4787 
4788   if (freq != NULL) {
4789     *freq = f;
4790   }
4791   if (sel != NULL) {
4792     *sel = s;
4793   }
4794 }
4795 #endif
4796 
4797 #if defined(SYSRTC_PRESENT)
4798 /***************************************************************************//**
4799  * @brief
4800  *   Get selected oscillator and frequency for @ref cmuClock_SYSRTCCLK
4801  *   clock tree.
4802  *
4803  * @param[out] freq
4804  *   The frequency.
4805  *
4806  * @param[out] sel
4807  *   The selected oscillator.
4808  ******************************************************************************/
sysrtcClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4809 static void sysrtcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4810 {
4811   uint32_t f = 0U;
4812   CMU_Select_TypeDef s;
4813 
4814   switch (CMU->SYSRTC0CLKCTRL & _CMU_SYSRTC0CLKCTRL_CLKSEL_MASK) {
4815     case CMU_SYSRTC0CLKCTRL_CLKSEL_LFRCO:
4816       f = SystemLFRCOClockGet();
4817       s = cmuSelect_LFRCO;
4818       break;
4819 
4820     case CMU_SYSRTC0CLKCTRL_CLKSEL_LFXO:
4821       f = SystemLFXOClockGet();
4822       s = cmuSelect_LFXO;
4823       break;
4824 
4825     case CMU_SYSRTC0CLKCTRL_CLKSEL_ULFRCO:
4826       f = SystemULFRCOClockGet();
4827       s = cmuSelect_ULFRCO;
4828       break;
4829 
4830     default:
4831       s = cmuSelect_Error;
4832       EFM_ASSERT(false);
4833       break;
4834   }
4835 
4836   if (freq != NULL) {
4837     *freq = f;
4838   }
4839   if (sel != NULL) {
4840     *sel = s;
4841   }
4842 }
4843 #endif
4844 
4845 /***************************************************************************//**
4846  * @brief
4847  *   Set wait-states to values valid for maximum allowable core clock frequency.
4848  ******************************************************************************/
waitStateMax(void)4849 static void waitStateMax(void)
4850 {
4851   flashWaitStateControl(SystemMaxCoreClockGet(), 0);
4852 }
4853 
4854 /***************************************************************************//**
4855  * @brief
4856  *   Get selected oscillator and frequency for @ref cmuClock_WDOG0CLK
4857  *   clock tree.
4858  *
4859  * @param[out] freq
4860  *   The frequency.
4861  *
4862  * @param[out] sel
4863  *   The selected oscillator.
4864  ******************************************************************************/
wdog0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4865 static void wdog0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4866 {
4867   uint32_t f = 0U;
4868   CMU_Select_TypeDef s;
4869 
4870   switch (CMU->WDOG0CLKCTRL & _CMU_WDOG0CLKCTRL_CLKSEL_MASK) {
4871     case CMU_WDOG0CLKCTRL_CLKSEL_LFRCO:
4872       f = SystemLFRCOClockGet();
4873       s = cmuSelect_LFRCO;
4874       break;
4875 
4876     case CMU_WDOG0CLKCTRL_CLKSEL_LFXO:
4877       f = SystemLFXOClockGet();
4878       s = cmuSelect_LFXO;
4879       break;
4880 
4881     case CMU_WDOG0CLKCTRL_CLKSEL_ULFRCO:
4882       f = SystemULFRCOClockGet();
4883       s = cmuSelect_ULFRCO;
4884       break;
4885 
4886     case CMU_WDOG0CLKCTRL_CLKSEL_HCLKDIV1024:
4887       f = SystemHCLKGet() / 1024U;
4888       s = cmuSelect_HCLKDIV1024;
4889       break;
4890 
4891     default:
4892       s = cmuSelect_Error;
4893       EFM_ASSERT(false);
4894       break;
4895   }
4896 
4897   if (freq != NULL) {
4898     *freq = f;
4899   }
4900   if (sel != NULL) {
4901     *sel = s;
4902   }
4903 }
4904 
4905 #if defined(_SILICON_LABS_32B_SERIES_2) && WDOG_COUNT > 1
4906 /***************************************************************************//**
4907  * @brief
4908  *   Get selected oscillator and frequency for @ref cmuClock_WDOG1CLK
4909  *   clock tree.
4910  *
4911  * @param[out] freq
4912  *   The frequency.
4913  *
4914  * @param[out] sel
4915  *   The selected oscillator.
4916  ******************************************************************************/
wdog1ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4917 static void wdog1ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4918 {
4919   uint32_t f = 0U;
4920   CMU_Select_TypeDef s;
4921 
4922   switch (CMU->WDOG1CLKCTRL & _CMU_WDOG1CLKCTRL_CLKSEL_MASK) {
4923     case CMU_WDOG1CLKCTRL_CLKSEL_LFRCO:
4924       f = SystemLFRCOClockGet();
4925       s = cmuSelect_LFRCO;
4926       break;
4927 
4928     case CMU_WDOG1CLKCTRL_CLKSEL_LFXO:
4929       f = SystemLFXOClockGet();
4930       s = cmuSelect_LFXO;
4931       break;
4932 
4933     case CMU_WDOG1CLKCTRL_CLKSEL_ULFRCO:
4934       f = SystemULFRCOClockGet();
4935       s = cmuSelect_ULFRCO;
4936       break;
4937 
4938     case CMU_WDOG1CLKCTRL_CLKSEL_HCLKDIV1024:
4939       f = SystemHCLKGet() / 1024U;
4940       s = cmuSelect_HCLKDIV1024;
4941       break;
4942 
4943     default:
4944       s = cmuSelect_Error;
4945       EFM_ASSERT(false);
4946       break;
4947   }
4948 
4949   if (freq != NULL) {
4950     *freq = f;
4951   }
4952   if (sel != NULL) {
4953     *sel = s;
4954   }
4955 }
4956 #endif // defined(_SILICON_LABS_32B_SERIES_2) && WDOG_COUNT > 1
4957 
4958 /***************************************************************************//**
4959  * @brief
4960  *   Get selected oscillator and frequency for @ref cmuClock_SYSTICK
4961  *   clock tree.
4962  *
4963  * @param[out] freq
4964  *   The frequency.
4965  *
4966  * @param[out] sel
4967  *   The selected oscillator.
4968  ******************************************************************************/
sysTickClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4969 static void sysTickClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4970 {
4971   uint32_t f = 0U;
4972   CMU_Select_TypeDef s;
4973 
4974   if (SysTick->CTRL & SysTick_CTRL_CLKSOURCE_Msk) {
4975     f = SystemHCLKGet();
4976     s = cmuSelect_HCLK;
4977   } else {
4978     em23GrpaClkGet(&f, &s);
4979   }
4980 
4981   if (freq != NULL) {
4982     *freq = f;
4983   }
4984   if (sel != NULL) {
4985     *sel = s;
4986   }
4987 }
4988 
4989 #if defined(USB_PRESENT)
4990 /***************************************************************************//**
4991  * @brief
4992  *   Get selected oscillator and frequency for @ref cmuClock_USB clock tree.
4993  *
4994  * @param[out] freq
4995  *   The frequency.
4996  *
4997  * @param[out] sel
4998  *   The selected oscillator.
4999  ******************************************************************************/
usbClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)5000 static void usbClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
5001 {
5002   uint32_t f = 0U;
5003   CMU_Select_TypeDef s;
5004 
5005   switch (CMU->USB0CLKCTRL & _CMU_USB0CLKCTRL_CLKSEL_MASK) {
5006     case CMU_USB0CLKCTRL_CLKSEL_USBPLL0:
5007       f = PLL0_USB_OUTPUT_FREQ;
5008       s = cmuSelect_USBPLL0;
5009       break;
5010 
5011     case CMU_USB0CLKCTRL_CLKSEL_LFXO:
5012       f = SystemLFXOClockGet();
5013       s = cmuSelect_LFXO;
5014       break;
5015 
5016     case CMU_USB0CLKCTRL_CLKSEL_LFRCO:
5017       f = SystemLFRCOClockGet();
5018       s = cmuSelect_LFRCO;
5019       break;
5020 
5021     default:
5022       s = cmuSelect_Error;
5023       EFM_ASSERT(false);
5024       break;
5025   }
5026 
5027   if (freq != NULL) {
5028     *freq = f;
5029   }
5030   if (sel != NULL) {
5031     *sel = s;
5032   }
5033 }
5034 #endif
5035 
5036 /** @endcond */
5037 
5038 #else // defined(_SILICON_LABS_32B_SERIES_2)
5039 
5040 /*******************************************************************************
5041  ******************************   DEFINES   ************************************
5042  ******************************************************************************/
5043 
5044 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
5045 
5046 #if defined(_SILICON_LABS_32B_SERIES_0)
5047 /** The maximum allowed core frequency when using 0 wait-states on flash access. */
5048 #define CMU_MAX_FREQ_0WS        16000000
5049 /** The maximum allowed core frequency when using 1 wait-states on flash access */
5050 #define CMU_MAX_FREQ_1WS        32000000
5051 
5052 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 80)
5053 // EFR32xG1x and EFM32xG1x
5054 #define CMU_MAX_FREQ_0WS_1V2    25000000
5055 #define CMU_MAX_FREQ_1WS_1V2    40000000
5056 
5057 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 84)
5058 // EFR32xG12x and EFM32xG12x
5059 #define CMU_MAX_FREQ_0WS_1V2    25000000
5060 #define CMU_MAX_FREQ_1WS_1V2    40000000
5061 #define CMU_MAX_FREQ_0WS_1V1    21330000
5062 #define CMU_MAX_FREQ_1WS_1V1    32000000
5063 #define CMU_MAX_FREQ_0WS_1V0     7000000
5064 #define CMU_MAX_FREQ_1WS_1V0    14000000
5065 #define CMU_MAX_FREQ_2WS_1V0    20000000
5066 
5067 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 89)
5068 // EFR32xG13x and EFM32xG13x
5069 #define CMU_MAX_FREQ_0WS_1V2    25000000
5070 #define CMU_MAX_FREQ_1WS_1V2    40000000
5071 #define CMU_MAX_FREQ_0WS_1V0     7000000
5072 #define CMU_MAX_FREQ_1WS_1V0    14000000
5073 #define CMU_MAX_FREQ_2WS_1V0    20000000
5074 
5075 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 95)
5076 // EFR32xG14x and EFM32xG14x
5077 #define CMU_MAX_FREQ_0WS_1V2    25000000
5078 #define CMU_MAX_FREQ_1WS_1V2    40000000
5079 #define CMU_MAX_FREQ_0WS_1V0     7000000
5080 #define CMU_MAX_FREQ_1WS_1V0    14000000
5081 #define CMU_MAX_FREQ_2WS_1V0    20000000
5082 
5083 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 100)
5084 // EFM32GG11x
5085 #define CMU_MAX_FREQ_0WS_1V2    18000000
5086 #define CMU_MAX_FREQ_1WS_1V2    36000000
5087 #define CMU_MAX_FREQ_2WS_1V2    54000000
5088 #define CMU_MAX_FREQ_3WS_1V2    72000000
5089 #define CMU_MAX_FREQ_0WS_1V0     7000000
5090 #define CMU_MAX_FREQ_1WS_1V0    14000000
5091 #define CMU_MAX_FREQ_2WS_1V0    20000000
5092 
5093 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 103)
5094 // EFM32TG11x
5095 #define CMU_MAX_FREQ_0WS_1V2    25000000
5096 #define CMU_MAX_FREQ_1WS_1V2    48000000
5097 #define CMU_MAX_FREQ_0WS_1V0    10000000
5098 #define CMU_MAX_FREQ_1WS_1V0    21000000
5099 #define CMU_MAX_FREQ_2WS_1V0    20000000
5100 
5101 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 106)
5102 // EFM32GG12x
5103 #define CMU_MAX_FREQ_0WS_1V2    18000000
5104 #define CMU_MAX_FREQ_1WS_1V2    36000000
5105 #define CMU_MAX_FREQ_2WS_1V2    54000000
5106 #define CMU_MAX_FREQ_3WS_1V2    72000000
5107 #define CMU_MAX_FREQ_0WS_1V0    7000000
5108 #define CMU_MAX_FREQ_1WS_1V0    14000000
5109 #define CMU_MAX_FREQ_2WS_1V0    20000000
5110 
5111 #else
5112 #error "Max Flash wait-state frequencies are not defined for this platform."
5113 #endif
5114 
5115 /** The maximum frequency for the HFLE interface. */
5116 #if defined(CMU_CTRL_HFLE)
5117 /** The maximum HFLE frequency for series 0 EFM32 and EZR32 Wonder Gecko. */
5118 #if defined(_SILICON_LABS_32B_SERIES_0) \
5119   && (defined(_EFM32_WONDER_FAMILY)     \
5120   || defined(_EZR32_WONDER_FAMILY))
5121 #define CMU_MAX_FREQ_HFLE                       24000000UL
5122 /** The maximum HFLE frequency for other series 0 parts with maximum core clock
5123     higher than 32 MHz. */
5124 #elif defined(_SILICON_LABS_32B_SERIES_0) \
5125   && (defined(_EFM32_GIANT_FAMILY)        \
5126   || defined(_EZR32_LEOPARD_FAMILY))
5127 #define CMU_MAX_FREQ_HFLE                       maxFreqHfle()
5128 #endif
5129 #elif defined(CMU_CTRL_WSHFLE)
5130 /** The maximum HFLE frequency for series 1 parts. */
5131 #define CMU_MAX_FREQ_HFLE                       32000000UL
5132 #endif
5133 
5134 #if defined(CMU_STATUS_HFXOSHUNTOPTRDY)
5135 #define HFXO_TUNING_READY_FLAGS  (CMU_STATUS_HFXOPEAKDETRDY | CMU_STATUS_HFXOSHUNTOPTRDY)
5136 #define HFXO_TUNING_MODE_AUTO    (_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_AUTOCMD)
5137 #define HFXO_TUNING_MODE_CMD     (_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_CMD)
5138 #elif defined(CMU_STATUS_HFXOPEAKDETRDY)
5139 #define HFXO_TUNING_READY_FLAGS  (CMU_STATUS_HFXOPEAKDETRDY)
5140 #define HFXO_TUNING_MODE_AUTO    (_CMU_HFXOCTRL_PEAKDETMODE_AUTOCMD)
5141 #define HFXO_TUNING_MODE_CMD     (_CMU_HFXOCTRL_PEAKDETMODE_CMD)
5142 #endif
5143 
5144 #if defined(CMU_HFXOCTRL_MODE_EXTCLK)
5145 /** HFXO external clock mode is renamed from EXTCLK to DIGEXTCLK. */
5146 #define CMU_HFXOCTRL_MODE_DIGEXTCLK     CMU_HFXOCTRL_MODE_EXTCLK
5147 #endif
5148 
5149 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
5150 #define VSCALE_DEFAULT    ((int)EMU_VScaleGet())
5151 #else
5152 #define VSCALE_DEFAULT    VSCALE_EM01_HIGH_PERFORMANCE
5153 #endif
5154 
5155 /*******************************************************************************
5156  **************************   LOCAL VARIABLES   ********************************
5157  ******************************************************************************/
5158 
5159 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
5160 static CMU_AUXHFRCOFreq_TypeDef auxHfrcoFreq = cmuAUXHFRCOFreq_19M0Hz;
5161 #endif
5162 #if defined(_CMU_STATUS_HFXOSHUNTOPTRDY_MASK)
5163 #define HFXO_INVALID_TRIM   (~_CMU_HFXOTRIMSTATUS_MASK)
5164 #endif
5165 
5166 #if defined(CMU_OSCENCMD_DPLLEN)
5167 /** A table of HFRCOCTRL values and their associated minimum/maximum frequencies and
5168     an optional band enumerator. */
5169 static const struct hfrcoCtrlTableElement{
5170   uint32_t              minFreq;
5171   uint32_t              maxFreq;
5172   uint32_t              value;
5173   CMU_HFRCOFreq_TypeDef band;
5174 } hfrcoCtrlTable[] =
5175 {
5176   // minFreq  maxFreq   HFRCOCTRL value  band
5177   {  860000UL, 1050000UL, 0xBC601F00UL, cmuHFRCOFreq_1M0Hz       },
5178   { 1050000UL, 1280000UL, 0xBC611F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5179   { 1280000UL, 1480000UL, 0xBCA21F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5180   { 1480000UL, 1800000UL, 0xAD231F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5181   { 1800000UL, 2110000UL, 0xBA601F00UL, cmuHFRCOFreq_2M0Hz       },
5182   { 2110000UL, 2560000UL, 0xBA611F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5183   { 2560000UL, 2970000UL, 0xBAA21F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5184   { 2970000UL, 3600000UL, 0xAB231F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5185   { 3600000UL, 4220000UL, 0xB8601F00UL, cmuHFRCOFreq_4M0Hz       },
5186   { 4220000UL, 5120000UL, 0xB8611F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5187   { 5120000UL, 5930000UL, 0xB8A21F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5188   { 5930000UL, 7520000UL, 0xA9231F00UL, cmuHFRCOFreq_7M0Hz       },
5189   { 7520000UL, 9520000UL, 0x99241F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5190   { 9520000UL, 11800000UL, 0x99251F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5191   { 11800000UL, 14400000UL, 0x99261F00UL, cmuHFRCOFreq_13M0Hz     },
5192   { 14400000UL, 17200000UL, 0x99271F00UL, cmuHFRCOFreq_16M0Hz     },
5193   { 17200000UL, 19700000UL, 0x99481F00UL, cmuHFRCOFreq_19M0Hz     },
5194   { 19700000UL, 23800000UL, 0x99491F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5195   { 23800000UL, 28700000UL, 0x994A1F00UL, cmuHFRCOFreq_26M0Hz      },
5196   { 28700000UL, 34800000UL, 0x996B1F00UL, cmuHFRCOFreq_32M0Hz      },
5197 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)  \
5198   || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_89) \
5199   || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_95)
5200   { 34800000UL, 40000000UL, 0x996C1F00UL, cmuHFRCOFreq_38M0Hz      }
5201 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_100) \
5202   || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_106)
5203   { 34800000UL, 42800000UL, 0x996C1F00UL, cmuHFRCOFreq_38M0Hz      },
5204   { 42800000UL, 51600000UL, 0x996D1F00UL, cmuHFRCOFreq_48M0Hz      },
5205   { 51600000UL, 60500000UL, 0x998E1F00UL, cmuHFRCOFreq_56M0Hz      },
5206   { 60500000UL, 72000000UL, 0xA98F1F00UL, cmuHFRCOFreq_64M0Hz      }
5207 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_103)
5208   { 34800000UL, 42800000UL, 0x996C1F00UL, cmuHFRCOFreq_38M0Hz      },
5209   { 42800000UL, 48000000UL, 0x996D1F00UL, cmuHFRCOFreq_48M0Hz      }
5210 #else
5211   #error "HFRCOCTRL values not set for this platform."
5212 #endif
5213 };
5214 
5215 #define HFRCOCTRLTABLE_ENTRIES (sizeof(hfrcoCtrlTable) \
5216                                 / sizeof(struct hfrcoCtrlTableElement))
5217 #endif // CMU_OSCENCMD_DPLLEN
5218 
5219 #if defined(_SILICON_LABS_32B_SERIES_1) && defined(_EMU_STATUS_VSCALE_MASK)
5220 /* Devices with Voltage Scaling needs extra handling of wait states. */
5221 static const struct flashWsTableElement{
5222   uint32_t maxFreq;
5223   uint8_t  vscale;
5224   uint8_t  ws;
5225 } flashWsTable[] =
5226 {
5227 #if (_SILICON_LABS_GECKO_INTERNAL_SDID == 100 || _SILICON_LABS_GECKO_INTERNAL_SDID == 106)
5228   { CMU_MAX_FREQ_0WS_1V2, 0, 0 },  /* 0 wait states at max frequency 18 MHz and 1.2V */
5229   { CMU_MAX_FREQ_1WS_1V2, 0, 1 },  /* 1 wait states at max frequency 36 MHz and 1.2V */
5230   { CMU_MAX_FREQ_2WS_1V2, 0, 2 },  /* 2 wait states at max frequency 54 MHz and 1.2V */
5231   { CMU_MAX_FREQ_3WS_1V2, 0, 3 },  /* 3 wait states at max frequency 72 MHz and 1.2V */
5232   { CMU_MAX_FREQ_0WS_1V0, 2, 0 },  /* 0 wait states at max frequency 7 MHz and 1.0V */
5233   { CMU_MAX_FREQ_1WS_1V0, 2, 1 },  /* 1 wait states at max frequency 14 MHz and 1.0V */
5234   { CMU_MAX_FREQ_2WS_1V0, 2, 2 },  /* 2 wait states at max frequency 21 MHz and 1.0V */
5235 #else
5236   { CMU_MAX_FREQ_0WS_1V2, 0, 0 },  /* 0 wait states at 1.2V */
5237   { CMU_MAX_FREQ_1WS_1V2, 0, 1 },  /* 1 wait states at 1.2V */
5238   { CMU_MAX_FREQ_0WS_1V0, 2, 0 },  /* 0 wait states at 1.0V */
5239   { CMU_MAX_FREQ_1WS_1V0, 2, 1 },  /* 1 wait states at 1.0V */
5240   { CMU_MAX_FREQ_2WS_1V0, 2, 2 },  /* 2 wait states at 1.0V */
5241 #endif
5242 };
5243 
5244 #define FLASH_WS_TABLE_ENTRIES (sizeof(flashWsTable) / sizeof(flashWsTable[0]))
5245 #endif
5246 
5247 #if defined(_CMU_USHFRCOCTRL_FREQRANGE_MASK) \
5248   || defined(_CMU_USHFRCOTUNE_MASK)
5249 #ifndef EFM32_USHFRCO_STARTUP_FREQ
5250 #define EFM32_USHFRCO_STARTUP_FREQ        (48000000UL)
5251 #endif
5252 
5253 static uint32_t ushfrcoFreq = EFM32_USHFRCO_STARTUP_FREQ;
5254 #endif
5255 
5256 /*******************************************************************************
5257  **************************   LOCAL PROTOTYPES   *******************************
5258  ******************************************************************************/
5259 #if defined(_CMU_HFRCOCTRL_FREQRANGE_MASK)
5260 static uint32_t CMU_HFRCODevinfoGet(CMU_HFRCOFreq_TypeDef freq);
5261 #endif
5262 
5263 #if defined(_CMU_USHFRCOCTRL_FREQRANGE_MASK)
5264 static uint32_t CMU_USHFRCODevinfoGet(CMU_USHFRCOFreq_TypeDef freq);
5265 #endif
5266 
5267 static void hfperClkSafePrescaler(void);
5268 static void hfperClkOptimizedPrescaler(void);
5269 
5270 static uint16_t lfxo_precision = 0xFFFF;
5271 
5272 /** @endcond */
5273 
5274 /*******************************************************************************
5275  **************************   LOCAL FUNCTIONS   ********************************
5276  ******************************************************************************/
5277 
5278 #if defined(_SILICON_LABS_32B_SERIES_0) \
5279   && (defined(_EFM32_GIANT_FAMILY)      \
5280   || defined(_EZR32_LEOPARD_FAMILY))
5281 /***************************************************************************//**
5282  * @brief
5283  *   Return maximum allowed frequency for low energy peripherals.
5284  ******************************************************************************/
maxFreqHfle(void)5285 static uint32_t maxFreqHfle(void)
5286 {
5287   uint16_t majorMinorRev;
5288 
5289   switch (SYSTEM_GetFamily()) {
5290     case systemPartFamilyEfm32Leopard:
5291     case systemPartFamilyEzr32Leopard:
5292       /* CHIP MAJOR bit [5:0] */
5293       majorMinorRev = (((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
5294                         >> _ROMTABLE_PID0_REVMAJOR_SHIFT) << 8);
5295       /* CHIP MINOR bit [7:4] */
5296       majorMinorRev |= (((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
5297                          >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4);
5298       /* CHIP MINOR bit [3:0] */
5299       majorMinorRev |=  ((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
5300                          >> _ROMTABLE_PID3_REVMINORLSB_SHIFT);
5301 
5302       if (majorMinorRev >= 0x0204) {
5303         return 24000000;
5304       } else {
5305         return 32000000;
5306       }
5307 
5308     case systemPartFamilyEfm32Giant:
5309       return 32000000;
5310 
5311     default:
5312       /* Invalid device family. */
5313       EFM_ASSERT(false);
5314       return 0;
5315   }
5316 }
5317 #endif
5318 
5319 #if defined(CMU_MAX_FREQ_HFLE)
5320 
5321 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
5322 /* Unified definitions for the HFLE wait-state and prescaler fields. */
5323 #if defined(CMU_CTRL_HFLE)
5324 #define _GENERIC_HFLE_WS_MASK           _CMU_CTRL_HFLE_MASK
5325 #define _GENERIC_HFLE_WS_SHIFT          _CMU_CTRL_HFLE_SHIFT
5326 #define GENERIC_HFLE_PRESC_REG          CMU->HFCORECLKDIV
5327 #define _GENERIC_HFLE_PRESC_MASK        _CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK
5328 #define _GENERIC_HFLE_PRESC_SHIFT       _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT
5329 #elif defined(CMU_CTRL_WSHFLE)
5330 #define _GENERIC_HFLE_WS_MASK           _CMU_CTRL_WSHFLE_MASK
5331 #define _GENERIC_HFLE_WS_SHIFT          _CMU_CTRL_WSHFLE_SHIFT
5332 #define GENERIC_HFLE_PRESC_REG          CMU->HFPRESC
5333 #define _GENERIC_HFLE_PRESC_MASK        _CMU_HFPRESC_HFCLKLEPRESC_MASK
5334 #define _GENERIC_HFLE_PRESC_SHIFT       _CMU_HFPRESC_HFCLKLEPRESC_SHIFT
5335 #endif
5336 /** @endcond */
5337 
5338 /***************************************************************************//**
5339  * @brief
5340  *   Set HFLE wait-states and HFCLKLE prescaler according to wanted HF clock.
5341  *
5342  * @param[in] hfFreq
5343  *   The HF clock frequency to use.
5344  *   This is:
5345  *     CORE clock on Series0 devices.
5346  *     HF clock on on Series1 devices.
5347  ******************************************************************************/
setHfLeConfig(uint32_t hfFreq)5348 static void setHfLeConfig(uint32_t hfFreq)
5349 {
5350   unsigned int hfleWs;
5351   uint32_t hflePresc;
5352 
5353   /* Check for 1 bit fields. @ref BUS_RegBitWrite() below are going to fail if the
5354      fields are changed to more than 1 bit. */
5355   EFM_ASSERT((_GENERIC_HFLE_WS_MASK >> _GENERIC_HFLE_WS_SHIFT) == 0x1U);
5356 
5357   /* - Enable HFLE wait-state to allow access to LE peripherals when HFBUSCLK is
5358        above maxLeFreq.
5359      - Set HFLE prescaler. Allowed HFLE clock frequency is maxLeFreq. */
5360 
5361   hfleWs = 1;
5362   if (hfFreq <= CMU_MAX_FREQ_HFLE) {
5363     hfleWs = 0;
5364     hflePresc = 0;
5365   } else if (hfFreq <= (2UL * CMU_MAX_FREQ_HFLE)) {
5366     hflePresc = 1;
5367   } else {
5368     hflePresc = 2;
5369   }
5370   BUS_RegBitWrite(&CMU->CTRL, _GENERIC_HFLE_WS_SHIFT, hfleWs);
5371   GENERIC_HFLE_PRESC_REG = (GENERIC_HFLE_PRESC_REG & ~_GENERIC_HFLE_PRESC_MASK)
5372                            | (hflePresc << _GENERIC_HFLE_PRESC_SHIFT);
5373 }
5374 
5375 #if defined(_CMU_CTRL_HFLE_MASK)
5376 /***************************************************************************//**
5377  * @brief
5378  *   Get HFLE wait-state configuration.
5379  *
5380  * @return
5381  *   The current wait-state configuration.
5382  ******************************************************************************/
getHfLeConfig(void)5383 static uint32_t getHfLeConfig(void)
5384 {
5385   uint32_t ws = BUS_RegBitRead(&CMU->CTRL, _GENERIC_HFLE_WS_SHIFT);
5386   return ws;
5387 }
5388 #endif
5389 #endif
5390 
5391 /***************************************************************************//**
5392  * @brief
5393  *   Get the AUX clock frequency. Used by MSC flash programming and LESENSE,
5394  *   by default also as a debug clock.
5395  *
5396  * @return
5397  *   AUX Frequency in Hz.
5398  ******************************************************************************/
auxClkGet(void)5399 static uint32_t auxClkGet(void)
5400 {
5401   uint32_t ret;
5402 
5403 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
5404   ret = (uint32_t)auxHfrcoFreq;
5405 
5406 #elif defined(_CMU_AUXHFRCOCTRL_BAND_MASK)
5407   /* All series 0 families except EFM32G */
5408   switch (CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_BAND_MASK) {
5409     case CMU_AUXHFRCOCTRL_BAND_1MHZ:
5410       if ( SYSTEM_GetProdRev() >= 19 ) {
5411         ret = 1200000;
5412       } else {
5413         ret = 1000000;
5414       }
5415       break;
5416 
5417     case CMU_AUXHFRCOCTRL_BAND_7MHZ:
5418       if ( SYSTEM_GetProdRev() >= 19 ) {
5419         ret = 6600000;
5420       } else {
5421         ret = 7000000;
5422       }
5423       break;
5424 
5425     case CMU_AUXHFRCOCTRL_BAND_11MHZ:
5426       ret = 11000000;
5427       break;
5428 
5429     case CMU_AUXHFRCOCTRL_BAND_14MHZ:
5430       ret = 14000000;
5431       break;
5432 
5433     case CMU_AUXHFRCOCTRL_BAND_21MHZ:
5434       ret = 21000000;
5435       break;
5436 
5437 #if defined(_CMU_AUXHFRCOCTRL_BAND_28MHZ)
5438     case CMU_AUXHFRCOCTRL_BAND_28MHZ:
5439       ret = 28000000;
5440       break;
5441 #endif
5442 
5443     default:
5444       ret = 0;
5445       EFM_ASSERT(false);
5446       break;
5447   }
5448 
5449 #else
5450   /* Gecko has a fixed 14 MHz AUXHFRCO clock. */
5451   ret = 14000000;
5452 
5453 #endif
5454 
5455   return ret;
5456 }
5457 
5458 #if defined (_CMU_ADCCTRL_ADC0CLKSEL_HFSRCCLK) \
5459   || defined (_CMU_ADCCTRL_ADC1CLKSEL_HFSRCCLK)
5460 /***************************************************************************//**
5461  * @brief
5462  *   Get the HFSRCCLK frequency.
5463  *
5464  * @return
5465  *   HFSRCCLK Frequency in Hz.
5466  ******************************************************************************/
hfSrcClkGet(void)5467 static uint32_t hfSrcClkGet(void)
5468 {
5469   uint32_t ret;
5470 
5471   ret = SystemHFClockGet();
5472   return ret * (1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
5473                       >> _CMU_HFPRESC_PRESC_SHIFT));
5474 }
5475 #endif
5476 
5477 /***************************************************************************//**
5478  * @brief
5479  *   Get the Debug Trace clock frequency.
5480  *
5481  * @return
5482  *   Debug Trace frequency in Hz.
5483  ******************************************************************************/
dbgClkGet(void)5484 static uint32_t dbgClkGet(void)
5485 {
5486   uint32_t ret;
5487   CMU_Select_TypeDef clk;
5488 
5489   /* Get selected clock source */
5490   clk = CMU_ClockSelectGet(cmuClock_DBG);
5491 
5492   switch (clk) {
5493     case cmuSelect_HFCLK:
5494       ret = SystemHFClockGet();
5495       break;
5496 
5497     case cmuSelect_AUXHFRCO:
5498       ret = auxClkGet();
5499       break;
5500 
5501     default:
5502       ret = 0;
5503       EFM_ASSERT(false);
5504       break;
5505   }
5506   return ret;
5507 }
5508 
5509 #if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
5510 /***************************************************************************//**
5511  * @brief
5512  *   Get the ADC n asynchronous clock frequency.
5513  *
5514  * @return
5515  *   ADC n asynchronous frequency in Hz.
5516  ******************************************************************************/
adcAsyncClkGet(uint32_t adc)5517 static uint32_t adcAsyncClkGet(uint32_t adc)
5518 {
5519   uint32_t ret;
5520   CMU_Select_TypeDef clk;
5521 
5522   /* Get the selected clock source. */
5523   switch (adc) {
5524     case 0:
5525       clk = CMU_ClockSelectGet(cmuClock_ADC0ASYNC);
5526       break;
5527 
5528 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
5529     case 1:
5530       clk = CMU_ClockSelectGet(cmuClock_ADC1ASYNC);
5531       break;
5532 #endif
5533 
5534     default:
5535       EFM_ASSERT(false);
5536       return 0;
5537   }
5538 
5539   switch (clk) {
5540     case cmuSelect_Disabled:
5541       ret = 0;
5542       break;
5543 
5544     case cmuSelect_AUXHFRCO:
5545       ret = auxClkGet();
5546       break;
5547 
5548     case cmuSelect_HFXO:
5549       ret = SystemHFXOClockGet();
5550       break;
5551 
5552     case cmuSelect_HFSRCCLK:
5553       ret = hfSrcClkGet();
5554       break;
5555 
5556     default:
5557       ret = 0;
5558       EFM_ASSERT(false);
5559       break;
5560   }
5561   return ret;
5562 }
5563 #endif
5564 
5565 #if defined(_CMU_SDIOCTRL_MASK)
5566 /***************************************************************************//**
5567  * @brief
5568  *   Get the SDIO reference clock frequency.
5569  *
5570  * @return
5571  *   SDIO reference clock frequency in Hz.
5572  ******************************************************************************/
sdioRefClkGet(void)5573 static uint32_t sdioRefClkGet(void)
5574 {
5575   uint32_t ret;
5576   CMU_Select_TypeDef clk;
5577 
5578   /* Get the selected clock source. */
5579   clk = CMU_ClockSelectGet(cmuClock_SDIOREF);
5580 
5581   switch (clk) {
5582     case cmuSelect_HFRCO:
5583       ret = SystemHfrcoFreq;
5584       break;
5585 
5586     case cmuSelect_HFXO:
5587       ret = SystemHFXOClockGet();
5588       break;
5589 
5590     case cmuSelect_AUXHFRCO:
5591       ret = auxClkGet();
5592       break;
5593 
5594     case cmuSelect_USHFRCO:
5595       ret = ushfrcoFreq;
5596       break;
5597 
5598     default:
5599       ret = 0;
5600       EFM_ASSERT(false);
5601       break;
5602   }
5603   return ret;
5604 }
5605 #endif
5606 
5607 #if defined(_CMU_QSPICTRL_MASK)
5608 /***************************************************************************//**
5609  * @brief
5610  *   Get the QSPI n reference clock frequency.
5611  *
5612  * @return
5613  *   QSPI n reference clock frequency in Hz.
5614  ******************************************************************************/
qspiRefClkGet(uint32_t qspi)5615 static uint32_t qspiRefClkGet(uint32_t qspi)
5616 {
5617   uint32_t ret;
5618   CMU_Select_TypeDef clk;
5619 
5620   /* Get the selected clock source. */
5621   switch (qspi) {
5622     case 0:
5623       clk = CMU_ClockSelectGet(cmuClock_QSPI0REF);
5624       break;
5625 
5626     default:
5627       EFM_ASSERT(false);
5628       return 0;
5629   }
5630 
5631   switch (clk) {
5632     case cmuSelect_HFRCO:
5633       ret = SystemHfrcoFreq;
5634       break;
5635 
5636     case cmuSelect_HFXO:
5637       ret = SystemHFXOClockGet();
5638       break;
5639 
5640     case cmuSelect_AUXHFRCO:
5641       ret = auxClkGet();
5642       break;
5643 
5644     case cmuSelect_USHFRCO:
5645       ret = ushfrcoFreq;
5646       break;
5647 
5648     default:
5649       ret = 0;
5650       EFM_ASSERT(false);
5651       break;
5652   }
5653   return ret;
5654 }
5655 #endif
5656 
5657 #if defined(_CMU_PDMCTRL_MASK)
5658 /***************************************************************************//**
5659  * @brief
5660  *   Get the PDM reference clock frequency.
5661  *
5662  * @return
5663  *   PDM reference clock frequency in Hz.
5664  ******************************************************************************/
pdmRefClkGet(void)5665 static uint32_t pdmRefClkGet(void)
5666 {
5667   uint32_t ret;
5668   CMU_Select_TypeDef clk;
5669 
5670   /* Get the selected clock source. */
5671   clk = CMU_ClockSelectGet(cmuClock_PDMREF);
5672 
5673   switch (clk) {
5674     case cmuSelect_HFRCO:
5675       ret = SystemHfrcoFreq;
5676       break;
5677 
5678     case cmuSelect_HFXO:
5679       ret = SystemHFXOClockGet();
5680       break;
5681 
5682     case cmuSelect_USHFRCO:
5683       ret = ushfrcoFreq;
5684       break;
5685 
5686     default:
5687       ret = 0;
5688       EFM_ASSERT(false);
5689       break;
5690   }
5691   return ret;
5692 }
5693 #endif
5694 
5695 #if defined(USBR_CLOCK_PRESENT)
5696 /***************************************************************************//**
5697  * @brief
5698  *   Get the USB rate clock frequency.
5699  *
5700  * @return
5701  *   USB rate clock frequency in Hz.
5702  ******************************************************************************/
usbRateClkGet(void)5703 static uint32_t usbRateClkGet(void)
5704 {
5705   uint32_t ret;
5706   CMU_Select_TypeDef clk;
5707 
5708   clk = CMU_ClockSelectGet(cmuClock_USBR);
5709 
5710   switch (clk) {
5711     case cmuSelect_USHFRCO:
5712       ret = ushfrcoFreq;
5713       break;
5714 
5715     case cmuSelect_HFXO:
5716       ret = SystemHFXOClockGet();
5717       break;
5718 
5719     case cmuSelect_HFXOX2:
5720       ret = 2u * SystemHFXOClockGet();
5721       break;
5722 
5723     case cmuSelect_HFRCO:
5724       ret = SystemHfrcoFreq;
5725       break;
5726 
5727     case cmuSelect_LFXO:
5728       ret = SystemLFXOClockGet();
5729       break;
5730 
5731     case cmuSelect_LFRCO:
5732       ret = SystemLFRCOClockGet();
5733       break;
5734 
5735     default:
5736       ret = 0;
5737       EFM_ASSERT(false);
5738       break;
5739   }
5740   return ret;
5741 }
5742 #endif
5743 
5744 /***************************************************************************//**
5745  * @brief
5746  *   Configure flash access wait states to support the given core clock
5747  *   frequency.
5748  *
5749  * @param[in] coreFreq
5750  *   The core clock frequency to configure flash wait-states.
5751  *
5752  * @param[in] vscale
5753  *   Voltage Scale level. Supported levels are 0 and 2 where 0 is the default.
5754  ******************************************************************************/
flashWaitStateControl(uint32_t coreFreq,int vscale)5755 static void flashWaitStateControl(uint32_t coreFreq, int vscale)
5756 {
5757   uint32_t mode;
5758 #if defined(MSC_READCTRL_MODE_WS0SCBTP)
5759   bool scbtpEn;   /* Suppressed Conditional Branch Target Prefetch setting. */
5760 #endif
5761   (void) vscale;  /* vscale parameter is only used on some devices. */
5762 
5763   /* Get mode and SCBTP enable. */
5764   mode = MSC_ReadCTRLGet() & _MSC_READCTRL_MODE_MASK;
5765 
5766 #if defined(_SILICON_LABS_32B_SERIES_0)
5767 #if defined(MSC_READCTRL_MODE_WS0SCBTP)
5768   /* Devices with MODE and SCBTP in the same register field. */
5769   switch (mode) {
5770     case MSC_READCTRL_MODE_WS0:
5771     case MSC_READCTRL_MODE_WS1:
5772 #if defined(MSC_READCTRL_MODE_WS2)
5773     case MSC_READCTRL_MODE_WS2:
5774 #endif
5775       scbtpEn = false;
5776       break;
5777 
5778     default: /* WSxSCBTP */
5779       scbtpEn = true;
5780       break;
5781   }
5782 
5783   /* Set mode based on the core clock frequency and SCBTP enable. */
5784   if (false) {
5785   }
5786 #if defined(MSC_READCTRL_MODE_WS2)
5787   else if (coreFreq > CMU_MAX_FREQ_1WS) {
5788     mode = (scbtpEn ? MSC_READCTRL_MODE_WS2SCBTP : MSC_READCTRL_MODE_WS2);
5789   }
5790 #endif
5791   else if ((coreFreq <= CMU_MAX_FREQ_1WS) && (coreFreq > CMU_MAX_FREQ_0WS)) {
5792     mode = (scbtpEn ? MSC_READCTRL_MODE_WS1SCBTP : MSC_READCTRL_MODE_WS1);
5793   } else {
5794     mode = (scbtpEn ? MSC_READCTRL_MODE_WS0SCBTP : MSC_READCTRL_MODE_WS0);
5795   }
5796 #else /* defined(MSC_READCTRL_MODE_WS0SCBTP) */
5797 
5798   if (coreFreq <= CMU_MAX_FREQ_0WS) {
5799     mode = 0;
5800   } else if (coreFreq <= CMU_MAX_FREQ_1WS) {
5801     mode = 1;
5802   }
5803 #endif /* defined(MSC_READCTRL_MODE_WS0SCBTP) */
5804 // End defined(_SILICON_LABS_32B_SERIES_0)
5805 
5806 #elif defined(_SILICON_LABS_32B_SERIES_1)
5807 #if defined(_EMU_STATUS_VSCALE_MASK)
5808 
5809   /* These devices have specific requirements on the supported flash wait state
5810    * depending on the frequency and voltage scale level. */
5811   uint32_t i;
5812   for (i = 0; i < FLASH_WS_TABLE_ENTRIES; i++) {
5813     if ((flashWsTable[i].vscale == (uint8_t)vscale)
5814         && (coreFreq <= flashWsTable[i].maxFreq)) {
5815       break; // Found a matching entry.
5816     }
5817   }
5818 
5819   if (i == FLASH_WS_TABLE_ENTRIES) {
5820     mode = 3; // Worst case flash wait state for unsupported cases.
5821     EFM_ASSERT(false);
5822   } else {
5823     mode = flashWsTable[i].ws;
5824   }
5825   mode = mode << _MSC_READCTRL_MODE_SHIFT;
5826 
5827 #else
5828   /* Devices where MODE and SCBTP are in separate fields and where the device
5829    * either does not support voltage scale or where the voltage scale does
5830    * not impact the flash wait state configuration. */
5831   if (coreFreq <= CMU_MAX_FREQ_0WS_1V2) {
5832     mode = 0;
5833   } else if (coreFreq <= CMU_MAX_FREQ_1WS_1V2) {
5834     mode = 1;
5835   }
5836 #if defined(MSC_READCTRL_MODE_WS2)
5837   else if (coreFreq <= CMU_MAX_FREQ_2WS) {
5838     mode = 2;
5839   }
5840 #endif
5841 #if defined(MSC_READCTRL_MODE_WS3)
5842   else if (coreFreq <= CMU_MAX_FREQ_3WS) {
5843     mode = 3;
5844   }
5845 #endif
5846   mode = mode << _MSC_READCTRL_MODE_SHIFT;
5847 #endif
5848 // End defined(_SILICON_LABS_32B_SERIES_1)
5849 
5850 #else
5851 #error "Undefined 32B SERIES!"
5852 #endif
5853 
5854   mode = (MSC_ReadCTRLGet() & ~_MSC_READCTRL_MODE_MASK) | mode;
5855   MSC_ReadCTRLSet(mode);
5856 }
5857 
5858 /***************************************************************************//**
5859  * @brief
5860  *   Configure flash access wait states to the most conservative setting for
5861  *   this target. Retain SCBTP (Suppressed Conditional Branch Target Prefetch)
5862  *   setting.
5863  ******************************************************************************/
flashWaitStateMax(void)5864 static void flashWaitStateMax(void)
5865 {
5866   /* Make sure the MSC is unlocked */
5867   bool mscLocked = MSC_LockGetLocked();
5868   MSC_LockSetUnlocked();
5869 
5870   flashWaitStateControl(SystemMaxCoreClockGet(), 0);
5871 
5872   if (mscLocked) {
5873     MSC_LockSetLocked();
5874   }
5875 }
5876 
5877 #if defined(_MSC_RAMCTRL_RAMWSEN_MASK)
5878 /***************************************************************************//**
5879  * @brief
5880  *   Configure RAM access wait states to support the given core clock
5881  *   frequency.
5882  *
5883  * @param[in] coreFreq
5884  *   The core clock frequency to configure RAM wait-states.
5885  *
5886  * @param[in] vscale
5887  *   A voltage scale level. Supported levels are 0 and 2 where 0 is the default.
5888  ******************************************************************************/
setRamWaitState(uint32_t coreFreq,int vscale)5889 static void setRamWaitState(uint32_t coreFreq, int vscale)
5890 {
5891   uint32_t limit = 38000000;
5892   if (vscale == 2) {
5893     limit = 16000000;
5894   }
5895 
5896   if (coreFreq > limit) {
5897     BUS_RegMaskedSet(&MSC->RAMCTRL, (MSC_RAMCTRL_RAMWSEN
5898                                      | MSC_RAMCTRL_RAM1WSEN
5899                                      | MSC_RAMCTRL_RAM2WSEN));
5900   } else {
5901     BUS_RegMaskedClear(&MSC->RAMCTRL, (MSC_RAMCTRL_RAMWSEN
5902                                        | MSC_RAMCTRL_RAM1WSEN
5903                                        | MSC_RAMCTRL_RAM2WSEN));
5904   }
5905 }
5906 #endif
5907 
5908 #if defined(_MSC_CTRL_WAITMODE_MASK)
5909 /***************************************************************************//**
5910  * @brief
5911  *   Configure the wait state for peripheral accesses over the bus to support
5912  *   the given bus clock frequency.
5913  *
5914  * @param[in] busFreq
5915  *   A peripheral bus clock frequency to configure wait-states.
5916  *
5917  * @param[in] vscale
5918  *   The voltage scale to configure wait-states. Expected values are
5919  *   0 or 2.
5920  *
5921  *   @li 0 = 1.2 V (VSCALE2)
5922  *   @li 2 = 1.0 V (VSCALE0)
5923  * ******************************************************************************/
setBusWaitState(uint32_t busFreq,int vscale)5924 static void setBusWaitState(uint32_t busFreq, int vscale)
5925 {
5926   if ((busFreq > 50000000) && (vscale == 0)) {
5927     BUS_RegMaskedSet(&MSC->CTRL, MSC_CTRL_WAITMODE_WS1);
5928   } else {
5929     BUS_RegMaskedClear(&MSC->CTRL, MSC_CTRL_WAITMODE_WS1);
5930   }
5931 }
5932 #endif
5933 
5934 #if defined(PLFRCO_PRESENT)
deviceHasPlfrco(void)5935 static bool deviceHasPlfrco(void)
5936 {
5937   SYSTEM_ChipRevision_TypeDef rev;
5938 
5939   if (_SILICON_LABS_GECKO_INTERNAL_SDID == 89) {
5940     // check the xG13 rev and check if it's >= Rev A3
5941     SYSTEM_ChipRevisionGet(&rev);
5942     return (rev.major > 1) || (rev.minor >= 3);
5943   } else {
5944     return false;
5945   }
5946 }
5947 #endif
5948 
5949 /***************************************************************************//**
5950  * @brief
5951  *   Configure various wait states to switch to a certain frequency
5952  *   and a certain voltage scale.
5953  *
5954  * @details
5955  *   This function will set up the necessary flash, bus, and RAM wait states.
5956  *   Updating the wait state configuration must be done before
5957  *   increasing the clock frequency and it must be done after decreasing the
5958  *   clock frequency. Updating the wait state configuration must be done before
5959  *   core voltage is decreased and it must be done after a core voltage is
5960  *   increased.
5961  *
5962  * @param[in] freq
5963  *   The core clock frequency to configure wait-states.
5964  *
5965  * @param[in] vscale
5966  *   The voltage scale to configure wait-states. Expected values are
5967  *   0 or 2, higher number is lower voltage.
5968  *
5969  *   @li 0 = 1.2 V (VSCALE2)
5970  *   @li 2 = 1.0 V (VSCALE0)
5971  *
5972  ******************************************************************************/
CMU_UpdateWaitStates(uint32_t freq,int vscale)5973 void CMU_UpdateWaitStates(uint32_t freq, int vscale)
5974 {
5975   /* Make sure the MSC is unlocked */
5976   bool mscLocked = MSC_LockGetLocked();
5977   MSC_LockSetUnlocked();
5978 
5979   flashWaitStateControl(freq, vscale);
5980 #if defined(_MSC_RAMCTRL_RAMWSEN_MASK)
5981   setRamWaitState(freq, vscale);
5982 #endif
5983 #if defined(_MSC_CTRL_WAITMODE_MASK)
5984   setBusWaitState(freq, vscale);
5985 #endif
5986 
5987   if (mscLocked) {
5988     MSC_LockSetLocked();
5989   }
5990 }
5991 
5992 #if defined(_CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK)
5993 /***************************************************************************//**
5994  * @brief
5995  *   Return the upper value for CMU_HFXOSTEADYSTATECTRL_REGISH.
5996  ******************************************************************************/
getRegIshUpperVal(uint32_t steadyStateRegIsh)5997 static uint32_t getRegIshUpperVal(uint32_t steadyStateRegIsh)
5998 {
5999   uint32_t regIshUpper;
6000   const uint32_t upperMax = _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK
6001                             >> _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_SHIFT;
6002   /* Add 3 as specified in the register description for CMU_HFXOSTEADYSTATECTRL_REGISHUPPER. */
6003   regIshUpper = SL_MIN(steadyStateRegIsh + 3UL, upperMax);
6004   regIshUpper <<= _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_SHIFT;
6005   return regIshUpper;
6006 }
6007 #endif
6008 
6009 #if defined(_CMU_HFXOCTRL_MASK)
6010 /***************************************************************************//**
6011  * @brief
6012  *   Get the HFXO tuning mode.
6013  *
6014  * @return
6015  *   The current HFXO tuning mode from the HFXOCTRL register.
6016  ******************************************************************************/
getHfxoTuningMode(void)6017 __STATIC_INLINE uint32_t getHfxoTuningMode(void)
6018 {
6019 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
6020   return (CMU->HFXOCTRL & _CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
6021          >> _CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_SHIFT;
6022 #else
6023   return (CMU->HFXOCTRL & _CMU_HFXOCTRL_PEAKDETMODE_MASK)
6024          >> _CMU_HFXOCTRL_PEAKDETMODE_SHIFT;
6025 #endif
6026 }
6027 
6028 /***************************************************************************//**
6029  * @brief
6030  *   Set the HFXO tuning mode.
6031  *
6032  * @param[in] mode
6033  *   The new HFXO tuning mode. This can be HFXO_TUNING_MODE_AUTO or
6034  *   HFXO_TUNING_MODE_CMD.
6035  ******************************************************************************/
setHfxoTuningMode(uint32_t mode)6036 __STATIC_INLINE void setHfxoTuningMode(uint32_t mode)
6037 {
6038 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
6039   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
6040                   | (mode << _CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_SHIFT);
6041 #else
6042   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_PEAKDETMODE_MASK)
6043                   | (mode << _CMU_HFXOCTRL_PEAKDETMODE_SHIFT);
6044 #endif
6045 }
6046 #endif
6047 
6048 /***************************************************************************//**
6049  * @brief
6050  *   Get the LFnCLK frequency based on the current configuration.
6051  *
6052  * @param[in] lfClkBranch
6053  *   Selected LF branch.
6054  *
6055  * @return
6056  *   The LFnCLK frequency in Hz. If no LFnCLK is selected (disabled), 0 is
6057  *   returned.
6058  ******************************************************************************/
lfClkGet(CMU_Clock_TypeDef lfClkBranch)6059 static uint32_t lfClkGet(CMU_Clock_TypeDef lfClkBranch)
6060 {
6061   uint32_t sel;
6062   uint32_t ret = 0;
6063 
6064   switch (lfClkBranch) {
6065     case cmuClock_LFA:
6066     case cmuClock_LFB:
6067 #if defined(_CMU_LFCCLKEN0_MASK)
6068     case cmuClock_LFC:
6069 #endif
6070 #if defined(_CMU_LFECLKSEL_MASK)
6071     case cmuClock_LFE:
6072 #endif
6073       break;
6074 
6075     default:
6076       EFM_ASSERT(false);
6077       break;
6078   }
6079 
6080   sel = (uint32_t)CMU_ClockSelectGet(lfClkBranch);
6081 
6082   /* Get clock select field */
6083   switch (lfClkBranch) {
6084     case cmuClock_LFA:
6085 #if defined(_CMU_LFCLKSEL_MASK)
6086       sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFA_MASK) >> _CMU_LFCLKSEL_LFA_SHIFT;
6087 #elif defined(_CMU_LFACLKSEL_MASK)
6088       sel = (CMU->LFACLKSEL & _CMU_LFACLKSEL_LFA_MASK) >> _CMU_LFACLKSEL_LFA_SHIFT;
6089 #else
6090       EFM_ASSERT(false);
6091 #endif
6092       break;
6093 
6094     case cmuClock_LFB:
6095 #if defined(_CMU_LFCLKSEL_MASK)
6096       sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFB_MASK) >> _CMU_LFCLKSEL_LFB_SHIFT;
6097 #elif defined(_CMU_LFBCLKSEL_MASK)
6098       sel = (CMU->LFBCLKSEL & _CMU_LFBCLKSEL_LFB_MASK) >> _CMU_LFBCLKSEL_LFB_SHIFT;
6099 #else
6100       EFM_ASSERT(false);
6101 #endif
6102       break;
6103 
6104 #if defined(_CMU_LFCCLKEN0_MASK)
6105     case cmuClock_LFC:
6106 #if defined(_CMU_LFCLKSEL_LFC_MASK)
6107       sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFC_MASK) >> _CMU_LFCLKSEL_LFC_SHIFT;
6108 #elif defined(_CMU_LFCCLKSEL_LFC_MASK)
6109       sel = (CMU->LFCCLKSEL & _CMU_LFCCLKSEL_LFC_MASK) >> _CMU_LFCCLKSEL_LFC_SHIFT;
6110 #else
6111       EFM_ASSERT(false);
6112 #endif
6113       break;
6114 #endif
6115 
6116 #if defined(_CMU_LFECLKSEL_MASK)
6117     case cmuClock_LFE:
6118       sel = (CMU->LFECLKSEL & _CMU_LFECLKSEL_LFE_MASK) >> _CMU_LFECLKSEL_LFE_SHIFT;
6119       break;
6120 #endif
6121 
6122     default:
6123       EFM_ASSERT(false);
6124       break;
6125   }
6126 
6127   /* Get the clock frequency. */
6128 #if defined(_CMU_LFCLKSEL_MASK)
6129   switch (sel) {
6130     case _CMU_LFCLKSEL_LFA_LFRCO:
6131       ret = SystemLFRCOClockGet();
6132       break;
6133 
6134     case _CMU_LFCLKSEL_LFA_LFXO:
6135       ret = SystemLFXOClockGet();
6136       break;
6137 
6138 #if defined(_CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2)
6139     case _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2:
6140 #if defined(CMU_MAX_FREQ_HFLE)
6141       /* HFLE bit is or'ed by hardware with HFCORECLKLEDIV to reduce the
6142        * frequency of CMU_HFCORECLKLEDIV2. */
6143       ret = SystemCoreClockGet() / (1U << (getHfLeConfig() + 1));
6144 #else
6145       ret = SystemCoreClockGet() / 2U;
6146 #endif
6147       break;
6148 #endif
6149 
6150     case _CMU_LFCLKSEL_LFA_DISABLED:
6151       ret = 0;
6152 #if defined(CMU_LFCLKSEL_LFAE)
6153       /* Check LF Extended bit setting for LFA or LFB ULFRCO clock. */
6154       if ((lfClkBranch == cmuClock_LFA) || (lfClkBranch == cmuClock_LFB)) {
6155         if (CMU->LFCLKSEL >> (lfClkBranch == cmuClock_LFA
6156                               ? _CMU_LFCLKSEL_LFAE_SHIFT
6157                               : _CMU_LFCLKSEL_LFBE_SHIFT)) {
6158           ret = SystemULFRCOClockGet();
6159         }
6160       }
6161 #endif
6162       break;
6163 
6164     default:
6165       ret = 0U;
6166       EFM_ASSERT(false);
6167       break;
6168   }
6169 #endif /* _CMU_LFCLKSEL_MASK */
6170 
6171 #if defined(_CMU_LFACLKSEL_MASK)
6172   switch (sel) {
6173     case _CMU_LFACLKSEL_LFA_LFRCO:
6174       ret = SystemLFRCOClockGet();
6175       break;
6176 
6177     case _CMU_LFACLKSEL_LFA_LFXO:
6178       ret = SystemLFXOClockGet();
6179       break;
6180 
6181     case _CMU_LFACLKSEL_LFA_ULFRCO:
6182       ret = SystemULFRCOClockGet();
6183       break;
6184 
6185 #if defined(PLFRCO_PRESENT)
6186     case _CMU_LFACLKSEL_LFA_PLFRCO:
6187       ret = SystemLFRCOClockGet();
6188       break;
6189 #endif
6190 
6191 #if defined(_CMU_LFBCLKSEL_LFB_HFCLKLE)
6192     case _CMU_LFBCLKSEL_LFB_HFCLKLE:
6193       ret = SystemHFClockGet()
6194             / SL_Log2ToDiv(((CMU->HFPRESC & _CMU_HFPRESC_HFCLKLEPRESC_MASK)
6195                             >> _CMU_HFPRESC_HFCLKLEPRESC_SHIFT) + 1UL);
6196       break;
6197 #endif
6198 
6199     case _CMU_LFACLKSEL_LFA_DISABLED:
6200       ret = 0;
6201       break;
6202 
6203     default:
6204       ret = 0U;
6205       EFM_ASSERT(false);
6206       break;
6207   }
6208 #endif
6209 
6210   return ret;
6211 }
6212 
6213 /***************************************************************************//**
6214  * @brief
6215  *   Wait for an ongoing sync of register(s) to low-frequency domain to complete.
6216  *
6217  * @param[in] mask
6218  *   A bitmask corresponding to SYNCBUSY register defined bits, indicating
6219  *   registers that must complete any ongoing synchronization.
6220  ******************************************************************************/
syncReg(uint32_t mask)6221 __STATIC_INLINE void syncReg(uint32_t mask)
6222 {
6223   /* Avoid a deadlock if modifying the same register twice when freeze mode is */
6224   /* activated. */
6225   if ((CMU->FREEZE & CMU_FREEZE_REGFREEZE) != 0UL) {
6226     return;
6227   }
6228 
6229   /* Wait for any pending previous write operation to complete */
6230   /* in low-frequency domain. */
6231   while ((CMU->SYNCBUSY & mask) != 0UL) {
6232   }
6233 }
6234 
6235 #if defined(USBC_CLOCK_PRESENT)
6236 /***************************************************************************//**
6237  * @brief
6238  *   Get the USBC frequency.
6239  *
6240  * @return
6241  *   USBC frequency in Hz.
6242  ******************************************************************************/
usbCClkGet(void)6243 static uint32_t usbCClkGet(void)
6244 {
6245   uint32_t ret;
6246   CMU_Select_TypeDef clk;
6247 
6248   /* Get the selected clock source. */
6249   clk = CMU_ClockSelectGet(cmuClock_USBC);
6250 
6251   switch (clk) {
6252     case cmuSelect_LFXO:
6253       ret = SystemLFXOClockGet();
6254       break;
6255     case cmuSelect_LFRCO:
6256       ret = SystemLFRCOClockGet();
6257       break;
6258 #if defined (_CMU_USHFRCOCTRL_MASK)
6259     case cmuSelect_USHFRCO:
6260       ret = ushfrcoFreq;
6261       break;
6262 #endif
6263     case cmuSelect_HFCLK:
6264       ret = SystemHFClockGet();
6265       break;
6266     default:
6267       /* Clock is not enabled */
6268       ret = 0;
6269       break;
6270   }
6271   return ret;
6272 }
6273 #endif
6274 
6275 /***************************************************************************//**
6276  * @brief
6277  *   Set HFPER clock tree prescalers to safe values.
6278  *
6279  * @note
6280  *   This function applies to EFM32GG11B. There are 3 HFPER clock trees with
6281  *   these frequency limits:
6282  *     HFPERCLK  (A-tree): 20MHz in VSCALE0 mode, 50MHz in VSCALE2 mode.
6283  *     HFPERBCLK (B-tree): 20MHz in VSCALE0 mode, 72MHz in VSCALE2 mode.
6284  *     HFPERCCLK (C-tree): 20MHz in VSCALE0 mode, 50MHz in VSCALE2 mode.
6285  ******************************************************************************/
hfperClkSafePrescaler(void)6286 static void hfperClkSafePrescaler(void)
6287 {
6288 #if defined(_CMU_HFPERPRESC_MASK) && defined(_CMU_HFPERPRESCB_MASK) \
6289   && defined(_CMU_HFPERPRESCC_MASK)
6290   // Assuming a maximum HFCLK of 72MHz, set prescalers to DIV4.
6291   CMU_ClockPrescSet(cmuClock_HFPER, 3U);
6292   CMU_ClockPrescSet(cmuClock_HFPERB, 3U);
6293   CMU_ClockPrescSet(cmuClock_HFPERC, 3U);
6294 #endif
6295 }
6296 
6297 /***************************************************************************//**
6298  * @brief
6299  *   Set HFPER clock tree prescalers to give highest possible clock node
6300  *   frequency while still beeing within spec.
6301  *
6302  * @note
6303  *   This function applies to EFM32GG11B. There are 3 HFPER clock trees with
6304  *   these frequency limits:
6305  *     HFPERCLK  (A-tree): 20MHz in VSCALE0 mode, 50MHz in VSCALE2 mode.
6306  *     HFPERBCLK (B-tree): 20MHz in VSCALE0 mode, 72MHz in VSCALE2 mode.
6307  *     HFPERCCLK (C-tree): 20MHz in VSCALE0 mode, 50MHz in VSCALE2 mode.
6308  ******************************************************************************/
hfperClkOptimizedPrescaler(void)6309 static void hfperClkOptimizedPrescaler(void)
6310 {
6311 #if defined(_CMU_HFPERPRESC_MASK) && defined(_CMU_HFPERPRESCB_MASK) \
6312   && defined(_CMU_HFPERPRESCC_MASK)
6313   uint32_t hfClkFreq, divisor;
6314 
6315   hfClkFreq = SystemHFClockGet();
6316 
6317   if ( EMU_VScaleGet() == emuVScaleEM01_LowPower) {
6318     divisor = (hfClkFreq + 20000000U - 1U) / 20000000U; // ceil(x)
6319     if (divisor > 0U) {
6320       divisor--;                                        // Convert to prescaler
6321     }
6322     CMU_ClockPrescSet(cmuClock_HFPER, divisor);
6323     CMU_ClockPrescSet(cmuClock_HFPERB, divisor);
6324     CMU_ClockPrescSet(cmuClock_HFPERC, divisor);
6325   } else {
6326     divisor = (hfClkFreq + 50000000U - 1U) / 50000000U;
6327     if (divisor > 0U) {
6328       divisor--;
6329     }
6330     CMU_ClockPrescSet(cmuClock_HFPER, divisor);
6331     CMU_ClockPrescSet(cmuClock_HFPERC, divisor);
6332 
6333     divisor = (hfClkFreq + 72000000U - 1U) / 72000000U;
6334     if (divisor > 0U) {
6335       divisor--;
6336     }
6337     CMU_ClockPrescSet(cmuClock_HFPERB, divisor);
6338   }
6339 #endif
6340 }
6341 
6342 /*******************************************************************************
6343  **************************   GLOBAL FUNCTIONS   *******************************
6344  ******************************************************************************/
6345 
6346 #if defined(_CMU_AUXHFRCOCTRL_BAND_MASK)
6347 /***************************************************************************//**
6348  * @brief
6349  *   Get the AUXHFRCO band in use.
6350  *
6351  * @return
6352  *   AUXHFRCO band in use.
6353  ******************************************************************************/
CMU_AUXHFRCOBandGet(void)6354 CMU_AUXHFRCOBand_TypeDef CMU_AUXHFRCOBandGet(void)
6355 {
6356   return (CMU_AUXHFRCOBand_TypeDef)((CMU->AUXHFRCOCTRL
6357                                      & _CMU_AUXHFRCOCTRL_BAND_MASK)
6358                                     >> _CMU_AUXHFRCOCTRL_BAND_SHIFT);
6359 }
6360 #endif /* _CMU_AUXHFRCOCTRL_BAND_MASK */
6361 
6362 #if defined(_CMU_AUXHFRCOCTRL_BAND_MASK)
6363 /***************************************************************************//**
6364  * @brief
6365  *   Set the AUXHFRCO band and the tuning value based on the value in the
6366  *   calibration table made during production.
6367  *
6368  * @param[in] band
6369  *   AUXHFRCO band to activate.
6370  ******************************************************************************/
CMU_AUXHFRCOBandSet(CMU_AUXHFRCOBand_TypeDef band)6371 void CMU_AUXHFRCOBandSet(CMU_AUXHFRCOBand_TypeDef band)
6372 {
6373   uint32_t tuning;
6374 
6375   /* Read a tuning value from the calibration table. */
6376   switch (band) {
6377     case cmuAUXHFRCOBand_1MHz:
6378       tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND1_MASK)
6379                >> _DEVINFO_AUXHFRCOCAL0_BAND1_SHIFT;
6380       break;
6381 
6382     case cmuAUXHFRCOBand_7MHz:
6383       tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND7_MASK)
6384                >> _DEVINFO_AUXHFRCOCAL0_BAND7_SHIFT;
6385       break;
6386 
6387     case cmuAUXHFRCOBand_11MHz:
6388       tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND11_MASK)
6389                >> _DEVINFO_AUXHFRCOCAL0_BAND11_SHIFT;
6390       break;
6391 
6392     case cmuAUXHFRCOBand_14MHz:
6393       tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND14_MASK)
6394                >> _DEVINFO_AUXHFRCOCAL0_BAND14_SHIFT;
6395       break;
6396 
6397     case cmuAUXHFRCOBand_21MHz:
6398       tuning = (DEVINFO->AUXHFRCOCAL1 & _DEVINFO_AUXHFRCOCAL1_BAND21_MASK)
6399                >> _DEVINFO_AUXHFRCOCAL1_BAND21_SHIFT;
6400       break;
6401 
6402 #if defined(_CMU_AUXHFRCOCTRL_BAND_28MHZ)
6403     case cmuAUXHFRCOBand_28MHz:
6404       tuning = (DEVINFO->AUXHFRCOCAL1 & _DEVINFO_AUXHFRCOCAL1_BAND28_MASK)
6405                >> _DEVINFO_AUXHFRCOCAL1_BAND28_SHIFT;
6406       break;
6407 #endif
6408 
6409     default:
6410       EFM_ASSERT(false);
6411       return;
6412   }
6413 
6414   /* Set band/tuning. */
6415   CMU->AUXHFRCOCTRL = (CMU->AUXHFRCOCTRL
6416                        & ~(_CMU_AUXHFRCOCTRL_BAND_MASK
6417                            | _CMU_AUXHFRCOCTRL_TUNING_MASK))
6418                       | (band << _CMU_AUXHFRCOCTRL_BAND_SHIFT)
6419                       | (tuning << _CMU_AUXHFRCOCTRL_TUNING_SHIFT);
6420 }
6421 #endif /* _CMU_AUXHFRCOCTRL_BAND_MASK */
6422 
6423 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
6424 /**************************************************************************//**
6425  * @brief
6426  *   Get the AUXHFRCO frequency calibration word in DEVINFO.
6427  *
6428  * @param[in] freq
6429  *   Frequency in Hz.
6430  *
6431  * @return
6432  *   AUXHFRCO calibration word for a given frequency.
6433  *****************************************************************************/
CMU_AUXHFRCODevinfoGet(CMU_AUXHFRCOFreq_TypeDef freq)6434 static uint32_t CMU_AUXHFRCODevinfoGet(CMU_AUXHFRCOFreq_TypeDef freq)
6435 {
6436   switch (freq) {
6437     /* 1, 2, and 4 MHz share the same calibration word. */
6438     case cmuAUXHFRCOFreq_1M0Hz:
6439     case cmuAUXHFRCOFreq_2M0Hz:
6440     case cmuAUXHFRCOFreq_4M0Hz:
6441       return DEVINFO->AUXHFRCOCAL0;
6442 
6443     case cmuAUXHFRCOFreq_7M0Hz:
6444       return DEVINFO->AUXHFRCOCAL3;
6445 
6446     case cmuAUXHFRCOFreq_13M0Hz:
6447       return DEVINFO->AUXHFRCOCAL6;
6448 
6449     case cmuAUXHFRCOFreq_16M0Hz:
6450       return DEVINFO->AUXHFRCOCAL7;
6451 
6452     case cmuAUXHFRCOFreq_19M0Hz:
6453       return DEVINFO->AUXHFRCOCAL8;
6454 
6455     case cmuAUXHFRCOFreq_26M0Hz:
6456       return DEVINFO->AUXHFRCOCAL10;
6457 
6458     case cmuAUXHFRCOFreq_32M0Hz:
6459       return DEVINFO->AUXHFRCOCAL11;
6460 
6461     case cmuAUXHFRCOFreq_38M0Hz:
6462       return DEVINFO->AUXHFRCOCAL12;
6463 
6464 #if defined(_DEVINFO_AUXHFRCOCAL13_MASK)
6465     case cmuAUXHFRCOFreq_48M0Hz:
6466       return DEVINFO->AUXHFRCOCAL13;
6467 #endif
6468 #if defined(_DEVINFO_AUXHFRCOCAL14_MASK)
6469     case cmuAUXHFRCOFreq_50M0Hz:
6470       return DEVINFO->AUXHFRCOCAL14;
6471 #endif
6472 
6473     default: /* cmuAUXHFRCOFreq_UserDefined */
6474       return 0;
6475   }
6476 }
6477 #endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */
6478 
6479 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
6480 /***************************************************************************//**
6481  * @brief
6482  *   Get the current AUXHFRCO frequency.
6483  *
6484  * @return
6485  *   AUXHFRCO frequency.
6486  ******************************************************************************/
CMU_AUXHFRCOBandGet(void)6487 CMU_AUXHFRCOFreq_TypeDef CMU_AUXHFRCOBandGet(void)
6488 {
6489   return auxHfrcoFreq;
6490 }
6491 #endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */
6492 
6493 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
6494 /***************************************************************************//**
6495  * @brief
6496  *   Set AUXHFRCO calibration for the selected target frequency.
6497  *
6498  * @param[in] setFreq
6499  *   AUXHFRCO frequency to set
6500  ******************************************************************************/
CMU_AUXHFRCOBandSet(CMU_AUXHFRCOFreq_TypeDef setFreq)6501 void CMU_AUXHFRCOBandSet(CMU_AUXHFRCOFreq_TypeDef setFreq)
6502 {
6503   uint32_t freqCal;
6504 
6505   /* Get DEVINFO index and set global auxHfrcoFreq. */
6506   freqCal = CMU_AUXHFRCODevinfoGet(setFreq);
6507   EFM_ASSERT((freqCal != 0UL) && (freqCal != UINT_MAX));
6508   auxHfrcoFreq = setFreq;
6509 
6510   /* Wait for any previous sync to complete, then set calibration data
6511      for the selected frequency.  */
6512   while (BUS_RegBitRead(&CMU->SYNCBUSY,
6513                         _CMU_SYNCBUSY_AUXHFRCOBSY_SHIFT) != 0UL) {
6514   }
6515 
6516   /* Set a divider in AUXHFRCOCTRL for 1, 2, and 4 MHz. */
6517   switch (setFreq) {
6518     case cmuAUXHFRCOFreq_1M0Hz:
6519       freqCal = (freqCal & ~_CMU_AUXHFRCOCTRL_CLKDIV_MASK)
6520                 | CMU_AUXHFRCOCTRL_CLKDIV_DIV4;
6521       break;
6522 
6523     case cmuAUXHFRCOFreq_2M0Hz:
6524       freqCal = (freqCal & ~_CMU_AUXHFRCOCTRL_CLKDIV_MASK)
6525                 | CMU_AUXHFRCOCTRL_CLKDIV_DIV2;
6526       break;
6527 
6528     case cmuAUXHFRCOFreq_4M0Hz:
6529       freqCal = (freqCal & ~_CMU_AUXHFRCOCTRL_CLKDIV_MASK)
6530                 | CMU_AUXHFRCOCTRL_CLKDIV_DIV1;
6531       break;
6532 
6533     default:
6534       break;
6535   }
6536   CMU->AUXHFRCOCTRL = freqCal;
6537 }
6538 #endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */
6539 
6540 /***************************************************************************//**
6541  * @brief
6542  *   Calibrate the clock.
6543  *
6544  * @details
6545  *   Run a calibration for HFCLK against a selectable reference clock.
6546  *   See the reference manual, CMU chapter, for more details.
6547  *
6548  * @note
6549  *   This function will not return until the calibration measurement is completed.
6550  *
6551  * @param[in] HFCycles
6552  *   The number of HFCLK cycles to run the calibration. Increasing this number
6553  *   increases precision but the calibration will take more time.
6554  *
6555  * @param[in] reference
6556  *   The reference clock used to compare HFCLK.
6557  *
6558  * @return
6559  *   The number of ticks the reference clock after HFCycles ticks on the HF
6560  *   clock.
6561  ******************************************************************************/
CMU_Calibrate(uint32_t HFCycles,CMU_Osc_TypeDef reference)6562 uint32_t CMU_Calibrate(uint32_t HFCycles, CMU_Osc_TypeDef reference)
6563 {
6564   EFM_ASSERT(HFCycles <= (_CMU_CALCNT_CALCNT_MASK >> _CMU_CALCNT_CALCNT_SHIFT));
6565 
6566   /* Set the reference clock source. */
6567   switch (reference) {
6568     case cmuOsc_LFXO:
6569       CMU->CALCTRL = CMU_CALCTRL_UPSEL_LFXO;
6570       break;
6571 
6572     case cmuOsc_LFRCO:
6573       CMU->CALCTRL = CMU_CALCTRL_UPSEL_LFRCO;
6574       break;
6575 
6576 #if defined(PLFRCO_PRESENT)
6577     case cmuOsc_PLFRCO:
6578       CMU->CALCTRL = CMU_CALCTRL_UPSEL_PLFRCO;
6579       break;
6580 #endif
6581 
6582     case cmuOsc_HFXO:
6583       CMU->CALCTRL = CMU_CALCTRL_UPSEL_HFXO;
6584       break;
6585 
6586     case cmuOsc_HFRCO:
6587       CMU->CALCTRL = CMU_CALCTRL_UPSEL_HFRCO;
6588       break;
6589 
6590     case cmuOsc_AUXHFRCO:
6591       CMU->CALCTRL = CMU_CALCTRL_UPSEL_AUXHFRCO;
6592       break;
6593 
6594 #if defined (_CMU_USHFRCOCTRL_MASK)
6595     case cmuOsc_USHFRCO:
6596       CMU->CALCTRL = CMU_CALCTRL_UPSEL_USHFRCO;
6597       break;
6598 #endif
6599 
6600     default:
6601       EFM_ASSERT(false);
6602       return 0;
6603   }
6604 
6605   /* Set the top value. */
6606   CMU->CALCNT = HFCycles;
6607 
6608   /* Start the calibration. */
6609   CMU->CMD = CMU_CMD_CALSTART;
6610 
6611 #if defined(CMU_STATUS_CALRDY)
6612   /* Wait until calibration completes. */
6613   while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALRDY_SHIFT) == 0UL) {
6614   }
6615 #else
6616   /* Wait until calibration completes. */
6617   while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALBSY_SHIFT) != 0UL) {
6618   }
6619 #endif
6620 
6621   return CMU->CALCNT;
6622 }
6623 
6624 #if defined(_CMU_CALCTRL_UPSEL_MASK) && defined(_CMU_CALCTRL_DOWNSEL_MASK)
6625 /***************************************************************************//**
6626  * @brief
6627  *   Configure the clock calibration.
6628  *
6629  * @details
6630  *   Configure a calibration for a selectable clock source against another
6631  *   selectable reference clock.
6632  *   See the reference manual, CMU chapter, for more details.
6633  *
6634  * @note
6635  *   After configuration, a call to @ref CMU_CalibrateStart() is required and
6636  *   the resulting calibration value can be read out with the
6637  *   @ref CMU_CalibrateCountGet() function call.
6638  *
6639  * @param[in] downCycles
6640  *   The number of downSel clock cycles to run the calibration. Increasing this
6641  *   number increases precision but the calibration will take more time.
6642  *
6643  * @param[in] downSel
6644  *   The clock, which will be counted down downCycles.
6645  *
6646  * @param[in] upSel
6647  *   The reference clock; the number of cycles generated by this clock will
6648  *   be counted and added up and the result can be given with the
6649  *   @ref CMU_CalibrateCountGet() function call.
6650  ******************************************************************************/
CMU_CalibrateConfig(uint32_t downCycles,CMU_Osc_TypeDef downSel,CMU_Osc_TypeDef upSel)6651 void CMU_CalibrateConfig(uint32_t downCycles, CMU_Osc_TypeDef downSel,
6652                          CMU_Osc_TypeDef upSel)
6653 {
6654   /* Keep configuration settings untouched. */
6655   uint32_t calCtrl = CMU->CALCTRL
6656                      & ~(_CMU_CALCTRL_UPSEL_MASK | _CMU_CALCTRL_DOWNSEL_MASK);
6657 
6658   /* 20 bits of precision to calibration count register. */
6659   EFM_ASSERT(downCycles <= (_CMU_CALCNT_CALCNT_MASK >> _CMU_CALCNT_CALCNT_SHIFT));
6660 
6661   /* Set down counting clock source - down counter. */
6662   switch (downSel) {
6663     case cmuOsc_LFXO:
6664       calCtrl |= CMU_CALCTRL_DOWNSEL_LFXO;
6665       break;
6666 
6667     case cmuOsc_LFRCO:
6668       calCtrl |= CMU_CALCTRL_DOWNSEL_LFRCO;
6669       break;
6670 
6671 #if defined(PLFRCO_PRESENT)
6672     case cmuOsc_PLFRCO:
6673       calCtrl |= CMU_CALCTRL_DOWNSEL_PLFRCO;
6674       break;
6675 #endif
6676 
6677     case cmuOsc_HFXO:
6678       calCtrl |= CMU_CALCTRL_DOWNSEL_HFXO;
6679       break;
6680 
6681     case cmuOsc_HFRCO:
6682       calCtrl |= CMU_CALCTRL_DOWNSEL_HFRCO;
6683       break;
6684 
6685     case cmuOsc_AUXHFRCO:
6686       calCtrl |= CMU_CALCTRL_DOWNSEL_AUXHFRCO;
6687       break;
6688 
6689 #if defined (_CMU_USHFRCOCTRL_MASK)
6690     case cmuOsc_USHFRCO:
6691       calCtrl |= CMU_CALCTRL_DOWNSEL_USHFRCO;
6692       break;
6693 #endif
6694 
6695     default:
6696       EFM_ASSERT(false);
6697       break;
6698   }
6699 
6700   /* Set the top value to be counted down by the downSel clock. */
6701   CMU->CALCNT = downCycles;
6702 
6703   /* Set the reference clock source - up counter. */
6704   switch (upSel) {
6705     case cmuOsc_LFXO:
6706       calCtrl |= CMU_CALCTRL_UPSEL_LFXO;
6707       break;
6708 
6709     case cmuOsc_LFRCO:
6710       calCtrl |= CMU_CALCTRL_UPSEL_LFRCO;
6711       break;
6712 
6713 #if defined(PLFRCO_PRESENT)
6714     case cmuOsc_PLFRCO:
6715       calCtrl |= CMU_CALCTRL_UPSEL_PLFRCO;
6716       break;
6717 #endif
6718 
6719     case cmuOsc_HFXO:
6720       calCtrl |= CMU_CALCTRL_UPSEL_HFXO;
6721       break;
6722 
6723     case cmuOsc_HFRCO:
6724       calCtrl |= CMU_CALCTRL_UPSEL_HFRCO;
6725       break;
6726 
6727     case cmuOsc_AUXHFRCO:
6728       calCtrl |= CMU_CALCTRL_UPSEL_AUXHFRCO;
6729       break;
6730 
6731 #if defined (_CMU_USHFRCOCTRL_MASK)
6732     case cmuOsc_USHFRCO:
6733       calCtrl |= CMU_CALCTRL_UPSEL_USHFRCO;
6734       break;
6735 #endif
6736 
6737     default:
6738       EFM_ASSERT(false);
6739       break;
6740   }
6741 
6742   CMU->CALCTRL = calCtrl;
6743 }
6744 #endif
6745 
6746 /***************************************************************************//**
6747  * @brief
6748  *    Get the calibration count register.
6749  * @note
6750  *    If continuous calibration mode is active, calibration busy will almost
6751  *    always be off and only the value needs to be read. In a normal case,
6752  *    this function call is triggered by the CALRDY
6753  *    interrupt flag.
6754  * @return
6755  *    The calibration count, the number of UPSEL clocks
6756  *    in the period of DOWNSEL oscillator clock cycles configured by a previous
6757  *    write operation to CMU->CALCNT.
6758  ******************************************************************************/
CMU_CalibrateCountGet(void)6759 uint32_t CMU_CalibrateCountGet(void)
6760 {
6761   /* Wait until calibration completes, UNLESS continuous calibration mode is  */
6762   /* active. */
6763 #if defined(CMU_CALCTRL_CONT)
6764   if (BUS_RegBitRead(&CMU->CALCTRL, _CMU_CALCTRL_CONT_SHIFT) == 0UL) {
6765 #if defined(CMU_STATUS_CALRDY)
6766     /* Wait until calibration completes */
6767     while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALRDY_SHIFT) == 0UL) {
6768     }
6769 #else
6770     /* Wait until calibration completes */
6771     while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALBSY_SHIFT) != 0UL) {
6772     }
6773 #endif
6774   }
6775 #else
6776   while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALBSY_SHIFT) != 0UL) {
6777   }
6778 #endif
6779   return CMU->CALCNT;
6780 }
6781 
6782 /***************************************************************************//**
6783  * @brief
6784  *   Get the clock divisor/prescaler.
6785  *
6786  * @param[in] clock
6787  *   A clock point to get the divisor/prescaler for. Notice that not all clock points
6788  *   have a divisor/prescaler. See the CMU overview in the reference manual.
6789  *
6790  * @return
6791  *   The current clock point divisor/prescaler. 1 is returned
6792  *   if @p clock specifies a clock point without a divisor/prescaler.
6793  ******************************************************************************/
CMU_ClockDivGet(CMU_Clock_TypeDef clock)6794 CMU_ClkDiv_TypeDef CMU_ClockDivGet(CMU_Clock_TypeDef clock)
6795 {
6796 #if defined(_SILICON_LABS_32B_SERIES_1)
6797   return 1UL + (uint32_t)CMU_ClockPrescGet(clock);
6798 
6799 #elif defined(_SILICON_LABS_32B_SERIES_0)
6800   uint32_t           divReg;
6801   CMU_ClkDiv_TypeDef ret;
6802 
6803   /* Get divisor reg ID. */
6804   divReg = (clock >> CMU_DIV_REG_POS) & CMU_DIV_REG_MASK;
6805 
6806   switch (divReg) {
6807 #if defined(_CMU_CTRL_HFCLKDIV_MASK)
6808     case CMU_HFCLKDIV_REG:
6809       ret = 1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK)
6810                  >> _CMU_CTRL_HFCLKDIV_SHIFT);
6811       break;
6812 #endif
6813 
6814     case CMU_HFPERCLKDIV_REG:
6815       ret = (CMU_ClkDiv_TypeDef)((CMU->HFPERCLKDIV
6816                                   & _CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
6817                                  >> _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT);
6818       ret = SL_Log2ToDiv(ret);
6819       break;
6820 
6821     case CMU_HFCORECLKDIV_REG:
6822       ret = (CMU_ClkDiv_TypeDef)((CMU->HFCORECLKDIV
6823                                   & _CMU_HFCORECLKDIV_HFCORECLKDIV_MASK)
6824                                  >> _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT);
6825       ret = SL_Log2ToDiv(ret);
6826       break;
6827 
6828 #if defined(_CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
6829     case CMU_HFCORECLKLEDIV_REG:
6830       ret = (CMU_ClkDiv_TypeDef)((CMU->HFCORECLKDIV
6831                                   & _CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
6832                                  >> _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT);
6833       ret = SL_Log2ToDiv(ret + 1U);
6834       break;
6835 #endif
6836 
6837     case CMU_LFAPRESC0_REG:
6838       switch (clock) {
6839         case cmuClock_RTC:
6840           ret = (CMU_ClkDiv_TypeDef)((CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK)
6841                                      >> _CMU_LFAPRESC0_RTC_SHIFT);
6842           ret = SL_Log2ToDiv(ret);
6843           break;
6844 
6845 #if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
6846         case cmuClock_LETIMER0:
6847           ret = (CMU_ClkDiv_TypeDef)((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
6848                                      >> _CMU_LFAPRESC0_LETIMER0_SHIFT);
6849           ret = SL_Log2ToDiv(ret);
6850           break;
6851 #endif
6852 
6853 #if defined(_CMU_LFAPRESC0_LCD_MASK)
6854         case cmuClock_LCDpre:
6855           ret = (CMU_ClkDiv_TypeDef)(((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
6856                                       >> _CMU_LFAPRESC0_LCD_SHIFT)
6857                                      + CMU_DivToLog2(cmuClkDiv_16));
6858           ret = SL_Log2ToDiv(ret);
6859           break;
6860 #endif
6861 
6862 #if defined(_CMU_LFAPRESC0_LESENSE_MASK)
6863         case cmuClock_LESENSE:
6864           ret = (CMU_ClkDiv_TypeDef)((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK)
6865                                      >> _CMU_LFAPRESC0_LESENSE_SHIFT);
6866           ret = SL_Log2ToDiv(ret);
6867           break;
6868 #endif
6869 
6870         default:
6871           ret = cmuClkDiv_1;
6872           EFM_ASSERT(false);
6873           break;
6874       }
6875       break;
6876 
6877     case CMU_LFBPRESC0_REG:
6878       switch (clock) {
6879 #if defined(_CMU_LFBPRESC0_LEUART0_MASK)
6880         case cmuClock_LEUART0:
6881           ret = (CMU_ClkDiv_TypeDef)((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
6882                                      >> _CMU_LFBPRESC0_LEUART0_SHIFT);
6883           ret = SL_Log2ToDiv(ret);
6884           break;
6885 #endif
6886 
6887 #if defined(_CMU_LFBPRESC0_LEUART1_MASK)
6888         case cmuClock_LEUART1:
6889           ret = (CMU_ClkDiv_TypeDef)((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
6890                                      >> _CMU_LFBPRESC0_LEUART1_SHIFT);
6891           ret = SL_Log2ToDiv(ret);
6892           break;
6893 #endif
6894 
6895         default:
6896           ret = cmuClkDiv_1;
6897           EFM_ASSERT(false);
6898           break;
6899       }
6900       break;
6901 
6902     default:
6903       ret = cmuClkDiv_1;
6904       EFM_ASSERT(false);
6905       break;
6906   }
6907 
6908   return ret;
6909 #endif
6910 }
6911 
6912 /***************************************************************************//**
6913  * @brief
6914  *   Set the clock divisor/prescaler.
6915  *
6916  * @note
6917  *   If setting an LF clock prescaler, synchronization into the low-frequency
6918  *   domain is required. If the same register is modified before a previous
6919  *   update has completed, this function will stall until the previous
6920  *   synchronization has completed. See @ref CMU_FreezeEnable() for
6921  *   a suggestion on how to reduce the stalling time in some use cases.
6922  *
6923  *   HFCLKLE prescaler is automatically modified when peripherals with clock
6924  *   domain HFBUSCLK is chosen based on the maximum HFLE frequency allowed.
6925  *
6926  * @param[in] clock
6927  *   Clock point to set divisor/prescaler for. Notice that not all clock points
6928  *   have a divisor/prescaler. See the CMU overview in the reference
6929  *   manual.
6930  *
6931  * @param[in] div
6932  *   The clock divisor to use (<= cmuClkDiv_512).
6933  ******************************************************************************/
CMU_ClockDivSet(CMU_Clock_TypeDef clock,CMU_ClkDiv_TypeDef div)6934 void CMU_ClockDivSet(CMU_Clock_TypeDef clock, CMU_ClkDiv_TypeDef div)
6935 {
6936 #if defined(_SILICON_LABS_32B_SERIES_1)
6937   CMU_ClockPrescSet(clock, (CMU_ClkPresc_TypeDef)(div - 1U));
6938 
6939 #elif defined(_SILICON_LABS_32B_SERIES_0)
6940   uint32_t freq;
6941   uint32_t divReg;
6942 
6943   /* Get the divisor reg ID. */
6944   divReg = (clock >> CMU_DIV_REG_POS) & CMU_DIV_REG_MASK;
6945 
6946   switch (divReg) {
6947 #if defined(_CMU_CTRL_HFCLKDIV_MASK)
6948     case CMU_HFCLKDIV_REG:
6949       EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_8));
6950 
6951       /* Configure worst case wait states for flash access before setting divisor. */
6952       flashWaitStateMax();
6953 
6954       /* Set the divider. */
6955       CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFCLKDIV_MASK)
6956                   | ((div - 1) << _CMU_CTRL_HFCLKDIV_SHIFT);
6957 
6958       /* Update the CMSIS core clock variable. */
6959       /* (The function will update the global variable). */
6960       freq = SystemCoreClockGet();
6961 
6962       /* Optimize flash access wait state setting for the current core clk. */
6963       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
6964       break;
6965 #endif
6966 
6967     case CMU_HFPERCLKDIV_REG:
6968       EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_512));
6969       /* Convert to the correct scale. */
6970       div = CMU_DivToLog2(div);
6971       CMU->HFPERCLKDIV = (CMU->HFPERCLKDIV & ~_CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
6972                          | (div << _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT);
6973       break;
6974 
6975 #if defined(_CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
6976     case CMU_HFCORECLKLEDIV_REG:
6977       /*
6978          This divisor is usually set when changing HF clock to keep HFLE clock
6979          within safe bounds. This code path ignore these constraints.
6980        */
6981       /* Convert to the correct scale. */
6982       div = CMU_DivToLog2(div) - 1U;
6983       CMU->HFCORECLKDIV = (CMU->HFCORECLKDIV
6984                            & ~_CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
6985                           | (div << _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT);
6986       break;
6987 #endif
6988 
6989     case CMU_HFCORECLKDIV_REG:
6990       EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_512));
6991 
6992       /* Configure worst case wait states for flash access before setting the divisor. */
6993       flashWaitStateMax();
6994 
6995 #if defined(CMU_MAX_FREQ_HFLE)
6996       setHfLeConfig(SystemCoreClockGet() / div);
6997 #endif
6998 
6999       /* Convert to the correct scale. */
7000       div = CMU_DivToLog2(div);
7001 
7002       CMU->HFCORECLKDIV = (CMU->HFCORECLKDIV
7003                            & ~_CMU_HFCORECLKDIV_HFCORECLKDIV_MASK)
7004                           | (div << _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT);
7005 
7006       /* Update the CMSIS core clock variable. */
7007       /* (The function will update the global variable). */
7008       freq = SystemCoreClockGet();
7009 
7010       /* Optimize wait state setting for the current core clk. */
7011       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
7012 #if defined(CMU_MAX_FREQ_HFLE)
7013       setHfLeConfig(freq);
7014 #endif
7015       break;
7016 
7017     case CMU_LFAPRESC0_REG:
7018       switch (clock) {
7019         case cmuClock_RTC:
7020           EFM_ASSERT(div <= cmuClkDiv_32768);
7021 
7022           /* LF register about to be modified requires sync. busy check. */
7023           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7024 
7025           /* Convert to the correct scale. */
7026           div = CMU_DivToLog2(div);
7027 
7028           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTC_MASK)
7029                            | (div << _CMU_LFAPRESC0_RTC_SHIFT);
7030           break;
7031 
7032 #if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
7033         case cmuClock_LETIMER0:
7034           EFM_ASSERT(div <= cmuClkDiv_32768);
7035 
7036           /* LF register about to be modified requires sync. busy check. */
7037           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7038 
7039           /* Convert to the correct scale. */
7040           div = CMU_DivToLog2(div);
7041 
7042           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LETIMER0_MASK)
7043                            | (div << _CMU_LFAPRESC0_LETIMER0_SHIFT);
7044           break;
7045 #endif
7046 
7047 #if defined(LCD_PRESENT)
7048         case cmuClock_LCDpre:
7049           EFM_ASSERT((div >= cmuClkDiv_16) && (div <= cmuClkDiv_128));
7050 
7051           /* LF register about to be modified requires sync. busy check. */
7052           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7053 
7054           /* Convert to the correct scale. */
7055           div = CMU_DivToLog2(div);
7056 
7057           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LCD_MASK)
7058                            | ((div - CMU_DivToLog2(cmuClkDiv_16))
7059                               << _CMU_LFAPRESC0_LCD_SHIFT);
7060           break;
7061 #endif /* defined(LCD_PRESENT) */
7062 
7063 #if defined(LESENSE_PRESENT)
7064         case cmuClock_LESENSE:
7065           EFM_ASSERT(div <= cmuClkDiv_8);
7066 
7067           /* LF register about to be modified requires sync. busy check. */
7068           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7069 
7070           /* Convert to the correct scale. */
7071           div = CMU_DivToLog2(div);
7072 
7073           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LESENSE_MASK)
7074                            | (div << _CMU_LFAPRESC0_LESENSE_SHIFT);
7075           break;
7076 #endif /* defined(LESENSE_PRESENT) */
7077 
7078         default:
7079           EFM_ASSERT(false);
7080           break;
7081       }
7082       break;
7083 
7084     case CMU_LFBPRESC0_REG:
7085       switch (clock) {
7086 #if defined(_CMU_LFBPRESC0_LEUART0_MASK)
7087         case cmuClock_LEUART0:
7088           EFM_ASSERT(div <= cmuClkDiv_8);
7089 
7090           /* LF register about to be modified requires sync. busy check. */
7091           syncReg(CMU_SYNCBUSY_LFBPRESC0);
7092 
7093           /* Convert to the correct scale. */
7094           div = CMU_DivToLog2(div);
7095 
7096           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART0_MASK)
7097                            | (((uint32_t)div) << _CMU_LFBPRESC0_LEUART0_SHIFT);
7098           break;
7099 #endif
7100 
7101 #if defined(_CMU_LFBPRESC0_LEUART1_MASK)
7102         case cmuClock_LEUART1:
7103           EFM_ASSERT(div <= cmuClkDiv_8);
7104 
7105           /* LF register about to be modified requires sync. busy check. */
7106           syncReg(CMU_SYNCBUSY_LFBPRESC0);
7107 
7108           /* Convert to the correct scale. */
7109           div = CMU_DivToLog2(div);
7110 
7111           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART1_MASK)
7112                            | (((uint32_t)div) << _CMU_LFBPRESC0_LEUART1_SHIFT);
7113           break;
7114 #endif
7115 
7116         default:
7117           EFM_ASSERT(false);
7118           break;
7119       }
7120       break;
7121 
7122     default:
7123       EFM_ASSERT(false);
7124       break;
7125   }
7126 #endif
7127 }
7128 
7129 /***************************************************************************//**
7130  * @brief
7131  *   Enable/disable a clock.
7132  *
7133  * @details
7134  *   In general, module clocking is disabled after a reset. If a module
7135  *   clock is disabled, the registers of that module are not accessible and
7136  *   reading from such registers may return undefined values. Writing to
7137  *   registers of clock-disabled modules has no effect.
7138  *   Avoid accessing module registers of a module with a disabled clock.
7139  *
7140  * @note
7141  *   If enabling/disabling an LF clock, synchronization into the low-frequency
7142  *   domain is required. If the same register is modified before a previous
7143  *   update has completed, this function will stall until the previous
7144  *   synchronization has completed. See @ref CMU_FreezeEnable() for
7145  *   a suggestion on how to reduce the stalling time in some use cases.
7146  *
7147  *   HFCLKLE prescaler is automatically modified when peripherals with clock
7148  *   domain HFBUSCLK is chosen based on the maximum HFLE frequency allowed.
7149  *
7150  * @param[in] clock
7151  *   The clock to enable/disable. Notice that not all defined clock
7152  *   points have separate enable/disable control. See the CMU overview
7153  *   in the reference manual.
7154  *
7155  * @param[in] enable
7156  *   @li true - enable specified clock.
7157  *   @li false - disable specified clock.
7158  ******************************************************************************/
CMU_ClockEnable(CMU_Clock_TypeDef clock,bool enable)7159 void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
7160 {
7161   volatile uint32_t *reg;
7162   uint32_t          bit;
7163   uint32_t          sync = 0;
7164 
7165   /* Identify enable register */
7166   switch (((unsigned)clock >> CMU_EN_REG_POS) & CMU_EN_REG_MASK) {
7167 #if defined(_CMU_CTRL_HFPERCLKEN_MASK)
7168     case CMU_CTRL_EN_REG:
7169       reg = &CMU->CTRL;
7170       break;
7171 #endif
7172 
7173 #if defined(_CMU_HFCORECLKEN0_MASK)
7174     case CMU_HFCORECLKEN0_EN_REG:
7175       reg = &CMU->HFCORECLKEN0;
7176 #if defined(CMU_MAX_FREQ_HFLE)
7177       setHfLeConfig(SystemCoreClockGet());
7178 #endif
7179       break;
7180 #endif
7181 
7182 #if defined(_CMU_HFBUSCLKEN0_MASK)
7183     case CMU_HFBUSCLKEN0_EN_REG:
7184       reg = &CMU->HFBUSCLKEN0;
7185       break;
7186 #endif
7187 
7188 #if defined(_CMU_HFPERCLKDIV_MASK)
7189     case CMU_HFPERCLKDIV_EN_REG:
7190       reg = &CMU->HFPERCLKDIV;
7191       break;
7192 #endif
7193 
7194     case CMU_HFPERCLKEN0_EN_REG:
7195       reg = &CMU->HFPERCLKEN0;
7196       break;
7197 
7198 #if defined(_CMU_HFPERCLKEN1_MASK)
7199     case CMU_HFPERCLKEN1_EN_REG:
7200       reg = &CMU->HFPERCLKEN1;
7201       break;
7202 #endif
7203 
7204     case CMU_LFACLKEN0_EN_REG:
7205       reg  = &CMU->LFACLKEN0;
7206       sync = CMU_SYNCBUSY_LFACLKEN0;
7207       break;
7208 
7209     case CMU_LFBCLKEN0_EN_REG:
7210       reg  = &CMU->LFBCLKEN0;
7211       sync = CMU_SYNCBUSY_LFBCLKEN0;
7212       break;
7213 
7214 #if defined(_CMU_LFCCLKEN0_MASK)
7215     case CMU_LFCCLKEN0_EN_REG:
7216       reg = &CMU->LFCCLKEN0;
7217       sync = CMU_SYNCBUSY_LFCCLKEN0;
7218       break;
7219 #endif
7220 
7221 #if defined(_CMU_LFECLKEN0_MASK)
7222     case CMU_LFECLKEN0_EN_REG:
7223       reg  = &CMU->LFECLKEN0;
7224       sync = CMU_SYNCBUSY_LFECLKEN0;
7225       break;
7226 #endif
7227 
7228 #if defined(_CMU_SDIOCTRL_MASK)
7229     case CMU_SDIOREF_EN_REG:
7230       reg = &CMU->SDIOCTRL;
7231       enable = !enable;
7232       break;
7233 #endif
7234 
7235 #if defined(_CMU_QSPICTRL_MASK)
7236     case CMU_QSPI0REF_EN_REG:
7237       reg = &CMU->QSPICTRL;
7238       enable = !enable;
7239       break;
7240 #endif
7241 #if defined(_CMU_USBCTRL_MASK)
7242     case CMU_USBRCLK_EN_REG:
7243       reg = &CMU->USBCTRL;
7244       break;
7245 #endif
7246 #if defined(_CMU_PDMCTRL_MASK)
7247     case CMU_PDMREF_EN_REG:
7248       reg = &CMU->PDMCTRL;
7249       break;
7250 #endif
7251 
7252     case CMU_PCNT_EN_REG:
7253       reg = &CMU->PCNTCTRL;
7254       break;
7255 
7256     default: /* Cannot enable/disable a clock point. */
7257       EFM_ASSERT(false);
7258       return;
7259   }
7260 
7261   /* Get the bit position used to enable/disable. */
7262   bit = ((unsigned)clock >> CMU_EN_BIT_POS) & CMU_EN_BIT_MASK;
7263 
7264   /* LF synchronization required. */
7265   if (sync > 0UL) {
7266     syncReg(sync);
7267   }
7268 
7269   /* Set/clear bit as requested. */
7270   BUS_RegBitWrite(reg, bit, (uint32_t)enable);
7271 }
7272 
7273 /***************************************************************************//**
7274  * @brief
7275  *   Get the clock frequency for a clock point.
7276  *
7277  * @param[in] clock
7278  *   A clock point to fetch the frequency for.
7279  *
7280  * @return
7281  *   The current frequency in Hz.
7282  ******************************************************************************/
CMU_ClockFreqGet(CMU_Clock_TypeDef clock)7283 uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
7284 {
7285   uint32_t ret;
7286 
7287   switch ((unsigned)clock & (CMU_CLK_BRANCH_MASK << CMU_CLK_BRANCH_POS)) {
7288     case (CMU_HF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7289       ret = SystemHFClockGet();
7290       break;
7291 
7292     case (CMU_HFPER_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7293       ret = SystemHFClockGet();
7294       /* Calculate frequency after HFPER divider. */
7295 #if defined(_CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
7296       ret >>= (CMU->HFPERCLKDIV & _CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
7297               >> _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT;
7298 #endif
7299 #if defined(_CMU_HFPERPRESC_PRESC_MASK)
7300       ret /= 1U + ((CMU->HFPERPRESC & _CMU_HFPERPRESC_PRESC_MASK)
7301                    >> _CMU_HFPERPRESC_PRESC_SHIFT);
7302 #endif
7303       break;
7304 
7305 #if defined(_CMU_HFPERPRESCB_MASK)
7306     case (CMU_HFPERB_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7307       ret = SystemHFClockGet();
7308       /* Calculate frequency after HFPERB prescaler. */
7309       ret /= 1U + ((CMU->HFPERPRESCB & _CMU_HFPERPRESCB_PRESC_MASK)
7310                    >> _CMU_HFPERPRESCB_PRESC_SHIFT);
7311       break;
7312 #endif
7313 
7314 #if defined(_CMU_HFPERPRESCC_MASK)
7315     case (CMU_HFPERC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7316       ret = SystemHFClockGet();
7317       /* Calculate frequency after HFPERC prescaler. */
7318       ret /= 1U + ((CMU->HFPERPRESCC & _CMU_HFPERPRESCC_PRESC_MASK)
7319                    >> _CMU_HFPERPRESCC_PRESC_SHIFT);
7320       break;
7321 #endif
7322 
7323 #if defined(_SILICON_LABS_32B_SERIES_1)
7324 #if defined(CRYPTO_PRESENT)     \
7325       || defined(LDMA_PRESENT)  \
7326       || defined(GPCRC_PRESENT) \
7327       || defined(PRS_PRESENT)   \
7328       || defined(GPIO_PRESENT)
7329     case (CMU_HFBUS_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7330       ret = SystemHFClockGet();
7331 #if defined(_CMU_HFBUSPRESC_MASK)
7332       ret /= 1U + ((CMU->HFBUSPRESC & _CMU_HFBUSPRESC_MASK)
7333                    >> _CMU_HFBUSPRESC_PRESC_SHIFT);
7334 #endif
7335       break;
7336 #endif
7337 
7338     case (CMU_HFCORE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7339       ret = SystemHFClockGet();
7340       ret /= 1U + ((CMU->HFCOREPRESC & _CMU_HFCOREPRESC_PRESC_MASK)
7341                    >> _CMU_HFCOREPRESC_PRESC_SHIFT);
7342       break;
7343 
7344     case (CMU_HFEXP_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7345       ret = SystemHFClockGet();
7346       ret /= 1U + ((CMU->HFEXPPRESC & _CMU_HFEXPPRESC_PRESC_MASK)
7347                    >> _CMU_HFEXPPRESC_PRESC_SHIFT);
7348       break;
7349 #endif
7350 
7351 #if defined(_SILICON_LABS_32B_SERIES_0)
7352 #if defined(AES_PRESENT)      \
7353       || defined(DMA_PRESENT) \
7354       || defined(EBI_PRESENT) \
7355       || defined(USB_PRESENT)
7356     case (CMU_HFCORE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7357     {
7358       ret = SystemCoreClockGet();
7359     } break;
7360 #endif
7361 #endif
7362 
7363     case (CMU_LFA_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7364       ret = lfClkGet(cmuClock_LFA);
7365       break;
7366 
7367 #if defined(_CMU_LFACLKEN0_RTC_MASK)
7368     case (CMU_RTC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7369       ret = lfClkGet(cmuClock_LFA);
7370       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK)
7371               >> _CMU_LFAPRESC0_RTC_SHIFT;
7372       break;
7373 #endif
7374 
7375 #if defined(_CMU_LFECLKEN0_RTCC_MASK)
7376     case (CMU_RTCC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7377       ret = lfClkGet(cmuClock_LFE);
7378       ret >>= (CMU->LFEPRESC0 & _CMU_LFEPRESC0_RTCC_MASK)
7379               >> _CMU_LFEPRESC0_RTCC_SHIFT;
7380       break;
7381 #endif
7382 
7383 #if defined(_CMU_LFACLKEN0_LETIMER0_MASK)
7384     case (CMU_LETIMER0_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7385       ret = lfClkGet(cmuClock_LFA);
7386 #if defined(_SILICON_LABS_32B_SERIES_0)
7387       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
7388               >> _CMU_LFAPRESC0_LETIMER0_SHIFT;
7389 #else
7390       ret /= SL_Log2ToDiv((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
7391                           >> _CMU_LFAPRESC0_LETIMER0_SHIFT);
7392 #endif
7393       break;
7394 #endif
7395 
7396 #if defined(_CMU_LFACLKEN0_LETIMER1_MASK)
7397     case (CMU_LETIMER1_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7398       ret = lfClkGet(cmuClock_LFA);
7399 #if defined(_SILICON_LABS_32B_SERIES_0)
7400       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER1_MASK)
7401               >> _CMU_LFAPRESC0_LETIMER1_SHIFT;
7402 #else
7403       ret /= SL_Log2ToDiv((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER1_MASK)
7404                           >> _CMU_LFAPRESC0_LETIMER1_SHIFT);
7405 #endif
7406       break;
7407 #endif
7408 
7409 #if defined(_CMU_LFACLKEN0_LCD_MASK)
7410     case (CMU_LCDPRE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7411       ret = lfClkGet(cmuClock_LFA);
7412 #if defined(_SILICON_LABS_32B_SERIES_0)
7413       ret >>= ((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
7414                >> _CMU_LFAPRESC0_LCD_SHIFT)
7415               + CMU_DivToLog2(cmuClkDiv_16);
7416 #else
7417       ret /= SL_Log2ToDiv((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
7418                           >> _CMU_LFAPRESC0_LCD_SHIFT);
7419 #endif
7420       break;
7421 
7422 #if defined(_CMU_LCDCTRL_MASK)
7423     case (CMU_LCD_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7424       ret = lfClkGet(cmuClock_LFA);
7425       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
7426               >> _CMU_LFAPRESC0_LCD_SHIFT;
7427       ret /= 1U + ((CMU->LCDCTRL & _CMU_LCDCTRL_FDIV_MASK)
7428                    >> _CMU_LCDCTRL_FDIV_SHIFT);
7429       break;
7430 #endif
7431 #endif
7432 
7433 #if defined(_CMU_LFACLKEN0_LESENSE_MASK)
7434     case (CMU_LESENSE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7435       ret = lfClkGet(cmuClock_LFA);
7436       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK)
7437               >> _CMU_LFAPRESC0_LESENSE_SHIFT;
7438       break;
7439 #endif
7440 
7441     case (CMU_LFB_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7442       ret = lfClkGet(cmuClock_LFB);
7443       break;
7444 
7445 #if defined(_CMU_LFBCLKEN0_LEUART0_MASK)
7446     case (CMU_LEUART0_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7447       ret = lfClkGet(cmuClock_LFB);
7448 #if defined(_SILICON_LABS_32B_SERIES_0)
7449       ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
7450               >> _CMU_LFBPRESC0_LEUART0_SHIFT;
7451 #else
7452       ret /= SL_Log2ToDiv((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
7453                           >> _CMU_LFBPRESC0_LEUART0_SHIFT);
7454 #endif
7455       break;
7456 #endif
7457 
7458 #if defined(_CMU_LFBCLKEN0_LEUART1_MASK)
7459     case (CMU_LEUART1_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7460       ret = lfClkGet(cmuClock_LFB);
7461 #if defined(_SILICON_LABS_32B_SERIES_0)
7462       ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
7463               >> _CMU_LFBPRESC0_LEUART1_SHIFT;
7464 #else
7465       ret /= SL_Log2ToDiv((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
7466                           >> _CMU_LFBPRESC0_LEUART1_SHIFT);
7467 #endif
7468       break;
7469 #endif
7470 
7471 #if defined(_CMU_LFBCLKEN0_CSEN_MASK)
7472     case (CMU_CSEN_LF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7473       ret = lfClkGet(cmuClock_LFB);
7474       ret /= SL_Log2ToDiv(((CMU->LFBPRESC0 & _CMU_LFBPRESC0_CSEN_MASK)
7475                            >> _CMU_LFBPRESC0_CSEN_SHIFT) + 4UL);
7476       break;
7477 #endif
7478 
7479 #if defined(CMU_LFCCLKEN0_USB)
7480     case (CMU_USBLE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7481       ret = lfClkGet(cmuClock_LFC);
7482       break;
7483 #endif
7484 
7485 #if defined(_SILICON_LABS_32B_SERIES_1)
7486     case (CMU_LFE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7487       ret = lfClkGet(cmuClock_LFE);
7488       break;
7489 #endif
7490 
7491     case (CMU_DBG_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7492       ret = dbgClkGet();
7493       break;
7494 
7495     case (CMU_AUX_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7496       ret = auxClkGet();
7497       break;
7498 
7499 #if defined(USBC_CLOCK_PRESENT)
7500     case (CMU_USBC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7501       ret = usbCClkGet();
7502       break;
7503 #endif
7504 
7505 #if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
7506     case (CMU_ADC0ASYNC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7507       ret = adcAsyncClkGet(0);
7508 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK)
7509       ret /= 1U + ((CMU->ADCCTRL & _CMU_ADCCTRL_ADC0CLKDIV_MASK)
7510                    >> _CMU_ADCCTRL_ADC0CLKDIV_SHIFT);
7511 #endif
7512       break;
7513 #endif
7514 
7515 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
7516     case (CMU_ADC1ASYNC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7517       ret = adcAsyncClkGet(1);
7518 #if defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
7519       ret /= 1U + ((CMU->ADCCTRL & _CMU_ADCCTRL_ADC1CLKDIV_MASK)
7520                    >> _CMU_ADCCTRL_ADC1CLKDIV_SHIFT);
7521 #endif
7522       break;
7523 #endif
7524 
7525 #if defined(_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
7526     case (CMU_SDIOREF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7527       ret = sdioRefClkGet();
7528       break;
7529 #endif
7530 
7531 #if defined(_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
7532     case (CMU_QSPI0REF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7533       ret = qspiRefClkGet(0);
7534       break;
7535 #endif
7536 
7537 #if defined(USBR_CLOCK_PRESENT)
7538     case (CMU_USBR_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7539       ret = usbRateClkGet();
7540       break;
7541 #endif
7542 
7543 #if defined(_CMU_PDMCTRL_PDMCLKSEL_MASK)
7544     case (CMU_PDMREF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7545       ret = pdmRefClkGet();
7546       break;
7547 #endif
7548 
7549     case (CMU_HFLE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7550 #if defined(_CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
7551       ret = SystemCoreClockGet() / CMU_ClockDivGet(clock);
7552 #elif defined(_CMU_HFPRESC_HFCLKLEPRESC_MASK)
7553       ret = SystemHFClockGet() / CMU_ClockDivGet(clock);
7554 #else
7555       ret = SystemCoreClockGet() / 2;
7556 #endif
7557       break;
7558 
7559     default:
7560       ret = 0;
7561       EFM_ASSERT(false);
7562       break;
7563   }
7564 
7565   return ret;
7566 }
7567 
7568 #if defined(_SILICON_LABS_32B_SERIES_1)
7569 /***************************************************************************//**
7570  * @brief
7571  *   Get the clock prescaler.
7572  *
7573  * @param[in] clock
7574  *   A clock point to get the prescaler for. Notice that not all clock points
7575  *   have a prescaler. See the CMU overview in the reference manual.
7576  *
7577  * @return
7578  *   The prescaler value of the current clock point. 0 is returned
7579  *   if @p clock specifies a clock point without a prescaler.
7580  ******************************************************************************/
CMU_ClockPrescGet(CMU_Clock_TypeDef clock)7581 uint32_t CMU_ClockPrescGet(CMU_Clock_TypeDef clock)
7582 {
7583   uint32_t  prescReg;
7584   uint32_t  ret;
7585 
7586   /* Get the prescaler register ID. */
7587   prescReg = ((unsigned)clock >> CMU_PRESC_REG_POS) & CMU_PRESC_REG_MASK;
7588 
7589   switch (prescReg) {
7590     case CMU_HFPRESC_REG:
7591       ret = (CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
7592             >> _CMU_HFPRESC_PRESC_SHIFT;
7593       break;
7594 
7595     case CMU_HFEXPPRESC_REG:
7596       ret = (CMU->HFEXPPRESC & _CMU_HFEXPPRESC_PRESC_MASK)
7597             >> _CMU_HFEXPPRESC_PRESC_SHIFT;
7598       break;
7599 
7600     case CMU_HFCLKLEPRESC_REG:
7601       ret = (CMU->HFPRESC & _CMU_HFPRESC_HFCLKLEPRESC_MASK)
7602             >> _CMU_HFPRESC_HFCLKLEPRESC_SHIFT;
7603       ret = SL_Log2ToDiv(ret + 1U) - 1U;
7604       break;
7605 
7606     case CMU_HFPERPRESC_REG:
7607       ret = (CMU->HFPERPRESC & _CMU_HFPERPRESC_PRESC_MASK)
7608             >> _CMU_HFPERPRESC_PRESC_SHIFT;
7609       break;
7610 
7611 #if defined(_CMU_HFPERPRESCB_MASK)
7612     case CMU_HFPERPRESCB_REG:
7613       ret = (CMU->HFPERPRESCB & _CMU_HFPERPRESCB_PRESC_MASK)
7614             >> _CMU_HFPERPRESCB_PRESC_SHIFT;
7615       break;
7616 #endif
7617 
7618 #if defined(_CMU_HFPERPRESCC_MASK)
7619     case CMU_HFPERPRESCC_REG:
7620       ret = (CMU->HFPERPRESCC & _CMU_HFPERPRESCC_PRESC_MASK)
7621             >> _CMU_HFPERPRESCC_PRESC_SHIFT;
7622       break;
7623 #endif
7624 
7625     case CMU_HFCOREPRESC_REG:
7626       ret = (CMU->HFCOREPRESC & _CMU_HFCOREPRESC_PRESC_MASK)
7627             >> _CMU_HFCOREPRESC_PRESC_SHIFT;
7628       break;
7629 
7630     case CMU_LFAPRESC0_REG:
7631       switch (clock) {
7632 #if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
7633         case cmuClock_LETIMER0:
7634           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
7635                 >> _CMU_LFAPRESC0_LETIMER0_SHIFT;
7636           /* Convert the exponent to a prescaler value. */
7637           ret = SL_Log2ToDiv(ret) - 1U;
7638           break;
7639 #endif
7640 
7641 #if defined(_CMU_LFAPRESC0_LESENSE_MASK)
7642         case cmuClock_LESENSE:
7643           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK)
7644                 >> _CMU_LFAPRESC0_LESENSE_SHIFT;
7645           /* Convert the exponent to a prescaler value. */
7646           ret = SL_Log2ToDiv(ret) - 1U;
7647           break;
7648 #endif
7649 
7650 #if defined(_CMU_LFAPRESC0_LETIMER1_MASK)
7651         case cmuClock_LETIMER1:
7652           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER1_MASK)
7653                 >> _CMU_LFAPRESC0_LETIMER1_SHIFT;
7654           ret = SL_Log2ToDiv(ret) - 1U;
7655           break;
7656 #endif
7657 
7658 #if defined(_CMU_LFAPRESC0_LCD_MASK)
7659         case cmuClock_LCD:
7660         case cmuClock_LCDpre:
7661           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
7662                 >> _CMU_LFAPRESC0_LCD_SHIFT;
7663           ret = SL_Log2ToDiv(ret) - 1U;
7664           break;
7665 #endif
7666 
7667 #if defined(_CMU_LFAPRESC0_RTC_MASK)
7668         case cmuClock_RTC:
7669           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK)
7670                 >> _CMU_LFAPRESC0_RTC_SHIFT;
7671           ret = SL_Log2ToDiv(ret) - 1U;
7672           break;
7673 #endif
7674 
7675         default:
7676           ret = 0U;
7677           EFM_ASSERT(false);
7678           break;
7679       }
7680       break;
7681 
7682     case CMU_LFBPRESC0_REG:
7683       switch (clock) {
7684 #if defined(_CMU_LFBPRESC0_LEUART0_MASK)
7685         case cmuClock_LEUART0:
7686           ret = (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
7687                 >> _CMU_LFBPRESC0_LEUART0_SHIFT;
7688           /* Convert the exponent to a prescaler value. */
7689           ret = SL_Log2ToDiv(ret) - 1U;
7690           break;
7691 #endif
7692 
7693 #if defined(_CMU_LFBPRESC0_LEUART1_MASK)
7694         case cmuClock_LEUART1:
7695           ret = (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
7696                 >> _CMU_LFBPRESC0_LEUART1_SHIFT;
7697           /* Convert the exponent to a prescaler value. */
7698           ret = SL_Log2ToDiv(ret) - 1U;
7699           break;
7700 #endif
7701 
7702 #if defined(_CMU_LFBPRESC0_CSEN_MASK)
7703         case cmuClock_CSEN_LF:
7704           ret = (CMU->LFBPRESC0 & _CMU_LFBPRESC0_CSEN_MASK)
7705                 >> _CMU_LFBPRESC0_CSEN_SHIFT;
7706           /* Convert the exponent to a prescaler value. */
7707           ret = SL_Log2ToDiv(ret + 4U) - 1U;
7708           break;
7709 #endif
7710 
7711         default:
7712           ret = 0U;
7713           EFM_ASSERT(false);
7714           break;
7715       }
7716       break;
7717 
7718     case CMU_LFEPRESC0_REG:
7719       switch (clock) {
7720 #if defined(RTCC_PRESENT)
7721         case cmuClock_RTCC:
7722           ret = (CMU->LFEPRESC0 & _CMU_LFEPRESC0_RTCC_MASK)
7723                 >> _CMU_LFEPRESC0_RTCC_SHIFT;
7724           break;
7725 
7726         default:
7727           ret = 0U;
7728           EFM_ASSERT(false);
7729           break;
7730 #endif
7731       }
7732       break;
7733 
7734 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK) \
7735       || defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
7736     case CMU_ADCASYNCDIV_REG:
7737       switch (clock) {
7738 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK)
7739         case cmuClock_ADC0ASYNC:
7740           ret = (CMU->ADCCTRL & _CMU_ADCCTRL_ADC0CLKDIV_MASK)
7741                 >> _CMU_ADCCTRL_ADC0CLKDIV_SHIFT;
7742           break;
7743 #endif
7744 #if defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
7745         case cmuClock_ADC1ASYNC:
7746           ret = (CMU->ADCCTRL & _CMU_ADCCTRL_ADC1CLKDIV_MASK)
7747                 >> _CMU_ADCCTRL_ADC1CLKDIV_SHIFT;
7748           break;
7749 #endif
7750         default:
7751           ret = 0U;
7752           EFM_ASSERT(false);
7753           break;
7754       }
7755       break;
7756 #endif
7757 #if defined(_CMU_HFBUSPRESC_MASK)
7758     case CMU_HFBUSPRESC_REG:
7759       ret = (CMU->HFBUSPRESC & _CMU_HFBUSPRESC_MASK)
7760             >> _CMU_HFBUSPRESC_PRESC_SHIFT;
7761       break;
7762 #endif
7763     default:
7764       ret = 0U;
7765       EFM_ASSERT(false);
7766       break;
7767   }
7768 
7769   return ret;
7770 }
7771 #endif
7772 
7773 #if defined(_SILICON_LABS_32B_SERIES_1)
7774 /***************************************************************************//**
7775  * @brief
7776  *   Set the clock prescaler.
7777  *
7778  * @note
7779  *   If setting an LF clock prescaler, synchronization into the low-frequency
7780  *   domain is required. If the same register is modified before a previous
7781  *   update has completed, this function will stall until the previous
7782  *   synchronization has completed. See @ref CMU_FreezeEnable() for
7783  *   a suggestion on how to reduce the stalling time in some use cases.
7784  *
7785  *   HFCLKLE prescaler is automatically modified when peripherals with clock
7786  *   domain HFBUSCLK is chosen based on the maximum HFLE frequency allowed.
7787  *
7788  * @param[in] clock
7789  *   A clock point to set the prescaler for. Notice that not all clock points
7790  *   have a prescaler. See the CMU overview in the reference manual.
7791  *
7792  * @param[in] presc
7793  *   The clock prescaler. The prescaler value is linked to the clock divider by:
7794  *   divider = 'presc' + 1.
7795  ******************************************************************************/
CMU_ClockPrescSet(CMU_Clock_TypeDef clock,CMU_ClkPresc_TypeDef presc)7796 void CMU_ClockPrescSet(CMU_Clock_TypeDef clock, CMU_ClkPresc_TypeDef presc)
7797 {
7798   uint32_t freq;
7799   uint32_t prescReg;
7800 
7801   /* Get the divisor reg ID. */
7802   prescReg = ((unsigned)clock >> CMU_PRESC_REG_POS) & CMU_PRESC_REG_MASK;
7803 
7804   switch (prescReg) {
7805     case CMU_HFPRESC_REG:
7806       EFM_ASSERT(presc < 32U);
7807 
7808       /* Configure worst case wait-states for flash and HFLE, set safe HFPER
7809          clock-tree prescalers. */
7810       flashWaitStateMax();
7811       setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
7812       hfperClkSafePrescaler();
7813 
7814       CMU->HFPRESC = (CMU->HFPRESC & ~_CMU_HFPRESC_PRESC_MASK)
7815                      | (presc << _CMU_HFPRESC_PRESC_SHIFT);
7816 
7817       /* Update the CMSIS core clock variable (this function updates the global
7818          variable). */
7819       freq = SystemCoreClockGet();
7820       /* Optimize flash and HFLE wait states and set optimized HFPER clock-tree
7821          prescalers. */
7822       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
7823       setHfLeConfig(SystemHFClockGet());
7824       hfperClkOptimizedPrescaler();
7825       break;
7826 
7827     case CMU_HFEXPPRESC_REG:
7828       EFM_ASSERT(presc < 32U);
7829 
7830       CMU->HFEXPPRESC = (CMU->HFEXPPRESC & ~_CMU_HFEXPPRESC_PRESC_MASK)
7831                         | (presc << _CMU_HFEXPPRESC_PRESC_SHIFT);
7832       break;
7833 
7834     case CMU_HFCLKLEPRESC_REG:
7835       presc = CMU_DivToLog2(presc);
7836       CMU->HFPRESC = (CMU->HFPRESC & ~_CMU_HFPRESC_HFCLKLEPRESC_MASK)
7837                      | (presc << _CMU_HFPRESC_HFCLKLEPRESC_SHIFT);
7838       break;
7839 
7840     case CMU_HFPERPRESC_REG:
7841       EFM_ASSERT(presc < 512U);
7842       CMU->HFPERPRESC = (CMU->HFPERPRESC & ~_CMU_HFPERPRESC_PRESC_MASK)
7843                         | (presc << _CMU_HFPERPRESC_PRESC_SHIFT);
7844       break;
7845 
7846 #if defined(_CMU_HFPERPRESCB_MASK)
7847     case CMU_HFPERPRESCB_REG:
7848       EFM_ASSERT(presc < 512U);
7849       CMU->HFPERPRESCB = (CMU->HFPERPRESCB & ~_CMU_HFPERPRESCB_PRESC_MASK)
7850                          | (presc << _CMU_HFPERPRESCB_PRESC_SHIFT);
7851       break;
7852 #endif
7853 
7854 #if defined(_CMU_HFPERPRESCC_MASK)
7855     case CMU_HFPERPRESCC_REG:
7856       EFM_ASSERT(presc < 512U);
7857       CMU->HFPERPRESCC = (CMU->HFPERPRESCC & ~_CMU_HFPERPRESCC_PRESC_MASK)
7858                          | (presc << _CMU_HFPERPRESCC_PRESC_SHIFT);
7859       break;
7860 #endif
7861 
7862     case CMU_HFCOREPRESC_REG:
7863       EFM_ASSERT(presc < 512U);
7864 
7865       /* Configure worst case wait-states for flash. */
7866       flashWaitStateMax();
7867 
7868       CMU->HFCOREPRESC = (CMU->HFCOREPRESC & ~_CMU_HFCOREPRESC_PRESC_MASK)
7869                          | (presc << _CMU_HFCOREPRESC_PRESC_SHIFT);
7870 
7871       /* Update the CMSIS core clock variable (this function updates the global variable).
7872          Optimize flash and HFLE wait states. */
7873       freq = SystemCoreClockGet();
7874       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
7875       break;
7876 
7877     case CMU_LFAPRESC0_REG:
7878       switch (clock) {
7879 #if defined(RTC_PRESENT)
7880         case cmuClock_RTC:
7881           EFM_ASSERT(presc <= 32768U);
7882 
7883           /* Convert the prescaler value to a DIV exponent scale. */
7884           presc = CMU_PrescToLog2(presc);
7885 
7886           /* LF register about to be modified requires sync. Busy check. */
7887           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7888 
7889           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTC_MASK)
7890                            | (presc << _CMU_LFAPRESC0_RTC_SHIFT);
7891           break;
7892 #endif
7893 
7894 #if defined(RTCC_PRESENT)
7895         case cmuClock_RTCC:
7896 #if defined(_CMU_LFEPRESC0_RTCC_MASK)
7897 #if defined(_CMU_LFEPRESC0_RTCC_DIV4)
7898           EFM_ASSERT(presc <= _CMU_LFEPRESC0_RTCC_DIV4);
7899 #elif defined(_CMU_LFEPRESC0_RTCC_DIV2)
7900           EFM_ASSERT(presc <= _CMU_LFEPRESC0_RTCC_DIV2);
7901 #else
7902           EFM_ASSERT(presc <= 0U);
7903 #endif
7904 
7905           /* LF register about to be modified requires sync. Busy check. */
7906           syncReg(CMU_SYNCBUSY_LFEPRESC0);
7907 
7908           CMU->LFEPRESC0 = (CMU->LFEPRESC0 & ~_CMU_LFEPRESC0_RTCC_MASK)
7909                            | (presc << _CMU_LFEPRESC0_RTCC_SHIFT);
7910 #else
7911           EFM_ASSERT(presc <= 32768U);
7912 
7913           /* Convert the prescaler value to a DIV exponent scale. */
7914           presc = CMU_PrescToLog2(presc);
7915 
7916           /* LF register about to be modified requires sync. Busy check. */
7917           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7918 
7919           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTCC_MASK)
7920                            | (presc << _CMU_LFAPRESC0_RTCC_SHIFT);
7921 #endif
7922           break;
7923 #endif
7924 
7925 #if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
7926         case cmuClock_LETIMER0:
7927           EFM_ASSERT(presc <= 32768U);
7928 
7929           /* Convert the prescaler value to a DIV exponent scale. */
7930           presc = CMU_PrescToLog2(presc);
7931 
7932           /* LF register about to be modified requires sync. Busy check. */
7933           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7934 
7935           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LETIMER0_MASK)
7936                            | (presc << _CMU_LFAPRESC0_LETIMER0_SHIFT);
7937           break;
7938 #endif
7939 
7940 #if defined(_CMU_LFAPRESC0_LETIMER1_MASK)
7941         case cmuClock_LETIMER1:
7942           EFM_ASSERT(presc <= 32768U);
7943 
7944           /* Convert the prescaler value to a DIV exponent scale. */
7945           presc = CMU_PrescToLog2(presc);
7946 
7947           /* LF register about to be modified requires sync. Busy check. */
7948           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7949 
7950           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LETIMER1_MASK)
7951                            | (presc << _CMU_LFAPRESC0_LETIMER1_SHIFT);
7952           break;
7953 #endif
7954 
7955 #if defined(_CMU_LFAPRESC0_LESENSE_MASK)
7956         case cmuClock_LESENSE:
7957           EFM_ASSERT(presc <= 8U);
7958 
7959           /* Convert the prescaler value to a DIV exponent scale. */
7960           presc = CMU_PrescToLog2(presc);
7961 
7962           /* LF register about to be modified requires sync. Busy check. */
7963           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7964 
7965           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LESENSE_MASK)
7966                            | (presc << _CMU_LFAPRESC0_LESENSE_SHIFT);
7967           break;
7968 #endif
7969 
7970 #if defined(_CMU_LFAPRESC0_LCD_MASK)
7971         case cmuClock_LCDpre:
7972         case cmuClock_LCD:
7973           EFM_ASSERT(presc <= 32768U);
7974 
7975           /* Convert the prescaler value to a DIV exponent scale. */
7976           presc = CMU_PrescToLog2(presc);
7977 
7978           /* LF register about to be modified requires sync. Busy check. */
7979           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7980 
7981           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LCD_MASK)
7982                            | (presc << _CMU_LFAPRESC0_LCD_SHIFT);
7983           break;
7984 #endif
7985 
7986         default:
7987           EFM_ASSERT(false);
7988           break;
7989       }
7990       break;
7991 
7992     case CMU_LFBPRESC0_REG:
7993       switch (clock) {
7994 #if defined(_CMU_LFBPRESC0_LEUART0_MASK)
7995         case cmuClock_LEUART0:
7996           EFM_ASSERT(presc <= 8U);
7997 
7998           /* Convert the prescaler value to a DIV exponent scale. */
7999           presc = CMU_PrescToLog2(presc);
8000 
8001           /* LF register about to be modified requires sync. Busy check. */
8002           syncReg(CMU_SYNCBUSY_LFBPRESC0);
8003 
8004           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART0_MASK)
8005                            | (presc << _CMU_LFBPRESC0_LEUART0_SHIFT);
8006           break;
8007 #endif
8008 
8009 #if defined(_CMU_LFBPRESC0_LEUART1_MASK)
8010         case cmuClock_LEUART1:
8011           EFM_ASSERT(presc <= 8U);
8012 
8013           /* Convert the prescaler value to a DIV exponent scale. */
8014           presc = CMU_PrescToLog2(presc);
8015 
8016           /* LF register about to be modified requires sync. Busy check. */
8017           syncReg(CMU_SYNCBUSY_LFBPRESC0);
8018 
8019           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART1_MASK)
8020                            | (presc << _CMU_LFBPRESC0_LEUART1_SHIFT);
8021           break;
8022 #endif
8023 
8024 #if defined(_CMU_LFBPRESC0_CSEN_MASK)
8025         case cmuClock_CSEN_LF:
8026           EFM_ASSERT((presc <= 127U) && (presc >= 15U));
8027 
8028           /* Convert the prescaler value to a DIV exponent scale.
8029            * DIV16 is the lowest supported prescaler. */
8030           presc = CMU_PrescToLog2(presc) - 4U;
8031 
8032           /* LF register about to be modified requires sync. Busy check. */
8033           syncReg(CMU_SYNCBUSY_LFBPRESC0);
8034 
8035           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_CSEN_MASK)
8036                            | (presc << _CMU_LFBPRESC0_CSEN_SHIFT);
8037           break;
8038 #endif
8039 
8040         default:
8041           EFM_ASSERT(false);
8042           break;
8043       }
8044       break;
8045 
8046     case CMU_LFEPRESC0_REG:
8047       switch (clock) {
8048 #if defined(_CMU_LFEPRESC0_RTCC_MASK)
8049         case cmuClock_RTCC:
8050 #if defined(_CMU_LFEPRESC0_RTCC_DIV4)
8051           EFM_ASSERT(presc <= _CMU_LFEPRESC0_RTCC_DIV4);
8052 #elif defined(_CMU_LFEPRESC0_RTCC_DIV2)
8053           EFM_ASSERT(presc <= _CMU_LFEPRESC0_RTCC_DIV2);
8054 #else
8055           EFM_ASSERT(presc <= 0U);
8056 #endif
8057 
8058           /* LF register about to be modified requires sync. Busy check. */
8059           syncReg(CMU_SYNCBUSY_LFEPRESC0);
8060 
8061           CMU->LFEPRESC0 = (CMU->LFEPRESC0 & ~_CMU_LFEPRESC0_RTCC_MASK)
8062                            | (presc << _CMU_LFEPRESC0_RTCC_SHIFT);
8063           break;
8064 #endif
8065 
8066         default:
8067           EFM_ASSERT(false);
8068           break;
8069       }
8070       break;
8071 
8072 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK) \
8073       ||  defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
8074     case CMU_ADCASYNCDIV_REG:
8075       switch (clock) {
8076 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK)
8077         case cmuClock_ADC0ASYNC:
8078           EFM_ASSERT(presc <= 3);
8079           CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC0CLKDIV_MASK)
8080                          | (presc << _CMU_ADCCTRL_ADC0CLKDIV_SHIFT);
8081           break;
8082 #endif
8083 
8084 #if defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
8085         case cmuClock_ADC1ASYNC:
8086           EFM_ASSERT(presc <= 3);
8087           CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC1CLKDIV_MASK)
8088                          | (presc << _CMU_ADCCTRL_ADC1CLKDIV_SHIFT);
8089           break;
8090 #endif
8091         default:
8092           EFM_ASSERT(false);
8093           break;
8094       }
8095       break;
8096 #endif
8097 
8098 #if defined(_CMU_HFBUSPRESC_MASK)
8099     case CMU_HFBUSPRESC_REG:
8100       EFM_ASSERT(presc <= _CMU_HFBUSPRESC_MASK >> _CMU_HFBUSPRESC_PRESC_SHIFT);
8101       CMU->HFBUSPRESC = (CMU->HFBUSPRESC & ~_CMU_HFBUSPRESC_MASK)
8102                         | (presc << _CMU_HFBUSPRESC_PRESC_SHIFT);
8103       break;
8104 #endif
8105 
8106     default:
8107       EFM_ASSERT(false);
8108       break;
8109   }
8110 }
8111 #endif
8112 
8113 /***************************************************************************//**
8114  * @brief
8115  *   Get the currently selected reference clock used for a clock branch.
8116  *
8117  * @param[in] clock
8118  *   Clock branch to fetch selected ref. clock for. One of:
8119  *   @li #cmuClock_HF
8120  *   @li #cmuClock_LFA
8121  *   @li #cmuClock_LFB @if _CMU_LFCLKSEL_LFAE_ULFRCO
8122  *   @li #cmuClock_LFC
8123  *   @endif            @if _SILICON_LABS_32B_SERIES_1
8124  *   @li #cmuClock_LFE
8125  *   @endif
8126  *   @li #cmuClock_DBG @if DOXYDOC_USB_PRESENT
8127  *   @li #cmuClock_USBC
8128  *   @endif
8129  *
8130  * @return
8131  *   The reference clock used for clocking the selected branch, #cmuSelect_Error if
8132  *   invalid @p clock provided.
8133  ******************************************************************************/
CMU_ClockSelectGet(CMU_Clock_TypeDef clock)8134 CMU_Select_TypeDef CMU_ClockSelectGet(CMU_Clock_TypeDef clock)
8135 {
8136   CMU_Select_TypeDef ret = cmuSelect_Disabled;
8137   uint32_t selReg;
8138 
8139   selReg = ((unsigned)clock >> CMU_SEL_REG_POS) & CMU_SEL_REG_MASK;
8140 
8141   switch (selReg) {
8142     case CMU_HFCLKSEL_REG:
8143 #if defined(_CMU_HFCLKSTATUS_MASK)
8144       switch (CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK) {
8145         case CMU_HFCLKSTATUS_SELECTED_LFXO:
8146           ret = cmuSelect_LFXO;
8147           break;
8148 
8149         case CMU_HFCLKSTATUS_SELECTED_LFRCO:
8150           ret = cmuSelect_LFRCO;
8151           break;
8152 
8153         case CMU_HFCLKSTATUS_SELECTED_HFXO:
8154           ret = cmuSelect_HFXO;
8155           break;
8156 
8157 #if defined(CMU_HFCLKSTATUS_SELECTED_HFRCODIV2)
8158         case CMU_HFCLKSTATUS_SELECTED_HFRCODIV2:
8159           ret = cmuSelect_HFRCODIV2;
8160           break;
8161 #endif
8162 
8163 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
8164         case CMU_HFCLKSTATUS_SELECTED_CLKIN0:
8165           ret = cmuSelect_CLKIN0;
8166           break;
8167 #endif
8168 
8169 #if defined(CMU_HFCLKSTATUS_SELECTED_USHFRCO)
8170         case CMU_HFCLKSTATUS_SELECTED_USHFRCO:
8171           ret = cmuSelect_USHFRCO;
8172           break;
8173 #endif
8174 
8175         default:
8176           ret = cmuSelect_HFRCO;
8177           break;
8178       }
8179 #else
8180       switch (CMU->STATUS
8181               & (CMU_STATUS_HFRCOSEL
8182                  | CMU_STATUS_HFXOSEL
8183                  | CMU_STATUS_LFRCOSEL
8184 #if defined(CMU_STATUS_USHFRCODIV2SEL)
8185                  | CMU_STATUS_USHFRCODIV2SEL
8186 #endif
8187                  | CMU_STATUS_LFXOSEL)) {
8188         case CMU_STATUS_LFXOSEL:
8189           ret = cmuSelect_LFXO;
8190           break;
8191 
8192         case CMU_STATUS_LFRCOSEL:
8193           ret = cmuSelect_LFRCO;
8194           break;
8195 
8196         case CMU_STATUS_HFXOSEL:
8197           ret = cmuSelect_HFXO;
8198           break;
8199 
8200 #if defined(CMU_STATUS_USHFRCODIV2SEL)
8201         case CMU_STATUS_USHFRCODIV2SEL:
8202           ret = cmuSelect_USHFRCODIV2;
8203           break;
8204 #endif
8205 
8206         default:
8207           ret = cmuSelect_HFRCO;
8208           break;
8209       }
8210 #endif
8211       break;
8212 
8213 #if defined(_CMU_LFCLKSEL_MASK) || defined(_CMU_LFACLKSEL_MASK)
8214     case CMU_LFACLKSEL_REG:
8215 #if defined(_CMU_LFCLKSEL_MASK)
8216       switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFA_MASK) {
8217         case CMU_LFCLKSEL_LFA_LFRCO:
8218           ret = cmuSelect_LFRCO;
8219           break;
8220 
8221         case CMU_LFCLKSEL_LFA_LFXO:
8222           ret = cmuSelect_LFXO;
8223           break;
8224 
8225 #if defined(CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2)
8226         case CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2:
8227           ret = cmuSelect_HFCLKLE;
8228           break;
8229 #endif
8230 
8231         default:
8232 #if defined(CMU_LFCLKSEL_LFAE)
8233           if (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFAE_MASK) {
8234             ret = cmuSelect_ULFRCO;
8235             break;
8236           }
8237 #else
8238           ret = cmuSelect_Disabled;
8239 #endif
8240           break;
8241       }
8242 
8243 #elif defined(_CMU_LFACLKSEL_MASK)
8244       switch (CMU->LFACLKSEL & _CMU_LFACLKSEL_LFA_MASK) {
8245         case CMU_LFACLKSEL_LFA_LFRCO:
8246           ret = cmuSelect_LFRCO;
8247           break;
8248 
8249         case CMU_LFACLKSEL_LFA_LFXO:
8250           ret = cmuSelect_LFXO;
8251           break;
8252 
8253         case CMU_LFACLKSEL_LFA_ULFRCO:
8254           ret = cmuSelect_ULFRCO;
8255           break;
8256 
8257 #if defined(PLFRCO_PRESENT)
8258         case CMU_LFACLKSEL_LFA_PLFRCO:
8259           ret = cmuSelect_PLFRCO;
8260           break;
8261 #endif
8262 
8263         default:
8264           ret = cmuSelect_Disabled;
8265           break;
8266       }
8267 #endif
8268       break;
8269 #endif /* _CMU_LFCLKSEL_MASK || _CMU_LFACLKSEL_MASK */
8270 
8271 #if defined(_CMU_LFCLKSEL_MASK) || defined(_CMU_LFBCLKSEL_MASK)
8272     case CMU_LFBCLKSEL_REG:
8273 #if defined(_CMU_LFCLKSEL_MASK)
8274       switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFB_MASK) {
8275         case CMU_LFCLKSEL_LFB_LFRCO:
8276           ret = cmuSelect_LFRCO;
8277           break;
8278 
8279         case CMU_LFCLKSEL_LFB_LFXO:
8280           ret = cmuSelect_LFXO;
8281           break;
8282 
8283 #if defined(CMU_LFCLKSEL_LFB_HFCORECLKLEDIV2)
8284         case CMU_LFCLKSEL_LFB_HFCORECLKLEDIV2:
8285           ret = cmuSelect_HFCLKLE;
8286           break;
8287 #endif
8288 
8289 #if defined(CMU_LFCLKSEL_LFB_HFCLKLE)
8290         case CMU_LFCLKSEL_LFB_HFCLKLE:
8291           ret = cmuSelect_HFCLKLE;
8292           break;
8293 #endif
8294 
8295         default:
8296 #if defined(CMU_LFCLKSEL_LFBE)
8297           if (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFBE_MASK) {
8298             ret = cmuSelect_ULFRCO;
8299             break;
8300           }
8301 #else
8302           ret = cmuSelect_Disabled;
8303 #endif
8304           break;
8305       }
8306 
8307 #elif defined(_CMU_LFBCLKSEL_MASK)
8308       switch (CMU->LFBCLKSEL & _CMU_LFBCLKSEL_LFB_MASK) {
8309         case CMU_LFBCLKSEL_LFB_LFRCO:
8310           ret = cmuSelect_LFRCO;
8311           break;
8312 
8313         case CMU_LFBCLKSEL_LFB_LFXO:
8314           ret = cmuSelect_LFXO;
8315           break;
8316 
8317         case CMU_LFBCLKSEL_LFB_ULFRCO:
8318           ret = cmuSelect_ULFRCO;
8319           break;
8320 
8321         case CMU_LFBCLKSEL_LFB_HFCLKLE:
8322           ret = cmuSelect_HFCLKLE;
8323           break;
8324 
8325 #if defined(PLFRCO_PRESENT)
8326         case CMU_LFBCLKSEL_LFB_PLFRCO:
8327           ret = cmuSelect_PLFRCO;
8328           break;
8329 #endif
8330 
8331         default:
8332           ret = cmuSelect_Disabled;
8333           break;
8334       }
8335 #endif
8336       break;
8337 #endif /* _CMU_LFCLKSEL_MASK || _CMU_LFBCLKSEL_MASK */
8338 
8339 #if defined(_CMU_LFCLKSEL_LFC_MASK)
8340     case CMU_LFCCLKSEL_REG:
8341       switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFC_MASK) {
8342         case CMU_LFCLKSEL_LFC_LFRCO:
8343           ret = cmuSelect_LFRCO;
8344           break;
8345 
8346         case CMU_LFCLKSEL_LFC_LFXO:
8347           ret = cmuSelect_LFXO;
8348           break;
8349 
8350         default:
8351           ret = cmuSelect_Disabled;
8352           break;
8353       }
8354       break;
8355 #endif
8356 
8357 #if defined(_CMU_LFECLKSEL_LFE_MASK)
8358     case CMU_LFECLKSEL_REG:
8359       switch (CMU->LFECLKSEL & _CMU_LFECLKSEL_LFE_MASK) {
8360         case CMU_LFECLKSEL_LFE_LFRCO:
8361           ret = cmuSelect_LFRCO;
8362           break;
8363 
8364         case CMU_LFECLKSEL_LFE_LFXO:
8365           ret = cmuSelect_LFXO;
8366           break;
8367 
8368         case CMU_LFECLKSEL_LFE_ULFRCO:
8369           ret = cmuSelect_ULFRCO;
8370           break;
8371 
8372 #if defined(PLFRCO_PRESENT)
8373         case CMU_LFECLKSEL_LFE_PLFRCO:
8374           ret = cmuSelect_PLFRCO;
8375           break;
8376 #endif
8377 
8378         default:
8379           ret = cmuSelect_Disabled;
8380           break;
8381       }
8382       break;
8383 #endif /* CMU_LFECLKSEL_REG */
8384 
8385 #if defined(_CMU_LFCCLKSEL_LFC_MASK)
8386     case CMU_LFCCLKSEL_REG:
8387       switch (CMU->LFCCLKSEL & _CMU_LFCCLKSEL_LFC_MASK) {
8388         case CMU_LFCCLKSEL_LFC_LFRCO:
8389           ret = cmuSelect_LFRCO;
8390           break;
8391 
8392         case CMU_LFCCLKSEL_LFC_LFXO:
8393           ret = cmuSelect_LFXO;
8394           break;
8395 
8396         case CMU_LFCCLKSEL_LFC_ULFRCO:
8397           ret = cmuSelect_ULFRCO;
8398           break;
8399 
8400         default:
8401           ret = cmuSelect_Disabled;
8402           break;
8403       }
8404       break;
8405 #endif /* CMU_LFCCLKSEL_REG */
8406 
8407     case CMU_DBGCLKSEL_REG:
8408 #if defined(_CMU_DBGCLKSEL_DBG_MASK)
8409       switch (CMU->DBGCLKSEL & _CMU_DBGCLKSEL_DBG_MASK) {
8410         case CMU_DBGCLKSEL_DBG_HFCLK:
8411           ret = cmuSelect_HFCLK;
8412           break;
8413 
8414         case CMU_DBGCLKSEL_DBG_AUXHFRCO:
8415           ret = cmuSelect_AUXHFRCO;
8416           break;
8417 
8418         default:
8419           ret = cmuSelect_Disabled;
8420           break;
8421       }
8422 
8423 #elif defined(_CMU_CTRL_DBGCLK_MASK)
8424       switch (CMU->CTRL & _CMU_CTRL_DBGCLK_MASK) {
8425         case CMU_CTRL_DBGCLK_AUXHFRCO:
8426           ret = cmuSelect_AUXHFRCO;
8427           break;
8428 
8429         case CMU_CTRL_DBGCLK_HFCLK:
8430           ret = cmuSelect_HFCLK;
8431           break;
8432       }
8433 #else
8434       ret = cmuSelect_AUXHFRCO;
8435 #endif
8436       break;
8437 
8438 #if defined(USBC_CLOCK_PRESENT)
8439     case CMU_USBCCLKSEL_REG:
8440       switch (CMU->STATUS
8441               & (CMU_STATUS_USBCLFXOSEL
8442 #if defined(_CMU_STATUS_USBCHFCLKSEL_MASK)
8443                  | CMU_STATUS_USBCHFCLKSEL
8444 #endif
8445 #if defined(_CMU_STATUS_USBCUSHFRCOSEL_MASK)
8446                  | CMU_STATUS_USBCUSHFRCOSEL
8447 #endif
8448                  | CMU_STATUS_USBCLFRCOSEL)) {
8449 #if defined(_CMU_STATUS_USBCHFCLKSEL_MASK)
8450         case CMU_STATUS_USBCHFCLKSEL:
8451           ret = cmuSelect_HFCLK;
8452           break;
8453 #endif
8454 
8455 #if defined(_CMU_STATUS_USBCUSHFRCOSEL_MASK)
8456         case CMU_STATUS_USBCUSHFRCOSEL:
8457           ret = cmuSelect_USHFRCO;
8458           break;
8459 #endif
8460 
8461         case CMU_STATUS_USBCLFXOSEL:
8462           ret = cmuSelect_LFXO;
8463           break;
8464 
8465         case CMU_STATUS_USBCLFRCOSEL:
8466           ret = cmuSelect_LFRCO;
8467           break;
8468 
8469         default:
8470           ret = cmuSelect_Disabled;
8471           break;
8472       }
8473       break;
8474 #endif
8475 
8476 #if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
8477     case CMU_ADC0ASYNCSEL_REG:
8478       switch (CMU->ADCCTRL & _CMU_ADCCTRL_ADC0CLKSEL_MASK) {
8479         case CMU_ADCCTRL_ADC0CLKSEL_DISABLED:
8480           ret = cmuSelect_Disabled;
8481           break;
8482 
8483         case CMU_ADCCTRL_ADC0CLKSEL_AUXHFRCO:
8484           ret = cmuSelect_AUXHFRCO;
8485           break;
8486 
8487         case CMU_ADCCTRL_ADC0CLKSEL_HFXO:
8488           ret = cmuSelect_HFXO;
8489           break;
8490 
8491         case CMU_ADCCTRL_ADC0CLKSEL_HFSRCCLK:
8492           ret = cmuSelect_HFSRCCLK;
8493           break;
8494 
8495         default:
8496           ret = cmuSelect_Disabled;
8497           break;
8498       }
8499       break;
8500 #endif
8501 
8502 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
8503     case CMU_ADC1ASYNCSEL_REG:
8504       switch (CMU->ADCCTRL & _CMU_ADCCTRL_ADC1CLKSEL_MASK) {
8505         case CMU_ADCCTRL_ADC1CLKSEL_DISABLED:
8506           ret = cmuSelect_Disabled;
8507           break;
8508 
8509         case CMU_ADCCTRL_ADC1CLKSEL_AUXHFRCO:
8510           ret = cmuSelect_AUXHFRCO;
8511           break;
8512 
8513         case CMU_ADCCTRL_ADC1CLKSEL_HFXO:
8514           ret = cmuSelect_HFXO;
8515           break;
8516 
8517         case CMU_ADCCTRL_ADC1CLKSEL_HFSRCCLK:
8518           ret = cmuSelect_HFSRCCLK;
8519           break;
8520       }
8521       break;
8522 #endif
8523 
8524 #if defined(_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
8525     case CMU_SDIOREFSEL_REG:
8526       switch (CMU->SDIOCTRL & _CMU_SDIOCTRL_SDIOCLKSEL_MASK) {
8527         case CMU_SDIOCTRL_SDIOCLKSEL_HFRCO:
8528           ret = cmuSelect_HFRCO;
8529           break;
8530 
8531         case CMU_SDIOCTRL_SDIOCLKSEL_HFXO:
8532           ret = cmuSelect_HFXO;
8533           break;
8534 
8535         case CMU_SDIOCTRL_SDIOCLKSEL_AUXHFRCO:
8536           ret = cmuSelect_AUXHFRCO;
8537           break;
8538 
8539         case CMU_SDIOCTRL_SDIOCLKSEL_USHFRCO:
8540           ret = cmuSelect_USHFRCO;
8541           break;
8542       }
8543       break;
8544 #endif
8545 
8546 #if defined(_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
8547     case CMU_QSPI0REFSEL_REG:
8548       switch (CMU->QSPICTRL & _CMU_QSPICTRL_QSPI0CLKSEL_MASK) {
8549         case CMU_QSPICTRL_QSPI0CLKSEL_HFRCO:
8550           ret = cmuSelect_HFRCO;
8551           break;
8552 
8553         case CMU_QSPICTRL_QSPI0CLKSEL_HFXO:
8554           ret = cmuSelect_HFXO;
8555           break;
8556 
8557         case CMU_QSPICTRL_QSPI0CLKSEL_AUXHFRCO:
8558           ret = cmuSelect_AUXHFRCO;
8559           break;
8560 
8561         case CMU_QSPICTRL_QSPI0CLKSEL_USHFRCO:
8562           ret = cmuSelect_USHFRCO;
8563           break;
8564       }
8565       break;
8566 #endif
8567 
8568 #if defined(_CMU_USBCTRL_USBCLKSEL_MASK)
8569     case CMU_USBRCLKSEL_REG:
8570       switch (CMU->USBCTRL & _CMU_USBCTRL_USBCLKSEL_MASK) {
8571         case CMU_USBCTRL_USBCLKSEL_USHFRCO:
8572           ret = cmuSelect_USHFRCO;
8573           break;
8574 
8575         case CMU_USBCTRL_USBCLKSEL_HFXO:
8576           ret = cmuSelect_HFXO;
8577           break;
8578 
8579         case CMU_USBCTRL_USBCLKSEL_HFXOX2:
8580           ret = cmuSelect_HFXOX2;
8581           break;
8582 
8583         case CMU_USBCTRL_USBCLKSEL_HFRCO:
8584           ret = cmuSelect_HFRCO;
8585           break;
8586 
8587         case CMU_USBCTRL_USBCLKSEL_LFXO:
8588           ret = cmuSelect_LFXO;
8589           break;
8590 
8591         case CMU_USBCTRL_USBCLKSEL_LFRCO:
8592           ret = cmuSelect_LFRCO;
8593           break;
8594       }
8595       break;
8596 #endif
8597 
8598 #if defined(_CMU_PDMCTRL_PDMCLKSEL_MASK)
8599     case CMU_PDMREFSEL_REG:
8600       switch (CMU->PDMCTRL & _CMU_PDMCTRL_PDMCLKSEL_MASK) {
8601         case CMU_PDMCTRL_PDMCLKSEL_USHFRCO:
8602           ret = cmuSelect_USHFRCO;
8603           break;
8604 
8605         case CMU_PDMCTRL_PDMCLKSEL_HFXO:
8606           ret = cmuSelect_HFXO;
8607           break;
8608 
8609         case CMU_PDMCTRL_PDMCLKSEL_HFRCO:
8610           ret = cmuSelect_HFRCO;
8611           break;
8612       }
8613       break;
8614 #endif
8615 
8616     default:
8617       ret = cmuSelect_Error;
8618       EFM_ASSERT(false);
8619       break;
8620   }
8621 
8622   return ret;
8623 }
8624 
8625 /***************************************************************************//**
8626  * @brief This function configures the HFLE wait-states and divider suitable
8627  *        for the System Core Clock.
8628  *
8629  * @note FOR INTERNAL USE ONLY.
8630  *
8631  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
8632  *       the clock source is HFCLKLE.
8633  ******************************************************************************/
sli_em_cmu_SetHFLEConfigSystemCoreClock(void)8634 void sli_em_cmu_SetHFLEConfigSystemCoreClock(void)
8635 {
8636 #if defined(CMU_MAX_FREQ_HFLE)
8637   setHfLeConfig(SystemCoreClockGet());
8638 #endif
8639 }
8640 
8641 /***************************************************************************//**
8642  * @brief This function configures the HFLE wait-states and divider suitable
8643  *        for the HF Clock.
8644  *
8645  * @note FOR INTERNAL USE ONLY.
8646  *
8647  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
8648  *       the clock source is HFCLKLE.
8649  ******************************************************************************/
sli_em_cmu_SetHFLEConfigHFClock(void)8650 void sli_em_cmu_SetHFLEConfigHFClock(void)
8651 {
8652 #if defined(CMU_MAX_FREQ_HFLE)
8653   setHfLeConfig(SystemHFClockGet());
8654 #endif
8655 }
8656 
8657 /***************************************************************************//**
8658  * @brief This function is used to initialize the HF clock and selecting
8659  *        an LF clock source.
8660  *
8661  * @note FOR INTERNAL USE ONLY.
8662  *
8663  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
8664  *       the clock is HF and LFXO or LFRCO is selected as the clock source.
8665  ******************************************************************************/
sli_em_cmu_HFClockSelectLFOsc(uint8_t osc)8666 void sli_em_cmu_HFClockSelectLFOsc(uint8_t osc)
8667 {
8668   if (osc == (uint8_t)cmuOsc_LFXO) {
8669     // Enable LFXO oscillator
8670     CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
8671   } else if (osc == (uint8_t)cmuOsc_LFRCO) {
8672     // Enable LFRCO oscillator
8673     CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
8674   } else {
8675     EFM_ASSERT(false);
8676   }
8677 
8678   // Configure worst case wait-states for flash and set safe HFPER
8679   // clock-tree prescalers.
8680   flashWaitStateMax();
8681   hfperClkSafePrescaler();
8682 
8683 #if defined(_SILICON_LABS_32B_SERIES_1)
8684   // Select HF clock source.
8685   if (osc == (uint8_t)cmuOsc_LFXO) {
8686     CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFXO;
8687   } else if (osc == (uint8_t)cmuOsc_LFRCO) {
8688     CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFRCO;
8689   }
8690 #if defined(CMU_MAX_FREQ_HFLE)
8691   // Set HFLE clock.
8692   setHfLeConfig(SystemHFClockGet());
8693 #endif
8694 #elif defined(_SILICON_LABS_32B_SERIES_0)
8695   // Select HF clock source.
8696   if (osc == (uint8_t)cmuOsc_LFXO) {
8697     CMU->CMD = CMU_CMD_HFCLKSEL_LFXO;
8698   } else if (osc == (uint8_t)cmuOsc_LFRCO) {
8699     CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO;
8700   }
8701 #if defined(CMU_MAX_FREQ_HFLE)
8702   // Set HFLE clock.
8703   setHfLeConfig(SystemCoreClockGet());
8704 #endif
8705 #endif
8706 
8707   // Optimize flash access wait state setting for the currently selected core clk.
8708   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
8709   // Set optimized HFPER clock-tree prescalers.
8710   hfperClkOptimizedPrescaler();
8711 }
8712 
8713 /***************************************************************************//**
8714  * @brief This function is used to initialize the HF clock and selecting
8715  *        HFXO as the clock source.
8716  *
8717  * @note FOR INTERNAL USE ONLY.
8718  *
8719  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
8720  *       the clock is HF and HFXO is selected as the clock source.
8721  ******************************************************************************/
sli_em_cmu_HFClockSelectHFXO(void)8722 void sli_em_cmu_HFClockSelectHFXO(void)
8723 {
8724 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
8725   uint32_t vScaleFrequency = SystemHFXOClockGet();
8726   EMU_VScaleEM01ByClock(vScaleFrequency, false);
8727 #endif
8728 
8729 #if defined(CMU_MAX_FREQ_HFLE)
8730   // Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
8731   // This is known after 'select' is written below.
8732   setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
8733 #endif
8734 #if defined(CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ)
8735   // Adjust HFXO buffer current for frequencies above 32 MHz.
8736   if (SystemHFXOClockGet() > 32000000) {
8737     CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
8738                 | CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ;
8739   } else {
8740     CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
8741                 | CMU_CTRL_HFXOBUFCUR_BOOSTUPTO32MHZ;
8742   }
8743 #endif
8744 
8745   // Enable HFXO oscillator
8746   CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
8747 
8748   // Configure worst case wait-states for flash and set safe HFPER
8749   // clock-tree prescalers.
8750   flashWaitStateMax();
8751   hfperClkSafePrescaler();
8752 
8753 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
8754   // Wait for voltage upscaling to complete before the clock is set.
8755   if (vScaleFrequency != 0UL) {
8756     EMU_VScaleWait();
8757   }
8758 #endif
8759 
8760 #if defined(CMU_HFCLKSEL_HF_HFXO)
8761   // Select HF clock source.
8762   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFXO;
8763 #if defined(CMU_MAX_FREQ_HFLE)
8764   // Set HFLE clock.
8765   setHfLeConfig(SystemHFClockGet());
8766 #endif
8767 #elif defined(CMU_CMD_HFCLKSEL_HFXO)
8768   // Select HF clock source.
8769   CMU->CMD = CMU_CMD_HFCLKSEL_HFXO;
8770 #if defined(CMU_MAX_FREQ_HFLE)
8771   // Set HFLE clock.
8772   setHfLeConfig(SystemCoreClockGet());
8773 #endif
8774 #endif
8775 
8776   // Optimize flash access wait state setting for the currently selected core clk.
8777   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
8778 
8779 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
8780   // Keep EMU module informed on the source HF clock frequency. This will apply voltage
8781   // downscaling after clock is set if downscaling is configured.
8782   if (vScaleFrequency == 0UL) {
8783     EMU_VScaleEM01ByClock(0, true);
8784   }
8785 #endif
8786 
8787   // Set optimized HFPER clock-tree prescalers.
8788   hfperClkOptimizedPrescaler();
8789 }
8790 
8791 /***************************************************************************//**
8792  * @brief This function is used to initialize the HF clock and selecting
8793  *        HFRCO as the clock source.
8794  *
8795  * @note FOR INTERNAL USE ONLY.
8796  *
8797  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
8798  *       the clock is HF and HFRCO is selected as the clock source.
8799  ******************************************************************************/
sli_em_cmu_HFClockSelectHFRCO(void)8800 void sli_em_cmu_HFClockSelectHFRCO(void)
8801 {
8802 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
8803   uint32_t vScaleFrequency = 0;    /* Use default. */
8804   if (((uint32_t)CMU_HFRCOBandGet() > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
8805     vScaleFrequency = (uint32_t)CMU_HFRCOBandGet();
8806   }
8807   if (vScaleFrequency != 0UL) {
8808     EMU_VScaleEM01ByClock(vScaleFrequency, false);
8809   }
8810 #endif
8811 
8812 #if defined(CMU_MAX_FREQ_HFLE)
8813   // Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
8814   // This is known after 'select' is written below.
8815   setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
8816 #endif
8817 
8818   // Enable HFRCO oscillator
8819   CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
8820 
8821   // Configure worst case wait-states for flash and set safe HFPER
8822   // clock-tree prescalers.
8823   flashWaitStateMax();
8824   hfperClkSafePrescaler();
8825 
8826 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
8827   // Wait for voltage upscaling to complete before the clock is set.
8828   if (vScaleFrequency != 0UL) {
8829     EMU_VScaleWait();
8830   }
8831 #endif
8832 
8833 #if defined(_SILICON_LABS_32B_SERIES_1)
8834   // Select HF clock source.
8835   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCO;
8836 #if defined(CMU_MAX_FREQ_HFLE)
8837   // Set HFLE clock.
8838   setHfLeConfig(SystemHFClockGet());
8839 #endif
8840 #elif defined(_SILICON_LABS_32B_SERIES_0)
8841   // Select HF clock source.
8842   CMU->CMD = CMU_CMD_HFCLKSEL_HFRCO;
8843 #if defined(CMU_MAX_FREQ_HFLE)
8844   // Set HFLE clock.
8845   setHfLeConfig(SystemCoreClockGet());
8846 #endif
8847 #endif
8848 
8849   // Optimize flash access wait state setting for the currently selected core clk.
8850   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
8851 
8852 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
8853   // Keep EMU module informed on the source HF clock frequency. This will apply voltage
8854   // downscaling after clock is set if downscaling is configured.
8855   if (vScaleFrequency == 0UL) {
8856     EMU_VScaleEM01ByClock(0, true);
8857   }
8858 #endif
8859 
8860   // Set optimized HFPER clock-tree prescalers.
8861   hfperClkOptimizedPrescaler();
8862 }
8863 
8864 #if defined(CMU_CMD_HFCLKSEL_USHFRCODIV2)
8865 /***************************************************************************//**
8866  * @brief This function is used to initialize the HF clock and selecting
8867  *        USHFRCODIV2 as the clock source.
8868  *
8869  * @note FOR INTERNAL USE ONLY.
8870  *
8871  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
8872  *       the clock is HF and USHFRCODIV2 is selected as the clock source.
8873  ******************************************************************************/
sli_em_cmu_HFClockSelectUSHFRCODIV2(void)8874 void sli_em_cmu_HFClockSelectUSHFRCODIV2(void)
8875 {
8876   // Enable USHFRCO oscillator
8877   CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
8878   // Configure worst case wait-states for flash and set safe HFPER
8879   // clock-tree prescalers.
8880   flashWaitStateMax();
8881   hfperClkSafePrescaler();
8882 
8883   // Select HF clock source.
8884   CMU->CMD = CMU_CMD_HFCLKSEL_USHFRCODIV2;
8885 #if defined(CMU_MAX_FREQ_HFLE)
8886   setHfLeConfig(SystemCoreClockGet());
8887 #endif
8888 
8889   // Optimize flash access wait state setting for the currently selected core clk.
8890   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
8891   // Set optimized HFPER clock-tree prescalers.
8892   hfperClkOptimizedPrescaler();
8893 }
8894 #endif
8895 
8896 #if defined(CMU_HFCLKSTATUS_SELECTED_HFRCODIV2)
8897 /***************************************************************************//**
8898  * @brief This function is used to initialize the HF clock and selecting
8899  *        HFRCODIV2 as the clock source.
8900  *
8901  * @note FOR INTERNAL USE ONLY.
8902  *
8903  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
8904  *       the clock is HF and HFRCODIV2 is selected as the clock source.
8905  ******************************************************************************/
sli_em_cmu_HFClockSelectHFRCODIV2(void)8906 void sli_em_cmu_HFClockSelectHFRCODIV2(void)
8907 {
8908   // Enable HFRCO oscillator
8909   CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
8910   // Configure worst case wait-states for flash and set safe HFPER
8911   // clock-tree prescalers.
8912   flashWaitStateMax();
8913   hfperClkSafePrescaler();
8914 
8915   // Select HF clock source.
8916   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCODIV2;
8917 #if defined(CMU_MAX_FREQ_HFLE)
8918   setHfLeConfig(SystemHFClockGet());
8919 #endif
8920 
8921   // Optimize flash access wait state setting for the currently selected core clk.
8922   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
8923   // Set optimized HFPER clock-tree prescalers.
8924   hfperClkOptimizedPrescaler();
8925 }
8926 #endif
8927 
8928 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
8929 /***************************************************************************//**
8930  * @brief This function is used to initialize the HF clock and selecting
8931  *        CLKIN0 as the clock source.
8932  *
8933  * @note FOR INTERNAL USE ONLY.
8934  *
8935  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
8936  *       the clock is HF and CLKIN0 is selected as the clock source.
8937  ******************************************************************************/
sli_em_cmu_HFClockSelectCLKIN0(void)8938 void sli_em_cmu_HFClockSelectCLKIN0(void)
8939 {
8940   // Configure worst case wait-states for flash and set safe HFPER
8941   // clock-tree prescalers.
8942   flashWaitStateMax();
8943   hfperClkSafePrescaler();
8944 
8945   // Select HF clock source.
8946   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_CLKIN0;
8947 #if defined(CMU_MAX_FREQ_HFLE)
8948   setHfLeConfig(SystemHFClockGet());
8949 #endif
8950 
8951   // Optimize flash access wait state setting for the currently selected core clk.
8952   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
8953   // Set optimized HFPER clock-tree prescalers.
8954   hfperClkOptimizedPrescaler();
8955 }
8956 #endif
8957 
8958 #if defined(CMU_HFCLKSTATUS_SELECTED_USHFRCO)
8959 /***************************************************************************//**
8960  * @brief This function is used to initialize the HF clock and selecting
8961  *        USHFRCO as the clock source.
8962  *
8963  * @note FOR INTERNAL USE ONLY.
8964  *
8965  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
8966  *       the clock is HF and USHFRCO is selected as the clock source.
8967  ******************************************************************************/
sli_em_cmu_HFClockSelectUSHFRCO(void)8968 void sli_em_cmu_HFClockSelectUSHFRCO(void)
8969 {
8970   // Enable USHFRCO oscillator
8971   CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
8972   // Configure worst case wait-states for flash and set safe HFPER
8973   // clock-tree prescalers.
8974   flashWaitStateMax();
8975   hfperClkSafePrescaler();
8976 
8977   // Select HF clock source.
8978   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_USHFRCO;
8979 #if defined(CMU_MAX_FREQ_HFLE)
8980   setHfLeConfig(SystemHFClockGet());
8981 #endif
8982 
8983   // Optimize flash access wait state setting for the currently selected core clk.
8984   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
8985   // Set optimized HFPER clock-tree prescalers.
8986   hfperClkOptimizedPrescaler();
8987 }
8988 #endif
8989 
8990 /***************************************************************************//**
8991  * @brief
8992  *   Select the reference clock/oscillator used for a clock branch.
8993  *
8994  * @details
8995  *   Notice that if a selected reference is not enabled prior to selecting its
8996  *   use, it will be enabled and this function will wait for the selected
8997  *   oscillator to be stable. It will however NOT be disabled if another
8998  *   reference clock is selected later.
8999  *
9000  *   This feature is particularly important if selecting a new reference
9001  *   clock for the clock branch clocking the core. Otherwise, the system
9002  *   may halt.
9003  *
9004  * @note
9005  *   HFCLKLE prescaler is automatically modified when peripherals with clock
9006  *   domain HFBUSCLK is chosen based on the maximum HFLE frequency allowed.
9007  *
9008  * @param[in] clock
9009  *   A clock branch to select reference clock for. One of:
9010  *   @li #cmuClock_HF
9011  *   @li #cmuClock_LFA
9012  *   @li #cmuClock_LFB
9013  *   @if _CMU_LFCCLKEN0_MASK
9014  *   @li #cmuClock_LFC
9015  *   @endif
9016  *   @if _CMU_LFECLKEN0_MASK
9017  *   @li #cmuClock_LFE
9018  *   @endif
9019  *   @li #cmuClock_DBG
9020  *   @if _CMU_CMD_USBCLKSEL_MASK
9021  *   @li #cmuClock_USBC
9022  *   @endif
9023  *   @if _CMU_USBCTRL_MASK
9024  *   @li #cmuClock_USBR
9025  *   @endif
9026  *
9027  * @param[in] ref
9028  *   A reference selected for clocking. See the reference manual
9029  *   for details about references available for a specific clock branch.
9030  *   @li #cmuSelect_HFRCO
9031  *   @li #cmuSelect_LFRCO
9032  *   @li #cmuSelect_HFXO
9033  *   @if _CMU_HFXOCTRL_HFXOX2EN_MASK
9034  *   @li #cmuSelect_HFXOX2
9035  *   @endif
9036  *   @li #cmuSelect_LFXO
9037  *   @li #cmuSelect_HFCLKLE
9038  *   @li #cmuSelect_AUXHFRCO
9039  *   @if _CMU_USHFRCOCTRL_MASK
9040  *   @li #cmuSelect_USHFRCO
9041  *   @endif
9042  *   @li #cmuSelect_HFCLK
9043  *   @ifnot DOXYDOC_EFM32_GECKO_FAMILY
9044  *   @li #cmuSelect_ULFRCO
9045  *   @endif
9046  *   @if CMU_OSCENCMD_PLFRCOEN
9047  *   @li #cmuSelect_PLFRCO
9048  *   @endif
9049  ******************************************************************************/
CMU_ClockSelectSet(CMU_Clock_TypeDef clock,CMU_Select_TypeDef ref)9050 void CMU_ClockSelectSet(CMU_Clock_TypeDef clock, CMU_Select_TypeDef ref)
9051 {
9052   uint32_t              select = (uint32_t)cmuOsc_HFRCO;
9053   CMU_Osc_TypeDef       osc    = cmuOsc_HFRCO;
9054   uint32_t              freq;
9055   uint32_t              tmp;
9056   uint32_t              selRegId;
9057 #if defined(_SILICON_LABS_32B_SERIES_1)
9058   volatile uint32_t     *selReg = NULL;
9059 #endif
9060 #if defined(CMU_LFCLKSEL_LFAE_ULFRCO)
9061   uint32_t              lfExtended = 0;
9062 #endif
9063 
9064 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9065   uint32_t              vScaleFrequency = 0; /* Use default. */
9066 
9067   /* Start voltage upscaling before the clock is set. */
9068   if (clock == cmuClock_HF) {
9069     if (ref == cmuSelect_HFXO) {
9070       vScaleFrequency = SystemHFXOClockGet();
9071     } else if ((ref == cmuSelect_HFRCO)
9072                && ((uint32_t)CMU_HFRCOBandGet()
9073                    > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
9074       vScaleFrequency = (uint32_t)CMU_HFRCOBandGet();
9075     } else {
9076       /* Use the default frequency. */
9077     }
9078     if (vScaleFrequency != 0UL) {
9079       EMU_VScaleEM01ByClock(vScaleFrequency, false);
9080     }
9081   }
9082 #endif
9083 
9084   selRegId = ((unsigned)clock >> CMU_SEL_REG_POS) & CMU_SEL_REG_MASK;
9085 
9086   switch (selRegId) {
9087     case CMU_HFCLKSEL_REG:
9088       switch (ref) {
9089         case cmuSelect_LFXO:
9090 #if defined(_SILICON_LABS_32B_SERIES_1)
9091           select = CMU_HFCLKSEL_HF_LFXO;
9092 #elif defined(_SILICON_LABS_32B_SERIES_0)
9093           select = CMU_CMD_HFCLKSEL_LFXO;
9094 #endif
9095           osc = cmuOsc_LFXO;
9096           break;
9097 
9098         case cmuSelect_LFRCO:
9099 #if defined(_SILICON_LABS_32B_SERIES_1)
9100           select = CMU_HFCLKSEL_HF_LFRCO;
9101 #elif defined(_SILICON_LABS_32B_SERIES_0)
9102           select = CMU_CMD_HFCLKSEL_LFRCO;
9103 #endif
9104           osc = cmuOsc_LFRCO;
9105           break;
9106 
9107         case cmuSelect_HFXO:
9108 #if defined(CMU_HFCLKSEL_HF_HFXO)
9109           select = CMU_HFCLKSEL_HF_HFXO;
9110 #elif defined(CMU_CMD_HFCLKSEL_HFXO)
9111           select = CMU_CMD_HFCLKSEL_HFXO;
9112 #endif
9113           osc = cmuOsc_HFXO;
9114 #if defined(CMU_MAX_FREQ_HFLE)
9115           /* Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
9116              This is known after 'select' is written below. */
9117           setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
9118 #endif
9119 #if defined(CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ)
9120           /* Adjust HFXO buffer current for frequencies above 32 MHz. */
9121           if (SystemHFXOClockGet() > 32000000) {
9122             CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
9123                         | CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ;
9124           } else {
9125             CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
9126                         | CMU_CTRL_HFXOBUFCUR_BOOSTUPTO32MHZ;
9127           }
9128 #endif
9129           break;
9130 
9131         case cmuSelect_HFRCO:
9132 #if defined(_SILICON_LABS_32B_SERIES_1)
9133           select = CMU_HFCLKSEL_HF_HFRCO;
9134 #elif defined(_SILICON_LABS_32B_SERIES_0)
9135           select = CMU_CMD_HFCLKSEL_HFRCO;
9136 #endif
9137           osc = cmuOsc_HFRCO;
9138 #if defined(CMU_MAX_FREQ_HFLE)
9139           /* Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
9140              This is known after 'select' is written below. */
9141           setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
9142 #endif
9143           break;
9144 
9145 #if defined(CMU_CMD_HFCLKSEL_USHFRCODIV2)
9146         case cmuSelect_USHFRCODIV2:
9147           select = CMU_CMD_HFCLKSEL_USHFRCODIV2;
9148           osc = cmuOsc_USHFRCO;
9149           break;
9150 #endif
9151 
9152 #if defined(CMU_HFCLKSTATUS_SELECTED_HFRCODIV2)
9153         case cmuSelect_HFRCODIV2:
9154           select = CMU_HFCLKSEL_HF_HFRCODIV2;
9155           osc = cmuOsc_HFRCO;
9156           break;
9157 #endif
9158 
9159 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
9160         case cmuSelect_CLKIN0:
9161           select = CMU_HFCLKSEL_HF_CLKIN0;
9162           osc = cmuOsc_CLKIN0;
9163           break;
9164 #endif
9165 
9166 #if defined(CMU_HFCLKSTATUS_SELECTED_USHFRCO)
9167         case cmuSelect_USHFRCO:
9168           select = CMU_HFCLKSEL_HF_USHFRCO;
9169           osc = cmuOsc_USHFRCO;
9170           break;
9171 #endif
9172 
9173 #if defined(CMU_LFCLKSEL_LFAE_ULFRCO) || defined(CMU_LFACLKSEL_LFA_ULFRCO)
9174         case cmuSelect_ULFRCO:
9175           /* ULFRCO cannot be used as HFCLK.  */
9176           EFM_ASSERT(false);
9177           return;
9178 #endif
9179 
9180         default:
9181           EFM_ASSERT(false);
9182           return;
9183       }
9184 
9185       /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9186 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
9187       if (osc != cmuOsc_CLKIN0) {
9188         CMU_OscillatorEnable(osc, true, true);
9189       }
9190 #else
9191       CMU_OscillatorEnable(osc, true, true);
9192 #endif
9193 
9194       /* Configure worst case wait-states for flash and set safe HFPER
9195          clock-tree prescalers. */
9196       flashWaitStateMax();
9197       hfperClkSafePrescaler();
9198 
9199 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9200       /* Wait for voltage upscaling to complete before the clock is set. */
9201       if (vScaleFrequency != 0UL) {
9202         EMU_VScaleWait();
9203       }
9204 #endif
9205 
9206       /* Switch to the selected oscillator. */
9207 #if defined(_CMU_HFCLKSEL_MASK)
9208       CMU->HFCLKSEL = select;
9209 #else
9210       CMU->CMD = select;
9211 #endif
9212       /* Update the CMSIS core clock variable. */
9213       /* (The function will update the global variable). */
9214       freq = SystemCoreClockGet();
9215 
9216 #if defined(CMU_MAX_FREQ_HFLE)
9217       /* Update the HFLE configuration after 'select' is set.
9218          Note that the HFCLKLE clock is connected differently on platforms 1 and 2. */
9219 #if defined(_SILICON_LABS_32B_SERIES_0)
9220       setHfLeConfig(freq);
9221 #else
9222       setHfLeConfig(SystemHFClockGet());
9223 #endif
9224 #endif
9225 
9226       /* Optimize flash access wait state setting for the currently selected core clk. */
9227       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
9228 
9229 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9230       /* Keep EMU module informed on the source HF clock frequency. This will apply voltage
9231          downscaling after clock is set if downscaling is configured. */
9232       if (vScaleFrequency == 0UL) {
9233         EMU_VScaleEM01ByClock(0, true);
9234       }
9235 #endif
9236       /* Set optimized HFPER clock-tree prescalers. */
9237       hfperClkOptimizedPrescaler();
9238       break;
9239 
9240 #if defined(_SILICON_LABS_32B_SERIES_1)
9241     case CMU_LFACLKSEL_REG:
9242       selReg = &CMU->LFACLKSEL;
9243       /* HFCLKCLE can't be used as LFACLK. */
9244       EFM_ASSERT(ref != cmuSelect_HFCLKLE);
9245       SL_FALLTHROUGH
9246       /* Fall through and select the clock source. */
9247 
9248 #if defined(_CMU_LFCCLKSEL_MASK)
9249     case CMU_LFCCLKSEL_REG:
9250       selReg = (selReg == NULL) ? &CMU->LFCCLKSEL : selReg;
9251       /* HFCLKCLE can't be used as LFCCLK. */
9252       EFM_ASSERT(ref != cmuSelect_HFCLKLE);
9253       SL_FALLTHROUGH
9254 #endif
9255     /* Fall through and select the clock source. */
9256 
9257     case CMU_LFECLKSEL_REG:
9258       selReg = (selReg == NULL) ? &CMU->LFECLKSEL : selReg;
9259       /* HFCLKCLE can't be used as LFECLK. */
9260       EFM_ASSERT(ref != cmuSelect_HFCLKLE);
9261       SL_FALLTHROUGH
9262     /* Fall through and select the clock source. */
9263 
9264     case CMU_LFBCLKSEL_REG:
9265       selReg = (selReg == NULL) ? &CMU->LFBCLKSEL : selReg;
9266       switch (ref) {
9267         case cmuSelect_Disabled:
9268           tmp = _CMU_LFACLKSEL_LFA_DISABLED;
9269           break;
9270 
9271         case cmuSelect_LFXO:
9272           /* Ensure that thes elected oscillator is enabled, waiting for it to stabilize. */
9273           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9274           tmp = _CMU_LFACLKSEL_LFA_LFXO;
9275           break;
9276 
9277         case cmuSelect_LFRCO:
9278           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9279           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9280           tmp = _CMU_LFACLKSEL_LFA_LFRCO;
9281           break;
9282 
9283         case cmuSelect_HFCLKLE:
9284           /* Ensure the correct HFLE wait-states and enable HFCLK to LE.*/
9285           setHfLeConfig(SystemHFClockGet());
9286           BUS_RegBitWrite(&CMU->HFBUSCLKEN0, _CMU_HFBUSCLKEN0_LE_SHIFT, 1);
9287           tmp = _CMU_LFBCLKSEL_LFB_HFCLKLE;
9288           break;
9289 
9290         case cmuSelect_ULFRCO:
9291           /* ULFRCO is always on, there is no need to enable it. */
9292           tmp = _CMU_LFACLKSEL_LFA_ULFRCO;
9293           break;
9294 
9295 #if defined(PLFRCO_PRESENT)
9296         case cmuSelect_PLFRCO:
9297           CMU_OscillatorEnable(cmuOsc_PLFRCO, true, true);
9298           tmp = _CMU_LFACLKSEL_LFA_PLFRCO;
9299           break;
9300 #endif
9301 
9302         default:
9303           EFM_ASSERT(false);
9304           return;
9305       }
9306       *selReg = tmp;
9307       break;
9308 
9309 #elif defined(_SILICON_LABS_32B_SERIES_0)
9310     case CMU_LFACLKSEL_REG:
9311     case CMU_LFBCLKSEL_REG:
9312       switch (ref) {
9313         case cmuSelect_Disabled:
9314           tmp = _CMU_LFCLKSEL_LFA_DISABLED;
9315           break;
9316 
9317         case cmuSelect_LFXO:
9318           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9319           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9320           tmp = _CMU_LFCLKSEL_LFA_LFXO;
9321           break;
9322 
9323         case cmuSelect_LFRCO:
9324           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9325           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9326           tmp = _CMU_LFCLKSEL_LFA_LFRCO;
9327           break;
9328 
9329         case cmuSelect_HFCLKLE:
9330 #if defined(CMU_MAX_FREQ_HFLE)
9331           /* Set the HFLE wait-state and divider. */
9332           freq = SystemCoreClockGet();
9333           setHfLeConfig(freq);
9334 #endif
9335           /* Ensure HFCORE to LE clocking is enabled. */
9336           BUS_RegBitWrite(&CMU->HFCORECLKEN0, _CMU_HFCORECLKEN0_LE_SHIFT, 1);
9337           tmp = _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2;
9338           break;
9339 
9340 #if defined(CMU_LFCLKSEL_LFAE_ULFRCO)
9341         case cmuSelect_ULFRCO:
9342           /* ULFRCO is always enabled. */
9343           tmp = _CMU_LFCLKSEL_LFA_DISABLED;
9344           lfExtended = 1;
9345           break;
9346 #endif
9347 
9348         default:
9349           /* An illegal clock source for LFA/LFB selected. */
9350           EFM_ASSERT(false);
9351           return;
9352       }
9353 
9354       /* Apply select. */
9355       if (selRegId == CMU_LFACLKSEL_REG) {
9356 #if defined(_CMU_LFCLKSEL_LFAE_MASK)
9357         CMU->LFCLKSEL = (CMU->LFCLKSEL
9358                          & ~(_CMU_LFCLKSEL_LFA_MASK | _CMU_LFCLKSEL_LFAE_MASK))
9359                         | (tmp << _CMU_LFCLKSEL_LFA_SHIFT)
9360                         | (lfExtended << _CMU_LFCLKSEL_LFAE_SHIFT);
9361 #else
9362         CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFA_MASK)
9363                         | (tmp << _CMU_LFCLKSEL_LFA_SHIFT);
9364 #endif
9365       } else {
9366 #if defined(_CMU_LFCLKSEL_LFBE_MASK)
9367         CMU->LFCLKSEL = (CMU->LFCLKSEL
9368                          & ~(_CMU_LFCLKSEL_LFB_MASK | _CMU_LFCLKSEL_LFBE_MASK))
9369                         | (tmp << _CMU_LFCLKSEL_LFB_SHIFT)
9370                         | (lfExtended << _CMU_LFCLKSEL_LFBE_SHIFT);
9371 #else
9372         CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFB_MASK)
9373                         | (tmp << _CMU_LFCLKSEL_LFB_SHIFT);
9374 #endif
9375       }
9376       break;
9377 
9378 #if defined(_CMU_LFCLKSEL_LFC_MASK)
9379     case CMU_LFCCLKSEL_REG:
9380       switch (ref) {
9381         case cmuSelect_Disabled:
9382           tmp = _CMU_LFCLKSEL_LFA_DISABLED;
9383           break;
9384 
9385         case cmuSelect_LFXO:
9386           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9387           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9388           tmp = _CMU_LFCLKSEL_LFC_LFXO;
9389           break;
9390 
9391         case cmuSelect_LFRCO:
9392           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9393           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9394           tmp = _CMU_LFCLKSEL_LFC_LFRCO;
9395           break;
9396 
9397         default:
9398           /* An illegal clock source for LFC selected. */
9399           EFM_ASSERT(false);
9400           return;
9401       }
9402 
9403       /* Apply select. */
9404       CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFC_MASK)
9405                       | (tmp << _CMU_LFCLKSEL_LFC_SHIFT);
9406       break;
9407 #endif
9408 #endif
9409 
9410 #if defined(_CMU_DBGCLKSEL_DBG_MASK) || defined(CMU_CTRL_DBGCLK)
9411     case CMU_DBGCLKSEL_REG:
9412       switch (ref) {
9413 #if defined(_CMU_DBGCLKSEL_DBG_MASK)
9414         case cmuSelect_AUXHFRCO:
9415           /* Select AUXHFRCO as a debug clock. */
9416           CMU->DBGCLKSEL = CMU_DBGCLKSEL_DBG_AUXHFRCO;
9417           break;
9418 
9419         case cmuSelect_HFCLK:
9420           /* Select divided HFCLK as a debug clock. */
9421           CMU->DBGCLKSEL = CMU_DBGCLKSEL_DBG_HFCLK;
9422           break;
9423 #endif
9424 
9425 #if defined(CMU_CTRL_DBGCLK)
9426         case cmuSelect_AUXHFRCO:
9427           /* Select AUXHFRCO as a debug clock. */
9428           CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_DBGCLK_MASK))
9429                       | CMU_CTRL_DBGCLK_AUXHFRCO;
9430           break;
9431 
9432         case cmuSelect_HFCLK:
9433           /* Select divided HFCLK as a debug clock. */
9434           CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_DBGCLK_MASK))
9435                       | CMU_CTRL_DBGCLK_HFCLK;
9436           break;
9437 #endif
9438 
9439         default:
9440           /* An illegal clock source for debug selected. */
9441           EFM_ASSERT(false);
9442           return;
9443       }
9444       break;
9445 #endif
9446 
9447 #if defined(USBC_CLOCK_PRESENT)
9448     case CMU_USBCCLKSEL_REG:
9449       switch (ref) {
9450         case cmuSelect_LFXO:
9451           /* Select LFXO as a clock source for USB. It can only be used in sleep mode. */
9452           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9453           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9454 
9455           /* Switch the oscillator. */
9456           CMU->CMD = CMU_CMD_USBCCLKSEL_LFXO;
9457 
9458           /* Wait until the clock is activated. */
9459           while ((CMU->STATUS & CMU_STATUS_USBCLFXOSEL) == 0) {
9460           }
9461           break;
9462 
9463         case cmuSelect_LFRCO:
9464           /* Select LFRCO as a clock source for USB. It can only be used in sleep mode. */
9465           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9466           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9467 
9468           /* Switch the oscillator. */
9469           CMU->CMD = CMU_CMD_USBCCLKSEL_LFRCO;
9470 
9471           /* Wait until the clock is activated. */
9472           while ((CMU->STATUS & CMU_STATUS_USBCLFRCOSEL) == 0) {
9473           }
9474           break;
9475 
9476 #if defined(CMU_STATUS_USBCHFCLKSEL)
9477         case cmuSelect_HFCLK:
9478           /* Select undivided HFCLK as a clock source for USB. */
9479           /* The oscillator must already be enabled to avoid a core lockup. */
9480           CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
9481           /* Wait until the clock is activated. */
9482           while ((CMU->STATUS & CMU_STATUS_USBCHFCLKSEL) == 0) {
9483           }
9484           break;
9485 #endif
9486 
9487 #if defined(CMU_CMD_USBCCLKSEL_USHFRCO)
9488         case cmuSelect_USHFRCO:
9489           /* Select USHFRCO as a clock source for USB. */
9490           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9491           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
9492 
9493           /* Switch the oscillator. */
9494           CMU->CMD = CMU_CMD_USBCCLKSEL_USHFRCO;
9495 
9496           /* Wait until the clock is activated. */
9497           while ((CMU->STATUS & CMU_STATUS_USBCUSHFRCOSEL) == 0) {
9498           }
9499           break;
9500 #endif
9501 
9502         default:
9503           /* An illegal clock source for USB. */
9504           EFM_ASSERT(false);
9505           return;
9506       }
9507       break;
9508 #endif
9509 
9510 #if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
9511     case CMU_ADC0ASYNCSEL_REG:
9512       switch (ref) {
9513         case cmuSelect_Disabled:
9514           tmp = _CMU_ADCCTRL_ADC0CLKSEL_DISABLED;
9515           break;
9516 
9517         case cmuSelect_AUXHFRCO:
9518           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9519           CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
9520           tmp = _CMU_ADCCTRL_ADC0CLKSEL_AUXHFRCO;
9521           break;
9522 
9523         case cmuSelect_HFXO:
9524           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9525           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9526           tmp = _CMU_ADCCTRL_ADC0CLKSEL_HFXO;
9527           break;
9528 
9529         case cmuSelect_HFSRCCLK:
9530           tmp = _CMU_ADCCTRL_ADC0CLKSEL_HFSRCCLK;
9531           break;
9532 
9533         default:
9534           /* An illegal clock source for ADC0ASYNC selected. */
9535           EFM_ASSERT(false);
9536           return;
9537       }
9538 
9539       /* Apply select. */
9540       CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC0CLKSEL_MASK)
9541                      | (tmp << _CMU_ADCCTRL_ADC0CLKSEL_SHIFT);
9542       break;
9543 #endif
9544 
9545 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
9546     case CMU_ADC1ASYNCSEL_REG:
9547       switch (ref) {
9548         case cmuSelect_Disabled:
9549           tmp = _CMU_ADCCTRL_ADC1CLKSEL_DISABLED;
9550           break;
9551 
9552         case cmuSelect_AUXHFRCO:
9553           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9554           CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
9555           tmp = _CMU_ADCCTRL_ADC1CLKSEL_AUXHFRCO;
9556           break;
9557 
9558         case cmuSelect_HFXO:
9559           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9560           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9561           tmp = _CMU_ADCCTRL_ADC1CLKSEL_HFXO;
9562           break;
9563 
9564         case cmuSelect_HFSRCCLK:
9565           tmp = _CMU_ADCCTRL_ADC1CLKSEL_HFSRCCLK;
9566           break;
9567 
9568         default:
9569           /* An illegal clock source for ADC1ASYNC selected. */
9570           EFM_ASSERT(false);
9571           return;
9572       }
9573 
9574       /* Apply select. */
9575       CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC1CLKSEL_MASK)
9576                      | (tmp << _CMU_ADCCTRL_ADC1CLKSEL_SHIFT);
9577       break;
9578 #endif
9579 
9580 #if defined(_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
9581     case CMU_SDIOREFSEL_REG:
9582       switch (ref) {
9583         case cmuSelect_HFRCO:
9584           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9585           CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
9586           tmp = _CMU_SDIOCTRL_SDIOCLKSEL_HFRCO;
9587           break;
9588 
9589         case cmuSelect_HFXO:
9590           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9591           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9592           tmp = _CMU_SDIOCTRL_SDIOCLKSEL_HFXO;
9593           break;
9594 
9595         case cmuSelect_AUXHFRCO:
9596           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9597           CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
9598           tmp = _CMU_SDIOCTRL_SDIOCLKSEL_AUXHFRCO;
9599           break;
9600 
9601         case cmuSelect_USHFRCO:
9602           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9603           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
9604           tmp = _CMU_SDIOCTRL_SDIOCLKSEL_USHFRCO;
9605           break;
9606 
9607         default:
9608           /* An illegal clock source for SDIOREF selected. */
9609           EFM_ASSERT(false);
9610           return;
9611       }
9612 
9613       /* Apply select. */
9614       CMU->SDIOCTRL = (CMU->SDIOCTRL & ~_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
9615                       | (tmp << _CMU_SDIOCTRL_SDIOCLKSEL_SHIFT);
9616       break;
9617 #endif
9618 
9619 #if defined(_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
9620     case CMU_QSPI0REFSEL_REG:
9621       switch (ref) {
9622         case cmuSelect_HFRCO:
9623           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9624           CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
9625           tmp = _CMU_QSPICTRL_QSPI0CLKSEL_HFRCO;
9626           break;
9627 
9628         case cmuSelect_HFXO:
9629           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9630           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9631           tmp = _CMU_QSPICTRL_QSPI0CLKSEL_HFXO;
9632           break;
9633 
9634         case cmuSelect_AUXHFRCO:
9635           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9636           CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
9637           tmp = _CMU_QSPICTRL_QSPI0CLKSEL_AUXHFRCO;
9638           break;
9639 
9640         case cmuSelect_USHFRCO:
9641           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9642           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
9643           tmp = _CMU_QSPICTRL_QSPI0CLKSEL_USHFRCO;
9644           break;
9645 
9646         default:
9647           /* An illegal clock source for QSPI0REF selected. */
9648           EFM_ASSERT(false);
9649           return;
9650       }
9651 
9652       /* Apply select. */
9653       CMU->QSPICTRL = (CMU->QSPICTRL & ~_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
9654                       | (tmp << _CMU_QSPICTRL_QSPI0CLKSEL_SHIFT);
9655       break;
9656 #endif
9657 
9658 #if defined(_CMU_USBCTRL_USBCLKSEL_MASK)
9659     case CMU_USBRCLKSEL_REG:
9660       switch (ref) {
9661         case cmuSelect_USHFRCO:
9662           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9663           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
9664           tmp = _CMU_USBCTRL_USBCLKSEL_USHFRCO;
9665           break;
9666 
9667         case cmuSelect_HFXO:
9668           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9669           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9670           tmp = _CMU_USBCTRL_USBCLKSEL_HFXO;
9671           break;
9672 
9673         case cmuSelect_HFXOX2:
9674           /* Only allowed for HFXO frequencies up to 25 MHz. */
9675           EFM_ASSERT(SystemHFXOClockGet() <= 25000000u);
9676 
9677           /* Enable HFXO X2. */
9678           CMU->HFXOCTRL |= CMU_HFXOCTRL_HFXOX2EN;
9679 
9680           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9681           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9682 
9683           tmp = _CMU_USBCTRL_USBCLKSEL_HFXOX2;
9684           break;
9685 
9686         case cmuSelect_HFRCO:
9687           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9688           CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
9689           tmp = _CMU_USBCTRL_USBCLKSEL_HFRCO;
9690           break;
9691 
9692         case cmuSelect_LFXO:
9693           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9694           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9695           tmp = _CMU_USBCTRL_USBCLKSEL_LFXO;
9696           break;
9697 
9698         case cmuSelect_LFRCO:
9699           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9700           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9701           tmp = _CMU_USBCTRL_USBCLKSEL_LFRCO;
9702           break;
9703 
9704         default:
9705           /* An illegal clock source for USBR selected. */
9706           EFM_ASSERT(false);
9707           return;
9708       }
9709 
9710       /* Apply select. */
9711       CMU->USBCTRL = (CMU->USBCTRL & ~_CMU_USBCTRL_USBCLKSEL_MASK)
9712                      | (tmp << _CMU_USBCTRL_USBCLKSEL_SHIFT);
9713       break;
9714 #endif
9715 
9716 #if defined(_CMU_PDMCTRL_PDMCLKSEL_MASK)
9717     case CMU_PDMREFSEL_REG:
9718       switch (ref) {
9719         case cmuSelect_USHFRCO:
9720           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9721           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
9722           tmp = _CMU_PDMCTRL_PDMCLKSEL_USHFRCO;
9723           break;
9724 
9725         case cmuSelect_HFXO:
9726           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9727           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9728           tmp = _CMU_PDMCTRL_PDMCLKSEL_HFXO;
9729           break;
9730 
9731         case cmuSelect_HFRCO:
9732           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9733           CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
9734           tmp = _CMU_PDMCTRL_PDMCLKSEL_HFRCO;
9735           break;
9736 
9737         default:
9738           /* An illegal clock source for PDMREF selected. */
9739           EFM_ASSERT(false);
9740           return;
9741       }
9742 
9743       /* Apply select. */
9744       CMU->PDMCTRL = (CMU->PDMCTRL & ~_CMU_PDMCTRL_PDMCLKSEL_MASK)
9745                      | (tmp << _CMU_PDMCTRL_PDMCLKSEL_SHIFT);
9746       break;
9747 #endif
9748 
9749     default:
9750       EFM_ASSERT(false);
9751       break;
9752   }
9753 }
9754 
9755 /***************************************************************************//**
9756  * @brief
9757  *   Gets the precision (in PPM) of the specified low frequency clock branch.
9758  *
9759  * @param[in] clock
9760  *   Clock branch.
9761  *
9762  * @return
9763  *   Precision, in PPM, of the specified clock branch.
9764  *
9765  * @note
9766  *   This function is only for internal usage.
9767  *
9768  * @note
9769  *   The current implementation of this function is used to determine if the
9770  *   clock has a precision <= 500 ppm or not (which is the minimum required
9771  *   for BLE). Future version of this function should provide more accurate
9772  *   precision numbers to allow for further optimizations from the stacks.
9773  ******************************************************************************/
CMU_LF_ClockPrecisionGet(CMU_Clock_TypeDef clock)9774 uint16_t CMU_LF_ClockPrecisionGet(CMU_Clock_TypeDef clock)
9775 {
9776   CMU_Select_TypeDef src = CMU_ClockSelectGet(clock);
9777   uint16_t precision;
9778 
9779   switch (src) {
9780     case cmuSelect_LFXO:
9781       precision = lfxo_precision;
9782       break;
9783 
9784 #if defined(_SILICON_LABS_32B_SERIES_1) && defined(PLFRCO_PRESENT)
9785     case cmuSelect_PLFRCO:
9786       precision = 500;
9787       break;
9788 #endif
9789 
9790     default:
9791       precision = 0xFFFF;
9792       break;
9793   }
9794 
9795   return precision;
9796 }
9797 
9798 #if defined(CMU_OSCENCMD_DPLLEN)
9799 /**************************************************************************//**
9800  * @brief
9801  *   Lock the DPLL to a given frequency.
9802  *
9803  *   The frequency is given by: Fout = Fref * (N+1) / (M+1).
9804  *
9805  * @note
9806  *   This function does not check if the given N & M values will actually
9807  *   produce the desired target frequency. @n
9808  *   N & M limitations: @n
9809  *     300 < N <= 4095 @n
9810  *     0 <= M <= 4095 @n
9811  *   Any peripheral running off HFRCO should be switched to HFRCODIV2 prior to
9812  *   calling this function to avoid over-clocking.
9813  *
9814  *   HFCLKLE prescaler is automatically modified before updating HFRCO
9815  *   based on the maximum HFLE frequency allowed.
9816  *
9817  * @param[in] init
9818  *    DPLL setup parameters.
9819  *
9820  * @return
9821  *   Returns false on invalid target frequency or DPLL locking error.
9822  *****************************************************************************/
CMU_DPLLLock(const CMU_DPLLInit_TypeDef * init)9823 bool CMU_DPLLLock(const CMU_DPLLInit_TypeDef *init)
9824 {
9825   int index = 0;
9826   unsigned int i;
9827   bool hfrcoDiv2override = false;
9828   uint32_t hfrcoCtrlVal, lockStatus, sysFreq;
9829 
9830   EFM_ASSERT(init->frequency >= hfrcoCtrlTable[0].minFreq);
9831   EFM_ASSERT(init->frequency
9832              <= hfrcoCtrlTable[HFRCOCTRLTABLE_ENTRIES - 1U].maxFreq);
9833   EFM_ASSERT(init->n > 300U);
9834   EFM_ASSERT(init->n <= (_CMU_DPLLCTRL1_N_MASK >> _CMU_DPLLCTRL1_N_SHIFT));
9835   EFM_ASSERT(init->m <= (_CMU_DPLLCTRL1_M_MASK >> _CMU_DPLLCTRL1_M_SHIFT));
9836   EFM_ASSERT(init->ssInterval  <= (_CMU_HFRCOSS_SSINV_MASK
9837                                    >> _CMU_HFRCOSS_SSINV_SHIFT));
9838   EFM_ASSERT(init->ssAmplitude <= (_CMU_HFRCOSS_SSAMP_MASK
9839                                    >> _CMU_HFRCOSS_SSAMP_SHIFT));
9840 
9841 #if defined(_EMU_STATUS_VSCALE_MASK)
9842   if ((EMU_VScaleGet() == emuVScaleEM01_LowPower)
9843       && (init->frequency > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
9844     EFM_ASSERT(false);
9845     return false;
9846   }
9847 #endif
9848 
9849   // Find the correct HFRCO band and retrieve a HFRCOCTRL value.
9850   for (i = 0; i < HFRCOCTRLTABLE_ENTRIES; i++) {
9851     if ((init->frequency    >= hfrcoCtrlTable[i].minFreq)
9852         && (init->frequency <= hfrcoCtrlTable[i].maxFreq)) {
9853       index = (int)i;                       // Correct band found
9854       break;
9855     }
9856   }
9857   if ((uint32_t)index == HFRCOCTRLTABLE_ENTRIES) {
9858     EFM_ASSERT(false);
9859     return false;                           // Target frequency out of spec.
9860   }
9861   hfrcoCtrlVal = hfrcoCtrlTable[index].value;
9862 
9863   // Check if a calibrated HFRCOCTRL.TUNING value is in device DI page.
9864   if (hfrcoCtrlTable[index].band != (CMU_HFRCOFreq_TypeDef)0) {
9865     uint32_t tuning;
9866 
9867     tuning = (CMU_HFRCODevinfoGet(hfrcoCtrlTable[index].band)
9868               & _CMU_HFRCOCTRL_TUNING_MASK)
9869              >> _CMU_HFRCOCTRL_TUNING_SHIFT;
9870 
9871     // When HFRCOCTRL.FINETUNINGEN is enabled, the center frequency
9872     // of the band shifts down by 5.8%. 9 is subtracted to compensate.
9873     if (tuning > 9UL) {
9874       tuning -= 9UL;
9875     } else {
9876       tuning = 0UL;
9877     }
9878 
9879     hfrcoCtrlVal |= tuning << _CMU_HFRCOCTRL_TUNING_SHIFT;
9880   }
9881 
9882   // Update the CMSIS frequency SystemHfrcoFreq value.
9883   SystemHfrcoFreq = init->frequency;
9884 
9885   // Set maximum wait-states while changing the core clock.
9886   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
9887     flashWaitStateMax();
9888   }
9889 
9890   // Update the HFLE configuration before updating HFRCO, use new DPLL frequency.
9891   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
9892     setHfLeConfig(init->frequency);
9893 
9894     // Switch to HFRCO/2 before setting DPLL to avoid over-clocking.
9895     hfrcoDiv2override = true;
9896     CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCODIV2;
9897   }
9898 
9899   CMU->OSCENCMD  = CMU_OSCENCMD_DPLLDIS;
9900   while ((CMU->STATUS & (CMU_STATUS_DPLLENS | CMU_STATUS_DPLLRDY)) != 0UL) {
9901   }
9902   CMU->IFC       = CMU_IFC_DPLLRDY | CMU_IFC_DPLLLOCKFAILLOW
9903                    | CMU_IFC_DPLLLOCKFAILHIGH;
9904   CMU->DPLLCTRL1 = ((uint32_t)init->n   << _CMU_DPLLCTRL1_N_SHIFT)
9905                    | ((uint32_t)init->m << _CMU_DPLLCTRL1_M_SHIFT);
9906   CMU->HFRCOCTRL = hfrcoCtrlVal;
9907   CMU->DPLLCTRL  = ((uint32_t)init->refClk << _CMU_DPLLCTRL_REFSEL_SHIFT)
9908                    | ((init->autoRecover ? 1UL : 0UL)
9909                       << _CMU_DPLLCTRL_AUTORECOVER_SHIFT)
9910                    | ((uint32_t)init->edgeSel << _CMU_DPLLCTRL_EDGESEL_SHIFT)
9911                    | ((uint32_t)init->lockMode << _CMU_DPLLCTRL_MODE_SHIFT);
9912   CMU->OSCENCMD  = CMU_OSCENCMD_DPLLEN;
9913   while ((lockStatus = (CMU->IF & (CMU_IF_DPLLRDY
9914                                    | CMU_IF_DPLLLOCKFAILLOW
9915                                    | CMU_IF_DPLLLOCKFAILHIGH))) == 0UL) {
9916   }
9917 
9918   // Restore to HFRCO
9919   if ((CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCODIV2)
9920       && (hfrcoDiv2override == true)) {
9921     CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCO;
9922   }
9923 
9924   // If HFRCO is selected as an HF clock, optimize the flash access wait-state
9925   // configuration for this frequency and update the CMSIS core clock variable.
9926   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
9927     // Call @ref SystemCoreClockGet() to update the CMSIS core clock variable.
9928     sysFreq = SystemCoreClockGet();
9929     EFM_ASSERT(sysFreq <= init->frequency);
9930     EFM_ASSERT(sysFreq <= SystemHfrcoFreq);
9931     EFM_ASSERT(init->frequency == SystemHfrcoFreq);
9932     CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
9933   }
9934 
9935   // Reduce HFLE frequency if possible.
9936   setHfLeConfig(SystemHFClockGet());
9937 
9938 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9939   // Update voltage scaling.
9940   EMU_VScaleEM01ByClock(0, true);
9941 #endif
9942 
9943   if (lockStatus == CMU_IF_DPLLRDY) {
9944     return true;
9945   }
9946   return false;
9947 }
9948 #endif // CMU_OSCENCMD_DPLLEN
9949 
9950 /**************************************************************************//**
9951  * @brief
9952  *   CMU low frequency register synchronization freeze control.
9953  *
9954  * @details
9955  *   Some CMU registers require synchronization into the low-frequency (LF)
9956  *   domain. The freeze feature allows for several such registers to be
9957  *   modified before passing them to the LF domain simultaneously (which
9958  *   takes place when the freeze mode is disabled).
9959  *
9960  *   Another use case for this feature is using an API (such
9961  *   as the CMU API) for modifying several bit fields consecutively in the
9962  *   same register. If freeze mode is enabled during this sequence, stalling
9963  *   can be avoided.
9964  *
9965  * @note
9966  *   When enabling freeze mode, this function will wait for all current
9967  *   ongoing CMU synchronization to LF domain to complete (normally
9968  *   synchronization will not be in progress.) However, for this reason, when
9969  *   using freeze mode, modifications of registers requiring LF synchronization
9970  *   should be done within one freeze enable/disable block to avoid unnecessary
9971  *   stalling.
9972  *
9973  * @param[in] enable
9974  *   @li true - enable freeze, modified registers are not propagated to the
9975  *       LF domain
9976  *   @li false - disable freeze, modified registers are propagated to the LF
9977  *       domain
9978  *****************************************************************************/
CMU_FreezeEnable(bool enable)9979 void CMU_FreezeEnable(bool enable)
9980 {
9981   if (enable) {
9982     /* Wait for any ongoing LF synchronizations to complete. This */
9983     /* protects against the rare case when a user                            */
9984     /* - modifies a register requiring LF sync                              */
9985     /* - then enables freeze before LF sync completed                       */
9986     /* - then modifies the same register again                              */
9987     /* since modifying a register while it is in sync progress should be    */
9988     /* avoided.                                                             */
9989     while (CMU->SYNCBUSY != 0UL) {
9990     }
9991 
9992     CMU->FREEZE = CMU_FREEZE_REGFREEZE;
9993   } else {
9994     CMU->FREEZE = 0;
9995   }
9996 }
9997 
9998 #if defined(_CMU_HFRCOCTRL_BAND_MASK)
9999 /***************************************************************************//**
10000  * @brief
10001  *   Get HFRCO band in use.
10002  *
10003  * @return
10004  *   HFRCO band in use.
10005  ******************************************************************************/
CMU_HFRCOBandGet(void)10006 CMU_HFRCOBand_TypeDef CMU_HFRCOBandGet(void)
10007 {
10008   return (CMU_HFRCOBand_TypeDef)((CMU->HFRCOCTRL & _CMU_HFRCOCTRL_BAND_MASK)
10009                                  >> _CMU_HFRCOCTRL_BAND_SHIFT);
10010 }
10011 #endif /* _CMU_HFRCOCTRL_BAND_MASK */
10012 
10013 #if defined(_CMU_HFRCOCTRL_BAND_MASK)
10014 /***************************************************************************//**
10015  * @brief
10016  *   Set HFRCO band and the tuning value based on the value in the calibration
10017  *   table made during production.
10018  *
10019  * @note
10020  *   HFCLKLE prescaler is automatically modified based on the maximum
10021  *   HFLE frequency allowed.
10022  *
10023  * @param[in] band
10024  *   HFRCO band to activate.
10025  ******************************************************************************/
CMU_HFRCOBandSet(CMU_HFRCOBand_TypeDef band)10026 void CMU_HFRCOBandSet(CMU_HFRCOBand_TypeDef band)
10027 {
10028   uint32_t           tuning;
10029   uint32_t           freq;
10030   CMU_Select_TypeDef osc;
10031 
10032   /* Read the tuning value from the calibration table. */
10033   switch (band) {
10034     case cmuHFRCOBand_1MHz:
10035       tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND1_MASK)
10036                >> _DEVINFO_HFRCOCAL0_BAND1_SHIFT;
10037       break;
10038 
10039     case cmuHFRCOBand_7MHz:
10040       tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND7_MASK)
10041                >> _DEVINFO_HFRCOCAL0_BAND7_SHIFT;
10042       break;
10043 
10044     case cmuHFRCOBand_11MHz:
10045       tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND11_MASK)
10046                >> _DEVINFO_HFRCOCAL0_BAND11_SHIFT;
10047       break;
10048 
10049     case cmuHFRCOBand_14MHz:
10050       tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND14_MASK)
10051                >> _DEVINFO_HFRCOCAL0_BAND14_SHIFT;
10052       break;
10053 
10054     case cmuHFRCOBand_21MHz:
10055       tuning = (DEVINFO->HFRCOCAL1 & _DEVINFO_HFRCOCAL1_BAND21_MASK)
10056                >> _DEVINFO_HFRCOCAL1_BAND21_SHIFT;
10057       break;
10058 
10059 #if defined(_CMU_HFRCOCTRL_BAND_28MHZ)
10060     case cmuHFRCOBand_28MHz:
10061       tuning = (DEVINFO->HFRCOCAL1 & _DEVINFO_HFRCOCAL1_BAND28_MASK)
10062                >> _DEVINFO_HFRCOCAL1_BAND28_SHIFT;
10063       break;
10064 #endif
10065 
10066     default:
10067       EFM_ASSERT(false);
10068       return;
10069   }
10070 
10071   /* If HFRCO is used for the core clock, flash access WS has to be considered. */
10072   osc = CMU_ClockSelectGet(cmuClock_HF);
10073   if (osc == cmuSelect_HFRCO) {
10074     /* Configure worst case wait states for flash access before setting the divider. */
10075     flashWaitStateMax();
10076   }
10077 
10078   /* Set band/tuning. */
10079   CMU->HFRCOCTRL = (CMU->HFRCOCTRL
10080                     & ~(_CMU_HFRCOCTRL_BAND_MASK | _CMU_HFRCOCTRL_TUNING_MASK))
10081                    | (band << _CMU_HFRCOCTRL_BAND_SHIFT)
10082                    | (tuning << _CMU_HFRCOCTRL_TUNING_SHIFT);
10083 
10084   /* If HFRCO is used for the core clock, optimize flash WS. */
10085   if (osc == cmuSelect_HFRCO) {
10086     /* Call @ref SystemCoreClockGet() to update the CMSIS core clock variable. */
10087     freq = SystemCoreClockGet();
10088     CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
10089   }
10090 
10091 #if defined(CMU_MAX_FREQ_HFLE)
10092   /* Reduce HFLE frequency if possible. */
10093   setHfLeConfig(SystemCoreClockGet());
10094 #endif
10095 }
10096 #endif /* _CMU_HFRCOCTRL_BAND_MASK */
10097 
10098 #if defined(_CMU_HFRCOCTRL_FREQRANGE_MASK)
10099 /**************************************************************************//**
10100  * @brief
10101  *   Get the HFRCO frequency calibration word in DEVINFO.
10102  *
10103  * @param[in] freq
10104  *   Frequency in Hz.
10105  *
10106  * @return
10107  *   HFRCO calibration word for a given frequency.
10108  *****************************************************************************/
CMU_HFRCODevinfoGet(CMU_HFRCOFreq_TypeDef freq)10109 static uint32_t CMU_HFRCODevinfoGet(CMU_HFRCOFreq_TypeDef freq)
10110 {
10111   switch (freq) {
10112     /* 1, 2, and 4 MHz share the same calibration word. */
10113     case cmuHFRCOFreq_1M0Hz:
10114     case cmuHFRCOFreq_2M0Hz:
10115     case cmuHFRCOFreq_4M0Hz:
10116       return DEVINFO->HFRCOCAL0;
10117 
10118     case cmuHFRCOFreq_7M0Hz:
10119       return DEVINFO->HFRCOCAL3;
10120 
10121     case cmuHFRCOFreq_13M0Hz:
10122       return DEVINFO->HFRCOCAL6;
10123 
10124     case cmuHFRCOFreq_16M0Hz:
10125       return DEVINFO->HFRCOCAL7;
10126 
10127     case cmuHFRCOFreq_19M0Hz:
10128       return DEVINFO->HFRCOCAL8;
10129 
10130     case cmuHFRCOFreq_26M0Hz:
10131       return DEVINFO->HFRCOCAL10;
10132 
10133     case cmuHFRCOFreq_32M0Hz:
10134       return DEVINFO->HFRCOCAL11;
10135 
10136     case cmuHFRCOFreq_38M0Hz:
10137       return DEVINFO->HFRCOCAL12;
10138 
10139 #if defined(_DEVINFO_HFRCOCAL13_MASK)
10140     case cmuHFRCOFreq_48M0Hz:
10141       return DEVINFO->HFRCOCAL13;
10142 #endif
10143 
10144 #if defined(_DEVINFO_HFRCOCAL14_MASK)
10145     case cmuHFRCOFreq_56M0Hz:
10146       return DEVINFO->HFRCOCAL14;
10147 #endif
10148 
10149 #if defined(_DEVINFO_HFRCOCAL15_MASK)
10150     case cmuHFRCOFreq_64M0Hz:
10151       return DEVINFO->HFRCOCAL15;
10152 #endif
10153 
10154 #if defined(_DEVINFO_HFRCOCAL16_MASK)
10155     case cmuHFRCOFreq_72M0Hz:
10156       return DEVINFO->HFRCOCAL16;
10157 #endif
10158 
10159     default: /* cmuHFRCOFreq_UserDefined */
10160       return 0;
10161   }
10162 }
10163 
10164 /***************************************************************************//**
10165  * @brief
10166  *   Get the current HFRCO frequency.
10167  *
10168  * @return
10169  *   HFRCO frequency.
10170  ******************************************************************************/
CMU_HFRCOBandGet(void)10171 CMU_HFRCOFreq_TypeDef CMU_HFRCOBandGet(void)
10172 {
10173   return (CMU_HFRCOFreq_TypeDef)SystemHfrcoFreq;
10174 }
10175 
10176 /***************************************************************************//**
10177  * @brief
10178  *   Set the HFRCO calibration for the selected target frequency.
10179  *
10180  * @note
10181  *   HFCLKLE prescaler is automatically modified based on the maximum
10182  *   HFLE frequency allowed.
10183  *
10184  * @param[in] setFreq
10185  *   HFRCO frequency to set.
10186  ******************************************************************************/
CMU_HFRCOBandSet(CMU_HFRCOFreq_TypeDef setFreq)10187 void CMU_HFRCOBandSet(CMU_HFRCOFreq_TypeDef setFreq)
10188 {
10189   uint32_t freqCal;
10190   uint32_t sysFreq;
10191   uint32_t prevFreq;
10192 
10193   /* Get the DEVINFO index and set the CMSIS frequency SystemHfrcoFreq. */
10194   freqCal = CMU_HFRCODevinfoGet(setFreq);
10195   EFM_ASSERT((freqCal != 0UL) && (freqCal != UINT_MAX));
10196   prevFreq = SystemHfrcoFreq;
10197   SystemHfrcoFreq = (uint32_t)setFreq;
10198 
10199   /* Set maximum wait-states and set safe HFPER clock-tree prescalers while
10200      changing the core clock. */
10201   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10202     flashWaitStateMax();
10203     hfperClkSafePrescaler();
10204   }
10205 
10206   /* Wait for any previous sync to complete and set calibration data
10207      for the selected frequency.  */
10208   while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_HFRCOBSY_SHIFT) != 0UL) {
10209   }
10210 
10211   /* Check for valid calibration data. */
10212   EFM_ASSERT(freqCal != UINT_MAX);
10213 
10214   /* Set divider in HFRCOCTRL for 1, 2, and 4 MHz. */
10215   switch (setFreq) {
10216     case cmuHFRCOFreq_1M0Hz:
10217       freqCal = (freqCal & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
10218                 | CMU_HFRCOCTRL_CLKDIV_DIV4;
10219       break;
10220 
10221     case cmuHFRCOFreq_2M0Hz:
10222       freqCal = (freqCal & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
10223                 | CMU_HFRCOCTRL_CLKDIV_DIV2;
10224       break;
10225 
10226     case cmuHFRCOFreq_4M0Hz:
10227       freqCal = (freqCal & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
10228                 | CMU_HFRCOCTRL_CLKDIV_DIV1;
10229       break;
10230 
10231     default:
10232       break;
10233   }
10234 
10235   /* Update HFLE configuration before updating HFRCO.
10236      Use the new set frequency. */
10237   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10238     /* setFreq is worst-case as dividers may reduce the HFLE frequency. */
10239     setHfLeConfig((uint32_t)setFreq);
10240   }
10241 
10242   if ((uint32_t)setFreq > prevFreq) {
10243 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
10244     /* When increasing frequency voltage scale must be done before the change. */
10245     EMU_VScaleEM01ByClock((uint32_t)setFreq, true);
10246 #endif
10247   }
10248 
10249   CMU->HFRCOCTRL = freqCal;
10250 
10251   /* If HFRCO is selected as an HF clock, optimize the flash access wait-state configuration
10252      for this frequency and update the CMSIS core clock variable. */
10253   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10254     /* Call @ref SystemCoreClockGet() to update the CMSIS core clock variable. */
10255     sysFreq = SystemCoreClockGet();
10256     EFM_ASSERT(sysFreq <= (uint32_t)setFreq);
10257     EFM_ASSERT(sysFreq <= SystemHfrcoFreq);
10258     EFM_ASSERT((uint32_t)setFreq == SystemHfrcoFreq);
10259     CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
10260   }
10261 
10262   /* Reduce HFLE frequency if possible. */
10263   setHfLeConfig(SystemHFClockGet());
10264 
10265   if ((uint32_t)setFreq <= prevFreq) {
10266 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
10267     /* When decreasing frequency voltage scale must be done after the change */
10268     EMU_VScaleEM01ByClock(0, true);
10269 #endif
10270   }
10271   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10272     /* Set optimized HFPER clock-tree prescalers. */
10273     hfperClkOptimizedPrescaler();
10274   }
10275 }
10276 #endif /* _CMU_HFRCOCTRL_FREQRANGE_MASK */
10277 
10278 #if defined(_CMU_HFRCOCTRL_SUDELAY_MASK)
10279 /***************************************************************************//**
10280  * @brief
10281  *   Get the HFRCO startup delay.
10282  *
10283  * @details
10284  *   See the reference manual for more details.
10285  *
10286  * @return
10287  *   The startup delay in use.
10288  ******************************************************************************/
CMU_HFRCOStartupDelayGet(void)10289 uint32_t CMU_HFRCOStartupDelayGet(void)
10290 {
10291   return (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_SUDELAY_MASK)
10292          >> _CMU_HFRCOCTRL_SUDELAY_SHIFT;
10293 }
10294 
10295 /***************************************************************************//**
10296  * @brief
10297  *   Set the HFRCO startup delay.
10298  *
10299  * @details
10300  *   See the reference manual for more details.
10301  *
10302  * @param[in] delay
10303  *   The startup delay to set (<= 31).
10304  ******************************************************************************/
CMU_HFRCOStartupDelaySet(uint32_t delay)10305 void CMU_HFRCOStartupDelaySet(uint32_t delay)
10306 {
10307   EFM_ASSERT(delay <= 31);
10308 
10309   delay &= _CMU_HFRCOCTRL_SUDELAY_MASK >> _CMU_HFRCOCTRL_SUDELAY_SHIFT;
10310   CMU->HFRCOCTRL = (CMU->HFRCOCTRL & ~(_CMU_HFRCOCTRL_SUDELAY_MASK))
10311                    | (delay << _CMU_HFRCOCTRL_SUDELAY_SHIFT);
10312 }
10313 #endif
10314 
10315 #if defined(_CMU_USHFRCOCTRL_FREQRANGE_MASK)
10316 /**************************************************************************//**
10317  * @brief
10318  *   Get the USHFRCO frequency calibration word in DEVINFO.
10319  *
10320  * @param[in] freq
10321  *   Frequency in Hz.
10322  *
10323  * @return
10324  *   USHFRCO calibration word for a given frequency.
10325  *****************************************************************************/
CMU_USHFRCODevinfoGet(CMU_USHFRCOFreq_TypeDef freq)10326 static uint32_t CMU_USHFRCODevinfoGet(CMU_USHFRCOFreq_TypeDef freq)
10327 {
10328   switch (freq) {
10329     case cmuUSHFRCOFreq_16M0Hz:
10330       return DEVINFO->USHFRCOCAL7;
10331 
10332     case cmuUSHFRCOFreq_32M0Hz:
10333       return DEVINFO->USHFRCOCAL11;
10334 
10335     case cmuUSHFRCOFreq_48M0Hz:
10336       return DEVINFO->USHFRCOCAL13;
10337 
10338     case cmuUSHFRCOFreq_50M0Hz:
10339       return DEVINFO->USHFRCOCAL14;
10340 
10341     default: /* cmuUSHFRCOFreq_UserDefined */
10342       return 0;
10343   }
10344 }
10345 
10346 /***************************************************************************//**
10347  * @brief
10348  *   Get the current USHFRCO frequency.
10349  *
10350  * @return
10351  *   HFRCO frequency.
10352  ******************************************************************************/
CMU_USHFRCOBandGet(void)10353 CMU_USHFRCOFreq_TypeDef CMU_USHFRCOBandGet(void)
10354 {
10355   return (CMU_USHFRCOFreq_TypeDef) ushfrcoFreq;
10356 }
10357 
10358 /***************************************************************************//**
10359  * @brief
10360  *   Get USHFRCO frequency.
10361  *
10362  * @return
10363  *   USHFRCO frequency.
10364  ******************************************************************************/
CMU_USHFRCOFreqGet(void)10365 uint32_t CMU_USHFRCOFreqGet(void)
10366 {
10367   return ushfrcoFreq;
10368 }
10369 
10370 /***************************************************************************//**
10371  * @brief
10372  *   Set the USHFRCO calibration for the selected target frequency.
10373  *
10374  * @param[in] setFreq
10375  *   USHFRCO frequency to set.
10376  ******************************************************************************/
CMU_USHFRCOBandSet(CMU_USHFRCOFreq_TypeDef setFreq)10377 void CMU_USHFRCOBandSet(CMU_USHFRCOFreq_TypeDef setFreq)
10378 {
10379   uint32_t freqCal;
10380 
10381   /* Get DEVINFO calibration values. */
10382   freqCal = CMU_USHFRCODevinfoGet(setFreq);
10383   EFM_ASSERT((freqCal != 0) && (freqCal != UINT_MAX));
10384   ushfrcoFreq = (uint32_t)setFreq;
10385 
10386   /* Wait for any previous sync to complete and set calibration data
10387      for the selected frequency.  */
10388   while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_USHFRCOBSY_SHIFT)) ;
10389 
10390   CMU->USHFRCOCTRL = freqCal;
10391 }
10392 #endif /* _CMU_USHFRCOCTRL_FREQRANGE_MASK  */
10393 
10394 #if defined(_CMU_HFXOCTRL_AUTOSTARTEM0EM1_MASK)
10395 /***************************************************************************//**
10396  * @brief
10397  *   Enable or disable HFXO autostart.
10398  *
10399  * @param[in] userSel
10400  *   Additional user specified enable bit.
10401  *
10402  * @param[in] enEM0EM1Start
10403  *   If true, HFXO is automatically started upon entering EM0/EM1 entry from
10404  *   EM2/EM3. HFXO selection has to be handled by the user.
10405  *   If false, HFXO is not started automatically when entering EM0/EM1.
10406  *
10407  * @param[in] enEM0EM1StartSel
10408  *   If true, HFXO is automatically started and immediately selected upon
10409  *   entering EM0/EM1 entry from EM2/EM3. Note that this option stalls the use of
10410  *   HFSRCCLK until HFXO becomes ready. HFCLKLE prescaler is also automatically
10411  *   modified if userSel is specified.
10412  *   If false, HFXO is not started or selected automatically when entering
10413  *   EM0/EM1.
10414  ******************************************************************************/
CMU_HFXOAutostartEnable(uint32_t userSel,bool enEM0EM1Start,bool enEM0EM1StartSel)10415 void CMU_HFXOAutostartEnable(uint32_t userSel,
10416                              bool enEM0EM1Start,
10417                              bool enEM0EM1StartSel)
10418 {
10419   uint32_t hfxoFreq;
10420   uint32_t hfxoCtrl;
10421 
10422 #if defined(_EMU_CTRL_EM23VSCALE_MASK)
10423   if (enEM0EM1StartSel) {
10424     /* Voltage scaling is not compatible with HFXO auto start and select. */
10425     EFM_ASSERT((EMU->CTRL & _EMU_CTRL_EM23VSCALE_MASK) == EMU_CTRL_EM23VSCALE_VSCALE2);
10426   }
10427 #endif
10428 
10429   /* Mask supported enable bits. */
10430 #if defined(_CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK)
10431   userSel &= _CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK;
10432 #else
10433   userSel = 0;
10434 #endif
10435 
10436   hfxoFreq = SystemHFXOClockGet();
10437 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
10438   // Update voltage scaling.
10439   EMU_VScaleEM01ByClock(hfxoFreq, true);
10440 #endif
10441   /* Set wait-states for HFXO if automatic start and select is configured. */
10442   if ((userSel > 0UL) || enEM0EM1StartSel) {
10443     CMU_UpdateWaitStates(hfxoFreq, VSCALE_DEFAULT);
10444     setHfLeConfig(hfxoFreq / CMU_ClockDivGet(cmuClock_HF));
10445   }
10446 
10447   if (enEM0EM1Start || enEM0EM1StartSel) {
10448     /* Enable the HFXO once in order to finish first time calibrations. */
10449     CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
10450   }
10451 
10452   /* Since call to CMU_OscillatorEnable() can change the CMU->HFXOCTRL register,
10453    * it's important to read the CMU->HFXOCTRL register after the call to CMU_OscillatorEnable(). */
10454   hfxoCtrl = CMU->HFXOCTRL & ~(userSel
10455                                | _CMU_HFXOCTRL_AUTOSTARTEM0EM1_MASK
10456                                | _CMU_HFXOCTRL_AUTOSTARTSELEM0EM1_MASK);
10457 
10458   hfxoCtrl |= userSel
10459               | (enEM0EM1Start ? CMU_HFXOCTRL_AUTOSTARTEM0EM1 : 0UL)
10460               | (enEM0EM1StartSel ? CMU_HFXOCTRL_AUTOSTARTSELEM0EM1 : 0UL);
10461 
10462   /* Update HFXOCTRL after wait-states are updated as HF may automatically switch
10463      to HFXO when automatic select is enabled . */
10464   CMU->HFXOCTRL = hfxoCtrl;
10465 }
10466 #endif
10467 
10468 /**************************************************************************//**
10469  * @brief
10470  *   Set HFXO control registers.
10471  *
10472  * @note
10473  *   HFXO configuration should be obtained from a configuration tool,
10474  *   app note, or crystal data sheet. This function disables the HFXO to
10475  *   ensure a valid state before update.
10476  *
10477  * @param[in] hfxoInit
10478  *    HFXO setup parameters.
10479  *****************************************************************************/
CMU_HFXOInit(const CMU_HFXOInit_TypeDef * hfxoInit)10480 void CMU_HFXOInit(const CMU_HFXOInit_TypeDef *hfxoInit)
10481 {
10482   /* Do not disable HFXO if it is currently selected as the HF/Core clock. */
10483   EFM_ASSERT(CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_HFXO);
10484 
10485   /* HFXO must be disabled before reconfiguration. */
10486   CMU_OscillatorEnable(cmuOsc_HFXO, false, true);
10487 
10488 #if defined(_SILICON_LABS_32B_SERIES_1) \
10489   && (_SILICON_LABS_GECKO_INTERNAL_SDID >= 100)
10490   uint32_t tmp = CMU_HFXOCTRL_MODE_XTAL;
10491 
10492   switch (hfxoInit->mode) {
10493     case cmuOscMode_Crystal:
10494       tmp = CMU_HFXOCTRL_MODE_XTAL;
10495       break;
10496     case cmuOscMode_External:
10497       tmp = CMU_HFXOCTRL_MODE_DIGEXTCLK;
10498       break;
10499     case cmuOscMode_AcCoupled:
10500       tmp = CMU_HFXOCTRL_MODE_ACBUFEXTCLK;
10501       break;
10502     default:
10503       EFM_ASSERT(false); /* Unsupported configuration */
10504       break;
10505   }
10506   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_MODE_MASK) | tmp;
10507 
10508 #if defined(CMU_HFXOCTRL_HFXOX2EN)
10509   /* HFXO Doubler can only be enabled on crystals up to max 25 MHz. */
10510   tmp = 0;
10511   if (SystemHFXOClockGet() <= 25000000) {
10512     tmp |= CMU_HFXOCTRL_HFXOX2EN;
10513   }
10514 
10515   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_HFXOX2EN_MASK) | tmp;
10516 #endif
10517 
10518   /* Set tuning for startup and steady state. */
10519   CMU->HFXOSTARTUPCTRL = (hfxoInit->ctuneStartup
10520                           << _CMU_HFXOSTARTUPCTRL_CTUNE_SHIFT)
10521                          | (hfxoInit->xoCoreBiasTrimStartup
10522                             << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_SHIFT);
10523 
10524   CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
10525                               & ~(_CMU_HFXOSTEADYSTATECTRL_CTUNE_MASK
10526                                   | _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK))
10527                              | (hfxoInit->ctuneSteadyState
10528                                 << _CMU_HFXOSTEADYSTATECTRL_CTUNE_SHIFT)
10529                              | (hfxoInit->xoCoreBiasTrimSteadyState
10530                                 << _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_SHIFT);
10531 
10532   /* Set timeouts */
10533   CMU->HFXOTIMEOUTCTRL = (hfxoInit->timeoutPeakDetect
10534                           << _CMU_HFXOTIMEOUTCTRL_PEAKDETTIMEOUT_SHIFT)
10535                          | (hfxoInit->timeoutSteady
10536                             << _CMU_HFXOTIMEOUTCTRL_STEADYTIMEOUT_SHIFT)
10537                          | (hfxoInit->timeoutStartup
10538                             << _CMU_HFXOTIMEOUTCTRL_STARTUPTIMEOUT_SHIFT);
10539 
10540 #elif defined(_CMU_HFXOCTRL_MASK)
10541   /* Verify that the deprecated autostart fields are not used,
10542    * @ref CMU_HFXOAutostartEnable must be used instead. */
10543   EFM_ASSERT(!(hfxoInit->autoStartEm01
10544                || hfxoInit->autoSelEm01
10545                || hfxoInit->autoStartSelOnRacWakeup));
10546 
10547   uint32_t tmp = CMU_HFXOCTRL_MODE_XTAL;
10548 
10549   /* AC coupled external clock not supported. */
10550   EFM_ASSERT(hfxoInit->mode != cmuOscMode_AcCoupled);
10551   if (hfxoInit->mode == cmuOscMode_External) {
10552     tmp = CMU_HFXOCTRL_MODE_DIGEXTCLK;
10553   }
10554 
10555   /* Apply control settings. */
10556   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_MODE_MASK)
10557                   | tmp;
10558   BUS_RegBitWrite(&CMU->HFXOCTRL,
10559                   _CMU_HFXOCTRL_LOWPOWER_SHIFT,
10560                   (unsigned)hfxoInit->lowPowerMode);
10561 
10562   /* Set XTAL tuning parameters. */
10563 
10564 #if defined(_CMU_HFXOCTRL1_PEAKDETTHR_MASK)
10565   /* Set peak detection threshold. */
10566   CMU->HFXOCTRL1 = (CMU->HFXOCTRL1 & ~_CMU_HFXOCTRL1_PEAKDETTHR_MASK)
10567                    | (hfxoInit->thresholdPeakDetect
10568                       << _CMU_HFXOCTRL1_PEAKDETTHR_SHIFT);
10569 #endif
10570   /* Set tuning for startup and steady state. */
10571   CMU->HFXOSTARTUPCTRL = ((uint32_t)hfxoInit->ctuneStartup
10572                           << _CMU_HFXOSTARTUPCTRL_CTUNE_SHIFT)
10573                          | ((uint32_t)hfxoInit->xoCoreBiasTrimStartup
10574                             << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_SHIFT);
10575 
10576   CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
10577                               & ~(_CMU_HFXOSTEADYSTATECTRL_CTUNE_MASK
10578                                   | _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK
10579                                   | _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK
10580                                   | _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK))
10581                              | ((uint32_t)hfxoInit->ctuneSteadyState
10582                                 << _CMU_HFXOSTEADYSTATECTRL_CTUNE_SHIFT)
10583                              | ((uint32_t)hfxoInit->xoCoreBiasTrimSteadyState
10584                                 << _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_SHIFT)
10585                              | ((uint32_t)hfxoInit->regIshSteadyState
10586                                 << _CMU_HFXOSTEADYSTATECTRL_REGISH_SHIFT)
10587                              | getRegIshUpperVal(hfxoInit->regIshSteadyState);
10588 
10589   /* Set timeouts. */
10590   CMU->HFXOTIMEOUTCTRL = ((uint32_t)hfxoInit->timeoutPeakDetect
10591                           << _CMU_HFXOTIMEOUTCTRL_PEAKDETTIMEOUT_SHIFT)
10592                          | ((uint32_t)hfxoInit->timeoutSteady
10593                             << _CMU_HFXOTIMEOUTCTRL_STEADYTIMEOUT_SHIFT)
10594                          | ((uint32_t)hfxoInit->timeoutStartup
10595                             << _CMU_HFXOTIMEOUTCTRL_STARTUPTIMEOUT_SHIFT)
10596                          | ((uint32_t)hfxoInit->timeoutShuntOptimization
10597                             << _CMU_HFXOTIMEOUTCTRL_SHUNTOPTTIMEOUT_SHIFT);
10598 
10599 #else
10600   CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_HFXOTIMEOUT_MASK
10601                              | _CMU_CTRL_HFXOBOOST_MASK
10602                              | _CMU_CTRL_HFXOMODE_MASK
10603                              | _CMU_CTRL_HFXOGLITCHDETEN_MASK))
10604               | (hfxoInit->timeout << _CMU_CTRL_HFXOTIMEOUT_SHIFT)
10605               | (hfxoInit->boost << _CMU_CTRL_HFXOBOOST_SHIFT)
10606               | (hfxoInit->mode << _CMU_CTRL_HFXOMODE_SHIFT)
10607               | (hfxoInit->glitchDetector ? CMU_CTRL_HFXOGLITCHDETEN : 0);
10608 #endif
10609 }
10610 
10611 /***************************************************************************//**
10612  * @brief
10613  *   Get the LCD framerate divisor (FDIV) setting.
10614  *
10615  * @return
10616  *   The LCD framerate divisor.
10617  ******************************************************************************/
CMU_LCDClkFDIVGet(void)10618 uint32_t CMU_LCDClkFDIVGet(void)
10619 {
10620 #if defined(LCD_PRESENT) && defined(_CMU_LCDCTRL_MASK)
10621   return (CMU->LCDCTRL & _CMU_LCDCTRL_FDIV_MASK) >> _CMU_LCDCTRL_FDIV_SHIFT;
10622 #else
10623   return 0;
10624 #endif /* defined(LCD_PRESENT) */
10625 }
10626 
10627 /***************************************************************************//**
10628  * @brief
10629  *   Set the LCD framerate divisor (FDIV) setting.
10630  *
10631  * @note
10632  *   The FDIV field (CMU LCDCTRL register) should only be modified while the
10633  *   LCD module is clock disabled (CMU LFACLKEN0.LCD bit is 0). This function
10634  *   will NOT modify FDIV if the LCD module clock is enabled. See
10635  *   @ref CMU_ClockEnable() for disabling/enabling LCD clock.
10636  *
10637  * @param[in] div
10638  *   The FDIV setting to use.
10639  ******************************************************************************/
CMU_LCDClkFDIVSet(uint32_t div)10640 void CMU_LCDClkFDIVSet(uint32_t div)
10641 {
10642 #if defined(LCD_PRESENT) && defined(_CMU_LCDCTRL_MASK)
10643   EFM_ASSERT(div <= cmuClkDiv_128);
10644 
10645   /* Do not allow modification if LCD clock enabled. */
10646   if (CMU->LFACLKEN0 & CMU_LFACLKEN0_LCD) {
10647     return;
10648   }
10649 
10650   div        <<= _CMU_LCDCTRL_FDIV_SHIFT;
10651   div         &= _CMU_LCDCTRL_FDIV_MASK;
10652   CMU->LCDCTRL = (CMU->LCDCTRL & ~_CMU_LCDCTRL_FDIV_MASK) | div;
10653 #else
10654   (void)div; /* Unused parameter. */
10655 #endif /* defined(LCD_PRESENT) */
10656 }
10657 
10658 /**************************************************************************//**
10659  * @brief
10660  *   Set LFXO control registers.
10661  *
10662  * @note
10663  *   LFXO configuration should be obtained from a configuration tool,
10664  *   app note, or crystal data sheet. This function disables the LFXO when
10665  *   necessary to ensure a valid state before update.
10666  *
10667  * @param[in] lfxoInit
10668  *    LFXO setup parameters.
10669  *****************************************************************************/
CMU_LFXOInit(const CMU_LFXOInit_TypeDef * lfxoInit)10670 void CMU_LFXOInit(const CMU_LFXOInit_TypeDef *lfxoInit)
10671 {
10672   /* Do not disable LFXO if it is currently selected as the HF/Core clock. */
10673   EFM_ASSERT(CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_LFXO);
10674 
10675 #if defined(_SILICON_LABS_32B_SERIES_1)
10676   uint32_t reg = (CMU->LFXOCTRL & ~(_CMU_LFXOCTRL_TUNING_MASK
10677                                     | _CMU_LFXOCTRL_GAIN_MASK
10678                                     | _CMU_LFXOCTRL_TIMEOUT_MASK
10679                                     | _CMU_LFXOCTRL_MODE_MASK))
10680                  | ((uint32_t)lfxoInit->ctune << _CMU_LFXOCTRL_TUNING_SHIFT)
10681                  | ((uint32_t)lfxoInit->gain << _CMU_LFXOCTRL_GAIN_SHIFT)
10682                  | ((uint32_t)lfxoInit->timeout << _CMU_LFXOCTRL_TIMEOUT_SHIFT)
10683                  | ((uint32_t)lfxoInit->mode << _CMU_LFXOCTRL_MODE_SHIFT);
10684 
10685   /* If LFXO already contains the correct configuration then there is no need
10686    * to stop the oscillator and apply new settings. The LFXO can be running out
10687    * of reset, in which case there is no need to disable it unless necessary. */
10688   if (reg != CMU->LFXOCTRL) {
10689     CMU_OscillatorEnable(cmuOsc_LFXO, false, true);
10690     CMU->LFXOCTRL = reg;
10691   }
10692 #elif defined(_SILICON_LABS_32B_SERIES_0)
10693   /* LFXO must be disabled before reconfiguration. */
10694   CMU_OscillatorEnable(cmuOsc_LFXO, false, true);
10695 
10696   bool cmuBoost  = (lfxoInit->boost & 0x2);
10697   BUS_RegMaskedWrite(&CMU->CTRL,
10698                      _CMU_CTRL_LFXOTIMEOUT_MASK
10699                      | _CMU_CTRL_LFXOBOOST_MASK
10700                      | _CMU_CTRL_LFXOMODE_MASK,
10701                      ((uint32_t)lfxoInit->timeout
10702                       << _CMU_CTRL_LFXOTIMEOUT_SHIFT)
10703                      | ((cmuBoost ? 1 : 0) << _CMU_CTRL_LFXOBOOST_SHIFT)
10704                      | ((uint32_t)lfxoInit->mode << _CMU_CTRL_LFXOMODE_SHIFT));
10705 #if defined(_EMU_AUXCTRL_REDLFXOBOOST_MASK)
10706   /* EFM32GG has a "reduce startup boost" field in the EMU */
10707   bool emuReduce = (lfxoInit->boost & 0x1);
10708   BUS_RegBitWrite(&EMU->AUXCTRL, _EMU_AUXCTRL_REDLFXOBOOST_SHIFT, emuReduce ? 1 : 0);
10709 #endif
10710 #endif
10711 }
10712 
10713 /**************************************************************************//**
10714  * @brief
10715  *   Sets LFXO's crystal precision, in PPM.
10716  *
10717  * @note
10718  *   LFXO precision should be obtained from a crystal datasheet.
10719  *
10720  * @param[in] precision
10721  *    LFXO's crystal precision, in PPM.
10722  *****************************************************************************/
CMU_LFXOPrecisionSet(uint16_t precision)10723 void CMU_LFXOPrecisionSet(uint16_t precision)
10724 {
10725   lfxo_precision = precision;
10726 }
10727 
10728 /**************************************************************************//**
10729  * @brief
10730  *   Gets LFXO's crystal precision, in PPM.
10731  *
10732  * @param[in] precision
10733  *    LFXO's crystal precision, in PPM.
10734  *****************************************************************************/
CMU_LFXOPrecisionGet(void)10735 uint16_t CMU_LFXOPrecisionGet(void)
10736 {
10737   return lfxo_precision;
10738 }
10739 
10740 /***************************************************************************//**
10741  * @brief
10742  *   Enable/disable oscillator.
10743  *
10744  * @note
10745  *   WARNING: When this function is called to disable either cmuOsc_LFXO or
10746  *   cmuOsc_HFXO, the LFXOMODE or HFXOMODE fields of the CMU_CTRL register
10747  *   are reset to the reset value. In other words, if external clock sources are selected
10748  *   in either LFXOMODE or HFXOMODE fields, the configuration will be cleared
10749  *   and needs to be reconfigured if needed later.
10750  *
10751  * @param[in] osc
10752  *   The oscillator to enable/disable.
10753  *
10754  * @param[in] enable
10755  *   @li true - enable specified oscillator.
10756  *   @li false - disable specified oscillator.
10757  *
10758  * @param[in] wait
10759  *   Only used if @p enable is true.
10760  *   @li true - wait for oscillator start-up time to timeout before returning.
10761  *   @li false - do not wait for oscillator start-up time to timeout before
10762  *     returning.
10763  ******************************************************************************/
CMU_OscillatorEnable(CMU_Osc_TypeDef osc,bool enable,bool wait)10764 void CMU_OscillatorEnable(CMU_Osc_TypeDef osc, bool enable, bool wait)
10765 {
10766   uint32_t rdyBitPos;
10767 #if defined(_SILICON_LABS_32B_SERIES_1)
10768   uint32_t ensBitPos;
10769 #endif
10770 #if defined(_CMU_STATUS_HFXOPEAKDETRDY_MASK)
10771   uint32_t hfxoTrimStatus;
10772 #endif
10773 
10774   uint32_t enBit;
10775   uint32_t disBit;
10776 
10777   switch (osc) {
10778     case cmuOsc_HFRCO:
10779       enBit  = CMU_OSCENCMD_HFRCOEN;
10780       disBit = CMU_OSCENCMD_HFRCODIS;
10781       rdyBitPos = _CMU_STATUS_HFRCORDY_SHIFT;
10782 #if defined(_SILICON_LABS_32B_SERIES_1)
10783       ensBitPos = _CMU_STATUS_HFRCOENS_SHIFT;
10784 #endif
10785       break;
10786 
10787     case cmuOsc_HFXO:
10788       enBit  = CMU_OSCENCMD_HFXOEN;
10789       disBit = CMU_OSCENCMD_HFXODIS;
10790       rdyBitPos = _CMU_STATUS_HFXORDY_SHIFT;
10791 #if defined(_SILICON_LABS_32B_SERIES_1)
10792       ensBitPos = _CMU_STATUS_HFXOENS_SHIFT;
10793 #endif
10794       break;
10795 
10796     case cmuOsc_AUXHFRCO:
10797       enBit  = CMU_OSCENCMD_AUXHFRCOEN;
10798       disBit = CMU_OSCENCMD_AUXHFRCODIS;
10799       rdyBitPos = _CMU_STATUS_AUXHFRCORDY_SHIFT;
10800 #if defined(_SILICON_LABS_32B_SERIES_1)
10801       ensBitPos = _CMU_STATUS_AUXHFRCOENS_SHIFT;
10802 #endif
10803       break;
10804 
10805     case cmuOsc_LFRCO:
10806       enBit  = CMU_OSCENCMD_LFRCOEN;
10807       disBit = CMU_OSCENCMD_LFRCODIS;
10808       rdyBitPos = _CMU_STATUS_LFRCORDY_SHIFT;
10809 #if defined(_SILICON_LABS_32B_SERIES_1)
10810       ensBitPos = _CMU_STATUS_LFRCOENS_SHIFT;
10811 #endif
10812       break;
10813 
10814     case cmuOsc_LFXO:
10815       enBit  = CMU_OSCENCMD_LFXOEN;
10816       disBit = CMU_OSCENCMD_LFXODIS;
10817       rdyBitPos = _CMU_STATUS_LFXORDY_SHIFT;
10818 #if defined(_SILICON_LABS_32B_SERIES_1)
10819       ensBitPos = _CMU_STATUS_LFXOENS_SHIFT;
10820 #endif
10821       break;
10822 
10823 #if defined(_CMU_STATUS_USHFRCOENS_MASK)
10824     case cmuOsc_USHFRCO:
10825       enBit  = CMU_OSCENCMD_USHFRCOEN;
10826       disBit = CMU_OSCENCMD_USHFRCODIS;
10827       rdyBitPos = _CMU_STATUS_USHFRCORDY_SHIFT;
10828 #if defined(_SILICON_LABS_32B_SERIES_1)
10829       ensBitPos = _CMU_STATUS_USHFRCOENS_SHIFT;
10830 #endif
10831       break;
10832 #endif
10833 
10834 #if defined(PLFRCO_PRESENT)
10835     case cmuOsc_PLFRCO:
10836       if (!deviceHasPlfrco()) {
10837         while (true) { // PLFRCO is not available
10838           EFM_ASSERT(false);
10839         }
10840       }
10841       enBit = CMU_OSCENCMD_PLFRCOEN;
10842       disBit = CMU_OSCENCMD_PLFRCODIS;
10843       rdyBitPos = _CMU_STATUS_PLFRCORDY_SHIFT;
10844       ensBitPos = _CMU_STATUS_PLFRCOENS_SHIFT;
10845       break;
10846 #endif
10847 
10848     default:
10849       /* Undefined clock source, cmuOsc_CLKIN0 or cmuOsc_ULFRCO. ULFRCO is always enabled
10850          and cannot be disabled. In other words,the definition of cmuOsc_ULFRCO is primarily
10851          intended for information: the ULFRCO is always on.  */
10852       EFM_ASSERT(false);
10853       return;
10854   }
10855 
10856   if (enable) {
10857  #if defined(_CMU_HFXOCTRL_MASK)
10858     bool firstHfxoEnable = false;
10859 
10860     /* Enabling the HFXO for the first time requires special handling.
10861      * PEAKDETSHUTOPTMODE field of the HFXOCTRL register is used to see if this is the
10862      * first time the HFXO is enabled. */
10863     if (osc == cmuOsc_HFXO) {
10864       if (getHfxoTuningMode() == HFXO_TUNING_MODE_AUTO) {
10865         /* REGPWRSEL must be set to DVDD before the HFXO can be enabled. */
10866 #if defined(_EMU_PWRCTRL_REGPWRSEL_MASK)
10867         EFM_ASSERT((EMU->PWRCTRL & EMU_PWRCTRL_REGPWRSEL_DVDD) != 0UL);
10868 #endif
10869 
10870         firstHfxoEnable = true;
10871         /* The first time that an external clock is enabled, switch to CMD mode to make sure that
10872          * only SCO and not PDA tuning is performed. */
10873         if ((CMU->HFXOCTRL & (_CMU_HFXOCTRL_MODE_MASK)) == CMU_HFXOCTRL_MODE_DIGEXTCLK) {
10874           setHfxoTuningMode(HFXO_TUNING_MODE_CMD);
10875         }
10876       }
10877     }
10878 #endif
10879     CMU->OSCENCMD = enBit;
10880 
10881 #if defined(_SILICON_LABS_32B_SERIES_1)
10882     /* Always wait for ENS to go high. */
10883     while (BUS_RegBitRead(&CMU->STATUS, ensBitPos) == 0UL) {
10884     }
10885 #endif
10886 
10887     /* Wait for the clock to become ready after enable. */
10888     if (wait) {
10889       while (BUS_RegBitRead(&CMU->STATUS, rdyBitPos) == 0UL) {
10890       }
10891 #if defined(_SILICON_LABS_32B_SERIES_1)
10892       if ((osc == cmuOsc_HFXO) && firstHfxoEnable) {
10893         if ((CMU->HFXOCTRL & _CMU_HFXOCTRL_MODE_MASK)
10894             == CMU_HFXOCTRL_MODE_DIGEXTCLK) {
10895 #if defined(CMU_CMD_HFXOSHUNTOPTSTART)
10896           /* External clock mode should only do shunt current optimization. */
10897           (void)CMU_OscillatorTuningOptimize(cmuOsc_HFXO,
10898                                              cmuHFXOTuningMode_ShuntCommand,
10899                                              true);
10900 #endif
10901         } else {
10902           /* Wait for the peak detection and shunt current optimization
10903              to complete. */
10904           (void)CMU_OscillatorTuningWait(cmuOsc_HFXO, cmuHFXOTuningMode_Auto);
10905         }
10906 
10907         /* Disable the HFXO again to apply the trims. Apply trim from
10908            HFXOTRIMSTATUS when disabled. */
10909         hfxoTrimStatus = CMU_OscillatorTuningGet(cmuOsc_HFXO);
10910         CMU_OscillatorEnable(cmuOsc_HFXO, false, true);
10911         CMU_OscillatorTuningSet(cmuOsc_HFXO, hfxoTrimStatus);
10912 
10913         /* Restart in CMD mode. */
10914         CMU->OSCENCMD = enBit;
10915         while (BUS_RegBitRead(&CMU->STATUS, rdyBitPos) == 0UL) {
10916         }
10917       }
10918 #endif
10919     }
10920   } else {
10921     CMU->OSCENCMD = disBit;
10922 
10923 #if defined(_SILICON_LABS_32B_SERIES_1)
10924     /* Always wait for ENS to go low. */
10925     while ((CMU->STATUS & (0x1 << ensBitPos)) != 0U) {
10926     }
10927 
10928     if (wait) {
10929       /* Wait for RDY to go low as well. */
10930       while ((CMU->STATUS & (0x1 << rdyBitPos)) != 0U) {
10931       }
10932     }
10933 #endif
10934   }
10935 }
10936 
10937 /***************************************************************************//**
10938  * @brief
10939  *   Get the oscillator frequency tuning setting.
10940  *
10941  * @param[in] osc
10942  *   An oscillator to get tuning value for, one of the following:
10943  *   @li #cmuOsc_LFRCO
10944  *   @li #cmuOsc_HFRCO @if _CMU_USHFRCOCTRL_TUNING_MASK
10945  *   @li #cmuOsc_USHFRCO
10946  *   @endif
10947  *   @li #cmuOsc_AUXHFRCO
10948  *   @li #cmuOsc_HFXO if CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE is defined
10949  *
10950  * @return
10951  *   The oscillator frequency tuning setting in use.
10952  ******************************************************************************/
CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)10953 uint32_t CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)
10954 {
10955   uint32_t ret;
10956 
10957   switch (osc) {
10958     case cmuOsc_LFRCO:
10959       ret = (CMU->LFRCOCTRL & _CMU_LFRCOCTRL_TUNING_MASK)
10960             >> _CMU_LFRCOCTRL_TUNING_SHIFT;
10961       break;
10962 
10963     case cmuOsc_HFRCO:
10964       ret = (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_TUNING_MASK)
10965             >> _CMU_HFRCOCTRL_TUNING_SHIFT;
10966       break;
10967 
10968 #if defined (_CMU_USHFRCOCTRL_TUNING_MASK)
10969     case cmuOsc_USHFRCO:
10970       ret = (CMU->USHFRCOCTRL & _CMU_USHFRCOCTRL_TUNING_MASK)
10971             >> _CMU_USHFRCOCTRL_TUNING_SHIFT;
10972       break;
10973 #endif
10974 
10975     case cmuOsc_AUXHFRCO:
10976       ret = (CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_TUNING_MASK)
10977             >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT;
10978       break;
10979 
10980 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
10981     case cmuOsc_HFXO:
10982       ret = CMU->HFXOTRIMSTATUS & (_CMU_HFXOTRIMSTATUS_IBTRIMXOCORE_MASK
10983 #if defined(_CMU_HFXOTRIMSTATUS_REGISH_MASK)
10984                                    | _CMU_HFXOTRIMSTATUS_REGISH_MASK
10985 #endif
10986                                    );
10987       break;
10988 #endif
10989 
10990     default:
10991       ret = 0;
10992       EFM_ASSERT(false);
10993       break;
10994   }
10995 
10996   return ret;
10997 }
10998 
10999 /***************************************************************************//**
11000  * @brief
11001  *   Set the oscillator frequency tuning control.
11002  *
11003  * @note
11004  *   Oscillator tuning is done during production and the tuning value is
11005  *   automatically loaded after reset. Changing the tuning value from the
11006  *   calibrated value is for more advanced use. Certain oscillators also have
11007  *   build-in tuning optimization.
11008  *
11009  * @param[in] osc
11010  *   An oscillator to set tuning value for, one of the following:
11011  *   @li #cmuOsc_LFRCO
11012  *   @li #cmuOsc_HFRCO @if _CMU_USHFRCOCTRL_TUNING_MASK
11013  *   @li #cmuOsc_USHFRCO
11014  *   @endif
11015  *   @li #cmuOsc_AUXHFRCO
11016  *   @li #cmuOsc_HFXO if PEAKDETSHUNTOPTMODE is available. Note that CMD mode is set.
11017  *
11018  * @param[in] val
11019  *   The oscillator frequency tuning setting to use.
11020  ******************************************************************************/
CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc,uint32_t val)11021 void CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc, uint32_t val)
11022 {
11023 #if defined(_CMU_HFXOSTEADYSTATECTRL_REGISH_MASK)
11024   uint32_t regIshUpper;
11025 #endif
11026 
11027   switch (osc) {
11028     case cmuOsc_LFRCO:
11029       EFM_ASSERT(val <= (_CMU_LFRCOCTRL_TUNING_MASK
11030                          >> _CMU_LFRCOCTRL_TUNING_SHIFT));
11031       val &= (_CMU_LFRCOCTRL_TUNING_MASK >> _CMU_LFRCOCTRL_TUNING_SHIFT);
11032 #if defined(_SILICON_LABS_32B_SERIES_1)
11033       while (BUS_RegBitRead(&CMU->SYNCBUSY,
11034                             _CMU_SYNCBUSY_LFRCOBSY_SHIFT) != 0UL) {
11035       }
11036 #endif
11037       CMU->LFRCOCTRL = (CMU->LFRCOCTRL & ~(_CMU_LFRCOCTRL_TUNING_MASK))
11038                        | (val << _CMU_LFRCOCTRL_TUNING_SHIFT);
11039       break;
11040 
11041     case cmuOsc_HFRCO:
11042       EFM_ASSERT(val <= (_CMU_HFRCOCTRL_TUNING_MASK
11043                          >> _CMU_HFRCOCTRL_TUNING_SHIFT));
11044       val &= (_CMU_HFRCOCTRL_TUNING_MASK >> _CMU_HFRCOCTRL_TUNING_SHIFT);
11045 #if defined(_SILICON_LABS_32B_SERIES_1)
11046       while (BUS_RegBitRead(&CMU->SYNCBUSY,
11047                             _CMU_SYNCBUSY_HFRCOBSY_SHIFT) != 0UL) {
11048       }
11049 #endif
11050       CMU->HFRCOCTRL = (CMU->HFRCOCTRL & ~(_CMU_HFRCOCTRL_TUNING_MASK))
11051                        | (val << _CMU_HFRCOCTRL_TUNING_SHIFT);
11052       break;
11053 
11054 #if defined (_CMU_USHFRCOCTRL_TUNING_MASK)
11055     case cmuOsc_USHFRCO:
11056       EFM_ASSERT(val <= (_CMU_USHFRCOCTRL_TUNING_MASK
11057                          >> _CMU_USHFRCOCTRL_TUNING_SHIFT));
11058       val &= (_CMU_USHFRCOCTRL_TUNING_MASK >> _CMU_USHFRCOCTRL_TUNING_SHIFT);
11059 #if defined(_SILICON_LABS_32B_SERIES_1)
11060       while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_USHFRCOBSY_SHIFT)) {
11061       }
11062 #endif
11063       CMU->USHFRCOCTRL = (CMU->USHFRCOCTRL & ~(_CMU_USHFRCOCTRL_TUNING_MASK))
11064                          | (val << _CMU_USHFRCOCTRL_TUNING_SHIFT);
11065       break;
11066 #endif
11067 
11068     case cmuOsc_AUXHFRCO:
11069       EFM_ASSERT(val <= (_CMU_AUXHFRCOCTRL_TUNING_MASK
11070                          >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT));
11071       val &= (_CMU_AUXHFRCOCTRL_TUNING_MASK >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT);
11072 #if defined(_SILICON_LABS_32B_SERIES_1)
11073       while (BUS_RegBitRead(&CMU->SYNCBUSY,
11074                             _CMU_SYNCBUSY_AUXHFRCOBSY_SHIFT) != 0UL) {
11075       }
11076 #endif
11077       CMU->AUXHFRCOCTRL = (CMU->AUXHFRCOCTRL & ~(_CMU_AUXHFRCOCTRL_TUNING_MASK))
11078                           | (val << _CMU_AUXHFRCOCTRL_TUNING_SHIFT);
11079       break;
11080 
11081 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
11082     case cmuOsc_HFXO:
11083 
11084       /* Do set PEAKDETSHUNTOPTMODE or HFXOSTEADYSTATECTRL if HFXO is enabled. */
11085       EFM_ASSERT((CMU->STATUS & CMU_STATUS_HFXOENS) == 0UL);
11086 
11087       /* Switch to command mode. Automatic SCO and PDA calibration is not done
11088          at the next enable. Set user REGISH, REGISHUPPER, and IBTRIMXOCORE. */
11089       CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
11090                       | CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_CMD;
11091 
11092 #if defined(_CMU_HFXOSTEADYSTATECTRL_REGISH_MASK)
11093       regIshUpper = getRegIshUpperVal((val & _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK)
11094                                       >> _CMU_HFXOSTEADYSTATECTRL_REGISH_SHIFT);
11095       CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
11096                                   & ~(_CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK
11097                                       | _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK
11098                                       | _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK))
11099                                  | val
11100                                  | regIshUpper;
11101 #else
11102       CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
11103                                   & ~_CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK)
11104                                  | val;
11105 #endif
11106 
11107       break;
11108 #endif
11109 
11110     default:
11111       EFM_ASSERT(false);
11112       break;
11113   }
11114 }
11115 
11116 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK) || defined(_CMU_HFXOCTRL_PEAKDETMODE_MASK)
11117 /***************************************************************************//**
11118  * @brief
11119  *   Wait for the oscillator tuning optimization.
11120  *
11121  * @param[in] osc
11122  *   An oscillator to set tuning value for, one of the following:
11123  *   @li #cmuOsc_HFXO
11124  *
11125  * @param[in] mode
11126  *   Tuning optimization mode.
11127  *
11128  * @return
11129  *   Returns false on invalid parameters or oscillator error status.
11130  ******************************************************************************/
CMU_OscillatorTuningWait(CMU_Osc_TypeDef osc,CMU_HFXOTuningMode_TypeDef mode)11131 bool CMU_OscillatorTuningWait(CMU_Osc_TypeDef osc,
11132                               CMU_HFXOTuningMode_TypeDef mode)
11133 {
11134   uint32_t waitFlags;
11135   EFM_ASSERT(osc == cmuOsc_HFXO);
11136 
11137   /* Currently implemented for HFXO with PEAKDETSHUNTOPTMODE only. */
11138   (void)osc;
11139 
11140   if (getHfxoTuningMode() == HFXO_TUNING_MODE_AUTO) {
11141     waitFlags = HFXO_TUNING_READY_FLAGS;
11142   } else {
11143     /* Set wait flags for each command and wait. */
11144     switch (mode) {
11145 #if defined(_CMU_STATUS_HFXOSHUNTOPTRDY_MASK)
11146       case cmuHFXOTuningMode_ShuntCommand:
11147         waitFlags = CMU_STATUS_HFXOSHUNTOPTRDY;
11148         break;
11149 #endif
11150       case cmuHFXOTuningMode_Auto:
11151         waitFlags = HFXO_TUNING_READY_FLAGS;
11152         break;
11153 
11154 #if defined(CMU_CMD_HFXOSHUNTOPTSTART)
11155       case cmuHFXOTuningMode_PeakShuntCommand:
11156         waitFlags = HFXO_TUNING_READY_FLAGS;
11157         break;
11158 #endif
11159 
11160       default:
11161         waitFlags = _CMU_STATUS_MASK;
11162         EFM_ASSERT(false);
11163         break;
11164     }
11165   }
11166   while ((CMU->STATUS & waitFlags) != waitFlags) {
11167   }
11168 
11169 #if defined(CMU_IF_HFXOPEAKDETERR)
11170   /* Check error flags. */
11171   if ((waitFlags & CMU_STATUS_HFXOPEAKDETRDY) != 0UL) {
11172     return (CMU->IF & CMU_IF_HFXOPEAKDETERR) != 0UL ? true : false;
11173   }
11174 #endif
11175   return true;
11176 }
11177 
11178 /***************************************************************************//**
11179  * @brief
11180  *   Start and optionally wait for the oscillator tuning optimization.
11181  *
11182  * @param[in] osc
11183  *   An oscillator to set tuning value for, one of the following:
11184  *   @li #cmuOsc_HFXO
11185  *
11186  * @param[in] mode
11187  *   Tuning optimization mode.
11188  *
11189  * @param[in] wait
11190  *   Wait for tuning optimization to complete.
11191  *   true - wait for tuning optimization to complete.
11192  *   false - return without waiting.
11193  *
11194  * @return
11195  *   Returns false on invalid parameters or oscillator error status.
11196  ******************************************************************************/
CMU_OscillatorTuningOptimize(CMU_Osc_TypeDef osc,CMU_HFXOTuningMode_TypeDef mode,bool wait)11197 bool CMU_OscillatorTuningOptimize(CMU_Osc_TypeDef osc,
11198                                   CMU_HFXOTuningMode_TypeDef mode,
11199                                   bool wait)
11200 {
11201   switch (osc) {
11202     case cmuOsc_HFXO:
11203       if ((unsigned)mode != 0U) {
11204 #if defined(CMU_IF_HFXOPEAKDETERR)
11205         /* Clear the error flag before command write. */
11206         CMU->IFC = CMU_IFC_HFXOPEAKDETERR;
11207 #endif
11208         CMU->CMD = (uint32_t)mode;
11209       }
11210       if (wait) {
11211         return CMU_OscillatorTuningWait(osc, mode);
11212       }
11213       break;
11214 
11215     default:
11216       EFM_ASSERT(false);
11217       break;
11218   }
11219   return true;
11220 }
11221 #endif
11222 
11223 /**************************************************************************//**
11224  * @brief
11225  *   Determine if the currently selected PCNTn clock used is external or LFBCLK.
11226  *
11227  * @param[in] instance
11228  *   PCNT instance number to get currently selected clock source for.
11229  *
11230  * @return
11231  *   @li true - selected clock is external clock.
11232  *   @li false - selected clock is LFBCLK.
11233  *****************************************************************************/
CMU_PCNTClockExternalGet(unsigned int instance)11234 bool CMU_PCNTClockExternalGet(unsigned int instance)
11235 {
11236   uint32_t setting;
11237 
11238   switch (instance) {
11239 #if defined(_CMU_PCNTCTRL_PCNT0CLKEN_MASK)
11240     case 0:
11241       setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT0CLKSEL_PCNT0S0;
11242       break;
11243 
11244 #if defined(_CMU_PCNTCTRL_PCNT1CLKEN_MASK)
11245     case 1:
11246       setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT1CLKSEL_PCNT1S0;
11247       break;
11248 
11249 #if defined(_CMU_PCNTCTRL_PCNT2CLKEN_MASK)
11250     case 2:
11251       setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT2CLKSEL_PCNT2S0;
11252       break;
11253 #endif
11254 #endif
11255 #endif
11256 
11257     default:
11258       setting = 0;
11259       break;
11260   }
11261   return setting > 0UL ? true : false;
11262 }
11263 
11264 /**************************************************************************//**
11265  * @brief
11266  *   Select the PCNTn clock.
11267  *
11268  * @param[in] instance
11269  *   PCNT instance number to set selected clock source for.
11270  *
11271  * @param[in] external
11272  *   Set to true to select the external clock, false to select LFBCLK.
11273  *****************************************************************************/
CMU_PCNTClockExternalSet(unsigned int instance,bool external)11274 void CMU_PCNTClockExternalSet(unsigned int instance, bool external)
11275 {
11276 #if defined(PCNT_PRESENT)
11277   uint32_t setting = 0;
11278 
11279   EFM_ASSERT(instance < (unsigned)PCNT_COUNT);
11280 
11281   if (external) {
11282     setting = 1;
11283   }
11284 
11285   BUS_RegBitWrite(&(CMU->PCNTCTRL), (instance * 2U) + 1U, setting);
11286 
11287 #else
11288   (void)instance; /* An unused parameter */
11289   (void)external; /* An unused parameter */
11290 #endif
11291 }
11292 
11293 #if defined(_CMU_USHFRCOCONF_BAND_MASK)
11294 /***************************************************************************//**
11295  * @brief
11296  *   Get USHFRCO band in use.
11297  *
11298  * @return
11299  *   USHFRCO band in use.
11300  ******************************************************************************/
CMU_USHFRCOBandGet(void)11301 CMU_USHFRCOBand_TypeDef CMU_USHFRCOBandGet(void)
11302 {
11303   return (CMU_USHFRCOBand_TypeDef)((CMU->USHFRCOCONF
11304                                     & _CMU_USHFRCOCONF_BAND_MASK)
11305                                    >> _CMU_USHFRCOCONF_BAND_SHIFT);
11306 }
11307 
11308 /***************************************************************************//**
11309  * @brief
11310  *   Get USHFRCO frequency.
11311  *
11312  * @return
11313  *   USHFRCO frequency.
11314  ******************************************************************************/
CMU_USHFRCOFreqGet(void)11315 uint32_t CMU_USHFRCOFreqGet(void)
11316 {
11317   return ushfrcoFreq;
11318 }
11319 #endif
11320 
11321 #if defined(_CMU_USHFRCOCONF_BAND_MASK)
11322 /***************************************************************************//**
11323  * @brief
11324  *   Set the USHFRCO band to use.
11325  *
11326  * @param[in] band
11327  *   USHFRCO band to activate.
11328  ******************************************************************************/
CMU_USHFRCOBandSet(CMU_USHFRCOBand_TypeDef band)11329 void CMU_USHFRCOBandSet(CMU_USHFRCOBand_TypeDef band)
11330 {
11331   uint32_t           tuning;
11332   uint32_t           fineTuning;
11333 
11334   /* Cannot switch band if USHFRCO is already selected as HF clock. */
11335   EFM_ASSERT(CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_USHFRCODIV2);
11336 
11337   /* Read tuning value from calibration table. */
11338   switch (band) {
11339     case cmuUSHFRCOBand_24MHz:
11340       tuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND24_TUNING_MASK)
11341                >> _DEVINFO_USHFRCOCAL0_BAND24_TUNING_SHIFT;
11342       fineTuning = (DEVINFO->USHFRCOCAL0
11343                     & _DEVINFO_USHFRCOCAL0_BAND24_FINETUNING_MASK)
11344                    >> _DEVINFO_USHFRCOCAL0_BAND24_FINETUNING_SHIFT;
11345       ushfrcoFreq = 24000000UL;
11346       break;
11347 
11348     case cmuUSHFRCOBand_48MHz:
11349       tuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND48_TUNING_MASK)
11350                >> _DEVINFO_USHFRCOCAL0_BAND48_TUNING_SHIFT;
11351       fineTuning = (DEVINFO->USHFRCOCAL0
11352                     & _DEVINFO_USHFRCOCAL0_BAND48_FINETUNING_MASK)
11353                    >> _DEVINFO_USHFRCOCAL0_BAND48_FINETUNING_SHIFT;
11354       /* Enable the clock divider before switching the band from 24 to 48 MHz */
11355       BUS_RegBitWrite(&CMU->USHFRCOCONF, _CMU_USHFRCOCONF_USHFRCODIV2DIS_SHIFT, 0);
11356       ushfrcoFreq = 48000000UL;
11357       break;
11358 
11359     default:
11360       EFM_ASSERT(false);
11361       return;
11362   }
11363 
11364   /* Set band and tuning. */
11365   CMU->USHFRCOCONF = (CMU->USHFRCOCONF & ~_CMU_USHFRCOCONF_BAND_MASK)
11366                      | (band << _CMU_USHFRCOCONF_BAND_SHIFT);
11367   CMU->USHFRCOCTRL = (CMU->USHFRCOCTRL & ~_CMU_USHFRCOCTRL_TUNING_MASK)
11368                      | (tuning << _CMU_USHFRCOCTRL_TUNING_SHIFT);
11369   CMU->USHFRCOTUNE = (CMU->USHFRCOTUNE & ~_CMU_USHFRCOTUNE_FINETUNING_MASK)
11370                      | (fineTuning << _CMU_USHFRCOTUNE_FINETUNING_SHIFT);
11371 
11372   /* Disable the clock divider after switching the band from 48 to 24 MHz. */
11373   if (band == cmuUSHFRCOBand_24MHz) {
11374     BUS_RegBitWrite(&CMU->USHFRCOCONF, _CMU_USHFRCOCONF_USHFRCODIV2DIS_SHIFT, 1);
11375   }
11376 }
11377 #endif
11378 
11379 #endif // defined(_SILICON_LABS_32B_SERIES_2)
11380 /** @} (end addtogroup cmu) */
11381 #endif /* defined(CMU_PRESENT) */
11382