Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fsl_clock.c Source File

fsl_clock.c

00001 /*
00002  * Copyright (c) 2015, Freescale Semiconductor, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without modification,
00006  * are permitted provided that the following conditions are met:
00007  *
00008  * o Redistributions of source code must retain the above copyright notice, this list
00009  *   of conditions and the following disclaimer.
00010  *
00011  * o Redistributions in binary form must reproduce the above copyright notice, this
00012  *   list of conditions and the following disclaimer in the documentation and/or
00013  *   other materials provided with the distribution.
00014  *
00015  * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
00016  *   contributors may be used to endorse or promote products derived from this
00017  *   software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00020  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00023  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00026  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 #include "fsl_common.h"
00032 #include "fsl_clock.h "
00033 
00034 /*******************************************************************************
00035  * Definitions
00036  ******************************************************************************/
00037 
00038 /* Macro definition remap workaround. */
00039 #if (defined(MCG_C2_EREFS_MASK) && !(defined(MCG_C2_EREFS0_MASK)))
00040 #define MCG_C2_EREFS0_MASK MCG_C2_EREFS_MASK
00041 #endif
00042 #if (defined(MCG_C2_HGO_MASK) && !(defined(MCG_C2_HGO0_MASK)))
00043 #define MCG_C2_HGO0_MASK MCG_C2_HGO_MASK
00044 #endif
00045 #if (defined(MCG_C2_RANGE_MASK) && !(defined(MCG_C2_RANGE0_MASK)))
00046 #define MCG_C2_RANGE0_MASK MCG_C2_RANGE_MASK
00047 #endif
00048 #if (defined(MCG_C6_CME_MASK) && !(defined(MCG_C6_CME0_MASK)))
00049 #define MCG_C6_CME0_MASK MCG_C6_CME_MASK
00050 #endif
00051 
00052 /* PLL fixed multiplier when there is not PRDIV and VDIV. */
00053 #define PLL_FIXED_MULT (375U)
00054 /* Max frequency of the reference clock used for internal clock trim. */
00055 #define TRIM_REF_CLK_MIN (8000000U)
00056 /* Min frequency of the reference clock used for internal clock trim. */
00057 #define TRIM_REF_CLK_MAX (16000000U)
00058 /* Max trim value of fast internal reference clock. */
00059 #define TRIM_FIRC_MAX (5000000U)
00060 /* Min trim value of fast internal reference clock. */
00061 #define TRIM_FIRC_MIN (3000000U)
00062 /* Max trim value of fast internal reference clock. */
00063 #define TRIM_SIRC_MAX (39063U)
00064 /* Min trim value of fast internal reference clock. */
00065 #define TRIM_SIRC_MIN (31250U)
00066 
00067 #define MCG_S_IRCST_VAL ((MCG->S & MCG_S_IRCST_MASK) >> MCG_S_IRCST_SHIFT)
00068 #define MCG_S_CLKST_VAL ((MCG->S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT)
00069 #define MCG_S_IREFST_VAL ((MCG->S & MCG_S_IREFST_MASK) >> MCG_S_IREFST_SHIFT)
00070 #define MCG_S_PLLST_VAL ((MCG->S & MCG_S_PLLST_MASK) >> MCG_S_PLLST_SHIFT)
00071 #define MCG_C1_FRDIV_VAL ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT)
00072 #define MCG_C2_LP_VAL ((MCG->C2 & MCG_C2_LP_MASK) >> MCG_C2_LP_SHIFT)
00073 #define MCG_C2_RANGE_VAL ((MCG->C2 & MCG_C2_RANGE_MASK) >> MCG_C2_RANGE_SHIFT)
00074 #define MCG_SC_FCRDIV_VAL ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)
00075 #define MCG_S2_PLLCST_VAL ((MCG->S2 & MCG_S2_PLLCST_MASK) >> MCG_S2_PLLCST_SHIFT)
00076 #define MCG_C7_OSCSEL_VAL ((MCG->C7 & MCG_C7_OSCSEL_MASK) >> MCG_C7_OSCSEL_SHIFT)
00077 #define MCG_C4_DMX32_VAL ((MCG->C4 & MCG_C4_DMX32_MASK) >> MCG_C4_DMX32_SHIFT)
00078 #define MCG_C4_DRST_DRS_VAL ((MCG->C4 & MCG_C4_DRST_DRS_MASK) >> MCG_C4_DRST_DRS_SHIFT)
00079 #define MCG_C7_PLL32KREFSEL_VAL ((MCG->C7 & MCG_C7_PLL32KREFSEL_MASK) >> MCG_C7_PLL32KREFSEL_SHIFT)
00080 #define MCG_C5_PLLREFSEL0_VAL ((MCG->C5 & MCG_C5_PLLREFSEL0_MASK) >> MCG_C5_PLLREFSEL0_SHIFT)
00081 #define MCG_C11_PLLREFSEL1_VAL ((MCG->C11 & MCG_C11_PLLREFSEL1_MASK) >> MCG_C11_PLLREFSEL1_SHIFT)
00082 #define MCG_C11_PRDIV1_VAL ((MCG->C11 & MCG_C11_PRDIV1_MASK) >> MCG_C11_PRDIV1_SHIFT)
00083 #define MCG_C12_VDIV1_VAL ((MCG->C12 & MCG_C12_VDIV1_MASK) >> MCG_C12_VDIV1_SHIFT)
00084 #define MCG_C5_PRDIV0_VAL ((MCG->C5 & MCG_C5_PRDIV0_MASK) >> MCG_C5_PRDIV0_SHIFT)
00085 #define MCG_C6_VDIV0_VAL ((MCG->C6 & MCG_C6_VDIV0_MASK) >> MCG_C6_VDIV0_SHIFT)
00086 
00087 #define OSC_MODE_MASK (MCG_C2_EREFS0_MASK | MCG_C2_HGO0_MASK | MCG_C2_RANGE0_MASK)
00088 
00089 #define SIM_CLKDIV1_OUTDIV1_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
00090 #define SIM_CLKDIV1_OUTDIV2_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT)
00091 #define SIM_CLKDIV1_OUTDIV3_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV3_MASK) >> SIM_CLKDIV1_OUTDIV3_SHIFT)
00092 #define SIM_CLKDIV1_OUTDIV4_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)
00093 #define SIM_SOPT1_OSC32KSEL_VAL ((SIM->SOPT1 & SIM_SOPT1_OSC32KSEL_MASK) >> SIM_SOPT1_OSC32KSEL_SHIFT)
00094 #define SIM_SOPT2_PLLFLLSEL_VAL ((SIM->SOPT2 & SIM_SOPT2_PLLFLLSEL_MASK) >> SIM_SOPT2_PLLFLLSEL_SHIFT)
00095 #define SIM_CLKDIV3_PLLFLLDIV_VAL ((SIM->CLKDIV3 & SIM_CLKDIV3_PLLFLLDIV_MASK) >> SIM_CLKDIV3_PLLFLLDIV_SHIFT)
00096 #define SIM_CLKDIV3_PLLFLLFRAC_VAL ((SIM->CLKDIV3 & SIM_CLKDIV3_PLLFLLFRAC_MASK) >> SIM_CLKDIV3_PLLFLLFRAC_SHIFT)
00097 
00098 /* MCG_S_CLKST definition. */
00099 enum _mcg_clkout_stat
00100 {
00101     kMCG_ClkOutStatFll, /* FLL.            */
00102     kMCG_ClkOutStatInt, /* Internal clock. */
00103     kMCG_ClkOutStatExt, /* External clock. */
00104     kMCG_ClkOutStatPll  /* PLL.            */
00105 };
00106 
00107 /* MCG_S_PLLST definition. */
00108 enum _mcg_pllst
00109 {
00110     kMCG_PllstFll, /* FLL is used. */
00111     kMCG_PllstPll  /* PLL is used. */
00112 };
00113 
00114 /*******************************************************************************
00115  * Variables
00116  ******************************************************************************/
00117 
00118 /* Slow internal reference clock frequency. */
00119 static uint32_t s_slowIrcFreq = 32768U;
00120 /* Fast internal reference clock frequency. */
00121 static uint32_t s_fastIrcFreq = 4000000U;
00122 /* The MCG external PLL clock frequency. */
00123 static uint32_t s_extPllFreq = 0U;
00124 
00125 /* External XTAL0 (OSC0) clock frequency. */
00126 uint32_t g_xtal0Freq;
00127 /* External XTAL32K clock frequency. */
00128 uint32_t g_xtal32Freq;
00129 
00130 /*******************************************************************************
00131  * Prototypes
00132  ******************************************************************************/
00133 
00134 /*!
00135  * @brief Get the MCG external reference clock frequency.
00136  *
00137  * Get the current MCG external reference clock frequency in Hz. It is
00138  * the frequency select by MCG_C7[OSCSEL]. This is an internal function.
00139  *
00140  * @return MCG external reference clock frequency in Hz.
00141  */
00142 static uint32_t CLOCK_GetMcgExtClkFreq(void);
00143 
00144 /*!
00145  * @brief Get the MCG FLL external reference clock frequency.
00146  *
00147  * Get the current MCG FLL external reference clock frequency in Hz. It is
00148  * the frequency after by MCG_C1[FRDIV]. This is an internal function.
00149  *
00150  * @return MCG FLL external reference clock frequency in Hz.
00151  */
00152 static uint32_t CLOCK_GetFllExtRefClkFreq(void);
00153 
00154 /*!
00155  * @brief Get the MCG FLL reference clock frequency.
00156  *
00157  * Get the current MCG FLL reference clock frequency in Hz. It is
00158  * the frequency select by MCG_C1[IREFS]. This is an internal function.
00159  *
00160  * @return MCG FLL reference clock frequency in Hz.
00161  */
00162 static uint32_t CLOCK_GetFllRefClkFreq(void);
00163 
00164 /*!
00165  * @brief Get the frequency of clock selected by MCG_C2[IRCS].
00166  *
00167  * This clock's two output:
00168  *  1. MCGOUTCLK when MCG_S[CLKST]=0.
00169  *  2. MCGIRCLK when MCG_C1[IRCLKEN]=1.
00170  *
00171  * @return The frequency in Hz.
00172  */
00173 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void);
00174 
00175 /*!
00176  * @brief Get the MCG PLL/PLL0 reference clock frequency.
00177  *
00178  * Get the current MCG PLL/PLL0 reference clock frequency in Hz.
00179  * This is an internal function.
00180  *
00181  * @return MCG PLL/PLL0 reference clock frequency in Hz.
00182  */
00183 static uint32_t CLOCK_GetPll0RefFreq(void);
00184 
00185 /*!
00186  * @brief Calculate the RANGE value base on crystal frequency.
00187  *
00188  * To setup external crystal oscillator, must set the register bits RANGE
00189  * base on the crystal frequency. This function returns the RANGE base on the
00190  * input frequency. This is an internal function.
00191  *
00192  * @param freq Crystal frequency in Hz.
00193  * @return The RANGE value.
00194  */
00195 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
00196 
00197 /*!
00198  * @brief Delay function to wait FLL stable.
00199  *
00200  * Delay function to wait FLL stable in FEI mode or FEE mode, should wait at least
00201  * 1ms. Every time changes FLL setting, should wait this time for FLL stable.
00202  */
00203 static void CLOCK_FllStableDelay(void);
00204 
00205 /*******************************************************************************
00206  * Code
00207  ******************************************************************************/
00208 
00209 static uint32_t CLOCK_GetMcgExtClkFreq(void)
00210 {
00211     uint32_t freq;
00212 
00213     switch (MCG_C7_OSCSEL_VAL)
00214     {
00215         case 0U:
00216             /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
00217             assert(g_xtal0Freq);
00218             freq = g_xtal0Freq;
00219             break;
00220         case 1U:
00221             /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
00222             assert(g_xtal32Freq);
00223             freq = g_xtal32Freq;
00224             break;
00225         case 2U:
00226             freq = MCG_INTERNAL_IRC_48M;
00227             break;
00228         default:
00229             freq = 0U;
00230             break;
00231     }
00232 
00233     return freq;
00234 }
00235 
00236 static uint32_t CLOCK_GetFllExtRefClkFreq(void)
00237 {
00238     /* FllExtRef = McgExtRef / FllExtRefDiv */
00239     uint8_t frdiv;
00240     uint8_t range;
00241     uint8_t oscsel;
00242 
00243     uint32_t freq = CLOCK_GetMcgExtClkFreq();
00244 
00245     if (!freq)
00246     {
00247         return freq;
00248     }
00249 
00250     frdiv = MCG_C1_FRDIV_VAL;
00251     freq >>= frdiv;
00252 
00253     range = MCG_C2_RANGE_VAL;
00254     oscsel = MCG_C7_OSCSEL_VAL;
00255 
00256     /*
00257        When should use divider 32, 64, 128, 256, 512, 1024, 1280, 1536.
00258        1. MCG_C7[OSCSEL] selects IRC48M.
00259        2. MCG_C7[OSCSEL] selects OSC0 and MCG_C2[RANGE] is not 0.
00260     */
00261     if (((0U != range) && (kMCG_OscselOsc  == oscsel)) || (kMCG_OscselIrc  == oscsel))
00262     {
00263         switch (frdiv)
00264         {
00265             case 0:
00266             case 1:
00267             case 2:
00268             case 3:
00269             case 4:
00270             case 5:
00271                 freq >>= 5u;
00272                 break;
00273             case 6:
00274                 /* 64*20=1280 */
00275                 freq /= 20u;
00276                 break;
00277             case 7:
00278                 /* 128*12=1536 */
00279                 freq /= 12u;
00280                 break;
00281             default:
00282                 freq = 0u;
00283                 break;
00284         }
00285     }
00286 
00287     return freq;
00288 }
00289 
00290 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void)
00291 {
00292     if (kMCG_IrcSlow  == MCG_S_IRCST_VAL)
00293     {
00294         /* Slow internal reference clock selected*/
00295         return s_slowIrcFreq;
00296     }
00297     else
00298     {
00299         /* Fast internal reference clock selected*/
00300         return s_fastIrcFreq >> MCG_SC_FCRDIV_VAL;
00301     }
00302 }
00303 
00304 static uint32_t CLOCK_GetFllRefClkFreq(void)
00305 {
00306     /* If use external reference clock. */
00307     if (kMCG_FllSrcExternal  == MCG_S_IREFST_VAL)
00308     {
00309         return CLOCK_GetFllExtRefClkFreq();
00310     }
00311     /* If use internal reference clock. */
00312     else
00313     {
00314         return s_slowIrcFreq;
00315     }
00316 }
00317 
00318 static uint32_t CLOCK_GetPll0RefFreq(void)
00319 {
00320     /* MCG external reference clock. */
00321     return CLOCK_GetMcgExtClkFreq();
00322 }
00323 
00324 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
00325 {
00326     uint8_t range;
00327 
00328     if (freq <= 39063U)
00329     {
00330         range = 0U;
00331     }
00332     else if (freq <= 8000000U)
00333     {
00334         range = 1U;
00335     }
00336     else
00337     {
00338         range = 2U;
00339     }
00340 
00341     return range;
00342 }
00343 
00344 static void CLOCK_FllStableDelay(void)
00345 {
00346     /*
00347        Should wait at least 1ms. Because in these modes, the core clock is 100MHz
00348        at most, so this function could obtain the 1ms delay.
00349      */
00350     volatile uint32_t i = 30000U;
00351     while (i--)
00352     {
00353         __NOP();
00354     }
00355 }
00356 
00357 uint32_t CLOCK_GetOsc0ErClkUndivFreq(void)
00358 {
00359     if (OSC0->CR & OSC_CR_ERCLKEN_MASK)
00360     {
00361         /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
00362         assert(g_xtal0Freq);
00363         return g_xtal0Freq;
00364     }
00365     else
00366     {
00367         return 0U;
00368     }
00369 }
00370 
00371 uint32_t CLOCK_GetOsc0ErClkDivFreq(void)
00372 {
00373     if (OSC0->CR & OSC_CR_ERCLKEN_MASK)
00374     {
00375         /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
00376         assert(g_xtal0Freq);
00377         return g_xtal0Freq >> ((OSC0->DIV & OSC_DIV_ERPS_MASK) >> OSC_DIV_ERPS_SHIFT);
00378     }
00379     else
00380     {
00381         return 0U;
00382     }
00383 }
00384 
00385 uint32_t CLOCK_GetEr32kClkFreq(void)
00386 {
00387     uint32_t freq;
00388 
00389     switch (SIM_SOPT1_OSC32KSEL_VAL)
00390     {
00391         case 0U: /* OSC 32k clock  */
00392             freq = (CLOCK_GetOsc0ErClkDivFreq() == 32768U) ? 32768U : 0U;
00393             break;
00394         case 2U: /* RTC 32k clock  */
00395             /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
00396             assert(g_xtal32Freq);
00397             freq = g_xtal32Freq;
00398             break;
00399         case 3U: /* LPO clock      */
00400             freq = LPO_CLK_FREQ;
00401             break;
00402         default:
00403             freq = 0U;
00404             break;
00405     }
00406     return freq;
00407 }
00408 
00409 uint32_t CLOCK_GetPllFllSelClkFreq(void)
00410 {
00411     uint32_t freq;
00412 
00413     switch (SIM_SOPT2_PLLFLLSEL_VAL)
00414     {
00415         case 0U: /* FLL. */
00416             freq = CLOCK_GetFllFreq();
00417             break;
00418         case 1U: /* PLL. */
00419             freq = CLOCK_GetPll0Freq();
00420             break;
00421         case 2U:
00422             freq = CLOCK_GetExtPllFreq();
00423             break;
00424         case 3U: /* MCG IRC48M. */
00425             freq = MCG_INTERNAL_IRC_48M;
00426             break;
00427         default:
00428             freq = 0U;
00429             break;
00430     }
00431 
00432     freq *= (SIM_CLKDIV3_PLLFLLFRAC_VAL + 1U);
00433     freq /= (SIM_CLKDIV3_PLLFLLDIV_VAL + 1U);
00434     return freq;
00435 }
00436 
00437 uint32_t CLOCK_GetOsc0ErClkFreq(void)
00438 {
00439     return CLOCK_GetOsc0ErClkDivFreq();
00440 }
00441 
00442 uint32_t CLOCK_GetPlatClkFreq(void)
00443 {
00444     return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
00445 }
00446 
00447 uint32_t CLOCK_GetFlashClkFreq(void)
00448 {
00449     return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV4_VAL + 1);
00450 }
00451 
00452 uint32_t CLOCK_GetFlexBusClkFreq(void)
00453 {
00454     return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV3_VAL + 1);
00455 }
00456 
00457 uint32_t CLOCK_GetBusClkFreq(void)
00458 {
00459     return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV2_VAL + 1);
00460 }
00461 
00462 uint32_t CLOCK_GetCoreSysClkFreq(void)
00463 {
00464     return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
00465 }
00466 
00467 uint32_t CLOCK_GetFreq(clock_name_t clockName)
00468 {
00469     uint32_t freq;
00470 
00471     switch (clockName)
00472     {
00473         case kCLOCK_CoreSysClk :
00474         case kCLOCK_PlatClk :
00475             freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
00476             break;
00477         case kCLOCK_BusClk :
00478             freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV2_VAL + 1);
00479             break;
00480         case kCLOCK_FlexBusClk :
00481             freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV3_VAL + 1);
00482             break;
00483         case kCLOCK_FlashClk :
00484             freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV4_VAL + 1);
00485             break;
00486         case kCLOCK_PllFllSelClk :
00487             freq = CLOCK_GetPllFllSelClkFreq();
00488             break;
00489         case kCLOCK_Er32kClk :
00490             freq = CLOCK_GetEr32kClkFreq();
00491             break;
00492         case kCLOCK_Osc0ErClk :
00493             freq = CLOCK_GetOsc0ErClkDivFreq();
00494             break;
00495         case kCLOCK_Osc0ErClkUndiv :
00496             freq = CLOCK_GetOsc0ErClkUndivFreq();
00497             break;
00498         case kCLOCK_McgFixedFreqClk :
00499             freq = CLOCK_GetFixedFreqClkFreq();
00500             break;
00501         case kCLOCK_McgInternalRefClk :
00502             freq = CLOCK_GetInternalRefClkFreq();
00503             break;
00504         case kCLOCK_McgFllClk :
00505             freq = CLOCK_GetFllFreq();
00506             break;
00507         case kCLOCK_McgPll0Clk :
00508             freq = CLOCK_GetPll0Freq();
00509             break;
00510         case kCLOCK_McgIrc48MClk :
00511             freq = MCG_INTERNAL_IRC_48M;
00512             break;
00513         case kCLOCK_LpoClk :
00514             freq = LPO_CLK_FREQ;
00515             break;
00516         default:
00517             freq = 0U;
00518             break;
00519     }
00520 
00521     return freq;
00522 }
00523 
00524 void CLOCK_SetSimConfig(sim_clock_config_t const *config)
00525 {
00526     SIM->CLKDIV1 = config->clkdiv1 ;
00527     CLOCK_SetPllFllSelClock(config->pllFllSel , config->pllFllDiv , config->pllFllFrac );
00528     CLOCK_SetEr32kClock(config->er32kSrc );
00529 }
00530 
00531 bool CLOCK_EnableUsbfs0Clock(clock_usb_src_t src, uint32_t freq)
00532 {
00533     /* In current implementation, USBPFDCLK is not used for USB FS. */
00534     assert(kCLOCK_UsbSrcUsbPfd  != src);
00535 
00536     bool ret = true;
00537 
00538     CLOCK_DisableClock(kCLOCK_Usbfs0);
00539 
00540     if (kCLOCK_UsbSrcExt  == src)
00541     {
00542         SIM->SOPT2 &= ~SIM_SOPT2_USBSRC_MASK;
00543     }
00544     else
00545     {
00546         switch (freq)
00547         {
00548             case 120000000U:
00549                 SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(4) | SIM_CLKDIV2_USBFRAC(1);
00550                 break;
00551             case 96000000U:
00552                 SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(1) | SIM_CLKDIV2_USBFRAC(0);
00553                 break;
00554             case 72000000U:
00555                 SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(2) | SIM_CLKDIV2_USBFRAC(1);
00556                 break;
00557             case 48000000U:
00558                 SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(0) | SIM_CLKDIV2_USBFRAC(0);
00559                 break;
00560             default:
00561                 ret = false;
00562                 break;
00563         }
00564 
00565         SIM->SOPT2 = ((SIM->SOPT2 & ~(SIM_SOPT2_PLLFLLSEL_MASK | SIM_SOPT2_USBSRC_MASK)) | (uint32_t)src);
00566     }
00567 
00568     CLOCK_EnableClock(kCLOCK_Usbfs0);
00569 
00570     if (kCLOCK_UsbSrcIrc48M  == src)
00571     {
00572         USB0->CLK_RECOVER_IRC_EN = 0x03U;
00573         USB0->CLK_RECOVER_CTRL |= USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK;
00574     }
00575     return ret;
00576 }
00577 
00578 bool CLOCK_EnableUsbhs0Clock(clock_usb_src_t src, uint32_t freq)
00579 {
00580     volatile uint32_t i;
00581 
00582     /*
00583      * In order to bring up the internal 480MHz USB PLL clock, should make sure:
00584      * 1. 32kHz IRC clock enable by setting IRCLKEN bit in MCG_C1 register.
00585      * 2. External reference clock enable on XTAL by setting ERCLKEN bit in OSC_CR register.
00586      */
00587     assert(MCG->C1 & MCG_C1_IRCLKEN_MASK);
00588     assert(!(MCG->C2 & MCG_C2_IRCS_MASK));
00589     assert(OSC0->CR & OSC_CR_ERCLKEN_MASK);
00590 
00591     /* Source and freq are not used for USB HS. */
00592     src = src;
00593     freq = freq;
00594 
00595     SIM->SOPT2 |= SIM_SOPT2_USBREGEN_MASK;
00596     SIM->SCGC3 |= (SIM_SCGC3_USBHS_MASK | SIM_SCGC3_USBHSPHY_MASK);
00597 
00598     i = 500000U;
00599     while (i--)
00600     {
00601         __NOP();
00602     }
00603 
00604     SIM->USBPHYCTL = ((SIM->USBPHYCTL & ~(SIM_USBPHYCTL_USB3VOUTTRG_MASK)) | SIM_USBPHYCTL_USB3VOUTTRG(6U) /* 3.310V */
00605                       | SIM_USBPHYCTL_USBVREGSEL_MASK); /* VREG_IN1 */
00606 
00607     return true;
00608 }
00609 
00610 uint32_t CLOCK_GetOutClkFreq(void)
00611 {
00612     uint32_t mcgoutclk;
00613     uint32_t clkst = MCG_S_CLKST_VAL;
00614     uint32_t pllcst = MCG_S2_PLLCST_VAL;
00615 
00616     switch (clkst)
00617     {
00618         case kMCG_ClkOutStatPll:
00619             switch (pllcst)
00620             {
00621                 case kMCG_PllClkSelExtPll:
00622                     mcgoutclk = CLOCK_GetExtPllFreq();
00623                     break;
00624                 case kMCG_PllClkSelPll0 :
00625                     mcgoutclk = CLOCK_GetPll0Freq();
00626                     break;
00627                 default:
00628                     mcgoutclk = 0U;
00629                     break;
00630             }
00631             break;
00632         case kMCG_ClkOutStatFll:
00633             mcgoutclk = CLOCK_GetFllFreq();
00634             break;
00635         case kMCG_ClkOutStatInt:
00636             mcgoutclk = CLOCK_GetInternalRefClkSelectFreq();
00637             break;
00638         case kMCG_ClkOutStatExt:
00639             mcgoutclk = CLOCK_GetMcgExtClkFreq();
00640             break;
00641         default:
00642             mcgoutclk = 0U;
00643             break;
00644     }
00645     return mcgoutclk;
00646 }
00647 
00648 uint32_t CLOCK_GetFllFreq(void)
00649 {
00650     static const uint16_t fllFactorTable[4][2] = {{640, 732}, {1280, 1464}, {1920, 2197}, {2560, 2929}};
00651 
00652     uint8_t drs, dmx32;
00653     uint32_t freq;
00654 
00655     /* If FLL is not enabled currently, then return 0U. */
00656     if ((MCG->C2 & MCG_C2_LP_MASK) || (MCG->S & MCG_S_PLLST_MASK))
00657     {
00658         return 0U;
00659     }
00660 
00661     /* Get FLL reference clock frequency. */
00662     freq = CLOCK_GetFllRefClkFreq();
00663     if (!freq)
00664     {
00665         return freq;
00666     }
00667 
00668     drs = MCG_C4_DRST_DRS_VAL;
00669     dmx32 = MCG_C4_DMX32_VAL;
00670 
00671     return freq * fllFactorTable[drs][dmx32];
00672 }
00673 
00674 uint32_t CLOCK_GetInternalRefClkFreq(void)
00675 {
00676     /* If MCGIRCLK is gated. */
00677     if (!(MCG->C1 & MCG_C1_IRCLKEN_MASK))
00678     {
00679         return 0U;
00680     }
00681 
00682     return CLOCK_GetInternalRefClkSelectFreq();
00683 }
00684 
00685 uint32_t CLOCK_GetFixedFreqClkFreq(void)
00686 {
00687     uint32_t freq = CLOCK_GetFllRefClkFreq();
00688 
00689     /* MCGFFCLK must be no more than MCGOUTCLK/8. */
00690     if ((freq) && (freq <= (CLOCK_GetOutClkFreq() / 8U)))
00691     {
00692         return freq;
00693     }
00694     else
00695     {
00696         return 0U;
00697     }
00698 }
00699 
00700 uint32_t CLOCK_GetPll0Freq(void)
00701 {
00702     uint32_t mcgpll0clk;
00703 
00704     /* If PLL0 is not enabled, return 0. */
00705     if (!(MCG->S & MCG_S_LOCK0_MASK))
00706     {
00707         return 0U;
00708     }
00709 
00710     mcgpll0clk = CLOCK_GetPll0RefFreq();
00711 
00712     /*
00713      * Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock.
00714      * Please call CLOCK_SetXtal1Freq base on board setting before using OSC1 clock.
00715      */
00716     assert(mcgpll0clk);
00717 
00718     mcgpll0clk /= (FSL_FEATURE_MCG_PLL_PRDIV_BASE + MCG_C5_PRDIV0_VAL);
00719     mcgpll0clk *= (FSL_FEATURE_MCG_PLL_VDIV_BASE + MCG_C6_VDIV0_VAL);
00720 
00721     mcgpll0clk >>= 1U;
00722     return mcgpll0clk;
00723 }
00724 
00725 uint32_t CLOCK_GetExtPllFreq(void)
00726 {
00727     return s_extPllFreq;
00728 }
00729 
00730 void CLOCK_SetExtPllFreq(uint32_t freq)
00731 {
00732     s_extPllFreq = freq;
00733 }
00734 
00735 status_t CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)
00736 {
00737     bool needDelay;
00738     uint32_t i;
00739 
00740 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
00741     /* If change MCG_C7[OSCSEL] and external reference clock is system clock source, return error. */
00742     if ((MCG_C7_OSCSEL_VAL != oscsel) && (!(MCG->S & MCG_S_IREFST_MASK)))
00743     {
00744         return kStatus_MCG_SourceUsed ;
00745     }
00746 #endif /* MCG_CONFIG_CHECK_PARAM */
00747 
00748     if (MCG_C7_OSCSEL_VAL != oscsel)
00749     {
00750         /* If change OSCSEL, need to delay, ERR009878. */
00751         needDelay = true;
00752     }
00753     else
00754     {
00755         needDelay = false;
00756     }
00757 
00758     MCG->C7 = (MCG->C7 & ~MCG_C7_OSCSEL_MASK) | MCG_C7_OSCSEL(oscsel);
00759     if (kMCG_OscselOsc  == oscsel)
00760     {
00761         if (MCG->C2 & MCG_C2_EREFS_MASK)
00762         {
00763             while (!(MCG->S & MCG_S_OSCINIT0_MASK))
00764             {
00765             }
00766         }
00767     }
00768 
00769     if (needDelay)
00770     {
00771         /* ERR009878 Delay at least 50 micro-seconds for external clock change valid. */
00772         i = 1500U;
00773         while (i--)
00774         {
00775             __NOP();
00776         }
00777     }
00778 
00779     return kStatus_Success;
00780 }
00781 
00782 status_t CLOCK_SetInternalRefClkConfig(uint8_t enableMode, mcg_irc_mode_t ircs, uint8_t fcrdiv)
00783 {
00784     uint32_t mcgOutClkState = MCG_S_CLKST_VAL;
00785     mcg_irc_mode_t curIrcs = (mcg_irc_mode_t)MCG_S_IRCST_VAL;
00786     uint8_t curFcrdiv = MCG_SC_FCRDIV_VAL;
00787 
00788 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
00789     /* If MCGIRCLK is used as system clock source. */
00790     if (kMCG_ClkOutStatInt == mcgOutClkState)
00791     {
00792         /* If need to change MCGIRCLK source or driver, return error. */
00793         if (((kMCG_IrcFast  == curIrcs) && (fcrdiv != curFcrdiv)) || (ircs != curIrcs))
00794         {
00795             return kStatus_MCG_SourceUsed ;
00796         }
00797     }
00798 #endif
00799 
00800     /* If need to update the FCRDIV. */
00801     if (fcrdiv != curFcrdiv)
00802     {
00803         /* If fast IRC is in use currently, change to slow IRC. */
00804         if ((kMCG_IrcFast  == curIrcs) && ((mcgOutClkState == kMCG_ClkOutStatInt) || (MCG->C1 & MCG_C1_IRCLKEN_MASK)))
00805         {
00806             MCG->C2 = ((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(kMCG_IrcSlow )));
00807             while (MCG_S_IRCST_VAL != kMCG_IrcSlow )
00808             {
00809             }
00810         }
00811         /* Update FCRDIV. */
00812         MCG->SC = (MCG->SC & ~(MCG_SC_FCRDIV_MASK | MCG_SC_ATMF_MASK | MCG_SC_LOCS0_MASK)) | MCG_SC_FCRDIV(fcrdiv);
00813     }
00814 
00815     /* Set internal reference clock selection. */
00816     MCG->C2 = (MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(ircs));
00817     MCG->C1 = (MCG->C1 & ~(MCG_C1_IRCLKEN_MASK | MCG_C1_IREFSTEN_MASK)) | (uint8_t)enableMode;
00818 
00819     /* If MCGIRCLK is used, need to wait for MCG_S_IRCST. */
00820     if ((mcgOutClkState == kMCG_ClkOutStatInt) || (enableMode & kMCG_IrclkEnable ))
00821     {
00822         while (MCG_S_IRCST_VAL != ircs)
00823         {
00824         }
00825     }
00826 
00827     return kStatus_Success;
00828 }
00829 
00830 uint32_t CLOCK_CalcPllDiv(uint32_t refFreq, uint32_t desireFreq, uint8_t *prdiv, uint8_t *vdiv)
00831 {
00832     uint8_t ret_prdiv = FSL_FEATURE_MCG_PLL_PRDIV_BASE;           /* PRDIV to return. */
00833     uint8_t ret_vdiv = FSL_FEATURE_MCG_PLL_VDIV_BASE;            /* VDIV to return.  */
00834     uint8_t prdiv_min;           /* Min PRDIV value to make reference clock in allowed range. */
00835     uint8_t prdiv_max;           /* Max PRDIV value to make reference clock in allowed range. */
00836     uint8_t prdiv_cur;           /* PRDIV value for iteration.    */
00837     uint8_t vdiv_cur;            /* VDIV value for iteration.     */
00838     uint32_t ret_freq = 0U;      /* PLL output fequency to return. */
00839     uint32_t diff = 0xFFFFFFFFU; /* Difference between desireFreq and return frequency. */
00840     uint32_t ref_div;            /* Reference frequency after PRDIV. */
00841 
00842     /*
00843        Steps:
00844        1. Get allowed prdiv with such rules:
00845           1). refFreq / prdiv >= FSL_FEATURE_MCG_PLL_REF_MIN.
00846           2). refFreq / prdiv <= FSL_FEATURE_MCG_PLL_REF_MAX.
00847        2. For each allowed prdiv, there are two candidate vdiv values:
00848           1). (desireFreq / (refFreq / prdiv)).
00849           2). (desireFreq / (refFreq / prdiv)) + 1.
00850           If could get the precise desired frequency, return current prdiv and
00851           vdiv directly. Otherwise choose the one which is closer to desired
00852           frequency.
00853      */
00854 
00855     /* Reference frequency is out of range. */
00856     if ((refFreq < FSL_FEATURE_MCG_PLL_REF_MIN) ||
00857         (refFreq > (FSL_FEATURE_MCG_PLL_REF_MAX * (FSL_FEATURE_MCG_PLL_PRDIV_MAX + FSL_FEATURE_MCG_PLL_PRDIV_BASE))))
00858     {
00859         return 0U;
00860     }
00861 
00862     /* refFreq/PRDIV must in a range. First get the allowed PRDIV range. */
00863     prdiv_max = refFreq / FSL_FEATURE_MCG_PLL_REF_MIN;
00864     prdiv_min = (refFreq + FSL_FEATURE_MCG_PLL_REF_MAX - 1U) / FSL_FEATURE_MCG_PLL_REF_MAX;
00865 
00866     desireFreq *= 2U;
00867 
00868     /* PRDIV traversal. */
00869     for (prdiv_cur = prdiv_max; prdiv_cur >= prdiv_min; prdiv_cur--)
00870     {
00871         /* Reference frequency after PRDIV. */
00872         ref_div = refFreq / prdiv_cur;
00873 
00874         vdiv_cur = desireFreq / ref_div;
00875 
00876         if ((vdiv_cur < FSL_FEATURE_MCG_PLL_VDIV_BASE - 1U) || (vdiv_cur > FSL_FEATURE_MCG_PLL_VDIV_BASE + 31U))
00877         {
00878             /* No VDIV is available with this PRDIV. */
00879             continue;
00880         }
00881 
00882         ret_freq = vdiv_cur * ref_div;
00883 
00884         if (vdiv_cur >= FSL_FEATURE_MCG_PLL_VDIV_BASE)
00885         {
00886             if (ret_freq == desireFreq) /* If desire frequency is got. */
00887             {
00888                 *prdiv = prdiv_cur - FSL_FEATURE_MCG_PLL_PRDIV_BASE;
00889                 *vdiv = vdiv_cur - FSL_FEATURE_MCG_PLL_VDIV_BASE;
00890                 return ret_freq / 2U;
00891             }
00892             /* New PRDIV/VDIV is closer. */
00893             if (diff > desireFreq - ret_freq)
00894             {
00895                 diff = desireFreq - ret_freq;
00896                 ret_prdiv = prdiv_cur;
00897                 ret_vdiv = vdiv_cur;
00898             }
00899         }
00900         vdiv_cur++;
00901         if (vdiv_cur <= (FSL_FEATURE_MCG_PLL_VDIV_BASE + 31U))
00902         {
00903             ret_freq += ref_div;
00904             /* New PRDIV/VDIV is closer. */
00905             if (diff > ret_freq - desireFreq)
00906             {
00907                 diff = ret_freq - desireFreq;
00908                 ret_prdiv = prdiv_cur;
00909                 ret_vdiv = vdiv_cur;
00910             }
00911         }
00912     }
00913 
00914     if (0xFFFFFFFFU != diff)
00915     {
00916         /* PRDIV/VDIV found. */
00917         *prdiv = ret_prdiv - FSL_FEATURE_MCG_PLL_PRDIV_BASE;
00918         *vdiv = ret_vdiv - FSL_FEATURE_MCG_PLL_VDIV_BASE;
00919         ret_freq = (refFreq / ret_prdiv) * ret_vdiv;
00920         return ret_freq / 2U;
00921     }
00922     else
00923     {
00924         /* No proper PRDIV/VDIV found. */
00925         return 0U;
00926     }
00927 }
00928 
00929 void CLOCK_EnablePll0(mcg_pll_config_t const *config)
00930 {
00931     assert(config);
00932 
00933     uint8_t mcg_c5 = 0U;
00934 
00935     mcg_c5 |= MCG_C5_PRDIV0(config->prdiv );
00936     MCG->C5 = mcg_c5; /* Disable the PLL first. */
00937 
00938     MCG->C6 = (MCG->C6 & ~MCG_C6_VDIV0_MASK) | MCG_C6_VDIV0(config->vdiv );
00939 
00940     /* Set enable mode. */
00941     MCG->C5 |= ((uint32_t)kMCG_PllEnableIndependent  | (uint32_t)config->enableMode );
00942 
00943     /* Wait for PLL lock. */
00944     while (!(MCG->S & MCG_S_LOCK0_MASK))
00945     {
00946     }
00947 }
00948 
00949 void CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)
00950 {
00951     /* Clear the previous flag, MCG_SC[LOCS0]. */
00952     MCG->SC &= ~MCG_SC_ATMF_MASK;
00953 
00954     if (kMCG_MonitorNone  == mode)
00955     {
00956         MCG->C6 &= ~MCG_C6_CME0_MASK;
00957     }
00958     else
00959     {
00960         if (kMCG_MonitorInt  == mode)
00961         {
00962             MCG->C2 &= ~MCG_C2_LOCRE0_MASK;
00963         }
00964         else
00965         {
00966             MCG->C2 |= MCG_C2_LOCRE0_MASK;
00967         }
00968         MCG->C6 |= MCG_C6_CME0_MASK;
00969     }
00970 }
00971 
00972 void CLOCK_SetRtcOscMonitorMode(mcg_monitor_mode_t mode)
00973 {
00974     uint8_t mcg_c8 = MCG->C8;
00975 
00976     mcg_c8 &= ~(MCG_C8_CME1_MASK | MCG_C8_LOCRE1_MASK);
00977 
00978     if (kMCG_MonitorNone  != mode)
00979     {
00980         if (kMCG_MonitorReset  == mode)
00981         {
00982             mcg_c8 |= MCG_C8_LOCRE1_MASK;
00983         }
00984         mcg_c8 |= MCG_C8_CME1_MASK;
00985     }
00986     MCG->C8 = mcg_c8;
00987 }
00988 
00989 void CLOCK_SetPll0MonitorMode(mcg_monitor_mode_t mode)
00990 {
00991     uint8_t mcg_c8;
00992 
00993     /* Clear previous flag. */
00994     MCG->S = MCG_S_LOLS0_MASK;
00995 
00996     if (kMCG_MonitorNone  == mode)
00997     {
00998         MCG->C6 &= ~MCG_C6_LOLIE0_MASK;
00999     }
01000     else
01001     {
01002         mcg_c8 = MCG->C8;
01003 
01004         mcg_c8 &= ~MCG_C8_LOCS1_MASK;
01005 
01006         if (kMCG_MonitorInt  == mode)
01007         {
01008             mcg_c8 &= ~MCG_C8_LOLRE_MASK;
01009         }
01010         else
01011         {
01012             mcg_c8 |= MCG_C8_LOLRE_MASK;
01013         }
01014         MCG->C8 = mcg_c8;
01015         MCG->C6 |= MCG_C6_LOLIE0_MASK;
01016     }
01017 }
01018 
01019 void CLOCK_SetExtPllMonitorMode(mcg_monitor_mode_t mode)
01020 {
01021     uint8_t mcg_c9 = MCG->C9;
01022 
01023     mcg_c9 &= ~(MCG_C9_PLL_LOCRE_MASK | MCG_C9_PLL_CME_MASK);
01024 
01025     if (kMCG_MonitorNone  != mode)
01026     {
01027         if (kMCG_MonitorReset  == mode)
01028         {
01029             mcg_c9 |= MCG_C9_PLL_LOCRE_MASK;
01030         }
01031         mcg_c9 |= MCG_C9_PLL_CME_MASK;
01032     }
01033     MCG->C9 = mcg_c9;
01034 }
01035 
01036 uint32_t CLOCK_GetStatusFlags(void)
01037 {
01038     uint32_t ret = 0U;
01039     uint8_t mcg_s = MCG->S;
01040 
01041     if (MCG->SC & MCG_SC_LOCS0_MASK)
01042     {
01043         ret |= kMCG_Osc0LostFlag ;
01044     }
01045     if (mcg_s & MCG_S_OSCINIT0_MASK)
01046     {
01047         ret |= kMCG_Osc0InitFlag ;
01048     }
01049     if (MCG->C8 & MCG_C8_LOCS1_MASK)
01050     {
01051         ret |= kMCG_RtcOscLostFlag ;
01052     }
01053     if (mcg_s & MCG_S_LOLS0_MASK)
01054     {
01055         ret |= kMCG_Pll0LostFlag ;
01056     }
01057     if (mcg_s & MCG_S_LOCK0_MASK)
01058     {
01059         ret |= kMCG_Pll0LockFlag ;
01060     }
01061     if (MCG->C9 & MCG_C9_EXT_PLL_LOCS_MASK)
01062     {
01063         ret |= kMCG_ExtPllLostFlag ;
01064     }
01065     return ret;
01066 }
01067 
01068 void CLOCK_ClearStatusFlags(uint32_t mask)
01069 {
01070     uint8_t reg;
01071 
01072     if (mask & kMCG_Osc0LostFlag )
01073     {
01074         MCG->SC &= ~MCG_SC_ATMF_MASK;
01075     }
01076     if (mask & kMCG_RtcOscLostFlag )
01077     {
01078         reg = MCG->C8;
01079         MCG->C8 = reg;
01080     }
01081     if (mask & kMCG_Pll0LostFlag )
01082     {
01083         MCG->S = MCG_S_LOLS0_MASK;
01084     }
01085     if (mask & kMCG_ExtPllLostFlag )
01086     {
01087         reg = MCG->C9;
01088         MCG->C9 = reg;
01089     }
01090 }
01091 
01092 void CLOCK_InitOsc0(osc_config_t const *config)
01093 {
01094     uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq );
01095 
01096     OSC_SetCapLoad(OSC0, config->capLoad );
01097     OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig );
01098 
01099     MCG->C2 = ((MCG->C2 & ~OSC_MODE_MASK) | MCG_C2_RANGE(range) | (uint8_t)config->workMode );
01100 
01101     if ((kOSC_ModeExt  != config->workMode ) && (OSC0->CR & OSC_CR_ERCLKEN_MASK))
01102     {
01103         /* Wait for stable. */
01104         while (!(MCG->S & MCG_S_OSCINIT0_MASK))
01105         {
01106         }
01107     }
01108 }
01109 
01110 void CLOCK_DeinitOsc0(void)
01111 {
01112     OSC0->CR = 0U;
01113     MCG->C2 &= ~OSC_MODE_MASK;
01114 }
01115 
01116 status_t CLOCK_TrimInternalRefClk(uint32_t extFreq, uint32_t desireFreq, uint32_t *actualFreq, mcg_atm_select_t atms)
01117 {
01118     uint32_t multi; /* extFreq / desireFreq */
01119     uint32_t actv;  /* Auto trim value. */
01120     uint8_t mcg_sc;
01121 
01122     static const uint32_t trimRange[2][2] = {
01123         /*     Min           Max      */
01124         {TRIM_SIRC_MIN, TRIM_SIRC_MAX}, /* Slow IRC. */
01125         {TRIM_FIRC_MIN, TRIM_FIRC_MAX}  /* Fast IRC. */
01126     };
01127 
01128     if ((extFreq > TRIM_REF_CLK_MAX) || (extFreq < TRIM_REF_CLK_MIN))
01129     {
01130         return kStatus_MCG_AtmBusClockInvalid ;
01131     }
01132 
01133     /* Check desired frequency range. */
01134     if ((desireFreq < trimRange[atms][0]) || (desireFreq > trimRange[atms][1]))
01135     {
01136         return kStatus_MCG_AtmDesiredFreqInvalid ;
01137     }
01138 
01139     /*
01140        Make sure internal reference clock is not used to generate bus clock.
01141        Here only need to check (MCG_S_IREFST == 1).
01142      */
01143     if (MCG_S_IREFST(kMCG_FllSrcInternal ) == (MCG->S & MCG_S_IREFST_MASK))
01144     {
01145         return kStatus_MCG_AtmIrcUsed ;
01146     }
01147 
01148     multi = extFreq / desireFreq;
01149     actv = multi * 21U;
01150 
01151     if (kMCG_AtmSel4m  == atms)
01152     {
01153         actv *= 128U;
01154     }
01155 
01156     /* Now begin to start trim. */
01157     MCG->ATCVL = (uint8_t)actv;
01158     MCG->ATCVH = (uint8_t)(actv >> 8U);
01159 
01160     mcg_sc = MCG->SC;
01161     mcg_sc &= ~(MCG_SC_ATMS_MASK | MCG_SC_LOCS0_MASK);
01162     mcg_sc |= (MCG_SC_ATMF_MASK | MCG_SC_ATMS(atms));
01163     MCG->SC = (mcg_sc | MCG_SC_ATME_MASK);
01164 
01165     /* Wait for finished. */
01166     while (MCG->SC & MCG_SC_ATME_MASK)
01167     {
01168     }
01169 
01170     /* Error occurs? */
01171     if (MCG->SC & MCG_SC_ATMF_MASK)
01172     {
01173         /* Clear the failed flag. */
01174         MCG->SC = mcg_sc;
01175         return kStatus_MCG_AtmHardwareFail ;
01176     }
01177 
01178     *actualFreq = extFreq / multi;
01179 
01180     if (kMCG_AtmSel4m  == atms)
01181     {
01182         s_fastIrcFreq = *actualFreq;
01183     }
01184     else
01185     {
01186         s_slowIrcFreq = *actualFreq;
01187     }
01188 
01189     return kStatus_Success;
01190 }
01191 
01192 mcg_mode_t CLOCK_GetMode(void)
01193 {
01194     mcg_mode_t mode = kMCG_ModeError ;
01195     uint32_t clkst = MCG_S_CLKST_VAL;
01196     uint32_t irefst = MCG_S_IREFST_VAL;
01197     uint32_t lp = MCG_C2_LP_VAL;
01198     uint32_t pllst = MCG_S_PLLST_VAL;
01199 
01200     /*------------------------------------------------------------------
01201                            Mode and Registers
01202     ____________________________________________________________________
01203 
01204       Mode   |   CLKST    |   IREFST   |   PLLST   |      LP
01205     ____________________________________________________________________
01206 
01207       FEI    |  00(FLL)   |   1(INT)   |   0(FLL)  |      X
01208     ____________________________________________________________________
01209 
01210       FEE    |  00(FLL)   |   0(EXT)   |   0(FLL)  |      X
01211     ____________________________________________________________________
01212 
01213       FBE    |  10(EXT)   |   0(EXT)   |   0(FLL)  |   0(NORMAL)
01214     ____________________________________________________________________
01215 
01216       FBI    |  01(INT)   |   1(INT)   |   0(FLL)  |   0(NORMAL)
01217     ____________________________________________________________________
01218 
01219       BLPI   |  01(INT)   |   1(INT)   |   0(FLL)  |   1(LOW POWER)
01220     ____________________________________________________________________
01221 
01222       BLPE   |  10(EXT)   |   0(EXT)   |     X     |   1(LOW POWER)
01223     ____________________________________________________________________
01224 
01225       PEE    |  11(PLL)   |   0(EXT)   |   1(PLL)  |      X
01226     ____________________________________________________________________
01227 
01228       PBE    |  10(EXT)   |   0(EXT)   |   1(PLL)  |   O(NORMAL)
01229     ____________________________________________________________________
01230 
01231       PBI    |  01(INT)   |   1(INT)   |   1(PLL)  |   0(NORMAL)
01232     ____________________________________________________________________
01233 
01234       PEI    |  11(PLL)   |   1(INT)   |   1(PLL)  |      X
01235     ____________________________________________________________________
01236 
01237     ----------------------------------------------------------------------*/
01238 
01239     switch (clkst)
01240     {
01241         case kMCG_ClkOutStatFll:
01242             if (kMCG_FllSrcExternal  == irefst)
01243             {
01244                 mode = kMCG_ModeFEE ;
01245             }
01246             else
01247             {
01248                 mode = kMCG_ModeFEI ;
01249             }
01250             break;
01251         case kMCG_ClkOutStatInt:
01252             if (lp)
01253             {
01254                 mode = kMCG_ModeBLPI ;
01255             }
01256             else
01257             {
01258                 {
01259                     mode = kMCG_ModeFBI ;
01260                 }
01261             }
01262             break;
01263         case kMCG_ClkOutStatExt:
01264             if (lp)
01265             {
01266                 mode = kMCG_ModeBLPE ;
01267             }
01268             else
01269             {
01270                 if (kMCG_PllstPll == pllst)
01271                 {
01272                     mode = kMCG_ModePBE ;
01273                 }
01274                 else
01275                 {
01276                     mode = kMCG_ModeFBE ;
01277                 }
01278             }
01279             break;
01280         case kMCG_ClkOutStatPll:
01281         {
01282             mode = kMCG_ModePEE ;
01283         }
01284         break;
01285         default:
01286             break;
01287     }
01288 
01289     return mode;
01290 }
01291 
01292 status_t CLOCK_SetFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
01293 {
01294     uint8_t mcg_c4;
01295     bool change_drs = false;
01296 
01297 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
01298     mcg_mode_t mode = CLOCK_GetMode();
01299     if (!((kMCG_ModeFEI  == mode) || (kMCG_ModeFBI  == mode) || (kMCG_ModeFBE  == mode) || (kMCG_ModeFEE  == mode)))
01300     {
01301         return kStatus_MCG_ModeUnreachable ;
01302     }
01303 #endif
01304     mcg_c4 = MCG->C4;
01305 
01306     /*
01307        Errata: ERR007993
01308        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
01309        reference clock source changes, then reset to previous value after
01310        reference clock changes.
01311      */
01312     if (kMCG_FllSrcExternal  == MCG_S_IREFST_VAL)
01313     {
01314         change_drs = true;
01315         /* Change the LSB of DRST_DRS. */
01316         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
01317     }
01318 
01319     /* Set CLKS and IREFS. */
01320     MCG->C1 =
01321         ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK))) | (MCG_C1_CLKS(kMCG_ClkOutSrcOut )        /* CLKS = 0 */
01322                                                                  | MCG_C1_IREFS(kMCG_FllSrcInternal )); /* IREFS = 1 */
01323 
01324     /* Wait and check status. */
01325     while (kMCG_FllSrcInternal  != MCG_S_IREFST_VAL)
01326     {
01327     }
01328 
01329     /* Errata: ERR007993 */
01330     if (change_drs)
01331     {
01332         MCG->C4 = mcg_c4;
01333     }
01334 
01335     /* In FEI mode, the MCG_C4[DMX32] is set to 0U. */
01336     MCG->C4 = (mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs));
01337 
01338     /* Check MCG_S[CLKST] */
01339     while (kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
01340     {
01341     }
01342 
01343     /* Wait for FLL stable time. */
01344     if (fllStableDelay)
01345     {
01346         fllStableDelay();
01347     }
01348 
01349     return kStatus_Success;
01350 }
01351 
01352 status_t CLOCK_SetFeeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
01353 {
01354     uint8_t mcg_c4;
01355     bool change_drs = false;
01356 
01357 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
01358     mcg_mode_t mode = CLOCK_GetMode();
01359     if (!((kMCG_ModeFEE  == mode) || (kMCG_ModeFBI  == mode) || (kMCG_ModeFBE  == mode) || (kMCG_ModeFEI  == mode)))
01360     {
01361         return kStatus_MCG_ModeUnreachable ;
01362     }
01363 #endif
01364     mcg_c4 = MCG->C4;
01365 
01366     /*
01367        Errata: ERR007993
01368        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
01369        reference clock source changes, then reset to previous value after
01370        reference clock changes.
01371      */
01372     if (kMCG_FllSrcInternal  == MCG_S_IREFST_VAL)
01373     {
01374         change_drs = true;
01375         /* Change the LSB of DRST_DRS. */
01376         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
01377     }
01378 
01379     /* Set CLKS and IREFS. */
01380     MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
01381                (MCG_C1_CLKS(kMCG_ClkOutSrcOut )         /* CLKS = 0 */
01382                 | MCG_C1_FRDIV(frdiv)                  /* FRDIV */
01383                 | MCG_C1_IREFS(kMCG_FllSrcExternal ))); /* IREFS = 0 */
01384 
01385     /* Wait and check status. */
01386     while (kMCG_FllSrcExternal  != MCG_S_IREFST_VAL)
01387     {
01388     }
01389 
01390     /* Errata: ERR007993 */
01391     if (change_drs)
01392     {
01393         MCG->C4 = mcg_c4;
01394     }
01395 
01396     /* Set DRS and DMX32. */
01397     mcg_c4 = ((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
01398     MCG->C4 = mcg_c4;
01399 
01400     /* Wait for DRST_DRS update. */
01401     while (MCG->C4 != mcg_c4)
01402     {
01403     }
01404 
01405     /* Check MCG_S[CLKST] */
01406     while (kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
01407     {
01408     }
01409 
01410     /* Wait for FLL stable time. */
01411     if (fllStableDelay)
01412     {
01413         fllStableDelay();
01414     }
01415 
01416     return kStatus_Success;
01417 }
01418 
01419 status_t CLOCK_SetFbiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
01420 {
01421     uint8_t mcg_c4;
01422     bool change_drs = false;
01423 
01424 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
01425     mcg_mode_t mode = CLOCK_GetMode();
01426 
01427     if (!((kMCG_ModeFEE  == mode) || (kMCG_ModeFBI  == mode) || (kMCG_ModeFBE  == mode) || (kMCG_ModeFEI  == mode) ||
01428           (kMCG_ModeBLPI  == mode)))
01429 
01430     {
01431         return kStatus_MCG_ModeUnreachable ;
01432     }
01433 #endif
01434 
01435     mcg_c4 = MCG->C4;
01436 
01437     MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
01438 
01439     /*
01440        Errata: ERR007993
01441        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
01442        reference clock source changes, then reset to previous value after
01443        reference clock changes.
01444      */
01445     if (kMCG_FllSrcExternal  == MCG_S_IREFST_VAL)
01446     {
01447         change_drs = true;
01448         /* Change the LSB of DRST_DRS. */
01449         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
01450     }
01451 
01452     /* Set CLKS and IREFS. */
01453     MCG->C1 =
01454         ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(kMCG_ClkOutSrcInternal )    /* CLKS = 1 */
01455                                                                 | MCG_C1_IREFS(kMCG_FllSrcInternal ))); /* IREFS = 1 */
01456 
01457     /* Wait and check status. */
01458     while (kMCG_FllSrcInternal  != MCG_S_IREFST_VAL)
01459     {
01460     }
01461 
01462     /* Errata: ERR007993 */
01463     if (change_drs)
01464     {
01465         MCG->C4 = mcg_c4;
01466     }
01467 
01468     while (kMCG_ClkOutStatInt != MCG_S_CLKST_VAL)
01469     {
01470     }
01471 
01472     MCG->C4 = (mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs));
01473 
01474     /* Wait for FLL stable time. */
01475     if (fllStableDelay)
01476     {
01477         fllStableDelay();
01478     }
01479 
01480     return kStatus_Success;
01481 }
01482 
01483 status_t CLOCK_SetFbeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
01484 {
01485     uint8_t mcg_c4;
01486     bool change_drs = false;
01487 
01488 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
01489     mcg_mode_t mode = CLOCK_GetMode();
01490     if (!((kMCG_ModeFEE  == mode) || (kMCG_ModeFBI  == mode) || (kMCG_ModeFBE  == mode) || (kMCG_ModeFEI  == mode) ||
01491           (kMCG_ModePBE  == mode) || (kMCG_ModeBLPE  == mode)))
01492     {
01493         return kStatus_MCG_ModeUnreachable ;
01494     }
01495 #endif
01496 
01497     /* Change to FLL mode. */
01498     MCG->C6 &= ~MCG_C6_PLLS_MASK;
01499     while (MCG->S & MCG_S_PLLST_MASK)
01500     {
01501     }
01502 
01503     /* Set LP bit to enable the FLL */
01504     MCG->C2 &= ~MCG_C2_LP_MASK;
01505 
01506     mcg_c4 = MCG->C4;
01507 
01508     /*
01509        Errata: ERR007993
01510        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
01511        reference clock source changes, then reset to previous value after
01512        reference clock changes.
01513      */
01514     if (kMCG_FllSrcInternal  == MCG_S_IREFST_VAL)
01515     {
01516         change_drs = true;
01517         /* Change the LSB of DRST_DRS. */
01518         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
01519     }
01520 
01521     /* Set CLKS and IREFS. */
01522     MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
01523                (MCG_C1_CLKS(kMCG_ClkOutSrcExternal )    /* CLKS = 2 */
01524                 | MCG_C1_FRDIV(frdiv)                  /* FRDIV = frdiv */
01525                 | MCG_C1_IREFS(kMCG_FllSrcExternal ))); /* IREFS = 0 */
01526 
01527     /* Wait for Reference clock Status bit to clear */
01528     while (kMCG_FllSrcExternal  != MCG_S_IREFST_VAL)
01529     {
01530     }
01531 
01532     /* Errata: ERR007993 */
01533     if (change_drs)
01534     {
01535         MCG->C4 = mcg_c4;
01536     }
01537 
01538     /* Set DRST_DRS and DMX32. */
01539     mcg_c4 = ((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
01540 
01541     /* Wait for clock status bits to show clock source is ext ref clk */
01542     while (kMCG_ClkOutStatExt != MCG_S_CLKST_VAL)
01543     {
01544     }
01545 
01546     /* Wait for fll stable time. */
01547     if (fllStableDelay)
01548     {
01549         fllStableDelay();
01550     }
01551 
01552     return kStatus_Success;
01553 }
01554 
01555 status_t CLOCK_SetBlpiMode(void)
01556 {
01557 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
01558     if (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
01559     {
01560         return kStatus_MCG_ModeUnreachable ;
01561     }
01562 #endif /* MCG_CONFIG_CHECK_PARAM */
01563 
01564     /* Set LP. */
01565     MCG->C2 |= MCG_C2_LP_MASK;
01566 
01567     return kStatus_Success;
01568 }
01569 
01570 status_t CLOCK_SetBlpeMode(void)
01571 {
01572 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
01573     if (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
01574     {
01575         return kStatus_MCG_ModeUnreachable ;
01576     }
01577 #endif
01578 
01579     /* Set LP bit to enter BLPE mode. */
01580     MCG->C2 |= MCG_C2_LP_MASK;
01581 
01582     return kStatus_Success;
01583 }
01584 
01585 status_t CLOCK_SetPbeMode(mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
01586 {
01587     /*
01588        This function is designed to change MCG to PBE mode from PEE/BLPE/FBE,
01589        but with this workflow, the source mode could be all modes except PEI/PBI.
01590      */
01591     MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
01592 
01593     /* Change to use external clock first. */
01594     MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal ));
01595 
01596     /* Wait for CLKST clock status bits to show clock source is ext ref clk */
01597     while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
01598            (MCG_S_IREFST(kMCG_FllSrcExternal ) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
01599     {
01600     }
01601 
01602     /* Disable PLL first, then configure PLL. */
01603     MCG->C6 &= ~MCG_C6_PLLS_MASK;
01604     while (MCG->S & MCG_S_PLLST_MASK)
01605     {
01606     }
01607 
01608     /* Configure the PLL. */
01609     if (kMCG_PllClkSelPll0  == pllcs)
01610     {
01611         CLOCK_EnablePll0(config);
01612     }
01613 
01614     MCG->C11 = ((MCG->C11 & ~MCG_C11_PLLCS_MASK)) | MCG_C11_PLLCS(pllcs);
01615     while (pllcs != MCG_S2_PLLCST_VAL)
01616     {
01617     }
01618 
01619     /* Change to PLL mode. */
01620     MCG->C6 |= MCG_C6_PLLS_MASK;
01621     while (!(MCG->S & MCG_S_PLLST_MASK))
01622     {
01623     }
01624 
01625     return kStatus_Success;
01626 }
01627 
01628 status_t CLOCK_SetPeeMode(void)
01629 {
01630 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
01631     mcg_mode_t mode = CLOCK_GetMode();
01632     if (kMCG_ModePBE  != mode)
01633     {
01634         return kStatus_MCG_ModeUnreachable ;
01635     }
01636 #endif
01637 
01638     /* Change to use PLL/FLL output clock first. */
01639     MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut );
01640 
01641     /* Wait for clock status bits to update */
01642     while (MCG_S_CLKST_VAL != kMCG_ClkOutStatPll)
01643     {
01644     }
01645 
01646     return kStatus_Success;
01647 }
01648 
01649 status_t CLOCK_ExternalModeToFbeModeQuick(void)
01650 {
01651 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
01652     if (MCG->S & MCG_S_IREFST_MASK)
01653     {
01654         return kStatus_MCG_ModeInvalid ;
01655     }
01656 #endif /* MCG_CONFIG_CHECK_PARAM */
01657 
01658     /* Disable low power */
01659     MCG->C2 &= ~MCG_C2_LP_MASK;
01660 
01661     MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal ));
01662     while (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
01663     {
01664     }
01665 
01666     /* Disable PLL. */
01667     MCG->C6 &= ~MCG_C6_PLLS_MASK;
01668     while (MCG->S & MCG_S_PLLST_MASK)
01669     {
01670     }
01671 
01672     return kStatus_Success;
01673 }
01674 
01675 status_t CLOCK_InternalModeToFbiModeQuick(void)
01676 {
01677 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
01678     if (!(MCG->S & MCG_S_IREFST_MASK))
01679     {
01680         return kStatus_MCG_ModeInvalid ;
01681     }
01682 #endif
01683 
01684     /* Disable low power */
01685     MCG->C2 &= ~MCG_C2_LP_MASK;
01686 
01687     MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal ));
01688     while (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
01689     {
01690     }
01691 
01692     return kStatus_Success;
01693 }
01694 
01695 status_t CLOCK_BootToFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
01696 {
01697     return CLOCK_SetFeiMode(dmx32, drs, fllStableDelay);
01698 }
01699 
01700 status_t CLOCK_BootToFeeMode(
01701     mcg_oscsel_t oscsel, uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
01702 {
01703     CLOCK_SetExternalRefClkConfig(oscsel);
01704 
01705     return CLOCK_SetFeeMode(frdiv, dmx32, drs, fllStableDelay);
01706 }
01707 
01708 status_t CLOCK_BootToBlpiMode(uint8_t fcrdiv, mcg_irc_mode_t ircs, uint8_t ircEnableMode)
01709 {
01710     /* If reset mode is FEI mode, set MCGIRCLK and always success. */
01711     CLOCK_SetInternalRefClkConfig(ircEnableMode, ircs, fcrdiv);
01712 
01713     /* If reset mode is not BLPI, first enter FBI mode. */
01714     MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal );
01715     while (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
01716     {
01717     }
01718 
01719     /* Enter BLPI mode. */
01720     MCG->C2 |= MCG_C2_LP_MASK;
01721 
01722     return kStatus_Success;
01723 }
01724 
01725 status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)
01726 {
01727     CLOCK_SetExternalRefClkConfig(oscsel);
01728 
01729     /* Set to FBE mode. */
01730     MCG->C1 =
01731         ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(kMCG_ClkOutSrcExternal )    /* CLKS = 2 */
01732                                                                 | MCG_C1_IREFS(kMCG_FllSrcExternal ))); /* IREFS = 0 */
01733 
01734     /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */
01735     while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
01736            (MCG_S_IREFST(kMCG_FllSrcExternal ) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
01737     {
01738     }
01739 
01740     /* In FBE now, start to enter BLPE. */
01741     MCG->C2 |= MCG_C2_LP_MASK;
01742 
01743     return kStatus_Success;
01744 }
01745 
01746 status_t CLOCK_BootToPeeMode(mcg_oscsel_t oscsel, mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
01747 {
01748     assert(config);
01749 
01750     CLOCK_SetExternalRefClkConfig(oscsel);
01751 
01752     CLOCK_SetPbeMode(pllcs, config);
01753 
01754     /* Change to use PLL output clock. */
01755     MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut );
01756     while (MCG_S_CLKST_VAL != kMCG_ClkOutStatPll)
01757     {
01758     }
01759 
01760     return kStatus_Success;
01761 }
01762 
01763 /*
01764    The transaction matrix. It defines the path for mode switch, the row is for
01765    current mode and the column is target mode.
01766    For example, switch from FEI to PEE:
01767    1. Current mode FEI, next mode is mcgModeMatrix[FEI][PEE] = FBE, so swith to FBE.
01768    2. Current mode FBE, next mode is mcgModeMatrix[FBE][PEE] = PBE, so swith to PBE.
01769    3. Current mode PBE, next mode is mcgModeMatrix[PBE][PEE] = PEE, so swith to PEE.
01770    Thus the MCG mode has changed from FEI to PEE.
01771  */
01772 static const mcg_mode_t mcgModeMatrix[8][8] = {
01773     {kMCG_ModeFEI , kMCG_ModeFBI , kMCG_ModeFBI , kMCG_ModeFEE , kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeFBE ,
01774      kMCG_ModeFBE}, /* FEI */
01775     {kMCG_ModeFEI , kMCG_ModeFBI , kMCG_ModeBLPI , kMCG_ModeFEE , kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeFBE ,
01776      kMCG_ModeFBE}, /* FBI */
01777     {kMCG_ModeFBI , kMCG_ModeFBI , kMCG_ModeBLPI , kMCG_ModeFBI , kMCG_ModeFBI , kMCG_ModeFBI , kMCG_ModeFBI ,
01778      kMCG_ModeFBI}, /* BLPI */
01779     {kMCG_ModeFEI , kMCG_ModeFBI , kMCG_ModeFBI , kMCG_ModeFEE , kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeFBE ,
01780      kMCG_ModeFBE}, /* FEE */
01781     {kMCG_ModeFEI , kMCG_ModeFBI , kMCG_ModeFBI , kMCG_ModeFEE , kMCG_ModeFBE , kMCG_ModeBLPE , kMCG_ModePBE ,
01782      kMCG_ModePBE}, /* FBE */
01783     {kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeBLPE , kMCG_ModePBE ,
01784      kMCG_ModePBE}, /* BLPE */
01785     {kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeFBE , kMCG_ModeBLPE , kMCG_ModePBE ,
01786      kMCG_ModePEE }, /* PBE */
01787     {kMCG_ModePBE , kMCG_ModePBE , kMCG_ModePBE , kMCG_ModePBE , kMCG_ModePBE , kMCG_ModePBE , kMCG_ModePBE ,
01788      kMCG_ModePBE} /* PEE */
01789     /*    FEI           FBI           BLPI           FEE           FBE           BLPE           PBE           PEE */
01790 };
01791 
01792 status_t CLOCK_SetMcgConfig(const mcg_config_t *config)
01793 {
01794     mcg_mode_t next_mode;
01795     status_t status = kStatus_Success;
01796 
01797     mcg_pll_clk_select_t pllcs = config->pllcs ;
01798 
01799     /* If need to change external clock, MCG_C7[OSCSEL]. */
01800     if (MCG_C7_OSCSEL_VAL != config->oscsel )
01801     {
01802         /* If external clock is in use, change to FEI first. */
01803         if (!(MCG->S & MCG_S_IRCST_MASK))
01804         {
01805             CLOCK_ExternalModeToFbeModeQuick();
01806             CLOCK_SetFeiMode(config->dmx32 , config->drs , (void (*)(void))0);
01807         }
01808 
01809         CLOCK_SetExternalRefClkConfig(config->oscsel );
01810     }
01811 
01812     /* Re-configure MCGIRCLK, if MCGIRCLK is used as system clock source, then change to FEI/PEI first. */
01813     if (MCG_S_CLKST_VAL == kMCG_ClkOutStatInt)
01814     {
01815         MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
01816 
01817         {
01818             CLOCK_SetFeiMode(config->dmx32 , config->drs , CLOCK_FllStableDelay);
01819         }
01820     }
01821 
01822     /* Configure MCGIRCLK. */
01823     CLOCK_SetInternalRefClkConfig(config->irclkEnableMode , config->ircs , config->fcrdiv );
01824 
01825     next_mode = CLOCK_GetMode();
01826 
01827     do
01828     {
01829         next_mode = mcgModeMatrix[next_mode][config->mcgMode ];
01830 
01831         switch (next_mode)
01832         {
01833             case kMCG_ModeFEI :
01834                 status = CLOCK_SetFeiMode(config->dmx32 , config->drs , CLOCK_FllStableDelay);
01835                 break;
01836             case kMCG_ModeFEE :
01837                 status = CLOCK_SetFeeMode(config->frdiv , config->dmx32 , config->drs , CLOCK_FllStableDelay);
01838                 break;
01839             case kMCG_ModeFBI :
01840                 status = CLOCK_SetFbiMode(config->dmx32 , config->drs , (void (*)(void))0);
01841                 break;
01842             case kMCG_ModeFBE :
01843                 status = CLOCK_SetFbeMode(config->frdiv , config->dmx32 , config->drs , (void (*)(void))0);
01844                 break;
01845             case kMCG_ModeBLPI :
01846                 status = CLOCK_SetBlpiMode();
01847                 break;
01848             case kMCG_ModeBLPE :
01849                 status = CLOCK_SetBlpeMode();
01850                 break;
01851             case kMCG_ModePBE :
01852                 /* If target mode is not PBE or PEE, then only need to set CLKS = EXT here. */
01853                 if ((kMCG_ModePEE  == config->mcgMode ) || (kMCG_ModePBE  == config->mcgMode ))
01854                 {
01855                     if (kMCG_PllClkSelPll0  == pllcs)
01856                     {
01857                         status = CLOCK_SetPbeMode(pllcs, &config->pll0Config );
01858                     }
01859                     else if (kMCG_PllClkSelExtPll == pllcs)
01860                     {
01861                         status = CLOCK_SetPbeMode(pllcs, NULL);
01862                     }
01863                     else
01864                     {
01865                     }
01866                 }
01867                 else
01868                 {
01869                     MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal ));
01870                     while (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
01871                     {
01872                     }
01873                 }
01874                 break;
01875             case kMCG_ModePEE :
01876                 status = CLOCK_SetPeeMode();
01877                 break;
01878             default:
01879                 break;
01880         }
01881         if (kStatus_Success != status)
01882         {
01883             return status;
01884         }
01885     } while (next_mode != config->mcgMode );
01886 
01887     if (config->pll0Config .enableMode  & kMCG_PllEnableIndependent )
01888     {
01889         CLOCK_EnablePll0(&config->pll0Config );
01890     }
01891     else
01892     {
01893         MCG->C5 &= ~(uint32_t)kMCG_PllEnableIndependent ;
01894     }
01895     return kStatus_Success;
01896 }