rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
fsl_clock.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright (c) 2016 - 2017 , NXP
4 * All rights reserved.
5 *
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 */
9
10#include "hal.h"
11#include "fsl_clock.h"
12
13/*******************************************************************************
14 * Definitions
15 ******************************************************************************/
16/* Component ID definition, used by tools. */
17#ifndef FSL_COMPONENT_ID
18#define FSL_COMPONENT_ID "platform.drivers.clock"
19#endif
20
21#define SCG_SIRC_LOW_RANGE_FREQ 2000000U /* Slow IRC low range clock frequency. */
22#define SCG_SIRC_HIGH_RANGE_FREQ 8000000U /* Slow IRC high range clock frequency. */
23
24#define SCG_FIRC_FREQ0 48000000U /* Fast IRC trimed clock frequency(48MHz). */
25#define SCG_FIRC_FREQ1 52000000U /* Fast IRC trimed clock frequency(52MHz). */
26#define SCG_FIRC_FREQ2 56000000U /* Fast IRC trimed clock frequency(56MHz). */
27#define SCG_FIRC_FREQ3 60000000U /* Fast IRC trimed clock frequency(60MHz). */
28
29/*
30 * System PLL base divider value, it is the PLL reference clock divider
31 * value when SCG_SPLLCFG[PREDIV]=0.
32 */
33#define SCG_SPLL_PREDIV_BASE_VALUE 1U
34
35/*
36 * System PLL base multiplier value, it is the PLL multiplier value
37 * when SCG_SPLLCFG[MULT]=0.
38 */
39#define SCG_SPLL_MULT_BASE_VALUE 16U
40
41#define SCG_SPLL_PREDIV_MAX_VALUE 7U /* Max value of SCG_SPLLCFG[PREDIV]. */
42#define SCG_SPLL_MULT_MAX_VALUE 31U /* Max value of SCG_SPLLCFG[MULT]. */
43
44/*
45 * System PLL reference clock after SCG_SPLLCFG[PREDIV] should be in
46 * the range of SCG_SPLL_REF_MIN to SCG_SPLL_REF_MAX.
47 */
48#define SCG_SPLL_REF_MIN 8000000U
49#define SCG_SPLL_REF_MAX 32000000U
50
51#define SCG_CSR_SCS_VAL ((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT)
52#define SCG_SOSCDIV_SOSCDIV1_VAL ((SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV1_MASK) >> SCG_SOSCDIV_SOSCDIV1_SHIFT)
53#define SCG_SOSCDIV_SOSCDIV2_VAL ((SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV2_MASK) >> SCG_SOSCDIV_SOSCDIV2_SHIFT)
54#define SCG_SIRCDIV_SIRCDIV1_VAL ((SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV1_MASK) >> SCG_SIRCDIV_SIRCDIV1_SHIFT)
55#define SCG_SIRCDIV_SIRCDIV2_VAL ((SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV2_MASK) >> SCG_SIRCDIV_SIRCDIV2_SHIFT)
56#define SCG_FIRCDIV_FIRCDIV1_VAL ((SCG->FIRCDIV & SCG_FIRCDIV_FIRCDIV1_MASK) >> SCG_FIRCDIV_FIRCDIV1_SHIFT)
57#define SCG_FIRCDIV_FIRCDIV2_VAL ((SCG->FIRCDIV & SCG_FIRCDIV_FIRCDIV2_MASK) >> SCG_FIRCDIV_FIRCDIV2_SHIFT)
58
59#define SCG_SPLLDIV_SPLLDIV1_VAL ((SCG->SPLLDIV & SCG_SPLLDIV_SPLLDIV1_MASK) >> SCG_SPLLDIV_SPLLDIV1_SHIFT)
60#define SCG_SPLLDIV_SPLLDIV2_VAL ((SCG->SPLLDIV & SCG_SPLLDIV_SPLLDIV2_MASK) >> SCG_SPLLDIV_SPLLDIV2_SHIFT)
61
62#define SCG_SIRCCFG_RANGE_VAL ((SCG->SIRCCFG & SCG_SIRCCFG_RANGE_MASK) >> SCG_SIRCCFG_RANGE_SHIFT)
63#define SCG_FIRCCFG_RANGE_VAL ((SCG->FIRCCFG & SCG_FIRCCFG_RANGE_MASK) >> SCG_FIRCCFG_RANGE_SHIFT)
64
65#define SCG_SPLLCFG_PREDIV_VAL ((SCG->SPLLCFG & SCG_SPLLCFG_PREDIV_MASK) >> SCG_SPLLCFG_PREDIV_SHIFT)
66#define SCG_SPLLCFG_MULT_VAL ((SCG->SPLLCFG & SCG_SPLLCFG_MULT_MASK) >> SCG_SPLLCFG_MULT_SHIFT)
67
68#define PCC_PCS_VAL(reg) (((reg) & PCC_CLKCFG_PCS_MASK) >> PCC_CLKCFG_PCS_SHIFT)
69
70/*******************************************************************************
71 * Variables
72 ******************************************************************************/
73
74/* External XTAL0 (OSC0) clock frequency. */
75volatile uint32_t g_xtal0Freq;
76/* External XTAL32K clock frequency. */
77volatile uint32_t g_xtal32Freq;
78
79/*******************************************************************************
80 * Prototypes
81 ******************************************************************************/
82
83/*!
84 * @brief Get the common System PLL frequency for both RAW SPLL output and SPLL PFD output.
85 *
86 * The "raw" SPLL output is the clkout divided by postdiv1-2 of SAPLL.
87 * The "common" System PLL frequency is the common part for both RAW SPLL and SPLL PFD output.
88 * That is the frequency calculated based on the clock source which passes through POSTDIV & MULT.
89 * "Common" SPLL Frequency = Divided Reference Frequency * MULT
90 *
91 * @return Clock frequency; If the clock is invalid, returns 0.
92 */
93static uint32_t CLOCK_GetSysPllCommonFreq(void);
94
95/*******************************************************************************
96 * Code
97 ******************************************************************************/
98
99/*!
100 * brief Get the external reference clock frequency (ERCLK).
101 *
102 * return Clock frequency in Hz.
103 */
104uint32_t CLOCK_GetErClkFreq(void)
105{
106 if (SCG->SOSCCSR & SCG_SOSCCSR_SOSCEN_MASK)
107 {
108 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
109 assert(g_xtal0Freq);
110 return g_xtal0Freq;
111 }
112 else
113 {
114 return 0U;
115 }
116}
117
118/*!
119 * brief Get the OSC 32K clock frequency (OSC32KCLK).
120 *
121 * return Clock frequency in Hz.
122 */
124{
125 assert(g_xtal32Freq);
126 return g_xtal32Freq;
127}
128
129/*!
130 * brief Get the flash clock frequency.
131 *
132 * return Clock frequency in Hz.
133 */
135{
137}
138
139/*!
140 * brief Get the bus clock frequency.
141 *
142 * return Clock frequency in Hz.
143 */
145{
147}
148
149/*!
150 * brief Get the core clock or system clock frequency.
151 *
152 * return Clock frequency in Hz.
153 */
155{
157}
158
159/*!
160 * brief Gets the clock frequency for a specific clock name.
161 *
162 * This function checks the current clock configurations and then calculates
163 * the clock frequency for a specific clock name defined in clock_name_t.
164 *
165 * param clockName Clock names defined in clock_name_t
166 * return Clock frequency value in hertz
167 */
168uint32_t CLOCK_GetFreq(clock_name_t clockName)
169{
170 uint32_t freq;
171
172 switch (clockName)
173 {
176 break;
177 case kCLOCK_BusClk:
179 break;
180 case kCLOCK_FlashClk:
182 break;
183
185 freq = CLOCK_GetSysOscFreq();
186 break;
188 freq = CLOCK_GetSircFreq();
189 break;
191 freq = CLOCK_GetFircFreq();
192 break;
194 freq = CLOCK_GetSysPllFreq();
195 break;
196
199 break;
202 break;
203
206 break;
209 break;
210
213 break;
216 break;
217
220 break;
223 break;
224
225 case kCLOCK_LpoClk:
226 freq = LPO_CLK_FREQ;
227 break;
228 case kCLOCK_Osc32kClk:
229 freq = CLOCK_GetOsc32kClkFreq();
230 break;
231 case kCLOCK_ErClk:
232 freq = CLOCK_GetErClkFreq();
233 break;
234 default:
235 freq = 0U;
236 break;
237 }
238 return freq;
239}
240
241/*!
242 * brief Gets the clock frequency for a specific IP module.
243 *
244 * This function gets the IP module clock frequency based on PCC registers. It is
245 * only used for the IP modules which could select clock source by PCC[PCS].
246 *
247 * param name Which peripheral to get, see \ref clock_ip_name_t.
248 * return Clock frequency value in hertz
249 */
251{
252 uint32_t reg = (*(volatile uint32_t *)name);
253
254 scg_async_clk_t asycClk;
255 uint32_t freq;
256
257 assert(reg & PCC_CLKCFG_PR_MASK);
258
259 /* FTM uses SCG DIV1 clock, others use SCG DIV2 clock. */
260 if ((kCLOCK_Ftm0 == name) || (kCLOCK_Ftm1 == name) || (kCLOCK_Ftm2 == name) || (kCLOCK_Ftm3 == name))
261 {
262 asycClk = kSCG_AsyncDiv1Clk;
263 }
264 else
265 {
266 asycClk = kSCG_AsyncDiv2Clk;
267 }
268
269 switch (PCC_PCS_VAL(reg))
270 {
272 freq = CLOCK_GetSysOscAsyncFreq(asycClk);
273 break;
275 freq = CLOCK_GetSircAsyncFreq(asycClk);
276 break;
278 freq = CLOCK_GetFircAsyncFreq(asycClk);
279 break;
281 freq = CLOCK_GetSysPllAsyncFreq(asycClk);
282 break;
283 default:
284 freq = 0U;
285 break;
286 }
287
288 return freq;
289}
290
291/*!
292 * brief Initializes OSC32.
293 *
294 * param base OSC32 peripheral base address.
295 * param mode OSC32 work mode, see ref osc32_mode_t
296 */
297void OSC32_Init(OSC32_Type *base, osc32_mode_t mode)
298{
299 /* Only support one instance now. */
300 assert(OSC32 == base);
301
303
304 /* Set work mode. */
305 base->CR = (uint8_t)mode;
306
307 if (mode & OSC32_CR_ROSCEREFS_MASK)
308 {
309 /* If use crystal mode, wait for stable. */
310 while (!(base->CR & OSC32_CR_ROSCSTB_MASK))
311 {
312 }
313 }
314}
315
316/*!
317 * brief Deinitializes OSC32.
318 *
319 * param base OSC32 peripheral base address.
320 */
321void OSC32_Deinit(OSC32_Type *base)
322{
323 /* Only support one instance now. */
324 assert(OSC32 == base);
325
326 base->CR = 0U;
328}
329
330/*!
331 * brief Gets the SCG system clock frequency.
332 *
333 * This function gets the SCG system clock frequency. These clocks are used for
334 * core, platform, external, and bus clock domains.
335 *
336 * param type Which type of clock to get, core clock or slow clock.
337 * return Clock frequency.
338 */
340{
341 uint32_t freq;
342
343 scg_sys_clk_config_t sysClkConfig;
344
345 CLOCK_GetCurSysClkConfig(&sysClkConfig);
346
347 switch (sysClkConfig.src)
348 {
350 freq = CLOCK_GetSysOscFreq();
351 break;
353 freq = CLOCK_GetSircFreq();
354 break;
356 freq = CLOCK_GetFircFreq();
357 break;
359 freq = CLOCK_GetSysPllFreq();
360 break;
361 default:
362 freq = 0U;
363 break;
364 }
365
366 freq /= (sysClkConfig.divCore + 1U);
367
368 if (kSCG_SysClkSlow == type)
369 {
370 freq /= (sysClkConfig.divSlow + 1U);
371 }
372 else if (kSCG_SysClkBus == type)
373 {
374 freq /= (sysClkConfig.divBus + 1U);
375 }
376 else
377 {
378 }
379
380 return freq;
381}
382
383/*!
384 * brief Initializes the SCG system OSC.
385 *
386 * This function enables the SCG system OSC clock according to the
387 * configuration.
388 *
389 * param config Pointer to the configuration structure.
390 * retval kStatus_Success System OSC is initialized.
391 * retval kStatus_SCG_Busy System OSC has been enabled and is used by the system clock.
392 * retval kStatus_ReadOnly System OSC control register is locked.
393 *
394 * note This function can't detect whether the system OSC has been enabled and
395 * used by an IP.
396 */
398{
399 assert(config);
400 uint8_t range = 0U; /* SCG_SOSCCFG[RANGE] */
401 status_t status;
402 uint8_t tmp8;
403
404 /* If crystal oscillator used, need to get RANGE value base on frequency. */
405 if (kSCG_SysOscModeExt != config->workMode)
406 {
407 if ((config->freq >= 32768U) && (config->freq <= 40000U))
408 {
409 range = 1U;
410 }
411 else if ((config->freq >= 1000000U) && (config->freq <= 8000000U))
412 {
413 range = 2U;
414 }
415 else if ((config->freq >= 8000000U) && (config->freq <= 32000000U))
416 {
417 range = 3U;
418 }
419 else
420 {
422 }
423 }
424
425 /* De-init the SOSC first. */
426 status = CLOCK_DeinitSysOsc();
427
428 if (kStatus_Success != status)
429 {
430 return status;
431 }
432
433 /* Now start to set up OSC clock. */
434 /* Step 1. Setup dividers. */
435 SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV1(config->div1) | SCG_SOSCDIV_SOSCDIV2(config->div2);
436
437 /* Step 2. Set OSC configuration. */
438 SCG->SOSCCFG = config->workMode | SCG_SOSCCFG_RANGE(range);
439
440 /* Step 3. Enable clock. */
441 /* SCG->SOSCCSR = SCG_SOSCCSR_SOSCEN_MASK | (config->enableMode); */
442 tmp8 = config->enableMode;
443 tmp8 |= SCG_SOSCCSR_SOSCEN_MASK;
444 SCG->SOSCCSR = tmp8;
445
446 /* Step 4. Wait for OSC clock to be valid. */
447 while (!(SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK))
448 {
449 }
450
451 /* Step 5. Enabe monitor. */
452 SCG->SOSCCSR |= (uint32_t)config->monitorMode;
453
454 return kStatus_Success;
455}
456
457/*!
458 * brief De-initializes the SCG system OSC.
459 *
460 * This function disables the SCG system OSC clock.
461 *
462 * retval kStatus_Success System OSC is deinitialized.
463 * retval kStatus_SCG_Busy System OSC is used by the system clock.
464 * retval kStatus_ReadOnly System OSC control register is locked.
465 *
466 * note This function can't detect whether the system OSC is used by an IP.
467 */
469{
470 uint32_t reg = SCG->SOSCCSR;
471
472 /* If clock is used by system, return error. */
473 if (reg & SCG_SOSCCSR_SOSCSEL_MASK)
474 {
475 return kStatus_SCG_Busy;
476 }
477
478 /* If configure register is locked, return error. */
479 if (reg & SCG_SOSCCSR_LK_MASK)
480 {
481 return kStatus_ReadOnly;
482 }
483
484 SCG->SOSCCSR = SCG_SOSCCSR_SOSCERR_MASK;
485
486 return kStatus_Success;
487}
488
489/*!
490 * brief Gets the SCG system OSC clock frequency (SYSOSC).
491 *
492 * return Clock frequency; If the clock is invalid, returns 0.
493 */
495{
496 if (SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) /* System OSC clock is valid. */
497 {
498 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
499 assert(g_xtal0Freq);
500 return g_xtal0Freq;
501 }
502 else
503 {
504 return 0U;
505 }
506}
507
508/*!
509 * brief Gets the SCG asynchronous clock frequency from the system OSC.
510 *
511 * param type The asynchronous clock type.
512 * return Clock frequency; If the clock is invalid, returns 0.
513 */
515{
516 uint32_t oscFreq = CLOCK_GetSysOscFreq();
517 uint32_t divider = 0U;
518
519 /* Get divider. */
520 if (oscFreq)
521 {
522 switch (type)
523 {
524 case kSCG_AsyncDiv2Clk: /* SOSCDIV2_CLK. */
525 divider = SCG_SOSCDIV_SOSCDIV2_VAL;
526 break;
527 case kSCG_AsyncDiv1Clk: /* SOSCDIV1_CLK. */
528 divider = SCG_SOSCDIV_SOSCDIV1_VAL;
529 break;
530 default:
531 break;
532 }
533 }
534 if (divider)
535 {
536 return oscFreq >> (divider - 1U);
537 }
538 else /* Output disabled. */
539 {
540 return 0U;
541 }
542}
543
544/*!
545 * brief Initializes the SCG slow IRC clock.
546 *
547 * This function enables the SCG slow IRC clock according to the
548 * configuration.
549 *
550 * param config Pointer to the configuration structure.
551 * retval kStatus_Success SIRC is initialized.
552 * retval kStatus_SCG_Busy SIRC has been enabled and is used by system clock.
553 * retval kStatus_ReadOnly SIRC control register is locked.
554 *
555 * note This function can't detect whether the system OSC has been enabled and
556 * used by an IP.
557 */
559{
560 assert(config);
561
562 status_t status;
563
564 /* De-init the SIRC first. */
565 status = CLOCK_DeinitSirc();
566
567 if (kStatus_Success != status)
568 {
569 return status;
570 }
571
572 /* Now start to set up SIRC clock. */
573 /* Step 1. Setup dividers. */
574 SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV1(config->div1) | SCG_SIRCDIV_SIRCDIV2(config->div2);
575
576 /* Step 2. Set SIRC configuration. */
577 SCG->SIRCCFG = SCG_SIRCCFG_RANGE(config->range);
578
579 /* Step 3. Enable clock. */
580 SCG->SIRCCSR = SCG_SIRCCSR_SIRCEN_MASK | config->enableMode;
581
582 /* Step 4. Wait for SIRC clock to be valid. */
583 while (!(SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK))
584 {
585 }
586
587 return kStatus_Success;
588}
589
590/*!
591 * brief De-initializes the SCG slow IRC.
592 *
593 * This function disables the SCG slow IRC.
594 *
595 * retval kStatus_Success SIRC is deinitialized.
596 * retval kStatus_SCG_Busy SIRC is used by system clock.
597 * retval kStatus_ReadOnly SIRC control register is locked.
598 *
599 * note This function can't detect whether the SIRC is used by an IP.
600 */
602{
603 uint32_t reg = SCG->SIRCCSR;
604
605 /* If clock is used by system, return error. */
606 if (reg & SCG_SIRCCSR_SIRCSEL_MASK)
607 {
608 return kStatus_SCG_Busy;
609 }
610
611 /* If configure register is locked, return error. */
612 if (reg & SCG_SIRCCSR_LK_MASK)
613 {
614 return kStatus_ReadOnly;
615 }
616
617 SCG->SIRCCSR = 0U;
618
619 return kStatus_Success;
620}
621
622/*!
623 * brief Gets the SCG SIRC clock frequency.
624 *
625 * return Clock frequency; If the clock is invalid, returns 0.
626 */
627uint32_t CLOCK_GetSircFreq(void)
628{
629 static const uint32_t sircFreq[] = {SCG_SIRC_LOW_RANGE_FREQ, SCG_SIRC_HIGH_RANGE_FREQ};
630
631 if (SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK) /* SIRC is valid. */
632 {
633 return sircFreq[SCG_SIRCCFG_RANGE_VAL];
634 }
635 else
636 {
637 return 0U;
638 }
639}
640
641/*!
642 * brief Gets the SCG asynchronous clock frequency from the SIRC.
643 *
644 * param type The asynchronous clock type.
645 * return Clock frequency; If the clock is invalid, returns 0.
646 */
648{
649 uint32_t sircFreq = CLOCK_GetSircFreq();
650 uint32_t divider = 0U;
651
652 /* Get divider. */
653 if (sircFreq)
654 {
655 switch (type)
656 {
657 case kSCG_AsyncDiv2Clk: /* SIRCDIV2_CLK. */
658 divider = SCG_SIRCDIV_SIRCDIV2_VAL;
659 break;
660 case kSCG_AsyncDiv1Clk: /* SIRCDIV2_CLK. */
661 divider = SCG_SIRCDIV_SIRCDIV1_VAL;
662 break;
663 default:
664 break;
665 }
666 }
667 if (divider)
668 {
669 return sircFreq >> (divider - 1U);
670 }
671 else /* Output disabled. */
672 {
673 return 0U;
674 }
675}
676
677/*!
678 * brief Initializes the SCG fast IRC clock.
679 *
680 * This function enables the SCG fast IRC clock according to the configuration.
681 *
682 * param config Pointer to the configuration structure.
683 * retval kStatus_Success FIRC is initialized.
684 * retval kStatus_SCG_Busy FIRC has been enabled and is used by the system clock.
685 * retval kStatus_ReadOnly FIRC control register is locked.
686 *
687 * note This function can't detect whether the FIRC has been enabled and
688 * used by an IP.
689 */
691{
692 assert(config);
693
694 status_t status;
695
696 /* De-init the FIRC first. */
697 status = CLOCK_DeinitFirc();
698
699 if (kStatus_Success != status)
700 {
701 return status;
702 }
703
704 /* Now start to set up FIRC clock. */
705 /* Step 1. Setup dividers. */
706 SCG->FIRCDIV = SCG_FIRCDIV_FIRCDIV1(config->div1) | SCG_FIRCDIV_FIRCDIV2(config->div2);
707
708 /* Step 2. Set FIRC configuration. */
709 SCG->FIRCCFG = SCG_FIRCCFG_RANGE(config->range);
710
711 /* Step 3. Set trimming configuration. */
712 if (config->trimConfig)
713 {
714 SCG->FIRCTCFG =
715 SCG_FIRCTCFG_TRIMDIV(config->trimConfig->trimDiv) | SCG_FIRCTCFG_TRIMSRC(config->trimConfig->trimSrc);
716
717 /* TODO: Write FIRCSTAT cause bus error: TKT266932. */
718 if (kSCG_FircTrimNonUpdate == config->trimConfig->trimMode)
719 {
720 SCG->FIRCSTAT = SCG_FIRCSTAT_TRIMCOAR(config->trimConfig->trimCoar) |
721 SCG_FIRCSTAT_TRIMFINE(config->trimConfig->trimFine);
722 }
723
724 /* trim mode. */
725 SCG->FIRCCSR = config->trimConfig->trimMode;
726
727 if (SCG->FIRCCSR & SCG_FIRCCSR_FIRCERR_MASK)
728 {
729 return kStatus_Fail;
730 }
731 }
732
733 /* Step 4. Enable clock. */
734 SCG->FIRCCSR |= (SCG_FIRCCSR_FIRCEN_MASK | config->enableMode);
735
736 /* Step 5. Wait for FIRC clock to be valid. */
737 while (!(SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK))
738 {
739 }
740
741 return kStatus_Success;
742}
743
744/*!
745 * brief De-initializes the SCG fast IRC.
746 *
747 * This function disables the SCG fast IRC.
748 *
749 * retval kStatus_Success FIRC is deinitialized.
750 * retval kStatus_SCG_Busy FIRC is used by the system clock.
751 * retval kStatus_ReadOnly FIRC control register is locked.
752 *
753 * note This function can't detect whether the FIRC is used by an IP.
754 */
756{
757 uint32_t reg = SCG->FIRCCSR;
758
759 /* If clock is used by system, return error. */
760 if (reg & SCG_FIRCCSR_FIRCSEL_MASK)
761 {
762 return kStatus_SCG_Busy;
763 }
764
765 /* If configure register is locked, return error. */
766 if (reg & SCG_FIRCCSR_LK_MASK)
767 {
768 return kStatus_ReadOnly;
769 }
770
771 SCG->FIRCCSR = SCG_FIRCCSR_FIRCERR_MASK;
772
773 return kStatus_Success;
774}
775
776/*!
777 * brief Gets the SCG FIRC clock frequency.
778 *
779 * return Clock frequency; If the clock is invalid, returns 0.
780 */
781uint32_t CLOCK_GetFircFreq(void)
782{
783 static const uint32_t fircFreq[] = {
784 SCG_FIRC_FREQ0, SCG_FIRC_FREQ1, SCG_FIRC_FREQ2, SCG_FIRC_FREQ3,
785 };
786
787 if (SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK) /* FIRC is valid. */
788 {
789 return fircFreq[SCG_FIRCCFG_RANGE_VAL];
790 }
791 else
792 {
793 return 0U;
794 }
795}
796
797/*!
798 * brief Gets the SCG asynchronous clock frequency from the FIRC.
799 *
800 * param type The asynchronous clock type.
801 * return Clock frequency; If the clock is invalid, returns 0.
802 */
804{
805 uint32_t fircFreq = CLOCK_GetFircFreq();
806 uint32_t divider = 0U;
807
808 /* Get divider. */
809 if (fircFreq)
810 {
811 switch (type)
812 {
813 case kSCG_AsyncDiv2Clk: /* FIRCDIV2_CLK. */
814 divider = SCG_FIRCDIV_FIRCDIV2_VAL;
815 break;
816 case kSCG_AsyncDiv1Clk: /* FIRCDIV1_CLK. */
817 divider = SCG_FIRCDIV_FIRCDIV1_VAL;
818 break;
819 default:
820 break;
821 }
822 }
823 if (divider)
824 {
825 return fircFreq >> (divider - 1U);
826 }
827 else /* Output disabled. */
828 {
829 return 0U;
830 }
831}
832
833/*!
834 * brief Calculates the MULT and PREDIV for the PLL.
835 *
836 * This function calculates the proper MULT and PREDIV to generate the desired PLL
837 * output frequency with the input reference clock frequency. It returns the closest
838 * frequency match that the PLL can generate. The corresponding MULT/PREDIV are returned with
839 * parameters. If the desired frequency is not valid, this function returns 0.
840 *
841 * param refFreq The input reference clock frequency.
842 * param desireFreq The desired output clock frequency.
843 * param mult The value of MULT.
844 * param prediv The value of PREDIV.
845 * return The PLL output frequency with the MULT and PREDIV; If
846 * the desired frequency can't be generated, this function returns 0U.
847 */
848uint32_t CLOCK_GetSysPllMultDiv(uint32_t refFreq, uint32_t desireFreq, uint8_t *mult, uint8_t *prediv)
849{
850 uint8_t ret_prediv; /* PREDIV to return */
851 uint8_t ret_mult; /* MULT to return */
852 uint8_t prediv_min; /* Minimal PREDIV value to make reference clock in allowed range. */
853 uint8_t prediv_max; /* Max PREDIV value to make reference clock in allowed range. */
854 uint8_t prediv_cur; /* PREDIV value for iteration. */
855 uint8_t mult_cur; /* MULT value for iteration. */
856 uint32_t ret_freq = 0U; /* Output frequency to return .*/
857 uint32_t diff = 0xFFFFFFFFU; /* Difference between desireFreq and return frequency. */
858 uint32_t ref_div; /* Reference frequency after PREDIV. */
859
860 /*
861 * Steps:
862 * 1. Get allowed prediv with such rules:
863 * 1). refFreq / prediv >= SCG_PLL_REF_MIN.
864 * 2). refFreq / prediv <= SCG_PLL_REF_MAX.
865 * 2. For each allowed prediv, there are two candidate mult values:
866 * 1). (desireFreq / (refFreq / prediv)).
867 * 2). (desireFreq / (refFreq / prediv)) + 1.
868 * If could get the precise desired frequency, return current prediv and
869 * mult directly. Otherwise choose the one which is closer to desired
870 * frequency.
871 */
872
873 /* Reference frequency is out of range. */
874 if ((refFreq < SCG_SPLL_REF_MIN) ||
875 (refFreq > (SCG_SPLL_REF_MAX * (SCG_SPLL_PREDIV_MAX_VALUE + SCG_SPLL_PREDIV_BASE_VALUE))))
876 {
877 return 0U;
878 }
879
880 /* refFreq/PREDIV must in a range. First get the allowed PREDIV range. */
881 prediv_max = refFreq / SCG_SPLL_REF_MIN;
882 prediv_min = (refFreq + SCG_SPLL_REF_MAX - 1U) / SCG_SPLL_REF_MAX;
883
884 desireFreq *= 2U;
885
886 /* PREDIV traversal. */
887 for (prediv_cur = prediv_max; prediv_cur >= prediv_min; prediv_cur--)
888 {
889 /*
890 * For each PREDIV, the available MULT is (desireFreq*PREDIV/refFreq)
891 * or (desireFreq*PREDIV/refFreq + 1U). This function chooses the closer
892 * one.
893 */
894 /* Reference frequency after PREDIV. */
895 ref_div = refFreq / prediv_cur;
896
897 mult_cur = desireFreq / ref_div;
898
899 if ((mult_cur < SCG_SPLL_MULT_BASE_VALUE - 1U) ||
900 (mult_cur > SCG_SPLL_MULT_BASE_VALUE + SCG_SPLL_MULT_MAX_VALUE))
901 {
902 /* No MULT is available with this PREDIV. */
903 continue;
904 }
905
906 ret_freq = mult_cur * ref_div;
907
908 if (mult_cur >= SCG_SPLL_MULT_BASE_VALUE)
909 {
910 if (ret_freq == desireFreq) /* If desire frequency is got. */
911 {
912 *prediv = prediv_cur - SCG_SPLL_PREDIV_BASE_VALUE;
913 *mult = mult_cur - SCG_SPLL_MULT_BASE_VALUE;
914 return ret_freq / 2U;
915 }
916 if (diff > desireFreq - ret_freq) /* New PRDIV/VDIV is closer. */
917 {
918 diff = desireFreq - ret_freq;
919 ret_prediv = prediv_cur;
920 ret_mult = mult_cur;
921 }
922 }
923 mult_cur++;
924 if (mult_cur <= (SCG_SPLL_MULT_BASE_VALUE + SCG_SPLL_MULT_MAX_VALUE))
925 {
926 ret_freq += ref_div;
927 if (diff > ret_freq - desireFreq) /* New PRDIV/VDIV is closer. */
928 {
929 diff = ret_freq - desireFreq;
930 ret_prediv = prediv_cur;
931 ret_mult = mult_cur;
932 }
933 }
934 }
935
936 if (0xFFFFFFFFU != diff)
937 {
938 /* PREDIV/MULT found. */
939 *prediv = ret_prediv - SCG_SPLL_PREDIV_BASE_VALUE;
940 *mult = ret_mult - SCG_SPLL_MULT_BASE_VALUE;
941 return ((refFreq / ret_prediv) * ret_mult) / 2;
942 }
943 else
944 {
945 return 0U; /* No proper PREDIV/MULT found. */
946 }
947}
948
949/*!
950 * brief Initializes the SCG system PLL.
951 *
952 * This function enables the SCG system PLL clock according to the
953 * configuration. The system PLL can use the system OSC or FIRC as
954 * the clock source. Ensure that the source clock is valid before
955 * calling this function.
956 *
957 * Example code for initializing SPLL clock output:
958 * code
959 * const scg_spll_config_t g_scgSysPllConfig = {.enableMode = kSCG_SysPllEnable,
960 * .monitorMode = kSCG_SysPllMonitorDisable,
961 * .div1 = kSCG_AsyncClkDivBy1,
962 * .div2 = kSCG_AsyncClkDisable,
963 * .div3 = kSCG_AsyncClkDivBy2,
964 * .src = kSCG_SysPllSrcFirc,
965 * .isBypassSelected = false,
966 * .isPfdSelected = false, // Configure SPLL PFD as diabled
967 * .prediv = 5U,
968 * .pfdClkout = kSCG_AuxPllPfd0Clk, // No need to configure pfdClkout; only
969 * needed for initialization
970 * .mult = 20U,
971 * .pllPostdiv1 = kSCG_SysClkDivBy3,
972 * .pllPostdiv2 = kSCG_SysClkDivBy4};
973 * CLOCK_InitSysPll(&g_scgSysPllConfig);
974 * endcode
975 *
976 * param config Pointer to the configuration structure.
977 * retval kStatus_Success System PLL is initialized.
978 * retval kStatus_SCG_Busy System PLL has been enabled and is used by the system clock.
979 * retval kStatus_ReadOnly System PLL control register is locked.
980 *
981 * note This function can't detect whether the system PLL has been enabled and
982 * used by an IP.
983 */
985{
986 assert(config);
987
988 status_t status;
989
990 /* De-init the SPLL first. */
991 status = CLOCK_DeinitSysPll();
992
993 if (kStatus_Success != status)
994 {
995 return status;
996 }
997
998 /* Now start to set up PLL clock. */
999 /* Step 1. Setup dividers. */
1000 SCG->SPLLDIV = SCG_SPLLDIV_SPLLDIV1(config->div1) | SCG_SPLLDIV_SPLLDIV2(config->div2);
1001
1002 /* Step 2. Set PLL configuration. */
1003 SCG->SPLLCFG =
1004 SCG_SPLLCFG_SOURCE(config->src) | SCG_SPLLCFG_PREDIV(config->prediv) | SCG_SPLLCFG_MULT(config->mult);
1005
1006 /* Step 3. Enable clock. */
1007 SCG->SPLLCSR = SCG_SPLLCSR_SPLLEN_MASK | config->enableMode;
1008
1009 /* Step 4. Wait for PLL clock to be valid. */
1010 while (!(SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK))
1011 {
1012 }
1013
1014 /* Step 5. Enabe monitor. */
1015 SCG->SPLLCSR |= (uint32_t)config->monitorMode;
1016
1017 return kStatus_Success;
1018}
1019
1020/*!
1021 * brief De-initializes the SCG system PLL.
1022 *
1023 * This function disables the SCG system PLL.
1024 *
1025 * retval kStatus_Success system PLL is deinitialized.
1026 * retval kStatus_SCG_Busy system PLL is used by the system clock.
1027 * retval kStatus_ReadOnly System PLL control register is locked.
1028 *
1029 * note This function can't detect whether the system PLL is used by an IP.
1030 */
1032{
1033 uint32_t reg = SCG->SPLLCSR;
1034
1035 /* If clock is used by system, return error. */
1036 if (reg & SCG_SPLLCSR_SPLLSEL_MASK)
1037 {
1038 return kStatus_SCG_Busy;
1039 }
1040
1041 /* If configure register is locked, return error. */
1042 if (reg & SCG_SPLLCSR_LK_MASK)
1043 {
1044 return kStatus_ReadOnly;
1045 }
1046
1047 /* Deinit and clear the error. */
1048 SCG->SPLLCSR = SCG_SPLLCSR_SPLLERR_MASK;
1049
1050 return kStatus_Success;
1051}
1052
1053static uint32_t CLOCK_GetSysPllCommonFreq(void)
1054{
1055 uint32_t freq = 0U;
1056
1057 if (SCG->SPLLCFG & SCG_SPLLCFG_SOURCE_MASK) /* If use FIRC */
1058 {
1059 freq = CLOCK_GetFircFreq();
1060 }
1061 else /* Use System OSC. */
1062 {
1063 freq = CLOCK_GetSysOscFreq();
1064 }
1065
1066 if (freq) /* If source is valid. */
1067 {
1068 freq /= (SCG_SPLLCFG_PREDIV_VAL + SCG_SPLL_PREDIV_BASE_VALUE); /* Pre-divider. */
1069 freq *= (SCG_SPLLCFG_MULT_VAL + SCG_SPLL_MULT_BASE_VALUE); /* Multiplier. */
1070 }
1071
1072 return freq;
1073}
1074
1075/*!
1076 * brief Gets the SCG system PLL clock frequency.
1077 *
1078 * return Clock frequency; If the clock is invalid, returns 0.
1079 */
1081{
1082 uint32_t freq;
1083
1084 if (SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK) /* System PLL is valid. */
1085 {
1087
1088 return freq >> 1U;
1089 }
1090 else
1091 {
1092 return 0U;
1093 }
1094}
1095
1096/*!
1097 * brief Gets the SCG asynchronous clock frequency from the system PLL.
1098 *
1099 * param type The asynchronous clock type.
1100 * return Clock frequency; If the clock is invalid, returns 0.
1101 */
1103{
1104 uint32_t pllFreq = CLOCK_GetSysPllFreq();
1105 uint32_t divider = 0U;
1106
1107 /* Get divider. */
1108 if (pllFreq)
1109 {
1110 switch (type)
1111 {
1112 case kSCG_AsyncDiv2Clk: /* SPLLDIV2_CLK. */
1113 divider = SCG_SPLLDIV_SPLLDIV2_VAL;
1114 break;
1115 case kSCG_AsyncDiv1Clk: /* SPLLDIV1_CLK. */
1116 divider = SCG_SPLLDIV_SPLLDIV1_VAL;
1117 break;
1118 default:
1119 break;
1120 }
1121 }
1122 if (divider)
1123 {
1124 return pllFreq >> (divider - 1U);
1125 }
1126 else /* Output disabled. */
1127 {
1128 return 0U;
1129 }
1130}
static constexpr persistent_config_s * config
static uint32_t CLOCK_GetSysPllCommonFreq(void)
Get the common System PLL frequency for both RAW SPLL output and SPLL PFD output.
Definition fsl_clock.c:1053
enum _clock_ip_name clock_ip_name_t
Peripheral clock name difinition used for clock gate, clock source and clock divider setting....
uint32_t CLOCK_GetSysPllMultDiv(uint32_t refFreq, uint32_t desireFreq, uint8_t *mult, uint8_t *prediv)
Calculates the MULT and PREDIV for the PLL.
Definition fsl_clock.c:848
volatile uint32_t g_xtal32Freq
External XTAL32/EXTAL32 clock frequency.
Definition fsl_clock.c:77
uint32_t CLOCK_GetSysPllFreq(void)
Gets the SCG system PLL clock frequency.
Definition fsl_clock.c:1080
uint32_t CLOCK_GetIpFreq(clock_ip_name_t name)
Gets the clock frequency for a specific IP module.
Definition fsl_clock.c:250
enum _clock_name clock_name_t
Clock name used to get clock frequency.
static void CLOCK_DisableClock(clock_ip_name_t name)
Disable the clock for specific IP.
Definition fsl_clock.h:653
void OSC32_Deinit(OSC32_Type *base)
Deinitializes OSC32.
Definition fsl_clock.c:321
uint32_t CLOCK_GetCoreSysClkFreq(void)
Get the core clock or system clock frequency.
Definition fsl_clock.c:154
uint32_t CLOCK_GetSysPllAsyncFreq(scg_async_clk_t type)
Gets the SCG asynchronous clock frequency from the system PLL.
Definition fsl_clock.c:1102
enum _scg_sys_clk scg_sys_clk_t
SCG system clock type.
status_t CLOCK_DeinitFirc(void)
De-initializes the SCG fast IRC.
Definition fsl_clock.c:755
uint32_t CLOCK_GetSircFreq(void)
Gets the SCG SIRC clock frequency.
Definition fsl_clock.c:627
uint32_t CLOCK_GetFreq(clock_name_t clockName)
Gets the clock frequency for a specific clock name.
Definition fsl_clock.c:168
uint32_t CLOCK_GetFircFreq(void)
Gets the SCG FIRC clock frequency.
Definition fsl_clock.c:781
volatile uint32_t g_xtal0Freq
External XTAL0 (OSC0/SYSOSC) clock frequency.
Definition fsl_clock.c:75
enum _scg_async_clk scg_async_clk_t
SCG asynchronous clock type.
uint32_t CLOCK_GetErClkFreq(void)
Get the external reference clock frequency (ERCLK).
Definition fsl_clock.c:104
uint32_t CLOCK_GetSysClkFreq(scg_sys_clk_t type)
Gets the SCG system clock frequency.
Definition fsl_clock.c:339
status_t CLOCK_DeinitSysPll(void)
De-initializes the SCG system PLL.
Definition fsl_clock.c:1031
static void CLOCK_GetCurSysClkConfig(scg_sys_clk_config_t *config)
Gets the system clock configuration in the current power mode.
Definition fsl_clock.h:823
uint32_t CLOCK_GetBusClkFreq(void)
Get the bus clock frequency.
Definition fsl_clock.c:144
uint32_t CLOCK_GetSircAsyncFreq(scg_async_clk_t type)
Gets the SCG asynchronous clock frequency from the SIRC.
Definition fsl_clock.c:647
uint32_t CLOCK_GetFlashClkFreq(void)
Get the flash clock frequency.
Definition fsl_clock.c:134
void OSC32_Init(OSC32_Type *base, osc32_mode_t mode)
Initializes OSC32.
Definition fsl_clock.c:297
uint32_t CLOCK_GetSysOscFreq(void)
Gets the SCG system OSC clock frequency (SYSOSC).
Definition fsl_clock.c:494
status_t CLOCK_DeinitSirc(void)
De-initializes the SCG slow IRC.
Definition fsl_clock.c:601
uint32_t CLOCK_GetOsc32kClkFreq(void)
Get the OSC 32K clock frequency (OSC32KCLK).
Definition fsl_clock.c:123
status_t CLOCK_InitSirc(const scg_sirc_config_t *config)
Initializes the SCG slow IRC clock.
Definition fsl_clock.c:558
status_t CLOCK_InitFirc(const scg_firc_config_t *config)
Initializes the SCG fast IRC clock.
Definition fsl_clock.c:690
status_t CLOCK_InitSysPll(const scg_spll_config_t *config)
Initializes the SCG system PLL.
Definition fsl_clock.c:984
uint32_t CLOCK_GetFircAsyncFreq(scg_async_clk_t type)
Gets the SCG asynchronous clock frequency from the FIRC.
Definition fsl_clock.c:803
status_t CLOCK_DeinitSysOsc(void)
De-initializes the SCG system OSC.
Definition fsl_clock.c:468
status_t CLOCK_InitSysOsc(const scg_sosc_config_t *config)
Initializes the SCG system OSC.
Definition fsl_clock.c:397
static void CLOCK_EnableClock(clock_ip_name_t name)
Enable the clock for specific IP.
Definition fsl_clock.h:641
uint32_t CLOCK_GetSysOscAsyncFreq(scg_async_clk_t type)
Gets the SCG asynchronous clock frequency from the system OSC.
Definition fsl_clock.c:514
enum _osc32_mode osc32_mode_t
OSC32 work mode.
@ kSCG_AsyncDiv1Clk
Definition fsl_clock.h:409
@ kSCG_AsyncDiv2Clk
Definition fsl_clock.h:410
@ kCLOCK_Ftm3
Definition fsl_clock.h:277
@ kCLOCK_RtcOsc0
Definition fsl_clock.h:301
@ kCLOCK_Ftm1
Definition fsl_clock.h:287
@ kCLOCK_Ftm2
Definition fsl_clock.h:288
@ kCLOCK_Ftm0
Definition fsl_clock.h:286
@ kCLOCK_ScgSysOscAsyncDiv1Clk
Definition fsl_clock.h:227
@ kCLOCK_CoreSysClk
Definition fsl_clock.h:216
@ kCLOCK_ScgSysOscClk
Definition fsl_clock.h:222
@ kCLOCK_ScgSysPllAsyncDiv2Clk
Definition fsl_clock.h:237
@ kCLOCK_BusClk
Definition fsl_clock.h:217
@ kCLOCK_ScgSysOscAsyncDiv2Clk
Definition fsl_clock.h:228
@ kCLOCK_ScgFircAsyncDiv2Clk
Definition fsl_clock.h:234
@ kCLOCK_LpoClk
Definition fsl_clock.h:240
@ kCLOCK_ErClk
Definition fsl_clock.h:242
@ kCLOCK_ScgFircClk
Definition fsl_clock.h:224
@ kCLOCK_ScgSircAsyncDiv1Clk
Definition fsl_clock.h:230
@ kCLOCK_ScgSircClk
Definition fsl_clock.h:223
@ kCLOCK_Osc32kClk
Definition fsl_clock.h:241
@ kCLOCK_FlashClk
Definition fsl_clock.h:219
@ kCLOCK_ScgSircAsyncDiv2Clk
Definition fsl_clock.h:231
@ kCLOCK_ScgFircAsyncDiv1Clk
Definition fsl_clock.h:233
@ kCLOCK_ScgSysPllClk
Definition fsl_clock.h:225
@ kCLOCK_ScgSysPllAsyncDiv1Clk
Definition fsl_clock.h:236
@ kStatus_SCG_Busy
Definition fsl_clock.h:329
@ kSCG_FircTrimNonUpdate
Definition fsl_clock.h:505
@ kSCG_SysClkCore
Definition fsl_clock.h:340
@ kSCG_SysClkBus
Definition fsl_clock.h:339
@ kSCG_SysClkSlow
Definition fsl_clock.h:338
@ kCLOCK_IpSrcSysPllAsync
Definition fsl_clock.h:259
@ kCLOCK_IpSrcSysOscAsync
Definition fsl_clock.h:256
@ kCLOCK_IpSrcSircAsync
Definition fsl_clock.h:257
@ kCLOCK_IpSrcFircAsync
Definition fsl_clock.h:258
@ kSCG_SysOscModeExt
Definition fsl_clock.h:442
@ kSCG_SysClkSrcSysPll
Definition fsl_clock.h:351
@ kSCG_SysClkSrcSysOsc
Definition fsl_clock.h:348
@ kSCG_SysClkSrcFirc
Definition fsl_clock.h:350
@ kSCG_SysClkSrcSirc
Definition fsl_clock.h:349
int32_t status_t
Type used for all status and error return values.
Definition fsl_common.h:169
@ kStatus_ReadOnly
Definition fsl_common.h:161
@ kStatus_Success
Definition fsl_common.h:159
@ kStatus_Fail
Definition fsl_common.h:160
@ kStatus_InvalidArgument
Definition fsl_common.h:163
SCG fast IRC clock configuration.
Definition fsl_clock.h:574
SCG slow IRC clock configuration.
Definition fsl_clock.h:492
SCG system OSC configuration.
Definition fsl_clock.h:460
SCG system PLL configuration.
Definition fsl_clock.h:616
SCG system clock configuration.
Definition fsl_clock.h:381