added prescaler for 16 bit pwm in LPC1347 target
Fork of mbed-dev by
Diff: targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL43Z/drivers/fsl_clock.c
- Revision:
- 144:ef7eb2e8f9f7
diff -r 423e1876dc07 -r ef7eb2e8f9f7 targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL43Z/drivers/fsl_clock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL43Z/drivers/fsl_clock.c Fri Sep 02 15:07:44 2016 +0100 @@ -0,0 +1,408 @@ +/* + * 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); + +/*! + * @brief Get RANGE value based on OSC frequency. + * + * To setup external crystal oscillator, must set the register bits RANGE base + * on the crystal frequency. This function returns the RANGE base on the input + * frequency. This is an internal function. + * + * @return RANGE value. + */ +static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq); + +/******************************************************************************* + * 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; + } +} + +static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq) +{ + uint8_t range; + + if (freq <= 39063U) + { + range = 0U; + } + else if (freq <= 8000000U) + { + range = 1U; + } + else + { + range = 2U; + } + + return range; +} + +uint32_t CLOCK_GetOsc0ErClkFreq(void) +{ + if (OSC0->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); +} + +bool CLOCK_EnableUsbfs0Clock(clock_usb_src_t src, uint32_t freq) +{ + bool ret = true; + + CLOCK_DisableClock(kCLOCK_Usbfs0); + + if (kCLOCK_UsbSrcExt == src) + { + SIM->SOPT2 &= ~SIM_SOPT2_USBSRC_MASK; + } + else + { + SIM->SOPT2 |= SIM_SOPT2_USBSRC_MASK; + } + + CLOCK_EnableClock(kCLOCK_Usbfs0); + + if (kCLOCK_UsbSrcIrc48M == src) + { + USB0->CLK_RECOVER_IRC_EN = 0x03U; + USB0->CLK_RECOVER_CTRL |= USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK; + } + + return ret; +} + +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) +{ + uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq); + + OSC_SetCapLoad(OSC0, config->capLoad); + OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig); + + MCG->C2 = ((MCG->C2 & MCG_C2_IRCS_MASK) | MCG_C2_RANGE0(range) | (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; +}