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