added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

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