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