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