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_ICSFixedFreqClk:
297 freq = CLOCK_GetICSFixedFreqClkFreq();
298 break;
299 case kCLOCK_ICSFllClk:
300 freq = CLOCK_GetFllFreq();
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->SOPT0 |= SIM_SOPT0_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 /*Note: When mode switching from FEE, FBE, to FEI, it is suggested to wait IREFST switch
583 * completion, then change ICS_C1[CLKS].
584 */
585
586 /* Set IREFS. */
587 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_IREFS_MASK)) | ICS_C1_IREFS(kICS_FllSrcInternal)); /* IREFS = 1 */
588
589 /* Set CLKS */
590 ICS->C1 = (uint8_t)((ICS->C1 & (~ICS_C1_CLKS_MASK)) | ICS_C1_CLKS(kICS_ClkOutSrcFll)); /* CLKS = 0 */
591 /* set bus clock divider */
592 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv));
593
594 /* Wait and check status. */
595 while ((uint8_t)kICS_FllSrcInternal != ICS_S_IREFST_VAL)
596 {
597 }
598
599 /* Check ICS_S[CLKST] */
600 while ((uint8_t)kICS_ClkOutStatFll != ICS_S_CLKST_VAL)
601 {
602 }
603
604 /* wait for FLL to lock */
605 while (0U == (ICS->S & ICS_S_LOCK_MASK))
606 {
607 }
608
609 /* clear Loss of lock sticky bit */
610 ICS->S |= ICS_S_LOLS_MASK;
611
612 return kStatus_Success;
613 }
614
615 /*!
616 * brief Sets the ICS to FEE mode.
617 *
618 * This function sets the ICS to FEE mode. If setting to FEE mode fails
619 * from the current mode, this function returns an error.
620 *
621 * param bDiv bus clock divider
622 * param rdiv FLL reference clock divider setting, RDIV.
623 *
624 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
625 * retval kStatus_Success Switched to the target mode successfully.
626 */
CLOCK_SetFeeMode(uint8_t bDiv,uint8_t rDiv)627 status_t CLOCK_SetFeeMode(uint8_t bDiv, uint8_t rDiv)
628 {
629 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
630 ics_mode_t mode = CLOCK_GetMode();
631 if (!((kICS_ModeFEE == mode) || (kICS_ModeFBI == mode) || (kICS_ModeFBE == mode) || (kICS_ModeFEI == mode)))
632 {
633 return kStatus_ICS_ModeUnreachable;
634 }
635 #endif
636
637 /* Set CLKS, rDiv and IREFS. */
638 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_CLKS_MASK | ICS_C1_RDIV_MASK | ICS_C1_IREFS_MASK)) |
639 (ICS_C1_CLKS(kICS_ClkOutSrcFll) /* CLKS = 0 */
640 | ICS_C1_RDIV(rDiv) /* FRDIV */
641 | ICS_C1_IREFS(kICS_FllSrcExternal))); /* IREFS = 0 */
642 /* set bus clock divider */
643 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv));
644
645 /* If use external crystal as clock source, wait for it stable. */
646 {
647 if ((OSC0->CR & OSC_CR_OSCOS_MASK) != 0U)
648 {
649 while (0U == (OSC0->CR & OSC_CR_OSCINIT_MASK))
650 {
651 }
652 }
653 }
654
655 /* Wait and check status. */
656 while ((uint8_t)kICS_FllSrcExternal != ICS_S_IREFST_VAL)
657 {
658 }
659
660 /* Check ICS_S[CLKST] */
661 while ((uint8_t)kICS_ClkOutStatFll != ICS_S_CLKST_VAL)
662 {
663 }
664
665 /* wait for FLL to lock */
666 while (0U == (ICS->S & ICS_S_LOCK_MASK))
667 {
668 }
669
670 /* clear Loss of lock sticky bit */
671 ICS->S |= ICS_S_LOLS_MASK;
672
673 return kStatus_Success;
674 }
675
676 /*!
677 * brief Sets the ICS to FBI mode.
678 *
679 * This function sets the ICS to FBI mode. If setting to FBI mode fails
680 * from the current mode, this function returns an error.
681 *
682 * param bDiv bus clock divider
683
684 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
685 * retval kStatus_Success Switched to the target mode successfully.
686 */
CLOCK_SetFbiMode(uint8_t bDiv)687 status_t CLOCK_SetFbiMode(uint8_t bDiv)
688 {
689 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
690 ics_mode_t mode = CLOCK_GetMode();
691
692 if (!((kICS_ModeFEE == mode) || (kICS_ModeFBI == mode) || (kICS_ModeFBE == mode) || (kICS_ModeFEI == mode) ||
693 (kICS_ModeBILP == mode)))
694
695 {
696 return kStatus_ICS_ModeUnreachable;
697 }
698 #endif
699
700 /* set bus clock divider and disable low power */
701 ICS->C2 = (uint8_t)((ICS->C2 & (~(ICS_C2_BDIV_MASK | ICS_C2_LP_MASK))) | ICS_C2_BDIV(bDiv));
702 /* Set CLKS and IREFS. */
703 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_CLKS_MASK | ICS_C1_IREFS_MASK)) |
704 (ICS_C1_CLKS(kICS_ClkOutSrcInternal) /* CLKS = 1 */
705 | ICS_C1_IREFS(kICS_FllSrcInternal))); /* IREFS = 1 */
706
707 /* Wait and check status. */
708 while ((uint8_t)kICS_FllSrcInternal != ICS_S_IREFST_VAL)
709 {
710 }
711
712 while ((uint8_t)kICS_ClkOutStatInt != ICS_S_CLKST_VAL)
713 {
714 }
715
716 /* clear Loss of lock sticky bit */
717 ICS->S |= ICS_S_LOLS_MASK;
718
719 return kStatus_Success;
720 }
721
722 /*!
723 * brief Sets the ICS to FBE mode.
724 *
725 * This function sets the ICS to FBE mode. If setting to FBE mode fails
726 * from the current mode, this function returns an error.
727 *
728 * param bDiv bus clock divider
729 * param rdiv FLL reference clock divider setting, RDIV.
730 *
731 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
732 * retval kStatus_Success Switched to the target mode successfully.
733 */
CLOCK_SetFbeMode(uint8_t bDiv,uint8_t rDiv)734 status_t CLOCK_SetFbeMode(uint8_t bDiv, uint8_t rDiv)
735 {
736 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
737 ics_mode_t mode = CLOCK_GetMode();
738 if (!((kICS_ModeFEE == mode) || (kICS_ModeFBI == mode) || (kICS_ModeFBE == mode) || (kICS_ModeFEI == mode) ||
739 (kICS_ModeBELP == mode)))
740 {
741 return kStatus_ICS_ModeUnreachable;
742 }
743 #endif
744
745 /* set bus clock divider and disable low power */
746 ICS->C2 = (uint8_t)((ICS->C2 & (~(ICS_C2_BDIV_MASK | ICS_C2_LP_MASK))) | ICS_C2_BDIV(bDiv));
747
748 /* Set CLKS and IREFS. */
749 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_CLKS_MASK | ICS_C1_RDIV_MASK | ICS_C1_IREFS_MASK)) |
750 (ICS_C1_CLKS(kICS_ClkOutSrcExternal) /* CLKS = 2 */
751 | ICS_C1_RDIV(rDiv) /* FRDIV = frDiv */
752 | ICS_C1_IREFS(kICS_FllSrcExternal))); /* IREFS = 0 */
753
754 /* If use external crystal as clock source, wait for it stable. */
755 {
756 if ((OSC0->CR & OSC_CR_OSCOS_MASK) != 0U)
757 {
758 while (0U == (OSC0->CR & OSC_CR_OSCINIT_MASK))
759 {
760 }
761 }
762 }
763
764 /* Wait for Reference clock Status bit to clear */
765 while ((uint8_t)kICS_FllSrcExternal != ICS_S_IREFST_VAL)
766 {
767 }
768
769 /* Wait for clock status bits to show clock source is ext ref clk */
770 while ((uint8_t)kICS_ClkOutStatExt != ICS_S_CLKST_VAL)
771 {
772 }
773
774 /* clear Loss of lock sticky bit */
775 ICS->S |= ICS_S_LOLS_MASK;
776
777 return kStatus_Success;
778 }
779
780 /*!
781 * brief Sets the ICS to BILP mode.
782 *
783 * This function sets the ICS to BILP mode. If setting to BILP mode fails
784 * from the current mode, this function returns an error.
785 *
786 * param bDiv bus clock divider
787 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
788 * retval kStatus_Success Switched to the target mode successfully.
789 */
CLOCK_SetBilpMode(uint8_t bDiv)790 status_t CLOCK_SetBilpMode(uint8_t bDiv)
791 {
792 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
793 if (ICS_S_CLKST_VAL != kICS_ClkOutStatInt)
794 {
795 return kStatus_ICS_ModeUnreachable;
796 }
797 #endif /* ICS_CONFIG_CHECK_PARAM */
798
799 /* set bus clock divider and enable low power */
800 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv) | ICS_C2_LP_MASK);
801
802 return kStatus_Success;
803 }
804
805 /*!
806 * brief Sets the ICS to BELP mode.
807 *
808 * This function sets the ICS to BELP mode. If setting to BELP mode fails
809 * from the current mode, this function returns an error.
810 *
811 * param bDiv bus clock divider
812 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
813 * retval kStatus_Success Switched to the target mode successfully.
814 */
CLOCK_SetBelpMode(uint8_t bDiv)815 status_t CLOCK_SetBelpMode(uint8_t bDiv)
816 {
817 #if (defined(ICS_CONFIG_CHECK_PARAM) && ICS_CONFIG_CHECK_PARAM)
818 if (ICS_S_CLKST_VAL != kICS_ClkOutStatExt)
819 {
820 return kStatus_ICS_ModeUnreachable;
821 }
822 #endif
823
824 /* set bus clock divider and enable low power */
825 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv) | ICS_C2_LP_MASK);
826
827 return kStatus_Success;
828 }
829
830 /*!
831 * brief Sets the ICS to FEI mode during system boot up.
832 *
833 * This function sets the ICS to FEI mode from the reset mode. It can also be used to
834 * set up ICS during system boot up.
835 *
836 * param bDiv bus clock divider.
837 *
838 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
839 * retval kStatus_Success Switched to the target mode successfully.
840 */
CLOCK_BootToFeiMode(uint8_t bDiv)841 status_t CLOCK_BootToFeiMode(uint8_t bDiv)
842 {
843 return CLOCK_SetFeiMode(bDiv);
844 }
845
846 /*!
847 * brief Sets the ICS to FEE mode during system bootup.
848 *
849 * This function sets ICS to FEE mode from the reset mode. It can also be used to
850 * set up the ICS during system boot up.
851 *
852 * param bDiv bus clock divider.
853 * param rdiv FLL reference clock divider setting, RDIV.
854 *
855 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
856 * retval kStatus_Success Switched to the target mode successfully.
857 */
CLOCK_BootToFeeMode(uint8_t bDiv,uint8_t rDiv)858 status_t CLOCK_BootToFeeMode(uint8_t bDiv, uint8_t rDiv)
859 {
860 return CLOCK_SetFeeMode(bDiv, rDiv);
861 }
862
863 /*!
864 * brief Sets the ICS to BILP mode during system boot up.
865 *
866 * This function sets the ICS to BILP mode from the reset mode. It can also be used to
867 * set up the ICS during system boot up.
868 *
869 * param bDiv bus clock divider.
870 * retval kStatus_ICS_SourceUsed Could not change ICSIRCLK setting.
871 * retval kStatus_Success Switched to the target mode successfully.
872 */
CLOCK_BootToBilpMode(uint8_t bDiv)873 status_t CLOCK_BootToBilpMode(uint8_t bDiv)
874 {
875 /* If reset mode is not BILP, first enter FBI mode. */
876 ICS->C1 = (uint8_t)((ICS->C1 & ~ICS_C1_CLKS_MASK) | ICS_C1_CLKS(kICS_ClkOutSrcInternal));
877 while (ICS_S_CLKST_VAL != (uint8_t)kICS_ClkOutStatInt)
878 {
879 }
880
881 /* set bus clock divider and enable low power */
882 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv) | ICS_C2_LP_MASK);
883
884 return kStatus_Success;
885 }
886
887 /*!
888 * brief Sets the ICS to BELP mode during system boot up.
889 *
890 * This function sets the ICS to BELP mode from the reset mode. It can also be used to
891 * set up the ICS during system boot up.
892 *
893 * param bDiv bus clock divider.
894 *
895 * retval kStatus_ICS_ModeUnreachable Could not switch to the target mode.
896 * retval kStatus_Success Switched to the target mode successfully.
897 */
CLOCK_BootToBelpMode(uint8_t bDiv)898 status_t CLOCK_BootToBelpMode(uint8_t bDiv)
899 {
900 /* Set to FBE mode. */
901 ICS->C1 = (uint8_t)((ICS->C1 & ~(ICS_C1_CLKS_MASK | ICS_C1_IREFS_MASK)) |
902 (ICS_C1_CLKS(kICS_ClkOutSrcExternal) /* CLKS = 2 */
903 | ICS_C1_IREFS(kICS_FllSrcExternal))); /* IREFS = 0 */
904 /* If use external crystal as clock source, wait for it stable. */
905 {
906 if ((OSC0->CR & OSC_CR_OSCOS_MASK) != 0U)
907 {
908 while (0U == (OSC0->CR & OSC_CR_OSCINIT_MASK))
909 {
910 }
911 }
912 }
913
914 /* Wait for ICS_S[CLKST] and ICS_S[IREFST]. */
915 while ((ICS->S & (ICS_S_IREFST_MASK | ICS_S_CLKST_MASK)) !=
916 (ICS_S_IREFST(kICS_FllSrcExternal) | ICS_S_CLKST(kICS_ClkOutStatExt)))
917 {
918 }
919
920 /* set bus clock divider and enable low power */
921 ICS->C2 = (uint8_t)((ICS->C2 & (~ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(bDiv) | ICS_C2_LP_MASK);
922
923 return kStatus_Success;
924 }
925
926 /*
927 The transaction matrix. It defines the path for mode switch, the row is for
928 current mode and the column is target mode.
929 For example, switch from FEI to BELP:
930 1. Current mode FEI, next mode is ICSModeMatrix[FEI][BELP] = FBE, so swith to FBE.
931 2. Current mode FBE, next mode is ICSModeMatrix[FBE][BELP] = BELP, so swith to BELP.
932 Thus the ICS mode has changed from FEI to BELP.
933 */
934 static const ics_mode_t ICSModeMatrix[6][6] = {
935 {kICS_ModeFEI, kICS_ModeFBI, kICS_ModeFBI, kICS_ModeFEE, kICS_ModeFBE, kICS_ModeFBE}, /* FEI */
936 {kICS_ModeFEI, kICS_ModeFBI, kICS_ModeBILP, kICS_ModeFEE, kICS_ModeFBE, kICS_ModeFBE}, /* FBI */
937 {kICS_ModeFBI, kICS_ModeFBI, kICS_ModeBILP, kICS_ModeFBI, kICS_ModeFBI, kICS_ModeFBI}, /* BILP */
938 {kICS_ModeFEI, kICS_ModeFBI, kICS_ModeFBI, kICS_ModeFEE, kICS_ModeFBE, kICS_ModeFBE}, /* FEE */
939 {kICS_ModeFEI, kICS_ModeFBI, kICS_ModeFBI, kICS_ModeFEE, kICS_ModeFBE, kICS_ModeBELP}, /* FBE */
940 {kICS_ModeFBE, kICS_ModeFBE, kICS_ModeFBE, kICS_ModeFBE, kICS_ModeFBE, kICS_ModeBELP}, /* BELP */
941 /* FEI FBI BILP FEE FBE BELP */
942 };
943
944 /*!
945 * brief Sets the ICS to a target mode.
946 *
947 * This function sets ICS to a target mode defined by the configuration
948 * structure. If switching to the target mode fails, this function
949 * chooses the correct path.
950 *
951 * param config Pointer to the target ICS mode configuration structure.
952 * return Return kStatus_Success if switched successfully; Otherwise, it returns an error code #_ICS_status.
953 *
954 * note If the external clock is used in the target mode, ensure that it is
955 * enabled. For example, if the OSC0 is used, set up OSC0 correctly before calling this
956 * function.
957 */
CLOCK_SetIcsConfig(const ics_config_t * config)958 status_t CLOCK_SetIcsConfig(const ics_config_t *config)
959 {
960 ics_mode_t next_mode;
961 status_t status = kStatus_Success;
962
963 /* Configure ICSIRCLK. */
964 CLOCK_SetInternalRefClkConfig(config->irClkEnableMode);
965
966 next_mode = CLOCK_GetMode();
967
968 do
969 {
970 next_mode = ICSModeMatrix[next_mode][config->icsMode];
971
972 switch (next_mode)
973 {
974 case kICS_ModeFEI:
975 status = CLOCK_SetFeiMode(config->bDiv);
976 break;
977 case kICS_ModeFEE:
978 status = CLOCK_SetFeeMode(config->bDiv, config->rDiv);
979 break;
980 case kICS_ModeFBI:
981 status = CLOCK_SetFbiMode(config->bDiv);
982 break;
983 case kICS_ModeFBE:
984 status = CLOCK_SetFbeMode(config->bDiv, config->rDiv);
985 break;
986 case kICS_ModeBILP:
987 status = CLOCK_SetBilpMode(config->bDiv);
988 break;
989 case kICS_ModeBELP:
990 status = CLOCK_SetBelpMode(config->bDiv);
991 break;
992 default:
993 status = kStatus_Success;
994 break;
995 }
996 if (kStatus_Success != status)
997 {
998 return status;
999 }
1000 } while (next_mode != config->icsMode);
1001
1002 return kStatus_Success;
1003 }
1004