/**************************************************************************** * arch/arm/src/efm32/efm32_clockconfig.c * * Copyright (C) 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include "up_arch.h" #include "chip.h" #include "itm_syslog.h" #include "efm32_gpio.h" #include "chip/efm32_msc.h" #include "chip/efm32_cmu.h" #include "chip/efm32_gpio.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* BOARD Configuration ******************************************************/ /* Pre-scalers not currently implemented */ #if defined(CONFIG_EFM32_EFM32GG) && defined(BOARD_HFCLKDIV) && BOARD_HFCLKDIV != 0 # error HFCLK divisor not yet supported #endif #if defined(BOARD_HFCORECLKDIV) && BOARD_HFCORECLKDIV != 0 # error HFCORECLK divisor not yet supported #endif #if defined(BOARD_HFPERCLKDIV) && BOARD_HFPERCLKDIV != 0 # error HFPERCLK divisor not yet supported #endif #ifdef BOARD_LFACLK_ULFRCO # define BOARD_LFA_ULFCO_ENABLE true #else # define BOARD_LFA_ULFCO_ENABLE false #endif #ifdef BOARD_LFBCLK_ULFRCO # define BOARD_LFB_ULFCO_ENABLE true #else # define BOARD_LFB_ULFCO_ENABLE false #endif #ifndef CONFIG_EFM32_LECLOCK # if ( ( BOARD_LFACLKSEL != _CMU_LFCLKSEL_LFA_DISABLED ) || \ ( BOARD_LFBCLKSEL != _CMU_LFCLKSEL_LFB_DISABLED ) || \ ( defined ( CONFIG_EFM32_RTC_BURTC ) ) || \ ( defined ( CONFIG_EFM32_LEUART0 ) ) || \ ( defined ( CONFIG_EFM32_LEUART1 ) ) \ ) # define CONFIG_EFM32_LECLOCK # endif #endif /**************************************************************************** * Public Data ****************************************************************************/ /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: efm32_synchronize * * Description: * Wait for ongoing sync of register(s) to low frequency domain to * complete. * * Input Parameters: * bitset - Bitset corresponding to SYNCBUSY register defined bits, * indicating registers that must complete any ongoing * synchronization. * * Returned Value: * None * ****************************************************************************/ static inline void efm32_synchronize(uint32_t bitset) { /* Avoid deadlock if modifying a register again after freeze mode is * activated. */ if ((getreg32(EFM32_CMU_FREEZE) & CMU_FREEZE_REGFREEZE) == 0) { /* Wait for any pending previous write operation to complete */ while ((getreg32(EFM32_CMU_SYNCBUSY) & bitset) != 0); } } /**************************************************************************** * Name: efm32_statuswait * * Description: * Wait for ongoing CMU status bit(s) to become set * * Input Parameters: * bitset - Bitset corresponding to STATUS register defined bits, * indicating events that we are waiting for. * * Returned Value: * None * ****************************************************************************/ static inline void efm32_statuswait(uint32_t bitset) { /* Wait for clock to stabilize if requested */ while ((getreg32(EFM32_CMU_STATUS) & bitset) == 0); } /**************************************************************************** * Name: efm32_enable_XXX * * Description: * Enable specific oscillators * ****************************************************************************/ static void efm32_enable_lfrco(void) { /* Enable the LFRCO */ putreg32(CMU_OSCENCMD_LFRCOEN, EFM32_CMU_OSCENCMD); efm32_statuswait(CMU_STATUS_LFRCORDY); } static void efm32_enable_lfxo(void) { /* Enable the LFXO */ putreg32(CMU_OSCENCMD_LFXOEN, EFM32_CMU_OSCENCMD); efm32_statuswait(CMU_STATUS_LFXORDY); } static inline void efm32_enable_hfrco(void) { /* Enable the HFRCO */ putreg32(CMU_OSCENCMD_HFRCOEN, EFM32_CMU_OSCENCMD); efm32_statuswait(CMU_STATUS_HFRCORDY); } static void efm32_enable_hfxo(void) { /* Enable the HFXO */ putreg32(CMU_OSCENCMD_HFXOEN, EFM32_CMU_OSCENCMD); efm32_statuswait(CMU_STATUS_HFXORDY); } static inline void efm32_enable_auxhfrco(void) { /* Enable the HFXO */ putreg32(CMU_OSCENCMD_AUXHFRCOEN, EFM32_CMU_OSCENCMD); efm32_statuswait(CMU_STATUS_AUXHFRCORDY); } /**************************************************************************** * Name: efm32_enable_leclocking * * Description: * Enable HFCORE clocking to the LE * ****************************************************************************/ static void efm32_enable_leclocking(void) { uint32_t regval; regval = getreg32(EFM32_CMU_HFCORECLKEN0); regval |= CMU_HFCORECLKEN0_LE; putreg32(regval, EFM32_CMU_HFCORECLKEN0); } /**************************************************************************** * Name: efm32_maxwaitstates * * Description: * Configure flash access wait states to most maximum number of wait * states, preserving the SCBTP setting. * ****************************************************************************/ static void efm32_maxwaitstates(void) { uint32_t regval; uint32_t mode; /* Get the READCTRL register content and mask out the mode setting */ regval = getreg32(EFM32_MSC_READCTRL); mode = regval & _MSC_READCTRL_MODE_MASK; regval &= ~_MSC_READCTRL_MODE_MASK; /* SCBTP mode? */ if (mode == MSC_READCTRL_MODE_WS0SCBTP || mode == MSC_READCTRL_MODE_WS1SCBTP #ifdef MSC_READCTRL_MODE_WS2SCBTP || mode == MSC_READCTRL_MODE_WS2SCBTP #endif ) { /* Yes.. select the mximum number of wait states with SCBTP */ regval |= MSC_READCTRL_MODE_WSMAXSCBTP; } else { /* No.. select the mximum number of wait states without SCBTP */ regval |= MSC_READCTRL_MODE_WSMAX; } /* And save the update READCTRL register */ putreg32(regval, EFM32_MSC_READCTRL); } /**************************************************************************** * Name: efm32_setwaitstates * * Description: * Configure the optimal number of flash access wait states, preserving * the SCBTP setting. * ****************************************************************************/ static void efm32_setwaitstates(uint32_t hfcoreclk) { uint32_t regval; uint32_t mode; bool scbtp; /* SCBTP mode? */ regval = getreg32(EFM32_MSC_READCTRL); mode = regval & _MSC_READCTRL_MODE_MASK; scbtp = (mode == MSC_READCTRL_MODE_WS0SCBTP || mode == MSC_READCTRL_MODE_WS1SCBTP #ifdef MSC_READCTRL_MODE_WS2SCBTP || mode == MSC_READCTRL_MODE_WS2SCBTP #endif ); /* Select the number of wait states based on the HFCORECLK frequency */ regval &= ~_MSC_READCTRL_MODE_MASK; /* We can't do more than 2 wait states in any configuration */ #ifdef MSC_READCTRL_MODE_WS2 if (hfcoreclk > CMU_MAX_FREQ_2WS) { PANIC(); } else #endif /* Check if we can use 2 wait states */ if (hfcoreclk > CMU_MAX_FREQ_1WS) { #ifdef MSC_READCTRL_MODE_WS2 /* Yes.. select 2 wait states */ regval |= (scbtp ? MSC_READCTRL_MODE_WS2SCBTP : MSC_READCTRL_MODE_WS2); #else /* No.. this MCU does not support 2 wait states */ PANIC(); #endif } /* Check if we can use 1 wait states */ else if (hfcoreclk > CMU_MAX_FREQ_0WS) { /* Yes.. select 1 wait state */ regval |= (scbtp ? MSC_READCTRL_MODE_WS1SCBTP : MSC_READCTRL_MODE_WS1); } /* Check if we can use no wait states */ else { /* Select no wait states */ regval |= (scbtp ? MSC_READCTRL_MODE_WS0SCBTP : MSC_READCTRL_MODE_WS0); } /* And save the update READCTRL register */ putreg32(regval, EFM32_MSC_READCTRL); } /**************************************************************************** * Name: efm32_hfclk_config * * Description: * Configure the High Frequency Clock, HFCLK. * * HFCLK is the selected High Frequency Clock. This clock is used by the * CMU and drives the two prescalers that generate HFCORECLK and HFPERCLK. * The HFCLK can be driven by a high-frequency oscillator (HFRCO or HFXO) * or one of the low-frequency oscillators (LFRCO or LFXO). By default the * HFRCO is selected. To change the selected HFCLK write to HFCLKSEL in * CMU_CMD. The HFCLK is running in EM0 and EM1. * * HFCLK can optionally be divided down by setting HFCLKDIV in CMU_CTRL to * a non-zero value. This divides down HFCLK to all high frequency * components except the USB Core and is typically used to save energy in * USB applications where the system is not required to run at 48 MHz. * Combined with the HFCORECLK and HFPERCLK prescalers the HFCLK divider * also allows for more flexible clock division. * ****************************************************************************/ static inline uint32_t efm32_hfclk_config(uint32_t hfclksel, uint32_t hfclkdiv) { uint32_t frequency; #ifdef CMU_CTRL_HFLE uint32_t regval; #endif /* The HFRCO oscillator is selected by hardware as the clock source for * HFCLK when the device starts up . After reset, the HFRCO frequency is * 14 MHz. * * First enable the oscillator and wait for the oscillator to become ready * before switching the clock source. This way, the system continues to run * on the HFRCO until the oscillator has timed out and provides a reliable * clock. */ switch (hfclksel) { case _CMU_CMD_HFCLKSEL_LFRCO: { frequency = BOARD_LFRCO_FREQUENCY; efm32_enable_lfrco(); } break; case _CMU_CMD_HFCLKSEL_LFXO: { frequency = BOARD_LFXO_FREQUENCY; efm32_enable_lfxo(); } break; case _CMU_CMD_HFCLKSEL_HFRCO: { frequency = BOARD_HFRCO_FREQUENCY; efm32_enable_hfrco(); } break; case _CMU_CMD_HFCLKSEL_HFXO: { frequency = BOARD_HFXO_FREQUENCY; #ifdef CMU_CTRL_HFLE #if BOARD_HFXO_FREQUENCY > CMU_MAX_FREQ_HFLE /* Adjust HFXO buffer current for high crystal frequencies, enable HFLE * for frequencies above CMU_MAX_FREQ_HFLE. * * We must also have HFLE enabled to access some LE peripherals >= 32MHz. */ regval = getreg32(EFM32_CMU_CTRL); regval &= ~_CMU_CTRL_HFXOBUFCUR_MASK; regval |= CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ | CMU_CTRL_HFLE; putreg32(regval, EFM32_CMU_CTRL); /* Set DIV4 factor for peripheral clock if HFCORE clock for LE is * enabled. */ if ((getreg32(EFM32_CMU_HFCORECLKEN0) & CMU_HFCORECLKEN0_LE) != 0) { regval = getreg32(EFM32_CMU_HFCORECLKDIV); regval |= CMU_HFCORECLKDIV_HFCORECLKLEDIV_DIV4; putreg32(regval, EFM32_CMU_HFCORECLKDIV); } #else /* No boost... no HFLE */ regval = getreg32(EFM32_CMU_CTRL); regval &= ~(_CMU_CTRL_HFXOBUFCUR_MASK | CMU_CTRL_HFLE); regval |= CMU_CTRL_HFXOBUFCUR_BOOSTUPTO32MHZ; putreg32(regval, EFM32_CMU_CTRL); #endif #endif /* Enable the HFXO */ efm32_enable_hfxo(); } break; #ifdef CONFIG_DEBUG default: PANIC(); #endif } /* Set the maximum number of FLASH wait states before selecting the new * HFCLK source. */ efm32_maxwaitstates(); /* Switch to selected oscillator */ putreg32(hfclksel << _CMU_CMD_HFCLKSEL_SHIFT, EFM32_CMU_CMD); /* Now select the optimal number of FLASH wait states */ efm32_setwaitstates(frequency); return frequency; } /**************************************************************************** * Name: efm32_hfcoreclk_config * * Description: * Configure the High Frequency Core Clock, HFCORECLK. * * HFCORECLK is a prescaled version of HFCLK. This clock drives the Core * Modules, which consists of the CPU and modules that are tightly coupled * to the CPU, e.g. MSC, DMA etc. This also includes the interface to the * Low Energy Peripherals. Some of the modules that are driven by this * clock can be clock gated completely when not in use. This is done by * clearing the clock enable bit for the specific module in * CMU_HFCORECLKEN0. The frequency of HFCORECLK is set using the * CMU_HFCORECLKDIV register. The setting can be changed dynamically and * the new setting takes effect immediately. * * The USB Core clock (USBC) is always undivided regardless of the * HFCLKDIV setting. When the USB Core is active this clock must be * switched to a 32 kHz clock (LFRCO or LFXO) when entering EM2. The USB * Core uses this clock for monitoring the USB bus. The switch is done by * writing USBCCLKSEL in CMU_CMD. The currently active clock can be * checked by reading CMU_STATUS. The clock switch can take up to 1.5 32 * kHz cycle (45 us). To avoid polling the clock selection status when * switching switching from 32 kHz to HFCLK when coming up from EM2 the * USBCHFCLKSEL interrupt can be used. EM3 is not supported when the USB * is active. * ****************************************************************************/ #ifdef CONFIG_EFM32_LECLOCK uint32_t efm32_coreleclk_config(int frequency) { #ifdef CMU_CTRL_HFLE uint32_t regval; /* Check if the core frequency is higher than CMU_MAX_FREQ_HFLE */ if (frequency > CMU_MAX_FREQ_HFLE) { /* Enable HFLE */ regval = getreg32(EFM32_CMU_CTRL); regval |= CMU_CTRL_HFLE; putreg32(regval, EFM32_CMU_CTRL); /* Enable DIV4 factor for peripheral clock */ regval = getreg32(EFM32_CMU_HFCORECLKDIV); regval |= CMU_HFCORECLKDIV_HFCORECLKLEDIV_DIV4; putreg32(regval, EFM32_CMU_HFCORECLKDIV); frequency /= 4; } #else frequency /= 2; #endif /* Enable core clocking to the LE */ efm32_enable_leclocking(); return frequency; } #else # define efm32_coreleclk_config 0 #endif /**************************************************************************** * Name: efm32_hfcoreclk_config * * Description: * Configure the High Frequency Core Clock, HFCORECLK. * * HFCORECLK is a prescaled version of HFCLK. This clock drives the Core * Modules, which consists of the CPU and modules that are tightly coupled * to the CPU, e.g. MSC, DMA etc. This also includes the interface to the * Low Energy Peripherals. Some of the modules that are driven by this * clock can be clock gated completely when not in use. This is done by * clearing the clock enable bit for the specific module in * CMU_HFCORECLKEN0. The frequency of HFCORECLK is set using the * CMU_HFCORECLKDIV register. The setting can be changed dynamically and * the new setting takes effect immediately. * * The USB Core clock (USBC) is always undivided regardless of the * HFCLKDIV setting. When the USB Core is active this clock must be * switched to a 32 kHz clock (LFRCO or LFXO) when entering EM2. The USB * Core uses this clock for monitoring the USB bus. The switch is done by * writing USBCCLKSEL in CMU_CMD. The currently active clock can be * checked by reading CMU_STATUS. The clock switch can take up to 1.5 32 * kHz cycle (45 us). To avoid polling the clock selection status when * switching switching from 32 kHz to HFCLK when coming up from EM2 the * USBCHFCLKSEL interrupt can be used. EM3 is not supported when the USB * is active. * ****************************************************************************/ static inline uint32_t efm32_hfcoreclk_config(uint32_t hfcoreclkdiv, uint32_t hfclk) { /* REVISIT: Divider not currently used */ return hfclk; } /**************************************************************************** * Name: efm32_hfperclk_config * * Description: * Configure the High Frequency Peripheral Clock, HFPERCLK. * * Like HFCORECLK, HFPERCLK can also be a prescaled version of HFCLK. This * clock drives the High-Frequency Peripherals. All the peripherals that * are driven by this clock can be clock gated completely when not in use. * This is done by clearing the clock enable bit for the specific * peripheral in CMU_HFPERCLKEN0. The frequency of HFPERCLK is set using * the CMU_HFPERCLKDIV register. The setting can be changed dynamically * and the new setting takes effect immediately. * ****************************************************************************/ static inline uint32_t efm32_hfperclk_config(uint32_t hfperclkdiv, uint32_t hfclk) { uint32_t regval; unsigned int divider; DEBUGASSERT(hfperclkdiv <= _CMU_HFPERCLKDIV_HFPERCLKDIV_HFCLK512); /* Set the divider and enable the HFPERCLK */ regval = (hfperclkdiv << _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT) | CMU_HFPERCLKDIV_HFPERCLKEN; putreg32(regval, EFM32_CMU_HFPERCLKDIV); /* The value of hfperclkdiv is log2 of the arithmetic divisor: * 0->1, 1->2, 2->4, 3->8, ... 9->512. */ divider = 1 << hfperclkdiv; return hfclk / divider; } /**************************************************************************** * Name: efm32_lfaclk_config * * Description: * Configure the Low Frequency A Clock, LFACLK. * * LFACLK is the selected clock for the Low Energy A Peripherals. There * are four selectable sources for LFACLK: LFRCO, LFXO, HFCORECLK/2 and * ULFRCO. In addition, the LFACLK can be disabled. From reset, the * LFACLK source is set to LFRCO. However, note that the LFRCO is disabled * from reset. The selection is configured using the LFA field in * CMU_LFCLKSEL. The HFCORECLK/2 setting allows the Low Energy A * Peripherals to be used as high-frequency peripherals. * * Each Low Energy Peripheral that is clocked by LFACLK has its own * prescaler setting and enable bit. The prescaler settings are configured * using CMU_LFAPRESC0 and the clock enable bits can be found in * CMU_LFACLKEN0. Notice that the LCD has an additional high resolution * prescaler for Frame Rate Control, configured by FDIV in CMU_LCDCTRL. * When operating in oversampling mode, the pulse counters are clocked by * LFACLK. This is configured for each pulse counter (n) individually by * setting PCNTnCLKSEL in CMU_PCNTCTRL. * ****************************************************************************/ static inline uint32_t efm32_lfaclk_config(uint32_t lfaclksel, bool ulfrco, uint32_t hfcoreclk) { uint32_t lfaclk; uint32_t regval; /* ULFRCO is a special case */ if (ulfrco) { /* ULFRCO is always enabled */ lfaclksel = _CMU_LFCLKSEL_LFA_DISABLED; lfaclk = BOARD_ULFRCO_FREQUNCY; } else { /* Enable the oscillator source */ switch (lfaclksel) { default: case _CMU_LFCLKSEL_LFA_DISABLED: { lfaclk = 0; } break; case CMU_LFCLKSEL_LFA_LFRCO: { efm32_enable_lfrco(); lfaclk = BOARD_LFRCO_FREQUENCY; } break; case _CMU_LFCLKSEL_LFA_LFXO: { efm32_enable_lfxo(); lfaclk = BOARD_LFXO_FREQUENCY; } break; case _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2: { lfaclk = hfcoreclk >> 1; } break; } } /* Enable the LFA clock in the LFCLKSEL register */ regval = getreg32(EFM32_CMU_LFCLKSEL); #ifdef CMU_LFCLKSEL_LFAE regval &= ~_CMU_LFCLKSEL_LFAE_MASK; #endif regval &= ~_CMU_LFCLKSEL_LFA_MASK; regval |= (lfaclksel << _CMU_LFCLKSEL_LFA_SHIFT); #ifdef CMU_LFCLKSEL_LFAE_ULFRCO regval |= ((uint32_t)ulfrco << _CMU_LFCLKSEL_LFAE_SHIFT); #endif putreg32(regval, EFM32_CMU_LFCLKSEL); return lfaclk; } /**************************************************************************** * Name: efm32_lfbclk_config * * Description: * Configure the Low Frequency B Clock, LFBCLK. * * LFBCLK is the selected clock for the Low Energy B Peripherals. There * are four selectable sources for LFBCLK: LFRCO, LFXO, HFCORECLK/2 and * ULFRCO. In addition, the LFBCLK can be disabled. From reset, the LFBCLK * source is set to LFRCO. However, note that the LFRCO is disabled from * reset. The selection is configured using the LFB field in CMU_LFCLKSEL. * The HFCORECLK/2 setting allows the Low Energy B Peripherals to be used * as high-frequency peripherals. * * Each Low Energy Peripheral that is clocked by LFBCLK has its own * prescaler setting and enable bit. The prescaler settings are * configured using CMU_LFBPRESC0 and the clock enable bits can be found * in CMU_LFBCLKEN0. * ****************************************************************************/ static inline uint32_t efm32_lfbclk_config(uint32_t lfbclksel, bool ulfrco, uint32_t hfcoreclk) { uint32_t lfbclk; uint32_t regval; /* ULFRCO is a special case */ if (ulfrco) { /* ULFRCO is always enabled */ lfbclksel = _CMU_LFCLKSEL_LFB_DISABLED; lfbclk = BOARD_ULFRCO_FREQUNCY; } else { /* Enable the oscillator source */ switch (lfbclksel) { default: case _CMU_LFCLKSEL_LFB_DISABLED: { lfbclk = 0; } break; case CMU_LFCLKSEL_LFB_LFRCO: { efm32_enable_lfrco(); } break; case _CMU_LFCLKSEL_LFB_LFXO: { efm32_enable_lfxo(); lfbclk = BOARD_LFXO_FREQUENCY; } break; case _CMU_LFCLKSEL_LFB_HFCORECLKLEDIV2: { lfbclk = hfcoreclk >> 1; } break; } } /* Enable the LFB clock in the LFCLKSEL register */ regval = getreg32(EFM32_CMU_LFCLKSEL); #ifdef CMU_LFCLKSEL_LFBE regval &= ~_CMU_LFCLKSEL_LFBE_MASK; #endif regval &= ~_CMU_LFCLKSEL_LFB_MASK; regval |= (lfbclksel << _CMU_LFCLKSEL_LFB_SHIFT); #ifdef CMU_LFCLKSEL_LFBE_ULFRCO regval |= ((uint32_t)ulfrco << _CMU_LFCLKSEL_LFBE_SHIFT); #endif putreg32(regval, EFM32_CMU_LFCLKSEL); return lfbclk; } /**************************************************************************** * Name: efm32_pcntclk_config * * Description: * Configure the Pulse Counter n Clock, PCNTnCLK. * * Each available pulse counter is driven by its own clock, PCNTnCLK where * n is the pulse counter instance number. Each pulse counter can be * configured to use an external pin (PCNTn_S0) or LFACLK as PCNTnCLK. * ****************************************************************************/ static inline void efm32_pcntclk_config(void) { /* REVISIT: Not yet implemented */ } /**************************************************************************** * Name: efm32_wdogclk_config * * Description: * Configure the Watchdog Timer Clock, WDOGCLK. * * The Watchdog Timer (WDOG) can be configured to use one of three * different clock sources: LFRCO, LFXO or ULFRCO. ULFRCO (Ultra Low * Frequency RC Oscillator) is a separate 1 kHz RC oscillator that also * runs in EM3. * ****************************************************************************/ static inline void efm32_wdogclk_config(void) { /* REVISIT: Not yet implemented */ } /**************************************************************************** * Name: efm32_auxclk_config * * Description: * Configure the Auxiliary Clock, AUXCLK. * * AUXCLK is a 1-28 MHz clock driven by a separate RC oscillator, AUXHFRCO. * This clock is used for flash programming, and Serial Wire Output (SWO), * and LESENSE operation. During flash programming, or if needed by * LESENSE, this clock will be active. If the AUXHFRCO has not been * enabled explicitly by software, the MSC or LESENSE module will * automatically start and stop it. The AUXHFRCO is enabled by writing a 1 * to AUXHFRCOEN in CMU_OSCENCMD. This explicit enabling is required when * SWO is used. * ****************************************************************************/ static inline void efm32_auxclk_config(void) { /* REVISIT: Not yet implemented */ } /**************************************************************************** * Name: efm32_gpioclock * * Description: * Enable clocking to the GPIO * ****************************************************************************/ static inline void efm32_gpioclock(void) { uint32_t regval; /* Enable clocking to the GPIO be setting the GPIO bit in the High * Frequency Peripheral Clock Enable. */ regval = getreg32(EFM32_CMU_HFPERCLKEN0); regval |= CMU_HFPERCLKEN0_GPIO; putreg32(regval, EFM32_CMU_HFPERCLKEN0); } /**************************************************************************** * Name: efm32_itm_syslog * * Description: * Enable Serial wire output pin, configure debug clocking, and enable * ITM syslog support. * ****************************************************************************/ #if defined(CONFIG_SYSLOG) || defined(CONFIG_ARMV7M_ITMSYSLOG) static inline void efm32_itm_syslog(void) { int regval; /* Enable Serial wire output pin * * Set location and enable output on the pin. All pin configuration * information must be provided in the board.h header file. */ regval = getreg32(EFM32_GPIO_ROUTE); regval &= ~_GPIO_ROUTE_SWLOCATION_MASK; regval |= GPIO_ROUTE_SWOPEN; regval |= ((uint32_t)BOARD_SWOPORT_LOCATION << _GPIO_ROUTE_SWLOCATION_SHIFT); putreg32(regval, EFM32_GPIO_ROUTE); /* Enable output on pin */ efm32_configgpio(BOARD_GPIO_SWOPORT); /* Enable debug clock AUXHFRCO */ efm32_enable_auxhfrco(); /* Then perform ARMv7-M ITM SYSLOG initialization */ itm_syslog_initialize(); } #else # define efm32_itm_syslog() #endif /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: efm32_clockconfig * * Description: * Called to initialize the EFM32 chip. This does whatever setup is * needed to put the MCU in a usable state. This includes the * initialization of clocking using the settings in board.h. * ****************************************************************************/ void efm32_clockconfig(void) { uint32_t hfclk; uint32_t hfcoreclk; uint32_t hfperclk; uint32_t coreleclk; uint32_t lfaclk; uint32_t lfbclk; /* Enable clocks and set dividers as determined by the board.h header file */ hfclk = efm32_hfclk_config(BOARD_HFCLKSEL, BOARD_HFCLKDIV); hfcoreclk = efm32_hfcoreclk_config(BOARD_HFCORECLKDIV, hfclk); hfperclk = efm32_hfperclk_config(BOARD_HFPERCLKDIV, hfclk); coreleclk = efm32_coreleclk_config(hfclk); lfaclk = efm32_lfaclk_config(BOARD_LFACLKSEL, BOARD_LFA_ULFCO_ENABLE, hfcoreclk); lfbclk = efm32_lfbclk_config(BOARD_LFBCLKSEL, BOARD_LFB_ULFCO_ENABLE, hfcoreclk); efm32_pcntclk_config(); efm32_wdogclk_config(); efm32_auxclk_config(); UNUSED(hfperclk); UNUSED(coreleclk); UNUSED(lfaclk); UNUSED(lfbclk); /* Enable clocking of the GPIO ports */ efm32_gpioclock(); /* Enable Serial wire output pin, configure debug clocking, and enable ITM * syslog support. */ efm32_itm_syslog(); }