status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel) { CLOCK_SetExternalRefClkConfig(oscsel); /* Set to FBE mode. */ MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */ | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */ /* If use external crystal as clock source, wait for it stable. */ { if (MCG->C2 & MCG_C2_EREFS_MASK) { while (!(MCG->S & MCG_S_OSCINIT0_MASK)) { } } } /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */ while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) != (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt))) { } /* In FBE now, start to enter BLPE. */ MCG->C2 |= MCG_C2_LP_MASK; return kStatus_Success; }
status_t CLOCK_SetPbeMode(mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config) { assert(config); /* This function is designed to change MCG to PBE mode from PEE/BLPE/FBE, but with this workflow, the source mode could be all modes except PEI/PBI. */ MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */ /* Change to use external clock first. */ MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal)); /* Wait for CLKST clock status bits to show clock source is ext ref clk */ while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) != (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt))) { } /* Disable PLL first, then configure PLL. */ MCG->C6 &= ~MCG_C6_PLLS_MASK; while (MCG->S & MCG_S_PLLST_MASK) { } /* Configure the PLL. */ { CLOCK_EnablePll0(config); } /* Change to PLL mode. */ MCG->C6 |= MCG_C6_PLLS_MASK; /* Wait for PLL mode changed. */ while (!(MCG->S & MCG_S_PLLST_MASK)) { } return kStatus_Success; }
status_t CLOCK_TrimInternalRefClk(uint32_t extFreq, uint32_t desireFreq, uint32_t *actualFreq, mcg_atm_select_t atms) { uint32_t multi; /* extFreq / desireFreq */ uint32_t actv; /* Auto trim value. */ uint8_t mcg_sc; static const uint32_t trimRange[2][2] = { /* Min Max */ {TRIM_SIRC_MIN, TRIM_SIRC_MAX}, /* Slow IRC. */ {TRIM_FIRC_MIN, TRIM_FIRC_MAX} /* Fast IRC. */ }; if ((extFreq > TRIM_REF_CLK_MAX) || (extFreq < TRIM_REF_CLK_MIN)) { return kStatus_MCG_AtmBusClockInvalid; } /* Check desired frequency range. */ if ((desireFreq < trimRange[atms][0]) || (desireFreq > trimRange[atms][1])) { return kStatus_MCG_AtmDesiredFreqInvalid; } /* Make sure internal reference clock is not used to generate bus clock. Here only need to check (MCG_S_IREFST == 1). */ if (MCG_S_IREFST(kMCG_FllSrcInternal) == (MCG->S & MCG_S_IREFST_MASK)) { return kStatus_MCG_AtmIrcUsed; } multi = extFreq / desireFreq; actv = multi * 21U; if (kMCG_AtmSel4m == atms) { actv *= 128U; } /* Now begin to start trim. */ MCG->ATCVL = (uint8_t)actv; MCG->ATCVH = (uint8_t)(actv >> 8U); mcg_sc = MCG->SC; mcg_sc &= ~(MCG_SC_ATMS_MASK | MCG_SC_LOCS0_MASK); mcg_sc |= (MCG_SC_ATMF_MASK | MCG_SC_ATMS(atms)); MCG->SC = (mcg_sc | MCG_SC_ATME_MASK); /* Wait for finished. */ while (MCG->SC & MCG_SC_ATME_MASK) { } /* Error occurs? */ if (MCG->SC & MCG_SC_ATMF_MASK) { /* Clear the failed flag. */ MCG->SC = mcg_sc; return kStatus_MCG_AtmHardwareFail; } *actualFreq = extFreq / multi; if (kMCG_AtmSel4m == atms) { s_fastIrcFreq = *actualFreq; } else { s_slowIrcFreq = *actualFreq; } return kStatus_Success; }