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