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