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