1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016 - 2019 , NXP
4 * All rights reserved.
5 *
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 */
9
10 #include "fsl_clock.h"
11
12 /*******************************************************************************
13 * Definitions
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 ICS_C2_BDIV_VAL ((ICS->C2 & ICS_C2_BDIV_MASK) >> ICS_C2_BDIV_SHIFT)
21 #define ICS_S_CLKST_VAL ((ICS->S & ICS_S_CLKST_MASK) >> ICS_S_CLKST_SHIFT)
22 #define ICS_S_IREFST_VAL ((ICS->S & ICS_S_IREFST_MASK) >> ICS_S_IREFST_SHIFT)
23 #define ICS_C1_RDIV_VAL ((ICS->C1 & ICS_C1_RDIV_MASK) >> ICS_C1_RDIV_SHIFT)
24 #define OSC_CR_RANGE_VAL ((OSC0->CR & OSC_CR_RANGE_MASK) >> OSC_CR_RANGE_SHIFT)
25 #define OSC_MODE_MASK \
26 (OSC_CR_OSCOS_MASK | OSC_CR_HGO_MASK | OSC_CR_RANGE_MASK | OSC_CR_OSCEN_MASK | OSC_CR_OSCSTEN_MASK)
27 #define ICS_C2_LP_VAL ((ICS->C2 & ICS_C2_LP_MASK) >> ICS_C2_LP_SHIFT)
28 #define SIM_CLKDIV_OUTDIV1_VAL ((SIM->CLKDIV & SIM_CLKDIV_OUTDIV1_MASK) >> SIM_CLKDIV_OUTDIV1_SHIFT)
29 #define SIM_CLKDIV_OUTDIV2_VAL ((SIM->CLKDIV & SIM_CLKDIV_OUTDIV2_MASK) >> SIM_CLKDIV_OUTDIV2_SHIFT)
30 #define SIM_CLKDIV_OUTDIV3_VAL ((SIM->CLKDIV & SIM_CLKDIV_OUTDIV3_MASK) >> SIM_CLKDIV_OUTDIV3_SHIFT)
31
32 /* ICS_S_CLKST definition. */
33 enum
34 {
35 kICS_ClkOutStatFll, /* FLL. */
36 kICS_ClkOutStatInt, /* Internal clock. */
37 kICS_ClkOutStatExt, /* External clock. */
38 };
39
40 /* ICS fll clock factor. */
41 #define ICS_FLL_CLOCK_FACTOR (1280U)
42
43 /*******************************************************************************
44 * Variables
45 ******************************************************************************/
46
47 /* Slow internal reference clock frequency. */
48 static uint32_t s_slowIrcFreq = 37500U;
49
50 /* External XTAL0 (OSC0) clock frequency. */
51 volatile uint32_t g_xtal0Freq;
52
53 /*******************************************************************************
54 * Prototypes
55 ******************************************************************************/
56
57 /*!
58 * @brief Get the ICS external reference clock frequency.
59 *
60 * Get the current ICS external reference clock frequency in Hz.This is an internal function.
61 *
62 * @return ICS external reference clock frequency in Hz.
63 */
64 static uint32_t CLOCK_GetICSExtClkFreq(void);
65
66 /*!
67 * @brief Get the ICS FLL external reference clock frequency.
68 *
69 * Get the current ICS FLL external reference clock frequency in Hz. It is
70 * the frequency after by ICS_C1[RDIV]. This is an internal function.
71 *
72 * @return ICS FLL external reference clock frequency in Hz.
73 */
74 static uint32_t CLOCK_GetFllExtRefClkFreq(void);
75
76 /*!
77 * @brief Get the ICS FLL reference clock frequency.
78 *
79 * Get the current ICS FLL reference clock frequency in Hz. It is
80 * the frequency select by ICS_C1[IREFS]. This is an internal function.
81 *
82 * @return ICS FLL reference clock frequency in Hz.
83 */
84 static uint32_t CLOCK_GetFllRefClkFreq(void);
85
86 /*!
87 * @brief Calculate the RANGE value base on crystal frequency.
88 *
89 * To setup external crystal oscillator, must set the register bits RANGE
90 * base on the crystal frequency. This function returns the RANGE base on the
91 * input frequency. This is an internal function.
92 *
93 * @param freq Crystal frequency in Hz.
94 * @return The RANGE value.
95 */
96 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
97
98 /*******************************************************************************
99 * Code
100 ******************************************************************************/
101
CLOCK_GetICSExtClkFreq(void)102 static uint32_t CLOCK_GetICSExtClkFreq(void)
103 {
104 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
105 assert(g_xtal0Freq);
106 return g_xtal0Freq;
107 }
108
CLOCK_GetFllExtRefClkFreq(void)109 static uint32_t CLOCK_GetFllExtRefClkFreq(void)
110 {
111 /* FllExtRef = ICSExtRef / FllExtRefDiv */
112 uint8_t rDiv;
113 uint8_t range;
114
115 uint32_t freq = CLOCK_GetICSExtClkFreq();
116
117 if (freq == 0UL)
118 {
119 return freq;
120 }
121 /* get reference clock divider */
122 rDiv = ICS_C1_RDIV_VAL;
123
124 freq >>= rDiv;
125 /* OSC clock range */
126 range = OSC_CR_RANGE_VAL;
127
128 /*
129 When should use divider 32, 64, 128, 256, 512, 1024.
130 */
131 if (((0U != range)))
132 {
133 switch (rDiv)
134 {
135 case 0:
136 case 1:
137 case 2:
138 case 3:
139 case 4:
140 case 5:
141 freq >>= 5u;
142 break;
143 case 6:
144 case 7:
145 break;
146 default:
147 freq = 0u;
148 break;
149 }
150 }
151
152 return freq;
153 }
154
CLOCK_GetFllRefClkFreq(void)155 static uint32_t CLOCK_GetFllRefClkFreq(void)
156 {
157 uint32_t freq;
158
159 /* If use external reference clock. */
160 if ((uint8_t)kICS_FllSrcExternal == ICS_S_IREFST_VAL)
161 {
162 freq = CLOCK_GetFllExtRefClkFreq();
163 }
164 /* If use internal reference clock. */
165 else
166 {
167 freq = s_slowIrcFreq;
168 }
169
170 return freq;
171 }
172
CLOCK_GetOscRangeFromFreq(uint32_t freq)173 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
174 {
175 assert((freq <= 32768U) || (freq >= 4000000U));
176
177 uint8_t range = 0U;
178
179 if (freq <= 32768U)
180 {
181 range = 0U;
182 }
183 /* high freq range 4M-24M */
184 else
185 {
186 range = 1U;
187 }
188
189 return range;
190 }
191
192 /*!
193 * brief Get the OSC0 external reference clock frequency (OSC0ERCLK).
194 *
195 * return Clock frequency in Hz.
196 */
CLOCK_GetOsc0ErClkFreq(void)197 uint32_t CLOCK_GetOsc0ErClkFreq(void)
198 {
199 uint32_t freq;
200
201 if ((OSC0->CR & OSC_CR_OSCEN_MASK) != 0U)
202 {
203 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
204 assert(g_xtal0Freq);
205 freq = g_xtal0Freq;
206 }
207 else
208 {
209 freq = 0U;
210 }
211
212 return freq;
213 }
214
215 /*!
216 * brief Get the flash clock frequency.
217 *
218 * return Clock frequency in Hz.
219 */
CLOCK_GetFlashClkFreq(void)220 uint32_t CLOCK_GetFlashClkFreq(void)
221 {
222 uint32_t freq;
223
224 freq = CLOCK_GetICSOutClkFreq() / (SIM_CLKDIV_OUTDIV1_VAL + 1U);
225 freq /= (SIM_CLKDIV_OUTDIV2_VAL + 1U);
226
227 return freq;
228 }
229
230 /*!
231 * brief Get the bus clock frequency.
232 *
233 * return Clock frequency in Hz.
234 */
CLOCK_GetBusClkFreq(void)235 uint32_t CLOCK_GetBusClkFreq(void)
236 {
237 return CLOCK_GetFlashClkFreq();
238 }
239
240 /*!
241 * brief Get the core clock or system clock frequency.
242 *
243 * return Clock frequency in Hz.
244 */
CLOCK_GetCoreSysClkFreq(void)245 uint32_t CLOCK_GetCoreSysClkFreq(void)
246 {
247 return CLOCK_GetICSOutClkFreq() / (SIM_CLKDIV_OUTDIV1_VAL + 1U);
248 }
249
250 /*!
251 * brief Gets the Timer(FTM/PWT) clock frequency.
252 *
253 * This function gets the Timer clock frequency in Hz based
254 * on the current ICSOUTCLK.
255 *
256 * return The frequency of Timer(FTM/PWT) clock.
257 */
CLOCK_GetTimerClkFreq(void)258 uint32_t CLOCK_GetTimerClkFreq(void)
259 {
260 return CLOCK_GetICSOutClkFreq() / (SIM_CLKDIV_OUTDIV3_VAL + 1U);
261 }
262
263 /*!
264 * brief Gets the clock frequency for a specific clock name.
265 *
266 * This function checks the current clock configurations and then calculates
267 * the clock frequency for a specific clock name defined in clock_name_t.
268 * The ICS must be properly configured before using this function.
269 *
270 * param clockName Clock names defined in clock_name_t
271 * return Clock frequency value in Hertz
272 */
CLOCK_GetFreq(clock_name_t clockName)273 uint32_t CLOCK_GetFreq(clock_name_t clockName)
274 {
275 uint32_t freq;
276
277 switch (clockName)
278 {
279 case kCLOCK_CoreSysClk:
280 case kCLOCK_PlatClk:
281 freq = CLOCK_GetCoreSysClkFreq();
282 break;
283
284 case kCLOCK_BusClk:
285 case kCLOCK_FlashClk:
286 freq = CLOCK_GetFlashClkFreq();
287 break;
288
289 case kCLOCK_Osc0ErClk:
290 freq = CLOCK_GetOsc0ErClkFreq();
291 break;
292
293 case kCLOCK_ICSInternalRefClk:
294 freq = CLOCK_GetInternalRefClkFreq();
295 break;
296 case kCLOCK_ICSFllClk:
297 freq = CLOCK_GetFllFreq();
298 break;
299 case kCLOCK_ICSFixedFreqClk:
300 freq = CLOCK_GetICSFixedFreqClkFreq();
301 break;
302 case kCLOCK_ICSOutClk:
303 freq = CLOCK_GetICSOutClkFreq();
304 break;
305
306 case kCLOCK_TimerClk:
307 freq = CLOCK_GetTimerClkFreq();
308 break;
309
310 case kCLOCK_LpoClk:
311 freq = LPO_CLK_FREQ;
312 break;
313 default:
314 freq = 0U;
315 break;
316 }
317
318 return freq;
319 }
320
321 /*!
322 * brief Set the clock configure in SIM module.
323 *
324 * This function sets system layer clock settings in SIM module.
325 *
326 * param config Pointer to the configure structure.
327 */
CLOCK_SetSimConfig(sim_clock_config_t const * config)328 void CLOCK_SetSimConfig(sim_clock_config_t const *config)
329 {
330 /* config divider */
331 CLOCK_SetOutDiv(config->outDiv1, config->outDiv2, config->outDiv3);
332 /* config bus clock prescaler optional */
333 SIM->SOPT |= SIM_SOPT_BUSREF(config->busClkPrescaler);
334 }
335
336 /*!
337 * brief Gets the ICS output clock (ICSOUTCLK) frequency.
338 *
339 * This function gets the ICS output clock frequency in Hz based on the current ICS
340 * register value.
341 *
342 * return The frequency of ICSOUTCLK.
343 */
CLOCK_GetICSOutClkFreq(void)344 uint32_t CLOCK_GetICSOutClkFreq(void)
345 {
346 uint32_t icsoutclk;
347 uint8_t clkst = ICS_S_CLKST_VAL;
348
349 switch (clkst)
350 {
351 case kICS_ClkOutStatFll:
352 icsoutclk = CLOCK_GetFllFreq();
353 break;
354 case kICS_ClkOutStatInt:
355 icsoutclk = s_slowIrcFreq;
356 break;
357 case kICS_ClkOutStatExt:
358 icsoutclk = CLOCK_GetICSExtClkFreq();
359 break;
360 default:
361 icsoutclk = 0U;
362 break;
363 }
364
365 return (icsoutclk / (1UL << ICS_C2_BDIV_VAL));
366 }
367
368 /*!
369 * brief Gets the ICS FLL clock (ICSFLLCLK) frequency.
370 *
371 * This function gets the ICS FLL clock frequency in Hz based on the current ICS
372 * register value. The FLL is enabled in FEI/FBI/FEE/FBE mode and
373 * disabled in low power state in other modes.
374 *
375 * return The frequency of ICSFLLCLK.
376 */
CLOCK_GetFllFreq(void)377 uint32_t CLOCK_GetFllFreq(void)
378 {
379 uint32_t freq;
380
381 /* If FLL is not enabled currently, then return 0U. */
382 if ((ICS->C2 & ICS_C2_LP_MASK) != 0U)
383 {
384 freq = 0U;
385 }
386 else
387 {
388 /* Get FLL reference clock frequency. */
389 freq = CLOCK_GetFllRefClkFreq() * ICS_FLL_CLOCK_FACTOR;
390 }
391
392 return freq;
393 }
394
395 /*!
396 * brief Gets the ICS internal reference clock (ICSIRCLK) frequency.
397 *
398 * This function gets the ICS internal reference clock frequency in Hz based
399 * on the current ICS register value.
400 *
401 * return The frequency of ICSIRCLK.
402 */
CLOCK_GetInternalRefClkFreq(void)403 uint32_t CLOCK_GetInternalRefClkFreq(void)
404 {
405 uint32_t freq;
406
407 /* If ICSIRCLK is gated. */
408 if ((ICS->C1 & ICS_C1_IRCLKEN_MASK) == 0U)
409 {
410 freq = 0U;
411 }
412 else
413 {
414 freq = s_slowIrcFreq;
415 }
416
417 return freq;
418 }
419
420 /*!
421 * brief Gets the ICS fixed frequency clock (ICSFFCLK) frequency.
422 *
423 * This function gets the ICS fixed frequency clock frequency in Hz based
424 * on the current ICS register value.
425 *
426 * return The frequency of ICSFFCLK.
427 */
CLOCK_GetICSFixedFreqClkFreq(void)428 uint32_t CLOCK_GetICSFixedFreqClkFreq(void)
429 {
430 uint32_t freq = CLOCK_GetFllRefClkFreq();
431 uint32_t ret;
432 uint32_t ICSOUTCLK;
433
434 ICSOUTCLK = CLOCK_GetICSOutClkFreq();
435 /* ICSFFCLK must be no more than ICSOUTCLK/4. */
436 if ((freq != 0UL) && (freq <= (ICSOUTCLK / 4U)))
437 {
438 ret = freq;
439 }
440 else
441 {
442 ret = 0U;
443 }
444
445 return ret;
446 }
447
448 /*!
449 * brief Initializes the OSC0.
450 *
451 * This function initializes the OSC0 according to the board configuration.
452 *
453 * param config Pointer to the OSC0 configuration structure.
454 */
CLOCK_InitOsc0(osc_config_t const * config)455 void CLOCK_InitOsc0(osc_config_t const *config)
456 {
457 uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
458
459 OSC0->CR = ((OSC0->CR & (uint8_t)(~OSC_MODE_MASK)) | (uint8_t)(OSC_CR_RANGE(range)) | ((uint8_t)config->workMode) |
460 ((uint8_t)config->enableMode));
461
462 if (((uint8_t)kOSC_ModeExt != config->workMode) && ((OSC0->CR & OSC_CR_OSCEN_MASK) != 0U))
463 {
464 /* Wait for stable. */
465 while (0U == (OSC0->CR & OSC_CR_OSCINIT_MASK))
466 {
467 }
468 }
469 }
470
471 /*!
472 * brief Deinitializes the OSC0.
473 *
474 * This function deinitializes the OSC0.
475 */
CLOCK_DeinitOsc0(void)476 void CLOCK_DeinitOsc0(void)
477 {
478 OSC0->CR = 0U;
479 }
480
481 /*!
482 * brief Gets the current ICS mode.
483 *
484 * This function checks the ICS registers and determines the current ICS mode.
485 *
486 * return Current ICS mode or error code; See ref ics_mode_t.
487 */
CLOCK_GetMode(void)488 ics_mode_t CLOCK_GetMode(void)
489 {
490 ics_mode_t mode = kICS_ModeError;
491 uint8_t clkst = ICS_S_CLKST_VAL;
492 uint8_t irefst = ICS_S_IREFST_VAL;
493 uint8_t lp = ICS_C2_LP_VAL;
494
495 /*------------------------------------------------------------------
496 Mode and Registers
497 ____________________________________________________________________
498
499 Mode | CLKST | IREFST | LP
500 ____________________________________________________________________
501
502 FEI | 00(FLL) | 1(INT) | X
503 ____________________________________________________________________
504
505 FEE | 00(FLL) | 0(EXT) | X
506 ____________________________________________________________________
507
508 FBE | 10(EXT) | 0(EXT) | 0(NORMAL)
509 ____________________________________________________________________
510
511 FBI | 01(INT) | 1(INT) | 0(NORMAL)
512 ____________________________________________________________________
513
514 FBILP | 01(INT) | 1(INT) | 1(LOW POWER)
515 ____________________________________________________________________
516
517 FBELP | 10(EXT) | 0(EXT) | 1(LOW POWER)
518 ____________________________________________________________________
519
520 ----------------------------------------------------------------------*/
521
522 switch (clkst)
523 {
524 case kICS_ClkOutStatFll:
525 if ((uint8_t)kICS_FllSrcExternal == irefst)
526 {
527 mode = kICS_ModeFEE;
528 }
529 else
530 {
531 mode = kICS_ModeFEI;
532 }
533 break;
534 case kICS_ClkOutStatInt:
535 if (lp != 0U)
536 {
537 mode = kICS_ModeBILP;
538 }
539 else
540 {
541 mode = kICS_ModeFBI;
542 }
543 break;
544 case kICS_ClkOutStatExt:
545 if (lp != 0U)
546 {
547 mode = kICS_ModeBELP;
548 }
549 else
550 {
551 mode = kICS_ModeFBE;
552 }
553 break;
554 default:
555 mode = kICS_ModeError;
556 break;
557 }
558
559 return mode;
560 }
561
562 /*!
563 * brief Sets the ICS to FEI mode.
564 *
565 * This function sets the ICS to FEI mode. If setting to FEI mode fails
566 * from the current mode, this function returns an error.
567 *
568 * param bDiv bus clock divider
569 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
570 * retval kStatus_Success Switched to the target mode successfully.
571 */
CLOCK_SetFeiMode(uint8_t bDiv)572 status_t CLOCK_SetFeiMode(uint8_t bDiv)
573 {
574 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
575 ics_mode_t mode = CLOCK_GetMode();
576 if (!((kICS_ModeFEI == mode) || (kICS_ModeFBI == mode) || (kICS_ModeFBE == mode) || (kICS_ModeFEE == mode)))
577 {
578 return kStatus_ICS_ModeUnreachable;
579 }
580 #endif
581
582 /* Set IREFS. */
583 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_IREFS_MASK)) | ICS_C1_IREFS(kICS_FllSrcInternal)); /* IREFS = 1 */
584
585 /* Set CLKS */
586 ICS->C1 = (uint8_t)((ICS->C1 & (~ICS_C1_CLKS_MASK)) | ICS_C1_CLKS(kICS_ClkOutSrcFll)); /* CLKS = 0 */
587 /* set bus clock divider */
588 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv));
589
590 /* Wait and check status. */
591 while ((uint8_t)kICS_FllSrcInternal != ICS_S_IREFST_VAL)
592 {
593 }
594
595 /* Check ICS_S[CLKST] */
596 while ((uint8_t)kICS_ClkOutStatFll != ICS_S_CLKST_VAL)
597 {
598 }
599
600 /* wait for FLL to lock */
601 while (0U == (ICS->S & ICS_S_LOCK_MASK))
602 {
603 }
604
605 /* clear Loss of lock sticky bit */
606 ICS->S |= ICS_S_LOLS_MASK;
607
608 return kStatus_Success;
609 }
610
611 /*!
612 * brief Sets the ICS to FEE mode.
613 *
614 * This function sets the ICS to FEE mode. If setting to FEE mode fails
615 * from the current mode, this function returns an error.
616 *
617 * param bDiv bus clock divider
618 * param rdiv FLL reference clock divider setting, RDIV.
619 *
620 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
621 * retval kStatus_Success Switched to the target mode successfully.
622 */
CLOCK_SetFeeMode(uint8_t bDiv,uint8_t rDiv)623 status_t CLOCK_SetFeeMode(uint8_t bDiv, uint8_t rDiv)
624 {
625 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
626 ics_mode_t mode = CLOCK_GetMode();
627 if (!((kICS_ModeFEE == mode) || (kICS_ModeFBI == mode) || (kICS_ModeFBE == mode) || (kICS_ModeFEI == mode)))
628 {
629 return kStatus_ICS_ModeUnreachable;
630 }
631 #endif
632
633 /* Set CLKS, rDiv and IREFS. */
634 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_CLKS_MASK | ICS_C1_RDIV_MASK | ICS_C1_IREFS_MASK)) |
635 (ICS_C1_CLKS(kICS_ClkOutSrcFll) /* CLKS = 0 */
636 | ICS_C1_RDIV(rDiv) /* FRDIV */
637 | ICS_C1_IREFS(kICS_FllSrcExternal))); /* IREFS = 0 */
638 /* set bus clock divider */
639 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv));
640
641 /* If use external crystal as clock source, wait for it stable. */
642 {
643 if ((OSC0->CR & OSC_CR_OSCOS_MASK) != 0U)
644 {
645 while (0U == (OSC0->CR & OSC_CR_OSCINIT_MASK))
646 {
647 }
648 }
649 }
650
651 /* Wait and check status. */
652 while ((uint8_t)kICS_FllSrcExternal != ICS_S_IREFST_VAL)
653 {
654 }
655
656 /* Check ICS_S[CLKST] */
657 while ((uint8_t)kICS_ClkOutStatFll != ICS_S_CLKST_VAL)
658 {
659 }
660
661 /* wait for FLL to lock */
662 while (0U == (ICS->S & ICS_S_LOCK_MASK))
663 {
664 }
665
666 /* clear Loss of lock sticky bit */
667 ICS->S |= ICS_S_LOLS_MASK;
668
669 return kStatus_Success;
670 }
671
672 /*!
673 * brief Sets the ICS to FBI mode.
674 *
675 * This function sets the ICS to FBI mode. If setting to FBI mode fails
676 * from the current mode, this function returns an error.
677 *
678 * param bDiv bus clock divider
679 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
680 * retval kStatus_Success Switched to the target mode successfully.
681 */
CLOCK_SetFbiMode(uint8_t bDiv)682 status_t CLOCK_SetFbiMode(uint8_t bDiv)
683 {
684 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
685 ics_mode_t mode = CLOCK_GetMode();
686
687 if (!((kICS_ModeFEE == mode) || (kICS_ModeFBI == mode) || (kICS_ModeFBE == mode) || (kICS_ModeFEI == mode) ||
688 (kICS_ModeBILP == mode)))
689
690 {
691 return kStatus_ICS_ModeUnreachable;
692 }
693 #endif
694
695 /* set bus clock divider and disable low power */
696 ICS->C2 = (uint8_t)((ICS->C2 & (~(ICS_C2_BDIV_MASK | ICS_C2_LP_MASK))) | ICS_C2_BDIV(bDiv));
697 /* Set CLKS and IREFS. */
698 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_CLKS_MASK | ICS_C1_IREFS_MASK)) |
699 (ICS_C1_CLKS(kICS_ClkOutSrcInternal) /* CLKS = 1 */
700 | ICS_C1_IREFS(kICS_FllSrcInternal))); /* IREFS = 1 */
701
702 /* Wait and check status. */
703 while ((uint8_t)kICS_FllSrcInternal != ICS_S_IREFST_VAL)
704 {
705 }
706
707 while ((uint8_t)kICS_ClkOutStatInt != ICS_S_CLKST_VAL)
708 {
709 }
710
711 /* clear Loss of lock sticky bit */
712 ICS->S |= ICS_S_LOLS_MASK;
713
714 return kStatus_Success;
715 }
716
717 /*!
718 * brief Sets the ICS to FBE mode.
719 *
720 * This function sets the ICS to FBE mode. If setting to FBE mode fails
721 * from the current mode, this function returns an error.
722 *
723 * param bDiv bus clock divider
724 * param rdiv FLL reference clock divider setting, RDIV.
725 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
726 * retval kStatus_Success Switched to the target mode successfully.
727 */
CLOCK_SetFbeMode(uint8_t bDiv,uint8_t rDiv)728 status_t CLOCK_SetFbeMode(uint8_t bDiv, uint8_t rDiv)
729 {
730 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
731 ics_mode_t mode = CLOCK_GetMode();
732 if (!((kICS_ModeFEE == mode) || (kICS_ModeFBI == mode) || (kICS_ModeFBE == mode) || (kICS_ModeFEI == mode) ||
733 (kICS_ModeBELP == mode)))
734 {
735 return kStatus_ICS_ModeUnreachable;
736 }
737 #endif
738
739 /* set bus clock divider and disable low power */
740 ICS->C2 = (uint8_t)((ICS->C2 & (~(ICS_C2_BDIV_MASK | ICS_C2_LP_MASK))) | ICS_C2_BDIV(bDiv));
741
742 /* Set CLKS and IREFS. */
743 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_CLKS_MASK | ICS_C1_RDIV_MASK | ICS_C1_IREFS_MASK)) |
744 (ICS_C1_CLKS(kICS_ClkOutSrcExternal) /* CLKS = 2 */
745 | ICS_C1_RDIV(rDiv) /* FRDIV = frDiv */
746 | ICS_C1_IREFS(kICS_FllSrcExternal))); /* IREFS = 0 */
747
748 /* If use external crystal as clock source, wait for it stable. */
749 {
750 if ((OSC0->CR & OSC_CR_OSCOS_MASK) != 0U)
751 {
752 while (0U == (OSC0->CR & OSC_CR_OSCINIT_MASK))
753 {
754 }
755 }
756 }
757
758 /* Wait for Reference clock Status bit to clear */
759 while ((uint8_t)kICS_FllSrcExternal != ICS_S_IREFST_VAL)
760 {
761 }
762
763 /* Wait for clock status bits to show clock source is ext ref clk */
764 while ((uint8_t)kICS_ClkOutStatExt != ICS_S_CLKST_VAL)
765 {
766 }
767
768 /* clear Loss of lock sticky bit */
769 ICS->S |= ICS_S_LOLS_MASK;
770
771 return kStatus_Success;
772 }
773
774 /*!
775 * brief Sets the ICS to BILP mode.
776 *
777 * This function sets the ICS to BILP mode. If setting to BILP mode fails
778 * from the current mode, this function returns an error.
779 *
780 * param bDiv bus clock divider
781 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
782 * retval kStatus_Success Switched to the target mode successfully.
783 */
CLOCK_SetBilpMode(uint8_t bDiv)784 status_t CLOCK_SetBilpMode(uint8_t bDiv)
785 {
786 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
787 if (ICS_S_CLKST_VAL != kICS_ClkOutStatInt)
788 {
789 return kStatus_ICS_ModeUnreachable;
790 }
791 #endif /* ICS_CONFIG_CHECK_PARAM */
792
793 /* set bus clock divider and enable low power */
794 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv) | ICS_C2_LP_MASK);
795
796 return kStatus_Success;
797 }
798
799 /*!
800 * brief Sets the ICS to BELP mode.
801 *
802 * This function sets the ICS to BELP mode. If setting to BELP mode fails
803 * from the current mode, this function returns an error.
804 *
805 * param bDiv bus clock divider
806 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
807 * retval kStatus_Success Switched to the target mode successfully.
808 */
CLOCK_SetBelpMode(uint8_t bDiv)809 status_t CLOCK_SetBelpMode(uint8_t bDiv)
810 {
811 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
812 if (ICS_S_CLKST_VAL != kICS_ClkOutStatExt)
813 {
814 return kStatus_ICS_ModeUnreachable;
815 }
816 #endif
817
818 /* set bus clock divider and enable low power */
819 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv) | ICS_C2_LP_MASK);
820
821 return kStatus_Success;
822 }
823
824 /*!
825 * brief Sets the ICS to FEI mode during system boot up.
826 *
827 * This function sets the ICS to FEI mode from the reset mode. It can also be used to
828 * set up ICS during system boot up.
829 *
830 * param bDiv bus clock divider.
831 *
832 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
833 * retval kStatus_Success Switched to the target mode successfully.
834 */
CLOCK_BootToFeiMode(uint8_t bDiv)835 status_t CLOCK_BootToFeiMode(uint8_t bDiv)
836 {
837 return CLOCK_SetFeiMode(bDiv);
838 }
839
840 /*!
841 * brief Sets the ICS to FEE mode during system bootup.
842 *
843 * This function sets ICS to FEE mode from the reset mode. It can also be used to
844 * set up the ICS during system boot up.
845 *
846 * param bDiv bus clock divider.
847 * param rdiv FLL reference clock divider setting, RDIV.
848 *
849 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
850 * retval kStatus_Success Switched to the target mode successfully.
851 */
CLOCK_BootToFeeMode(uint8_t bDiv,uint8_t rDiv)852 status_t CLOCK_BootToFeeMode(uint8_t bDiv, uint8_t rDiv)
853 {
854 return CLOCK_SetFeeMode(bDiv, rDiv);
855 }
856
857 /*!
858 * brief Sets the ICS to BILP mode during system boot up.
859 *
860 * This function sets the ICS to BILP mode from the reset mode. It can also be used to
861 * set up the ICS during system boot up.
862 *
863 * param bDiv bus clock divider.
864 * retval kStatus_ICS_SourceUsed Could not change ICSIRCLK setting.
865 * retval kStatus_Success Switched to the target mode successfully.
866 */
CLOCK_BootToBilpMode(uint8_t bDiv)867 status_t CLOCK_BootToBilpMode(uint8_t bDiv)
868 {
869 /* If reset mode is not BILP, first enter FBI mode. */
870 ICS->C1 = (uint8_t)((ICS->C1 & ~ICS_C1_CLKS_MASK) | ICS_C1_CLKS(kICS_ClkOutSrcInternal));
871 while (ICS_S_CLKST_VAL != (uint8_t)kICS_ClkOutStatInt)
872 {
873 }
874
875 /* set bus clock divider and enable low power */
876 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv) | ICS_C2_LP_MASK);
877
878 return kStatus_Success;
879 }
880
881 /*!
882 * brief Sets the ICS to BELP mode during system boot up.
883 *
884 * This function sets the ICS to BELP mode from the reset mode. It can also be used to
885 * set up the ICS during system boot up.
886 *
887 * param bDiv bus clock divider.
888 *
889 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
890 * retval kStatus_Success Switched to the target mode successfully.
891 */
CLOCK_BootToBelpMode(uint8_t bDiv)892 status_t CLOCK_BootToBelpMode(uint8_t bDiv)
893 {
894 /* Set to FBE mode. */
895 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_CLKS_MASK | ICS_C1_IREFS_MASK)) |
896 (ICS_C1_CLKS(kICS_ClkOutSrcExternal) /* CLKS = 2 */
897 | ICS_C1_IREFS(kICS_FllSrcExternal))); /* IREFS = 0 */
898
899 /* If use external crystal as clock source, wait for it stable. */
900 {
901 if ((OSC0->CR & OSC_CR_OSCOS_MASK) != 0U)
902 {
903 while (0U == (OSC0->CR & OSC_CR_OSCINIT_MASK))
904 {
905 }
906 }
907 }
908
909 /* Wait for ICS_S[CLKST] and ICS_S[IREFST]. */
910 while ((ICS->S & (ICS_S_IREFST_MASK | ICS_S_CLKST_MASK)) !=
911 (ICS_S_IREFST(kICS_FllSrcExternal) | ICS_S_CLKST(kICS_ClkOutStatExt)))
912 {
913 }
914
915 /* set bus clock divider and enable low power */
916 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv) | ICS_C2_LP_MASK);
917
918 return kStatus_Success;
919 }
920
921 /*
922 The transaction matrix. It defines the path for mode switch, the row is for
923 current mode and the column is target mode.
924 For example, switch from FEI to BELP:
925 1. Current mode FEI, next mode is ICSModeMatrix[FEI][BELP] = FBE, so swith to FBE.
926 2. Current mode FBE, next mode is ICSModeMatrix[FBE][BELP] = BELP, so swith to BELP.
927 Thus the ICS mode has changed from FEI to BELP.
928 */
929 static const ics_mode_t ICSModeMatrix[6][6] = {
930 {kICS_ModeFEI, kICS_ModeFBI, kICS_ModeFBI, kICS_ModeFEE, kICS_ModeFBE, kICS_ModeFBE}, /* FEI */
931 {kICS_ModeFEI, kICS_ModeFBI, kICS_ModeBILP, kICS_ModeFEE, kICS_ModeFBE, kICS_ModeFBE}, /* FBI */
932 {kICS_ModeFBI, kICS_ModeFBI, kICS_ModeBILP, kICS_ModeFBI, kICS_ModeFBI, kICS_ModeFBI}, /* BILP */
933 {kICS_ModeFEI, kICS_ModeFBI, kICS_ModeFBI, kICS_ModeFEE, kICS_ModeFBE, kICS_ModeFBE}, /* FEE */
934 {kICS_ModeFEI, kICS_ModeFBI, kICS_ModeFBI, kICS_ModeFEE, kICS_ModeFBE, kICS_ModeBELP}, /* FBE */
935 {kICS_ModeFBE, kICS_ModeFBE, kICS_ModeFBE, kICS_ModeFBE, kICS_ModeFBE, kICS_ModeBELP}, /* BELP */
936 /* FEI FBI BILP FEE FBE BELP */
937 };
938
939 /*!
940 * brief Sets the ICS to a target mode.
941 *
942 * This function sets ICS to a target mode defined by the configuration
943 * structure. If switching to the target mode fails, this function
944 * chooses the correct path.
945 *
946 * param config Pointer to the target ICS mode configuration structure.
947 * return Return kStatus_Success if switched successfully; Otherwise, it returns an error code #_ICS_status.
948 *
949 * note If the external clock is used in the target mode, ensure that it is
950 * enabled. For example, if the OSC0 is used, set up OSC0 correctly before calling this
951 * function.
952 */
CLOCK_SetIcsConfig(const ics_config_t * config)953 status_t CLOCK_SetIcsConfig(const ics_config_t *config)
954 {
955 ics_mode_t next_mode;
956 status_t status = kStatus_Success;
957
958 /* Configure ICSIRCLK. */
959 CLOCK_SetInternalRefClkConfig(config->irClkEnableMode);
960
961 next_mode = CLOCK_GetMode();
962
963 do
964 {
965 next_mode = ICSModeMatrix[next_mode][config->icsMode];
966
967 switch (next_mode)
968 {
969 case kICS_ModeFEI:
970 status = CLOCK_SetFeiMode(config->bDiv);
971 break;
972 case kICS_ModeFEE:
973 status = CLOCK_SetFeeMode(config->bDiv, config->rDiv);
974 break;
975 case kICS_ModeFBI:
976 status = CLOCK_SetFbiMode(config->bDiv);
977 break;
978 case kICS_ModeFBE:
979 status = CLOCK_SetFbeMode(config->bDiv, config->rDiv);
980 break;
981 case kICS_ModeBILP:
982 status = CLOCK_SetBilpMode(config->bDiv);
983 break;
984 case kICS_ModeBELP:
985 status = CLOCK_SetBelpMode(config->bDiv);
986 break;
987 default:
988 status = kStatus_Success;
989 break;
990 }
991 if (kStatus_Success != status)
992 {
993 return status;
994 }
995 } while (next_mode != config->icsMode);
996
997 return kStatus_Success;
998 }
999