--- /dev/null
+/***************************************************************************//**\r
+ * @file em_cmu.c\r
+ * @brief Clock management unit (CMU) Peripheral API\r
+ * @version 4.0.0\r
+ *******************************************************************************\r
+ * @section License\r
+ * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>\r
+ *******************************************************************************\r
+ *\r
+ * Permission is granted to anyone to use this software for any purpose,\r
+ * including commercial applications, and to alter it and redistribute it\r
+ * freely, subject to the following restrictions:\r
+ *\r
+ * 1. The origin of this software must not be misrepresented; you must not\r
+ * claim that you wrote the original software.\r
+ * 2. Altered source versions must be plainly marked as such, and must not be\r
+ * misrepresented as being the original software.\r
+ * 3. This notice may not be removed or altered from any source distribution.\r
+ *\r
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no\r
+ * obligation to support this Software. Silicon Labs is providing the\r
+ * Software "AS IS", with no express or implied warranties of any kind,\r
+ * including, but not limited to, any implied warranties of merchantability\r
+ * or fitness for any particular purpose or warranties against infringement\r
+ * of any proprietary rights of a third party.\r
+ *\r
+ * Silicon Labs will not be liable for any consequential, incidental, or\r
+ * special damages, or any other relief, or for any claim by any third party,\r
+ * arising from your use of this Software.\r
+ *\r
+ ******************************************************************************/\r
+\r
+\r
+#include "em_cmu.h"\r
+#if defined( CMU_PRESENT )\r
+\r
+#include "em_assert.h"\r
+#include "em_bitband.h"\r
+#include "em_emu.h"\r
+\r
+/***************************************************************************//**\r
+ * @addtogroup EM_Library\r
+ * @{\r
+ ******************************************************************************/\r
+\r
+/***************************************************************************//**\r
+ * @addtogroup CMU\r
+ * @brief Clock management unit (CMU) Peripheral API\r
+ * @{\r
+ ******************************************************************************/\r
+\r
+/*******************************************************************************\r
+ ****************************** DEFINES ************************************\r
+ ******************************************************************************/\r
+\r
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */\r
+\r
+/** Maximum allowed core frequency when using 0 wait states on flash access. */\r
+#define CMU_MAX_FREQ_0WS 16000000\r
+/** Maximum allowed core frequency when using 1 wait states on flash access */\r
+#define CMU_MAX_FREQ_1WS 32000000\r
+\r
+#if defined( CMU_CTRL_HFLE )\r
+/** Maximum frequency for HFLE needs to be enabled on Giant, Leopard and\r
+ Wonder. */\r
+#if defined ( _EFM32_WONDER_FAMILY ) || \\r
+ defined ( _EZR32_LEOPARD_FAMILY ) || \\r
+ defined ( _EZR32_WONDER_FAMILY )\r
+#define CMU_MAX_FREQ_HFLE 24000000\r
+#elif defined ( _EFM32_GIANT_FAMILY )\r
+#define CMU_MAX_FREQ_HFLE (CMU_MaxFreqHfle())\r
+#else\r
+#error Invalid part/device.\r
+#endif\r
+#endif\r
+\r
+/** Low frequency A group identifier */\r
+#define CMU_LFA 0\r
+\r
+/** Low frequency B group identifier */\r
+#define CMU_LFB 1\r
+\r
+/** @endcond */\r
+\r
+/*******************************************************************************\r
+ ************************** LOCAL FUNCTIONS ********************************\r
+ ******************************************************************************/\r
+\r
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */\r
+\r
+#if defined( CMU_CTRL_HFLE ) && \\r
+ !defined ( _EFM32_WONDER_FAMILY ) && \\r
+ !defined ( _EZR32_LEOPARD_FAMILY ) && \\r
+ !defined ( _EZR32_WONDER_FAMILY )\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Return max allowed frequency for low energy peripherals.\r
+ ******************************************************************************/\r
+static uint32_t CMU_MaxFreqHfle(void)\r
+{\r
+ /* SYSTEM_GetFamily and SYSTEM_ChipRevisionGet could have been used here\r
+ but we want to minimize dependencies in em_cmu.c. */\r
+ uint16_t majorMinorRev;\r
+ uint8_t deviceFamily = ((DEVINFO->PART & _DEVINFO_PART_DEVICE_FAMILY_MASK)\r
+ >> _DEVINFO_PART_DEVICE_FAMILY_SHIFT);\r
+ switch (deviceFamily)\r
+ {\r
+ case _DEVINFO_PART_DEVICE_FAMILY_LG:\r
+ /* CHIP MAJOR bit [3:0] */\r
+ majorMinorRev = (((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)\r
+ >> _ROMTABLE_PID0_REVMAJOR_SHIFT) << 8);\r
+ /* CHIP MINOR bit [7:4] */\r
+ majorMinorRev |= (((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)\r
+ >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4);\r
+ /* CHIP MINOR bit [3:0] */\r
+ majorMinorRev |= ((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)\r
+ >> _ROMTABLE_PID3_REVMINORLSB_SHIFT);\r
+\r
+ if (majorMinorRev >= 0x0204)\r
+ return 24000000;\r
+ else\r
+ return 32000000;\r
+ case _DEVINFO_PART_DEVICE_FAMILY_GG:\r
+ return 32000000;\r
+ case _DEVINFO_PART_DEVICE_FAMILY_WG:\r
+ return 24000000;\r
+ default:\r
+ /* Invalid device family. */\r
+ EFM_ASSERT(false);\r
+ return 0;\r
+ }\r
+}\r
+#endif\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Configure flash access wait states in order to support given core clock\r
+ * frequency.\r
+ *\r
+ * @param[in] hfcoreclk\r
+ * Core clock frequency to configure flash wait-states for\r
+ ******************************************************************************/\r
+static void CMU_FlashWaitStateControl(uint32_t hfcoreclk)\r
+{\r
+ uint32_t mode;\r
+ bool mscLocked;\r
+#if defined( MSC_READCTRL_MODE_WS0SCBTP )\r
+ bool scbtpEn;\r
+#endif\r
+\r
+ /* Make sure the MSC is unlocked */\r
+ mscLocked = MSC->LOCK;\r
+ MSC->LOCK = MSC_UNLOCK_CODE;\r
+\r
+ /* Get mode and SCBTP enable */\r
+ mode = MSC->READCTRL & _MSC_READCTRL_MODE_MASK;\r
+#if defined( MSC_READCTRL_MODE_WS0SCBTP )\r
+ switch(mode)\r
+ {\r
+ case MSC_READCTRL_MODE_WS0:\r
+ case MSC_READCTRL_MODE_WS1:\r
+#if defined( MSC_READCTRL_MODE_WS2 )\r
+ case MSC_READCTRL_MODE_WS2:\r
+#endif\r
+ scbtpEn = false;\r
+ break;\r
+\r
+ default: /* WSxSCBTP */\r
+ scbtpEn = true;\r
+ break;\r
+ }\r
+#endif\r
+\r
+\r
+ /* Set mode based on the core clock frequency and SCBTP enable */\r
+#if defined( MSC_READCTRL_MODE_WS0SCBTP )\r
+ if (false)\r
+ {\r
+ }\r
+#if defined( MSC_READCTRL_MODE_WS2 )\r
+ else if (hfcoreclk > CMU_MAX_FREQ_1WS)\r
+ {\r
+ mode = (scbtpEn ? MSC_READCTRL_MODE_WS2SCBTP : MSC_READCTRL_MODE_WS2);\r
+ }\r
+#endif\r
+ else if ((hfcoreclk <= CMU_MAX_FREQ_1WS) && (hfcoreclk > CMU_MAX_FREQ_0WS))\r
+ {\r
+ mode = (scbtpEn ? MSC_READCTRL_MODE_WS1SCBTP : MSC_READCTRL_MODE_WS1);\r
+ }\r
+ else\r
+ {\r
+ mode = (scbtpEn ? MSC_READCTRL_MODE_WS0SCBTP : MSC_READCTRL_MODE_WS0);\r
+ }\r
+\r
+#else /* If MODE and SCBTP is in separate register fields */\r
+\r
+ if (false)\r
+ {\r
+ }\r
+#if defined( MSC_READCTRL_MODE_WS2 )\r
+ else if (hfcoreclk > CMU_MAX_FREQ_1WS)\r
+ {\r
+ mode = MSC_READCTRL_MODE_WS2;\r
+ }\r
+#endif\r
+ else if ((hfcoreclk <= CMU_MAX_FREQ_1WS) && (hfcoreclk > CMU_MAX_FREQ_0WS))\r
+ {\r
+ mode = MSC_READCTRL_MODE_WS1;\r
+ }\r
+ else\r
+ {\r
+ mode = MSC_READCTRL_MODE_WS0;\r
+ }\r
+#endif\r
+\r
+ /* BUS_RegMaskedWrite cannot be used here as it would temporarely set the\r
+ mode field to WS0 */\r
+ MSC->READCTRL = (MSC->READCTRL &~_MSC_READCTRL_MODE_MASK) | mode;\r
+\r
+ if (mscLocked)\r
+ {\r
+ MSC->LOCK = 0;\r
+ }\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Configure flash access wait states to most conservative setting for\r
+ * this target. Retain SCBTP setting.\r
+ ******************************************************************************/\r
+static void CMU_FlashWaitStateMax(void)\r
+{\r
+ uint32_t maxCoreClock;\r
+#if defined (_EFM32_GECKO_FAMILY)\r
+ maxCoreClock = 32000000;\r
+#elif defined (_EFM32_GIANT_FAMILY)\r
+ maxCoreClock = 48000000;\r
+#elif defined (_EFM32_TINY_FAMILY)\r
+ maxCoreClock = 32000000;\r
+#elif defined (_EFM32_LEOPARD_FAMILY)\r
+ maxCoreClock = 48000000;\r
+#elif defined (_EFM32_WONDER_FAMILY)\r
+ maxCoreClock = 48000000;\r
+#elif defined (_EFM32_ZERO_FAMILY)\r
+ maxCoreClock = 24000000;\r
+#elif defined (_EFM32_HAPPY_FAMILY)\r
+ maxCoreClock = 25000000;\r
+#else\r
+#error "Max core clock frequency is not defined for this family"\r
+#endif\r
+\r
+ /* Use SystemMaxCoreClockGet() when available in CMSIS */\r
+ CMU_FlashWaitStateControl(maxCoreClock);\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief Convert dividend to prescaler logarithmic value. Only works for even\r
+ * numbers equal to 2^n\r
+ * @param[in] div Unscaled dividend,\r
+ * @return Base 2 logarithm of input, as used by fixed prescalers\r
+ ******************************************************************************/\r
+__STATIC_INLINE uint32_t CMU_DivToLog2(CMU_ClkDiv_TypeDef div)\r
+{\r
+ uint32_t log2;\r
+\r
+ /* Prescalers take argument of 32768 or less */\r
+ EFM_ASSERT((div>0) && (div <= 32768));\r
+\r
+ /* Count leading zeroes and "reverse" result, Cortex-M3 intrinsic */\r
+ log2 = (31 - __CLZ(div));\r
+\r
+ return log2;\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief Convert logarithm of 2 prescaler to division factor\r
+ * @param[in] log2\r
+ * @return Dividend\r
+ ******************************************************************************/\r
+__STATIC_INLINE uint32_t CMU_Log2ToDiv(uint32_t log2)\r
+{\r
+ return 1<<log2;\r
+}\r
+\r
+\r
+#if defined(USB_PRESENT)\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get the USBC frequency\r
+ *\r
+ * @return\r
+ * USBC frequency in Hz\r
+ ******************************************************************************/\r
+static uint32_t CMU_USBCClkGet(void)\r
+{\r
+ uint32_t ret;\r
+ CMU_Select_TypeDef clk;\r
+\r
+ /* Get selected clock source */\r
+ clk = CMU_ClockSelectGet(cmuClock_USBC);\r
+\r
+ switch(clk)\r
+ {\r
+ case cmuSelect_LFXO:\r
+ ret = SystemLFXOClockGet();\r
+ break;\r
+ case cmuSelect_LFRCO:\r
+ ret = SystemLFRCOClockGet();\r
+ break;\r
+ case cmuSelect_HFCLK:\r
+ ret = SystemHFClockGet();\r
+ break;\r
+ default:\r
+ /* Clock is not enabled */\r
+ ret = 0;\r
+ break;\r
+ }\r
+ return ret;\r
+}\r
+#endif\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get the AUX clock frequency. Used by MSC flash programming and LESENSE,\r
+ * by default also as debug clock.\r
+ *\r
+ * @return\r
+ * AUX Frequency in Hz\r
+ ******************************************************************************/\r
+static uint32_t CMU_AUXClkGet(void)\r
+{\r
+ uint32_t ret;\r
+\r
+#if defined(_EFM32_GECKO_FAMILY)\r
+ /* Gecko has a fixed 14Mhz AUXHFRCO clock */\r
+ ret = 14000000;\r
+#else\r
+ switch(CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_BAND_MASK)\r
+ {\r
+ case CMU_AUXHFRCOCTRL_BAND_1MHZ:\r
+ ret = 1000000;\r
+ break;\r
+ case CMU_AUXHFRCOCTRL_BAND_7MHZ:\r
+ ret = 7000000;\r
+ break;\r
+ case CMU_AUXHFRCOCTRL_BAND_11MHZ:\r
+ ret = 11000000;\r
+ break;\r
+ case CMU_AUXHFRCOCTRL_BAND_14MHZ:\r
+ ret = 14000000;\r
+ break;\r
+ case CMU_AUXHFRCOCTRL_BAND_21MHZ:\r
+ ret = 21000000;\r
+ break;\r
+#if defined( _CMU_AUXHFRCOCTRL_BAND_28MHZ )\r
+ case CMU_AUXHFRCOCTRL_BAND_28MHZ:\r
+ ret = 28000000;\r
+ break;\r
+#endif\r
+ default:\r
+ ret = 0;\r
+ break;\r
+ }\r
+#endif\r
+ return ret;\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get the Debug Trace clock frequency\r
+ *\r
+ * @return\r
+ * Debug Trace frequency in Hz\r
+ ******************************************************************************/\r
+static uint32_t CMU_DBGClkGet(void)\r
+{\r
+ uint32_t ret;\r
+ CMU_Select_TypeDef clk;\r
+\r
+ /* Get selected clock source */\r
+ clk = CMU_ClockSelectGet(cmuClock_DBG);\r
+\r
+ switch(clk)\r
+ {\r
+ case cmuSelect_HFCLK:\r
+ ret = SystemHFClockGet();\r
+#if defined( _CMU_CTRL_HFCLKDIV_MASK )\r
+ /* Giant Gecko has an additional divider, not used by USBC */\r
+ ret = ret / (1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK) >>\r
+ _CMU_CTRL_HFCLKDIV_SHIFT));\r
+#endif\r
+ break;\r
+\r
+ case cmuSelect_AUXHFRCO:\r
+ ret = CMU_AUXClkGet();\r
+ break;\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ ret = 0;\r
+ break;\r
+ }\r
+ return ret;\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get the LFnCLK frequency based on current configuration.\r
+ *\r
+ * @param[in] lfClkBranch\r
+ * LF branch, 0 = LFA, 1 = LFB, ...\r
+ *\r
+ * @return\r
+ * The LFnCLK frequency in Hz. If no LFnCLK is selected (disabled), 0 is\r
+ * returned.\r
+ ******************************************************************************/\r
+static uint32_t CMU_LFClkGet(unsigned int lfClkBranch)\r
+{\r
+ uint32_t ret;\r
+\r
+ EFM_ASSERT(lfClkBranch == CMU_LFA || lfClkBranch == CMU_LFB);\r
+\r
+ switch ((CMU->LFCLKSEL >> (lfClkBranch * 2)) & 0x3)\r
+ {\r
+ case _CMU_LFCLKSEL_LFA_LFRCO:\r
+ ret = SystemLFRCOClockGet();\r
+ break;\r
+\r
+ case _CMU_LFCLKSEL_LFA_LFXO:\r
+ ret = SystemLFXOClockGet();\r
+ break;\r
+\r
+ case _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2:\r
+#if defined( CMU_CTRL_HFLE )\r
+ /* Giant Gecko can use a /4 divider (and must if >32MHz) or HFLE is set */\r
+ if(((CMU->HFCORECLKDIV & _CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK) == CMU_HFCORECLKDIV_HFCORECLKLEDIV_DIV4)||\r
+ (CMU->CTRL & CMU_CTRL_HFLE))\r
+ {\r
+ ret = SystemCoreClockGet() / 4;\r
+ }\r
+ else\r
+ {\r
+ ret = SystemCoreClockGet() / 2;\r
+ }\r
+#else\r
+ ret = SystemCoreClockGet() / 2;\r
+#endif\r
+ break;\r
+\r
+ case _CMU_LFCLKSEL_LFA_DISABLED:\r
+#if defined( CMU_LFCLKSEL_LFAE )\r
+ /* Check LF Extended bit setting for ULFRCO clock */\r
+ if(CMU->LFCLKSEL >> (_CMU_LFCLKSEL_LFAE_SHIFT + lfClkBranch * 4))\r
+ {\r
+ ret = SystemULFRCOClockGet();\r
+ }\r
+ else\r
+ {\r
+ ret = 0;\r
+ }\r
+#else\r
+ ret = 0;\r
+#endif\r
+ break;\r
+\r
+ default:\r
+ ret = 0;\r
+ break;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Wait for ongoing sync of register(s) to low frequency domain to complete.\r
+ *\r
+ * @param[in] mask\r
+ * Bitmask corresponding to SYNCBUSY register defined bits, indicating\r
+ * registers that must complete any ongoing synchronization.\r
+ ******************************************************************************/\r
+__STATIC_INLINE void CMU_Sync(uint32_t mask)\r
+{\r
+ /* Avoid deadlock if modifying the same register twice when freeze mode is */\r
+ /* activated. */\r
+ if (CMU->FREEZE & CMU_FREEZE_REGFREEZE)\r
+ return;\r
+\r
+ /* Wait for any pending previous write operation to have been completed */\r
+ /* in low frequency domain */\r
+ while (CMU->SYNCBUSY & mask)\r
+ ;\r
+}\r
+\r
+\r
+/** @endcond */\r
+\r
+/*******************************************************************************\r
+ ************************** GLOBAL FUNCTIONS *******************************\r
+ ******************************************************************************/\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Calibrate clock.\r
+ *\r
+ * @details\r
+ * Run a calibration for HFCLK against a selectable reference clock. Please\r
+ * refer to the EFM32 reference manual, CMU chapter, for further details.\r
+ *\r
+ * @note\r
+ * This function will not return until calibration measurement is completed.\r
+ *\r
+ * @param[in] HFCycles\r
+ * The number of HFCLK cycles to run calibration. Increasing this number\r
+ * increases precision, but the calibration will take more time.\r
+ *\r
+ * @param[in] ref\r
+ * The reference clock used to compare HFCLK with.\r
+ *\r
+ * @return\r
+ * The number of ticks the reference clock after HFCycles ticks on the HF\r
+ * clock.\r
+ ******************************************************************************/\r
+uint32_t CMU_Calibrate(uint32_t HFCycles, CMU_Osc_TypeDef ref)\r
+{\r
+ EFM_ASSERT(HFCycles <= (_CMU_CALCNT_CALCNT_MASK >> _CMU_CALCNT_CALCNT_SHIFT));\r
+\r
+ /* Set reference clock source */\r
+ switch (ref)\r
+ {\r
+ case cmuOsc_LFXO:\r
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_LFXO;\r
+ break;\r
+\r
+ case cmuOsc_LFRCO:\r
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_LFRCO;\r
+ break;\r
+\r
+ case cmuOsc_HFXO:\r
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_HFXO;\r
+ break;\r
+\r
+ case cmuOsc_HFRCO:\r
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_HFRCO;\r
+ break;\r
+\r
+ case cmuOsc_AUXHFRCO:\r
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_AUXHFRCO;\r
+ break;\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ return 0;\r
+ }\r
+\r
+ /* Set top value */\r
+ CMU->CALCNT = HFCycles;\r
+\r
+ /* Start calibration */\r
+ CMU->CMD = CMU_CMD_CALSTART;\r
+\r
+ /* Wait until calibration completes */\r
+ while (CMU->STATUS & CMU_STATUS_CALBSY)\r
+ ;\r
+\r
+ return CMU->CALCNT;\r
+}\r
+\r
+\r
+#if defined( _CMU_CALCTRL_UPSEL_MASK ) && defined( _CMU_CALCTRL_DOWNSEL_MASK )\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Configure clock calibration\r
+ *\r
+ * @details\r
+ * Configure a calibration for a selectable clock source against another\r
+ * selectable reference clock.\r
+ * Refer to the EFM32 reference manual, CMU chapter, for further details.\r
+ *\r
+ * @note\r
+ * After configuration, a call to CMU_CalibrateStart() is required, and\r
+ * the resulting calibration value can be read out with the\r
+ * CMU_CalibrateCountGet() function call.\r
+ *\r
+ * @param[in] downCycles\r
+ * The number of downSel clock cycles to run calibration. Increasing this\r
+ * number increases precision, but the calibration will take more time.\r
+ *\r
+ * @param[in] downSel\r
+ * The clock which will be counted down downCycles\r
+ *\r
+ * @param[in] upSel\r
+ * The reference clock, the number of cycles generated by this clock will\r
+ * be counted and added up, the result can be given with the\r
+ * CMU_CalibrateCountGet() function call.\r
+ ******************************************************************************/\r
+void CMU_CalibrateConfig(uint32_t downCycles, CMU_Osc_TypeDef downSel,\r
+ CMU_Osc_TypeDef upSel)\r
+{\r
+ /* Keep untouched configuration settings */\r
+ uint32_t calCtrl = CMU->CALCTRL & ~(_CMU_CALCTRL_UPSEL_MASK | _CMU_CALCTRL_DOWNSEL_MASK);\r
+\r
+ /* 20 bits of precision to calibration count register */\r
+ EFM_ASSERT(downCycles <= (_CMU_CALCNT_CALCNT_MASK >> _CMU_CALCNT_CALCNT_SHIFT));\r
+\r
+ /* Set down counting clock source - down counter */\r
+ switch (downSel)\r
+ {\r
+ case cmuOsc_LFXO:\r
+ calCtrl |= CMU_CALCTRL_DOWNSEL_LFXO;\r
+ break;\r
+\r
+ case cmuOsc_LFRCO:\r
+ calCtrl |= CMU_CALCTRL_DOWNSEL_LFRCO;\r
+ break;\r
+\r
+ case cmuOsc_HFXO:\r
+ calCtrl |= CMU_CALCTRL_DOWNSEL_HFXO;\r
+ break;\r
+\r
+ case cmuOsc_HFRCO:\r
+ calCtrl |= CMU_CALCTRL_DOWNSEL_HFRCO;\r
+ break;\r
+\r
+ case cmuOsc_AUXHFRCO:\r
+ calCtrl |= CMU_CALCTRL_DOWNSEL_AUXHFRCO;\r
+ break;\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ break;\r
+ }\r
+\r
+ /* Set top value to be counted down by the downSel clock */\r
+ CMU->CALCNT = downCycles;\r
+\r
+ /* Set reference clock source - up counter */\r
+ switch (upSel)\r
+ {\r
+ case cmuOsc_LFXO:\r
+ calCtrl |= CMU_CALCTRL_UPSEL_LFXO;\r
+ break;\r
+\r
+ case cmuOsc_LFRCO:\r
+ calCtrl |= CMU_CALCTRL_UPSEL_LFRCO;\r
+ break;\r
+\r
+ case cmuOsc_HFXO:\r
+ calCtrl |= CMU_CALCTRL_UPSEL_HFXO;\r
+ break;\r
+\r
+ case cmuOsc_HFRCO:\r
+ calCtrl |= CMU_CALCTRL_UPSEL_HFRCO;\r
+ break;\r
+\r
+ case cmuOsc_AUXHFRCO:\r
+ calCtrl |= CMU_CALCTRL_UPSEL_AUXHFRCO;\r
+ break;\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ break;\r
+ }\r
+\r
+ CMU->CALCTRL = calCtrl;\r
+}\r
+#endif\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get clock divisor/prescaler.\r
+ *\r
+ * @param[in] clock\r
+ * Clock point to get divisor/prescaler for. Notice that not all clock points\r
+ * have a divisor/prescaler. Please refer to CMU overview in reference manual.\r
+ *\r
+ * @return\r
+ * The current clock point divisor/prescaler. 1 is returned\r
+ * if @p clock specifies a clock point without a divisor/prescaler.\r
+ ******************************************************************************/\r
+CMU_ClkDiv_TypeDef CMU_ClockDivGet(CMU_Clock_TypeDef clock)\r
+{\r
+ uint32_t divReg;\r
+ CMU_ClkDiv_TypeDef ret;\r
+\r
+ /* Get divisor reg id */\r
+ divReg = (clock >> CMU_DIV_REG_POS) & CMU_DIV_REG_MASK;\r
+\r
+ switch (divReg)\r
+ {\r
+#if defined( _CMU_CTRL_HFCLKDIV_MASK )\r
+ case CMU_HFCLKDIV_REG:\r
+ ret = 1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK) >>\r
+ _CMU_CTRL_HFCLKDIV_SHIFT);\r
+ break;\r
+#endif\r
+\r
+ case CMU_HFPERCLKDIV_REG:\r
+ ret = (CMU_ClkDiv_TypeDef)((CMU->HFPERCLKDIV &\r
+ _CMU_HFPERCLKDIV_HFPERCLKDIV_MASK) >>\r
+ _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT);\r
+ ret = CMU_Log2ToDiv(ret);\r
+ break;\r
+\r
+ case CMU_HFCORECLKDIV_REG:\r
+ ret = (CMU_ClkDiv_TypeDef)((CMU->HFCORECLKDIV &\r
+ _CMU_HFCORECLKDIV_HFCORECLKDIV_MASK) >>\r
+ _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT);\r
+ ret = CMU_Log2ToDiv(ret);\r
+ break;\r
+\r
+ case CMU_LFAPRESC0_REG:\r
+ switch (clock)\r
+ {\r
+ case cmuClock_RTC:\r
+ ret = (CMU_ClkDiv_TypeDef)(((CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK) >>\r
+ _CMU_LFAPRESC0_RTC_SHIFT));\r
+ ret = CMU_Log2ToDiv(ret);\r
+ break;\r
+\r
+#if defined(_CMU_LFAPRESC0_LETIMER0_MASK)\r
+ case cmuClock_LETIMER0:\r
+ ret = (CMU_ClkDiv_TypeDef)(((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK) >>\r
+ _CMU_LFAPRESC0_LETIMER0_SHIFT));\r
+ ret = CMU_Log2ToDiv(ret);\r
+ break;\r
+#endif\r
+\r
+#if defined(_CMU_LFAPRESC0_LCD_MASK)\r
+ case cmuClock_LCDpre:\r
+ ret = (CMU_ClkDiv_TypeDef)(((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK) >>\r
+ _CMU_LFAPRESC0_LCD_SHIFT) + CMU_DivToLog2(cmuClkDiv_16));\r
+ ret = CMU_Log2ToDiv(ret);\r
+ break;\r
+#endif\r
+\r
+#if defined(_CMU_LFAPRESC0_LESENSE_MASK)\r
+ case cmuClock_LESENSE:\r
+ ret = (CMU_ClkDiv_TypeDef)(((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK) >>\r
+ _CMU_LFAPRESC0_LESENSE_SHIFT));\r
+ ret = CMU_Log2ToDiv(ret);\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ ret = cmuClkDiv_1;\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case CMU_LFBPRESC0_REG:\r
+ switch (clock)\r
+ {\r
+#if defined(_CMU_LFBPRESC0_LEUART0_MASK)\r
+ case cmuClock_LEUART0:\r
+ ret = (CMU_ClkDiv_TypeDef)(((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK) >>\r
+ _CMU_LFBPRESC0_LEUART0_SHIFT));\r
+ ret = CMU_Log2ToDiv(ret);\r
+ break;\r
+#endif\r
+\r
+#if defined(_CMU_LFBPRESC0_LEUART1_MASK)\r
+ case cmuClock_LEUART1:\r
+ ret = (CMU_ClkDiv_TypeDef)(((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK) >>\r
+ _CMU_LFBPRESC0_LEUART1_SHIFT));\r
+ ret = CMU_Log2ToDiv(ret);\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ ret = cmuClkDiv_1;\r
+ break;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ ret = cmuClkDiv_1;\r
+ break;\r
+ }\r
+\r
+ return(ret);\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Set clock divisor/prescaler.\r
+ *\r
+ * @note\r
+ * If setting a LF clock prescaler, synchronization into the low frequency\r
+ * domain is required. If the same register is modified before a previous\r
+ * update has completed, this function will stall until the previous\r
+ * synchronization has completed. Please refer to CMU_FreezeEnable() for\r
+ * a suggestion on how to reduce stalling time in some use cases.\r
+ *\r
+ * @param[in] clock\r
+ * Clock point to set divisor/prescaler for. Notice that not all clock points\r
+ * have a divisor/prescaler, please refer to CMU overview in the reference\r
+ * manual.\r
+ *\r
+ * @param[in] div\r
+ * The clock divisor to use (<= cmuClkDiv_512).\r
+ ******************************************************************************/\r
+void CMU_ClockDivSet(CMU_Clock_TypeDef clock, CMU_ClkDiv_TypeDef div)\r
+{\r
+ uint32_t freq;\r
+ uint32_t divReg;\r
+\r
+ /* Get divisor reg id */\r
+ divReg = (clock >> CMU_DIV_REG_POS) & CMU_DIV_REG_MASK;\r
+\r
+ switch (divReg)\r
+ {\r
+#if defined( _CMU_CTRL_HFCLKDIV_MASK )\r
+ case CMU_HFCLKDIV_REG:\r
+ EFM_ASSERT((div>=cmuClkDiv_1) && (div<=cmuClkDiv_8));\r
+\r
+ /* Configure worst case wait states for flash access before setting divisor */\r
+ CMU_FlashWaitStateMax();\r
+\r
+ /* Set divider */\r
+ CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFCLKDIV_MASK) |\r
+ ((div-1) << _CMU_CTRL_HFCLKDIV_SHIFT);\r
+\r
+ /* Update CMSIS core clock variable */\r
+ /* (The function will update the global variable) */\r
+ freq = SystemCoreClockGet();\r
+\r
+ /* Optimize flash access wait state setting for current core clk */\r
+ CMU_FlashWaitStateControl(freq);\r
+ break;\r
+#endif\r
+\r
+ case CMU_HFPERCLKDIV_REG:\r
+ EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_512));\r
+ /* Convert to correct scale */\r
+ div = CMU_DivToLog2(div);\r
+ CMU->HFPERCLKDIV = (CMU->HFPERCLKDIV & ~_CMU_HFPERCLKDIV_HFPERCLKDIV_MASK) |\r
+ (div << _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT);\r
+ break;\r
+\r
+ case CMU_HFCORECLKDIV_REG:\r
+ EFM_ASSERT(div <= cmuClkDiv_512);\r
+\r
+ /* Configure worst case wait states for flash access before setting divisor */\r
+ CMU_FlashWaitStateMax();\r
+\r
+#if defined( CMU_CTRL_HFLE )\r
+ /* Clear HFLE and set DIV2 factor for peripheral clock\r
+ when running at frequencies lower than or equal to CMU_MAX_FREQ_HFLE. */\r
+ if ((CMU_ClockFreqGet(cmuClock_HF) / div) <= CMU_MAX_FREQ_HFLE)\r
+ {\r
+ /* Clear CMU HFLE */\r
+ BITBAND_Peripheral(&(CMU->CTRL), _CMU_CTRL_HFLE_SHIFT, 0);\r
+\r
+ /* Set DIV2 factor for peripheral clock */\r
+ BITBAND_Peripheral(&(CMU->HFCORECLKDIV),\r
+ _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 0);\r
+ }\r
+ else\r
+ {\r
+ /* Set CMU HFLE */\r
+ BITBAND_Peripheral(&(CMU->CTRL), _CMU_CTRL_HFLE_SHIFT, 1);\r
+\r
+ /* Set DIV4 factor for peripheral clock */\r
+ BITBAND_Peripheral(&(CMU->HFCORECLKDIV),\r
+ _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 1);\r
+ }\r
+#endif\r
+\r
+ /* Convert to correct scale */\r
+ div = CMU_DivToLog2(div);\r
+\r
+ CMU->HFCORECLKDIV = (CMU->HFCORECLKDIV & ~_CMU_HFCORECLKDIV_HFCORECLKDIV_MASK) |\r
+ (div << _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT);\r
+\r
+ /* Update CMSIS core clock variable */\r
+ /* (The function will update the global variable) */\r
+ freq = SystemCoreClockGet();\r
+\r
+ /* Optimize flash access wait state setting for current core clk */\r
+ CMU_FlashWaitStateControl(freq);\r
+ break;\r
+\r
+ case CMU_LFAPRESC0_REG:\r
+ switch (clock)\r
+ {\r
+ case cmuClock_RTC:\r
+ EFM_ASSERT(div <= cmuClkDiv_32768);\r
+\r
+ /* LF register about to be modified require sync. busy check */\r
+ CMU_Sync(CMU_SYNCBUSY_LFAPRESC0);\r
+\r
+ /* Convert to correct scale */\r
+ div = CMU_DivToLog2(div);\r
+\r
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTC_MASK) |\r
+ (div << _CMU_LFAPRESC0_RTC_SHIFT);\r
+ break;\r
+\r
+#if defined(_CMU_LFAPRESC0_LETIMER0_MASK)\r
+ case cmuClock_LETIMER0:\r
+ EFM_ASSERT(div <= cmuClkDiv_32768);\r
+\r
+ /* LF register about to be modified require sync. busy check */\r
+ CMU_Sync(CMU_SYNCBUSY_LFAPRESC0);\r
+\r
+ /* Convert to correct scale */\r
+ div = CMU_DivToLog2(div);\r
+\r
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LETIMER0_MASK) |\r
+ (div << _CMU_LFAPRESC0_LETIMER0_SHIFT);\r
+ break;\r
+#endif\r
+\r
+#if defined(LCD_PRESENT)\r
+ case cmuClock_LCDpre:\r
+ EFM_ASSERT((div >= cmuClkDiv_16) && (div <= cmuClkDiv_128));\r
+\r
+ /* LF register about to be modified require sync. busy check */\r
+ CMU_Sync(CMU_SYNCBUSY_LFAPRESC0);\r
+\r
+ /* Convert to correct scale */\r
+ div = CMU_DivToLog2(div);\r
+\r
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LCD_MASK) |\r
+ ((div - CMU_DivToLog2(cmuClkDiv_16)) << _CMU_LFAPRESC0_LCD_SHIFT);\r
+ break;\r
+#endif /* defined(LCD_PRESENT) */\r
+\r
+#if defined(LESENSE_PRESENT)\r
+ case cmuClock_LESENSE:\r
+ EFM_ASSERT(div <= cmuClkDiv_8);\r
+\r
+ /* LF register about to be modified require sync. busy check */\r
+ CMU_Sync(CMU_SYNCBUSY_LFAPRESC0);\r
+\r
+ /* Convert to correct scale */\r
+ div = CMU_DivToLog2(div);\r
+\r
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LESENSE_MASK) |\r
+ (div << _CMU_LFAPRESC0_LESENSE_SHIFT);\r
+ break;\r
+#endif /* defined(LESENSE_PRESENT) */\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case CMU_LFBPRESC0_REG:\r
+ switch (clock)\r
+ {\r
+#if defined(_CMU_LFBPRESC0_LEUART0_MASK)\r
+ case cmuClock_LEUART0:\r
+ EFM_ASSERT(div <= cmuClkDiv_8);\r
+\r
+ /* LF register about to be modified require sync. busy check */\r
+ CMU_Sync(CMU_SYNCBUSY_LFBPRESC0);\r
+\r
+ /* Convert to correct scale */\r
+ div = CMU_DivToLog2(div);\r
+\r
+ CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART0_MASK) |\r
+ (((uint32_t)div) << _CMU_LFBPRESC0_LEUART0_SHIFT);\r
+ break;\r
+#endif\r
+\r
+#if defined(_CMU_LFBPRESC0_LEUART1_MASK)\r
+ case cmuClock_LEUART1:\r
+ EFM_ASSERT(div <= cmuClkDiv_8);\r
+\r
+ /* LF register about to be modified require sync. busy check */\r
+ CMU_Sync(CMU_SYNCBUSY_LFBPRESC0);\r
+\r
+ /* Convert to correct scale */\r
+ div = CMU_DivToLog2(div);\r
+\r
+ CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART1_MASK) |\r
+ (((uint32_t)div) << _CMU_LFBPRESC0_LEUART1_SHIFT);\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ break;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Enable/disable a clock.\r
+ *\r
+ * @details\r
+ * In general, module clocking is disabled after a reset. If a module\r
+ * clock is disabled, the registers of that module are not accessible and\r
+ * reading from such registers may return undefined values. Writing to\r
+ * registers of clock disabled modules have no effect. One should normally\r
+ * avoid accessing module registers of a module with a disabled clock.\r
+ *\r
+ * @note\r
+ * If enabling/disabling a LF clock, synchronization into the low frequency\r
+ * domain is required. If the same register is modified before a previous\r
+ * update has completed, this function will stall until the previous\r
+ * synchronization has completed. Please refer to CMU_FreezeEnable() for\r
+ * a suggestion on how to reduce stalling time in some use cases.\r
+ *\r
+ * @param[in] clock\r
+ * The clock to enable/disable. Notice that not all defined clock\r
+ * points have separate enable/disable control, please refer to CMU overview\r
+ * in reference manual.\r
+ *\r
+ * @param[in] enable\r
+ * @li true - enable specified clock.\r
+ * @li false - disable specified clock.\r
+ ******************************************************************************/\r
+void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)\r
+{\r
+ volatile uint32_t *reg;\r
+ uint32_t bit;\r
+ uint32_t sync = 0;\r
+\r
+ /* Identify enable register */\r
+ switch ((clock >> CMU_EN_REG_POS) & CMU_EN_REG_MASK)\r
+ {\r
+ case CMU_HFPERCLKDIV_EN_REG:\r
+ reg = &(CMU->HFPERCLKDIV);\r
+ break;\r
+\r
+ case CMU_HFPERCLKEN0_EN_REG:\r
+ reg = &(CMU->HFPERCLKEN0);\r
+ break;\r
+\r
+ case CMU_HFCORECLKEN0_EN_REG:\r
+ reg = &(CMU->HFCORECLKEN0);\r
+\r
+#if defined( CMU_CTRL_HFLE )\r
+ /* Set HFLE and DIV4 factor for peripheral clock when\r
+ running at frequencies higher than or equal to CMU_MAX_FREQ_HFLE. */\r
+ if ( CMU_ClockFreqGet(cmuClock_CORE) > CMU_MAX_FREQ_HFLE )\r
+ {\r
+ /* Enable CMU HFLE */\r
+ BITBAND_Peripheral(&(CMU->CTRL), _CMU_CTRL_HFLE_SHIFT, 1);\r
+\r
+ /* Set DIV4 factor for peripheral clock */\r
+ BITBAND_Peripheral(&(CMU->HFCORECLKDIV),\r
+ _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 1);\r
+ }\r
+#endif\r
+ break;\r
+\r
+ case CMU_LFACLKEN0_EN_REG:\r
+ reg = &(CMU->LFACLKEN0);\r
+ sync = CMU_SYNCBUSY_LFACLKEN0;\r
+ break;\r
+\r
+ case CMU_LFBCLKEN0_EN_REG:\r
+ reg = &(CMU->LFBCLKEN0);\r
+ sync = CMU_SYNCBUSY_LFBCLKEN0;\r
+ break;\r
+\r
+ case CMU_PCNT_EN_REG:\r
+ reg = &(CMU->PCNTCTRL);\r
+ break;\r
+\r
+#if defined( _CMU_LFCCLKEN0_MASK )\r
+ case CMU_LFCCLKEN0_EN_REG:\r
+ reg = &(CMU->LFCCLKEN0);\r
+ sync = CMU_SYNCBUSY_LFCCLKEN0;\r
+ break;\r
+#endif\r
+\r
+ default: /* Cannot enable/disable clock point */\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+\r
+ /* Get bit position used to enable/disable */\r
+ bit = (clock >> CMU_EN_BIT_POS) & CMU_EN_BIT_MASK;\r
+\r
+ /* LF synchronization required? */\r
+ if (sync)\r
+ {\r
+ CMU_Sync(sync);\r
+ }\r
+\r
+ /* Set/clear bit as requested */\r
+ BITBAND_Peripheral(reg, bit, (unsigned int)enable);\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get clock frequency for a clock point.\r
+ *\r
+ * @param[in] clock\r
+ * Clock point to fetch frequency for.\r
+ *\r
+ * @return\r
+ * The current frequency in Hz.\r
+ ******************************************************************************/\r
+uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)\r
+{\r
+ uint32_t ret;\r
+\r
+ switch(clock & (CMU_CLK_BRANCH_MASK << CMU_CLK_BRANCH_POS))\r
+ {\r
+ case (CMU_HF_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = SystemHFClockGet();\r
+#if defined( _CMU_CTRL_HFCLKDIV_MASK )\r
+ /* Giant Gecko has an additional divider, not used by USBC */\r
+ ret = ret / (1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK) >>\r
+ _CMU_CTRL_HFCLKDIV_SHIFT));\r
+#endif\r
+ } break;\r
+\r
+#if defined(_CMU_HFPERCLKEN0_USART0_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_USART1_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_USART2_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_UART0_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_UART1_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_TIMER0_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_TIMER1_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_TIMER2_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_TIMER3_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_ACMP0_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_ACMP1_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_DAC0_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_IDAC0_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_ADC0_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_I2C0_MASK) || \\r
+ defined(_CMU_HFPERCLKEN0_I2C1_MASK) || \\r
+ defined(PRS_PRESENT) || \\r
+ defined(VCMP_PRESENT)|| \\r
+ defined(GPIO_PRESENT)\r
+ case (CMU_HFPER_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = SystemHFClockGet();\r
+#if defined( _CMU_CTRL_HFCLKDIV_MASK )\r
+ /* Leopard/Giant Gecko has an additional divider */\r
+ ret = ret / (1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK) >>\r
+ _CMU_CTRL_HFCLKDIV_SHIFT));\r
+#endif\r
+ ret >>= (CMU->HFPERCLKDIV & _CMU_HFPERCLKDIV_HFPERCLKDIV_MASK) >>\r
+ _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT;\r
+ } break;\r
+#endif\r
+\r
+#if defined(AES_PRESENT) || \\r
+ defined(DMA_PRESENT) || \\r
+ defined(EBI_PRESENT) || \\r
+ defined(USB_PRESENT)\r
+ case (CMU_HFCORE_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = SystemCoreClockGet();\r
+ } break;\r
+#endif\r
+\r
+ case (CMU_LFA_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_LFClkGet(CMU_LFA);\r
+ } break;\r
+#if defined(_CMU_LFACLKEN0_RTC_MASK)\r
+ case (CMU_RTC_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_LFClkGet(CMU_LFA);\r
+ ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK) >>\r
+ _CMU_LFAPRESC0_RTC_SHIFT;\r
+ } break;\r
+#endif\r
+#if defined(_CMU_LFACLKEN0_LETIMER0_MASK)\r
+ case (CMU_LETIMER_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_LFClkGet(CMU_LFA);\r
+ ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK) >>\r
+ _CMU_LFAPRESC0_LETIMER0_SHIFT;\r
+ } break;\r
+#endif\r
+#if defined(_CMU_LFACLKEN0_LCD_MASK)\r
+ case (CMU_LCDPRE_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_LFClkGet(CMU_LFA);\r
+ ret >>= ((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK) >>\r
+ _CMU_LFAPRESC0_LCD_SHIFT) + CMU_DivToLog2(cmuClkDiv_16);\r
+ } break;\r
+\r
+ case (CMU_LCD_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_LFClkGet(CMU_LFA);\r
+ ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK) >>\r
+ _CMU_LFAPRESC0_LCD_SHIFT;\r
+ ret /= (1 + ((CMU->LCDCTRL & _CMU_LCDCTRL_FDIV_MASK) >>\r
+ _CMU_LCDCTRL_FDIV_SHIFT));\r
+ } break;\r
+#endif\r
+#if defined(_CMU_LFACLKEN0_LESENSE_MASK)\r
+ case (CMU_LESENSE_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_LFClkGet(CMU_LFA);\r
+ ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK) >>\r
+ _CMU_LFAPRESC0_LESENSE_SHIFT;\r
+ } break;\r
+#endif\r
+ case (CMU_LFB_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_LFClkGet(CMU_LFB);\r
+ } break;\r
+#if defined(_CMU_LFBCLKEN0_LEUART0_MASK)\r
+ case (CMU_LEUART0_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_LFClkGet(CMU_LFB);\r
+ ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK) >>\r
+ _CMU_LFBPRESC0_LEUART0_SHIFT;\r
+ } break;\r
+#endif\r
+#if defined(_CMU_LFBCLKEN0_LEUART1_MASK)\r
+ case (CMU_LEUART1_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_LFClkGet(CMU_LFB);\r
+ ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK) >>\r
+ _CMU_LFBPRESC0_LEUART1_SHIFT;\r
+ } break;\r
+#endif\r
+\r
+ case (CMU_DBG_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_DBGClkGet();\r
+ } break;\r
+\r
+ case (CMU_AUX_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_AUXClkGet();\r
+ } break;\r
+\r
+#if defined(USB_PRESENT)\r
+ case (CMU_USBC_CLK_BRANCH << CMU_CLK_BRANCH_POS):\r
+ {\r
+ ret = CMU_USBCClkGet();\r
+ } break;\r
+#endif\r
+ default:\r
+ {\r
+ EFM_ASSERT(0);\r
+ ret = 0;\r
+ } break;\r
+ }\r
+ return ret;\r
+}\r
+\r
+\r
+/**************************************************************************//**\r
+ * @brief\r
+ * Get currently selected reference clock used for a clock branch.\r
+ *\r
+ * @param[in] clock\r
+ * Clock branch to fetch selected ref. clock for. One of:\r
+ * @li #cmuClock_HF\r
+ * @li #cmuClock_LFA\r
+ * @li #cmuClock_LFB\r
+ * @li #cmuClock_DBG @if DOXYDOC_USB_PRESENT\r
+ * @li #cmuClock_USBC\r
+ * @endif\r
+ *\r
+ * @return\r
+ * Reference clock used for clocking selected branch, #cmuSelect_Error if\r
+ * invalid @p clock provided.\r
+ *****************************************************************************/\r
+CMU_Select_TypeDef CMU_ClockSelectGet(CMU_Clock_TypeDef clock)\r
+{\r
+ CMU_Select_TypeDef ret = cmuSelect_Disabled;\r
+ uint32_t selReg;\r
+ uint32_t statusClkSelMask;\r
+\r
+ statusClkSelMask =\r
+ (CMU_STATUS_HFRCOSEL |\r
+ CMU_STATUS_HFXOSEL |\r
+ CMU_STATUS_LFRCOSEL |\r
+#if defined( CMU_STATUS_USHFRCODIV2SEL )\r
+ CMU_STATUS_USHFRCODIV2SEL |\r
+#endif\r
+ CMU_STATUS_LFXOSEL);\r
+\r
+ selReg = (clock >> CMU_SEL_REG_POS) & CMU_SEL_REG_MASK;\r
+\r
+ switch (selReg)\r
+ {\r
+ case CMU_HFCLKSEL_REG:\r
+ switch (CMU->STATUS & statusClkSelMask)\r
+ {\r
+ case CMU_STATUS_LFXOSEL:\r
+ ret = cmuSelect_LFXO;\r
+ break;\r
+\r
+ case CMU_STATUS_LFRCOSEL:\r
+ ret = cmuSelect_LFRCO;\r
+ break;\r
+\r
+ case CMU_STATUS_HFXOSEL:\r
+ ret = cmuSelect_HFXO;\r
+ break;\r
+\r
+#if defined( CMU_STATUS_USHFRCODIV2SEL )\r
+ case CMU_STATUS_USHFRCODIV2SEL:\r
+ ret = cmuSelect_USHFRCODIV2;\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ ret = cmuSelect_HFRCO;\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case CMU_LFACLKSEL_REG:\r
+ switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFA_MASK)\r
+ {\r
+ case CMU_LFCLKSEL_LFA_LFRCO:\r
+ ret = cmuSelect_LFRCO;\r
+ break;\r
+\r
+ case CMU_LFCLKSEL_LFA_LFXO:\r
+ ret = cmuSelect_LFXO;\r
+ break;\r
+\r
+ case CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2:\r
+ ret = cmuSelect_CORELEDIV2;\r
+ break;\r
+\r
+ default:\r
+#if defined( CMU_LFCLKSEL_LFAE )\r
+ if (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFAE_MASK)\r
+ {\r
+ ret = cmuSelect_ULFRCO;\r
+ break;\r
+ }\r
+#else\r
+ ret = cmuSelect_Disabled;\r
+#endif\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case CMU_LFBCLKSEL_REG:\r
+ switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFB_MASK)\r
+ {\r
+ case CMU_LFCLKSEL_LFB_LFRCO:\r
+ ret = cmuSelect_LFRCO;\r
+ break;\r
+\r
+ case CMU_LFCLKSEL_LFB_LFXO:\r
+ ret = cmuSelect_LFXO;\r
+ break;\r
+\r
+ case CMU_LFCLKSEL_LFB_HFCORECLKLEDIV2:\r
+ ret = cmuSelect_CORELEDIV2;\r
+ break;\r
+\r
+ default:\r
+#if defined( CMU_LFCLKSEL_LFBE )\r
+ if (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFBE_MASK)\r
+ {\r
+ ret = cmuSelect_ULFRCO;\r
+ break;\r
+ }\r
+#else\r
+ ret = cmuSelect_Disabled;\r
+#endif\r
+ break;\r
+ }\r
+ break;\r
+\r
+#if defined( _CMU_LFCLKSEL_LFC_MASK )\r
+ case CMU_LFCCLKSEL_REG:\r
+ switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFC_MASK)\r
+ {\r
+ case CMU_LFCLKSEL_LFC_LFRCO:\r
+ ret = cmuSelect_LFRCO;\r
+ break;\r
+\r
+ case CMU_LFCLKSEL_LFC_LFXO:\r
+ ret = cmuSelect_LFXO;\r
+ break;\r
+\r
+ default:\r
+ ret = cmuSelect_Disabled;\r
+ break;\r
+ }\r
+ break;\r
+#endif\r
+\r
+ case CMU_DBGCLKSEL_REG:\r
+\r
+#if defined( _CMU_DBGCLKSEL_DBG_MASK )\r
+ switch (CMU->DBGCLKSEL & _CMU_DBGCLKSEL_DBG_MASK)\r
+ {\r
+ case CMU_DBGCLKSEL_DBG_HFCLK:\r
+ ret = cmuSelect_HFCLK;\r
+ break;\r
+\r
+ case CMU_DBGCLKSEL_DBG_AUXHFRCO:\r
+ ret = cmuSelect_AUXHFRCO;\r
+ break;\r
+ }\r
+#else\r
+ ret = cmuSelect_AUXHFRCO;\r
+#endif /* CMU_DBGCLKSEL_DBG */\r
+\r
+#if defined( _CMU_CTRL_DBGCLK_MASK )\r
+ switch(CMU->CTRL & _CMU_CTRL_DBGCLK_MASK)\r
+ {\r
+ case CMU_CTRL_DBGCLK_AUXHFRCO:\r
+ ret = cmuSelect_AUXHFRCO;\r
+ break;\r
+\r
+ case CMU_CTRL_DBGCLK_HFCLK:\r
+ ret = cmuSelect_HFCLK;\r
+ break;\r
+ }\r
+#else\r
+ ret = cmuSelect_AUXHFRCO;\r
+#endif\r
+ break;\r
+\r
+\r
+#if defined(USB_PRESENT)\r
+\r
+ case CMU_USBCCLKSEL_REG:\r
+ switch(CMU->STATUS &\r
+ (CMU_STATUS_USBCLFXOSEL |\r
+#if defined(_CMU_STATUS_USBCHFCLKSEL_MASK)\r
+ CMU_STATUS_USBCHFCLKSEL |\r
+#endif\r
+#if defined(_CMU_STATUS_USBCUSHFRCOSEL_MASK)\r
+ CMU_STATUS_USBCUSHFRCOSEL |\r
+#endif\r
+ CMU_STATUS_USBCLFRCOSEL))\r
+ {\r
+\r
+ case CMU_STATUS_USBCLFXOSEL:\r
+ ret = cmuSelect_LFXO;\r
+ break;\r
+\r
+ case CMU_STATUS_USBCLFRCOSEL:\r
+ ret = cmuSelect_LFRCO;\r
+ break;\r
+\r
+#if defined(_CMU_STATUS_USBCHFCLKSEL_MASK)\r
+ case CMU_STATUS_USBCHFCLKSEL:\r
+ ret = cmuSelect_HFCLK;\r
+ break;\r
+#endif\r
+\r
+#if defined(_CMU_STATUS_USBCUSHFRCOSEL_MASK)\r
+ case CMU_STATUS_USBCUSHFRCOSEL:\r
+ ret = cmuSelect_USHFRCO;\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ ret = cmuSelect_Disabled;\r
+ break;\r
+ }\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ ret = cmuSelect_Error;\r
+ break;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+\r
+/**************************************************************************//**\r
+ * @brief\r
+ * Select reference clock/oscillator used for a clock branch.\r
+ *\r
+ * @details\r
+ * Notice that if a selected reference is not enabled prior to selecting its\r
+ * use, it will be enabled, and this function will wait for the selected\r
+ * oscillator to be stable. It will however NOT be disabled if another\r
+ * reference clock is selected later.\r
+ *\r
+ * This feature is particularly important if selecting a new reference\r
+ * clock for the clock branch clocking the core, otherwise the system\r
+ * may halt.\r
+ *\r
+ * @param[in] clock\r
+ * Clock branch to select reference clock for. One of:\r
+ * @li #cmuClock_HF\r
+ * @li #cmuClock_LFA\r
+ * @li #cmuClock_LFB\r
+ * @li #cmuClock_DBG @if DOXYDOC_USB_PRESENT\r
+ * @li #cmuClock_USBC\r
+ * @endif\r
+ *\r
+ * @param[in] ref\r
+ * Reference selected for clocking, please refer to reference manual for\r
+ * for details on which reference is available for a specific clock branch.\r
+ * @li #cmuSelect_HFRCO\r
+ * @li #cmuSelect_LFRCO\r
+ * @li #cmuSelect_HFXO\r
+ * @li #cmuSelect_LFXO\r
+ * @li #cmuSelect_CORELEDIV2\r
+ * @li #cmuSelect_AUXHFRCO\r
+ * @li #cmuSelect_HFCLK @ifnot DOXYDOC_EFM32_GECKO_FAMILY\r
+ * @li #cmuSelect_ULFRCO\r
+ * @endif\r
+ *****************************************************************************/\r
+void CMU_ClockSelectSet(CMU_Clock_TypeDef clock, CMU_Select_TypeDef ref)\r
+{\r
+ uint32_t select = cmuOsc_HFRCO;\r
+ CMU_Osc_TypeDef osc = cmuOsc_HFRCO;\r
+ uint32_t freq;\r
+ uint32_t selReg;\r
+#if !defined(_EFM32_GECKO_FAMILY)\r
+ uint32_t lfExtended = 0;\r
+#endif\r
+ uint32_t tmp;\r
+\r
+ selReg = (clock >> CMU_SEL_REG_POS) & CMU_SEL_REG_MASK;\r
+\r
+ switch (selReg)\r
+ {\r
+ case CMU_HFCLKSEL_REG:\r
+ switch (ref)\r
+ {\r
+ case cmuSelect_LFXO:\r
+ select = CMU_CMD_HFCLKSEL_LFXO;\r
+ osc = cmuOsc_LFXO;\r
+ break;\r
+\r
+ case cmuSelect_LFRCO:\r
+ select = CMU_CMD_HFCLKSEL_LFRCO;\r
+ osc = cmuOsc_LFRCO;\r
+ break;\r
+\r
+ case cmuSelect_HFXO:\r
+ select = CMU_CMD_HFCLKSEL_HFXO;\r
+ osc = cmuOsc_HFXO;\r
+#if defined( CMU_CTRL_HFLE )\r
+ /* Adjust HFXO buffer current for high frequencies, enable HFLE for */\r
+ /* frequencies above CMU_MAX_FREQ_HFLE. */\r
+ if(SystemHFXOClockGet() > CMU_MAX_FREQ_HFLE)\r
+ {\r
+ CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK) |\r
+ CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ |\r
+ /* Must have HFLE enabled to access some LE peripherals >=32MHz */\r
+ CMU_CTRL_HFLE;\r
+\r
+ /* Set HFLE and DIV4 factor for peripheral clock if HFCORE clock for\r
+ LE is enabled. */\r
+ if (CMU->HFCORECLKEN0 & CMU_HFCORECLKEN0_LE)\r
+ {\r
+ BITBAND_Peripheral(&(CMU->HFCORECLKDIV),\r
+ _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 1);\r
+ }\r
+ } else {\r
+ /* This can happen if the user configures the EFM32_HFXO_FREQ to */\r
+ /* use another oscillator frequency */\r
+ CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK) |\r
+ CMU_CTRL_HFXOBUFCUR_BOOSTUPTO32MHZ;\r
+ }\r
+#endif\r
+ break;\r
+\r
+ case cmuSelect_HFRCO:\r
+ select = CMU_CMD_HFCLKSEL_HFRCO;\r
+ osc = cmuOsc_HFRCO;\r
+ break;\r
+\r
+#if defined( CMU_CMD_HFCLKSEL_USHFRCODIV2 )\r
+ case cmuSelect_USHFRCODIV2:\r
+ select = CMU_CMD_HFCLKSEL_USHFRCODIV2;\r
+ osc = cmuOsc_USHFRCO;\r
+ break;\r
+#endif\r
+\r
+#if !defined( _EFM32_GECKO_FAMILY )\r
+ case cmuSelect_ULFRCO:\r
+ /* ULFRCO cannot be used as HFCLK */\r
+ EFM_ASSERT(0);\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+\r
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */\r
+ CMU_OscillatorEnable(osc, true, true);\r
+\r
+ /* Configure worst case wait states for flash access before selecting */\r
+ CMU_FlashWaitStateMax();\r
+\r
+ /* Switch to selected oscillator */\r
+ CMU->CMD = select;\r
+\r
+ /* Keep EMU module informed */\r
+ EMU_UpdateOscConfig();\r
+\r
+ /* Update CMSIS core clock variable */\r
+ /* (The function will update the global variable) */\r
+ freq = SystemCoreClockGet();\r
+\r
+ /* Optimize flash access wait state setting for currently selected core clk */\r
+ CMU_FlashWaitStateControl(freq);\r
+ break;\r
+\r
+ case CMU_LFACLKSEL_REG:\r
+ case CMU_LFBCLKSEL_REG:\r
+\r
+ switch (ref)\r
+ {\r
+ case cmuSelect_Disabled:\r
+ tmp = _CMU_LFCLKSEL_LFA_DISABLED;\r
+ break;\r
+\r
+ case cmuSelect_LFXO:\r
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */\r
+ CMU_OscillatorEnable(cmuOsc_LFXO, true, true);\r
+ tmp = _CMU_LFCLKSEL_LFA_LFXO;\r
+ break;\r
+\r
+ case cmuSelect_LFRCO:\r
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */\r
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);\r
+ tmp = _CMU_LFCLKSEL_LFA_LFRCO;\r
+ break;\r
+\r
+ case cmuSelect_CORELEDIV2:\r
+ /* Ensure HFCORE to LE clocking is enabled */\r
+ BITBAND_Peripheral(&(CMU->HFCORECLKEN0), _CMU_HFCORECLKEN0_LE_SHIFT, 1);\r
+ tmp = _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2;\r
+#if defined( CMU_CTRL_HFLE )\r
+ /* If core frequency is higher than CMU_MAX_FREQ_HFLE on\r
+ Giant/Leopard/Wonder, enable HFLE and DIV4. */\r
+ freq = SystemCoreClockGet();\r
+ if(freq > CMU_MAX_FREQ_HFLE)\r
+ {\r
+ /* Enable CMU HFLE */\r
+ BITBAND_Peripheral(&(CMU->CTRL), _CMU_CTRL_HFLE_SHIFT, 1);\r
+\r
+ /* Enable DIV4 factor for peripheral clock */\r
+ BITBAND_Peripheral(&(CMU->HFCORECLKDIV),\r
+ _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 1);\r
+ }\r
+#endif\r
+ break;\r
+\r
+#if !defined(_EFM32_GECKO_FAMILY)\r
+ case cmuSelect_ULFRCO:\r
+ /* ULFRCO is always enabled */\r
+ tmp = _CMU_LFCLKSEL_LFA_DISABLED;\r
+ lfExtended = 1;\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ /* Illegal clock source for LFA/LFB selected */\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+\r
+ /* Apply select */\r
+ if (selReg == CMU_LFACLKSEL_REG)\r
+ {\r
+#if !defined( _EFM32_GECKO_FAMILY )\r
+ CMU->LFCLKSEL = (CMU->LFCLKSEL & ~(_CMU_LFCLKSEL_LFA_MASK | _CMU_LFCLKSEL_LFAE_MASK) ) |\r
+ (tmp << _CMU_LFCLKSEL_LFA_SHIFT) | (lfExtended << _CMU_LFCLKSEL_LFAE_SHIFT);\r
+#else\r
+ CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFA_MASK) |\r
+ (tmp << _CMU_LFCLKSEL_LFA_SHIFT);\r
+#endif\r
+ }\r
+ else\r
+ {\r
+#if !defined( _EFM32_GECKO_FAMILY )\r
+ CMU->LFCLKSEL = (CMU->LFCLKSEL & ~(_CMU_LFCLKSEL_LFB_MASK | _CMU_LFCLKSEL_LFBE_MASK) ) |\r
+ (tmp << _CMU_LFCLKSEL_LFB_SHIFT) | (lfExtended << _CMU_LFCLKSEL_LFBE_SHIFT);\r
+#else\r
+ CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFB_MASK) |\r
+ (tmp << _CMU_LFCLKSEL_LFB_SHIFT);\r
+#endif\r
+ }\r
+ break;\r
+\r
+#if defined( _CMU_LFCLKSEL_LFC_MASK )\r
+ case CMU_LFCCLKSEL_REG:\r
+ switch(ref)\r
+ {\r
+ case cmuSelect_Disabled:\r
+ tmp = _CMU_LFCLKSEL_LFA_DISABLED;\r
+ break;\r
+\r
+ case cmuSelect_LFXO:\r
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */\r
+ CMU_OscillatorEnable(cmuOsc_LFXO, true, true);\r
+ tmp = _CMU_LFCLKSEL_LFC_LFXO;\r
+ break;\r
+\r
+ case cmuSelect_LFRCO:\r
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */\r
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);\r
+ tmp = _CMU_LFCLKSEL_LFC_LFRCO;\r
+ break;\r
+\r
+ default:\r
+ /* Illegal clock source for LFC selected */\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+\r
+ /* Apply select */\r
+ CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFC_MASK) |\r
+ (tmp << _CMU_LFCLKSEL_LFC_SHIFT);\r
+ break;\r
+#endif\r
+\r
+#if defined( CMU_CTRL_DBGCLK )\r
+ case CMU_DBGCLKSEL_REG:\r
+ switch(ref)\r
+ {\r
+ case cmuSelect_AUXHFRCO:\r
+ /* Select AUXHFRCO as debug clock */\r
+ CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_DBGCLK_MASK))| CMU_CTRL_DBGCLK_AUXHFRCO;\r
+ break;\r
+\r
+ case cmuSelect_HFCLK:\r
+ /* Select divided HFCLK as debug clock */\r
+ CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_DBGCLK_MASK))| CMU_CTRL_DBGCLK_HFCLK;\r
+ break;\r
+\r
+ default:\r
+ /* Illegal clock source for debug selected */\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+ break;\r
+#endif\r
+\r
+#if defined(USB_PRESENT)\r
+ case CMU_USBCCLKSEL_REG:\r
+ switch(ref)\r
+ {\r
+ case cmuSelect_LFXO:\r
+ /* Select LFXO as clock source for USB, can only be used in sleep mode */\r
+\r
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */\r
+ CMU_OscillatorEnable(cmuOsc_LFXO, true, true);\r
+\r
+ /* Switch oscillator */\r
+ CMU->CMD = CMU_CMD_USBCCLKSEL_LFXO;\r
+\r
+ /* Wait until clock is activated */\r
+ while((CMU->STATUS & CMU_STATUS_USBCLFXOSEL)==0);\r
+ break;\r
+\r
+ case cmuSelect_LFRCO:\r
+ /* Select LFRCO as clock source for USB, can only be used in sleep mode */\r
+\r
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */\r
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);\r
+\r
+ /* Switch oscillator */\r
+ CMU->CMD = CMU_CMD_USBCCLKSEL_LFRCO;\r
+\r
+ /* Wait until clock is activated */\r
+ while((CMU->STATUS & CMU_STATUS_USBCLFRCOSEL)==0);\r
+ break;\r
+\r
+#if defined( CMU_STATUS_USBCHFCLKSEL )\r
+ case cmuSelect_HFCLK:\r
+ /* Select undivided HFCLK as clock source for USB */\r
+\r
+ /* Oscillator must already be enabled to avoid a core lockup */\r
+ CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;\r
+ /* Wait until clock is activated */\r
+ while((CMU->STATUS & CMU_STATUS_USBCHFCLKSEL)==0);\r
+ break;\r
+#endif\r
+\r
+#if defined( CMU_CMD_USBCCLKSEL_USHFRCO )\r
+ case cmuSelect_USHFRCO:\r
+ /* Select USHFRCO as clock source for USB */\r
+\r
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */\r
+ CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);\r
+\r
+ /* Switch oscillator */\r
+ CMU->CMD = CMU_CMD_USBCCLKSEL_USHFRCO;\r
+\r
+ /* Wait until clock is activated */\r
+ while((CMU->STATUS & CMU_STATUS_USBCUSHFRCOSEL)==0);\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ /* Illegal clock source for USB */\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+ /* Wait until clock has been activated */\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+/**************************************************************************//**\r
+ * @brief\r
+ * CMU low frequency register synchronization freeze control.\r
+ *\r
+ * @details\r
+ * Some CMU registers requires synchronization into the low frequency (LF)\r
+ * domain. The freeze feature allows for several such registers to be\r
+ * modified before passing them to the LF domain simultaneously (which\r
+ * takes place when the freeze mode is disabled).\r
+ *\r
+ * Another usage scenario of this feature, is when using an API (such\r
+ * as the CMU API) for modifying several bit fields consecutively in the\r
+ * same register. If freeze mode is enabled during this sequence, stalling\r
+ * can be avoided.\r
+ *\r
+ * @note\r
+ * When enabling freeze mode, this function will wait for all current\r
+ * ongoing CMU synchronization to LF domain to complete (Normally\r
+ * synchronization will not be in progress.) However for this reason, when\r
+ * using freeze mode, modifications of registers requiring LF synchronization\r
+ * should be done within one freeze enable/disable block to avoid unecessary\r
+ * stalling.\r
+ *\r
+ * @param[in] enable\r
+ * @li true - enable freeze, modified registers are not propagated to the\r
+ * LF domain\r
+ * @li false - disable freeze, modified registers are propagated to LF\r
+ * domain\r
+ *****************************************************************************/\r
+void CMU_FreezeEnable(bool enable)\r
+{\r
+ if (enable)\r
+ {\r
+ /* Wait for any ongoing LF synchronization to complete. This is just to */\r
+ /* protect against the rare case when a user */\r
+ /* - modifies a register requiring LF sync */\r
+ /* - then enables freeze before LF sync completed */\r
+ /* - then modifies the same register again */\r
+ /* since modifying a register while it is in sync progress should be */\r
+ /* avoided. */\r
+ while (CMU->SYNCBUSY)\r
+ ;\r
+\r
+ CMU->FREEZE = CMU_FREEZE_REGFREEZE;\r
+ }\r
+ else\r
+ {\r
+ CMU->FREEZE = 0;\r
+ }\r
+}\r
+\r
+\r
+#if defined( _CMU_AUXHFRCOCTRL_BAND_MASK )\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get AUXHFRCO band in use.\r
+ *\r
+ * @return\r
+ * AUXHFRCO band in use.\r
+ ******************************************************************************/\r
+CMU_AUXHFRCOBand_TypeDef CMU_AUXHFRCOBandGet(void)\r
+{\r
+ return (CMU_AUXHFRCOBand_TypeDef)((CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_BAND_MASK) >>\r
+ _CMU_AUXHFRCOCTRL_BAND_SHIFT);\r
+}\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Set AUIXHFRCO band and the tuning value based on the value in the\r
+ * calibration table made during production.\r
+ *\r
+ * @param[in] band\r
+ * AUXHFRCO band to activate.\r
+ ******************************************************************************/\r
+void CMU_AUXHFRCOBandSet(CMU_AUXHFRCOBand_TypeDef band)\r
+{\r
+ uint32_t tuning;\r
+\r
+ /* Read tuning value from calibration table */\r
+ switch (band)\r
+ {\r
+ case cmuAUXHFRCOBand_1MHz:\r
+ tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND1_MASK) >>\r
+ _DEVINFO_AUXHFRCOCAL0_BAND1_SHIFT;\r
+ break;\r
+\r
+ case cmuAUXHFRCOBand_7MHz:\r
+ tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND7_MASK) >>\r
+ _DEVINFO_AUXHFRCOCAL0_BAND7_SHIFT;\r
+ break;\r
+\r
+ case cmuAUXHFRCOBand_11MHz:\r
+ tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND11_MASK) >>\r
+ _DEVINFO_AUXHFRCOCAL0_BAND11_SHIFT;\r
+ break;\r
+\r
+ case cmuAUXHFRCOBand_14MHz:\r
+ tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND14_MASK) >>\r
+ _DEVINFO_AUXHFRCOCAL0_BAND14_SHIFT;\r
+ break;\r
+\r
+ case cmuAUXHFRCOBand_21MHz:\r
+ tuning = (DEVINFO->AUXHFRCOCAL1 & _DEVINFO_AUXHFRCOCAL1_BAND21_MASK) >>\r
+ _DEVINFO_AUXHFRCOCAL1_BAND21_SHIFT;\r
+ break;\r
+\r
+#if defined( _CMU_AUXHFRCOCTRL_BAND_28MHZ )\r
+ case cmuAUXHFRCOBand_28MHz:\r
+ tuning = (DEVINFO->AUXHFRCOCAL1 & _DEVINFO_AUXHFRCOCAL1_BAND28_MASK) >>\r
+ _DEVINFO_AUXHFRCOCAL1_BAND28_SHIFT;\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+\r
+ /* Set band/tuning */\r
+ CMU->AUXHFRCOCTRL = (CMU->AUXHFRCOCTRL &\r
+ ~(_CMU_AUXHFRCOCTRL_BAND_MASK | _CMU_AUXHFRCOCTRL_TUNING_MASK)) |\r
+ (band << _CMU_AUXHFRCOCTRL_BAND_SHIFT) |\r
+ (tuning << _CMU_AUXHFRCOCTRL_TUNING_SHIFT);\r
+\r
+}\r
+#endif\r
+\r
+\r
+#if defined( _CMU_USHFRCOCONF_BAND_MASK )\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get USHFRCO band in use.\r
+ *\r
+ * @return\r
+ * USHFRCO band in use.\r
+ ******************************************************************************/\r
+CMU_USHFRCOBand_TypeDef CMU_USHFRCOBandGet(void)\r
+{\r
+ return (CMU_USHFRCOBand_TypeDef)((CMU->USHFRCOCONF & _CMU_USHFRCOCONF_BAND_MASK) >>\r
+ _CMU_USHFRCOCONF_BAND_SHIFT);\r
+}\r
+\r
+void CMU_USHFRCOBandSet(CMU_USHFRCOBand_TypeDef band)\r
+{\r
+ uint32_t tuning;\r
+ uint32_t fineTuning;\r
+ CMU_Select_TypeDef osc;\r
+\r
+ /* Cannot switch band if USHFRCO is already selected as HF clock. */\r
+ osc = CMU_ClockSelectGet(cmuClock_HF);\r
+ EFM_ASSERT((CMU_USHFRCOBandGet() != band) && (osc != cmuSelect_USHFRCO));\r
+\r
+ /* Read tuning value from calibration table */\r
+ switch (band)\r
+ {\r
+ case cmuUSHFRCOBand_24MHz:\r
+ tuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND24_TUNING_MASK) >>\r
+ _DEVINFO_USHFRCOCAL0_BAND24_TUNING_SHIFT;\r
+ fineTuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND24_FINETUNING_MASK) >>\r
+ _DEVINFO_USHFRCOCAL0_BAND24_FINETUNING_SHIFT;\r
+ break;\r
+\r
+ case cmuUSHFRCOBand_48MHz:\r
+ tuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND48_TUNING_MASK) >>\r
+ _DEVINFO_USHFRCOCAL0_BAND48_TUNING_SHIFT;\r
+ fineTuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND48_FINETUNING_MASK) >>\r
+ _DEVINFO_USHFRCOCAL0_BAND48_FINETUNING_SHIFT;\r
+ /* Enable the clock divider before switching the band from 24 to 48MHz */\r
+ BITBAND_Peripheral(&CMU->USHFRCOCONF, _CMU_USHFRCOCONF_USHFRCODIV2DIS_SHIFT, 0);\r
+ break;\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+\r
+ /* Set band and tuning */\r
+ CMU->USHFRCOCONF = (CMU->USHFRCOCONF & ~_CMU_USHFRCOCONF_BAND_MASK) |\r
+ (band << _CMU_USHFRCOCONF_BAND_SHIFT);\r
+ CMU->USHFRCOCTRL = (CMU->USHFRCOCTRL & ~_CMU_USHFRCOCTRL_TUNING_MASK) |\r
+ (tuning << _CMU_USHFRCOCTRL_TUNING_SHIFT);\r
+ CMU->USHFRCOTUNE = (CMU->USHFRCOTUNE & ~_CMU_USHFRCOTUNE_FINETUNING_MASK) |\r
+ (fineTuning << _CMU_USHFRCOTUNE_FINETUNING_SHIFT);\r
+\r
+ /* Disable the clock divider after switching the band from 48 to 24MHz */\r
+ if (band == cmuUSHFRCOBand_24MHz)\r
+ {\r
+ BITBAND_Peripheral(&CMU->USHFRCOCONF, _CMU_USHFRCOCONF_USHFRCODIV2DIS_SHIFT, 1);\r
+ }\r
+}\r
+#endif\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get HFRCO band in use.\r
+ *\r
+ * @return\r
+ * HFRCO band in use.\r
+ ******************************************************************************/\r
+CMU_HFRCOBand_TypeDef CMU_HFRCOBandGet(void)\r
+{\r
+ return (CMU_HFRCOBand_TypeDef)((CMU->HFRCOCTRL & _CMU_HFRCOCTRL_BAND_MASK) >>\r
+ _CMU_HFRCOCTRL_BAND_SHIFT);\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Set HFRCO band and the tuning value based on the value in the calibration\r
+ * table made during production.\r
+ *\r
+ * @param[in] band\r
+ * HFRCO band to activate.\r
+ ******************************************************************************/\r
+void CMU_HFRCOBandSet(CMU_HFRCOBand_TypeDef band)\r
+{\r
+ uint32_t tuning;\r
+ uint32_t freq;\r
+ CMU_Select_TypeDef osc;\r
+\r
+ /* Read tuning value from calibration table */\r
+ switch (band)\r
+ {\r
+ case cmuHFRCOBand_1MHz:\r
+ tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND1_MASK) >>\r
+ _DEVINFO_HFRCOCAL0_BAND1_SHIFT;\r
+ break;\r
+\r
+ case cmuHFRCOBand_7MHz:\r
+ tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND7_MASK) >>\r
+ _DEVINFO_HFRCOCAL0_BAND7_SHIFT;\r
+ break;\r
+\r
+ case cmuHFRCOBand_11MHz:\r
+ tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND11_MASK) >>\r
+ _DEVINFO_HFRCOCAL0_BAND11_SHIFT;\r
+ break;\r
+\r
+ case cmuHFRCOBand_14MHz:\r
+ tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND14_MASK) >>\r
+ _DEVINFO_HFRCOCAL0_BAND14_SHIFT;\r
+ break;\r
+\r
+ case cmuHFRCOBand_21MHz:\r
+ tuning = (DEVINFO->HFRCOCAL1 & _DEVINFO_HFRCOCAL1_BAND21_MASK) >>\r
+ _DEVINFO_HFRCOCAL1_BAND21_SHIFT;\r
+ break;\r
+\r
+#if defined( _CMU_HFRCOCTRL_BAND_28MHZ )\r
+ case cmuHFRCOBand_28MHz:\r
+ tuning = (DEVINFO->HFRCOCAL1 & _DEVINFO_HFRCOCAL1_BAND28_MASK) >>\r
+ _DEVINFO_HFRCOCAL1_BAND28_SHIFT;\r
+ break;\r
+#endif\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+\r
+ /* If HFRCO is used for core clock, we have to consider flash access WS. */\r
+ osc = CMU_ClockSelectGet(cmuClock_HF);\r
+ if (osc == cmuSelect_HFRCO)\r
+ {\r
+ /* Configure worst case wait states for flash access before setting divider */\r
+ CMU_FlashWaitStateMax();\r
+ }\r
+\r
+ /* Set band/tuning */\r
+ CMU->HFRCOCTRL = (CMU->HFRCOCTRL &\r
+ ~(_CMU_HFRCOCTRL_BAND_MASK | _CMU_HFRCOCTRL_TUNING_MASK)) |\r
+ (band << _CMU_HFRCOCTRL_BAND_SHIFT) |\r
+ (tuning << _CMU_HFRCOCTRL_TUNING_SHIFT);\r
+\r
+ /* If HFRCO is used for core clock, optimize flash WS */\r
+ if (osc == cmuSelect_HFRCO)\r
+ {\r
+ /* Update CMSIS core clock variable and get current core clock */\r
+ /* (The function will update the global variable) */\r
+ /* NOTE! We need at least 21 cycles before setting zero wait state to flash */\r
+ /* (i.e. WS0) when going from the 28MHz to 1MHz in the HFRCO band */\r
+ freq = SystemCoreClockGet();\r
+\r
+ /* Optimize flash access wait state setting for current core clk */\r
+ CMU_FlashWaitStateControl(freq);\r
+ }\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get the HFRCO startup delay.\r
+ *\r
+ * @details\r
+ * Please refer to the reference manual for further details.\r
+ *\r
+ * @return\r
+ * The startup delay in use.\r
+ ******************************************************************************/\r
+uint32_t CMU_HFRCOStartupDelayGet(void)\r
+{\r
+ return((CMU->HFRCOCTRL & _CMU_HFRCOCTRL_SUDELAY_MASK) >>\r
+ _CMU_HFRCOCTRL_SUDELAY_SHIFT);\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Set the HFRCO startup delay.\r
+ *\r
+ * @details\r
+ * Please refer to the reference manual for further details.\r
+ *\r
+ * @param[in] delay\r
+ * The startup delay to set (<= 31).\r
+ ******************************************************************************/\r
+void CMU_HFRCOStartupDelaySet(uint32_t delay)\r
+{\r
+ EFM_ASSERT(delay <= 31);\r
+\r
+ delay &= (_CMU_HFRCOCTRL_SUDELAY_MASK >> _CMU_HFRCOCTRL_SUDELAY_SHIFT);\r
+ CMU->HFRCOCTRL = (CMU->HFRCOCTRL & ~(_CMU_HFRCOCTRL_SUDELAY_MASK)) |\r
+ (delay << _CMU_HFRCOCTRL_SUDELAY_SHIFT);\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get the LCD framerate divisor (FDIV) setting.\r
+ *\r
+ * @return\r
+ * The LCD framerate divisor.\r
+ ******************************************************************************/\r
+uint32_t CMU_LCDClkFDIVGet(void)\r
+{\r
+#if defined(LCD_PRESENT)\r
+ return((CMU->LCDCTRL & _CMU_LCDCTRL_FDIV_MASK) >> _CMU_LCDCTRL_FDIV_SHIFT);\r
+#else\r
+ return 0;\r
+#endif /* defined(LCD_PRESENT) */\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Set the LCD framerate divisor (FDIV) setting.\r
+ *\r
+ * @note\r
+ * The FDIV field (CMU LCDCTRL register) should only be modified while the\r
+ * LCD module is clock disabled (CMU LFACLKEN0.LCD bit is 0). This function\r
+ * will NOT modify FDIV if the LCD module clock is enabled. Please refer to\r
+ * CMU_ClockEnable() for disabling/enabling LCD clock.\r
+ *\r
+ * @param[in] div\r
+ * The FDIV setting to use.\r
+ ******************************************************************************/\r
+void CMU_LCDClkFDIVSet(uint32_t div)\r
+{\r
+#if defined(LCD_PRESENT)\r
+ EFM_ASSERT(div <= cmuClkDiv_128);\r
+\r
+ /* Do not allow modification if LCD clock enabled */\r
+ if (CMU->LFACLKEN0 & CMU_LFACLKEN0_LCD)\r
+ {\r
+ return;\r
+ }\r
+\r
+ div <<= _CMU_LCDCTRL_FDIV_SHIFT;\r
+ div &= _CMU_LCDCTRL_FDIV_MASK;\r
+ CMU->LCDCTRL = (CMU->LCDCTRL & ~_CMU_LCDCTRL_FDIV_MASK) | div;\r
+#else\r
+ (void)div; /* Unused parameter */\r
+#endif /* defined(LCD_PRESENT) */\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Enable/disable oscillator.\r
+ *\r
+ * @note\r
+ * WARNING: When this function is called to disable either cmuOsc_LFXO or\r
+ * cmuOsc_HFXO the LFXOMODE or HFXOMODE fields of the CMU_CTRL register\r
+ * are reset to the reset value. I.e. if external clock sources are selected\r
+ * in either LFXOMODE or HFXOMODE fields, the configuration will be cleared\r
+ * and needs to be reconfigured if needed later.\r
+ *\r
+ * @param[in] osc\r
+ * The oscillator to enable/disable.\r
+ *\r
+ * @param[in] enable\r
+ * @li true - enable specified oscillator.\r
+ * @li false - disable specified oscillator.\r
+ *\r
+ * @param[in] wait\r
+ * Only used if @p enable is true.\r
+ * @li true - wait for oscillator start-up time to timeout before returning.\r
+ * @li false - do not wait for oscillator start-up time to timeout before\r
+ * returning.\r
+ ******************************************************************************/\r
+void CMU_OscillatorEnable(CMU_Osc_TypeDef osc, bool enable, bool wait)\r
+{\r
+ uint32_t status;\r
+ uint32_t enBit;\r
+ uint32_t disBit;\r
+\r
+ switch (osc)\r
+ {\r
+ case cmuOsc_HFRCO:\r
+ enBit = CMU_OSCENCMD_HFRCOEN;\r
+ disBit = CMU_OSCENCMD_HFRCODIS;\r
+ status = CMU_STATUS_HFRCORDY;\r
+ break;\r
+\r
+ case cmuOsc_HFXO:\r
+ enBit = CMU_OSCENCMD_HFXOEN;\r
+ disBit = CMU_OSCENCMD_HFXODIS;\r
+ status = CMU_STATUS_HFXORDY;\r
+ break;\r
+\r
+ case cmuOsc_AUXHFRCO:\r
+ enBit = CMU_OSCENCMD_AUXHFRCOEN;\r
+ disBit = CMU_OSCENCMD_AUXHFRCODIS;\r
+ status = CMU_STATUS_AUXHFRCORDY;\r
+ break;\r
+\r
+ case cmuOsc_LFRCO:\r
+ enBit = CMU_OSCENCMD_LFRCOEN;\r
+ disBit = CMU_OSCENCMD_LFRCODIS;\r
+ status = CMU_STATUS_LFRCORDY;\r
+ break;\r
+\r
+ case cmuOsc_LFXO:\r
+ enBit = CMU_OSCENCMD_LFXOEN;\r
+ disBit = CMU_OSCENCMD_LFXODIS;\r
+ status = CMU_STATUS_LFXORDY;\r
+ break;\r
+\r
+#if defined( _CMU_STATUS_USHFRCOENS_MASK )\r
+ case cmuOsc_USHFRCO:\r
+ enBit = CMU_OSCENCMD_USHFRCOEN;\r
+ disBit = CMU_OSCENCMD_USHFRCODIS;\r
+ status = CMU_STATUS_USHFRCORDY;\r
+ break;\r
+#endif\r
+\r
+#if defined( _CMU_LFCLKSEL_LFAE_ULFRCO )\r
+ case cmuOsc_ULFRCO:\r
+ /* ULFRCO is always enabled, and cannot be turned off */\r
+ return;\r
+#endif\r
+\r
+ default:\r
+ /* Undefined clock source */\r
+ EFM_ASSERT(0);\r
+ return;\r
+ }\r
+\r
+ if (enable)\r
+ {\r
+ CMU->OSCENCMD = enBit;\r
+\r
+ /* Wait for clock to stabilize if requested */\r
+ if (wait)\r
+ {\r
+ while (!(CMU->STATUS & status))\r
+ ;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ CMU->OSCENCMD = disBit;\r
+ }\r
+\r
+ /* Keep EMU module informed */\r
+ EMU_UpdateOscConfig();\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Get oscillator frequency tuning setting.\r
+ *\r
+ * @param[in] osc\r
+ * Oscillator to get tuning value for, one of:\r
+ * @li #cmuOsc_LFRCO\r
+ * @li #cmuOsc_HFRCO\r
+ * @li #cmuOsc_AUXHFRCO\r
+ *\r
+ * @return\r
+ * The oscillator frequency tuning setting in use.\r
+ ******************************************************************************/\r
+uint32_t CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)\r
+{\r
+ uint32_t ret;\r
+\r
+ switch (osc)\r
+ {\r
+ case cmuOsc_LFRCO:\r
+ ret = (CMU->LFRCOCTRL & _CMU_LFRCOCTRL_TUNING_MASK) >>\r
+ _CMU_LFRCOCTRL_TUNING_SHIFT;\r
+ break;\r
+\r
+ case cmuOsc_HFRCO:\r
+ ret = (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_TUNING_MASK) >>\r
+ _CMU_HFRCOCTRL_TUNING_SHIFT;\r
+ break;\r
+\r
+ case cmuOsc_AUXHFRCO:\r
+ ret = (CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_TUNING_MASK) >>\r
+ _CMU_AUXHFRCOCTRL_TUNING_SHIFT;\r
+ break;\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ ret = 0;\r
+ break;\r
+ }\r
+\r
+ return(ret);\r
+}\r
+\r
+\r
+/***************************************************************************//**\r
+ * @brief\r
+ * Set the oscillator frequency tuning control.\r
+ *\r
+ * @note\r
+ * Oscillator tuning is done during production, and the tuning value is\r
+ * automatically loaded after a reset. Changing the tuning value from the\r
+ * calibrated value is for more advanced use.\r
+ *\r
+ * @param[in] osc\r
+ * Oscillator to set tuning value for, one of:\r
+ * @li #cmuOsc_LFRCO\r
+ * @li #cmuOsc_HFRCO\r
+ * @li #cmuOsc_AUXHFRCO\r
+ *\r
+ * @param[in] val\r
+ * The oscillator frequency tuning setting to use.\r
+ ******************************************************************************/\r
+void CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc, uint32_t val)\r
+{\r
+ switch (osc)\r
+ {\r
+ case cmuOsc_LFRCO:\r
+ EFM_ASSERT(val <= (_CMU_LFRCOCTRL_TUNING_MASK >> _CMU_LFRCOCTRL_TUNING_SHIFT));\r
+\r
+ val &= (_CMU_LFRCOCTRL_TUNING_MASK >> _CMU_LFRCOCTRL_TUNING_SHIFT);\r
+ CMU->LFRCOCTRL = (CMU->LFRCOCTRL & ~(_CMU_LFRCOCTRL_TUNING_MASK)) |\r
+ (val << _CMU_LFRCOCTRL_TUNING_SHIFT);\r
+ break;\r
+\r
+ case cmuOsc_HFRCO:\r
+ EFM_ASSERT(val <= (_CMU_HFRCOCTRL_TUNING_MASK >> _CMU_HFRCOCTRL_TUNING_SHIFT));\r
+\r
+ val &= (_CMU_HFRCOCTRL_TUNING_MASK >> _CMU_HFRCOCTRL_TUNING_SHIFT);\r
+ CMU->HFRCOCTRL = (CMU->HFRCOCTRL & ~(_CMU_HFRCOCTRL_TUNING_MASK)) |\r
+ (val << _CMU_HFRCOCTRL_TUNING_SHIFT);\r
+ break;\r
+\r
+ case cmuOsc_AUXHFRCO:\r
+ EFM_ASSERT(val <= (_CMU_AUXHFRCOCTRL_TUNING_MASK >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT));\r
+\r
+ val <<= _CMU_AUXHFRCOCTRL_TUNING_SHIFT;\r
+ val &= _CMU_AUXHFRCOCTRL_TUNING_MASK;\r
+ CMU->AUXHFRCOCTRL = (CMU->AUXHFRCOCTRL & ~(_CMU_AUXHFRCOCTRL_TUNING_MASK)) | val;\r
+ break;\r
+\r
+ default:\r
+ EFM_ASSERT(0);\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+/**************************************************************************//**\r
+ * @brief\r
+ * Determine if currently selected PCNTn clock used is external or LFBCLK.\r
+ *\r
+ * @param[in] inst\r
+ * PCNT instance number to get currently selected clock source for.\r
+ *\r
+ * @return\r
+ * @li true - selected clock is external clock.\r
+ * @li false - selected clock is LFBCLK.\r
+ *****************************************************************************/\r
+bool CMU_PCNTClockExternalGet(unsigned int inst)\r
+{\r
+ bool ret;\r
+ uint32_t setting;\r
+\r
+ switch (inst)\r
+ {\r
+#if defined(_CMU_PCNTCTRL_PCNT0CLKEN_MASK)\r
+ case 0:\r
+ setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT0CLKSEL_PCNT0S0;\r
+ break;\r
+\r
+#if defined(_CMU_PCNTCTRL_PCNT1CLKEN_MASK)\r
+ case 1:\r
+ setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT1CLKSEL_PCNT1S0;\r
+ break;\r
+\r
+#if defined(_CMU_PCNTCTRL_PCNT2CLKEN_MASK)\r
+ case 2:\r
+ setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT2CLKSEL_PCNT2S0;\r
+ break;\r
+#endif\r
+#endif\r
+#endif\r
+\r
+ default:\r
+ setting = 0;\r
+ break;\r
+ }\r
+\r
+ if (setting)\r
+ {\r
+ ret = true;\r
+ }\r
+ else\r
+ {\r
+ ret = false;\r
+ }\r
+ return ret;\r
+}\r
+\r
+\r
+/**************************************************************************//**\r
+ * @brief\r
+ * Select PCNTn clock.\r
+ *\r
+ * @param[in] inst\r
+ * PCNT instance number to set selected clock source for.\r
+ *\r
+ * @param[in] external\r
+ * Set to true to select external clock, false to select LFBCLK.\r
+ *****************************************************************************/\r
+void CMU_PCNTClockExternalSet(unsigned int inst, bool external)\r
+{\r
+#if defined(PCNT_PRESENT)\r
+ uint32_t setting = 0;\r
+\r
+ EFM_ASSERT(inst < PCNT_COUNT);\r
+\r
+ if (external)\r
+ {\r
+ setting = 1;\r
+ }\r
+\r
+ BITBAND_Peripheral(&(CMU->PCNTCTRL), (inst * 2) + 1, setting);\r
+\r
+#else\r
+ (void)inst; /* Unused parameter */\r
+ (void)external; /* Unused parameter */\r
+#endif\r
+}\r
+\r
+\r
+/** @} (end addtogroup CMU) */\r
+/** @} (end addtogroup EM_Library) */\r
+#endif /* __EM_CMU_H */\r