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