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