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