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