1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016 - 2020, 2022 - 2023 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_clock.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.clock"
18 #endif
19
20 /* Macro definition remap workaround. */
21 #if (defined(MCG_C2_EREFS_MASK) && !(defined(MCG_C2_EREFS0_MASK)))
22 #define MCG_C2_EREFS0_MASK MCG_C2_EREFS_MASK
23 #endif
24 #if (defined(MCG_C2_HGO_MASK) && !(defined(MCG_C2_HGO0_MASK)))
25 #define MCG_C2_HGO0_MASK MCG_C2_HGO_MASK
26 #endif
27 #if (defined(MCG_C2_RANGE_MASK) && !(defined(MCG_C2_RANGE0_MASK)))
28 #define MCG_C2_RANGE0_MASK MCG_C2_RANGE_MASK
29 #endif
30 #if (defined(MCG_C6_CME_MASK) && !(defined(MCG_C6_CME0_MASK)))
31 #define MCG_C6_CME0_MASK MCG_C6_CME_MASK
32 #endif
33
34 /* PLL fixed multiplier when there is not PRDIV and VDIV. */
35 #define PLL_FIXED_MULT (375U)
36 /* Max frequency of the reference clock used for internal clock trim. */
37 #define TRIM_REF_CLK_MIN (8000000U)
38 /* Min frequency of the reference clock used for internal clock trim. */
39 #define TRIM_REF_CLK_MAX (16000000U)
40 /* Max trim value of fast internal reference clock. */
41 #define TRIM_FIRC_MAX (5000000U)
42 /* Min trim value of fast internal reference clock. */
43 #define TRIM_FIRC_MIN (3000000U)
44 /* Max trim value of fast internal reference clock. */
45 #define TRIM_SIRC_MAX (39063U)
46 /* Min trim value of fast internal reference clock. */
47 #define TRIM_SIRC_MIN (31250U)
48
49 #define MCG_S_IRCST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_IRCST_MASK) >> (uint32_t)MCG_S_IRCST_SHIFT)
50 #define MCG_S_CLKST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_CLKST_MASK) >> (uint32_t)MCG_S_CLKST_SHIFT)
51 #define MCG_S_IREFST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_IREFST_MASK) >> (uint32_t)MCG_S_IREFST_SHIFT)
52 #define MCG_S_PLLST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_PLLST_MASK) >> (uint32_t)MCG_S_PLLST_SHIFT)
53 #define MCG_C1_FRDIV_VAL ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT)
54 #define MCG_C2_LP_VAL (((uint32_t)MCG->C2 & (uint32_t)MCG_C2_LP_MASK) >> (uint32_t)MCG_C2_LP_SHIFT)
55 #define MCG_C2_RANGE_VAL ((MCG->C2 & MCG_C2_RANGE_MASK) >> MCG_C2_RANGE_SHIFT)
56 #define MCG_SC_FCRDIV_VAL ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)
57 #define MCG_S2_PLLCST_VAL (((uint32_t)MCG->S2 & (uint32_t)MCG_S2_PLLCST_MASK) >> (uint32_t)MCG_S2_PLLCST_SHIFT)
58 #define MCG_C7_OSCSEL_VAL ((MCG->C7 & MCG_C7_OSCSEL_MASK) >> MCG_C7_OSCSEL_SHIFT)
59 #define MCG_C4_DMX32_VAL ((MCG->C4 & MCG_C4_DMX32_MASK) >> MCG_C4_DMX32_SHIFT)
60 #define MCG_C4_DRST_DRS_VAL ((MCG->C4 & MCG_C4_DRST_DRS_MASK) >> MCG_C4_DRST_DRS_SHIFT)
61 #define MCG_C7_PLL32KREFSEL_VAL ((MCG->C7 & MCG_C7_PLL32KREFSEL_MASK) >> MCG_C7_PLL32KREFSEL_SHIFT)
62 #define MCG_C5_PLLREFSEL0_VAL ((MCG->C5 & MCG_C5_PLLREFSEL0_MASK) >> MCG_C5_PLLREFSEL0_SHIFT)
63 #define MCG_C11_PLLREFSEL1_VAL ((MCG->C11 & MCG_C11_PLLREFSEL1_MASK) >> MCG_C11_PLLREFSEL1_SHIFT)
64 #define MCG_C11_PRDIV1_VAL ((MCG->C11 & MCG_C11_PRDIV1_MASK) >> MCG_C11_PRDIV1_SHIFT)
65 #define MCG_C12_VDIV1_VAL ((MCG->C12 & MCG_C12_VDIV1_MASK) >> MCG_C12_VDIV1_SHIFT)
66 #define MCG_C5_PRDIV0_VAL ((uint8_t)(MCG->C5 & MCG_C5_PRDIV0_MASK) >> MCG_C5_PRDIV0_SHIFT)
67 #define MCG_C6_VDIV0_VAL ((uint8_t)(MCG->C6 & MCG_C6_VDIV0_MASK) >> MCG_C6_VDIV0_SHIFT)
68
69 #define OSC_MODE_MASK (MCG_C2_EREFS0_MASK | MCG_C2_HGO0_MASK | MCG_C2_RANGE0_MASK)
70
71 #define SIM_CLKDIV1_OUTDIV1_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
72 #define SIM_CLKDIV1_OUTDIV2_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT)
73 #define SIM_CLKDIV1_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 MCG->C4 = mcg_c4;
1835
1836 /* Wait for clock status bits to show clock source is ext ref clk */
1837 while ((uint8_t)kMCG_ClkOutStatExt != MCG_S_CLKST_VAL)
1838 {
1839 }
1840
1841 /* Wait for fll stable time. */
1842 if (NULL != fllStableDelay)
1843 {
1844 fllStableDelay();
1845 }
1846
1847 return kStatus_Success;
1848 }
1849
1850 /*!
1851 * brief Sets the MCG to BLPI mode.
1852 *
1853 * This function sets the MCG to BLPI mode. If setting to BLPI mode fails
1854 * from the current mode, this function returns an error.
1855 *
1856 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1857 * retval kStatus_Success Switched to the target mode successfully.
1858 */
CLOCK_SetBlpiMode(void)1859 status_t CLOCK_SetBlpiMode(void)
1860 {
1861 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1862 if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1863 {
1864 return kStatus_MCG_ModeUnreachable;
1865 }
1866 #endif /* MCG_CONFIG_CHECK_PARAM */
1867
1868 /* Set LP. */
1869 MCG->C2 |= MCG_C2_LP_MASK;
1870
1871 return kStatus_Success;
1872 }
1873
1874 /*!
1875 * brief Sets the MCG to BLPE mode.
1876 *
1877 * This function sets the MCG to BLPE mode. If setting to BLPE mode fails
1878 * from the current mode, this function returns an error.
1879 *
1880 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1881 * retval kStatus_Success Switched to the target mode successfully.
1882 */
CLOCK_SetBlpeMode(void)1883 status_t CLOCK_SetBlpeMode(void)
1884 {
1885 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1886 if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
1887 {
1888 return kStatus_MCG_ModeUnreachable;
1889 }
1890 #endif
1891
1892 /* Set LP bit to enter BLPE mode. */
1893 MCG->C2 |= MCG_C2_LP_MASK;
1894
1895 return kStatus_Success;
1896 }
1897
1898 /*!
1899 * brief Sets the MCG to PBE mode.
1900 *
1901 * This function sets the MCG to PBE mode. If setting to PBE mode fails
1902 * from the current mode, this function returns an error.
1903 *
1904 * param pllcs The PLL selection, PLLCS.
1905 * param config Pointer to the PLL configuration.
1906 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1907 * retval kStatus_Success Switched to the target mode successfully.
1908 *
1909 * note
1910 * 1. The parameter \c pllcs selects the PLL. For platforms with
1911 * only one PLL, the parameter pllcs is kept for interface compatibility.
1912 * 2. The parameter \c config is the PLL configuration structure. On some
1913 * platforms, it is possible to choose the external PLL directly, which renders the
1914 * configuration structure not necessary. In this case, pass in NULL.
1915 * For example: CLOCK_SetPbeMode(kMCG_OscselOsc, kMCG_PllClkSelExtPll, NULL);
1916 */
CLOCK_SetPbeMode(mcg_pll_clk_select_t pllcs,mcg_pll_config_t const * config)1917 status_t CLOCK_SetPbeMode(mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
1918 {
1919 assert(config);
1920
1921 /*
1922 This function is designed to change MCG to PBE mode from PEE/BLPE/FBE,
1923 but with this workflow, the source mode could be all modes except PEI/PBI.
1924 */
1925 MCG->C2 &= (uint8_t)(~MCG_C2_LP_MASK); /* Disable lowpower. */
1926
1927 /* Change to use external clock first. */
1928 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
1929
1930 /* Wait for CLKST clock status bits to show clock source is ext ref clk */
1931 while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
1932 (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
1933 {
1934 }
1935
1936 /* Disable PLL first, then configure PLL. */
1937 MCG->C6 &= (uint8_t)(~MCG_C6_PLLS_MASK);
1938 while ((MCG->S & MCG_S_PLLST_MASK) != 0U)
1939 {
1940 }
1941
1942 /* Configure the PLL. */
1943 {
1944 CLOCK_EnablePll0(config);
1945 }
1946
1947 /* Change to PLL mode. */
1948 MCG->C6 |= MCG_C6_PLLS_MASK;
1949
1950 /* Wait for PLL mode changed. */
1951 while (((MCG->S & MCG_S_PLLST_MASK)) == 0U)
1952 {
1953 }
1954
1955 return kStatus_Success;
1956 }
1957
1958 /*!
1959 * brief Sets the MCG to PEE mode.
1960 *
1961 * This function sets the MCG to PEE mode.
1962 *
1963 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1964 * retval kStatus_Success Switched to the target mode successfully.
1965 *
1966 * note This function only changes the CLKS to use the PLL/FLL output. If the
1967 * PRDIV/VDIV are different than in the PBE mode, set them up
1968 * in PBE mode and wait. When the clock is stable, switch to PEE mode.
1969 */
CLOCK_SetPeeMode(void)1970 status_t CLOCK_SetPeeMode(void)
1971 {
1972 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1973 mcg_mode_t mode = CLOCK_GetMode();
1974 if (kMCG_ModePBE != mode)
1975 {
1976 return kStatus_MCG_ModeUnreachable;
1977 }
1978 #endif
1979
1980 /* Change to use PLL/FLL output clock first. */
1981 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut));
1982
1983 /* Wait for clock status bits to update */
1984 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatPll)
1985 {
1986 }
1987
1988 return kStatus_Success;
1989 }
1990
1991 /*!
1992 * brief Switches the MCG to FBE mode from the external mode.
1993 *
1994 * This function switches the MCG from external modes (PEE/PBE/BLPE/FEE) to the FBE mode quickly.
1995 * The external clock is used as the system clock source and PLL is disabled. However,
1996 * the FLL settings are not configured. This is a lite function with a small code size, which is useful
1997 * during the mode switch. For example, to switch from PEE mode to FEI mode:
1998 *
1999 * code
2000 * CLOCK_ExternalModeToFbeModeQuick();
2001 * CLOCK_SetFeiMode(...);
2002 * endcode
2003 *
2004 * retval kStatus_Success Switched successfully.
2005 * retval kStatus_MCG_ModeInvalid If the current mode is not an external mode, do not call this function.
2006 */
CLOCK_ExternalModeToFbeModeQuick(void)2007 status_t CLOCK_ExternalModeToFbeModeQuick(void)
2008 {
2009 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
2010 if ((MCG->S & MCG_S_IREFST_MASK) != 0U)
2011 {
2012 return kStatus_MCG_ModeInvalid;
2013 }
2014 #endif /* MCG_CONFIG_CHECK_PARAM */
2015
2016 /* Disable low power */
2017 MCG->C2 &= (uint8_t)(~MCG_C2_LP_MASK);
2018
2019 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
2020 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
2021 {
2022 }
2023
2024 /* Disable PLL. */
2025 MCG->C6 &= ~(uint8_t)MCG_C6_PLLS_MASK;
2026 while ((MCG->S & MCG_S_PLLST_MASK) != 0U)
2027 {
2028 }
2029
2030 return kStatus_Success;
2031 }
2032
2033 /*!
2034 * brief Switches the MCG to FBI mode from internal modes.
2035 *
2036 * This function switches the MCG from internal modes (PEI/PBI/BLPI/FEI) to the FBI mode quickly.
2037 * The MCGIRCLK is used as the system clock source and PLL is disabled. However,
2038 * FLL settings are not configured. This is a lite function with a small code size, which is useful
2039 * during the mode switch. For example, to switch from PEI mode to FEE mode:
2040 *
2041 * code
2042 * CLOCK_InternalModeToFbiModeQuick();
2043 * CLOCK_SetFeeMode(...);
2044 * endcode
2045 *
2046 * retval kStatus_Success Switched successfully.
2047 * retval kStatus_MCG_ModeInvalid If the current mode is not an internal mode, do not call this function.
2048 */
CLOCK_InternalModeToFbiModeQuick(void)2049 status_t CLOCK_InternalModeToFbiModeQuick(void)
2050 {
2051 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
2052 if ((MCG->S & MCG_S_IREFST_MASK) == 0U)
2053 {
2054 return kStatus_MCG_ModeInvalid;
2055 }
2056 #endif
2057
2058 /* Disable low power */
2059 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
2060
2061 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
2062 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
2063 {
2064 }
2065
2066 return kStatus_Success;
2067 }
2068
2069 /*!
2070 * brief Sets the MCG to FEI mode during system boot up.
2071 *
2072 * This function sets the MCG to FEI mode from the reset mode. It can also be used to
2073 * set up MCG during system boot up.
2074 *
2075 * param dmx32 DMX32 in FEI mode.
2076 * param drs The DCO range selection.
2077 * param fllStableDelay Delay function to ensure that the FLL is stable.
2078 *
2079 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
2080 * retval kStatus_Success Switched to the target mode successfully.
2081 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
2082 * to frequency above 32768 Hz.
2083 */
CLOCK_BootToFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))2084 status_t CLOCK_BootToFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
2085 {
2086 return CLOCK_SetFeiMode(dmx32, drs, fllStableDelay);
2087 }
2088
2089 /*!
2090 * brief Sets the MCG to FEE mode during system bootup.
2091 *
2092 * This function sets MCG to FEE mode from the reset mode. It can also be used to
2093 * set up the MCG during system boot up.
2094 *
2095 * param oscsel OSC clock select, OSCSEL.
2096 * param frdiv FLL reference clock divider setting, FRDIV.
2097 * param dmx32 DMX32 in FEE mode.
2098 * param drs The DCO range selection.
2099 * param fllStableDelay Delay function to ensure that the FLL is stable.
2100 *
2101 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
2102 * retval kStatus_Success Switched to the target mode successfully.
2103 */
CLOCK_BootToFeeMode(mcg_oscsel_t oscsel,uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))2104 status_t CLOCK_BootToFeeMode(
2105 mcg_oscsel_t oscsel, uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
2106 {
2107 (void)CLOCK_SetExternalRefClkConfig(oscsel);
2108
2109 return CLOCK_SetFeeMode(frdiv, dmx32, drs, fllStableDelay);
2110 }
2111
2112 /*!
2113 * brief Sets the MCG to BLPI mode during system boot up.
2114 *
2115 * This function sets the MCG to BLPI mode from the reset mode. It can also be used to
2116 * set up the MCG during system boot up.
2117 *
2118 * param fcrdiv Fast IRC divider, FCRDIV.
2119 * param ircs The internal reference clock to select, IRCS.
2120 * param ircEnableMode The MCGIRCLK enable mode, OR'ed value of ref _mcg_irclk_enable_mode.
2121 *
2122 * retval kStatus_MCG_SourceUsed Could not change MCGIRCLK setting.
2123 * retval kStatus_Success Switched to the target mode successfully.
2124 */
CLOCK_BootToBlpiMode(uint8_t fcrdiv,mcg_irc_mode_t ircs,uint8_t ircEnableMode)2125 status_t CLOCK_BootToBlpiMode(uint8_t fcrdiv, mcg_irc_mode_t ircs, uint8_t ircEnableMode)
2126 {
2127 /* If reset mode is FEI mode, set MCGIRCLK and always success. */
2128 (void)CLOCK_SetInternalRefClkConfig(ircEnableMode, ircs, fcrdiv);
2129
2130 /* If reset mode is not BLPI, first enter FBI mode. */
2131 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
2132 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
2133 {
2134 }
2135
2136 /* Enter BLPI mode. */
2137 MCG->C2 |= MCG_C2_LP_MASK;
2138
2139 return kStatus_Success;
2140 }
2141
2142 /*!
2143 * brief Sets the MCG to BLPE mode during system boot up.
2144 *
2145 * This function sets the MCG to BLPE mode from the reset mode. It can also be used to
2146 * set up the MCG during system boot up.
2147 *
2148 * param oscsel OSC clock select, MCG_C7[OSCSEL].
2149 *
2150 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
2151 * retval kStatus_Success Switched to the target mode successfully.
2152 */
CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)2153 status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)
2154 {
2155 (void)CLOCK_SetExternalRefClkConfig(oscsel);
2156
2157 /* Set to FBE mode. */
2158 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) |
2159 (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
2160 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
2161
2162 /* If use external crystal as clock source, wait for it stable. */
2163 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
2164 {
2165 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
2166 {
2167 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
2168 {
2169 }
2170 }
2171 }
2172
2173 /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */
2174 while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
2175 (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
2176 {
2177 }
2178
2179 /* In FBE now, start to enter BLPE. */
2180 MCG->C2 |= MCG_C2_LP_MASK;
2181
2182 return kStatus_Success;
2183 }
2184
2185 /*!
2186 * brief Sets the MCG to PEE mode during system boot up.
2187 *
2188 * This function sets the MCG to PEE mode from reset mode. It can also be used to
2189 * set up the MCG during system boot up.
2190 *
2191 * param oscsel OSC clock select, MCG_C7[OSCSEL].
2192 * param pllcs The PLL selection, PLLCS.
2193 * param config Pointer to the PLL configuration.
2194 *
2195 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
2196 * retval kStatus_Success Switched to the target mode successfully.
2197 */
CLOCK_BootToPeeMode(mcg_oscsel_t oscsel,mcg_pll_clk_select_t pllcs,mcg_pll_config_t const * config)2198 status_t CLOCK_BootToPeeMode(mcg_oscsel_t oscsel, mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
2199 {
2200 assert(config);
2201
2202 (void)CLOCK_SetExternalRefClkConfig(oscsel);
2203
2204 (void)CLOCK_SetPbeMode(pllcs, config);
2205
2206 /* Change to use PLL output clock. */
2207 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut));
2208 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatPll)
2209 {
2210 }
2211
2212 return kStatus_Success;
2213 }
2214
2215 /*
2216 The transaction matrix. It defines the path for mode switch, the row is for
2217 current mode and the column is target mode.
2218 For example, switch from FEI to PEE:
2219 1. Current mode FEI, next mode is mcgModeMatrix[FEI][PEE] = FBE, so swith to FBE.
2220 2. Current mode FBE, next mode is mcgModeMatrix[FBE][PEE] = PBE, so swith to PBE.
2221 3. Current mode PBE, next mode is mcgModeMatrix[PBE][PEE] = PEE, so swith to PEE.
2222 Thus the MCG mode has changed from FEI to PEE.
2223 */
2224 static const mcg_mode_t mcgModeMatrix[8][8] = {
2225 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
2226 kMCG_ModeFBE}, /* FEI */
2227 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
2228 kMCG_ModeFBE}, /* FBI */
2229 {kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI,
2230 kMCG_ModeFBI}, /* BLPI */
2231 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
2232 kMCG_ModeFBE}, /* FEE */
2233 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
2234 kMCG_ModePBE}, /* FBE */
2235 {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
2236 kMCG_ModePBE}, /* BLPE */
2237 {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
2238 kMCG_ModePEE}, /* PBE */
2239 {kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE,
2240 kMCG_ModePBE} /* PEE */
2241 /* FEI FBI BLPI FEE FBE BLPE PBE PEE */
2242 };
2243
2244 /*!
2245 * brief Sets the MCG to a target mode.
2246 *
2247 * This function sets MCG to a target mode defined by the configuration
2248 * structure. If switching to the target mode fails, this function
2249 * chooses the correct path.
2250 *
2251 * param config Pointer to the target MCG mode configuration structure.
2252 * return Return kStatus_Success if switched successfully; Otherwise, it returns an error code #_mcg_status.
2253 *
2254 * note If the external clock is used in the target mode, ensure that it is
2255 * enabled. For example, if the OSC0 is used, set up OSC0 correctly before calling this
2256 * function.
2257 */
CLOCK_SetMcgConfig(const mcg_config_t * config)2258 status_t CLOCK_SetMcgConfig(const mcg_config_t *config)
2259 {
2260 assert(config->mcgMode != kMCG_ModeError);
2261
2262 mcg_mode_t next_mode;
2263 status_t status = kStatus_Success;
2264
2265 mcg_pll_clk_select_t pllcs = kMCG_PllClkSelPll0;
2266
2267 /* If need to change external clock, MCG_C7[OSCSEL]. */
2268 if (MCG_C7_OSCSEL_VAL != (uint8_t)(config->oscsel))
2269 {
2270 /* If external clock is in use, change to FEI first. */
2271 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
2272 {
2273 (void)CLOCK_ExternalModeToFbeModeQuick();
2274 (void)CLOCK_SetFeiMode(config->dmx32, config->drs, NULL);
2275 }
2276
2277 (void)CLOCK_SetExternalRefClkConfig(config->oscsel);
2278 }
2279
2280 /* Re-configure MCGIRCLK, if MCGIRCLK is used as system clock source, then change to FEI/PEI first. */
2281 if (MCG_S_CLKST_VAL == (uint8_t)kMCG_ClkOutStatInt)
2282 {
2283 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK; /* Disable lowpower. */
2284
2285 {
2286 (void)CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
2287 }
2288 }
2289
2290 /* Configure MCGIRCLK. */
2291 (void)CLOCK_SetInternalRefClkConfig(config->irclkEnableMode, config->ircs, config->fcrdiv);
2292
2293 next_mode = CLOCK_GetMode();
2294
2295 if (next_mode == kMCG_ModeError)
2296 {
2297 return kStatus_MCG_ModeInvalid;
2298 }
2299
2300 do
2301 {
2302 next_mode = mcgModeMatrix[next_mode][config->mcgMode];
2303
2304 switch (next_mode)
2305 {
2306 case kMCG_ModeFEI:
2307 status = CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
2308 break;
2309 case kMCG_ModeFEE:
2310 status = CLOCK_SetFeeMode(config->frdiv, config->dmx32, config->drs, CLOCK_FllStableDelay);
2311 break;
2312 case kMCG_ModeFBI:
2313 status = CLOCK_SetFbiMode(config->dmx32, config->drs, NULL);
2314 break;
2315 case kMCG_ModeFBE:
2316 status = CLOCK_SetFbeMode(config->frdiv, config->dmx32, config->drs, NULL);
2317 break;
2318 case kMCG_ModeBLPI:
2319 status = CLOCK_SetBlpiMode();
2320 break;
2321 case kMCG_ModeBLPE:
2322 status = CLOCK_SetBlpeMode();
2323 break;
2324 case kMCG_ModePBE:
2325 /* If target mode is not PBE or PEE, then only need to set CLKS = EXT here. */
2326 if ((kMCG_ModePEE == config->mcgMode) || (kMCG_ModePBE == config->mcgMode))
2327 {
2328 {
2329 status = CLOCK_SetPbeMode(pllcs, &config->pll0Config);
2330 }
2331 }
2332 else
2333 {
2334 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
2335 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
2336 {
2337 }
2338 }
2339 break;
2340 case kMCG_ModePEE:
2341 status = CLOCK_SetPeeMode();
2342 break;
2343 default:
2344 assert(false);
2345 break;
2346 }
2347 if (kStatus_Success != status)
2348 {
2349 break;
2350 }
2351 } while (next_mode != config->mcgMode);
2352
2353 if (status == kStatus_Success)
2354 {
2355 if ((config->pll0Config.enableMode & (uint8_t)kMCG_PllEnableIndependent) != 0U)
2356 {
2357 CLOCK_EnablePll0(&config->pll0Config);
2358 }
2359 else
2360 {
2361 MCG->C5 &= ~(uint8_t)kMCG_PllEnableIndependent;
2362 }
2363 }
2364
2365 return status;
2366 }
2367