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