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