1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016 - 2019, NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_clock.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.clock"
18 #endif
19 
20 /* Macro definition remap workaround. */
21 #if (defined(MCG_C2_EREFS_MASK) && !(defined(MCG_C2_EREFS0_MASK)))
22 #define MCG_C2_EREFS0_MASK MCG_C2_EREFS_MASK
23 #endif
24 #if (defined(MCG_C2_HGO_MASK) && !(defined(MCG_C2_HGO0_MASK)))
25 #define MCG_C2_HGO0_MASK MCG_C2_HGO_MASK
26 #endif
27 #if (defined(MCG_C2_RANGE_MASK) && !(defined(MCG_C2_RANGE0_MASK)))
28 #define MCG_C2_RANGE0_MASK MCG_C2_RANGE_MASK
29 #endif
30 #if (defined(MCG_C6_CME_MASK) && !(defined(MCG_C6_CME0_MASK)))
31 #define MCG_C6_CME0_MASK MCG_C6_CME_MASK
32 #endif
33 
34 /* PLL fixed multiplier when there is not PRDIV and VDIV. */
35 #define PLL_FIXED_MULT (375U)
36 /* Max frequency of the reference clock used for internal clock trim. */
37 #define TRIM_REF_CLK_MIN (8000000U)
38 /* Min frequency of the reference clock used for internal clock trim. */
39 #define TRIM_REF_CLK_MAX (16000000U)
40 /* Max trim value of fast internal reference clock. */
41 #define TRIM_FIRC_MAX (5000000U)
42 /* Min trim value of fast internal reference clock. */
43 #define TRIM_FIRC_MIN (3000000U)
44 /* Max trim value of fast internal reference clock. */
45 #define TRIM_SIRC_MAX (39063U)
46 /* Min trim value of fast internal reference clock. */
47 #define TRIM_SIRC_MIN (31250U)
48 
49 #define MCG_S_IRCST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_IRCST_MASK) >> (uint32_t)MCG_S_IRCST_SHIFT)
50 #define MCG_S_CLKST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_CLKST_MASK) >> (uint32_t)MCG_S_CLKST_SHIFT)
51 #define MCG_S_IREFST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_IREFST_MASK) >> (uint32_t)MCG_S_IREFST_SHIFT)
52 #define MCG_S_PLLST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_PLLST_MASK) >> (uint32_t)MCG_S_PLLST_SHIFT)
53 #define MCG_C1_FRDIV_VAL ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT)
54 #define MCG_C2_LP_VAL (((uint32_t)MCG->C2 & (uint32_t)MCG_C2_LP_MASK) >> (uint32_t)MCG_C2_LP_SHIFT)
55 #define MCG_C2_RANGE_VAL ((MCG->C2 & MCG_C2_RANGE_MASK) >> MCG_C2_RANGE_SHIFT)
56 #define MCG_SC_FCRDIV_VAL ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)
57 #define MCG_S2_PLLCST_VAL (((uint32_t)MCG->S2 & (uint32_t)MCG_S2_PLLCST_MASK) >> (uint32_t)MCG_S2_PLLCST_SHIFT)
58 #define MCG_C7_OSCSEL_VAL ((MCG->C7 & MCG_C7_OSCSEL_MASK) >> MCG_C7_OSCSEL_SHIFT)
59 #define MCG_C4_DMX32_VAL ((MCG->C4 & MCG_C4_DMX32_MASK) >> MCG_C4_DMX32_SHIFT)
60 #define MCG_C4_DRST_DRS_VAL ((MCG->C4 & MCG_C4_DRST_DRS_MASK) >> MCG_C4_DRST_DRS_SHIFT)
61 #define MCG_C7_PLL32KREFSEL_VAL ((MCG->C7 & MCG_C7_PLL32KREFSEL_MASK) >> MCG_C7_PLL32KREFSEL_SHIFT)
62 #define MCG_C5_PLLREFSEL0_VAL ((MCG->C5 & MCG_C5_PLLREFSEL0_MASK) >> MCG_C5_PLLREFSEL0_SHIFT)
63 #define MCG_C11_PLLREFSEL1_VAL ((MCG->C11 & MCG_C11_PLLREFSEL1_MASK) >> MCG_C11_PLLREFSEL1_SHIFT)
64 #define MCG_C11_PRDIV1_VAL ((MCG->C11 & MCG_C11_PRDIV1_MASK) >> MCG_C11_PRDIV1_SHIFT)
65 #define MCG_C12_VDIV1_VAL ((MCG->C12 & MCG_C12_VDIV1_MASK) >> MCG_C12_VDIV1_SHIFT)
66 #define MCG_C5_PRDIV0_VAL ((uint8_t)(MCG->C5 & MCG_C5_PRDIV0_MASK) >> MCG_C5_PRDIV0_SHIFT)
67 #define MCG_C6_VDIV0_VAL ((uint8_t)(MCG->C6 & MCG_C6_VDIV0_MASK) >> MCG_C6_VDIV0_SHIFT)
68 
69 #define OSC_MODE_MASK (MCG_C2_EREFS0_MASK | MCG_C2_HGO0_MASK | MCG_C2_RANGE0_MASK)
70 
71 #define SIM_CLKDIV1_OUTDIV1_VAL ((uint32_t)(SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
72 #define SIM_CLKDIV1_OUTDIV2_VAL ((uint32_t)(SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT)
73 #define SIM_CLKDIV1_OUTDIV3_VAL ((uint32_t)(SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV3_MASK) >> SIM_CLKDIV1_OUTDIV3_SHIFT)
74 #define SIM_CLKDIV1_OUTDIV4_VAL ((uint32_t)(SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)
75 #define SIM_SOPT1_OSC32KSEL_VAL ((SIM->SOPT1 & SIM_SOPT1_OSC32KSEL_MASK) >> SIM_SOPT1_OSC32KSEL_SHIFT)
76 #define SIM_SOPT2_PLLFLLSEL_VAL ((SIM->SOPT2 & SIM_SOPT2_PLLFLLSEL_MASK) >> SIM_SOPT2_PLLFLLSEL_SHIFT)
77 #define SIM_CLKDIV3_PLLFLLDIV_VAL ((SIM->CLKDIV3 & SIM_CLKDIV3_PLLFLLDIV_MASK) >> SIM_CLKDIV3_PLLFLLDIV_SHIFT)
78 #define SIM_CLKDIV3_PLLFLLFRAC_VAL ((SIM->CLKDIV3 & SIM_CLKDIV3_PLLFLLFRAC_MASK) >> SIM_CLKDIV3_PLLFLLFRAC_SHIFT)
79 
80 /* MCG_S_CLKST definition. */
81 enum _mcg_clkout_stat
82 {
83     kMCG_ClkOutStatFll, /* FLL.            */
84     kMCG_ClkOutStatInt, /* Internal clock. */
85     kMCG_ClkOutStatExt, /* External clock. */
86     kMCG_ClkOutStatPll  /* PLL.            */
87 };
88 
89 /* MCG_S_PLLST definition. */
90 enum _mcg_pllst
91 {
92     kMCG_PllstFll, /* FLL is used. */
93     kMCG_PllstPll  /* PLL is used. */
94 };
95 
96 /*******************************************************************************
97  * Variables
98  ******************************************************************************/
99 
100 /* Slow internal reference clock frequency. */
101 static uint32_t s_slowIrcFreq = 32768U;
102 /* Fast internal reference clock frequency. */
103 static uint32_t s_fastIrcFreq = 4000000U;
104 
105 /* External XTAL0 (OSC0) clock frequency. */
106 volatile uint32_t g_xtal0Freq;
107 /* External XTAL32K clock frequency. */
108 volatile uint32_t g_xtal32Freq;
109 
110 /*******************************************************************************
111  * Prototypes
112  ******************************************************************************/
113 
114 /*!
115  * @brief Get the MCG external reference clock frequency.
116  *
117  * Get the current MCG external reference clock frequency in Hz. It is
118  * the frequency select by MCG_C7[OSCSEL]. This is an internal function.
119  *
120  * @return MCG external reference clock frequency in Hz.
121  */
122 static uint32_t CLOCK_GetMcgExtClkFreq(void);
123 
124 /*!
125  * @brief Get the MCG FLL external reference clock frequency.
126  *
127  * Get the current MCG FLL external reference clock frequency in Hz. It is
128  * the frequency after by MCG_C1[FRDIV]. This is an internal function.
129  *
130  * @return MCG FLL external reference clock frequency in Hz.
131  */
132 static uint32_t CLOCK_GetFllExtRefClkFreq(void);
133 
134 /*!
135  * @brief Get the MCG FLL reference clock frequency.
136  *
137  * Get the current MCG FLL reference clock frequency in Hz. It is
138  * the frequency select by MCG_C1[IREFS]. This is an internal function.
139  *
140  * @return MCG FLL reference clock frequency in Hz.
141  */
142 static uint32_t CLOCK_GetFllRefClkFreq(void);
143 
144 /*!
145  * @brief Get the frequency of clock selected by MCG_C2[IRCS].
146  *
147  * This clock's two output:
148  *  1. MCGOUTCLK when MCG_S[CLKST]=0.
149  *  2. MCGIRCLK when MCG_C1[IRCLKEN]=1.
150  *
151  * @return The frequency in Hz.
152  */
153 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void);
154 
155 /*!
156  * @brief Get the MCG PLL/PLL0 reference clock frequency.
157  *
158  * Get the current MCG PLL/PLL0 reference clock frequency in Hz.
159  * This is an internal function.
160  *
161  * @return MCG PLL/PLL0 reference clock frequency in Hz.
162  */
163 static uint32_t CLOCK_GetPll0RefFreq(void);
164 
165 /*!
166  * @brief Calculate the RANGE value base on crystal frequency.
167  *
168  * To setup external crystal oscillator, must set the register bits RANGE
169  * base on the crystal frequency. This function returns the RANGE base on the
170  * input frequency. This is an internal function.
171  *
172  * @param freq Crystal frequency in Hz.
173  * @return The RANGE value.
174  */
175 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
176 
177 #ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
178 /*!
179  * @brief Delay function to wait FLL stable.
180  *
181  * Delay function to wait FLL stable in FEI mode or FEE mode, should wait at least
182  * 1ms. Every time changes FLL setting, should wait this time for FLL stable.
183  */
184 static void CLOCK_FllStableDelay(void);
185 #endif
186 
187 /*******************************************************************************
188  * Code
189  ******************************************************************************/
190 
191 #ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
CLOCK_FllStableDelay(void)192 static void CLOCK_FllStableDelay(void)
193 {
194     /*
195        Should wait at least 1ms. Because in these modes, the core clock is 100MHz
196        at most, so this function could obtain the 1ms delay.
197      */
198     volatile uint32_t i = 30000U;
199     while (0U != (i--))
200     {
201         __NOP();
202     }
203 }
204 #else  /* With MCG_USER_CONFIG_FLL_STABLE_DELAY_EN defined. */
205 /* Once user defines the MCG_USER_CONFIG_FLL_STABLE_DELAY_EN to use their own delay function, he has to
206  * create his own CLOCK_FllStableDelay() function in application code. Since the clock functions in this
207  * file would call the CLOCK_FllStableDelay() regardless how it is defined.
208  */
209 extern void CLOCK_FllStableDelay(void);
210 #endif /* MCG_USER_CONFIG_FLL_STABLE_DELAY_EN */
211 
CLOCK_GetMcgExtClkFreq(void)212 static uint32_t CLOCK_GetMcgExtClkFreq(void)
213 {
214     /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
215     assert(0U != g_xtal0Freq);
216     return g_xtal0Freq;
217 }
218 
CLOCK_GetFllExtRefClkFreq(void)219 static uint32_t CLOCK_GetFllExtRefClkFreq(void)
220 {
221     /* FllExtRef = McgExtRef / FllExtRefDiv */
222     uint8_t frdiv;
223     uint8_t range;
224 
225     uint32_t freq = CLOCK_GetMcgExtClkFreq();
226 
227     frdiv = MCG_C1_FRDIV_VAL;
228     freq >>= frdiv;
229 
230     range = MCG_C2_RANGE_VAL;
231 
232     /*
233        When should use divider 32, 64, 128, 256, 512, 1024, 1280, 1536.
234        1. MCG_C7[OSCSEL] selects IRC48M.
235        2. MCG_C7[OSCSEL] selects OSC0 and MCG_C2[RANGE] is not 0.
236     */
237     if (((0U != range)))
238     {
239         switch (frdiv)
240         {
241             case 0:
242             case 1:
243             case 2:
244             case 3:
245             case 4:
246             case 5:
247                 freq >>= 5u;
248                 break;
249             case 6:
250                 /* 64*20=1280 */
251                 freq /= 20u;
252                 break;
253             case 7:
254                 /* 128*12=1536 */
255                 freq /= 12u;
256                 break;
257             default:
258                 freq = 0u;
259                 break;
260         }
261     }
262 
263     return freq;
264 }
265 
CLOCK_GetInternalRefClkSelectFreq(void)266 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void)
267 {
268     uint32_t freq;
269 
270     if ((uint8_t)kMCG_IrcSlow == MCG_S_IRCST_VAL)
271     {
272         /* Slow internal reference clock selected*/
273         freq = s_slowIrcFreq;
274     }
275     else
276     {
277         /* Fast internal reference clock selected*/
278         freq = s_fastIrcFreq >> MCG_SC_FCRDIV_VAL;
279     }
280 
281     return freq;
282 }
283 
CLOCK_GetFllRefClkFreq(void)284 static uint32_t CLOCK_GetFllRefClkFreq(void)
285 {
286     uint32_t freq;
287 
288     /* If use external reference clock. */
289     if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
290     {
291         freq = CLOCK_GetFllExtRefClkFreq();
292     }
293     /* If use internal reference clock. */
294     else
295     {
296         freq = s_slowIrcFreq;
297     }
298 
299     return freq;
300 }
301 
CLOCK_GetPll0RefFreq(void)302 static uint32_t CLOCK_GetPll0RefFreq(void)
303 {
304     /* MCG external reference clock. */
305     return CLOCK_GetMcgExtClkFreq();
306 }
307 
CLOCK_GetOscRangeFromFreq(uint32_t freq)308 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
309 {
310     uint8_t range;
311 
312     if (freq <= 39063U)
313     {
314         range = 0U;
315     }
316     else if (freq <= 8000000U)
317     {
318         range = 1U;
319     }
320     else
321     {
322         range = 2U;
323     }
324 
325     return range;
326 }
327 
328 /*!
329  * brief Get the OSC0 external reference undivided clock frequency (OSC0ERCLK_UNDIV).
330  *
331  * return Clock frequency in Hz.
332  */
CLOCK_GetOsc0ErClkUndivFreq(void)333 uint32_t CLOCK_GetOsc0ErClkUndivFreq(void)
334 {
335     uint32_t freq;
336 
337     if ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U)
338     {
339         /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
340         assert(g_xtal0Freq);
341         freq = g_xtal0Freq;
342     }
343     else
344     {
345         freq = 0U;
346     }
347     return freq;
348 }
349 
350 /*!
351  * brief Get the OSC0 external reference divided clock frequency.
352  *
353  * return Clock frequency in Hz.
354  */
CLOCK_GetOsc0ErClkDivFreq(void)355 uint32_t CLOCK_GetOsc0ErClkDivFreq(void)
356 {
357     uint32_t freq;
358     uint8_t temp;
359     if ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U)
360     {
361         /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
362         assert(g_xtal0Freq);
363         temp = OSC0->DIV & OSC_DIV_ERPS_MASK;
364         freq = g_xtal0Freq >> ((temp) >> OSC_DIV_ERPS_SHIFT);
365     }
366     else
367     {
368         freq = 0U;
369     }
370     return freq;
371 }
372 
373 /*!
374  * brief Get the external reference 32K clock frequency (ERCLK32K).
375  *
376  * return Clock frequency in Hz.
377  */
CLOCK_GetEr32kClkFreq(void)378 uint32_t CLOCK_GetEr32kClkFreq(void)
379 {
380     uint32_t freq;
381 
382     switch (SIM_SOPT1_OSC32KSEL_VAL)
383     {
384         case 0U: /* OSC 32k clock  */
385             freq = (CLOCK_GetOsc0ErClkUndivFreq() == 32768U) ? 32768U : 0U;
386             break;
387         case 3U: /* LPO clock      */
388             freq = LPO_CLK_FREQ;
389             break;
390         default:
391             freq = 0U;
392             break;
393     }
394     return freq;
395 }
396 
397 /*!
398  * brief Get the output clock frequency selected by SIM[PLLFLLSEL].
399  *
400  * return Clock frequency in Hz.
401  */
CLOCK_GetPllFllSelClkFreq(void)402 uint32_t CLOCK_GetPllFllSelClkFreq(void)
403 {
404     uint32_t freq;
405 
406     switch (SIM_SOPT2_PLLFLLSEL_VAL)
407     {
408         case 0U: /* FLL. */
409             freq = CLOCK_GetFllFreq();
410             break;
411         case 1U: /* PLL. */
412             freq = CLOCK_GetPll0Freq();
413             break;
414         default:
415             freq = 0U;
416             break;
417     }
418 
419     return freq;
420 }
421 
422 /*!
423  * brief Get the OSC0 external reference clock frequency (OSC0ERCLK).
424  *
425  * return Clock frequency in Hz.
426  */
CLOCK_GetOsc0ErClkFreq(void)427 uint32_t CLOCK_GetOsc0ErClkFreq(void)
428 {
429     return CLOCK_GetOsc0ErClkDivFreq();
430 }
431 
432 /*!
433  * brief Get the fast peripheral clock frequency.
434  *
435  * return Clock frequency in Hz.
436  */
CLOCK_GetFastPeriphClkFreq(void)437 uint32_t CLOCK_GetFastPeriphClkFreq(void)
438 {
439     return CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV2_VAL + 1UL));
440 }
441 
442 /*!
443  * brief Get the flash clock frequency.
444  *
445  * return Clock frequency in Hz.
446  */
CLOCK_GetFlashClkFreq(void)447 uint32_t CLOCK_GetFlashClkFreq(void)
448 {
449     return CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV4_VAL + 1UL));
450 }
451 
452 /*!
453  * brief Get the flexbus clock frequency.
454  *
455  * return Clock frequency in Hz.
456  */
CLOCK_GetFlexBusClkFreq(void)457 uint32_t CLOCK_GetFlexBusClkFreq(void)
458 {
459     return CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV3_VAL + 1UL));
460 }
461 
462 /*!
463  * brief Get the bus clock frequency.
464  *
465  * return Clock frequency in Hz.
466  */
CLOCK_GetBusClkFreq(void)467 uint32_t CLOCK_GetBusClkFreq(void)
468 {
469     return CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV4_VAL + 1UL));
470 }
471 
472 /*!
473  * brief Get the core clock or system clock frequency.
474  *
475  * return Clock frequency in Hz.
476  */
CLOCK_GetCoreSysClkFreq(void)477 uint32_t CLOCK_GetCoreSysClkFreq(void)
478 {
479     return CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV1_VAL + 1UL));
480 }
481 
482 /*!
483  * brief Gets the clock frequency for a specific clock name.
484  *
485  * This function checks the current clock configurations and then calculates
486  * the clock frequency for a specific clock name defined in clock_name_t.
487  * The MCG must be properly configured before using this function.
488  *
489  * param clockName Clock names defined in clock_name_t
490  * return Clock frequency value in Hertz
491  */
CLOCK_GetFreq(clock_name_t clockName)492 uint32_t CLOCK_GetFreq(clock_name_t clockName)
493 {
494     uint32_t freq;
495 
496     switch (clockName)
497     {
498         case kCLOCK_CoreSysClk:
499             freq = CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV1_VAL + 1UL));
500             break;
501         case kCLOCK_FastPeriphClk:
502             freq = CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV2_VAL + 1UL));
503             break;
504         case kCLOCK_FlexBusClk:
505             freq = CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV3_VAL + 1UL));
506             break;
507         case kCLOCK_BusClk:
508         case kCLOCK_FlashClk:
509             freq = CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV4_VAL + 1UL));
510             break;
511         case kCLOCK_PllFllSelClk:
512             freq = CLOCK_GetPllFllSelClkFreq();
513             break;
514         case kCLOCK_Er32kClk:
515             freq = CLOCK_GetEr32kClkFreq();
516             break;
517         case kCLOCK_McgFixedFreqClk:
518             freq = CLOCK_GetFixedFreqClkFreq();
519             break;
520         case kCLOCK_McgInternalRefClk:
521             freq = CLOCK_GetInternalRefClkFreq();
522             break;
523         case kCLOCK_McgFllClk:
524             freq = CLOCK_GetFllFreq();
525             break;
526         case kCLOCK_McgPll0Clk:
527             freq = CLOCK_GetPll0Freq();
528             break;
529         case kCLOCK_LpoClk:
530             freq = LPO_CLK_FREQ;
531             break;
532         case kCLOCK_Osc0ErClkUndiv:
533             freq = CLOCK_GetOsc0ErClkUndivFreq();
534             break;
535         case kCLOCK_Osc0ErClk:
536             freq = CLOCK_GetOsc0ErClkDivFreq();
537             break;
538         default:
539             freq = 0U;
540             break;
541     }
542 
543     return freq;
544 }
545 
546 /*!
547  * brief Set the clock configure in SIM module.
548  *
549  * This function sets system layer clock settings in SIM module.
550  *
551  * param config Pointer to the configure structure.
552  */
CLOCK_SetSimConfig(sim_clock_config_t const * config)553 void CLOCK_SetSimConfig(sim_clock_config_t const *config)
554 {
555     SIM->CLKDIV1 = config->clkdiv1;
556     CLOCK_SetPllFllSelClock(config->pllFllSel);
557     CLOCK_SetEr32kClock(config->er32kSrc);
558 }
559 
560 /*!
561  * brief Gets the MCG output clock (MCGOUTCLK) frequency.
562  *
563  * This function gets the MCG output clock frequency in Hz based on the current MCG
564  * register value.
565  *
566  * return The frequency of MCGOUTCLK.
567  */
CLOCK_GetOutClkFreq(void)568 uint32_t CLOCK_GetOutClkFreq(void)
569 {
570     uint32_t mcgoutclk;
571     uint32_t clkst = (uint32_t)MCG_S_CLKST_VAL;
572 
573     switch (clkst)
574     {
575         case (uint32_t)kMCG_ClkOutStatPll:
576             mcgoutclk = CLOCK_GetPll0Freq();
577             break;
578         case (uint32_t)kMCG_ClkOutStatFll:
579             mcgoutclk = CLOCK_GetFllFreq();
580             break;
581         case (uint32_t)kMCG_ClkOutStatInt:
582             mcgoutclk = CLOCK_GetInternalRefClkSelectFreq();
583             break;
584         case (uint32_t)kMCG_ClkOutStatExt:
585             mcgoutclk = CLOCK_GetMcgExtClkFreq();
586             break;
587         default:
588             mcgoutclk = 0U;
589             break;
590     }
591 
592     return mcgoutclk;
593 }
594 
595 /*!
596  * brief Gets the MCG FLL clock (MCGFLLCLK) frequency.
597  *
598  * This function gets the MCG FLL clock frequency in Hz based on the current MCG
599  * register value. The FLL is enabled in FEI/FBI/FEE/FBE mode and
600  * disabled in low power state in other modes.
601  *
602  * return The frequency of MCGFLLCLK.
603  */
CLOCK_GetFllFreq(void)604 uint32_t CLOCK_GetFllFreq(void)
605 {
606     static const uint16_t fllFactorTable[4][2] = {{640, 732}, {1280, 1464}, {1920, 2197}, {2560, 2929}};
607 
608     uint8_t drs, dmx32;
609     uint32_t freq;
610     uint32_t ret;
611 
612     /* If FLL is not enabled currently, then return 0U. */
613     if ((((MCG->C2 & MCG_C2_LP_MASK) != 0U) || ((MCG->S & MCG_S_PLLST_MASK) != 0U)))
614     {
615         ret = 0U;
616     }
617     else
618     {
619         /* Get FLL reference clock frequency. */
620         freq = CLOCK_GetFllRefClkFreq();
621         if (0U == freq)
622         {
623             ret = freq;
624         }
625         else
626         {
627             drs   = MCG_C4_DRST_DRS_VAL;
628             dmx32 = MCG_C4_DMX32_VAL;
629             ret   = freq * fllFactorTable[drs][dmx32];
630         }
631     }
632 
633     return ret;
634 }
635 
636 /*!
637  * brief Gets the MCG internal reference clock (MCGIRCLK) frequency.
638  *
639  * This function gets the MCG internal reference clock frequency in Hz based
640  * on the current MCG register value.
641  *
642  * return The frequency of MCGIRCLK.
643  */
CLOCK_GetInternalRefClkFreq(void)644 uint32_t CLOCK_GetInternalRefClkFreq(void)
645 {
646     uint32_t freq;
647 
648     /* If MCGIRCLK is gated. */
649     if (0U == (MCG->C1 & MCG_C1_IRCLKEN_MASK))
650     {
651         freq = 0U;
652     }
653     else
654     {
655         freq = CLOCK_GetInternalRefClkSelectFreq();
656     }
657 
658     return freq;
659 }
660 
661 /*!
662  * brief Gets the MCG fixed frequency clock (MCGFFCLK) frequency.
663  *
664  * This function gets the MCG fixed frequency clock frequency in Hz based
665  * on the current MCG register value.
666  *
667  * return The frequency of MCGFFCLK.
668  */
CLOCK_GetFixedFreqClkFreq(void)669 uint32_t CLOCK_GetFixedFreqClkFreq(void)
670 {
671     uint32_t freq = CLOCK_GetFllRefClkFreq();
672     uint32_t ret;
673 
674     /* MCGFFCLK must be no more than MCGOUTCLK/8. */
675     if ((freq <= (CLOCK_GetOutClkFreq() / 8U)) && (0U != freq))
676     {
677         ret = freq;
678     }
679     else
680     {
681         ret = 0U;
682     }
683 
684     return ret;
685 }
686 
687 /*!
688  * brief Gets the MCG PLL0 clock (MCGPLL0CLK) frequency.
689  *
690  * This function gets the MCG PLL0 clock frequency in Hz based on the current MCG
691  * register value.
692  *
693  * return The frequency of MCGPLL0CLK.
694  */
CLOCK_GetPll0Freq(void)695 uint32_t CLOCK_GetPll0Freq(void)
696 {
697     uint32_t mcgpll0clk;
698     uint32_t freq;
699 
700     uint8_t mcgpll0prdiv;
701     uint8_t mcgpll0vdiv;
702     /* If PLL0 is not enabled, return 0. */
703     if (((MCG->S & MCG_S_LOCK0_MASK)) == 0U)
704     {
705         freq = 0U;
706     }
707     else
708     {
709         mcgpll0clk = CLOCK_GetPll0RefFreq();
710 
711         /*
712          * Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock.
713          * Please call CLOCK_SetXtal1Freq base on board setting before using OSC1 clock.
714          */
715         assert(mcgpll0clk);
716 
717         mcgpll0prdiv = ((uint8_t)FSL_FEATURE_MCG_PLL_PRDIV_BASE + MCG_C5_PRDIV0_VAL);
718         mcgpll0clk /= (uint32_t)mcgpll0prdiv;
719         mcgpll0vdiv = ((uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE + MCG_C6_VDIV0_VAL);
720         mcgpll0clk *= (uint32_t)mcgpll0vdiv;
721 
722         mcgpll0clk >>= 1UL;
723         freq = mcgpll0clk;
724     }
725 
726     return freq;
727 }
728 
729 /*!
730  * brief Selects the MCG external reference clock.
731  *
732  * Selects the MCG external reference clock source, changes the MCG_C7[OSCSEL],
733  * and waits for the clock source to be stable. Because the external reference
734  * clock should not be changed in FEE/FBE/BLPE/PBE/PEE modes, do not call this function in these modes.
735  *
736  * param oscsel MCG external reference clock source, MCG_C7[OSCSEL].
737  * retval kStatus_MCG_SourceUsed Because the external reference clock is used as a clock source,
738  * the configuration should not be changed. Otherwise, a glitch occurs.
739  * retval kStatus_Success External reference clock set successfully.
740  */
CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)741 status_t CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)
742 {
743 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
744 #endif /* MCG_CONFIG_CHECK_PARAM */
745 
746     return kStatus_Success;
747 }
748 
749 /*!
750  * brief Configures the Internal Reference clock (MCGIRCLK).
751  *
752  * This function sets the \c MCGIRCLK base on parameters. It also selects the IRC
753  * source. If the fast IRC is used, this function sets the fast IRC divider.
754  * This function also sets whether the \c MCGIRCLK is enabled in stop mode.
755  * Calling this function in FBI/PBI/BLPI modes may change the system clock. As a result,
756  * using the function in these modes it is not allowed.
757  *
758  * param enableMode MCGIRCLK enable mode, OR'ed value of ref _mcg_irclk_enable_mode.
759  * param ircs       MCGIRCLK clock source, choose fast or slow.
760  * param fcrdiv     Fast IRC divider setting (\c FCRDIV).
761  * retval kStatus_MCG_SourceUsed Because the internal reference clock is used as a clock source,
762  * the configuration should not be changed. Otherwise, a glitch occurs.
763  * retval kStatus_Success MCGIRCLK configuration finished successfully.
764  */
CLOCK_SetInternalRefClkConfig(uint8_t enableMode,mcg_irc_mode_t ircs,uint8_t fcrdiv)765 status_t CLOCK_SetInternalRefClkConfig(uint8_t enableMode, mcg_irc_mode_t ircs, uint8_t fcrdiv)
766 {
767     uint32_t mcgOutClkState = (uint32_t)MCG_S_CLKST_VAL;
768     mcg_irc_mode_t curIrcs  = (mcg_irc_mode_t)((uint32_t)MCG_S_IRCST_VAL);
769     uint8_t curFcrdiv       = MCG_SC_FCRDIV_VAL;
770 
771 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
772     /* If MCGIRCLK is used as system clock source. */
773     if ((uint32_t)kMCG_ClkOutStatInt == mcgOutClkState)
774     {
775         /* If need to change MCGIRCLK source or driver, return error. */
776         if (((kMCG_IrcFast == curIrcs) && (fcrdiv != curFcrdiv)) || (ircs != curIrcs))
777         {
778             return kStatus_MCG_SourceUsed;
779         }
780     }
781 #endif
782 
783     /* If need to update the FCRDIV. */
784     if (fcrdiv != curFcrdiv)
785     {
786         /* If fast IRC is in use currently, change to slow IRC. */
787         if (((0U != (MCG->C1 & MCG_C1_IRCLKEN_MASK)) || (mcgOutClkState == (uint32_t)kMCG_ClkOutStatInt)) &&
788             (kMCG_IrcFast == curIrcs))
789         {
790             MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(kMCG_IrcSlow)));
791             while (MCG_S_IRCST_VAL != (uint8_t)kMCG_IrcSlow)
792             {
793             }
794         }
795         /* Update FCRDIV. */
796         MCG->SC =
797             (uint8_t)(MCG->SC & ~(MCG_SC_FCRDIV_MASK | MCG_SC_ATMF_MASK | MCG_SC_LOCS0_MASK)) | MCG_SC_FCRDIV(fcrdiv);
798     }
799 
800     /* Set internal reference clock selection. */
801     MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(ircs)));
802     MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_IRCLKEN_MASK | MCG_C1_IREFSTEN_MASK)) | (uint8_t)enableMode);
803 
804     /* If MCGIRCLK is used, need to wait for MCG_S_IRCST. */
805     if ((mcgOutClkState == (uint32_t)kMCG_ClkOutStatInt) || (0U != (enableMode & (uint32_t)kMCG_IrclkEnable)))
806     {
807         while (MCG_S_IRCST_VAL != (uint8_t)ircs)
808         {
809         }
810     }
811 
812     return kStatus_Success;
813 }
814 
815 /*!
816  * brief Calculates the PLL divider setting for a desired output frequency.
817  *
818  * This function calculates the correct reference clock divider (\c PRDIV) and
819  * VCO divider (\c VDIV) to generate a desired PLL output frequency. It returns the
820  * closest frequency match with the corresponding \c PRDIV/VDIV
821  * returned from parameters. If a desired frequency is not valid, this function
822  * returns 0.
823  *
824  * param refFreq    PLL reference clock frequency.
825  * param desireFreq Desired PLL output frequency.
826  * param prdiv      PRDIV value to generate desired PLL frequency.
827  * param vdiv       VDIV value to generate desired PLL frequency.
828  * return Closest frequency match that the PLL was able generate.
829  */
CLOCK_CalcPllDiv(uint32_t refFreq,uint32_t desireFreq,uint8_t * prdiv,uint8_t * vdiv)830 uint32_t CLOCK_CalcPllDiv(uint32_t refFreq, uint32_t desireFreq, uint8_t *prdiv, uint8_t *vdiv)
831 {
832     uint8_t ret_prdiv;               /* PRDIV to return. */
833     uint8_t ret_vdiv;                /* VDIV to return.  */
834     uint8_t prdiv_min;               /* Min PRDIV value to make reference clock in allowed range. */
835     uint8_t prdiv_max;               /* Max PRDIV value to make reference clock in allowed range. */
836     uint8_t prdiv_cur;               /* PRDIV value for iteration.    */
837     uint8_t vdiv_cur;                /* VDIV value for iteration.     */
838     uint32_t ret_freq = 0U;          /* PLL output frequency to return. */
839     uint32_t diff     = 0xFFFFFFFFU; /* Difference between desireFreq and return frequency. */
840     uint32_t ref_div;                /* Reference frequency after PRDIV. */
841 
842     /*
843        Steps:
844        1. Get allowed prdiv with such rules:
845           1). refFreq / prdiv >= FSL_FEATURE_MCG_PLL_REF_MIN.
846           2). refFreq / prdiv <= FSL_FEATURE_MCG_PLL_REF_MAX.
847        2. For each allowed prdiv, there are two candidate vdiv values:
848           1). (desireFreq / (refFreq / prdiv)).
849           2). (desireFreq / (refFreq / prdiv)) + 1.
850           If could get the precise desired frequency, return current prdiv and
851           vdiv directly. Otherwise choose the one which is closer to desired
852           frequency.
853      */
854 
855     /* Reference frequency is out of range. */
856     if ((refFreq < (uint32_t)FSL_FEATURE_MCG_PLL_REF_MIN) ||
857         (refFreq > ((uint32_t)FSL_FEATURE_MCG_PLL_REF_MAX *
858                     ((uint32_t)FSL_FEATURE_MCG_PLL_PRDIV_MAX + (uint32_t)FSL_FEATURE_MCG_PLL_PRDIV_BASE))))
859     {
860         return 0U;
861     }
862 
863     /* refFreq/PRDIV must in a range. First get the allowed PRDIV range. */
864     prdiv_max = (uint8_t)(refFreq / (uint32_t)FSL_FEATURE_MCG_PLL_REF_MIN);
865     prdiv_min =
866         (uint8_t)((refFreq + (uint32_t)FSL_FEATURE_MCG_PLL_REF_MAX - 1U) / (uint32_t)FSL_FEATURE_MCG_PLL_REF_MAX);
867 
868     desireFreq *= 2U;
869 
870     /* PRDIV traversal. */
871     for (prdiv_cur = prdiv_max; prdiv_cur >= prdiv_min; prdiv_cur--)
872     {
873         /* Reference frequency after PRDIV. */
874         ref_div = refFreq / prdiv_cur;
875 
876         vdiv_cur = (uint8_t)(desireFreq / ref_div);
877 
878         if ((vdiv_cur < ((uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE - 1U)) ||
879             (vdiv_cur > (uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE + 31U))
880         {
881             /* No VDIV is available with this PRDIV. */
882             continue;
883         }
884 
885         ret_freq = vdiv_cur * ref_div;
886 
887         if (vdiv_cur >= (uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE)
888         {
889             if (ret_freq == desireFreq) /* If desire frequency is got. */
890             {
891                 *prdiv = prdiv_cur - (uint8_t)FSL_FEATURE_MCG_PLL_PRDIV_BASE;
892                 *vdiv  = vdiv_cur - (uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE;
893                 return ret_freq / 2U;
894             }
895             /* New PRDIV/VDIV is closer. */
896             if (diff > desireFreq - ret_freq)
897             {
898                 diff      = desireFreq - ret_freq;
899                 ret_prdiv = prdiv_cur;
900                 ret_vdiv  = vdiv_cur;
901             }
902         }
903         vdiv_cur++;
904         if (vdiv_cur <= ((uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE + 31U))
905         {
906             ret_freq += ref_div;
907             /* New PRDIV/VDIV is closer. */
908             if (diff > ret_freq - desireFreq)
909             {
910                 diff      = ret_freq - desireFreq;
911                 ret_prdiv = prdiv_cur;
912                 ret_vdiv  = vdiv_cur;
913             }
914         }
915     }
916 
917     if (0xFFFFFFFFU != diff)
918     {
919         /* PRDIV/VDIV found. */
920         *prdiv   = ret_prdiv - (uint8_t)FSL_FEATURE_MCG_PLL_PRDIV_BASE;
921         *vdiv    = ret_vdiv - (uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE;
922         ret_freq = (refFreq / ret_prdiv) * ret_vdiv;
923         return ret_freq / 2U;
924     }
925     else
926     {
927         /* No proper PRDIV/VDIV found. */
928         return 0U;
929     }
930 }
931 
932 /*!
933  * brief Enables the PLL0 in FLL mode.
934  *
935  * This function sets us the PLL0 in FLL mode and reconfigures
936  * the PLL0. Ensure that the PLL reference
937  * clock is enabled before calling this function and that the PLL0 is not used as a clock source.
938  * The function CLOCK_CalcPllDiv gets the correct PLL
939  * divider values.
940  *
941  * param config Pointer to the configuration structure.
942  */
CLOCK_EnablePll0(mcg_pll_config_t const * config)943 void CLOCK_EnablePll0(mcg_pll_config_t const *config)
944 {
945     assert(config);
946 
947     uint8_t mcg_c5 = 0U;
948 
949     mcg_c5 |= MCG_C5_PRDIV0(config->prdiv);
950     MCG->C5 = mcg_c5; /* Disable the PLL first. */
951 
952     MCG->C6 = (uint8_t)((MCG->C6 & ~MCG_C6_VDIV0_MASK) | MCG_C6_VDIV0(config->vdiv));
953 
954     /* Set enable mode. */
955     MCG->C5 |= ((uint8_t)kMCG_PllEnableIndependent | (uint8_t)config->enableMode);
956 
957     /* Wait for PLL lock. */
958     while (((MCG->S & MCG_S_LOCK0_MASK)) == 0U)
959     {
960     }
961 }
962 
963 /*!
964  * brief Sets the OSC0 clock monitor mode.
965  *
966  * This function sets the OSC0 clock monitor mode. See ref mcg_monitor_mode_t for details.
967  *
968  * param mode Monitor mode to set.
969  */
CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)970 void CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)
971 {
972     /* Clear the previous flag, MCG_SC[LOCS0]. */
973     MCG->SC &= ~(uint8_t)MCG_SC_ATMF_MASK;
974 
975     if (kMCG_MonitorNone == mode)
976     {
977         MCG->C6 &= ~(uint8_t)MCG_C6_CME0_MASK;
978     }
979     else
980     {
981         if (kMCG_MonitorInt == mode)
982         {
983             MCG->C2 &= ~(uint8_t)MCG_C2_LOCRE0_MASK;
984         }
985         else
986         {
987             MCG->C2 |= MCG_C2_LOCRE0_MASK;
988         }
989         MCG->C6 |= MCG_C6_CME0_MASK;
990     }
991 }
992 
993 /*!
994  * brief Sets the PLL0 clock monitor mode.
995  *
996  * This function sets the PLL0 clock monitor mode. See ref mcg_monitor_mode_t for details.
997  *
998  * param mode Monitor mode to set.
999  */
CLOCK_SetPll0MonitorMode(mcg_monitor_mode_t mode)1000 void CLOCK_SetPll0MonitorMode(mcg_monitor_mode_t mode)
1001 {
1002     uint8_t mcg_c8;
1003 
1004     /* Clear previous flag. */
1005     MCG->S = MCG_S_LOLS0_MASK;
1006 
1007     if (kMCG_MonitorNone == mode)
1008     {
1009         MCG->C6 &= (uint8_t)(~MCG_C6_LOLIE0_MASK);
1010     }
1011     else
1012     {
1013         mcg_c8 = MCG->C8;
1014 
1015         if (kMCG_MonitorInt == mode)
1016         {
1017             mcg_c8 &= (uint8_t)(~MCG_C8_LOLRE_MASK);
1018         }
1019         else
1020         {
1021             mcg_c8 |= MCG_C8_LOLRE_MASK;
1022         }
1023         MCG->C8 = mcg_c8;
1024         MCG->C6 |= MCG_C6_LOLIE0_MASK;
1025     }
1026 }
1027 
1028 /*!
1029  * brief Gets the MCG status flags.
1030  *
1031  * This function gets the MCG clock status flags. All status flags are
1032  * returned as a logical OR of the enumeration ref _mcg_status_flags_t. To
1033  * check a specific flag, compare the return value with the flag.
1034  *
1035  * Example:
1036  * code
1037  * To check the clock lost lock status of OSC0 and PLL0.
1038  * uint32_t mcgFlags;
1039  *
1040  * mcgFlags = CLOCK_GetStatusFlags();
1041  *
1042  * if (mcgFlags & kMCG_Osc0LostFlag)
1043  * {
1044  *     OSC0 clock lock lost. Do something.
1045  * }
1046  * if (mcgFlags & kMCG_Pll0LostFlag)
1047  * {
1048  *     PLL0 clock lock lost. Do something.
1049  * }
1050  * endcode
1051  *
1052  * return  Logical OR value of the ref _mcg_status_flags_t.
1053  */
CLOCK_GetStatusFlags(void)1054 uint32_t CLOCK_GetStatusFlags(void)
1055 {
1056     uint32_t ret  = 0U;
1057     uint8_t mcg_s = MCG->S;
1058 
1059     if ((MCG->SC & MCG_SC_LOCS0_MASK) != 0U)
1060     {
1061         ret |= (uint32_t)kMCG_Osc0LostFlag;
1062     }
1063     if ((mcg_s & MCG_S_OSCINIT0_MASK) != 0U)
1064     {
1065         ret |= (uint32_t)kMCG_Osc0InitFlag;
1066     }
1067     if ((mcg_s & MCG_S_LOLS0_MASK) != 0U)
1068     {
1069         ret |= (uint32_t)kMCG_Pll0LostFlag;
1070     }
1071     if ((mcg_s & MCG_S_LOCK0_MASK) != 0U)
1072     {
1073         ret |= (uint32_t)kMCG_Pll0LockFlag;
1074     }
1075     return ret;
1076 }
1077 
1078 /*!
1079  * brief Clears the MCG status flags.
1080  *
1081  * This function clears the MCG clock lock lost status. The parameter is a logical
1082  * OR value of the flags to clear. See ref _mcg_status_flags_t.
1083  *
1084  * Example:
1085  * code
1086  * To clear the clock lost lock status flags of OSC0 and PLL0.
1087  *
1088  * CLOCK_ClearStatusFlags(kMCG_Osc0LostFlag | kMCG_Pll0LostFlag);
1089  * endcode
1090  *
1091  * param mask The status flags to clear. This is a logical OR of members of the
1092  *             enumeration ref _mcg_status_flags_t.
1093  */
CLOCK_ClearStatusFlags(uint32_t mask)1094 void CLOCK_ClearStatusFlags(uint32_t mask)
1095 {
1096     if ((mask & (uint32_t)kMCG_Osc0LostFlag) != 0UL)
1097     {
1098         MCG->SC &= (uint8_t)(~MCG_SC_ATMF_MASK);
1099     }
1100     if ((mask & (uint32_t)kMCG_Pll0LostFlag) != 0UL)
1101     {
1102         MCG->S = MCG_S_LOLS0_MASK;
1103     }
1104 }
1105 
1106 /*!
1107  * brief Initializes the OSC0.
1108  *
1109  * This function initializes the OSC0 according to the board configuration.
1110  *
1111  * param  config Pointer to the OSC0 configuration structure.
1112  */
CLOCK_InitOsc0(osc_config_t const * config)1113 void CLOCK_InitOsc0(osc_config_t const *config)
1114 {
1115     uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
1116 
1117     OSC_SetCapLoad(OSC0, config->capLoad);
1118 
1119     MCG->C2 = (uint8_t)((MCG->C2 & ~OSC_MODE_MASK) | MCG_C2_RANGE(range) | (uint8_t)config->workMode);
1120     OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig);
1121 
1122     if ((kOSC_ModeExt != config->workMode) && ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U))
1123     {
1124         /* Wait for stable. */
1125         while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1126         {
1127         }
1128     }
1129 }
1130 
1131 /*!
1132  * brief Deinitializes the OSC0.
1133  *
1134  * This function deinitializes the OSC0.
1135  */
CLOCK_DeinitOsc0(void)1136 void CLOCK_DeinitOsc0(void)
1137 {
1138     OSC0->CR = 0U;
1139     MCG->C2 &= ~(uint8_t)OSC_MODE_MASK;
1140 }
1141 
1142 /*!
1143  * brief Set the Slow IRC frequency based on the trimmed value
1144  *
1145  * param freq The Slow IRC frequency input clock frequency in Hz.
1146  */
CLOCK_SetSlowIrcFreq(uint32_t freq)1147 void CLOCK_SetSlowIrcFreq(uint32_t freq)
1148 {
1149     s_slowIrcFreq = freq;
1150 }
1151 
1152 /*!
1153  * brief Set the Fast IRC frequency based on the trimmed value
1154  *
1155  * param freq The Fast IRC frequency input clock frequency in Hz.
1156  */
CLOCK_SetFastIrcFreq(uint32_t freq)1157 void CLOCK_SetFastIrcFreq(uint32_t freq)
1158 {
1159     s_fastIrcFreq = freq;
1160 }
1161 
1162 /*!
1163  * brief Auto trims the internal reference clock.
1164  *
1165  * This function trims the internal reference clock by using the external clock. If
1166  * successful, it returns the kStatus_Success and the frequency after
1167  * trimming is received in the parameter p actualFreq. If an error occurs,
1168  * the error code is returned.
1169  *
1170  * param extFreq      External clock frequency, which should be a bus clock.
1171  * param desireFreq   Frequency to trim to.
1172  * param actualFreq   Actual frequency after trimming.
1173  * param atms         Trim fast or slow internal reference clock.
1174  * retval kStatus_Success ATM success.
1175  * retval kStatus_MCG_AtmBusClockInvalid The bus clock is not in allowed range for the ATM.
1176  * retval kStatus_MCG_AtmDesiredFreqInvalid MCGIRCLK could not be trimmed to the desired frequency.
1177  * retval kStatus_MCG_AtmIrcUsed Could not trim because MCGIRCLK is used as a bus clock source.
1178  * retval kStatus_MCG_AtmHardwareFail Hardware fails while trimming.
1179  */
CLOCK_TrimInternalRefClk(uint32_t extFreq,uint32_t desireFreq,uint32_t * actualFreq,mcg_atm_select_t atms)1180 status_t CLOCK_TrimInternalRefClk(uint32_t extFreq, uint32_t desireFreq, uint32_t *actualFreq, mcg_atm_select_t atms)
1181 {
1182     uint32_t multi; /* extFreq / desireFreq */
1183     uint32_t actv;  /* Auto trim value. */
1184     uint8_t mcg_sc;
1185     status_t status = kStatus_Success;
1186 
1187     static const uint32_t trimRange[2][2] = {
1188         /*     Min           Max      */
1189         {TRIM_SIRC_MIN, TRIM_SIRC_MAX}, /* Slow IRC. */
1190         {TRIM_FIRC_MIN, TRIM_FIRC_MAX}  /* Fast IRC. */
1191     };
1192 
1193     if ((extFreq > TRIM_REF_CLK_MAX) || (extFreq < TRIM_REF_CLK_MIN))
1194     {
1195         status = kStatus_MCG_AtmBusClockInvalid;
1196     }
1197     /* Check desired frequency range. */
1198     else if ((desireFreq < trimRange[atms][0]) || (desireFreq > trimRange[atms][1]))
1199     {
1200         status = kStatus_MCG_AtmDesiredFreqInvalid;
1201     }
1202     /*
1203        Make sure internal reference clock is not used to generate bus clock.
1204        Here only need to check (MCG_S_IREFST == 1).
1205      */
1206     else if (MCG_S_IREFST(kMCG_FllSrcInternal) == (MCG->S & MCG_S_IREFST_MASK))
1207     {
1208         status = kStatus_MCG_AtmIrcUsed;
1209     }
1210     else
1211     {
1212         multi = extFreq / desireFreq;
1213         actv  = multi * 21U;
1214 
1215         if (kMCG_AtmSel4m == atms)
1216         {
1217             actv *= 128U;
1218         }
1219 
1220         /* Now begin to start trim. */
1221         MCG->ATCVL = (uint8_t)actv;
1222         MCG->ATCVH = (uint8_t)(actv >> 8U);
1223 
1224         mcg_sc = MCG->SC;
1225         mcg_sc &= ~(uint8_t)(MCG_SC_ATMS_MASK | MCG_SC_LOCS0_MASK);
1226         mcg_sc |= (MCG_SC_ATMF_MASK | MCG_SC_ATMS(atms));
1227         MCG->SC = (mcg_sc | MCG_SC_ATME_MASK);
1228 
1229         /* Wait for MCG finished. */
1230         while (0U != (MCG->SC & MCG_SC_ATME_MASK))
1231         {
1232         }
1233 
1234         /* Error occurs? */
1235         if (0U != (MCG->SC & MCG_SC_ATMF_MASK))
1236         {
1237             /* Clear the failed flag. */
1238             MCG->SC = mcg_sc;
1239             status  = kStatus_MCG_AtmHardwareFail;
1240         }
1241         else
1242         {
1243             *actualFreq = extFreq / multi;
1244 
1245             if (kMCG_AtmSel4m == atms)
1246             {
1247                 s_fastIrcFreq = *actualFreq;
1248             }
1249             else
1250             {
1251                 s_slowIrcFreq = *actualFreq;
1252             }
1253         }
1254     }
1255 
1256     return status;
1257 }
1258 
1259 /*!
1260  * brief Gets the current MCG mode.
1261  *
1262  * This function checks the MCG registers and determines the current MCG mode.
1263  *
1264  * return Current MCG mode or error code; See ref mcg_mode_t.
1265  */
CLOCK_GetMode(void)1266 mcg_mode_t CLOCK_GetMode(void)
1267 {
1268     mcg_mode_t mode = kMCG_ModeError;
1269     uint32_t clkst  = (uint32_t)MCG_S_CLKST_VAL;
1270     uint32_t irefst = (uint32_t)MCG_S_IREFST_VAL;
1271     uint32_t lp     = (uint32_t)MCG_C2_LP_VAL;
1272     uint32_t pllst  = MCG_S_PLLST_VAL;
1273 
1274     /*------------------------------------------------------------------
1275                            Mode and Registers
1276     ____________________________________________________________________
1277 
1278       Mode   |   CLKST    |   IREFST   |   PLLST   |      LP
1279     ____________________________________________________________________
1280 
1281       FEI    |  00(FLL)   |   1(INT)   |   0(FLL)  |      X
1282     ____________________________________________________________________
1283 
1284       FEE    |  00(FLL)   |   0(EXT)   |   0(FLL)  |      X
1285     ____________________________________________________________________
1286 
1287       FBE    |  10(EXT)   |   0(EXT)   |   0(FLL)  |   0(NORMAL)
1288     ____________________________________________________________________
1289 
1290       FBI    |  01(INT)   |   1(INT)   |   0(FLL)  |   0(NORMAL)
1291     ____________________________________________________________________
1292 
1293       BLPI   |  01(INT)   |   1(INT)   |   0(FLL)  |   1(LOW POWER)
1294     ____________________________________________________________________
1295 
1296       BLPE   |  10(EXT)   |   0(EXT)   |     X     |   1(LOW POWER)
1297     ____________________________________________________________________
1298 
1299       PEE    |  11(PLL)   |   0(EXT)   |   1(PLL)  |      X
1300     ____________________________________________________________________
1301 
1302       PBE    |  10(EXT)   |   0(EXT)   |   1(PLL)  |   O(NORMAL)
1303     ____________________________________________________________________
1304 
1305       PBI    |  01(INT)   |   1(INT)   |   1(PLL)  |   0(NORMAL)
1306     ____________________________________________________________________
1307 
1308       PEI    |  11(PLL)   |   1(INT)   |   1(PLL)  |      X
1309     ____________________________________________________________________
1310 
1311     ----------------------------------------------------------------------*/
1312 
1313     if (clkst == (uint32_t)kMCG_ClkOutStatFll)
1314     {
1315         if ((uint32_t)kMCG_FllSrcExternal == irefst)
1316         {
1317             mode = kMCG_ModeFEE;
1318         }
1319         else
1320         {
1321             mode = kMCG_ModeFEI;
1322         }
1323     }
1324     else if (clkst == (uint32_t)kMCG_ClkOutStatInt)
1325     {
1326         if (0U != lp)
1327         {
1328             mode = kMCG_ModeBLPI;
1329         }
1330         else
1331         {
1332             {
1333                 mode = kMCG_ModeFBI;
1334             }
1335         }
1336     }
1337     else if (clkst == (uint32_t)kMCG_ClkOutStatExt)
1338     {
1339         if (0U != lp)
1340         {
1341             mode = kMCG_ModeBLPE;
1342         }
1343         else
1344         {
1345             if ((uint32_t)kMCG_PllstPll == pllst)
1346             {
1347                 mode = kMCG_ModePBE;
1348             }
1349             else
1350             {
1351                 mode = kMCG_ModeFBE;
1352             }
1353         }
1354     }
1355     else if (clkst == (uint32_t)kMCG_ClkOutStatPll)
1356     {
1357         {
1358             mode = kMCG_ModePEE;
1359         }
1360     }
1361     else
1362     {
1363         /*do nothing*/
1364     }
1365 
1366     return mode;
1367 }
1368 
1369 /*!
1370  * brief Sets the MCG to FEI mode.
1371  *
1372  * This function sets the MCG to FEI mode. If setting to FEI mode fails
1373  * from the current mode, this function returns an error.
1374  *
1375  * param       dmx32  DMX32 in FEI mode.
1376  * param       drs The DCO range selection.
1377  * param       fllStableDelay Delay function to  ensure that the FLL is stable. Passing
1378  *              NULL does not cause a delay.
1379  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1380  * retval kStatus_Success Switched to the target mode successfully.
1381  * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1382  * to a frequency above 32768 Hz.
1383  */
CLOCK_SetFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1384 status_t CLOCK_SetFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1385 {
1386     uint8_t mcg_c4;
1387     bool change_drs = false;
1388 
1389 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1390     mcg_mode_t mode = CLOCK_GetMode();
1391     if (!((kMCG_ModeFEI == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEE == mode)))
1392     {
1393         return kStatus_MCG_ModeUnreachable;
1394     }
1395 #endif
1396     mcg_c4 = MCG->C4;
1397 
1398     /*
1399        Errata: ERR007993
1400        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1401        reference clock source changes, then reset to previous value after
1402        reference clock changes.
1403      */
1404     if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1405     {
1406         change_drs = true;
1407         /* Change the LSB of DRST_DRS. */
1408         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1409     }
1410 
1411     /* Set CLKS and IREFS. */
1412     MCG->C1 = (uint8_t)(((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK))) |
1413                         (MCG_C1_CLKS(kMCG_ClkOutSrcOut)         /* CLKS = 0 */
1414                          | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1415 
1416     /* Wait and check status. */
1417     while ((uint8_t)kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1418     {
1419     }
1420 
1421     /* Errata: ERR007993 */
1422     if (change_drs)
1423     {
1424         MCG->C4 = mcg_c4;
1425     }
1426 
1427     /* In FEI mode, the MCG_C4[DMX32] is set to 0U. */
1428     MCG->C4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1429                         (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1430 
1431     /* Check MCG_S[CLKST] */
1432     while ((uint8_t)kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1433     {
1434     }
1435 
1436     /* Wait for FLL stable time. */
1437     if (NULL != fllStableDelay)
1438     {
1439         fllStableDelay();
1440     }
1441 
1442     return kStatus_Success;
1443 }
1444 
1445 /*!
1446  * brief Sets the MCG to FEE mode.
1447  *
1448  * This function sets the MCG to FEE mode. If setting to FEE mode fails
1449  * from the current mode, this function returns an error.
1450  *
1451  * param   frdiv  FLL reference clock divider setting, FRDIV.
1452  * param   dmx32  DMX32 in FEE mode.
1453  * param   drs    The DCO range selection.
1454  * param   fllStableDelay Delay function to make sure FLL is stable. Passing
1455  *          NULL does not cause a delay.
1456  *
1457  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1458  * retval kStatus_Success Switched to the target mode successfully.
1459  */
CLOCK_SetFeeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1460 status_t CLOCK_SetFeeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1461 {
1462     uint8_t mcg_c4;
1463     bool change_drs = false;
1464 
1465 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1466     mcg_mode_t mode = CLOCK_GetMode();
1467     if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode)))
1468     {
1469         return kStatus_MCG_ModeUnreachable;
1470     }
1471 #endif
1472     mcg_c4 = MCG->C4;
1473 
1474     /*
1475        Errata: ERR007993
1476        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1477        reference clock source changes, then reset to previous value after
1478        reference clock changes.
1479      */
1480     if ((uint8_t)kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1481     {
1482         change_drs = true;
1483         /* Change the LSB of DRST_DRS. */
1484         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1485     }
1486 
1487     /* Set CLKS and IREFS. */
1488     MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1489                         (MCG_C1_CLKS(kMCG_ClkOutSrcOut)         /* CLKS = 0 */
1490                          | MCG_C1_FRDIV(frdiv)                  /* FRDIV */
1491                          | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1492 
1493     /* If use external crystal as clock source, wait for it stable. */
1494     {
1495         if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1496         {
1497             while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1498             {
1499             }
1500         }
1501     }
1502 
1503     /* Wait and check status. */
1504     while ((uint8_t)kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1505     {
1506     }
1507 
1508     /* Errata: ERR007993 */
1509     if (change_drs)
1510     {
1511         MCG->C4 = mcg_c4;
1512     }
1513 
1514     /* Set DRS and DMX32. */
1515     mcg_c4  = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1516                        (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1517     MCG->C4 = mcg_c4;
1518 
1519     /* Wait for DRST_DRS update. */
1520     while (MCG->C4 != mcg_c4)
1521     {
1522     }
1523 
1524     /* Check MCG_S[CLKST] */
1525     while ((uint8_t)kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1526     {
1527     }
1528 
1529     /* Wait for FLL stable time. */
1530     if (NULL != fllStableDelay)
1531     {
1532         fllStableDelay();
1533     }
1534 
1535     return kStatus_Success;
1536 }
1537 
1538 /*!
1539  * brief Sets the MCG to FBI mode.
1540  *
1541  * This function sets the MCG to FBI mode. If setting to FBI mode fails
1542  * from the current mode, this function returns an error.
1543  *
1544  * param  dmx32  DMX32 in FBI mode.
1545  * param  drs  The DCO range selection.
1546  * param  fllStableDelay Delay function to make sure FLL is stable. If the FLL
1547  *         is not used in FBI mode, this parameter can be NULL. Passing
1548  *         NULL does not cause a delay.
1549  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1550  * retval kStatus_Success Switched to the target mode successfully.
1551  * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1552  * to frequency above 32768 Hz.
1553  */
CLOCK_SetFbiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1554 status_t CLOCK_SetFbiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1555 {
1556     uint8_t mcg_c4;
1557     bool change_drs = false;
1558 
1559 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1560     mcg_mode_t mode = CLOCK_GetMode();
1561 
1562     if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1563           (kMCG_ModeBLPI == mode)))
1564 
1565     {
1566         return kStatus_MCG_ModeUnreachable;
1567     }
1568 #endif
1569 
1570     mcg_c4 = MCG->C4;
1571 
1572     MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK; /* Disable lowpower. */
1573 
1574     /*
1575        Errata: ERR007993
1576        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1577        reference clock source changes, then reset to previous value after
1578        reference clock changes.
1579      */
1580     if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1581     {
1582         change_drs = true;
1583         /* Change the LSB of DRST_DRS. */
1584         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1585     }
1586 
1587     /* Set CLKS and IREFS. */
1588     MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) |
1589                         (MCG_C1_CLKS(kMCG_ClkOutSrcInternal)    /* CLKS = 1 */
1590                          | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1591 
1592     /* Wait and check status. */
1593     while ((uint8_t)kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1594     {
1595     }
1596 
1597     /* Errata: ERR007993 */
1598     if (change_drs)
1599     {
1600         MCG->C4 = mcg_c4;
1601     }
1602 
1603     while ((uint8_t)kMCG_ClkOutStatInt != MCG_S_CLKST_VAL)
1604     {
1605     }
1606 
1607     MCG->C4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1608                         (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1609 
1610     /* Wait for FLL stable time. */
1611     if (NULL != fllStableDelay)
1612     {
1613         fllStableDelay();
1614     }
1615 
1616     return kStatus_Success;
1617 }
1618 
1619 /*!
1620  * brief Sets the MCG to FBE mode.
1621  *
1622  * This function sets the MCG to FBE mode. If setting to FBE mode fails
1623  * from the current mode, this function returns an error.
1624  *
1625  * param   frdiv  FLL reference clock divider setting, FRDIV.
1626  * param   dmx32  DMX32 in FBE mode.
1627  * param   drs    The DCO range selection.
1628  * param   fllStableDelay Delay function to make sure FLL is stable. If the FLL
1629  *          is not used in FBE mode, this parameter can be NULL. Passing NULL
1630  *          does not cause a delay.
1631  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1632  * retval kStatus_Success Switched to the target mode successfully.
1633  */
CLOCK_SetFbeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1634 status_t CLOCK_SetFbeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1635 {
1636     uint8_t mcg_c4;
1637     bool change_drs = false;
1638 
1639 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1640     mcg_mode_t mode = CLOCK_GetMode();
1641     if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1642           (kMCG_ModePBE == mode) || (kMCG_ModeBLPE == mode)))
1643     {
1644         return kStatus_MCG_ModeUnreachable;
1645     }
1646 #endif
1647 
1648     /* Change to FLL mode. */
1649     MCG->C6 &= ~(uint8_t)MCG_C6_PLLS_MASK;
1650     while ((MCG->S & MCG_S_PLLST_MASK) != 0U)
1651     {
1652     }
1653 
1654     /* Set LP bit to enable the FLL */
1655     MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
1656 
1657     mcg_c4 = MCG->C4;
1658 
1659     /*
1660        Errata: ERR007993
1661        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1662        reference clock source changes, then reset to previous value after
1663        reference clock changes.
1664      */
1665     if ((uint8_t)kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1666     {
1667         change_drs = true;
1668         /* Change the LSB of DRST_DRS. */
1669         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1670     }
1671 
1672     /* Set CLKS and IREFS. */
1673     MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1674                         (MCG_C1_CLKS(kMCG_ClkOutSrcExternal)    /* CLKS = 2 */
1675                          | MCG_C1_FRDIV(frdiv)                  /* FRDIV = frdiv */
1676                          | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1677 
1678     /* If use external crystal as clock source, wait for it stable. */
1679     {
1680         if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1681         {
1682             while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1683             {
1684             }
1685         }
1686     }
1687 
1688     /* Wait for Reference clock Status bit to clear */
1689     while ((uint8_t)kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1690     {
1691     }
1692 
1693     /* Errata: ERR007993 */
1694     if (change_drs)
1695     {
1696         MCG->C4 = mcg_c4;
1697     }
1698 
1699     /* Set DRST_DRS and DMX32. */
1700     mcg_c4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1701                        (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1702 
1703     /* Wait for clock status bits to show clock source is ext ref clk */
1704     while ((uint8_t)kMCG_ClkOutStatExt != MCG_S_CLKST_VAL)
1705     {
1706     }
1707 
1708     /* Wait for fll stable time. */
1709     if (NULL != fllStableDelay)
1710     {
1711         fllStableDelay();
1712     }
1713 
1714     return kStatus_Success;
1715 }
1716 
1717 /*!
1718  * brief Sets the MCG to BLPI mode.
1719  *
1720  * This function sets the MCG to BLPI mode. If setting to BLPI mode fails
1721  * from the current mode, this function returns an error.
1722  *
1723  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1724  * retval kStatus_Success Switched to the target mode successfully.
1725  */
CLOCK_SetBlpiMode(void)1726 status_t CLOCK_SetBlpiMode(void)
1727 {
1728 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1729     if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1730     {
1731         return kStatus_MCG_ModeUnreachable;
1732     }
1733 #endif /* MCG_CONFIG_CHECK_PARAM */
1734 
1735     /* Set LP. */
1736     MCG->C2 |= MCG_C2_LP_MASK;
1737 
1738     return kStatus_Success;
1739 }
1740 
1741 /*!
1742  * brief Sets the MCG to BLPE mode.
1743  *
1744  * This function sets the MCG to BLPE mode. If setting to BLPE mode fails
1745  * from the current mode, this function returns an error.
1746  *
1747  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1748  * retval kStatus_Success Switched to the target mode successfully.
1749  */
CLOCK_SetBlpeMode(void)1750 status_t CLOCK_SetBlpeMode(void)
1751 {
1752 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1753     if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
1754     {
1755         return kStatus_MCG_ModeUnreachable;
1756     }
1757 #endif
1758 
1759     /* Set LP bit to enter BLPE mode. */
1760     MCG->C2 |= MCG_C2_LP_MASK;
1761 
1762     return kStatus_Success;
1763 }
1764 
1765 /*!
1766  * brief Sets the MCG to PBE mode.
1767  *
1768  * This function sets the MCG to PBE mode. If setting to PBE mode fails
1769  * from the current mode, this function returns an error.
1770  *
1771  * param   pllcs  The PLL selection, PLLCS.
1772  * param   config Pointer to the PLL configuration.
1773  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1774  * retval kStatus_Success Switched to the target mode successfully.
1775  *
1776  * note
1777  * 1. The parameter \c pllcs selects the PLL. For platforms with
1778  * only one PLL, the parameter pllcs is kept for interface compatibility.
1779  * 2. The parameter \c config is the PLL configuration structure. On some
1780  * platforms,  it is possible to choose the external PLL directly, which renders the
1781  * configuration structure not necessary. In this case, pass in NULL.
1782  * For example: CLOCK_SetPbeMode(kMCG_OscselOsc, kMCG_PllClkSelExtPll, NULL);
1783  */
CLOCK_SetPbeMode(mcg_pll_clk_select_t pllcs,mcg_pll_config_t const * config)1784 status_t CLOCK_SetPbeMode(mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
1785 {
1786     assert(config);
1787 
1788     /*
1789        This function is designed to change MCG to PBE mode from PEE/BLPE/FBE,
1790        but with this workflow, the source mode could be all modes except PEI/PBI.
1791      */
1792     MCG->C2 &= (uint8_t)(~MCG_C2_LP_MASK); /* Disable lowpower. */
1793 
1794     /* Change to use external clock first. */
1795     MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
1796 
1797     /* Wait for CLKST clock status bits to show clock source is ext ref clk */
1798     while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
1799            (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
1800     {
1801     }
1802 
1803     /* Disable PLL first, then configure PLL. */
1804     MCG->C6 &= (uint8_t)(~MCG_C6_PLLS_MASK);
1805     while ((MCG->S & MCG_S_PLLST_MASK) != 0U)
1806     {
1807     }
1808 
1809     /* Configure the PLL. */
1810     {
1811         CLOCK_EnablePll0(config);
1812     }
1813 
1814     /* Change to PLL mode. */
1815     MCG->C6 |= MCG_C6_PLLS_MASK;
1816 
1817     /* Wait for PLL mode changed. */
1818     while (((MCG->S & MCG_S_PLLST_MASK)) == 0U)
1819     {
1820     }
1821 
1822     return kStatus_Success;
1823 }
1824 
1825 /*!
1826  * brief Sets the MCG to PEE mode.
1827  *
1828  * This function sets the MCG to PEE mode.
1829  *
1830  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1831  * retval kStatus_Success Switched to the target mode successfully.
1832  *
1833  * note This function only changes the CLKS to use the PLL/FLL output. If the
1834  *       PRDIV/VDIV are different than in the PBE mode, set them up
1835  *       in PBE mode and wait. When the clock is stable, switch to PEE mode.
1836  */
CLOCK_SetPeeMode(void)1837 status_t CLOCK_SetPeeMode(void)
1838 {
1839 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1840     mcg_mode_t mode = CLOCK_GetMode();
1841     if (kMCG_ModePBE != mode)
1842     {
1843         return kStatus_MCG_ModeUnreachable;
1844     }
1845 #endif
1846 
1847     /* Change to use PLL/FLL output clock first. */
1848     MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut));
1849 
1850     /* Wait for clock status bits to update */
1851     while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatPll)
1852     {
1853     }
1854 
1855     return kStatus_Success;
1856 }
1857 
1858 /*!
1859  * brief Switches the MCG to FBE mode from the external mode.
1860  *
1861  * This function switches the MCG from external modes (PEE/PBE/BLPE/FEE) to the FBE mode quickly.
1862  * The external clock is used as the system clock source and PLL is disabled. However,
1863  * the FLL settings are not configured. This is a lite function with a small code size, which is useful
1864  * during the mode switch. For example, to switch from PEE mode to FEI mode:
1865  *
1866  * code
1867  * CLOCK_ExternalModeToFbeModeQuick();
1868  * CLOCK_SetFeiMode(...);
1869  * endcode
1870  *
1871  * retval kStatus_Success Switched successfully.
1872  * retval kStatus_MCG_ModeInvalid If the current mode is not an external mode, do not call this function.
1873  */
CLOCK_ExternalModeToFbeModeQuick(void)1874 status_t CLOCK_ExternalModeToFbeModeQuick(void)
1875 {
1876 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1877     if ((MCG->S & MCG_S_IREFST_MASK) != 0U)
1878     {
1879         return kStatus_MCG_ModeInvalid;
1880     }
1881 #endif /* MCG_CONFIG_CHECK_PARAM */
1882 
1883     /* Disable low power */
1884     MCG->C2 &= (uint8_t)(~MCG_C2_LP_MASK);
1885 
1886     MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
1887     while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
1888     {
1889     }
1890 
1891     /* Disable PLL. */
1892     MCG->C6 &= ~(uint8_t)MCG_C6_PLLS_MASK;
1893     while ((MCG->S & MCG_S_PLLST_MASK) != 0U)
1894     {
1895     }
1896 
1897     return kStatus_Success;
1898 }
1899 
1900 /*!
1901  * brief Switches the MCG to FBI mode from internal modes.
1902  *
1903  * This function switches the MCG from internal modes (PEI/PBI/BLPI/FEI) to the FBI mode quickly.
1904  * The MCGIRCLK is used as the system clock source and PLL is disabled. However,
1905  * FLL settings are not configured. This is a lite function with a small code size, which is useful
1906  * during the mode switch. For example, to switch from PEI mode to FEE mode:
1907  *
1908  * code
1909  * CLOCK_InternalModeToFbiModeQuick();
1910  * CLOCK_SetFeeMode(...);
1911  * endcode
1912  *
1913  * retval kStatus_Success Switched successfully.
1914  * retval kStatus_MCG_ModeInvalid If the current mode is not an internal mode, do not call this function.
1915  */
CLOCK_InternalModeToFbiModeQuick(void)1916 status_t CLOCK_InternalModeToFbiModeQuick(void)
1917 {
1918 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1919     if ((MCG->S & MCG_S_IREFST_MASK) == 0U)
1920     {
1921         return kStatus_MCG_ModeInvalid;
1922     }
1923 #endif
1924 
1925     /* Disable low power */
1926     MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
1927 
1928     MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
1929     while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1930     {
1931     }
1932 
1933     return kStatus_Success;
1934 }
1935 
1936 /*!
1937  * brief Sets the MCG to FEI mode during system boot up.
1938  *
1939  * This function sets the MCG to FEI mode from the reset mode. It can also be used to
1940  * set up MCG during system boot up.
1941  *
1942  * param  dmx32  DMX32 in FEI mode.
1943  * param  drs The DCO range selection.
1944  * param  fllStableDelay Delay function to ensure that the FLL is stable.
1945  *
1946  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1947  * retval kStatus_Success Switched to the target mode successfully.
1948  * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1949  * to frequency above 32768 Hz.
1950  */
CLOCK_BootToFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1951 status_t CLOCK_BootToFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1952 {
1953     return CLOCK_SetFeiMode(dmx32, drs, fllStableDelay);
1954 }
1955 
1956 /*!
1957  * brief Sets the MCG to FEE mode during system bootup.
1958  *
1959  * This function sets MCG to FEE mode from the reset mode. It can also be used to
1960  * set up the MCG during system boot up.
1961  *
1962  * param   oscsel OSC clock select, OSCSEL.
1963  * param   frdiv  FLL reference clock divider setting, FRDIV.
1964  * param   dmx32  DMX32 in FEE mode.
1965  * param   drs    The DCO range selection.
1966  * param   fllStableDelay Delay function to ensure that the FLL is stable.
1967  *
1968  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1969  * retval kStatus_Success Switched to the target mode successfully.
1970  */
CLOCK_BootToFeeMode(mcg_oscsel_t oscsel,uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1971 status_t CLOCK_BootToFeeMode(
1972     mcg_oscsel_t oscsel, uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1973 {
1974     (void)CLOCK_SetExternalRefClkConfig(oscsel);
1975 
1976     return CLOCK_SetFeeMode(frdiv, dmx32, drs, fllStableDelay);
1977 }
1978 
1979 /*!
1980  * brief Sets the MCG to BLPI mode during system boot up.
1981  *
1982  * This function sets the MCG to BLPI mode from the reset mode. It can also be used to
1983  * set up the MCG during system boot up.
1984  *
1985  * param  fcrdiv Fast IRC divider, FCRDIV.
1986  * param  ircs   The internal reference clock to select, IRCS.
1987  * param  ircEnableMode  The MCGIRCLK enable mode, OR'ed value of ref _mcg_irclk_enable_mode.
1988  *
1989  * retval kStatus_MCG_SourceUsed Could not change MCGIRCLK setting.
1990  * retval kStatus_Success Switched to the target mode successfully.
1991  */
CLOCK_BootToBlpiMode(uint8_t fcrdiv,mcg_irc_mode_t ircs,uint8_t ircEnableMode)1992 status_t CLOCK_BootToBlpiMode(uint8_t fcrdiv, mcg_irc_mode_t ircs, uint8_t ircEnableMode)
1993 {
1994     /* If reset mode is FEI mode, set MCGIRCLK and always success. */
1995     (void)CLOCK_SetInternalRefClkConfig(ircEnableMode, ircs, fcrdiv);
1996 
1997     /* If reset mode is not BLPI, first enter FBI mode. */
1998     MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
1999     while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
2000     {
2001     }
2002 
2003     /* Enter BLPI mode. */
2004     MCG->C2 |= MCG_C2_LP_MASK;
2005 
2006     return kStatus_Success;
2007 }
2008 
2009 /*!
2010  * brief Sets the MCG to BLPE mode during system boot up.
2011  *
2012  * This function sets the MCG to BLPE mode from the reset mode. It can also be used to
2013  * set up the MCG during system boot up.
2014  *
2015  * param  oscsel OSC clock select, MCG_C7[OSCSEL].
2016  *
2017  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
2018  * retval kStatus_Success Switched to the target mode successfully.
2019  */
CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)2020 status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)
2021 {
2022     (void)CLOCK_SetExternalRefClkConfig(oscsel);
2023 
2024     /* Set to FBE mode. */
2025     MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) |
2026                         (MCG_C1_CLKS(kMCG_ClkOutSrcExternal)    /* CLKS = 2 */
2027                          | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
2028 
2029     /* If use external crystal as clock source, wait for it stable. */
2030     {
2031         if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
2032         {
2033             while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
2034             {
2035             }
2036         }
2037     }
2038 
2039     /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */
2040     while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
2041            (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
2042     {
2043     }
2044 
2045     /* In FBE now, start to enter BLPE. */
2046     MCG->C2 |= MCG_C2_LP_MASK;
2047 
2048     return kStatus_Success;
2049 }
2050 
2051 /*!
2052  * brief Sets the MCG to PEE mode during system boot up.
2053  *
2054  * This function sets the MCG to PEE mode from reset mode. It can also be used to
2055  * set up the MCG during system boot up.
2056  *
2057  * param   oscsel OSC clock select, MCG_C7[OSCSEL].
2058  * param   pllcs  The PLL selection, PLLCS.
2059  * param   config Pointer to the PLL configuration.
2060  *
2061  * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
2062  * retval kStatus_Success Switched to the target mode successfully.
2063  */
CLOCK_BootToPeeMode(mcg_oscsel_t oscsel,mcg_pll_clk_select_t pllcs,mcg_pll_config_t const * config)2064 status_t CLOCK_BootToPeeMode(mcg_oscsel_t oscsel, mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
2065 {
2066     assert(config);
2067 
2068     (void)CLOCK_SetExternalRefClkConfig(oscsel);
2069 
2070     (void)CLOCK_SetPbeMode(pllcs, config);
2071 
2072     /* Change to use PLL output clock. */
2073     MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut));
2074     while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatPll)
2075     {
2076     }
2077 
2078     return kStatus_Success;
2079 }
2080 
2081 /*
2082    The transaction matrix. It defines the path for mode switch, the row is for
2083    current mode and the column is target mode.
2084    For example, switch from FEI to PEE:
2085    1. Current mode FEI, next mode is mcgModeMatrix[FEI][PEE] = FBE, so swith to FBE.
2086    2. Current mode FBE, next mode is mcgModeMatrix[FBE][PEE] = PBE, so swith to PBE.
2087    3. Current mode PBE, next mode is mcgModeMatrix[PBE][PEE] = PEE, so swith to PEE.
2088    Thus the MCG mode has changed from FEI to PEE.
2089  */
2090 static const mcg_mode_t mcgModeMatrix[8][8] = {
2091     {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
2092      kMCG_ModeFBE}, /* FEI */
2093     {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
2094      kMCG_ModeFBE}, /* FBI */
2095     {kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI,
2096      kMCG_ModeFBI}, /* BLPI */
2097     {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
2098      kMCG_ModeFBE}, /* FEE */
2099     {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
2100      kMCG_ModePBE}, /* FBE */
2101     {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
2102      kMCG_ModePBE}, /* BLPE */
2103     {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
2104      kMCG_ModePEE}, /* PBE */
2105     {kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE,
2106      kMCG_ModePBE} /* PEE */
2107     /*    FEI           FBI           BLPI           FEE           FBE           BLPE           PBE           PEE */
2108 };
2109 
2110 /*!
2111  * brief Sets the MCG to a target mode.
2112  *
2113  * This function sets MCG to a target mode defined by the configuration
2114  * structure. If switching to the target mode fails, this function
2115  * chooses the correct path.
2116  *
2117  * param  config Pointer to the target MCG mode configuration structure.
2118  * return Return kStatus_Success if switched successfully; Otherwise, it returns an error code #_mcg_status.
2119  *
2120  * note If the external clock is used in the target mode, ensure that it is
2121  * enabled. For example, if the OSC0 is used, set up OSC0 correctly before calling this
2122  * function.
2123  */
CLOCK_SetMcgConfig(const mcg_config_t * config)2124 status_t CLOCK_SetMcgConfig(const mcg_config_t *config)
2125 {
2126     mcg_mode_t next_mode;
2127     status_t status = kStatus_Success;
2128 
2129     mcg_pll_clk_select_t pllcs = kMCG_PllClkSelPll0;
2130 
2131     /* Re-configure MCGIRCLK, if MCGIRCLK is used as system clock source, then change to FEI/PEI first. */
2132     if (MCG_S_CLKST_VAL == (uint8_t)kMCG_ClkOutStatInt)
2133     {
2134         MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK; /* Disable lowpower. */
2135 
2136         {
2137             (void)CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
2138         }
2139     }
2140 
2141     /* Configure MCGIRCLK. */
2142     (void)CLOCK_SetInternalRefClkConfig(config->irclkEnableMode, config->ircs, config->fcrdiv);
2143 
2144     next_mode = CLOCK_GetMode();
2145 
2146     do
2147     {
2148         next_mode = mcgModeMatrix[next_mode][config->mcgMode];
2149 
2150         switch (next_mode)
2151         {
2152             case kMCG_ModeFEI:
2153                 status = CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
2154                 break;
2155             case kMCG_ModeFEE:
2156                 status = CLOCK_SetFeeMode(config->frdiv, config->dmx32, config->drs, CLOCK_FllStableDelay);
2157                 break;
2158             case kMCG_ModeFBI:
2159                 status = CLOCK_SetFbiMode(config->dmx32, config->drs, NULL);
2160                 break;
2161             case kMCG_ModeFBE:
2162                 status = CLOCK_SetFbeMode(config->frdiv, config->dmx32, config->drs, NULL);
2163                 break;
2164             case kMCG_ModeBLPI:
2165                 status = CLOCK_SetBlpiMode();
2166                 break;
2167             case kMCG_ModeBLPE:
2168                 status = CLOCK_SetBlpeMode();
2169                 break;
2170             case kMCG_ModePBE:
2171                 /* If target mode is not PBE or PEE, then only need to set CLKS = EXT here. */
2172                 if ((kMCG_ModePEE == config->mcgMode) || (kMCG_ModePBE == config->mcgMode))
2173                 {
2174                     {
2175                         status = CLOCK_SetPbeMode(pllcs, &config->pll0Config);
2176                     }
2177                 }
2178                 else
2179                 {
2180                     MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
2181                     while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
2182                     {
2183                     }
2184                 }
2185                 break;
2186             case kMCG_ModePEE:
2187                 status = CLOCK_SetPeeMode();
2188                 break;
2189             default:
2190                 assert(false);
2191                 break;
2192         }
2193         if (kStatus_Success != status)
2194         {
2195             break;
2196         }
2197     } while (next_mode != config->mcgMode);
2198 
2199     if (status == kStatus_Success)
2200     {
2201         if ((config->pll0Config.enableMode & (uint8_t)kMCG_PllEnableIndependent) != 0U)
2202         {
2203             CLOCK_EnablePll0(&config->pll0Config);
2204         }
2205         else
2206         {
2207             MCG->C5 &= ~(uint8_t)kMCG_PllEnableIndependent;
2208         }
2209     }
2210 
2211     return status;
2212 }
2213