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