1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright (c) 2016 - 2017 , NXP
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without modification,
7 * are permitted provided that the following conditions are met:
8 *
9 * o Redistributions of source code must retain the above copyright notice, this list
10 * of conditions and the following disclaimer.
11 *
12 * o Redistributions in binary form must reproduce the above copyright notice, this
13 * list of conditions and the following disclaimer in the documentation and/or
14 * other materials provided with the distribution.
15 *
16 * o Neither the name of copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from this
18 * software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Copyright (c) 2016, NXP Semiconductors, Inc.
32 * All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without modification,
35 * are permitted provided that the following conditions are met:
36 *
37 * o Redistributions of source code must retain the above copyright notice, this list
38 * of conditions and the following disclaimer.
39 *
40 * o Redistributions in binary form must reproduce the above copyright notice, this
41 * list of conditions and the following disclaimer in the documentation and/or
42 * other materials provided with the distribution.
43 *
44 * o Neither the name of NXP Semiconductors, Inc. nor the names of its
45 * contributors may be used to endorse or promote products derived from this
46 * software without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
50 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
51 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
52 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
55 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
57 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 */
59
60 #include "fsl_clock.h"
61
62 /*******************************************************************************
63 * Definitions
64 ******************************************************************************/
65
66 /* Macro definition remap workaround. */
67 #if (defined(MCG_C2_EREFS_MASK) && !(defined(MCG_C2_EREFS0_MASK)))
68 #define MCG_C2_EREFS0_MASK MCG_C2_EREFS_MASK
69 #endif
70 #if (defined(MCG_C2_HGO_MASK) && !(defined(MCG_C2_HGO0_MASK)))
71 #define MCG_C2_HGO0_MASK MCG_C2_HGO_MASK
72 #endif
73 #if (defined(MCG_C2_RANGE_MASK) && !(defined(MCG_C2_RANGE0_MASK)))
74 #define MCG_C2_RANGE0_MASK MCG_C2_RANGE_MASK
75 #endif
76 #if (defined(MCG_C6_CME_MASK) && !(defined(MCG_C6_CME0_MASK)))
77 #define MCG_C6_CME0_MASK MCG_C6_CME_MASK
78 #endif
79
80 /* PLL fixed multiplier when there is not PRDIV and VDIV. */
81 #define PLL_FIXED_MULT (375U)
82 /* Max frequency of the reference clock used for internal clock trim. */
83 #define TRIM_REF_CLK_MIN (8000000U)
84 /* Min frequency of the reference clock used for internal clock trim. */
85 #define TRIM_REF_CLK_MAX (16000000U)
86 /* Max trim value of fast internal reference clock. */
87 #define TRIM_FIRC_MAX (5000000U)
88 /* Min trim value of fast internal reference clock. */
89 #define TRIM_FIRC_MIN (3000000U)
90 /* Max trim value of fast internal reference clock. */
91 #define TRIM_SIRC_MAX (39063U)
92 /* Min trim value of fast internal reference clock. */
93 #define TRIM_SIRC_MIN (31250U)
94
95 #define MCG_S_IRCST_VAL ((MCG->S & MCG_S_IRCST_MASK) >> MCG_S_IRCST_SHIFT)
96 #define MCG_S_CLKST_VAL ((MCG->S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT)
97 #define MCG_S_IREFST_VAL ((MCG->S & MCG_S_IREFST_MASK) >> MCG_S_IREFST_SHIFT)
98 #define MCG_S_PLLST_VAL ((MCG->S & MCG_S_PLLST_MASK) >> MCG_S_PLLST_SHIFT)
99 #define MCG_C1_FRDIV_VAL ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT)
100 #define MCG_C2_LP_VAL ((MCG->C2 & MCG_C2_LP_MASK) >> MCG_C2_LP_SHIFT)
101 #define MCG_C2_RANGE_VAL ((MCG->C2 & MCG_C2_RANGE_MASK) >> MCG_C2_RANGE_SHIFT)
102 #define MCG_SC_FCRDIV_VAL ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)
103 #define MCG_S2_PLLCST_VAL ((MCG->S2 & MCG_S2_PLLCST_MASK) >> MCG_S2_PLLCST_SHIFT)
104 #define MCG_C7_OSCSEL_VAL ((MCG->C7 & MCG_C7_OSCSEL_MASK) >> MCG_C7_OSCSEL_SHIFT)
105 #define MCG_C4_DMX32_VAL ((MCG->C4 & MCG_C4_DMX32_MASK) >> MCG_C4_DMX32_SHIFT)
106 #define MCG_C4_DRST_DRS_VAL ((MCG->C4 & MCG_C4_DRST_DRS_MASK) >> MCG_C4_DRST_DRS_SHIFT)
107 #define MCG_C7_PLL32KREFSEL_VAL ((MCG->C7 & MCG_C7_PLL32KREFSEL_MASK) >> MCG_C7_PLL32KREFSEL_SHIFT)
108 #define MCG_C5_PLLREFSEL0_VAL ((MCG->C5 & MCG_C5_PLLREFSEL0_MASK) >> MCG_C5_PLLREFSEL0_SHIFT)
109 #define MCG_C11_PLLREFSEL1_VAL ((MCG->C11 & MCG_C11_PLLREFSEL1_MASK) >> MCG_C11_PLLREFSEL1_SHIFT)
110 #define MCG_C11_PRDIV1_VAL ((MCG->C11 & MCG_C11_PRDIV1_MASK) >> MCG_C11_PRDIV1_SHIFT)
111 #define MCG_C12_VDIV1_VAL ((MCG->C12 & MCG_C12_VDIV1_MASK) >> MCG_C12_VDIV1_SHIFT)
112 #define MCG_C5_PRDIV0_VAL ((MCG->C5 & MCG_C5_PRDIV0_MASK) >> MCG_C5_PRDIV0_SHIFT)
113 #define MCG_C6_VDIV0_VAL ((MCG->C6 & MCG_C6_VDIV0_MASK) >> MCG_C6_VDIV0_SHIFT)
114
115 #define OSC_MODE_MASK (MCG_C2_EREFS0_MASK | MCG_C2_HGO0_MASK | MCG_C2_RANGE0_MASK)
116
117 #define SIM_CLKDIV1_OUTDIV1_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
118 #define SIM_CLKDIV1_OUTDIV4_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)
119 #define SIM_SOPT1_OSC32KSEL_VAL ((SIM->SOPT1 & SIM_SOPT1_OSC32KSEL_MASK) >> SIM_SOPT1_OSC32KSEL_SHIFT)
120
121 /* MCG_S_CLKST definition. */
122 enum _mcg_clkout_stat
123 {
124 kMCG_ClkOutStatFll, /* FLL. */
125 kMCG_ClkOutStatInt, /* Internal clock. */
126 kMCG_ClkOutStatExt, /* External clock. */
127 kMCG_ClkOutStatPll /* PLL. */
128 };
129
130 /* MCG_S_PLLST definition. */
131 enum _mcg_pllst
132 {
133 kMCG_PllstFll, /* FLL is used. */
134 kMCG_PllstPll /* PLL is used. */
135 };
136
137 /*******************************************************************************
138 * Variables
139 ******************************************************************************/
140
141 /* Slow internal reference clock frequency. */
142 static uint32_t s_slowIrcFreq = 32768U;
143 /* Fast internal reference clock frequency. */
144 static uint32_t s_fastIrcFreq = 4000000U;
145
146 /* External XTAL0 (OSC0) clock frequency. */
147 uint32_t g_xtal0Freq;
148 /* External XTAL32K clock frequency. */
149 uint32_t g_xtal32Freq;
150
151
152
153 /*******************************************************************************
154 * Prototypes
155 ******************************************************************************/
156
157 /*!
158 * @brief Get the MCG external reference clock frequency.
159 *
160 * Get the current MCG external reference clock frequency in Hz. It is
161 * the frequency select by MCG_C7[OSCSEL]. This is an internal function.
162 *
163 * @return MCG external reference clock frequency in Hz.
164 */
165 static uint32_t CLOCK_GetMcgExtClkFreq(void);
166
167 /*!
168 * @brief Get the MCG FLL external reference clock frequency.
169 *
170 * Get the current MCG FLL external reference clock frequency in Hz. It is
171 * the frequency after by MCG_C1[FRDIV]. This is an internal function.
172 *
173 * @return MCG FLL external reference clock frequency in Hz.
174 */
175 static uint32_t CLOCK_GetFllExtRefClkFreq(void);
176
177 /*!
178 * @brief Get the MCG FLL reference clock frequency.
179 *
180 * Get the current MCG FLL reference clock frequency in Hz. It is
181 * the frequency select by MCG_C1[IREFS]. This is an internal function.
182 *
183 * @return MCG FLL reference clock frequency in Hz.
184 */
185 static uint32_t CLOCK_GetFllRefClkFreq(void);
186
187 /*!
188 * @brief Get the frequency of clock selected by MCG_C2[IRCS].
189 *
190 * This clock's two output:
191 * 1. MCGOUTCLK when MCG_S[CLKST]=0.
192 * 2. MCGIRCLK when MCG_C1[IRCLKEN]=1.
193 *
194 * @return The frequency in Hz.
195 */
196 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void);
197
198
199 /*!
200 * @brief Calculate the RANGE value base on crystal frequency.
201 *
202 * To setup external crystal oscillator, must set the register bits RANGE
203 * base on the crystal frequency. This function returns the RANGE base on the
204 * input frequency. This is an internal function.
205 *
206 * @param freq Crystal frequency in Hz.
207 * @return The RANGE value.
208 */
209 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
210
211
212
213
214 /*******************************************************************************
215 * Code
216 ******************************************************************************/
217
218 #ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
219 /*!
220 * @brief Delay function to wait FLL stable.
221 *
222 * Delay function to wait FLL stable in FEI mode or FEE mode, should wait at least
223 * 1ms. Every time changes FLL setting, should wait this time for FLL stable.
224 */
CLOCK_FllStableDelay(void)225 void CLOCK_FllStableDelay(void)
226 {
227 /*
228 Should wait at least 1ms. Because in these modes, the core clock is 100MHz
229 at most, so this function could obtain the 1ms delay.
230 */
231 volatile uint32_t i = 30000U;
232 while (i--)
233 {
234 __NOP();
235 }
236 }
237 #else /* With MCG_USER_CONFIG_FLL_STABLE_DELAY_EN defined. */
238 /* Once user defines the MCG_USER_CONFIG_FLL_STABLE_DELAY_EN to use their own delay function, they have to
239 * create their own CLOCK_FllStableDelay() function in application code. Since the clock functions in this
240 * file would call the CLOCK_FllStableDelay() regardness how it is defined.
241 */
242 extern void CLOCK_FllStableDelay(void);
243 #endif /* MCG_USER_CONFIG_FLL_STABLE_DELAY_EN */
244
CLOCK_GetMcgExtClkFreq(void)245 static uint32_t CLOCK_GetMcgExtClkFreq(void)
246 {
247 uint32_t freq;
248
249 switch (MCG_C7_OSCSEL_VAL)
250 {
251 case 0U:
252 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
253 assert(g_xtal0Freq);
254 freq = g_xtal0Freq;
255 break;
256 case 1U:
257 /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
258 assert(g_xtal32Freq);
259 freq = g_xtal32Freq;
260 break;
261 default:
262 freq = 0U;
263 break;
264 }
265
266 return freq;
267 }
268
CLOCK_GetFllExtRefClkFreq(void)269 static uint32_t CLOCK_GetFllExtRefClkFreq(void)
270 {
271 /* FllExtRef = McgExtRef / FllExtRefDiv */
272 uint8_t frdiv;
273 uint8_t range;
274 uint8_t oscsel;
275
276 uint32_t freq = CLOCK_GetMcgExtClkFreq();
277
278 if (!freq)
279 {
280 return freq;
281 }
282
283 frdiv = MCG_C1_FRDIV_VAL;
284 freq >>= frdiv;
285
286 range = MCG_C2_RANGE_VAL;
287 oscsel = MCG_C7_OSCSEL_VAL;
288
289 /*
290 When should use divider 32, 64, 128, 256, 512, 1024, 1280, 1536.
291 1. MCG_C7[OSCSEL] selects IRC48M.
292 2. MCG_C7[OSCSEL] selects OSC0 and MCG_C2[RANGE] is not 0.
293 */
294 if (((0U != range)
295 && (kMCG_OscselOsc == oscsel)
296 )
297 )
298 {
299 switch (frdiv)
300 {
301 case 0:
302 case 1:
303 case 2:
304 case 3:
305 case 4:
306 case 5:
307 freq >>= 5u;
308 break;
309 case 6:
310 /* 64*20=1280 */
311 freq /= 20u;
312 break;
313 case 7:
314 /* 128*12=1536 */
315 freq /= 12u;
316 break;
317 default:
318 freq = 0u;
319 break;
320 }
321 }
322
323 return freq;
324 }
325
CLOCK_GetInternalRefClkSelectFreq(void)326 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void)
327 {
328 if (kMCG_IrcSlow == MCG_S_IRCST_VAL)
329 {
330 /* Slow internal reference clock selected*/
331 return s_slowIrcFreq;
332 }
333 else
334 {
335 /* Fast internal reference clock selected*/
336 return s_fastIrcFreq >> MCG_SC_FCRDIV_VAL;
337 }
338 }
339
CLOCK_GetFllRefClkFreq(void)340 static uint32_t CLOCK_GetFllRefClkFreq(void)
341 {
342 /* If use external reference clock. */
343 if (kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
344 {
345 return CLOCK_GetFllExtRefClkFreq();
346 }
347 /* If use internal reference clock. */
348 else
349 {
350 return s_slowIrcFreq;
351 }
352 }
353
354
CLOCK_GetOscRangeFromFreq(uint32_t freq)355 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
356 {
357 uint8_t range;
358
359 if (freq <= 39063U)
360 {
361 range = 0U;
362 }
363 else if (freq <= 8000000U)
364 {
365 range = 1U;
366 }
367 else
368 {
369 range = 2U;
370 }
371
372 return range;
373 }
374
375
CLOCK_GetEr32kClkFreq(void)376 uint32_t CLOCK_GetEr32kClkFreq(void)
377 {
378 uint32_t freq;
379
380 switch (SIM_SOPT1_OSC32KSEL_VAL)
381 {
382 case 0U: /* OSC 32k clock */
383 case 2U: /* RTC 32k clock */
384 /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
385 assert(g_xtal32Freq);
386 freq = g_xtal32Freq;
387 break;
388 case 3U: /* LPO clock */
389 freq = LPO_CLK_FREQ;
390 break;
391 default:
392 freq = 0U;
393 break;
394 }
395 return freq;
396 }
397
CLOCK_GetOsc0ErClkFreq(void)398 uint32_t CLOCK_GetOsc0ErClkFreq(void)
399 {
400 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
401 assert(g_xtal0Freq);
402 return g_xtal0Freq;
403 }
404
CLOCK_GetPlatClkFreq(void)405 uint32_t CLOCK_GetPlatClkFreq(void)
406 {
407 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
408 }
409
CLOCK_GetFlashClkFreq(void)410 uint32_t CLOCK_GetFlashClkFreq(void)
411 {
412 uint32_t freq;
413
414 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
415 freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
416
417 return freq;
418 }
419
CLOCK_GetBusClkFreq(void)420 uint32_t CLOCK_GetBusClkFreq(void)
421 {
422 uint32_t freq;
423
424 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
425 freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
426
427 return freq;
428 }
429
CLOCK_GetCoreSysClkFreq(void)430 uint32_t CLOCK_GetCoreSysClkFreq(void)
431 {
432 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
433 }
434
CLOCK_GetFreq(clock_name_t clockName)435 uint32_t CLOCK_GetFreq(clock_name_t clockName)
436 {
437 uint32_t freq;
438
439 switch (clockName)
440 {
441 case kCLOCK_CoreSysClk:
442 case kCLOCK_PlatClk:
443 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
444 break;
445 case kCLOCK_BusClk:
446 case kCLOCK_FlashClk:
447 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
448 freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
449 break;
450 case kCLOCK_Er32kClk:
451 freq = CLOCK_GetEr32kClkFreq();
452 break;
453 case kCLOCK_McgInternalRefClk:
454 freq = CLOCK_GetInternalRefClkFreq();
455 break;
456 case kCLOCK_McgFllClk:
457 freq = CLOCK_GetFllFreq();
458 break;
459 case kCLOCK_LpoClk:
460 freq = LPO_CLK_FREQ;
461 break;
462 case kCLOCK_Osc0ErClk:
463 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
464 assert(g_xtal0Freq);
465 freq = g_xtal0Freq;
466 break;
467 default:
468 freq = 0U;
469 break;
470 }
471
472 return freq;
473 }
474
CLOCK_SetSimConfig(sim_clock_config_t const * config)475 void CLOCK_SetSimConfig(sim_clock_config_t const *config)
476 {
477 SIM->CLKDIV1 = config->clkdiv1;
478 CLOCK_SetEr32kClock(config->er32kSrc);
479 }
480
CLOCK_GetOutClkFreq(void)481 uint32_t CLOCK_GetOutClkFreq(void)
482 {
483 uint32_t mcgoutclk;
484 uint32_t clkst = MCG_S_CLKST_VAL;
485
486 switch (clkst)
487 {
488 case kMCG_ClkOutStatFll:
489 mcgoutclk = CLOCK_GetFllFreq();
490 break;
491 case kMCG_ClkOutStatInt:
492 mcgoutclk = CLOCK_GetInternalRefClkSelectFreq();
493 break;
494 case kMCG_ClkOutStatExt:
495 mcgoutclk = CLOCK_GetMcgExtClkFreq();
496 break;
497 default:
498 mcgoutclk = 0U;
499 break;
500 }
501 return mcgoutclk;
502 }
503
CLOCK_GetFllFreq(void)504 uint32_t CLOCK_GetFllFreq(void)
505 {
506 static const uint16_t fllFactorTable[4][2] = {{640, 732}, {1280, 1464}, {1920, 2197}, {2560, 2929}};
507
508 uint8_t drs, dmx32;
509 uint32_t freq;
510
511 /* If FLL is not enabled currently, then return 0U. */
512 if ((MCG->C2 & MCG_C2_LP_MASK)
513 )
514 {
515 return 0U;
516 }
517
518 /* Get FLL reference clock frequency. */
519 freq = CLOCK_GetFllRefClkFreq();
520 if (!freq)
521 {
522 return freq;
523 }
524
525 drs = MCG_C4_DRST_DRS_VAL;
526 dmx32 = MCG_C4_DMX32_VAL;
527
528 return freq * fllFactorTable[drs][dmx32];
529 }
530
CLOCK_GetInternalRefClkFreq(void)531 uint32_t CLOCK_GetInternalRefClkFreq(void)
532 {
533 /* If MCGIRCLK is gated. */
534 if (!(MCG->C1 & MCG_C1_IRCLKEN_MASK))
535 {
536 return 0U;
537 }
538
539 return CLOCK_GetInternalRefClkSelectFreq();
540 }
541
CLOCK_GetFixedFreqClkFreq(void)542 uint32_t CLOCK_GetFixedFreqClkFreq(void)
543 {
544 uint32_t freq = CLOCK_GetFllRefClkFreq();
545
546 /* MCGFFCLK must be no more than MCGOUTCLK/8. */
547 if ((freq) && (freq <= (CLOCK_GetOutClkFreq() / 8U)))
548 {
549 return freq;
550 }
551 else
552 {
553 return 0U;
554 }
555 }
556
557
CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)558 status_t CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)
559 {
560 bool needDelay;
561 uint32_t i;
562
563 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
564 /* If change MCG_C7[OSCSEL] and external reference clock is system clock source, return error. */
565 if ((MCG_C7_OSCSEL_VAL != oscsel) && (!(MCG->S & MCG_S_IREFST_MASK)))
566 {
567 return kStatus_MCG_SourceUsed;
568 }
569 #endif /* MCG_CONFIG_CHECK_PARAM */
570
571 if (MCG_C7_OSCSEL_VAL != oscsel)
572 {
573 /* If change OSCSEL, need to delay, ERR009878. */
574 needDelay = true;
575 }
576 else
577 {
578 needDelay = false;
579 }
580
581 MCG->C7 = (MCG->C7 & ~MCG_C7_OSCSEL_MASK) | MCG_C7_OSCSEL(oscsel);
582 if (needDelay)
583 {
584 /* ERR009878 Delay at least 50 micro-seconds for external clock change valid. */
585 i = 1500U;
586 while (i--)
587 {
588 __NOP();
589 }
590 }
591
592 return kStatus_Success;
593 }
594
CLOCK_SetInternalRefClkConfig(uint8_t enableMode,mcg_irc_mode_t ircs,uint8_t fcrdiv)595 status_t CLOCK_SetInternalRefClkConfig(uint8_t enableMode, mcg_irc_mode_t ircs, uint8_t fcrdiv)
596 {
597 uint32_t mcgOutClkState = MCG_S_CLKST_VAL;
598 mcg_irc_mode_t curIrcs = (mcg_irc_mode_t)MCG_S_IRCST_VAL;
599 uint8_t curFcrdiv = MCG_SC_FCRDIV_VAL;
600
601 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
602 /* If MCGIRCLK is used as system clock source. */
603 if (kMCG_ClkOutStatInt == mcgOutClkState)
604 {
605 /* If need to change MCGIRCLK source or driver, return error. */
606 if (((kMCG_IrcFast == curIrcs) && (fcrdiv != curFcrdiv)) || (ircs != curIrcs))
607 {
608 return kStatus_MCG_SourceUsed;
609 }
610 }
611 #endif
612
613 /* If need to update the FCRDIV. */
614 if (fcrdiv != curFcrdiv)
615 {
616 /* If fast IRC is in use currently, change to slow IRC. */
617 if ((kMCG_IrcFast == curIrcs) && ((mcgOutClkState == kMCG_ClkOutStatInt) || (MCG->C1 & MCG_C1_IRCLKEN_MASK)))
618 {
619 MCG->C2 = ((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(kMCG_IrcSlow)));
620 while (MCG_S_IRCST_VAL != kMCG_IrcSlow)
621 {
622 }
623 }
624 /* Update FCRDIV. */
625 MCG->SC = (MCG->SC & ~(MCG_SC_FCRDIV_MASK | MCG_SC_ATMF_MASK | MCG_SC_LOCS0_MASK)) | MCG_SC_FCRDIV(fcrdiv);
626 }
627
628 /* Set internal reference clock selection. */
629 MCG->C2 = (MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(ircs));
630 MCG->C1 = (MCG->C1 & ~(MCG_C1_IRCLKEN_MASK | MCG_C1_IREFSTEN_MASK)) | (uint8_t)enableMode;
631
632 /* If MCGIRCLK is used, need to wait for MCG_S_IRCST. */
633 if ((mcgOutClkState == kMCG_ClkOutStatInt) || (enableMode & kMCG_IrclkEnable))
634 {
635 while (MCG_S_IRCST_VAL != ircs)
636 {
637 }
638 }
639
640 return kStatus_Success;
641 }
642
643
644
CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)645 void CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)
646 {
647 /* Clear the previous flag, MCG_SC[LOCS0]. */
648 MCG->SC &= ~MCG_SC_ATMF_MASK;
649
650 if (kMCG_MonitorNone == mode)
651 {
652 MCG->C6 &= ~MCG_C6_CME0_MASK;
653 }
654 else
655 {
656 if (kMCG_MonitorInt == mode)
657 {
658 MCG->C2 &= ~MCG_C2_LOCRE0_MASK;
659 }
660 else
661 {
662 MCG->C2 |= MCG_C2_LOCRE0_MASK;
663 }
664 MCG->C6 |= MCG_C6_CME0_MASK;
665 }
666 }
667
668
CLOCK_SetRtcOscMonitorMode(mcg_monitor_mode_t mode)669 void CLOCK_SetRtcOscMonitorMode(mcg_monitor_mode_t mode)
670 {
671 uint8_t mcg_c8 = MCG->C8;
672
673 mcg_c8 &= ~(MCG_C8_CME1_MASK | MCG_C8_LOCRE1_MASK);
674
675 if (kMCG_MonitorNone != mode)
676 {
677 if (kMCG_MonitorReset == mode)
678 {
679 mcg_c8 |= MCG_C8_LOCRE1_MASK;
680 }
681 mcg_c8 |= MCG_C8_CME1_MASK;
682 }
683 MCG->C8 = mcg_c8;
684 }
685
686
CLOCK_GetStatusFlags(void)687 uint32_t CLOCK_GetStatusFlags(void)
688 {
689 uint32_t ret = 0U;
690
691 if (MCG->C8 & MCG_C8_LOCS1_MASK)
692 {
693 ret |= kMCG_RtcOscLostFlag;
694 }
695 return ret;
696 }
697
CLOCK_ClearStatusFlags(uint32_t mask)698 void CLOCK_ClearStatusFlags(uint32_t mask)
699 {
700 uint8_t reg;
701
702 if (mask & kMCG_RtcOscLostFlag)
703 {
704 reg = MCG->C8;
705 MCG->C8 = reg;
706 }
707 }
708
CLOCK_InitOsc0(osc_config_t const * config)709 void CLOCK_InitOsc0(osc_config_t const *config)
710 {
711 uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
712
713
714 MCG->C2 = ((MCG->C2 & ~OSC_MODE_MASK) | MCG_C2_RANGE(range) | (uint8_t)config->workMode);
715
716 if ((kOSC_ModeExt != config->workMode)
717 )
718 {
719 /* Wait for stable. */
720 while (!(MCG->S & MCG_S_OSCINIT0_MASK))
721 {
722 }
723 }
724 }
725
CLOCK_DeinitOsc0(void)726 void CLOCK_DeinitOsc0(void)
727 {
728 MCG->C2 &= ~OSC_MODE_MASK;
729 }
730
731
CLOCK_TrimInternalRefClk(uint32_t extFreq,uint32_t desireFreq,uint32_t * actualFreq,mcg_atm_select_t atms)732 status_t CLOCK_TrimInternalRefClk(uint32_t extFreq, uint32_t desireFreq, uint32_t *actualFreq, mcg_atm_select_t atms)
733 {
734 uint32_t multi; /* extFreq / desireFreq */
735 uint32_t actv; /* Auto trim value. */
736 uint8_t mcg_sc;
737
738 static const uint32_t trimRange[2][2] = {
739 /* Min Max */
740 {TRIM_SIRC_MIN, TRIM_SIRC_MAX}, /* Slow IRC. */
741 {TRIM_FIRC_MIN, TRIM_FIRC_MAX} /* Fast IRC. */
742 };
743
744 if ((extFreq > TRIM_REF_CLK_MAX) || (extFreq < TRIM_REF_CLK_MIN))
745 {
746 return kStatus_MCG_AtmBusClockInvalid;
747 }
748
749 /* Check desired frequency range. */
750 if ((desireFreq < trimRange[atms][0]) || (desireFreq > trimRange[atms][1]))
751 {
752 return kStatus_MCG_AtmDesiredFreqInvalid;
753 }
754
755 /*
756 Make sure internal reference clock is not used to generate bus clock.
757 Here only need to check (MCG_S_IREFST == 1).
758 */
759 if (MCG_S_IREFST(kMCG_FllSrcInternal) == (MCG->S & MCG_S_IREFST_MASK))
760 {
761 return kStatus_MCG_AtmIrcUsed;
762 }
763
764 multi = extFreq / desireFreq;
765 actv = multi * 21U;
766
767 if (kMCG_AtmSel4m == atms)
768 {
769 actv *= 128U;
770 }
771
772 /* Now begin to start trim. */
773 MCG->ATCVL = (uint8_t)actv;
774 MCG->ATCVH = (uint8_t)(actv >> 8U);
775
776 mcg_sc = MCG->SC;
777 mcg_sc &= ~(MCG_SC_ATMS_MASK | MCG_SC_LOCS0_MASK);
778 mcg_sc |= (MCG_SC_ATMF_MASK | MCG_SC_ATMS(atms));
779 MCG->SC = (mcg_sc | MCG_SC_ATME_MASK);
780
781 /* Wait for finished. */
782 while (MCG->SC & MCG_SC_ATME_MASK)
783 {
784 }
785
786 /* Error occurs? */
787 if (MCG->SC & MCG_SC_ATMF_MASK)
788 {
789 /* Clear the failed flag. */
790 MCG->SC = mcg_sc;
791 return kStatus_MCG_AtmHardwareFail;
792 }
793
794 *actualFreq = extFreq / multi;
795
796 if (kMCG_AtmSel4m == atms)
797 {
798 s_fastIrcFreq = *actualFreq;
799 }
800 else
801 {
802 s_slowIrcFreq = *actualFreq;
803 }
804
805 return kStatus_Success;
806 }
807
CLOCK_GetMode(void)808 mcg_mode_t CLOCK_GetMode(void)
809 {
810 mcg_mode_t mode = kMCG_ModeError;
811 uint32_t clkst = MCG_S_CLKST_VAL;
812 uint32_t irefst = MCG_S_IREFST_VAL;
813 uint32_t lp = MCG_C2_LP_VAL;
814
815 /*------------------------------------------------------------------
816 Mode and Registers
817 ____________________________________________________________________
818
819 Mode | CLKST | IREFST | PLLST | LP
820 ____________________________________________________________________
821
822 FEI | 00(FLL) | 1(INT) | 0(FLL) | X
823 ____________________________________________________________________
824
825 FEE | 00(FLL) | 0(EXT) | 0(FLL) | X
826 ____________________________________________________________________
827
828 FBE | 10(EXT) | 0(EXT) | 0(FLL) | 0(NORMAL)
829 ____________________________________________________________________
830
831 FBI | 01(INT) | 1(INT) | 0(FLL) | 0(NORMAL)
832 ____________________________________________________________________
833
834 BLPI | 01(INT) | 1(INT) | 0(FLL) | 1(LOW POWER)
835 ____________________________________________________________________
836
837 BLPE | 10(EXT) | 0(EXT) | X | 1(LOW POWER)
838 ____________________________________________________________________
839
840 PEE | 11(PLL) | 0(EXT) | 1(PLL) | X
841 ____________________________________________________________________
842
843 PBE | 10(EXT) | 0(EXT) | 1(PLL) | O(NORMAL)
844 ____________________________________________________________________
845
846 PBI | 01(INT) | 1(INT) | 1(PLL) | 0(NORMAL)
847 ____________________________________________________________________
848
849 PEI | 11(PLL) | 1(INT) | 1(PLL) | X
850 ____________________________________________________________________
851
852 ----------------------------------------------------------------------*/
853
854 switch (clkst)
855 {
856 case kMCG_ClkOutStatFll:
857 if (kMCG_FllSrcExternal == irefst)
858 {
859 mode = kMCG_ModeFEE;
860 }
861 else
862 {
863 mode = kMCG_ModeFEI;
864 }
865 break;
866 case kMCG_ClkOutStatInt:
867 if (lp)
868 {
869 mode = kMCG_ModeBLPI;
870 }
871 else
872 {
873 {
874 mode = kMCG_ModeFBI;
875 }
876 }
877 break;
878 case kMCG_ClkOutStatExt:
879 if (lp)
880 {
881 mode = kMCG_ModeBLPE;
882 }
883 else
884 {
885 {
886 mode = kMCG_ModeFBE;
887 }
888 }
889 break;
890 default:
891 break;
892 }
893
894 return mode;
895 }
896
CLOCK_SetFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))897 status_t CLOCK_SetFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
898 {
899 uint8_t mcg_c4;
900 bool change_drs = false;
901
902 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
903 mcg_mode_t mode = CLOCK_GetMode();
904 if (!((kMCG_ModeFEI == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEE == mode)))
905 {
906 return kStatus_MCG_ModeUnreachable;
907 }
908 #endif
909 mcg_c4 = MCG->C4;
910
911 /*
912 Errata: ERR007993
913 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
914 reference clock source changes, then reset to previous value after
915 reference clock changes.
916 */
917 if (kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
918 {
919 change_drs = true;
920 /* Change the LSB of DRST_DRS. */
921 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
922 }
923
924 /* Set CLKS and IREFS. */
925 MCG->C1 =
926 ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK))) | (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
927 | MCG_C1_IREFS(kMCG_FllSrcInternal)); /* IREFS = 1 */
928
929 /* Wait and check status. */
930 while (kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
931 {
932 }
933
934 /* Errata: ERR007993 */
935 if (change_drs)
936 {
937 MCG->C4 = mcg_c4;
938 }
939
940 /* In FEI mode, the MCG_C4[DMX32] is set to 0U. */
941 MCG->C4 = (mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs));
942
943 /* Check MCG_S[CLKST] */
944 while (kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
945 {
946 }
947
948 /* Wait for FLL stable time. */
949 if (fllStableDelay)
950 {
951 fllStableDelay();
952 }
953
954 return kStatus_Success;
955 }
956
CLOCK_SetFeeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))957 status_t CLOCK_SetFeeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
958 {
959 uint8_t mcg_c4;
960 bool change_drs = false;
961
962 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
963 mcg_mode_t mode = CLOCK_GetMode();
964 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode)))
965 {
966 return kStatus_MCG_ModeUnreachable;
967 }
968 #endif
969 mcg_c4 = MCG->C4;
970
971 /*
972 Errata: ERR007993
973 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
974 reference clock source changes, then reset to previous value after
975 reference clock changes.
976 */
977 if (kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
978 {
979 change_drs = true;
980 /* Change the LSB of DRST_DRS. */
981 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
982 }
983
984 /* Set CLKS and IREFS. */
985 MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
986 (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
987 | MCG_C1_FRDIV(frdiv) /* FRDIV */
988 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
989
990 /* If use external crystal as clock source, wait for it stable. */
991 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
992 {
993 if (MCG->C2 & MCG_C2_EREFS_MASK)
994 {
995 while (!(MCG->S & MCG_S_OSCINIT0_MASK))
996 {
997 }
998 }
999 }
1000
1001 /* Wait and check status. */
1002 while (kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1003 {
1004 }
1005
1006 /* Errata: ERR007993 */
1007 if (change_drs)
1008 {
1009 MCG->C4 = mcg_c4;
1010 }
1011
1012 /* Set DRS and DMX32. */
1013 mcg_c4 = ((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1014 MCG->C4 = mcg_c4;
1015
1016 /* Wait for DRST_DRS update. */
1017 while (MCG->C4 != mcg_c4)
1018 {
1019 }
1020
1021 /* Check MCG_S[CLKST] */
1022 while (kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1023 {
1024 }
1025
1026 /* Wait for FLL stable time. */
1027 if (fllStableDelay)
1028 {
1029 fllStableDelay();
1030 }
1031
1032 return kStatus_Success;
1033 }
1034
CLOCK_SetFbiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1035 status_t CLOCK_SetFbiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1036 {
1037 uint8_t mcg_c4;
1038 bool change_drs = false;
1039
1040 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1041 mcg_mode_t mode = CLOCK_GetMode();
1042
1043 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1044 (kMCG_ModeBLPI == mode)))
1045
1046 {
1047 return kStatus_MCG_ModeUnreachable;
1048 }
1049 #endif
1050
1051 mcg_c4 = MCG->C4;
1052
1053 MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
1054
1055 /*
1056 Errata: ERR007993
1057 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1058 reference clock source changes, then reset to previous value after
1059 reference clock changes.
1060 */
1061 if (kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1062 {
1063 change_drs = true;
1064 /* Change the LSB of DRST_DRS. */
1065 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1066 }
1067
1068 /* Set CLKS and IREFS. */
1069 MCG->C1 =
1070 ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(kMCG_ClkOutSrcInternal) /* CLKS = 1 */
1071 | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1072
1073 /* Wait and check status. */
1074 while (kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1075 {
1076 }
1077
1078 /* Errata: ERR007993 */
1079 if (change_drs)
1080 {
1081 MCG->C4 = mcg_c4;
1082 }
1083
1084 while (kMCG_ClkOutStatInt != MCG_S_CLKST_VAL)
1085 {
1086 }
1087
1088 MCG->C4 = (mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs));
1089
1090 /* Wait for FLL stable time. */
1091 if (fllStableDelay)
1092 {
1093 fllStableDelay();
1094 }
1095
1096 return kStatus_Success;
1097 }
1098
CLOCK_SetFbeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1099 status_t CLOCK_SetFbeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1100 {
1101 uint8_t mcg_c4;
1102 bool change_drs = false;
1103
1104 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1105 mcg_mode_t mode = CLOCK_GetMode();
1106 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1107 (kMCG_ModeBLPE == mode)))
1108 {
1109 return kStatus_MCG_ModeUnreachable;
1110 }
1111 #endif
1112
1113
1114 /* Set LP bit to enable the FLL */
1115 MCG->C2 &= ~MCG_C2_LP_MASK;
1116
1117 mcg_c4 = MCG->C4;
1118
1119 /*
1120 Errata: ERR007993
1121 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1122 reference clock source changes, then reset to previous value after
1123 reference clock changes.
1124 */
1125 if (kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1126 {
1127 change_drs = true;
1128 /* Change the LSB of DRST_DRS. */
1129 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1130 }
1131
1132 /* Set CLKS and IREFS. */
1133 MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1134 (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
1135 | MCG_C1_FRDIV(frdiv) /* FRDIV = frdiv */
1136 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1137
1138 /* If use external crystal as clock source, wait for it stable. */
1139 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
1140 {
1141 if (MCG->C2 & MCG_C2_EREFS_MASK)
1142 {
1143 while (!(MCG->S & MCG_S_OSCINIT0_MASK))
1144 {
1145 }
1146 }
1147 }
1148
1149 /* Wait for Reference clock Status bit to clear */
1150 while (kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1151 {
1152 }
1153
1154 /* Errata: ERR007993 */
1155 if (change_drs)
1156 {
1157 MCG->C4 = mcg_c4;
1158 }
1159
1160 /* Set DRST_DRS and DMX32. */
1161 mcg_c4 = ((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1162
1163 /* Wait for clock status bits to show clock source is ext ref clk */
1164 while (kMCG_ClkOutStatExt != MCG_S_CLKST_VAL)
1165 {
1166 }
1167
1168 /* Wait for fll stable time. */
1169 if (fllStableDelay)
1170 {
1171 fllStableDelay();
1172 }
1173
1174 return kStatus_Success;
1175 }
1176
CLOCK_SetBlpiMode(void)1177 status_t CLOCK_SetBlpiMode(void)
1178 {
1179 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1180 if (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
1181 {
1182 return kStatus_MCG_ModeUnreachable;
1183 }
1184 #endif /* MCG_CONFIG_CHECK_PARAM */
1185
1186 /* Set LP. */
1187 MCG->C2 |= MCG_C2_LP_MASK;
1188
1189 return kStatus_Success;
1190 }
1191
CLOCK_SetBlpeMode(void)1192 status_t CLOCK_SetBlpeMode(void)
1193 {
1194 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1195 if (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
1196 {
1197 return kStatus_MCG_ModeUnreachable;
1198 }
1199 #endif
1200
1201 /* Set LP bit to enter BLPE mode. */
1202 MCG->C2 |= MCG_C2_LP_MASK;
1203
1204 return kStatus_Success;
1205 }
1206
1207
CLOCK_ExternalModeToFbeModeQuick(void)1208 status_t CLOCK_ExternalModeToFbeModeQuick(void)
1209 {
1210 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1211 if (MCG->S & MCG_S_IREFST_MASK)
1212 {
1213 return kStatus_MCG_ModeInvalid;
1214 }
1215 #endif /* MCG_CONFIG_CHECK_PARAM */
1216
1217 /* Disable low power */
1218 MCG->C2 &= ~MCG_C2_LP_MASK;
1219
1220 MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
1221 while (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
1222 {
1223 }
1224
1225
1226 return kStatus_Success;
1227 }
1228
CLOCK_InternalModeToFbiModeQuick(void)1229 status_t CLOCK_InternalModeToFbiModeQuick(void)
1230 {
1231 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1232 if (!(MCG->S & MCG_S_IREFST_MASK))
1233 {
1234 return kStatus_MCG_ModeInvalid;
1235 }
1236 #endif
1237
1238 /* Disable low power */
1239 MCG->C2 &= ~MCG_C2_LP_MASK;
1240
1241 MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
1242 while (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
1243 {
1244 }
1245
1246
1247 return kStatus_Success;
1248 }
1249
CLOCK_BootToFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1250 status_t CLOCK_BootToFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1251 {
1252 return CLOCK_SetFeiMode(dmx32, drs, fllStableDelay);
1253 }
1254
CLOCK_BootToFeeMode(mcg_oscsel_t oscsel,uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1255 status_t CLOCK_BootToFeeMode(
1256 mcg_oscsel_t oscsel, uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1257 {
1258
1259 CLOCK_SetExternalRefClkConfig(oscsel);
1260
1261 return CLOCK_SetFeeMode(frdiv, dmx32, drs, fllStableDelay);
1262 }
1263
CLOCK_BootToBlpiMode(uint8_t fcrdiv,mcg_irc_mode_t ircs,uint8_t ircEnableMode)1264 status_t CLOCK_BootToBlpiMode(uint8_t fcrdiv, mcg_irc_mode_t ircs, uint8_t ircEnableMode)
1265 {
1266 /* If reset mode is FEI mode, set MCGIRCLK and always success. */
1267 CLOCK_SetInternalRefClkConfig(ircEnableMode, ircs, fcrdiv);
1268
1269 /* If reset mode is not BLPI, first enter FBI mode. */
1270 MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal);
1271 while (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
1272 {
1273 }
1274
1275 /* Enter BLPI mode. */
1276 MCG->C2 |= MCG_C2_LP_MASK;
1277
1278 return kStatus_Success;
1279 }
1280
CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)1281 status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)
1282 {
1283
1284 CLOCK_SetExternalRefClkConfig(oscsel);
1285
1286 /* Set to FBE mode. */
1287 MCG->C1 =
1288 ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
1289 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1290
1291 /* If use external crystal as clock source, wait for it stable. */
1292 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
1293 {
1294 if (MCG->C2 & MCG_C2_EREFS_MASK)
1295 {
1296 while (!(MCG->S & MCG_S_OSCINIT0_MASK))
1297 {
1298 }
1299 }
1300 }
1301
1302 /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */
1303 while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
1304 (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
1305 {
1306 }
1307
1308 /* In FBE now, start to enter BLPE. */
1309 MCG->C2 |= MCG_C2_LP_MASK;
1310
1311 return kStatus_Success;
1312 }
1313
1314
1315 /*
1316 The transaction matrix. It defines the path for mode switch, the row is for
1317 current mode and the column is target mode.
1318 For example, switch from FEI to PEE:
1319 1. Current mode FEI, next mode is mcgModeMatrix[FEI][PEE] = FBE, so swith to FBE.
1320 2. Current mode FBE, next mode is mcgModeMatrix[FBE][PEE] = PBE, so swith to PBE.
1321 3. Current mode PBE, next mode is mcgModeMatrix[PBE][PEE] = PEE, so swith to PEE.
1322 Thus the MCG mode has changed from FEI to PEE.
1323 */
1324 static const mcg_mode_t mcgModeMatrix[6][6] = {
1325 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FEI */
1326 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FBI */
1327 {kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI}, /* BLPI */
1328 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FEE */
1329 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeBLPE}, /* FBE */
1330 {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE}, /* BLPE */
1331 /* FEI FBI BLPI FEE FBE BLPE */
1332 };
1333
CLOCK_SetMcgConfig(const mcg_config_t * config)1334 status_t CLOCK_SetMcgConfig(const mcg_config_t *config)
1335 {
1336 mcg_mode_t next_mode;
1337 status_t status = kStatus_Success;
1338
1339
1340 /* If need to change external clock, MCG_C7[OSCSEL]. */
1341 if (MCG_C7_OSCSEL_VAL != config->oscsel)
1342 {
1343 /* If external clock is in use, change to FEI first. */
1344 if (!(MCG->S & MCG_S_IRCST_MASK))
1345 {
1346 CLOCK_ExternalModeToFbeModeQuick();
1347 CLOCK_SetFeiMode(config->dmx32, config->drs, (void (*)(void))0);
1348 }
1349
1350 CLOCK_SetExternalRefClkConfig(config->oscsel);
1351 }
1352
1353 /* Re-configure MCGIRCLK, if MCGIRCLK is used as system clock source, then change to FEI/PEI first. */
1354 if (MCG_S_CLKST_VAL == kMCG_ClkOutStatInt)
1355 {
1356 MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
1357
1358 {
1359 CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
1360 }
1361 }
1362
1363 /* Configure MCGIRCLK. */
1364 CLOCK_SetInternalRefClkConfig(config->irclkEnableMode, config->ircs, config->fcrdiv);
1365
1366 next_mode = CLOCK_GetMode();
1367
1368 do
1369 {
1370 next_mode = mcgModeMatrix[next_mode][config->mcgMode];
1371
1372 switch (next_mode)
1373 {
1374 case kMCG_ModeFEI:
1375 status = CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
1376 break;
1377 case kMCG_ModeFEE:
1378 status = CLOCK_SetFeeMode(config->frdiv, config->dmx32, config->drs, CLOCK_FllStableDelay);
1379 break;
1380 case kMCG_ModeFBI:
1381 status = CLOCK_SetFbiMode(config->dmx32, config->drs, (void (*)(void))0);
1382 break;
1383 case kMCG_ModeFBE:
1384 status = CLOCK_SetFbeMode(config->frdiv, config->dmx32, config->drs, (void (*)(void))0);
1385 break;
1386 case kMCG_ModeBLPI:
1387 status = CLOCK_SetBlpiMode();
1388 break;
1389 case kMCG_ModeBLPE:
1390 status = CLOCK_SetBlpeMode();
1391 break;
1392 default:
1393 break;
1394 }
1395 if (kStatus_Success != status)
1396 {
1397 return status;
1398 }
1399 } while (next_mode != config->mcgMode);
1400
1401 return kStatus_Success;
1402 }
1403