1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016 - 2021, 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 #define SCG_SIRC_LOW_RANGE_FREQ  2000000U /* Slow IRC low range clock frequency. */
21 #define SCG_SIRC_HIGH_RANGE_FREQ 8000000U /* Slow IRC high range clock frequency.   */
22 
23 #define SCG_FIRC_FREQ0 48000000U /* Fast IRC trimed clock frequency(48MHz). */
24 
25 #define SCG_LPFLL_FREQ0 48000000U  /* LPFLL trimed clock frequency(48MHz). */
26 #define SCG_LPFLL_FREQ1 72000000U  /* LPFLL trimed clock frequency(72MHz). */
27 #define SCG_LPFLL_FREQ2 96000000U  /* LPFLL trimed clock frequency(96MHz). */
28 #define SCG_LPFLL_FREQ3 120000000U /* LPFLL trimed clock frequency(120MHz). */
29 
30 #define SCG_CSR_SCS_VAL          ((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT)
31 #define SCG_SOSCDIV_SOSCDIV2_VAL ((SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV2_MASK) >> SCG_SOSCDIV_SOSCDIV2_SHIFT)
32 #define SCG_SIRCDIV_SIRCDIV2_VAL ((SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV2_MASK) >> SCG_SIRCDIV_SIRCDIV2_SHIFT)
33 #define SCG_FIRCDIV_FIRCDIV2_VAL ((SCG->FIRCDIV & SCG_FIRCDIV_FIRCDIV2_MASK) >> SCG_FIRCDIV_FIRCDIV2_SHIFT)
34 
35 #define SCG_LPFLLDIV_LPFLLDIV2_VAL ((SCG->LPFLLDIV & SCG_LPFLLDIV_LPFLLDIV2_MASK) >> SCG_LPFLLDIV_LPFLLDIV2_SHIFT)
36 
37 #define SCG_SIRCCFG_RANGE_VAL ((SCG->SIRCCFG & SCG_SIRCCFG_RANGE_MASK) >> SCG_SIRCCFG_RANGE_SHIFT)
38 #define SCG_FIRCCFG_RANGE_VAL ((SCG->FIRCCFG & SCG_FIRCCFG_RANGE_MASK) >> SCG_FIRCCFG_RANGE_SHIFT)
39 
40 #define SCG_LPFLLCFG_FSEL_VAL ((SCG->LPFLLCFG & SCG_LPFLLCFG_FSEL_MASK) >> SCG_LPFLLCFG_FSEL_SHIFT)
41 
42 #define PCC_PCS_VAL(reg)  (((reg)&PCC_CLKCFG_PCS_MASK) >> PCC_CLKCFG_PCS_SHIFT)
43 #define PCC_FRAC_VAL(reg) (((reg)&PCC_CLKCFG_FRAC_MASK) >> PCC_CLKCFG_FRAC_SHIFT)
44 #define PCC_PCD_VAL(reg)  (((reg)&PCC_CLKCFG_PCD_MASK) >> PCC_CLKCFG_PCD_SHIFT)
45 
46 /*******************************************************************************
47  * Variables
48  ******************************************************************************/
49 
50 /* External XTAL0 (OSC0) clock frequency. */
51 volatile uint32_t g_xtal0Freq;
52 
53 /*******************************************************************************
54  * Prototypes
55  ******************************************************************************/
56 
57 /*******************************************************************************
58  * Code
59  ******************************************************************************/
60 
61 /*!
62  * brief Get the external reference clock frequency (ERCLK).
63  *
64  * return Clock frequency in Hz.
65  */
CLOCK_GetErClkFreq(void)66 uint32_t CLOCK_GetErClkFreq(void)
67 {
68     uint32_t freq;
69 
70     if ((SCG->SOSCCSR & SCG_SOSCCSR_SOSCEN_MASK) != 0UL)
71     {
72         /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
73         assert(g_xtal0Freq);
74         freq = g_xtal0Freq;
75     }
76     else
77     {
78         freq = 0U;
79     }
80 
81     return freq;
82 }
83 
84 /*!
85  * brief Get the flash clock frequency.
86  *
87  * return Clock frequency in Hz.
88  */
CLOCK_GetFlashClkFreq(void)89 uint32_t CLOCK_GetFlashClkFreq(void)
90 {
91     return CLOCK_GetSysClkFreq(kSCG_SysClkSlow);
92 }
93 
94 /*!
95  * brief Get the bus clock frequency.
96  *
97  * return Clock frequency in Hz.
98  */
CLOCK_GetBusClkFreq(void)99 uint32_t CLOCK_GetBusClkFreq(void)
100 {
101     return CLOCK_GetSysClkFreq(kSCG_SysClkSlow);
102 }
103 
104 /*!
105  * brief Get the core clock or system clock frequency.
106  *
107  * return Clock frequency in Hz.
108  */
CLOCK_GetCoreSysClkFreq(void)109 uint32_t CLOCK_GetCoreSysClkFreq(void)
110 {
111     return CLOCK_GetSysClkFreq(kSCG_SysClkCore);
112 }
113 
114 /*!
115  * brief Gets the clock frequency for a specific clock name.
116  *
117  * This function checks the current clock configurations and then calculates
118  * the clock frequency for a specific clock name defined in clock_name_t.
119  *
120  * param clockName Clock names defined in clock_name_t
121  * return Clock frequency value in hertz
122  */
CLOCK_GetFreq(clock_name_t clockName)123 uint32_t CLOCK_GetFreq(clock_name_t clockName)
124 {
125     uint32_t freq;
126 
127     switch (clockName)
128     {
129         case kCLOCK_CoreSysClk:
130             freq = CLOCK_GetSysClkFreq(kSCG_SysClkCore);
131             break;
132         case kCLOCK_BusClk:
133         case kCLOCK_FlashClk:
134             freq = CLOCK_GetSysClkFreq(kSCG_SysClkSlow);
135             break;
136 
137         case kCLOCK_ScgSysOscClk:
138             freq = CLOCK_GetSysOscFreq();
139             break;
140         case kCLOCK_ScgSircClk:
141             freq = CLOCK_GetSircFreq();
142             break;
143         case kCLOCK_ScgFircClk:
144             freq = CLOCK_GetFircFreq();
145             break;
146         case kCLOCK_ScgLpFllClk:
147             freq = CLOCK_GetLpFllFreq();
148             break;
149 
150         case kCLOCK_ScgSysOscAsyncDiv2Clk:
151             freq = CLOCK_GetSysOscAsyncFreq(kSCG_AsyncDiv2Clk);
152             break;
153 
154         case kCLOCK_ScgSircAsyncDiv2Clk:
155             freq = CLOCK_GetSircAsyncFreq(kSCG_AsyncDiv2Clk);
156             break;
157 
158         case kCLOCK_ScgFircAsyncDiv2Clk:
159             freq = CLOCK_GetFircAsyncFreq(kSCG_AsyncDiv2Clk);
160             break;
161 
162         case kCLOCK_ScgLpFllAsyncDiv2Clk:
163             freq = CLOCK_GetLpFllAsyncFreq(kSCG_AsyncDiv2Clk);
164             break;
165 
166         case kCLOCK_LpoClk:
167             freq = LPO_CLK_FREQ;
168             break;
169 
170         case kCLOCK_ErClk:
171             freq = CLOCK_GetErClkFreq();
172             break;
173 
174         default:
175             freq = 0U;
176             break;
177     }
178     return freq;
179 }
180 
181 /*!
182  * brief Gets the clock frequency for a specific IP module.
183  *
184  * This function gets the IP module clock frequency based on PCC registers. It is
185  * only used for the IP modules which could select clock source by PCC[PCS].
186  *
187  * param name Which peripheral to get, see \ref clock_ip_name_t.
188  * return Clock frequency value in hertz
189  */
CLOCK_GetIpFreq(clock_ip_name_t name)190 uint32_t CLOCK_GetIpFreq(clock_ip_name_t name)
191 {
192     uint32_t reg = (*(volatile uint32_t *)((uint32_t)name));
193 
194     scg_async_clk_t asycClk;
195     uint32_t freq;
196     uint32_t ret;
197 
198     assert(reg & PCC_CLKCFG_PR_MASK);
199 
200     asycClk = kSCG_AsyncDiv2Clk;
201 
202     switch (PCC_PCS_VAL(reg))
203     {
204         case (uint32_t)kCLOCK_IpSrcSysOscAsync:
205             freq = CLOCK_GetSysOscAsyncFreq(asycClk);
206             break;
207         case (uint32_t)kCLOCK_IpSrcSircAsync:
208             freq = CLOCK_GetSircAsyncFreq(asycClk);
209             break;
210         case (uint32_t)kCLOCK_IpSrcFircAsync:
211             freq = CLOCK_GetFircAsyncFreq(asycClk);
212             break;
213         case (uint32_t)kCLOCK_IpSrcLpFllAsync:
214             freq = CLOCK_GetLpFllAsyncFreq(asycClk);
215             break;
216         default:
217             freq = 0U;
218             break;
219     }
220 
221     if ((reg & (PCC_CLKCFG_PCD_MASK | PCC_CLKCFG_FRAC_MASK)) != 0UL)
222     {
223         ret = freq * (PCC_FRAC_VAL(reg) + 1U) / (PCC_PCD_VAL(reg) + 1U);
224     }
225     else
226     {
227         ret = freq;
228     }
229 
230     return ret;
231 }
232 
233 /*!
234  * brief Gets the SCG system clock frequency.
235  *
236  * This function gets the SCG system clock frequency. These clocks are used for
237  * core, platform, external, and bus clock domains.
238  *
239  * param type     Which type of clock to get, core clock or slow clock.
240  * return  Clock frequency.
241  */
CLOCK_GetSysClkFreq(scg_sys_clk_t type)242 uint32_t CLOCK_GetSysClkFreq(scg_sys_clk_t type)
243 {
244     uint32_t freq;
245 
246     scg_sys_clk_config_t sysClkConfig;
247 
248     CLOCK_GetCurSysClkConfig(&sysClkConfig); /* Get the main clock for SoC platform. */
249 
250     switch (sysClkConfig.src)
251     {
252         case (uint8_t)kSCG_SysClkSrcSysOsc:
253             freq = CLOCK_GetSysOscFreq();
254             break;
255         case (uint8_t)kSCG_SysClkSrcSirc:
256             freq = CLOCK_GetSircFreq();
257             break;
258         case (uint8_t)kSCG_SysClkSrcFirc:
259             freq = CLOCK_GetFircFreq();
260             break;
261         case (uint8_t)kSCG_SysClkSrcLpFll:
262             freq = CLOCK_GetLpFllFreq();
263             break;
264         default:
265             freq = 0U;
266             break;
267     }
268 
269     freq /= ((uint32_t)sysClkConfig.divCore + 1UL); /* divided by the DIVCORE firstly. */
270 
271     if (kSCG_SysClkSlow == type)
272     {
273         freq /= ((uint32_t)sysClkConfig.divSlow + 1UL);
274     }
275     else
276     {
277         /* Add comment to prevent the case of MISRA C-2012 rule 15.7 */
278     }
279 
280     return freq;
281 }
282 
283 /*!
284  * brief Initializes the SCG system OSC.
285  *
286  * This function enables the SCG system OSC clock according to the
287  * configuration.
288  *
289  * param config   Pointer to the configuration structure.
290  * retval kStatus_Success System OSC is initialized.
291  * retval kStatus_SCG_Busy System OSC has been enabled and is used by the system clock.
292  * retval kStatus_ReadOnly System OSC control register is locked.
293  *
294  * note This function can't detect whether the system OSC has been enabled and
295  * used by an IP.
296  */
CLOCK_InitSysOsc(const scg_sosc_config_t * config)297 status_t CLOCK_InitSysOsc(const scg_sosc_config_t *config)
298 {
299     assert(config);
300     uint8_t range = 0U; /* SCG_SOSCCFG[RANGE] */
301     status_t status;
302     uint8_t tmp8;
303 
304     /* If crystal oscillator used, need to get RANGE value base on frequency. */
305     if (kSCG_SysOscModeExt != config->workMode)
306     {
307         if ((config->freq >= 32768U) && (config->freq <= 40000U))
308         {
309             range = 1U;
310         }
311         else if ((config->freq >= 1000000U) && (config->freq <= 8000000U))
312         {
313             range = 2U;
314         }
315         else if ((config->freq >= 8000000U) && (config->freq <= 32000000U))
316         {
317             range = 3U;
318         }
319         else
320         {
321             return kStatus_InvalidArgument;
322         }
323     }
324 
325     /* De-init the SOSC first. */
326     status = CLOCK_DeinitSysOsc();
327 
328     if (kStatus_Success != status)
329     {
330         return status;
331     }
332 
333     /* Now start to set up OSC clock. */
334     /* Step 1. Setup dividers. */
335     SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV2(config->div2);
336 
337     /* Step 2. Set OSC configuration. */
338     SCG->SOSCCFG = (uint32_t)(config->workMode) | SCG_SOSCCFG_RANGE(range);
339 
340     /* Step 3. Enable clock. */
341     /* SCG->SOSCCSR = SCG_SOSCCSR_SOSCEN_MASK | (config->enableMode); */
342     tmp8 = config->enableMode;
343     tmp8 |= SCG_SOSCCSR_SOSCEN_MASK;
344     SCG->SOSCCSR = tmp8;
345 
346     /* Step 4. Wait for OSC clock to be valid. */
347     while (0UL == (SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK))
348     {
349     }
350 
351     /* Step 5. Enabe monitor. */
352     SCG->SOSCCSR |= (uint32_t)config->monitorMode;
353 
354     return kStatus_Success;
355 }
356 
357 /*!
358  * brief De-initializes the SCG system OSC.
359  *
360  * This function disables the SCG system OSC clock.
361  *
362  * retval kStatus_Success System OSC is deinitialized.
363  * retval kStatus_SCG_Busy System OSC is used by the system clock.
364  * retval kStatus_ReadOnly System OSC control register is locked.
365  *
366  * note This function can't detect whether the system OSC is used by an IP.
367  */
CLOCK_DeinitSysOsc(void)368 status_t CLOCK_DeinitSysOsc(void)
369 {
370     uint32_t reg = SCG->SOSCCSR;
371     status_t status;
372 
373     /* If clock is used by system, return error. */
374     if ((reg & SCG_SOSCCSR_SOSCSEL_MASK) != 0UL)
375     {
376         status = kStatus_SCG_Busy;
377     }
378 
379     /* If configure register is locked, return error. */
380     else if ((reg & SCG_SOSCCSR_LK_MASK) != 0UL)
381     {
382         status = kStatus_ReadOnly;
383     }
384     else
385     {
386         SCG->SOSCCSR = SCG_SOSCCSR_SOSCERR_MASK;
387         status       = kStatus_Success;
388     }
389 
390     return status;
391 }
392 
393 /*!
394  * brief Gets the SCG system OSC clock frequency (SYSOSC).
395  *
396  * return  Clock frequency; If the clock is invalid, returns 0.
397  */
CLOCK_GetSysOscFreq(void)398 uint32_t CLOCK_GetSysOscFreq(void)
399 {
400     uint32_t freq;
401 
402     if ((SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) != 0UL) /* System OSC clock is valid. */
403     {
404         /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
405         assert(g_xtal0Freq);
406         freq = g_xtal0Freq;
407     }
408     else
409     {
410         freq = 0U;
411     }
412 
413     return freq;
414 }
415 
416 /*!
417  * brief Gets the SCG asynchronous clock frequency from the system OSC.
418  *
419  * param type     The asynchronous clock type.
420  * return  Clock frequency; If the clock is invalid, returns 0.
421  */
CLOCK_GetSysOscAsyncFreq(scg_async_clk_t type)422 uint32_t CLOCK_GetSysOscAsyncFreq(scg_async_clk_t type)
423 {
424     uint32_t oscFreq = CLOCK_GetSysOscFreq();
425     uint32_t divider = 0U;
426     uint32_t freq;
427 
428     /* Get divider. */
429     if (oscFreq != 0UL)
430     {
431         switch (type)
432         {
433             case kSCG_AsyncDiv2Clk: /* SOSCDIV2_CLK. */
434                 divider = SCG_SOSCDIV_SOSCDIV2_VAL;
435                 break;
436             default:
437                 divider = 0U;
438                 break;
439         }
440     }
441     if (divider != 0U)
442     {
443         freq = (oscFreq >> (divider - 1U));
444     }
445     else /* Output disabled. */
446     {
447         freq = 0U;
448     }
449 
450     return freq;
451 }
452 
453 /*!
454  * brief Initializes the SCG slow IRC clock.
455  *
456  * This function enables the SCG slow IRC clock according to the
457  * configuration.
458  *
459  * param config   Pointer to the configuration structure.
460  * retval kStatus_Success SIRC is initialized.
461  * retval kStatus_SCG_Busy SIRC has been enabled and is used by system clock.
462  * retval kStatus_ReadOnly SIRC control register is locked.
463  *
464  * note This function can't detect whether the system OSC has been enabled and
465  * used by an IP.
466  */
CLOCK_InitSirc(const scg_sirc_config_t * config)467 status_t CLOCK_InitSirc(const scg_sirc_config_t *config)
468 {
469     assert(config);
470 
471     status_t status;
472 
473     /* De-init the SIRC first. */
474     status = CLOCK_DeinitSirc();
475 
476     if (status == kStatus_Success)
477     {
478         /* Now start to set up SIRC clock. */
479         /* Step 1. Setup dividers. */
480         SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV2(config->div2);
481 
482         /* Step 2. Set SIRC configuration. */
483         SCG->SIRCCFG = SCG_SIRCCFG_RANGE(config->range);
484 
485         /* Step 3. Enable clock. */
486         SCG->SIRCCSR = SCG_SIRCCSR_SIRCEN_MASK | config->enableMode;
487 
488         /* Step 4. Wait for SIRC clock to be valid. */
489         while (0UL == (SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK))
490         {
491         }
492     }
493 
494     return status;
495 }
496 
497 /*!
498  * brief De-initializes the SCG slow IRC.
499  *
500  * This function disables the SCG slow IRC.
501  *
502  * retval kStatus_Success SIRC is deinitialized.
503  * retval kStatus_SCG_Busy SIRC is used by system clock.
504  * retval kStatus_ReadOnly SIRC control register is locked.
505  *
506  * note This function can't detect whether the SIRC is used by an IP.
507  */
CLOCK_DeinitSirc(void)508 status_t CLOCK_DeinitSirc(void)
509 {
510     uint32_t reg = SCG->SIRCCSR;
511     status_t status;
512 
513     /* If clock is used by system, return error. */
514     if ((reg & SCG_SIRCCSR_SIRCSEL_MASK) != 0UL)
515     {
516         status = kStatus_SCG_Busy;
517     }
518     /* If configure register is locked, return error. */
519     else if ((reg & SCG_SIRCCSR_LK_MASK) != 0UL)
520     {
521         status = kStatus_ReadOnly;
522     }
523     else
524     {
525         SCG->SIRCCSR = 0U;
526         status       = kStatus_Success;
527     }
528 
529     return status;
530 }
531 
532 /*!
533  * brief Gets the SCG SIRC clock frequency.
534  *
535  * return  Clock frequency; If the clock is invalid, returns 0.
536  */
CLOCK_GetSircFreq(void)537 uint32_t CLOCK_GetSircFreq(void)
538 {
539     static const uint32_t sircFreq[] = {SCG_SIRC_LOW_RANGE_FREQ, SCG_SIRC_HIGH_RANGE_FREQ};
540     uint32_t freq;
541 
542     if ((SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK) != 0UL) /* SIRC is valid. */
543     {
544         freq = sircFreq[SCG_SIRCCFG_RANGE_VAL];
545     }
546     else
547     {
548         freq = 0U;
549     }
550 
551     return freq;
552 }
553 
554 /*!
555  * brief Gets the SCG asynchronous clock frequency from the SIRC.
556  *
557  * param type     The asynchronous clock type.
558  * return  Clock frequency; If the clock is invalid, returns 0.
559  */
CLOCK_GetSircAsyncFreq(scg_async_clk_t type)560 uint32_t CLOCK_GetSircAsyncFreq(scg_async_clk_t type)
561 {
562     uint32_t sircFreq = CLOCK_GetSircFreq();
563     uint32_t divider  = 0U;
564     uint32_t freq;
565 
566     /* Get divider. */
567     if (sircFreq != 0UL)
568     {
569         switch (type)
570         {
571             case kSCG_AsyncDiv2Clk: /* SIRCDIV2_CLK. */
572                 divider = SCG_SIRCDIV_SIRCDIV2_VAL;
573                 break;
574             default:
575                 divider = 0U;
576                 break;
577         }
578     }
579     if (divider != 0UL)
580     {
581         freq = (sircFreq >> (divider - 1U));
582     }
583     else /* Output disabled. */
584     {
585         freq = 0U;
586     }
587 
588     return freq;
589 }
590 
591 /*!
592  * brief Initializes the SCG fast IRC clock.
593  *
594  * This function enables the SCG fast IRC clock according to the configuration.
595  *
596  * param config   Pointer to the configuration structure.
597  * retval kStatus_Success FIRC is initialized.
598  * retval kStatus_SCG_Busy FIRC has been enabled and is used by the system clock.
599  * retval kStatus_ReadOnly FIRC control register is locked.
600  *
601  * note This function can't detect whether the FIRC has been enabled and
602  * used by an IP.
603  */
CLOCK_InitFirc(const scg_firc_config_t * config)604 status_t CLOCK_InitFirc(const scg_firc_config_t *config)
605 {
606     assert(config);
607 
608     status_t status;
609 
610     /* De-init the FIRC first. */
611     status = CLOCK_DeinitFirc();
612 
613     if (kStatus_Success != status)
614     {
615         return status;
616     }
617 
618     /* Now start to set up FIRC clock. */
619     /* Step 1. Setup dividers. */
620     SCG->FIRCDIV = SCG_FIRCDIV_FIRCDIV2(config->div2);
621 
622     /* Step 2. Set FIRC configuration. */
623     SCG->FIRCCFG = SCG_FIRCCFG_RANGE(config->range);
624 
625     /* Step 3. Set trimming configuration. */
626     if ((config->trimConfig) != NULL)
627     {
628         SCG->FIRCTCFG =
629             SCG_FIRCTCFG_TRIMDIV(config->trimConfig->trimDiv) | SCG_FIRCTCFG_TRIMSRC(config->trimConfig->trimSrc);
630 
631         /* TODO: Write FIRCSTAT cause bus error: TKT266932. */
632         if (kSCG_FircTrimNonUpdate == config->trimConfig->trimMode)
633         {
634             SCG->FIRCSTAT = SCG_FIRCSTAT_TRIMCOAR(config->trimConfig->trimCoar) |
635                             SCG_FIRCSTAT_TRIMFINE(config->trimConfig->trimFine);
636         }
637 
638         /* trim mode. */
639         SCG->FIRCCSR = (uint32_t)(config->trimConfig->trimMode);
640     }
641 
642     /* Step 4. Enable clock. */
643     SCG->FIRCCSR |= (SCG_FIRCCSR_FIRCEN_MASK | config->enableMode);
644 
645     /* Step 5. Wait for FIRC clock to be valid. */
646     while (0UL == (SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK))
647     {
648     }
649 
650     return kStatus_Success;
651 }
652 
653 /*!
654  * brief De-initializes the SCG fast IRC.
655  *
656  * This function disables the SCG fast IRC.
657  *
658  * retval kStatus_Success FIRC is deinitialized.
659  * retval kStatus_SCG_Busy FIRC is used by the system clock.
660  * retval kStatus_ReadOnly FIRC control register is locked.
661  *
662  * note This function can't detect whether the FIRC is used by an IP.
663  */
CLOCK_DeinitFirc(void)664 status_t CLOCK_DeinitFirc(void)
665 {
666     uint32_t reg    = SCG->FIRCCSR;
667     status_t status = kStatus_Success;
668 
669     /* If clock is used by system, return error. */
670     if ((reg & SCG_FIRCCSR_FIRCSEL_MASK) != 0UL)
671     {
672         status = kStatus_SCG_Busy;
673     }
674     /* If configure register is locked, return error. */
675     else if ((reg & SCG_FIRCCSR_LK_MASK) != 0UL)
676     {
677         status = kStatus_ReadOnly;
678     }
679     else
680     {
681         ; /* Intentional empty. */
682     }
683 
684     return status;
685 }
686 
687 /*!
688  * brief Gets the SCG FIRC clock frequency.
689  *
690  * return  Clock frequency; If the clock is invalid, returns 0.
691  */
CLOCK_GetFircFreq(void)692 uint32_t CLOCK_GetFircFreq(void)
693 {
694     uint32_t freq;
695 
696     static const uint32_t fircFreq[] = {
697         SCG_FIRC_FREQ0,
698     };
699 
700     if ((SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK) != 0UL) /* FIRC is valid. */
701     {
702         freq = fircFreq[SCG_FIRCCFG_RANGE_VAL];
703     }
704     else
705     {
706         freq = 0U;
707     }
708 
709     return freq;
710 }
711 
712 /*!
713  * brief Gets the SCG asynchronous clock frequency from the FIRC.
714  *
715  * param type     The asynchronous clock type.
716  * return  Clock frequency; If the clock is invalid, returns 0.
717  */
CLOCK_GetFircAsyncFreq(scg_async_clk_t type)718 uint32_t CLOCK_GetFircAsyncFreq(scg_async_clk_t type)
719 {
720     uint32_t fircFreq = CLOCK_GetFircFreq();
721     uint32_t divider  = 0U;
722     uint32_t freq;
723 
724     /* Get divider. */
725     if (fircFreq != 0UL)
726     {
727         switch (type)
728         {
729             case kSCG_AsyncDiv2Clk: /* FIRCDIV2_CLK. */
730                 divider = SCG_FIRCDIV_FIRCDIV2_VAL;
731                 break;
732             default:
733                 divider = 0U;
734                 break;
735         }
736     }
737     if (divider != 0U)
738     {
739         freq = (fircFreq >> (divider - 1U));
740     }
741     else /* Output disabled. */
742     {
743         freq = 0U;
744     }
745 
746     return freq;
747 }
748 
749 /*!
750  * brief Initializes the SCG LPFLL clock.
751  *
752  * This function enables the SCG LPFLL clock according to the configuration.
753  *
754  * param config   Pointer to the configuration structure.
755  * retval kStatus_Success LPFLL is initialized.
756  * retval kStatus_SCG_Busy LPFLL has been enabled and is used by the system clock.
757  * retval kStatus_ReadOnly LPFLL control register is locked.
758  *
759  * note This function can't detect whether the LPFLL has been enabled and
760  * used by an IP.
761  */
CLOCK_InitLpFll(const scg_lpfll_config_t * config)762 status_t CLOCK_InitLpFll(const scg_lpfll_config_t *config)
763 {
764     assert(config);
765 
766     status_t status;
767 
768     /* De-init the LPFLL first. */
769     status = CLOCK_DeinitLpFll();
770 
771     if (kStatus_Success != status)
772     {
773         return status;
774     }
775 
776     /* Now start to set up LPFLL clock. */
777     /* Step 1. Setup dividers. */
778     SCG->LPFLLDIV = SCG_LPFLLDIV_LPFLLDIV2(config->div2);
779 
780     /* Step 2. Set LPFLL configuration. */
781     SCG->LPFLLCFG = SCG_LPFLLCFG_FSEL(config->range);
782 
783     /* Step 3. Set trimming configuration. */
784     if ((config->trimConfig) != NULL)
785     {
786         SCG->LPFLLTCFG = SCG_LPFLLTCFG_TRIMDIV(config->trimConfig->trimDiv) |
787                          SCG_LPFLLTCFG_TRIMSRC(config->trimConfig->trimSrc) |
788                          SCG_LPFLLTCFG_LOCKW2LSB(config->trimConfig->lockMode);
789 
790         if (kSCG_LpFllTrimNonUpdate == config->trimConfig->trimMode)
791         {
792             SCG->LPFLLSTAT = config->trimConfig->trimValue;
793         }
794 
795         /* Trim mode. */
796         SCG->LPFLLCSR = (uint32_t)(config->trimConfig->trimMode);
797 
798         if ((SCG->LPFLLCSR & SCG_LPFLLCSR_LPFLLERR_MASK) != 0UL)
799         {
800             return kStatus_Fail;
801         }
802     }
803 
804     /* Step 4. Enable clock. */
805     SCG->LPFLLCSR |= ((uint32_t)SCG_LPFLLCSR_LPFLLEN_MASK | config->enableMode);
806 
807     /* Step 5. Wait for LPFLL clock to be valid. */
808     while (0UL == (SCG->LPFLLCSR & SCG_LPFLLCSR_LPFLLVLD_MASK))
809     {
810     }
811 
812     /* Step 6. Wait for LPFLL trim lock. */
813     if (((config->trimConfig) != NULL) && (kSCG_LpFllTrimUpdate == config->trimConfig->trimMode))
814     {
815         while (0UL == (SCG->LPFLLCSR & SCG_LPFLLCSR_LPFLLTRMLOCK_MASK))
816         {
817         }
818     }
819 
820     return kStatus_Success;
821 }
822 
823 /*!
824  * brief De-initializes the SCG LPFLL.
825  *
826  * This function disables the SCG LPFLL.
827  *
828  * retval kStatus_Success LPFLL is deinitialized.
829  * retval kStatus_SCG_Busy LPFLL is used by the system clock.
830  * retval kStatus_ReadOnly LPFLL control register is locked.
831  *
832  * note This function can't detect whether the LPFLL is used by an IP.
833  */
CLOCK_DeinitLpFll(void)834 status_t CLOCK_DeinitLpFll(void)
835 {
836     uint32_t reg = SCG->LPFLLCSR;
837     status_t status;
838 
839     /* If clock is used by system, return error. */
840     if ((reg & SCG_LPFLLCSR_LPFLLSEL_MASK) != 0UL)
841     {
842         status = kStatus_SCG_Busy;
843     }
844     /* If configure register is locked, return error. */
845     else if ((reg & SCG_LPFLLCSR_LK_MASK) != 0UL)
846     {
847         status = kStatus_ReadOnly;
848     }
849     else
850     {
851         SCG->LPFLLCSR = SCG_LPFLLCSR_LPFLLERR_MASK;
852         status        = kStatus_Success;
853     }
854 
855     return status;
856 }
857 
858 /*!
859  * brief Gets the SCG LPFLL clock frequency.
860  *
861  * return  Clock frequency in Hz; If the clock is invalid, returns 0.
862  */
CLOCK_GetLpFllFreq(void)863 uint32_t CLOCK_GetLpFllFreq(void)
864 {
865     uint32_t freq;
866 
867     static const uint32_t lpfllFreq[] = {
868         SCG_LPFLL_FREQ0,
869         SCG_LPFLL_FREQ1,
870     };
871 
872     if ((SCG->LPFLLCSR & SCG_LPFLLCSR_LPFLLVLD_MASK) != 0UL) /* LPFLL is valid. */
873     {
874         freq = lpfllFreq[SCG_LPFLLCFG_FSEL_VAL];
875     }
876     else
877     {
878         freq = 0U;
879     }
880 
881     return freq;
882 }
883 
884 /*!
885  * brief Gets the SCG asynchronous clock frequency from the LPFLL.
886  *
887  * param type     The asynchronous clock type.
888  * return  Clock frequency in Hz; If the clock is invalid, returns 0.
889  */
CLOCK_GetLpFllAsyncFreq(scg_async_clk_t type)890 uint32_t CLOCK_GetLpFllAsyncFreq(scg_async_clk_t type)
891 {
892     uint32_t lpfllFreq = CLOCK_GetLpFllFreq();
893     uint32_t divider   = 0U;
894     uint32_t freq;
895 
896     /* Get divider. */
897     if (lpfllFreq != 0UL)
898     {
899         switch (type)
900         {
901             case kSCG_AsyncDiv2Clk: /* LPFLLDIV2_CLK. */
902                 divider = SCG_LPFLLDIV_LPFLLDIV2_VAL;
903                 break;
904             default:
905                 divider = 0U;
906                 break;
907         }
908     }
909     if (divider != 0UL)
910     {
911         freq = lpfllFreq >> (divider - 1U);
912     }
913     else /* Output disabled. */
914     {
915         freq = 0U;
916     }
917 
918     return freq;
919 }
920