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