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