349 lines
10 KiB
C
349 lines
10 KiB
C
/*
|
|
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* o Redistributions of source code must retain the above copyright notice, this list
|
|
* of conditions and the following disclaimer.
|
|
*
|
|
* o Redistributions in binary form must reproduce the above copyright notice, this
|
|
* list of conditions and the following disclaimer in the documentation and/or
|
|
* other materials provided with the distribution.
|
|
*
|
|
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "fsl_common.h"
|
|
#include "fsl_clock.h"
|
|
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
|
|
#if (defined(OSC) && !(defined(OSC0)))
|
|
#define OSC0 OSC
|
|
#endif
|
|
|
|
#define MCG_HIRC_FREQ (48000000U)
|
|
#define MCG_LIRC_FREQ1 (2000000U)
|
|
#define MCG_LIRC_FREQ2 (8000000U)
|
|
|
|
#define MCG_S_CLKST_VAL ((MCG->S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT)
|
|
#define MCG_SC_FCRDIV_VAL ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)
|
|
#define MCG_MC_LIRC_DIV2_VAL ((MCG->MC & MCG_MC_LIRC_DIV2_MASK) >> MCG_MC_LIRC_DIV2_SHIFT)
|
|
#define MCG_C2_IRCS_VAL ((MCG->C2 & MCG_C2_IRCS_MASK) >> MCG_C2_IRCS_SHIFT)
|
|
|
|
#define SIM_CLKDIV1_OUTDIV1_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
|
|
#define SIM_CLKDIV1_OUTDIV4_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)
|
|
#define SIM_SOPT1_OSC32KSEL_VAL ((SIM->SOPT1 & SIM_SOPT1_OSC32KSEL_MASK) >> SIM_SOPT1_OSC32KSEL_SHIFT)
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
|
|
/* External XTAL0 (OSC0) clock frequency. */
|
|
uint32_t g_xtal0Freq;
|
|
/* External XTAL32K clock frequency. */
|
|
uint32_t g_xtal32Freq;
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
|
|
/*!
|
|
* @brief Get the current MCG_Lite LIRC_CLK frequency in Hz.
|
|
*
|
|
* This function will return the LIRC_CLK value in frequency(Hz) based
|
|
* on current MCG_Lite configurations and settings. It is an internal function.
|
|
*
|
|
* @return MCG_Lite LIRC_CLK frequency.
|
|
*/
|
|
static uint32_t CLOCK_GetLircClkFreq(void);
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
|
|
static uint32_t CLOCK_GetLircClkFreq(void)
|
|
{
|
|
static const uint32_t lircFreqs[] = {MCG_LIRC_FREQ1, MCG_LIRC_FREQ2};
|
|
|
|
/* Check whether the LIRC is enabled. */
|
|
if ((MCG->C1 & MCG_C1_IRCLKEN_MASK) || (kMCGLITE_ClkSrcLirc == MCG_S_CLKST_VAL))
|
|
{
|
|
return lircFreqs[MCG_C2_IRCS_VAL];
|
|
}
|
|
else
|
|
{
|
|
return 0U;
|
|
}
|
|
}
|
|
|
|
uint32_t CLOCK_GetOsc0ErClkFreq(void)
|
|
{
|
|
if (OSC->CR & OSC_CR_ERCLKEN_MASK)
|
|
{
|
|
/* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
|
|
assert(g_xtal0Freq);
|
|
return g_xtal0Freq;
|
|
}
|
|
else
|
|
{
|
|
return 0U;
|
|
}
|
|
}
|
|
|
|
uint32_t CLOCK_GetEr32kClkFreq(void)
|
|
{
|
|
uint32_t freq;
|
|
|
|
switch (SIM_SOPT1_OSC32KSEL_VAL)
|
|
{
|
|
case 0U: /* OSC 32k clock */
|
|
freq = (CLOCK_GetOsc0ErClkFreq() == 32768U) ? 32768U : 0U;
|
|
break;
|
|
case 2U: /* RTC 32k clock */
|
|
/* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
|
|
assert(g_xtal32Freq);
|
|
freq = g_xtal32Freq;
|
|
break;
|
|
case 3U: /* LPO clock */
|
|
freq = LPO_CLK_FREQ;
|
|
break;
|
|
default:
|
|
freq = 0U;
|
|
break;
|
|
}
|
|
return freq;
|
|
}
|
|
|
|
uint32_t CLOCK_GetPlatClkFreq(void)
|
|
{
|
|
return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
|
|
}
|
|
|
|
uint32_t CLOCK_GetFlashClkFreq(void)
|
|
{
|
|
uint32_t freq;
|
|
|
|
freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
|
|
freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
|
|
|
|
return freq;
|
|
}
|
|
|
|
uint32_t CLOCK_GetBusClkFreq(void)
|
|
{
|
|
uint32_t freq;
|
|
|
|
freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
|
|
freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
|
|
|
|
return freq;
|
|
}
|
|
|
|
uint32_t CLOCK_GetCoreSysClkFreq(void)
|
|
{
|
|
return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
|
|
}
|
|
|
|
uint32_t CLOCK_GetFreq(clock_name_t clockName)
|
|
{
|
|
uint32_t freq;
|
|
|
|
switch (clockName)
|
|
{
|
|
case kCLOCK_CoreSysClk:
|
|
case kCLOCK_PlatClk:
|
|
freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
|
|
break;
|
|
case kCLOCK_BusClk:
|
|
case kCLOCK_FlashClk:
|
|
freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
|
|
freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
|
|
break;
|
|
case kCLOCK_Er32kClk:
|
|
freq = CLOCK_GetEr32kClkFreq();
|
|
break;
|
|
case kCLOCK_Osc0ErClk:
|
|
freq = CLOCK_GetOsc0ErClkFreq();
|
|
break;
|
|
case kCLOCK_McgInternalRefClk:
|
|
freq = CLOCK_GetInternalRefClkFreq();
|
|
break;
|
|
case kCLOCK_McgPeriphClk:
|
|
case kCLOCK_McgIrc48MClk:
|
|
freq = CLOCK_GetPeriphClkFreq();
|
|
break;
|
|
case kCLOCK_LpoClk:
|
|
freq = LPO_CLK_FREQ;
|
|
break;
|
|
default:
|
|
freq = 0U;
|
|
break;
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
|
|
void CLOCK_SetSimConfig(sim_clock_config_t const *config)
|
|
{
|
|
SIM->CLKDIV1 = config->clkdiv1;
|
|
CLOCK_SetEr32kClock(config->er32kSrc);
|
|
}
|
|
|
|
uint32_t CLOCK_GetInternalRefClkFreq(void)
|
|
{
|
|
uint8_t divider1 = MCG_SC_FCRDIV_VAL;
|
|
uint8_t divider2 = MCG_MC_LIRC_DIV2_VAL;
|
|
/* LIRC internal reference clock is selected*/
|
|
return CLOCK_GetLircClkFreq() >> (divider1 + divider2);
|
|
}
|
|
|
|
uint32_t CLOCK_GetPeriphClkFreq(void)
|
|
{
|
|
/* Check whether the HIRC is enabled. */
|
|
if ((MCG->MC & MCG_MC_HIRCEN_MASK) || (kMCGLITE_ClkSrcHirc == MCG_S_CLKST_VAL))
|
|
{
|
|
return MCG_HIRC_FREQ;
|
|
}
|
|
else
|
|
{
|
|
return 0U;
|
|
}
|
|
}
|
|
|
|
uint32_t CLOCK_GetOutClkFreq(void)
|
|
{
|
|
uint32_t freq;
|
|
|
|
switch (MCG_S_CLKST_VAL)
|
|
{
|
|
case kMCGLITE_ClkSrcHirc:
|
|
freq = MCG_HIRC_FREQ;
|
|
break;
|
|
case kMCGLITE_ClkSrcLirc:
|
|
freq = CLOCK_GetLircClkFreq() >> MCG_SC_FCRDIV_VAL;
|
|
break;
|
|
case kMCGLITE_ClkSrcExt:
|
|
/* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
|
|
assert(g_xtal0Freq);
|
|
freq = g_xtal0Freq;
|
|
break;
|
|
default:
|
|
freq = 0U;
|
|
break;
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
|
|
mcglite_mode_t CLOCK_GetMode(void)
|
|
{
|
|
mcglite_mode_t mode;
|
|
|
|
switch (MCG_S_CLKST_VAL)
|
|
{
|
|
case kMCGLITE_ClkSrcHirc: /* HIRC */
|
|
mode = kMCGLITE_ModeHirc48M;
|
|
break;
|
|
case kMCGLITE_ClkSrcLirc: /* LIRC */
|
|
if (kMCGLITE_Lirc2M == MCG_C2_IRCS_VAL)
|
|
{
|
|
mode = kMCGLITE_ModeLirc2M;
|
|
}
|
|
else
|
|
{
|
|
mode = kMCGLITE_ModeLirc8M;
|
|
}
|
|
break;
|
|
case kMCGLITE_ClkSrcExt: /* EXT */
|
|
mode = kMCGLITE_ModeExt;
|
|
break;
|
|
default:
|
|
mode = kMCGLITE_ModeError;
|
|
break;
|
|
}
|
|
|
|
return mode;
|
|
}
|
|
|
|
status_t CLOCK_SetMcgliteConfig(mcglite_config_t const *targetConfig)
|
|
{
|
|
assert(targetConfig);
|
|
|
|
/*
|
|
* If switch between LIRC8M and LIRC2M, need to switch to HIRC mode first,
|
|
* because could not switch directly.
|
|
*/
|
|
if ((kMCGLITE_ClkSrcLirc == MCG_S_CLKST_VAL) && (kMCGLITE_ClkSrcLirc == targetConfig->outSrc) &&
|
|
(MCG_C2_IRCS_VAL != targetConfig->ircs))
|
|
{
|
|
MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCGLITE_ClkSrcHirc);
|
|
while (kMCGLITE_ClkSrcHirc != MCG_S_CLKST_VAL)
|
|
{
|
|
}
|
|
}
|
|
|
|
/* Set configuration now. */
|
|
MCG->SC = MCG_SC_FCRDIV(targetConfig->fcrdiv);
|
|
MCG->MC = MCG_MC_HIRCEN(targetConfig->hircEnableInNotHircMode) | MCG_MC_LIRC_DIV2(targetConfig->lircDiv2);
|
|
MCG->C2 = (MCG->C2 & ~MCG_C2_IRCS_MASK) | MCG_C2_IRCS(targetConfig->ircs);
|
|
MCG->C1 = MCG_C1_CLKS(targetConfig->outSrc) | targetConfig->irclkEnableMode;
|
|
|
|
/*
|
|
* If external oscillator used and MCG_Lite is set to EXT mode, need to
|
|
* wait for the OSC stable.
|
|
*/
|
|
if ((MCG->C2 & MCG_C2_EREFS0_MASK) && (kMCGLITE_ClkSrcExt == targetConfig->outSrc))
|
|
{
|
|
while (!(MCG->S & MCG_S_OSCINIT0_MASK))
|
|
{
|
|
}
|
|
}
|
|
|
|
/* Wait for clock source change completed. */
|
|
while (targetConfig->outSrc != MCG_S_CLKST_VAL)
|
|
{
|
|
}
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
void CLOCK_InitOsc0(osc_config_t const *config)
|
|
{
|
|
OSC_SetCapLoad(OSC0, config->capLoad);
|
|
OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig);
|
|
|
|
MCG->C2 = ((MCG->C2 & MCG_C2_IRCS_MASK) | (uint8_t)config->workMode);
|
|
|
|
if ((kOSC_ModeExt != config->workMode) && (OSC0->CR & OSC_CR_ERCLKEN_MASK))
|
|
{
|
|
/* Wait for stable. */
|
|
while (!(MCG->S & MCG_S_OSCINIT0_MASK))
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
void CLOCK_DeinitOsc0(void)
|
|
{
|
|
OSC0->CR = 0U;
|
|
MCG->C2 &= MCG_C2_IRCS_MASK;
|
|
}
|