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