1 /*
2  * Copyright 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 /* 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 4000000U   /* Slow IRC low range clock frequency. */
20 #define SCG_SIRC_HIGH_RANGE_FREQ 16000000U /* Slow IRC high range clock frequency.   */
21 
22 #define SCG_FIRC_FREQ0 48000000U /* Fast IRC trimed clock frequency(48MHz). */
23 #define SCG_FIRC_FREQ1 52000000U /* Fast IRC trimed clock frequency(52MHz). */
24 #define SCG_FIRC_FREQ2 56000000U /* Fast IRC trimed clock frequency(56MHz). */
25 #define SCG_FIRC_FREQ3 60000000U /* Fast IRC trimed clock frequency(60MHz). */
26 
27 /*
28  * System PLL base divider value, it is the PLL reference clock divider
29  * value when SCG_SPLLCFG[PREDIV]=0.
30  */
31 #define SCG_SPLL_PREDIV_BASE_VALUE 1U
32 
33 /*
34  * System PLL base multiplier value, it is the PLL multiplier value
35  * when SCG_SPLLCFG[MULT]=0.
36  */
37 #define SCG_SPLL_MULT_BASE_VALUE 0U
38 
39 /*
40  * Auxiliary PLL base divider value, it is the PLL reference clock divider
41  * value when SCG_APLLCFG[PREDIV]=0.
42  */
43 #define SCG_APLL_PREDIV_BASE_VALUE 1U
44 
45 /*
46  * Auxiliary PLL base multiplier value, it is the PLL multiplier value
47  * when SCG_APLLCFG[MULT]=0.
48  */
49 #define SCG_APLL_MULT_BASE_VALUE 0U
50 
51 /*
52  * Auxiliary PLL post divider 1 value
53  * value when SCG_APLLCFG[PLLPOSTDIV1]=0.
54  */
55 #define SCG_APLL_POSTDIV1_BASE_VALUE 1U
56 
57 /*
58  * Auxiliary PLL post divider 2 value
59  * value when SCG_APLLCFG[PLLPOSTDIV2]=0.
60  */
61 #define SCG_APLL_POSTDIV2_BASE_VALUE 1U
62 
63 #define SCG_CSR_SCS_VAL ((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT)
64 #define SCG_SOSCDIV_SOSCDIV1_VAL ((SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV1_MASK) >> SCG_SOSCDIV_SOSCDIV1_SHIFT)
65 #define SCG_SOSCDIV_SOSCDIV2_VAL ((SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV2_MASK) >> SCG_SOSCDIV_SOSCDIV2_SHIFT)
66 #define SCG_SOSCDIV_SOSCDIV3_VAL ((SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV3_MASK) >> SCG_SOSCDIV_SOSCDIV3_SHIFT)
67 #define SCG_SIRCDIV_SIRCDIV1_VAL ((SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV1_MASK) >> SCG_SIRCDIV_SIRCDIV1_SHIFT)
68 #define SCG_SIRCDIV_SIRCDIV2_VAL ((SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV2_MASK) >> SCG_SIRCDIV_SIRCDIV2_SHIFT)
69 #define SCG_SIRCDIV_SIRCDIV3_VAL ((SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV3_MASK) >> SCG_SIRCDIV_SIRCDIV3_SHIFT)
70 #define SCG_FIRCDIV_FIRCDIV1_VAL ((SCG->FIRCDIV & SCG_FIRCDIV_FIRCDIV1_MASK) >> SCG_FIRCDIV_FIRCDIV1_SHIFT)
71 #define SCG_FIRCDIV_FIRCDIV2_VAL ((SCG->FIRCDIV & SCG_FIRCDIV_FIRCDIV2_MASK) >> SCG_FIRCDIV_FIRCDIV2_SHIFT)
72 #define SCG_FIRCDIV_FIRCDIV3_VAL ((SCG->FIRCDIV & SCG_FIRCDIV_FIRCDIV3_MASK) >> SCG_FIRCDIV_FIRCDIV3_SHIFT)
73 
74 #define SCG_SPLLDIV_SPLLDIV1_VAL ((SCG->SPLLDIV & SCG_SPLLDIV_SPLLDIV1_MASK) >> SCG_SPLLDIV_SPLLDIV1_SHIFT)
75 #define SCG_SPLLDIV_SPLLDIV2_VAL ((SCG->SPLLDIV & SCG_SPLLDIV_SPLLDIV2_MASK) >> SCG_SPLLDIV_SPLLDIV2_SHIFT)
76 #define SCG_SPLLDIV_SPLLDIV3_VAL ((SCG->SPLLDIV & SCG_SPLLDIV_SPLLDIV3_MASK) >> SCG_SPLLDIV_SPLLDIV3_SHIFT)
77 
78 #define SCG_SIRCCFG_RANGE_VAL ((SCG->SIRCCFG & SCG_SIRCCFG_RANGE_MASK) >> SCG_SIRCCFG_RANGE_SHIFT)
79 #define SCG_FIRCCFG_RANGE_VAL ((SCG->FIRCCFG & SCG_FIRCCFG_RANGE_MASK) >> SCG_FIRCCFG_RANGE_SHIFT)
80 
81 #define SCG_SPLLCFG_PREDIV_VAL ((SCG->SPLLCFG & SCG_SPLLCFG_PREDIV_MASK) >> SCG_SPLLCFG_PREDIV_SHIFT)
82 #define SCG_SPLLCFG_MULT_VAL ((SCG->SPLLCFG & SCG_SPLLCFG_MULT_MASK) >> SCG_SPLLCFG_MULT_SHIFT)
83 #define SCG_SPLLPFD_PFD_MAX_VAL (SCG_SPLLPFD_PFD0_MASK >> SCG_SPLLPFD_PFD0_SHIFT)
84 
85 #define SCG_APLLCFG_PREDIV_VAL ((SCG->APLLCFG & SCG_APLLCFG_PREDIV_MASK) >> SCG_APLLCFG_PREDIV_SHIFT)
86 #define SCG_APLLCFG_MULT_VAL ((SCG->APLLCFG & SCG_APLLCFG_MULT_MASK) >> SCG_APLLCFG_MULT_SHIFT)
87 #define SCG_APLLNUM_NUM_VAL (((uint64_t)SCG->APLLNUM & SCG_APLLNUM_NUM_MASK) >> SCG_APLLNUM_NUM_SHIFT)
88 #define SCG_APLLDENOM_DENOM_VAL ((SCG->APLLDENOM & SCG_APLLDENOM_DENOM_MASK) >> SCG_APLLDENOM_DENOM_SHIFT)
89 #define SCG_APLLPFD_PFD_MAX_VAL (SCG_APLLPFD_PFD0_MASK >> SCG_SPLLPFD_PFD0_SHIFT)
90 #define SCG_APLLCFG_POSTDIV1_VAL ((SCG->APLLCFG & SCG_APLLCFG_PLLPOSTDIV1_MASK) >> SCG_APLLCFG_PLLPOSTDIV1_SHIFT)
91 #define SCG_APLLCFG_POSTDIV2_VAL ((SCG->APLLCFG & SCG_APLLCFG_PLLPOSTDIV2_MASK) >> SCG_APLLCFG_PLLPOSTDIV2_SHIFT)
92 #define SCG_APLLDIV_APLLDIV1_VAL ((SCG->APLLDIV & SCG_APLLDIV_APLLDIV1_MASK) >> SCG_APLLDIV_APLLDIV1_SHIFT)
93 #define SCG_APLLDIV_APLLDIV2_VAL ((SCG->APLLDIV & SCG_APLLDIV_APLLDIV2_MASK) >> SCG_APLLDIV_APLLDIV2_SHIFT)
94 #define SCG_APLLDIV_APLLDIV3_VAL ((SCG->APLLDIV & SCG_APLLDIV_APLLDIV3_MASK) >> SCG_APLLDIV_APLLDIV3_SHIFT)
95 
96 /*
97  * Constant used to calcul PLL PFD clock frequency
98  * PFD Clock Frequency = PLL output frequency * 18/frac value
99  */
100 #define PFD_FREQ_CALCUL_CONSTANT 18U
101 
102 /*! @brief Bitfield values for general PCC registers. */
103 #define PCC_PCS_VAL(reg) (((reg)&PCC_CLKCFG_PCS_MASK) >> PCC_CLKCFG_PCS_SHIFT)
104 #define PCC_FRAC_VAL(reg) (((reg)&PCC_CLKCFG_FRAC_MASK) >> PCC_CLKCFG_FRAC_SHIFT)
105 #define PCC_PCD_VAL(reg) (((reg)&PCC_CLKCFG_PCD_MASK) >> PCC_CLKCFG_PCD_SHIFT)
106 
107 /*******************************************************************************
108  * Variables
109  ******************************************************************************/
110 /* System PLL multiplier array */
111 static const uint8_t s_spllMulti[] = {0U, 15U, 16U, 20U, 22U, 25U, 30U, 0U};
112 
113 /* External XTAL0 (OSC0) clock frequency. */
114 volatile uint32_t g_xtal0Freq;
115 /* External XTAL32K clock frequency. */
116 volatile uint32_t g_xtal32Freq;
117 /* External LVDS pad clock frequency. */
118 volatile uint32_t g_lvdsFreq;
119 
120 /*******************************************************************************
121  * Prototypes
122  ******************************************************************************/
123 
124 /*!
125  * @brief Get the common Auxiliary PLL frequency for both RAW APLL output and APLL PFD output.
126  *
127  * The "raw" APLL output is the clkout divided by postdiv1-2 of APLL.
128  * The "common" Auxiliary PLL frequency is the common part for both RAW APLL and APLL PFD output.
129  * That is the frequency calculated based on the clock source which passes through POSTDIV & MULT.
130  * "Common" APLL Frequency = Divided Reference Frequency * MULT
131  *
132  * @return  Clock frequency; If the clock is invalid, returns 0.
133  */
134 static uint32_t CLOCK_GetAuxPllCommonFreq(void);
135 
136 /*!
137  * @brief Get the common System PLL frequency for both RAW SPLL output and SPLL PFD output.
138  *
139  * The "raw" SPLL output is the clkout divided by postdiv1-2 of SAPLL.
140  * The "common" System PLL frequency is the common part for both RAW SPLL and SPLL PFD output.
141  * That is the frequency calculated based on the clock source which passes through POSTDIV & MULT.
142  * "Common" SPLL Frequency = Divided Reference Frequency * MULT
143  *
144  * @return  Clock frequency; If the clock is invalid, returns 0.
145  */
146 static uint32_t CLOCK_GetSysPllCommonFreq(void);
147 
148 /*******************************************************************************
149  * Code
150  ******************************************************************************/
151 
152 /* Function Name : CLOCK_GetErClkFreq */
153 /*!
154  * brief Get the external reference clock frequency (ERCLK).
155  *
156  * return Clock frequency in Hz.
157  */
CLOCK_GetErClkFreq(void)158 uint32_t CLOCK_GetErClkFreq(void)
159 {
160     uint32_t freq;
161 
162     if ((SCG->SOSCCSR & SCG_SOSCCSR_SOSCEN_MASK) != 0UL)
163     {
164         /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
165         assert(g_xtal0Freq);
166         freq = g_xtal0Freq;
167     }
168     else
169     {
170         freq = 0U;
171     }
172 
173     return freq;
174 }
175 
176 /*!
177  * brief Get the OSC 32K clock frequency (OSC32KCLK).
178  *
179  * return Clock frequency in Hz.
180  */
CLOCK_GetOsc32kClkFreq(void)181 uint32_t CLOCK_GetOsc32kClkFreq(void)
182 {
183     assert(g_xtal32Freq);
184     return g_xtal32Freq;
185 }
186 
187 /*!
188  * brief Get the external LVDS pad clock frequency (LVDS).
189  *
190  * return Clock frequency in Hz.
191  */
CLOCK_GetLvdsClkFreq(void)192 uint32_t CLOCK_GetLvdsClkFreq(void)
193 {
194     assert(g_lvdsFreq);
195     return g_lvdsFreq;
196 }
197 
198 /*!
199  * brief Get the slow clock frequency.
200  *
201  * return Clock frequency in Hz.
202  */
CLOCK_GetSlowClkFreq(void)203 uint32_t CLOCK_GetSlowClkFreq(void)
204 {
205     return CLOCK_GetSysClkFreq(kSCG_SysClkSlow);
206 }
207 
208 /*!
209  * brief Get the bus clock frequency.
210  *
211  * return Clock frequency in Hz.
212  */
CLOCK_GetBusClkFreq(void)213 uint32_t CLOCK_GetBusClkFreq(void)
214 {
215     return CLOCK_GetSysClkFreq(kSCG_SysClkBus);
216 }
217 
218 /*!
219  * brief Get the external clock frequency.
220  *
221  * return Clock frequency in Hz.
222  */
CLOCK_GetExtClkFreq(void)223 uint32_t CLOCK_GetExtClkFreq(void)
224 {
225     return CLOCK_GetSysClkFreq(kSCG_SysClkExt);
226 }
227 
228 /*!
229  * brief Get the platform clock frequency.
230  *
231  * return Clock frequency in Hz.
232  */
CLOCK_GetPlatClkFreq(void)233 uint32_t CLOCK_GetPlatClkFreq(void)
234 {
235     return CLOCK_GetSysClkFreq(kSCG_SysClkPlat);
236 }
237 
238 /*!
239  * brief Get the core clock or system clock frequency.
240  *
241  * return Clock frequency in Hz.
242  */
CLOCK_GetCoreSysClkFreq(void)243 uint32_t CLOCK_GetCoreSysClkFreq(void)
244 {
245     return CLOCK_GetSysClkFreq(kSCG_SysClkCore);
246 }
247 
248 /*!
249  * brief Gets the clock frequency for a specific clock name.
250  *
251  * This function checks the current clock configurations and then calculates
252  * the clock frequency for a specific clock name defined in clock_name_t.
253  *
254  * param clockName Clock names defined in clock_name_t
255  * return Clock frequency value in hertz
256  */
CLOCK_GetFreq(clock_name_t clockName)257 uint32_t CLOCK_GetFreq(clock_name_t clockName)
258 {
259     uint32_t freq;
260 
261     switch (clockName)
262     {
263         case kCLOCK_CoreSysClk:
264             freq = CLOCK_GetSysClkFreq(kSCG_SysClkCore);
265             break;
266         case kCLOCK_PlatClk:
267             freq = CLOCK_GetSysClkFreq(kSCG_SysClkPlat);
268             break;
269         case kCLOCK_ExtClk:
270             freq = CLOCK_GetSysClkFreq(kSCG_SysClkExt);
271             break;
272         case kCLOCK_BusClk:
273             freq = CLOCK_GetSysClkFreq(kSCG_SysClkBus);
274             break;
275         case kCLOCK_SlowClk:
276             freq = CLOCK_GetSysClkFreq(kSCG_SysClkSlow);
277             break;
278 
279         case kCLOCK_ScgSysOscClk:
280             freq = CLOCK_GetSysOscFreq();
281             break;
282         case kCLOCK_ScgSircClk:
283             freq = CLOCK_GetSircFreq();
284             break;
285         case kCLOCK_ScgFircClk:
286             freq = CLOCK_GetFircFreq();
287             break;
288         case kCLOCK_ScgSysPllClk:
289             freq = CLOCK_GetSysPllFreq();
290             break;
291         case kCLOCK_ScgAuxPllClk:
292             freq = CLOCK_GetAuxPllFreq();
293             break;
294 
295         case kCLOCK_ScgSysOscAsyncDiv1Clk:
296             freq = CLOCK_GetSysOscAsyncFreq(kSCG_AsyncDiv1Clk);
297             break;
298         case kCLOCK_ScgSysOscAsyncDiv2Clk:
299             freq = CLOCK_GetSysOscAsyncFreq(kSCG_AsyncDiv2Clk);
300             break;
301         case kCLOCK_ScgSysOscAsyncDiv3Clk:
302             freq = CLOCK_GetSysOscAsyncFreq(kSCG_AsyncDiv3Clk);
303             break;
304 
305         case kCLOCK_ScgSircAsyncDiv1Clk:
306             freq = CLOCK_GetSircAsyncFreq(kSCG_AsyncDiv1Clk);
307             break;
308         case kCLOCK_ScgSircAsyncDiv2Clk:
309             freq = CLOCK_GetSircAsyncFreq(kSCG_AsyncDiv2Clk);
310             break;
311         case kCLOCK_ScgSircAsyncDiv3Clk:
312             freq = CLOCK_GetSircAsyncFreq(kSCG_AsyncDiv3Clk);
313             break;
314 
315         case kCLOCK_ScgFircAsyncDiv1Clk:
316             freq = CLOCK_GetFircAsyncFreq(kSCG_AsyncDiv1Clk);
317             break;
318         case kCLOCK_ScgFircAsyncDiv2Clk:
319             freq = CLOCK_GetFircAsyncFreq(kSCG_AsyncDiv2Clk);
320             break;
321         case kCLOCK_ScgFircAsyncDiv3Clk:
322             freq = CLOCK_GetFircAsyncFreq(kSCG_AsyncDiv3Clk);
323             break;
324 
325         case kCLOCK_ScgSysPllPfd0Clk:
326             freq = CLOCK_GetSysPllPfdFreq(kSCG_SysPllPfd0Clk);
327             break;
328         case kCLOCK_ScgSysPllPfd1Clk:
329             freq = CLOCK_GetSysPllPfdFreq(kSCG_SysPllPfd1Clk);
330             break;
331         case kCLOCK_ScgSysPllPfd2Clk:
332             freq = CLOCK_GetSysPllPfdFreq(kSCG_SysPllPfd2Clk);
333             break;
334         case kCLOCK_ScgSysPllPfd3Clk:
335             freq = CLOCK_GetSysPllPfdFreq(kSCG_SysPllPfd3Clk);
336             break;
337 
338         case kCLOCK_ScgAuxPllPfd0Clk:
339             freq = CLOCK_GetAuxPllPfdFreq(kSCG_AuxPllPfd0Clk);
340             break;
341         case kCLOCK_ScgAuxPllPfd1Clk:
342             freq = CLOCK_GetAuxPllPfdFreq(kSCG_AuxPllPfd1Clk);
343             break;
344         case kCLOCK_ScgAuxPllPfd2Clk:
345             freq = CLOCK_GetAuxPllPfdFreq(kSCG_AuxPllPfd2Clk);
346             break;
347         case kCLOCK_ScgAuxPllPfd3Clk:
348             freq = CLOCK_GetAuxPllPfdFreq(kSCG_AuxPllPfd3Clk);
349             break;
350 
351         case kCLOCK_ScgSysPllAsyncDiv1Clk:
352             freq = CLOCK_GetSysPllAsyncFreq(kSCG_AsyncDiv1Clk);
353             break;
354         case kCLOCK_ScgSysPllAsyncDiv2Clk:
355             freq = CLOCK_GetSysPllAsyncFreq(kSCG_AsyncDiv2Clk);
356             break;
357         case kCLOCK_ScgSysPllAsyncDiv3Clk:
358             freq = CLOCK_GetSysPllAsyncFreq(kSCG_AsyncDiv3Clk);
359             break;
360 
361         case kCLOCK_ScgAuxPllAsyncDiv1Clk:
362             freq = CLOCK_GetAuxPllAsyncFreq(kSCG_AsyncDiv1Clk);
363             break;
364         case kCLOCK_ScgAuxPllAsyncDiv2Clk:
365             freq = CLOCK_GetAuxPllAsyncFreq(kSCG_AsyncDiv2Clk);
366             break;
367         case kCLOCK_ScgAuxPllAsyncDiv3Clk:
368             freq = CLOCK_GetAuxPllAsyncFreq(kSCG_AsyncDiv3Clk);
369             break;
370 
371         case kCLOCK_LpoClk:
372             freq = LPO_CLK_FREQ;
373             break;
374         case kCLOCK_Osc32kClk:
375             freq = CLOCK_GetOsc32kClkFreq();
376             break;
377         case kCLOCK_ErClk:
378             freq = CLOCK_GetErClkFreq();
379             break;
380         case kCLOCK_LvdsClk:
381             freq = CLOCK_GetLvdsClkFreq();
382             break;
383         default:
384             freq = 0U;
385             break;
386     }
387     return freq;
388 }
389 
390 /* Function Name : CLOCK_GetIpFreq */
391 /*!
392  * brief Gets the clock frequency for a specific IP module.
393  *
394  * This function gets the IP module clock frequency based on PCC registers. It is
395  * only used for the IP modules which could select clock source by PCC[PCS].
396  *
397  * param name Which peripheral to get, see \ref clock_ip_name_t.
398  * return Clock frequency value in hertz
399  */
CLOCK_GetIpFreq(clock_ip_name_t name)400 uint32_t CLOCK_GetIpFreq(clock_ip_name_t name)
401 {
402     uint32_t reg = (*(volatile uint32_t *)(uint32_t)name);
403 
404     scg_async_clk_t asycClk;
405     scg_sys_clk_t sysClk;
406     uint32_t freq;
407 
408     assert(reg & PCC_CLKCFG_PR_MASK);
409 
410     if (kCLOCK_Tpiu == name)
411     {
412         freq = TPIU_CLK_FREQ;
413     }
414     else
415     {
416         /* QSPI uses SCG DIV1 clock, while the others use SCG DIV2 clock. */
417         if (kCLOCK_Qspi == name)
418         {
419             sysClk  = kSCG_SysClkPlat;
420             asycClk = kSCG_AsyncDiv1Clk;
421         }
422         else
423         {
424             sysClk  = kSCG_SysClkBus;
425             asycClk = kSCG_AsyncDiv2Clk;
426         }
427 
428         switch (PCC_PCS_VAL(reg))
429         {
430             case (uint32_t)kCLOCK_IpSrcNone:
431                 freq = 0U;
432                 break;
433             case (uint32_t)kCLOCK_IpSrcPllPfdAsync:
434                 if (kCLOCK_Qspi == name)
435                 {
436                     freq = CLOCK_GetSysPllPfdFreq(kSCG_SysPllPfd3Clk);
437                 }
438                 else
439                 {
440                     freq = CLOCK_GetAuxPllPfdFreq(kSCG_AuxPllPfd0Clk);
441                 }
442                 break;
443             case (uint32_t)kCLOCK_IpSrcSysPllAsync:
444                 if (kCLOCK_Qspi == name)
445                 {
446                     freq = CLOCK_GetSysPllFreq();
447                 }
448                 else
449                 {
450                     freq = CLOCK_GetSysPllAsyncFreq(asycClk);
451                 }
452                 break;
453             case (uint32_t)kCLOCK_IpSrcSystem:
454                 freq = CLOCK_GetSysClkFreq(sysClk);
455                 break;
456             case (uint32_t)kCLOCK_IpSrcRtcAuxPllAsync:
457                 if (kCLOCK_Qspi == name)
458                 {
459                     freq = CLOCK_GetRtcOscFreq();
460                 }
461                 else
462                 {
463                     freq = CLOCK_GetAuxPllFreq();
464                 }
465                 break;
466             case (uint32_t)kCLOCK_IpSrcFircAsync:
467                 freq = CLOCK_GetFircAsyncFreq(asycClk);
468                 break;
469             case (uint32_t)kCLOCK_IpSrcSircAsync:
470                 freq = CLOCK_GetSircAsyncFreq(asycClk);
471                 break;
472             case (uint32_t)kCLOCK_IpSrcSysOscAsync:
473                 freq = CLOCK_GetSysOscAsyncFreq(asycClk);
474                 break;
475             default:
476                 freq = 0U;
477                 break;
478         }
479     }
480 
481     if ((kCLOCK_Sai0 == name) || (kCLOCK_Sai1 == name))
482     {
483         if ((reg & (PCC1_PCC_SAI1_PCD_MASK)) != 0UL)
484         {
485             return freq * (((reg & PCC1_PCC_SAI1_PCD_MASK) >> PCC1_PCC_SAI1_PCD_SHIFT) + 1U);
486         }
487         else
488         {
489             return freq;
490         }
491     }
492     else
493     {
494         if ((reg & (PCC_CLKCFG_PCD_MASK | PCC_CLKCFG_FRAC_MASK)) != 0UL)
495         {
496             return freq * (PCC_FRAC_VAL(reg) + 1U) / (PCC_PCD_VAL(reg) + 1U);
497         }
498         else
499         {
500             return freq;
501         }
502     }
503 }
504 
505 /*!
506  * brief Gets the SCG system clock frequency.
507  *
508  * This function gets the SCG system clock frequency. These clocks are used for
509  * core, platform, external, and bus clock domains.
510  *
511  * param type     Which type of clock to get, core clock or slow clock.
512  * return  Clock frequency.
513  */
CLOCK_GetSysClkFreq(scg_sys_clk_t type)514 uint32_t CLOCK_GetSysClkFreq(scg_sys_clk_t type)
515 {
516     uint32_t freq;
517 
518     scg_sys_clk_config_t sysClkConfig;
519 
520     CLOCK_GetCurSysClkConfig(&sysClkConfig);
521 
522     switch (sysClkConfig.src)
523     {
524         case (uint32_t)kSCG_SysClkSrcSysOsc:
525             freq = CLOCK_GetSysOscFreq();
526             break;
527         case (uint32_t)kSCG_SysClkSrcSirc:
528             freq = CLOCK_GetSircFreq();
529             break;
530         case (uint32_t)kSCG_SysClkSrcFirc:
531             freq = CLOCK_GetFircFreq();
532             break;
533         case (uint32_t)kSCG_SysClkSrcRosc:
534             freq = CLOCK_GetRtcOscFreq();
535             break;
536         case (uint32_t)kSCG_SysClkSrcAuxPll:
537             freq = CLOCK_GetAuxPllFreq();
538             break;
539         case (uint32_t)kSCG_SysClkSrcSysPll:
540             freq = CLOCK_GetSysPllFreq();
541             break;
542         default:
543             freq = 0U;
544             break;
545     }
546 
547     freq /= (sysClkConfig.divCore + 1U);
548 
549     if (kSCG_SysClkSlow == type)
550     {
551         freq /= (sysClkConfig.divSlow + 1U);
552     }
553     else if (kSCG_SysClkPlat == type)
554     {
555         freq /= (sysClkConfig.divPlat + 1U);
556     }
557     else if (kSCG_SysClkBus == type)
558     {
559         freq /= (sysClkConfig.divBus + 1U);
560     }
561     /*    else if (kSCG_SysClkExt == type)
562         {
563             freq /= (sysClkConfig.divExt + 1U);
564         } */
565     else
566     {
567         /* Add comment to prevent the case of rule 15.7. */
568     }
569 
570     return freq;
571 }
572 
573 /*!
574  * brief Initializes the SCG system OSC.
575  *
576  * This function enables the SCG system OSC clock according to the
577  * configuration.
578  *
579  * param config   Pointer to the configuration structure.
580  * retval kStatus_Success System OSC is initialized.
581  * retval kStatus_SCG_Busy System OSC has been enabled and is used by the system clock.
582  * retval kStatus_ReadOnly System OSC control register is locked.
583  *
584  * note This function can't detect whether the system OSC has been enabled and
585  * used by an IP.
586  */
CLOCK_InitSysOsc(const scg_sosc_config_t * config)587 status_t CLOCK_InitSysOsc(const scg_sosc_config_t *config)
588 {
589     assert(config);
590     status_t status;
591 
592     /* De-init the SOSC first. */
593     status = CLOCK_DeinitSysOsc();
594 
595     if (kStatus_Success != status)
596     {
597         return status;
598     }
599 
600     /* Now start to set up OSC clock. */
601     /* Step 1. Setup dividers. */
602     SCG->SOSCDIV =
603         SCG_SOSCDIV_SOSCDIV1(config->div1) | SCG_SOSCDIV_SOSCDIV2(config->div2) | SCG_SOSCDIV_SOSCDIV3(config->div3);
604 
605     /* Step 2. Set OSC configuration. */
606     SCG->SOSCCFG = (uint32_t)(config->workMode);
607 
608     /* Step 3. Enable clock. */
609     SCG->SOSCCSR = (uint32_t)SCG_SOSCCSR_SOSCEN_MASK | (config->enableMode);
610 
611     /* Step 4. Wait for OSC clock to be valid. */
612     while (0UL == (SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK))
613     {
614     }
615 
616     /* Step 5. Enabe monitor. */
617     SCG->SOSCCSR |= (uint32_t)config->monitorMode;
618 
619     return kStatus_Success;
620 }
621 
622 /*!
623  * brief De-initializes the SCG system OSC.
624  *
625  * This function disables the SCG system OSC clock.
626  *
627  * retval kStatus_Success System OSC is deinitialized.
628  * retval kStatus_SCG_Busy System OSC is used by the system clock.
629  * retval kStatus_ReadOnly System OSC control register is locked.
630  *
631  * note This function can't detect whether the system OSC is used by an IP.
632  */
CLOCK_DeinitSysOsc(void)633 status_t CLOCK_DeinitSysOsc(void)
634 {
635     uint32_t reg = SCG->SOSCCSR;
636     status_t status;
637 
638     /* If clock is used by system, return error. */
639     if ((reg & SCG_SOSCCSR_SOSCSEL_MASK) != 0UL)
640     {
641         status = kStatus_SCG_Busy;
642     }
643     /* If configure register is locked, return error. */
644     else if ((reg & SCG_SOSCCSR_LK_MASK) != 0UL)
645     {
646         status = kStatus_ReadOnly;
647     }
648     else
649     {
650         SCG->SOSCCSR = SCG_SOSCCSR_SOSCERR_MASK;
651         status       = kStatus_Success;
652     }
653 
654     return status;
655 }
656 
657 /*!
658  * brief Gets the SCG system OSC clock frequency (SYSOSC).
659  *
660  * return  Clock frequency; If the clock is invalid, returns 0.
661  */
CLOCK_GetSysOscFreq(void)662 uint32_t CLOCK_GetSysOscFreq(void)
663 {
664     uint32_t freq;
665 
666     if ((SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) != 0UL) /* System OSC clock is valid. */
667     {
668         /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
669         assert(g_xtal0Freq);
670         freq = g_xtal0Freq;
671     }
672     else
673     {
674         freq = 0U;
675     }
676 
677     return freq;
678 }
679 
680 /*!
681  * brief Gets the SCG asynchronous clock frequency from the system OSC.
682  *
683  * param type     The asynchronous clock type.
684  * return  Clock frequency; If the clock is invalid, returns 0.
685  */
CLOCK_GetSysOscAsyncFreq(scg_async_clk_t type)686 uint32_t CLOCK_GetSysOscAsyncFreq(scg_async_clk_t type)
687 {
688     uint32_t oscFreq = CLOCK_GetSysOscFreq();
689     uint32_t divider = 0U;
690     uint32_t freq;
691 
692     /* Get divider. */
693     if (oscFreq != 0UL)
694     {
695         switch (type)
696         {
697             case kSCG_AsyncDiv3Clk: /* SOSCDIV3_CLK. */
698                 divider = SCG_SOSCDIV_SOSCDIV3_VAL;
699                 break;
700             case kSCG_AsyncDiv2Clk: /* SOSCDIV2_CLK. */
701                 divider = SCG_SOSCDIV_SOSCDIV2_VAL;
702                 break;
703             case kSCG_AsyncDiv1Clk: /* SOSCDIV1_CLK. */
704                 divider = SCG_SOSCDIV_SOSCDIV1_VAL;
705                 break;
706             default:
707                 divider = 0U;
708                 break;
709         }
710     }
711     if (divider != 0UL)
712     {
713         freq = oscFreq >> (divider - 1U);
714     }
715     else /* Output disabled. */
716     {
717         freq = 0U;
718     }
719 
720     return freq;
721 }
722 
723 /*!
724  * brief Initializes the SCG slow IRC clock.
725  *
726  * This function enables the SCG slow IRC clock according to the
727  * configuration.
728  *
729  * param config   Pointer to the configuration structure.
730  * retval kStatus_Success SIRC is initialized.
731  * retval kStatus_SCG_Busy SIRC has been enabled and is used by system clock.
732  * retval kStatus_ReadOnly SIRC control register is locked.
733  *
734  * note This function can't detect whether the system OSC has been enabled and
735  * used by an IP.
736  */
CLOCK_InitSirc(const scg_sirc_config_t * config)737 status_t CLOCK_InitSirc(const scg_sirc_config_t *config)
738 {
739     assert(config);
740 
741     status_t status;
742 
743     /* De-init the SIRC first. */
744     status = CLOCK_DeinitSirc();
745 
746     if (kStatus_Success != status)
747     {
748         return status;
749     }
750 
751     /* Now start to set up SIRC clock. */
752     /* Step 1. Setup dividers. */
753     SCG->SIRCDIV =
754         SCG_SIRCDIV_SIRCDIV1(config->div1) | SCG_SIRCDIV_SIRCDIV2(config->div2) | SCG_SIRCDIV_SIRCDIV3(config->div3);
755 
756     /* Step 2. Set SIRC configuration. */
757     SCG->SIRCCFG = SCG_SIRCCFG_RANGE(config->range);
758 
759     /* Step 3. Enable clock. */
760     SCG->SIRCCSR = SCG_SIRCCSR_SIRCEN_MASK | config->enableMode;
761 
762     /* Step 4. Wait for SIRC clock to be valid. */
763     while (0UL == (SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK))
764     {
765     }
766 
767     return kStatus_Success;
768 }
769 
770 /*!
771  * brief De-initializes the SCG slow IRC.
772  *
773  * This function disables the SCG slow IRC.
774  *
775  * retval kStatus_Success SIRC is deinitialized.
776  * retval kStatus_SCG_Busy SIRC is used by system clock.
777  * retval kStatus_ReadOnly SIRC control register is locked.
778  *
779  * note This function can't detect whether the SIRC is used by an IP.
780  */
CLOCK_DeinitSirc(void)781 status_t CLOCK_DeinitSirc(void)
782 {
783     uint32_t reg = SCG->SIRCCSR;
784     status_t status;
785 
786     /* If clock is used by system, return error. */
787     if ((reg & SCG_SIRCCSR_SIRCSEL_MASK) != 0UL)
788     {
789         status = kStatus_SCG_Busy;
790     }
791     /* If configure register is locked, return error. */
792     else if ((reg & SCG_SIRCCSR_LK_MASK) != 0UL)
793     {
794         status = kStatus_ReadOnly;
795     }
796     else
797     {
798         SCG->SIRCCSR = 0U;
799         status       = kStatus_Success;
800     }
801 
802     return status;
803 }
804 
805 /*!
806  * brief Gets the SCG SIRC clock frequency.
807  *
808  * return  Clock frequency; If the clock is invalid, returns 0.
809  */
CLOCK_GetSircFreq(void)810 uint32_t CLOCK_GetSircFreq(void)
811 {
812     static const uint32_t sircFreq[] = {SCG_SIRC_LOW_RANGE_FREQ, SCG_SIRC_HIGH_RANGE_FREQ};
813     uint32_t freq;
814 
815     if ((SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK) != 0UL) /* SIRC is valid. */
816     {
817         freq = sircFreq[SCG_SIRCCFG_RANGE_VAL];
818     }
819     else
820     {
821         freq = 0U;
822     }
823 
824     return freq;
825 }
826 
827 /*!
828  * brief Gets the SCG asynchronous clock frequency from the SIRC.
829  *
830  * param type     The asynchronous clock type.
831  * return  Clock frequency; If the clock is invalid, returns 0.
832  */
CLOCK_GetSircAsyncFreq(scg_async_clk_t type)833 uint32_t CLOCK_GetSircAsyncFreq(scg_async_clk_t type)
834 {
835     uint32_t sircFreq = CLOCK_GetSircFreq();
836     uint32_t divider  = 0U;
837     uint32_t freq;
838 
839     /* Get divider. */
840     if (sircFreq != 0UL)
841     {
842         switch (type)
843         {
844             case kSCG_AsyncDiv3Clk: /* SIRCDIV3_CLK. */
845                 divider = SCG_SIRCDIV_SIRCDIV3_VAL;
846                 break;
847             case kSCG_AsyncDiv2Clk: /* SIRCDIV2_CLK. */
848                 divider = SCG_SIRCDIV_SIRCDIV2_VAL;
849                 break;
850             case kSCG_AsyncDiv1Clk: /* SIRCDIV2_CLK. */
851                 divider = SCG_SIRCDIV_SIRCDIV1_VAL;
852                 break;
853             default:
854                 divider = 0U;
855                 break;
856         }
857     }
858     if (divider != 0UL)
859     {
860         freq = sircFreq >> (divider - 1U);
861     }
862     else /* Output disabled. */
863     {
864         freq = 0U;
865     }
866 
867     return freq;
868 }
869 
870 /*!
871  * brief Initializes the SCG fast IRC clock.
872  *
873  * This function enables the SCG fast IRC clock according to the configuration.
874  *
875  * param config   Pointer to the configuration structure.
876  * retval kStatus_Success FIRC is initialized.
877  * retval kStatus_SCG_Busy FIRC has been enabled and is used by the system clock.
878  * retval kStatus_ReadOnly FIRC control register is locked.
879  *
880  * note This function can't detect whether the FIRC has been enabled and
881  * used by an IP.
882  */
CLOCK_InitFirc(const scg_firc_config_t * config)883 status_t CLOCK_InitFirc(const scg_firc_config_t *config)
884 {
885     assert(config);
886 
887     status_t status;
888 
889     /* De-init the FIRC first. */
890     status = CLOCK_DeinitFirc();
891 
892     if (kStatus_Success != status)
893     {
894         return status;
895     }
896 
897     /* Now start to set up FIRC clock. */
898     /* Step 1. Setup dividers. */
899     SCG->FIRCDIV =
900         SCG_FIRCDIV_FIRCDIV1(config->div1) | SCG_FIRCDIV_FIRCDIV2(config->div2) | SCG_FIRCDIV_FIRCDIV3(config->div3);
901 
902     /* Step 2. Set FIRC configuration. */
903     SCG->FIRCCFG = SCG_FIRCCFG_RANGE(config->range);
904 
905     /* Step 3. Set trimming configuration. */
906     if ((config->trimConfig) != NULL)
907     {
908         SCG->FIRCTCFG =
909             SCG_FIRCTCFG_TRIMDIV(config->trimConfig->trimDiv) | SCG_FIRCTCFG_TRIMSRC(config->trimConfig->trimSrc);
910 
911         /* TODO: Write FIRCSTAT cause bus error: TKT266932. */
912         if (kSCG_FircTrimNonUpdate == config->trimConfig->trimMode)
913         {
914             SCG->FIRCSTAT = SCG_FIRCSTAT_TRIMCOAR(config->trimConfig->trimCoar) |
915                             SCG_FIRCSTAT_TRIMFINE(config->trimConfig->trimFine);
916         }
917 
918         /* trim mode. */
919         SCG->FIRCCSR = (uint32_t)(config->trimConfig->trimMode);
920 
921         if ((SCG->FIRCCSR & SCG_FIRCCSR_FIRCERR_MASK) != 0UL)
922         {
923             return kStatus_Fail;
924         }
925     }
926 
927     /* Step 4. Enable clock. */
928     SCG->FIRCCSR |= (SCG_FIRCCSR_FIRCEN_MASK | config->enableMode);
929 
930     /* Step 5. Wait for FIRC clock to be valid. */
931     while (0UL == (SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK))
932     {
933     }
934 
935     return kStatus_Success;
936 }
937 
938 /*!
939  * brief De-initializes the SCG fast IRC.
940  *
941  * This function disables the SCG fast IRC.
942  *
943  * retval kStatus_Success FIRC is deinitialized.
944  * retval kStatus_SCG_Busy FIRC is used by the system clock.
945  * retval kStatus_ReadOnly FIRC control register is locked.
946  *
947  * note This function can't detect whether the FIRC is used by an IP.
948  */
CLOCK_DeinitFirc(void)949 status_t CLOCK_DeinitFirc(void)
950 {
951     uint32_t reg = SCG->FIRCCSR;
952     status_t status;
953 
954     /* If clock is used by system, return error. */
955     if ((reg & SCG_FIRCCSR_FIRCSEL_MASK) != 0UL)
956     {
957         status = kStatus_SCG_Busy;
958     }
959     /* If configure register is locked, return error. */
960     else if ((reg & SCG_FIRCCSR_LK_MASK) != 0UL)
961     {
962         status = kStatus_ReadOnly;
963     }
964     else
965     {
966         SCG->FIRCCSR = SCG_FIRCCSR_FIRCERR_MASK;
967         status       = kStatus_Success;
968     }
969 
970     return status;
971 }
972 
973 /*!
974  * brief Gets the SCG FIRC clock frequency.
975  *
976  * return  Clock frequency; If the clock is invalid, returns 0.
977  */
CLOCK_GetFircFreq(void)978 uint32_t CLOCK_GetFircFreq(void)
979 {
980     static const uint32_t fircFreq[] = {
981         SCG_FIRC_FREQ0,
982         SCG_FIRC_FREQ1,
983         SCG_FIRC_FREQ2,
984         SCG_FIRC_FREQ3,
985     };
986     uint32_t freq;
987 
988     if ((SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK) != 0UL) /* FIRC is valid. */
989     {
990         freq = fircFreq[SCG_FIRCCFG_RANGE_VAL];
991     }
992     else
993     {
994         freq = 0U;
995     }
996 
997     return freq;
998 }
999 
1000 /*!
1001  * brief Gets the SCG asynchronous clock frequency from the FIRC.
1002  *
1003  * param type     The asynchronous clock type.
1004  * return  Clock frequency; If the clock is invalid, returns 0.
1005  */
CLOCK_GetFircAsyncFreq(scg_async_clk_t type)1006 uint32_t CLOCK_GetFircAsyncFreq(scg_async_clk_t type)
1007 {
1008     uint32_t fircFreq = CLOCK_GetFircFreq();
1009     uint32_t divider  = 0U;
1010     uint32_t freq;
1011 
1012     /* Get divider. */
1013     if (fircFreq != 0UL)
1014     {
1015         switch (type)
1016         {
1017             case kSCG_AsyncDiv3Clk: /* FIRCDIV3_CLK. */
1018                 divider = SCG_FIRCDIV_FIRCDIV3_VAL;
1019                 break;
1020             case kSCG_AsyncDiv2Clk: /* FIRCDIV2_CLK. */
1021                 divider = SCG_FIRCDIV_FIRCDIV2_VAL;
1022                 break;
1023             case kSCG_AsyncDiv1Clk: /* FIRCDIV1_CLK. */
1024                 divider = SCG_FIRCDIV_FIRCDIV1_VAL;
1025                 break;
1026             default:
1027                 divider = 0U;
1028                 break;
1029         }
1030     }
1031     if (divider != 0UL)
1032     {
1033         freq = fircFreq >> (divider - 1U);
1034     }
1035     else /* Output disabled. */
1036     {
1037         freq = 0U;
1038     }
1039 
1040     return freq;
1041 }
1042 
1043 /*!
1044  * brief Gets the SCG RTC OSC clock frequency.
1045  *
1046  * return  Clock frequency; If the clock is invalid, returns 0.
1047  */
CLOCK_GetRtcOscFreq(void)1048 uint32_t CLOCK_GetRtcOscFreq(void)
1049 {
1050     uint32_t freq;
1051 
1052     if ((SCG->ROSCCSR & SCG_ROSCCSR_ROSCVLD_MASK) != 0UL) /* RTC OSC clock is valid. */
1053     {
1054         /* Please call CLOCK_SetXtal32Freq base on board setting before using RTC OSC clock. */
1055         assert(g_xtal32Freq);
1056         freq = g_xtal32Freq;
1057     }
1058     else
1059     {
1060         freq = 0U;
1061     }
1062 
1063     return freq;
1064 }
1065 
1066 /*!
1067  * brief Initializes the SCG auxiliary PLL.
1068  *
1069  * This function enables the SCG auxiliary PLL clock according to the
1070  * configuration. The auxiliary PLL can use the system OSC or FIRC as
1071  * the clock source. Ensure that the source clock is valid before
1072  * calling this function.
1073  *
1074  * Example code for initializing APLL clock output:
1075  * code
1076  * const scg_apll_config_t g_scgAuxPllConfig = {.enableMode = kSCG_AuxPllEnable,
1077  *                                            .div1 = kSCG_AsyncClkDisable,
1078  *                                            .div2 = kSCG_AsyncClkDisable,
1079  *                                            .div3 = kSCG_AsyncClkDisable,
1080  *                                            .src = kSCG_SysPllSrcFirc,
1081  *                                            .isPfdSelected = false,
1082  *                                            .prediv = 5U,
1083  *                                            .pfdClkout = kSCG_AuxPllPfd0Clk,
1084  *                                            .mult = 20U,
1085  *                                            .pllPostdiv1 = kSCG_SysClkDivBy3,
1086  *                                            .pllPostdiv2 = kSCG_SysClkDivBy4,
1087  *                                            .num = 578,
1088  *                                            .denom = 1000};
1089  * CLOCK_InitAuxPll(&g_scgAuxPllConfig);
1090  * endcode
1091  *
1092  * param config   Pointer to the configuration structure.
1093  * retval kStatus_Success auxiliary PLL is initialized.
1094  * retval kStatus_SCG_Busy auxiliary PLL has been enabled and is used by the system clock.
1095  * retval kStatus_ReadOnly auxiliary PLL control register is locked.
1096  *
1097  * note This function can't detect whether the auxiliary PLL has been enabled and
1098  * is used by an IP.
1099  */
CLOCK_InitAuxPll(const scg_apll_config_t * config)1100 status_t CLOCK_InitAuxPll(const scg_apll_config_t *config)
1101 {
1102     assert(config);
1103     /* For i.MX 7ULP, valid MULT values are 33, 27, 22, 20, 17, 16. */
1104     assert((33U == config->mult) || (27U == config->mult) || (22U == config->mult) || (20U == config->mult) ||
1105            (17U == config->mult) || (16U == config->mult));
1106 
1107     status_t status;
1108 
1109     /* De-init the APLL first. */
1110     status = CLOCK_DeinitAuxPll();
1111 
1112     if (kStatus_Success != status)
1113     {
1114         return status;
1115     }
1116 
1117     /* Now start to set up PLL clock. */
1118     /* Step 1. Setup dividers. */
1119     SCG->APLLDIV =
1120         SCG_APLLDIV_APLLDIV1(config->div1) | SCG_APLLDIV_APLLDIV2(config->div2) | SCG_APLLDIV_APLLDIV3(config->div3);
1121 
1122     /* Step 2. Set PLL configuration. */
1123     SCG->APLLCFG = SCG_APLLCFG_SOURCE(config->src) | SCG_APLLCFG_PREDIV(config->prediv) |
1124                    SCG_APLLCFG_MULT(config->mult) | SCG_APLLCFG_PLLS(config->isPfdSelected) |
1125                    SCG_APLLCFG_PFDSEL(((uint32_t)config->pfdClkout) >> 3U) |
1126                    SCG_APLLCFG_PLLPOSTDIV1(config->pllPostdiv1) | SCG_APLLCFG_PLLPOSTDIV2(config->pllPostdiv2);
1127 
1128     /* Step 3. Set Numerator and Denominator. */
1129     SCG->APLLDENOM = config->denom;
1130     SCG->APLLNUM   = config->num;
1131 
1132     /* Step 4. Enable clock. */
1133     SCG->APLLCSR = (uint32_t)SCG_APLLCSR_APLLEN_MASK | config->enableMode;
1134 
1135     /* Step 5. Wait for PLL clock to be valid. */
1136     while (0UL == (SCG->APLLCSR & SCG_APLLCSR_APLLVLD_MASK))
1137     {
1138     }
1139 
1140     return kStatus_Success;
1141 }
1142 
1143 /*!
1144  * brief De-initializes the SCG auxiliary PLL.
1145  *
1146  * This function disables the SCG auxiliary PLL.
1147  *
1148  * retval kStatus_Success auxiliary PLL is deinitialized.
1149  * retval kStatus_SCG_Busy auxiliary PLL is used by the system clock.
1150  * retval kStatus_ReadOnly auxiliary PLL control register is locked.
1151  *
1152  * note This function can't detect whether the auxiliary PLL is used by an IP.
1153  */
CLOCK_DeinitAuxPll(void)1154 status_t CLOCK_DeinitAuxPll(void)
1155 {
1156     uint32_t reg = SCG->APLLCSR;
1157     status_t status;
1158 
1159     /* If clock is used by system, return error. */
1160     if ((reg & SCG_APLLCSR_APLLSEL_MASK) != 0UL)
1161     {
1162         status = kStatus_SCG_Busy;
1163     }
1164     /* If configure register is locked, return error. */
1165     else if ((reg & SCG_APLLCSR_LK_MASK) != 0UL)
1166     {
1167         status = kStatus_ReadOnly;
1168     }
1169     else
1170     {
1171         /* Deinit and clear the error. */
1172         SCG->APLLCSR = 0;
1173         status       = kStatus_Success;
1174     }
1175 
1176     return status;
1177 }
1178 
CLOCK_GetAuxPllCommonFreq(void)1179 static uint32_t CLOCK_GetAuxPllCommonFreq(void)
1180 {
1181     uint32_t freq = 0U;
1182     uint64_t freqTmp;
1183     uint64_t apllnumTmp;
1184 
1185     if ((SCG->APLLCFG & SCG_APLLCFG_SOURCE_MASK) != 0UL) /* If use FIRC */
1186     {
1187         freq = CLOCK_GetFircFreq();
1188     }
1189     else /* Use System OSC. */
1190     {
1191         freq = CLOCK_GetSysOscFreq();
1192     }
1193 
1194     if (freq != 0UL) /* If source is valid. */
1195     {
1196         freq /= (SCG_APLLCFG_PREDIV_VAL + SCG_APLL_PREDIV_BASE_VALUE); /* Pre-divider. */
1197         apllnumTmp = SCG_APLLNUM_NUM_VAL;
1198         freqTmp    = (uint64_t)freq * (apllnumTmp) / (SCG_APLLDENOM_DENOM_VAL);
1199         freq       = freq * (SCG_APLLCFG_MULT_VAL + SCG_APLL_MULT_BASE_VALUE) + (uint32_t)freqTmp;
1200     }
1201 
1202     return freq;
1203 }
1204 
1205 /*!
1206  * brief Gets the SCG auxiliary PLL clock frequency.
1207  *
1208  * return  Clock frequency; If the clock is invalid, returns 0.
1209  */
CLOCK_GetAuxPllFreq(void)1210 uint32_t CLOCK_GetAuxPllFreq(void)
1211 {
1212     uint32_t freq;
1213     scg_apll_pfd_clkout_t pfdClkout;
1214 
1215     if ((SCG->APLLCFG & SCG_APLLCFG_PLLS_MASK) != 0UL)
1216     {
1217         /* pfdClkout is SCG_APLLCFG[PFDSEL] x 8. */
1218         pfdClkout = (scg_apll_pfd_clkout_t)(uint32_t)(
1219             ((SCG->APLLCFG & SCG_APLLCFG_PFDSEL_MASK) >> SCG_APLLCFG_PFDSEL_SHIFT) << 3U);
1220         freq = CLOCK_GetAuxPllPfdFreq(pfdClkout);
1221     }
1222     else
1223     {
1224         if ((SCG->APLLCSR & SCG_APLLCSR_APLLVLD_MASK) != 0UL) /* Auxiliary PLL is valid. */
1225         {
1226             freq = CLOCK_GetAuxPllCommonFreq();
1227 
1228             if (freq != 0UL)
1229             {
1230                 freq /= (SCG_APLLCFG_POSTDIV1_VAL + SCG_APLL_POSTDIV1_BASE_VALUE); /* Post-divider 1. */
1231                 freq /= (SCG_APLLCFG_POSTDIV2_VAL + SCG_APLL_POSTDIV2_BASE_VALUE); /* Post-divider 2. */
1232             }
1233 
1234             return freq;
1235         }
1236         else
1237         {
1238             return 0U;
1239         }
1240     }
1241 
1242     return freq;
1243 }
1244 
1245 /*!
1246  * brief Gets the SCG asynchronous clock frequency from the auxiliary PLL.
1247  *
1248  * param type     The asynchronous clock type.
1249  * return  Clock frequency; If the clock is invalid, returns 0.
1250  */
CLOCK_GetAuxPllAsyncFreq(scg_async_clk_t type)1251 uint32_t CLOCK_GetAuxPllAsyncFreq(scg_async_clk_t type)
1252 {
1253     uint32_t pllFreq = CLOCK_GetAuxPllFreq();
1254     uint32_t divider = 0U;
1255     uint32_t freq;
1256 
1257     /* Get divider. */
1258     if (pllFreq != 0UL)
1259     {
1260         switch (type)
1261         {
1262             case kSCG_AsyncDiv3Clk: /* APLLDIV3_CLK. */
1263                 divider = SCG_APLLDIV_APLLDIV3_VAL;
1264                 break;
1265             case kSCG_AsyncDiv2Clk: /* APLLDIV2_CLK. */
1266                 divider = SCG_APLLDIV_APLLDIV2_VAL;
1267                 break;
1268             case kSCG_AsyncDiv1Clk: /* APLLDIV1_CLK. */
1269                 divider = SCG_APLLDIV_APLLDIV1_VAL;
1270                 break;
1271             default:
1272                 divider = 0U;
1273                 break;
1274         }
1275     }
1276     if (divider != 0UL)
1277     {
1278         freq = pllFreq >> (divider - 1U);
1279     }
1280     else /* Output disabled. */
1281     {
1282         freq = 0U;
1283     }
1284 
1285     return freq;
1286 }
1287 
1288 /*!
1289  * brief Gets the SCG auxiliary PLL PFD clock frequency.
1290  *
1291  * param pfdClkout     The selected PFD clocks out. See "scg_apll_pfd_clkout_t".
1292  * return  Clock frequency; If the clock is invalid, returns 0.
1293  */
CLOCK_GetAuxPllPfdFreq(scg_apll_pfd_clkout_t pfdClkout)1294 uint32_t CLOCK_GetAuxPllPfdFreq(scg_apll_pfd_clkout_t pfdClkout)
1295 {
1296     uint32_t freq      = 0U;
1297     uint32_t fracValue = 0U;
1298 
1299     if ((SCG->APLLPFD & SCG_PLLPFD_PFD_VALID_MASK(pfdClkout)) != 0UL) /* Auxiliary PLL PFD is valid. */
1300     {
1301         if (0UL == (SCG->APLLPFD & SCG_PLLPFD_PFD_CLKGATE_MASK(pfdClkout)))
1302         {
1303             fracValue = (SCG->APLLPFD & SCG_PLLPFD_PFD_MASK(pfdClkout)) >> (uint32_t)pfdClkout;
1304 
1305             if (fracValue != 0UL)
1306             {
1307                 freq = CLOCK_GetAuxPllCommonFreq();
1308 
1309                 if (freq != 0UL) /* If source is valid. */
1310                 {
1311                     freq = (uint32_t)((uint64_t)freq * PFD_FREQ_CALCUL_CONSTANT /
1312                                       fracValue); /* PFD Clock Frequency = PLL output frequency * 18 / frac value. */
1313                 }
1314             }
1315         }
1316         else
1317         {
1318             freq = 0U;
1319         }
1320 
1321         return freq;
1322     }
1323     else
1324     {
1325         return 0U;
1326     }
1327 }
1328 
1329 /*!
1330  * brief Enables the SCG auxiliary PLL Fractional Divide (PFD) clock out with configurations.
1331  *
1332  * APLL Frequency = Fref * (MULT + NUM/DENOM)
1333  * PFD Clock Frequency = PLL output frequency * 18/frac value
1334  *
1335  * Example code for configuring APLL as APLL PFD clock output:
1336  * code
1337  * const scg_apll_config_t g_scgAuxPllConfig = {.enableMode = kSCG_AuxPllEnable,
1338  *                                              .div1 = kSCG_AsyncClkDisable,
1339  *                                              .div2 = kSCG_AsyncClkDisable,
1340  *                                              .div3 = kSCG_AsyncClkDisable,
1341  *                                              .src = kSCG_SysPllSrcFirc,
1342  *                                              .isPfdSelected = true,
1343  *                                              .prediv = 5U,
1344  *                                              .pfdClkout = kSCG_AuxPllPfd3Clk,
1345  *                                              .mult = 20U,
1346  *                                              .pllPostdiv1 = kSCG_SysClkDivBy1,
1347  *                                              .pllPostdiv2 = kSCG_SysClkDivBy1,
1348  *                                              .num = 578,
1349  *                                              .denom = 1000};
1350  * CLOCK_InitAuxPll(&g_scgAuxPllConfig);
1351  * CLOCK_EnableAuxPllPfdClkout(g_scgAuxPllConfig.pfdClkout, 15U);
1352  * endcode
1353  *
1354  * param pfdClkout  APLL PFD clock out select.
1355  * param fracValue  Fractional Divider value. Recommended to be kept between 12-35 for all PFDs.
1356  */
CLOCK_EnableAuxPllPfdClkout(scg_apll_pfd_clkout_t pfdClkout,uint8_t fracValue)1357 void CLOCK_EnableAuxPllPfdClkout(scg_apll_pfd_clkout_t pfdClkout, uint8_t fracValue)
1358 {
1359     /*
1360      * Input fractional divider value should have a maximum size of 6 bits (64U).
1361      * Note: It is recommended that PFD settings are kept between 12-35 for all PFDs.
1362      */
1363     assert(fracValue);
1364     assert(fracValue < SCG_APLLPFD_PFD_MAX_VAL);
1365 
1366     /* Step 1. Ungate PFD clock. */
1367     SCG->APLLPFD &= ~SCG_PLLPFD_PFD_CLKGATE_MASK(pfdClkout);
1368 
1369     /* Step 2. Program the new PFD value. */
1370     SCG->APLLPFD = (SCG->APLLPFD & ~SCG_PLLPFD_PFD_MASK(pfdClkout)) | SCG_PLLPFD_PFD_VAL(pfdClkout, fracValue);
1371 
1372     /* Step 3. Wait for PFD clock to be stable. */
1373     while (0UL == (SCG->APLLPFD & SCG_PLLPFD_PFD_VALID_MASK(pfdClkout)))
1374     {
1375     }
1376 }
1377 
1378 /*!
1379  * brief Initializes the SCG system PLL.
1380  *
1381  * This function enables the SCG system PLL clock according to the
1382  * configuration. The system PLL can use the system OSC or FIRC as
1383  * the clock source. Ensure that the source clock is valid before
1384  * calling this function.
1385  *
1386  * Example code for initializing SPLL clock output:
1387  * code
1388  * const scg_spll_config_t g_scgSysPllConfig = {.enableMode = kSCG_SysPllEnable,
1389  *                                              .div1 = kSCG_AsyncClkDivBy1,
1390  *                                              .div2 = kSCG_AsyncClkDisable,
1391  *                                              .div3 = kSCG_AsyncClkDivBy2,
1392  *                                              .src = kSCG_SysPllSrcFirc,
1393  *                                              .isPfdSelected = false,
1394  *                                              .prediv = 0U,
1395  *                                              .pfdClkout = kSCG_SysPllPfd0Clk,
1396  *                                              .mult = 3U};
1397  * CLOCK_InitSysPll(&g_scgSysPllConfig);
1398  * endcode
1399  *
1400  * param config   Pointer to the configuration structure.
1401  * retval kStatus_Success System PLL is initialized.
1402  * retval kStatus_SCG_Busy System PLL has been enabled and is used by the system clock.
1403  * retval kStatus_ReadOnly System PLL control register is locked.
1404  *
1405  * note This function can't detect whether the system PLL has been enabled and
1406  * used by an IP.
1407  */
CLOCK_InitSysPll(const scg_spll_config_t * config)1408 status_t CLOCK_InitSysPll(const scg_spll_config_t *config)
1409 {
1410     assert(config);
1411     assert(config->mult < 7U);
1412 
1413     status_t status;
1414 
1415     /* De-init the SPLL first. */
1416     status = CLOCK_DeinitSysPll();
1417 
1418     if (kStatus_Success != status)
1419     {
1420         return status;
1421     }
1422 
1423     /* Now start to set up PLL clock. */
1424     /* Step 1. Setup dividers. */
1425     SCG->SPLLDIV =
1426         SCG_SPLLDIV_SPLLDIV1(config->div1) | SCG_SPLLDIV_SPLLDIV2(config->div2) | SCG_SPLLDIV_SPLLDIV3(config->div3);
1427 
1428     /* Step 2. Set PLL configuration. */
1429     SCG->SPLLCFG = SCG_SPLLCFG_SOURCE(config->src) | SCG_SPLLCFG_PREDIV(config->prediv) |
1430                    SCG_SPLLCFG_MULT(config->mult) | SCG_SPLLCFG_PLLS(config->isPfdSelected) |
1431                    SCG_SPLLCFG_PFDSEL(((uint32_t)config->pfdClkout >> 3U));
1432 
1433     /* Step 3. Enable clock. */
1434     SCG->SPLLCSR = (uint32_t)SCG_SPLLCSR_SPLLEN_MASK | config->enableMode;
1435 
1436     /* Step 4. Wait for PLL clock to be valid. */
1437     while (0UL == (SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK))
1438     {
1439     }
1440 
1441     return kStatus_Success;
1442 }
1443 
1444 /*!
1445  * brief De-initializes the SCG system PLL.
1446  *
1447  * This function disables the SCG system PLL.
1448  *
1449  * retval kStatus_Success system PLL is deinitialized.
1450  * retval kStatus_SCG_Busy system PLL is used by the system clock.
1451  * retval kStatus_ReadOnly System PLL control register is locked.
1452  *
1453  * note This function can't detect whether the system PLL is used by an IP.
1454  */
CLOCK_DeinitSysPll(void)1455 status_t CLOCK_DeinitSysPll(void)
1456 {
1457     uint32_t reg = SCG->SPLLCSR;
1458     status_t status;
1459 
1460     /* If clock is used by system, return error. */
1461     if ((reg & SCG_SPLLCSR_SPLLSEL_MASK) != 0UL)
1462     {
1463         status = kStatus_SCG_Busy;
1464     }
1465     /* If configure register is locked, return error. */
1466     else if ((reg & SCG_SPLLCSR_LK_MASK) != 0UL)
1467     {
1468         status = kStatus_ReadOnly;
1469     }
1470     else
1471     {
1472         /* Deinit and clear the error. */
1473         SCG->SPLLCSR = SCG_SPLLCSR_SPLLERR_MASK;
1474         status       = kStatus_Success;
1475     }
1476 
1477     return status;
1478 }
1479 
CLOCK_GetSysPllCommonFreq(void)1480 static uint32_t CLOCK_GetSysPllCommonFreq(void)
1481 {
1482     uint32_t freq = 0U;
1483 
1484     if ((SCG->SPLLCFG & SCG_SPLLCFG_SOURCE_MASK) != 0UL) /* If use FIRC */
1485     {
1486         freq = CLOCK_GetFircFreq();
1487     }
1488     else /* Use System OSC. */
1489     {
1490         freq = CLOCK_GetSysOscFreq();
1491     }
1492 
1493     if (freq != 0UL) /* If source is valid. */
1494     {
1495         freq /= (SCG_SPLLCFG_PREDIV_VAL + SCG_SPLL_PREDIV_BASE_VALUE); /* Pre-divider. */
1496         freq *= s_spllMulti[SCG_SPLLCFG_MULT_VAL];                     /* Multiplier. */
1497     }
1498 
1499     return freq;
1500 }
1501 
1502 /*!
1503  * brief Gets the SCG system PLL clock frequency.
1504  *
1505  * return  Clock frequency; If the clock is invalid, returns 0.
1506  */
CLOCK_GetSysPllFreq(void)1507 uint32_t CLOCK_GetSysPllFreq(void)
1508 {
1509     uint32_t freq;
1510     scg_spll_pfd_clkout_t pfdClkout;
1511 
1512     if ((SCG->SPLLCFG & SCG_SPLLCFG_PLLS_MASK) != 0UL)
1513     {
1514         /* pfdClkout is SCG_SPLLCFG[PFDSEL] x 8. */
1515         pfdClkout = (scg_spll_pfd_clkout_t)(uint32_t)(
1516             ((SCG->SPLLCFG & SCG_SPLLCFG_PFDSEL_MASK) >> SCG_SPLLCFG_PFDSEL_SHIFT) << 3U);
1517         freq = CLOCK_GetSysPllPfdFreq(pfdClkout);
1518     }
1519     else
1520     {
1521         if ((SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK) != 0UL) /* System PLL is valid. */
1522         {
1523             freq = CLOCK_GetSysPllCommonFreq();
1524 
1525             return freq;
1526         }
1527         else
1528         {
1529             return 0U;
1530         }
1531     }
1532 
1533     return freq;
1534 }
1535 
1536 /*!
1537  * brief Gets the SCG asynchronous clock frequency from the system PLL.
1538  *
1539  * param type     The asynchronous clock type.
1540  * return  Clock frequency; If the clock is invalid, returns 0.
1541  */
CLOCK_GetSysPllAsyncFreq(scg_async_clk_t type)1542 uint32_t CLOCK_GetSysPllAsyncFreq(scg_async_clk_t type)
1543 {
1544     uint32_t pllFreq = CLOCK_GetSysPllFreq();
1545     uint32_t divider = 0U;
1546     uint32_t freq;
1547 
1548     /* Get divider. */
1549     if (pllFreq != 0UL)
1550     {
1551         switch (type)
1552         {
1553             case kSCG_AsyncDiv3Clk: /* SPLLDIV3_CLK. */
1554                 divider = SCG_SPLLDIV_SPLLDIV3_VAL;
1555                 break;
1556             case kSCG_AsyncDiv2Clk: /* SPLLDIV2_CLK. */
1557                 divider = SCG_SPLLDIV_SPLLDIV2_VAL;
1558                 break;
1559             case kSCG_AsyncDiv1Clk: /* SPLLDIV1_CLK. */
1560                 divider = SCG_SPLLDIV_SPLLDIV1_VAL;
1561                 break;
1562             default:
1563                 divider = 0U;
1564                 break;
1565         }
1566     }
1567     if (divider != 0UL)
1568     {
1569         freq = pllFreq >> (divider - 1U);
1570     }
1571     else /* Output disabled. */
1572     {
1573         freq = 0U;
1574     }
1575 
1576     return freq;
1577 }
1578 
1579 /*!
1580  * brief Gets the SCG system PLL PFD clock frequency.
1581  *
1582  * param pfdClkout     The selected PFD clock out. See "scg_spll_pfd_clkout_t".
1583  * return  Clock frequency; If the clock is invalid, returns 0.
1584  */
CLOCK_GetSysPllPfdFreq(scg_spll_pfd_clkout_t pfdClkout)1585 uint32_t CLOCK_GetSysPllPfdFreq(scg_spll_pfd_clkout_t pfdClkout)
1586 {
1587     uint32_t freq      = 0U;
1588     uint32_t fracValue = 0U;
1589 
1590     if ((SCG->SPLLPFD & SCG_PLLPFD_PFD_VALID_MASK(pfdClkout)) != 0UL) /* System PLL PFD is valid. */
1591     {
1592         if (0UL == (SCG->SPLLPFD & SCG_PLLPFD_PFD_CLKGATE_MASK(pfdClkout)))
1593         {
1594             fracValue = (SCG->SPLLPFD & SCG_PLLPFD_PFD_MASK(pfdClkout)) >> (uint32_t)pfdClkout;
1595 
1596             if (fracValue != 0UL)
1597             {
1598                 freq = CLOCK_GetSysPllCommonFreq();
1599 
1600                 if (freq != 0UL) /* If source is valid. */
1601                 {
1602                     freq = (uint32_t)((uint64_t)freq * PFD_FREQ_CALCUL_CONSTANT /
1603                                       fracValue); /* PFD Clock Frequency = PLL output frequency * 18 / frac value. */
1604                 }
1605             }
1606         }
1607         else
1608         {
1609             freq = 0U;
1610         }
1611 
1612         return freq;
1613     }
1614     else
1615     {
1616         return 0U;
1617     }
1618 }
1619 
1620 /*!
1621  * brief Enables the SCG system PLL Fractional Divide (PFD) clock out with configurations.
1622  *
1623  * SPLL Frequency = Fref * (MULT + NUM/DENOM)
1624  * PFD Clock Frequency = PLL output frequency * 18/frac value
1625  *
1626  * code
1627  * Example code for configuring SPLL as SPLL PFD clock output:
1628  * const scg_spll_config_t g_scgSysPllConfig = {.enableMode = kSCG_SysPllEnable,
1629  *                                            .div1 = kSCG_AsyncClkDisable,
1630  *                                            .div2 = kSCG_AsyncClkDisable,
1631  *                                            .div3 = kSCG_AsyncClkDisable,
1632  *                                            .src = kSCG_SysPllSrcFirc,
1633  *                                            .isPfdSelected = true,
1634  *                                            .prediv = 5U,
1635  *                                            .pfdClkout = kSCG_AuxPllPfd3Clk,
1636  *                                            .mult = 20U};
1637  * CLOCK_InitSysPll(&g_scgSysPllConfig);
1638  * CLOCK_EnableSysPllPfdClkout(g_scgSysPllConfig.pfdClkout, 15U);
1639  * endcode
1640  *
1641  * param pfdClkout  SPLL PFD clock out select.
1642  * param fracValue  Fractional Divider value. Recommended to be kept between 12-35 for all PFDs.
1643  */
CLOCK_EnableSysPllPfdClkout(scg_spll_pfd_clkout_t pfdClkout,uint8_t fracValue)1644 void CLOCK_EnableSysPllPfdClkout(scg_spll_pfd_clkout_t pfdClkout, uint8_t fracValue)
1645 {
1646     /*
1647      * Input fractional divider value should have a maximum size of 6 bits (64U).
1648      * Note: It is recommended that PFD settings are kept between 12-35 for all PFDs.
1649      */
1650     assert(fracValue);
1651     assert(fracValue < SCG_SPLLPFD_PFD_MAX_VAL);
1652 
1653     /* Step 1. Ungate PFD clock. */
1654     SCG->SPLLPFD &= ~SCG_PLLPFD_PFD_CLKGATE_MASK(pfdClkout);
1655 
1656     /* Step 2. Program the new PFD value. */
1657     SCG->SPLLPFD = (SCG->SPLLPFD & ~SCG_PLLPFD_PFD_MASK(pfdClkout)) | SCG_PLLPFD_PFD_VAL(pfdClkout, fracValue);
1658 
1659     /* Step 3. Wait for PFD clock to be stable. */
1660     while (0UL == (SCG->SPLLPFD & SCG_PLLPFD_PFD_VALID_MASK(pfdClkout)))
1661     {
1662     }
1663 }
1664