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