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