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