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