mbed library sources

Fork of mbed-src by mbed official

Revision:
613:bc40b8d2aec4
Parent:
612:fba1c7dc54c0
Child:
614:9d86c2ae5de0
--- a/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/system/clock/clock_samd21_r21/clock.c	Tue Aug 18 15:00:09 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,958 +0,0 @@
-#include <compiler.h>
-#include <clock.h>
-#include <conf_clocks.h>
-#include <system.h>
-
-#ifndef SYSCTRL_FUSES_OSC32K_ADDR
-#  define SYSCTRL_FUSES_OSC32K_ADDR SYSCTRL_FUSES_OSC32K_CAL_ADDR
-#  define SYSCTRL_FUSES_OSC32K_Pos  SYSCTRL_FUSES_OSC32K_CAL_Pos
-#endif
-
-/**
- * \internal
- * \brief DFLL-specific data container.
- */
-struct _system_clock_dfll_config {
-    uint32_t control;
-    uint32_t val;
-    uint32_t mul;
-};
-
-/**
- * \internal
- * \brief DPLL-specific data container.
- */
-struct _system_clock_dpll_config {
-    uint32_t frequency;
-};
-
-
-/**
- * \internal
- * \brief XOSC-specific data container.
- */
-struct _system_clock_xosc_config {
-    uint32_t frequency;
-};
-
-/**
- * \internal
- * \brief System clock module data container.
- */
-struct _system_clock_module {
-    volatile struct _system_clock_dfll_config dfll;
-
-#ifdef FEATURE_SYSTEM_CLOCK_DPLL
-    volatile struct _system_clock_dpll_config dpll;
-#endif
-
-    volatile struct _system_clock_xosc_config xosc;
-    volatile struct _system_clock_xosc_config xosc32k;
-};
-
-/**
- * \internal
- * \brief Internal module instance to cache configuration values.
- */
-static struct _system_clock_module _system_clock_inst = {
-    .dfll = {
-        .control     = 0,
-        .val     = 0,
-        .mul     = 0,
-    },
-
-#ifdef FEATURE_SYSTEM_CLOCK_DPLL
-    .dpll = {
-        .frequency   = 0,
-    },
-#endif
-    .xosc = {
-        .frequency   = 0,
-    },
-    .xosc32k = {
-        .frequency   = 0,
-    },
-};
-
-/**
- * \internal
- * \brief Wait for sync to the DFLL control registers.
- */
-static inline void _system_dfll_wait_for_sync(void)
-{
-    while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY)) {
-        /* Wait for DFLL sync */
-    }
-}
-
-/**
- * \internal
- * \brief Wait for sync to the OSC32K control registers.
- */
-static inline void _system_osc32k_wait_for_sync(void)
-{
-    while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC32KRDY)) {
-        /* Wait for OSC32K sync */
-    }
-}
-
-static inline void _system_clock_source_dfll_set_config_errata_9905(void)
-{
-
-    /* Disable ONDEMAND mode while writing configurations */
-    SYSCTRL->DFLLCTRL.reg = _system_clock_inst.dfll.control & ~SYSCTRL_DFLLCTRL_ONDEMAND;
-    _system_dfll_wait_for_sync();
-
-    SYSCTRL->DFLLMUL.reg = _system_clock_inst.dfll.mul;
-    SYSCTRL->DFLLVAL.reg = _system_clock_inst.dfll.val;
-
-    /* Write full configuration to DFLL control register */
-    SYSCTRL->DFLLCTRL.reg = _system_clock_inst.dfll.control;
-}
-
-/**
- * \brief Retrieve the frequency of a clock source.
- *
- * Determines the current operating frequency of a given clock source.
- *
- * \param[in] clock_source  Clock source to get the frequency
- *
- * \returns Frequency of the given clock source, in Hz.
- */
-uint32_t system_clock_source_get_hz(
-    const enum system_clock_source clock_source)
-{
-    switch (clock_source) {
-        case SYSTEM_CLOCK_SOURCE_XOSC:
-            return _system_clock_inst.xosc.frequency;
-
-        case SYSTEM_CLOCK_SOURCE_OSC8M:
-            return 8000000UL >> SYSCTRL->OSC8M.bit.PRESC;
-
-        case SYSTEM_CLOCK_SOURCE_OSC32K:
-            return 32768UL;
-
-        case SYSTEM_CLOCK_SOURCE_ULP32K:
-            return 32768UL;
-
-        case SYSTEM_CLOCK_SOURCE_XOSC32K:
-            return _system_clock_inst.xosc32k.frequency;
-
-        case SYSTEM_CLOCK_SOURCE_DFLL:
-
-            /* Check if the DFLL has been configured */
-            if (!(_system_clock_inst.dfll.control & SYSCTRL_DFLLCTRL_ENABLE))
-                return 0;
-
-            /* Make sure that the DFLL module is ready */
-            _system_dfll_wait_for_sync();
-
-            /* Check if operating in closed loop mode */
-            if (_system_clock_inst.dfll.control & SYSCTRL_DFLLCTRL_MODE) {
-                return system_gclk_chan_get_hz(SYSCTRL_GCLK_ID_DFLL48) *
-                       (_system_clock_inst.dfll.mul & 0xffff);
-            }
-
-            return 48000000UL;
-
-#ifdef FEATURE_SYSTEM_CLOCK_DPLL
-        case SYSTEM_CLOCK_SOURCE_DPLL:
-            if (!(SYSCTRL->DPLLSTATUS.reg & SYSCTRL_DPLLSTATUS_ENABLE)) {
-                return 0;
-            }
-
-            return _system_clock_inst.dpll.frequency;
-#endif
-
-        default:
-            return 0;
-    }
-}
-
-/**
- * \brief Configure the internal OSC8M oscillator clock source.
- *
- * Configures the 8MHz (nominal) internal RC oscillator with the given
- * configuration settings.
- *
- * \param[in] config  OSC8M configuration structure containing the new config
- */
-void system_clock_source_osc8m_set_config(
-    struct system_clock_source_osc8m_config *const config)
-{
-    SYSCTRL_OSC8M_Type temp = SYSCTRL->OSC8M;
-
-    /* Use temporary struct to reduce register access */
-    temp.bit.PRESC    = config->prescaler;
-    temp.bit.ONDEMAND = config->on_demand;
-    temp.bit.RUNSTDBY = config->run_in_standby;
-
-    SYSCTRL->OSC8M = temp;
-}
-
-/**
- * \brief Configure the internal OSC32K oscillator clock source.
- *
- * Configures the 32KHz (nominal) internal RC oscillator with the given
- * configuration settings.
- *
- * \param[in] config  OSC32K configuration structure containing the new config
- */
-void system_clock_source_osc32k_set_config(
-    struct system_clock_source_osc32k_config *const config)
-{
-    SYSCTRL_OSC32K_Type temp = SYSCTRL->OSC32K;
-
-    /* Update settings via a temporary struct to reduce register access */
-    temp.bit.EN1K     = config->enable_1khz_output;
-    temp.bit.EN32K    = config->enable_32khz_output;
-    temp.bit.STARTUP  = config->startup_time;
-    temp.bit.ONDEMAND = config->on_demand;
-    temp.bit.RUNSTDBY = config->run_in_standby;
-    temp.bit.WRTLOCK  = config->write_once;
-
-    SYSCTRL->OSC32K  = temp;
-}
-
-/**
- * \brief Configure the external oscillator clock source.
- *
- * Configures the external oscillator clock source with the given configuration
- * settings.
- *
- * \param[in] config  External oscillator configuration structure containing
- *                    the new config
- */
-void system_clock_source_xosc_set_config(
-    struct system_clock_source_xosc_config *const config)
-{
-    SYSCTRL_XOSC_Type temp = SYSCTRL->XOSC;
-
-    temp.bit.STARTUP = config->startup_time;
-
-    if (config->external_clock == SYSTEM_CLOCK_EXTERNAL_CRYSTAL) {
-        temp.bit.XTALEN = 1;
-    } else {
-        temp.bit.XTALEN = 0;
-    }
-
-    temp.bit.AMPGC = config->auto_gain_control;
-
-    /* Set gain if automatic gain control is not selected */
-    if (!config->auto_gain_control) {
-        if (config->frequency <= 2000000) {
-            temp.bit.GAIN = 0;
-        } else if (config->frequency <= 4000000) {
-            temp.bit.GAIN = 1;
-        } else if (config->frequency <= 8000000) {
-            temp.bit.GAIN = 2;
-        } else if (config->frequency <= 16000000) {
-            temp.bit.GAIN = 3;
-        } else if (config->frequency <= 30000000) {
-            temp.bit.GAIN = 4;
-        }
-
-    }
-
-    temp.bit.ONDEMAND = config->on_demand;
-    temp.bit.RUNSTDBY = config->run_in_standby;
-
-    /* Store XOSC frequency for internal use */
-    _system_clock_inst.xosc.frequency = config->frequency;
-
-    SYSCTRL->XOSC = temp;
-}
-
-/**
- * \brief Configure the XOSC32K external 32KHz oscillator clock source.
- *
- * Configures the external 32KHz oscillator clock source with the given
- * configuration settings.
- *
- * \param[in] config  XOSC32K configuration structure containing the new config
- */
-void system_clock_source_xosc32k_set_config(
-    struct system_clock_source_xosc32k_config *const config)
-{
-    SYSCTRL_XOSC32K_Type temp = SYSCTRL->XOSC32K;
-
-    temp.bit.STARTUP = config->startup_time;
-
-    if (config->external_clock == SYSTEM_CLOCK_EXTERNAL_CRYSTAL) {
-        temp.bit.XTALEN = 1;
-    } else {
-        temp.bit.XTALEN = 0;
-    }
-
-    temp.bit.AAMPEN = config->auto_gain_control;
-    temp.bit.EN1K = config->enable_1khz_output;
-    temp.bit.EN32K = config->enable_32khz_output;
-
-    temp.bit.ONDEMAND = config->on_demand;
-    temp.bit.RUNSTDBY = config->run_in_standby;
-    temp.bit.WRTLOCK  = config->write_once;
-
-    /* Cache the new frequency in case the user needs to check the current
-     * operating frequency later */
-    _system_clock_inst.xosc32k.frequency = config->frequency;
-
-    SYSCTRL->XOSC32K = temp;
-}
-
-/**
- * \brief Configure the DFLL clock source.
- *
- * Configures the Digital Frequency Locked Loop clock source with the given
- * configuration settings.
- *
- * \note The DFLL will be running when this function returns, as the DFLL module
- *       needs to be enabled in order to perform the module configuration.
- *
- * \param[in] config  DFLL configuration structure containing the new config
- */
-void system_clock_source_dfll_set_config(
-    struct system_clock_source_dfll_config *const config)
-{
-    _system_clock_inst.dfll.val =
-        SYSCTRL_DFLLVAL_COARSE(config->coarse_value) |
-        SYSCTRL_DFLLVAL_FINE(config->fine_value);
-
-    _system_clock_inst.dfll.control =
-        (uint32_t)config->wakeup_lock     |
-        (uint32_t)config->stable_tracking |
-        (uint32_t)config->quick_lock      |
-        (uint32_t)config->chill_cycle     |
-        ((uint32_t)config->on_demand << SYSCTRL_DFLLCTRL_ONDEMAND_Pos);
-
-    if (config->loop_mode == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) {
-
-        _system_clock_inst.dfll.mul =
-            SYSCTRL_DFLLMUL_CSTEP(config->coarse_max_step) |
-            SYSCTRL_DFLLMUL_FSTEP(config->fine_max_step)   |
-            SYSCTRL_DFLLMUL_MUL(config->multiply_factor);
-
-        /* Enable the closed loop mode */
-        _system_clock_inst.dfll.control |= config->loop_mode;
-    }
-    if (config->loop_mode == SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY) {
-
-        _system_clock_inst.dfll.mul =
-            SYSCTRL_DFLLMUL_MUL(config->multiply_factor);
-
-        /* Enable the USB recovery mode */
-        _system_clock_inst.dfll.control |= config->loop_mode |
-                                           SYSCTRL_DFLLCTRL_BPLCKC;
-    }
-}
-
-#ifdef FEATURE_SYSTEM_CLOCK_DPLL
-/**
- * \brief Configure the DPLL clock source.
- *
- * Configures the Digital Phase-Locked Loop clock source with the given
- * configuration settings.
- *
- * \note The DPLL will be running when this function returns, as the DPLL module
- *       needs to be enabled in order to perform the module configuration.
- *
- * \param[in] config  DPLL configuration structure containing the new config
- */
-void system_clock_source_dpll_set_config(
-    struct system_clock_source_dpll_config *const config)
-{
-
-    uint32_t tmpldr;
-    uint8_t  tmpldrfrac;
-    uint32_t refclk;
-
-    refclk = config->reference_frequency;
-
-    /* Only reference clock REF1 can be divided */
-    if (config->reference_clock == SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_REF1) {
-        refclk = refclk / config->reference_divider;
-    }
-
-    /* Calculate LDRFRAC and LDR */
-    tmpldr = (config->output_frequency << 4) / refclk;
-    tmpldrfrac = tmpldr & 0x0f;
-    tmpldr = (tmpldr >> 4) - 1;
-
-    SYSCTRL->DPLLCTRLA.reg =
-        ((uint32_t)config->on_demand << SYSCTRL_DPLLCTRLA_ONDEMAND_Pos) |
-        ((uint32_t)config->run_in_standby << SYSCTRL_DPLLCTRLA_RUNSTDBY_Pos);
-
-    SYSCTRL->DPLLRATIO.reg =
-        SYSCTRL_DPLLRATIO_LDRFRAC(tmpldrfrac) |
-        SYSCTRL_DPLLRATIO_LDR(tmpldr);
-
-    SYSCTRL->DPLLCTRLB.reg =
-        SYSCTRL_DPLLCTRLB_DIV(config->reference_divider) |
-        ((uint32_t)config->lock_bypass << SYSCTRL_DPLLCTRLB_LBYPASS_Pos) |
-        SYSCTRL_DPLLCTRLB_LTIME(config->lock_time) |
-        SYSCTRL_DPLLCTRLB_REFCLK(config->reference_clock) |
-        ((uint32_t)config->wake_up_fast << SYSCTRL_DPLLCTRLB_WUF_Pos) |
-        ((uint32_t)config->low_power_enable << SYSCTRL_DPLLCTRLB_LPEN_Pos) |
-        SYSCTRL_DPLLCTRLB_FILTER(config->filter);
-
-    /*
-     * Fck = Fckrx * (LDR + 1 + LDRFRAC / 16)
-     */
-    _system_clock_inst.dpll.frequency =
-        (config->reference_frequency *
-         (((tmpldr + 1) << 4) + tmpldrfrac)
-        ) >> 4;
-}
-#endif
-
-/**
- * \brief Writes the calibration values for a given oscillator clock source.
- *
- * Writes an oscillator calibration value to the given oscillator control
- * registers. The acceptable ranges are:
- *
- * For OSC32K:
- *  - 7 bits (max value 128)
- * For OSC8MHZ:
- *  - 8 bits (Max value 255)
- * For OSCULP:
- *  - 5 bits (Max value 32)
- *
- * \note The frequency range parameter applies only when configuring the 8MHz
- *       oscillator and will be ignored for the other oscillators.
- *
- * \param[in] clock_source       Clock source to calibrate
- * \param[in] calibration_value  Calibration value to write
- * \param[in] freq_range         Frequency range (8MHz oscillator only)
- *
- * \retval STATUS_OK               The calibration value was written
- *                                 successfully.
- * \retval STATUS_ERR_INVALID_ARG  The setting is not valid for selected clock
- *                                 source.
- */
-enum status_code system_clock_source_write_calibration(
-    const enum system_clock_source clock_source,
-    const uint16_t calibration_value,
-    const uint8_t freq_range)
-{
-    switch (clock_source) {
-        case SYSTEM_CLOCK_SOURCE_OSC8M:
-
-                    if (calibration_value > 0xfff || freq_range > 4) {
-                    return STATUS_ERR_INVALID_ARG;
-                }
-
-            SYSCTRL->OSC8M.bit.CALIB  = calibration_value;
-            SYSCTRL->OSC8M.bit.FRANGE = freq_range;
-            break;
-
-        case SYSTEM_CLOCK_SOURCE_OSC32K:
-
-            if (calibration_value > 128) {
-                return STATUS_ERR_INVALID_ARG;
-            }
-
-            _system_osc32k_wait_for_sync();
-            SYSCTRL->OSC32K.bit.CALIB = calibration_value;
-            break;
-
-        case SYSTEM_CLOCK_SOURCE_ULP32K:
-
-            if (calibration_value > 32) {
-                return STATUS_ERR_INVALID_ARG;
-            }
-
-            SYSCTRL->OSCULP32K.bit.CALIB = calibration_value;
-            break;
-
-        default:
-            Assert(false);
-            return STATUS_ERR_INVALID_ARG;
-            break;
-    }
-
-    return STATUS_OK;
-}
-
-/**
- * \brief Enables a clock source.
- *
- * Enables a clock source which has been previously configured.
- *
- * \param[in] clock_source       Clock source to enable
- *
- * \retval STATUS_OK               Clock source was enabled successfully and
- *                                 is ready
- * \retval STATUS_ERR_INVALID_ARG  The clock source is not available on this
- *                                 device
- */
-enum status_code system_clock_source_enable(
-    const enum system_clock_source clock_source)
-{
-    switch (clock_source) {
-        case SYSTEM_CLOCK_SOURCE_OSC8M:
-                    SYSCTRL->OSC8M.reg |= SYSCTRL_OSC8M_ENABLE;
-                return STATUS_OK;
-
-            case SYSTEM_CLOCK_SOURCE_OSC32K:
-                SYSCTRL->OSC32K.reg |= SYSCTRL_OSC32K_ENABLE;
-                break;
-
-            case SYSTEM_CLOCK_SOURCE_XOSC:
-                SYSCTRL->XOSC.reg |= SYSCTRL_XOSC_ENABLE;
-                break;
-
-            case SYSTEM_CLOCK_SOURCE_XOSC32K:
-                SYSCTRL->XOSC32K.reg |= SYSCTRL_XOSC32K_ENABLE;
-                break;
-
-            case SYSTEM_CLOCK_SOURCE_DFLL:
-                _system_clock_inst.dfll.control |= SYSCTRL_DFLLCTRL_ENABLE;
-                _system_clock_source_dfll_set_config_errata_9905();
-                break;
-
-#ifdef FEATURE_SYSTEM_CLOCK_DPLL
-            case SYSTEM_CLOCK_SOURCE_DPLL:
-                SYSCTRL->DPLLCTRLA.reg |= SYSCTRL_DPLLCTRLA_ENABLE;
-                break;
-#endif
-
-            case SYSTEM_CLOCK_SOURCE_ULP32K:
-                /* Always enabled */
-                return STATUS_OK;
-
-            default:
-                Assert(false);
-                return STATUS_ERR_INVALID_ARG;
-        }
-
-        return STATUS_OK;
-    }
-
-    /**
-     * \brief Disables a clock source.
-     *
-     * Disables a clock source that was previously enabled.
-     *
-     * \param[in] clock_source  Clock source to disable
-     *
-     * \retval STATUS_OK               Clock source was disabled successfully
-     * \retval STATUS_ERR_INVALID_ARG  An invalid or unavailable clock source was
-     *                                 given
-     */
-    enum status_code system_clock_source_disable(
-        const enum system_clock_source clock_source)
-{
-    switch (clock_source) {
-        case SYSTEM_CLOCK_SOURCE_OSC8M:
-                    SYSCTRL->OSC8M.reg &= ~SYSCTRL_OSC8M_ENABLE;
-                break;
-
-            case SYSTEM_CLOCK_SOURCE_OSC32K:
-                SYSCTRL->OSC32K.reg &= ~SYSCTRL_OSC32K_ENABLE;
-                break;
-
-            case SYSTEM_CLOCK_SOURCE_XOSC:
-                SYSCTRL->XOSC.reg &= ~SYSCTRL_XOSC_ENABLE;
-                break;
-
-            case SYSTEM_CLOCK_SOURCE_XOSC32K:
-                SYSCTRL->XOSC32K.reg &= ~SYSCTRL_XOSC32K_ENABLE;
-                break;
-
-            case SYSTEM_CLOCK_SOURCE_DFLL:
-                _system_clock_inst.dfll.control &= ~SYSCTRL_DFLLCTRL_ENABLE;
-                SYSCTRL->DFLLCTRL.reg = _system_clock_inst.dfll.control;
-                break;
-
-#ifdef FEATURE_SYSTEM_CLOCK_DPLL
-            case SYSTEM_CLOCK_SOURCE_DPLL:
-                SYSCTRL->DPLLCTRLA.reg &= ~SYSCTRL_DPLLCTRLA_ENABLE;
-                break;
-#endif
-
-            case SYSTEM_CLOCK_SOURCE_ULP32K:
-            /* Not possible to disable */
-
-            default:
-                Assert(false);
-                return STATUS_ERR_INVALID_ARG;
-
-        }
-
-        return STATUS_OK;
-    }
-
-    /**
-     * \brief Checks if a clock source is ready.
-     *
-     * Checks if a given clock source is ready to be used.
-     *
-     * \param[in] clock_source  Clock source to check if ready
-     *
-     * \returns Ready state of the given clock source.
-     *
-     * \retval true   Clock source is enabled and ready
-     * \retval false  Clock source is disabled or not yet ready
-     */
-    bool system_clock_source_is_ready(
-        const enum system_clock_source clock_source)
-{
-    uint32_t mask = 0;
-
-    switch (clock_source) {
-        case SYSTEM_CLOCK_SOURCE_OSC8M:
-            mask = SYSCTRL_PCLKSR_OSC8MRDY;
-            break;
-
-        case SYSTEM_CLOCK_SOURCE_OSC32K:
-            mask = SYSCTRL_PCLKSR_OSC32KRDY;
-            break;
-
-        case SYSTEM_CLOCK_SOURCE_XOSC:
-            mask = SYSCTRL_PCLKSR_XOSCRDY;
-            break;
-
-        case SYSTEM_CLOCK_SOURCE_XOSC32K:
-            mask = SYSCTRL_PCLKSR_XOSC32KRDY;
-            break;
-
-        case SYSTEM_CLOCK_SOURCE_DFLL:
-            if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) {
-                mask = (SYSCTRL_PCLKSR_DFLLRDY |
-                        SYSCTRL_PCLKSR_DFLLLCKF | SYSCTRL_PCLKSR_DFLLLCKC);
-            } else {
-                mask = SYSCTRL_PCLKSR_DFLLRDY;
-            }
-            break;
-
-#ifdef FEATURE_SYSTEM_CLOCK_DPLL
-        case SYSTEM_CLOCK_SOURCE_DPLL:
-            return ((SYSCTRL->DPLLSTATUS.reg &
-                     (SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK)) ==
-                    (SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK));
-#endif
-
-        case SYSTEM_CLOCK_SOURCE_ULP32K:
-            /* Not possible to disable */
-            return true;
-
-        default:
-            return false;
-    }
-
-    return ((SYSCTRL->PCLKSR.reg & mask) == mask);
-}
-
-/* Include some checks for conf_clocks.h validation */
-#include "clock_config_check.h"
-
-#if !defined(__DOXYGEN__)
-/** \internal
- *
- * Configures a Generic Clock Generator with the configuration from \c conf_clocks.h.
- */
-#  define _CONF_CLOCK_GCLK_CONFIG(n, unused) \
-	if (CONF_CLOCK_GCLK_##n##_ENABLE == true) { \
-		struct system_gclk_gen_config gclk_conf;                          \
-		system_gclk_gen_get_config_defaults(&gclk_conf);                  \
-		gclk_conf.source_clock    = CONF_CLOCK_GCLK_##n##_CLOCK_SOURCE;   \
-		gclk_conf.division_factor = CONF_CLOCK_GCLK_##n##_PRESCALER;      \
-		gclk_conf.run_in_standby  = CONF_CLOCK_GCLK_##n##_RUN_IN_STANDBY; \
-		gclk_conf.output_enable   = CONF_CLOCK_GCLK_##n##_OUTPUT_ENABLE;  \
-		system_gclk_gen_set_config(GCLK_GENERATOR_##n, &gclk_conf);       \
-		system_gclk_gen_enable(GCLK_GENERATOR_##n);                       \
-	}
-
-/** \internal
- *
- * Configures a Generic Clock Generator with the configuration from \c conf_clocks.h,
- * provided that it is not the main Generic Clock Generator channel.
- */
-#  define _CONF_CLOCK_GCLK_CONFIG_NONMAIN(n, unused) \
-		if (n > 0) { _CONF_CLOCK_GCLK_CONFIG(n, unused); }
-#endif
-
-/** \internal
- *
- * Switch all peripheral clock to a not enabled general clock
- * to save power.
- */
-static void _switch_peripheral_gclk(void)
-{
-    uint32_t gclk_id;
-    struct system_gclk_chan_config gclk_conf;
-
-#if CONF_CLOCK_GCLK_1_ENABLE == false
-    gclk_conf.source_generator = GCLK_GENERATOR_1;
-#elif CONF_CLOCK_GCLK_2_ENABLE == false
-    gclk_conf.source_generator = GCLK_GENERATOR_2;
-#elif CONF_CLOCK_GCLK_3_ENABLE == false
-    gclk_conf.source_generator = GCLK_GENERATOR_3;
-#elif CONF_CLOCK_GCLK_4_ENABLE == false
-    gclk_conf.source_generator = GCLK_GENERATOR_4;
-#elif CONF_CLOCK_GCLK_5_ENABLE == false
-    gclk_conf.source_generator = GCLK_GENERATOR_5;
-#elif CONF_CLOCK_GCLK_6_ENABLE == false
-    gclk_conf.source_generator = GCLK_GENERATOR_6;
-#elif CONF_CLOCK_GCLK_7_ENABLE == false
-    gclk_conf.source_generator = GCLK_GENERATOR_7;
-#else
-    gclk_conf.source_generator = GCLK_GENERATOR_7;
-#endif
-
-    for (gclk_id = 0; gclk_id < GCLK_NUM; gclk_id++) {
-        system_gclk_chan_set_config(gclk_id, &gclk_conf);
-    }
-}
-
-/**
- * \brief Initialize clock system based on the configuration in conf_clocks.h.
- *
- * This function will apply the settings in conf_clocks.h when run from the user
- * application. All clock sources and GCLK generators are running when this function
- * returns.
- *
- * \note OSC8M is always enabled and if user selects other clocks for GCLK generators,
- * the OSC8M default enable can be disabled after system_clock_init. Make sure the
- * clock switch successfully before disabling OSC8M.
- */
-void system_clock_init(void)
-{
-    /* Various bits in the INTFLAG register can be set to one at startup.
-       This will ensure that these bits are cleared */
-    SYSCTRL->INTFLAG.reg = SYSCTRL_INTFLAG_BOD33RDY | SYSCTRL_INTFLAG_BOD33DET |
-                           SYSCTRL_INTFLAG_DFLLRDY;
-
-    system_flash_set_waitstates(CONF_CLOCK_FLASH_WAIT_STATES);
-
-    /* Switch all peripheral clock to a not enabled general clock to save power. */
-    _switch_peripheral_gclk();
-
-    /* XOSC */
-#if CONF_CLOCK_XOSC_ENABLE == true
-    struct system_clock_source_xosc_config xosc_conf;
-    system_clock_source_xosc_get_config_defaults(&xosc_conf);
-
-    xosc_conf.external_clock    = CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL;
-    xosc_conf.startup_time      = CONF_CLOCK_XOSC_STARTUP_TIME;
-    xosc_conf.auto_gain_control = CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL;
-    xosc_conf.frequency         = CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY;
-    xosc_conf.on_demand         = CONF_CLOCK_XOSC_ON_DEMAND;
-    xosc_conf.run_in_standby    = CONF_CLOCK_XOSC_RUN_IN_STANDBY;
-
-    system_clock_source_xosc_set_config(&xosc_conf);
-    system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC);
-#endif
-
-
-    /* XOSC32K */
-#if CONF_CLOCK_XOSC32K_ENABLE == true
-    struct system_clock_source_xosc32k_config xosc32k_conf;
-    system_clock_source_xosc32k_get_config_defaults(&xosc32k_conf);
-
-    xosc32k_conf.frequency           = 32768UL;
-    xosc32k_conf.external_clock      = CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL;
-    xosc32k_conf.startup_time        = CONF_CLOCK_XOSC32K_STARTUP_TIME;
-    xosc32k_conf.auto_gain_control   = CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL;
-    xosc32k_conf.enable_1khz_output  = CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT;
-    xosc32k_conf.enable_32khz_output = CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT;
-    xosc32k_conf.on_demand           = false;
-    xosc32k_conf.run_in_standby      = CONF_CLOCK_XOSC32K_RUN_IN_STANDBY;
-
-    system_clock_source_xosc32k_set_config(&xosc32k_conf);
-    system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC32K);
-    while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_XOSC32K));
-    if (CONF_CLOCK_XOSC32K_ON_DEMAND) {
-        SYSCTRL->XOSC32K.bit.ONDEMAND = 1;
-    }
-#endif
-
-
-    /* OSCK32K */
-#if CONF_CLOCK_OSC32K_ENABLE == true
-    SYSCTRL->OSC32K.bit.CALIB =
-        (*(uint32_t *)SYSCTRL_FUSES_OSC32K_ADDR >> SYSCTRL_FUSES_OSC32K_Pos);
-
-    struct system_clock_source_osc32k_config osc32k_conf;
-    system_clock_source_osc32k_get_config_defaults(&osc32k_conf);
-
-    osc32k_conf.startup_time        = CONF_CLOCK_OSC32K_STARTUP_TIME;
-    osc32k_conf.enable_1khz_output  = CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT;
-    osc32k_conf.enable_32khz_output = CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT;
-    osc32k_conf.on_demand           = CONF_CLOCK_OSC32K_ON_DEMAND;
-    osc32k_conf.run_in_standby      = CONF_CLOCK_OSC32K_RUN_IN_STANDBY;
-
-    system_clock_source_osc32k_set_config(&osc32k_conf);
-    system_clock_source_enable(SYSTEM_CLOCK_SOURCE_OSC32K);
-#endif
-
-
-    /* DFLL Config (Open and Closed Loop) */
-#if CONF_CLOCK_DFLL_ENABLE == true
-    struct system_clock_source_dfll_config dfll_conf;
-    system_clock_source_dfll_get_config_defaults(&dfll_conf);
-
-    dfll_conf.loop_mode      = CONF_CLOCK_DFLL_LOOP_MODE;
-    dfll_conf.on_demand      = false;
-
-    if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN) {
-        dfll_conf.coarse_value = CONF_CLOCK_DFLL_COARSE_VALUE;
-        dfll_conf.fine_value   = CONF_CLOCK_DFLL_FINE_VALUE;
-    }
-
-#  if CONF_CLOCK_DFLL_QUICK_LOCK == true
-    dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE;
-#  else
-    dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_DISABLE;
-#  endif
-
-#  if CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK == true
-    dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK;
-#  else
-    dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_FIX_AFTER_LOCK;
-#  endif
-
-#  if CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP == true
-    dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP;
-#  else
-    dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_LOSE;
-#  endif
-
-#  if CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE == true
-    dfll_conf.chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_ENABLE;
-#  else
-    dfll_conf.chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_DISABLE;
-#  endif
-
-    if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) {
-        dfll_conf.multiply_factor = CONF_CLOCK_DFLL_MULTIPLY_FACTOR;
-    }
-
-    dfll_conf.coarse_max_step = CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE;
-    dfll_conf.fine_max_step   = CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE;
-
-    if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY) {
-#define NVM_DFLL_COARSE_POS    58
-#define NVM_DFLL_COARSE_SIZE   6
-#define NVM_DFLL_FINE_POS      64
-#define NVM_DFLL_FINE_SIZE     10
-        uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP4)
-                             + (NVM_DFLL_COARSE_POS / 32))
-                           >> (NVM_DFLL_COARSE_POS % 32))
-                         & ((1 << NVM_DFLL_COARSE_SIZE) - 1);
-        if (coarse == 0x3f) {
-            coarse = 0x1f;
-        }
-        uint32_t fine =( *((uint32_t *)(NVMCTRL_OTP4)
-                           + (NVM_DFLL_FINE_POS / 32))
-                         >> (NVM_DFLL_FINE_POS % 32))
-                       & ((1 << NVM_DFLL_FINE_SIZE) - 1);
-        if (fine == 0x3ff) {
-            fine = 0x1ff;
-        }
-        dfll_conf.coarse_value = coarse;
-        dfll_conf.fine_value   = fine;
-
-        dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE;
-        dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_FIX_AFTER_LOCK;
-        dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP;
-        dfll_conf.chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_DISABLE;
-
-        dfll_conf.multiply_factor = 48000;
-    }
-
-    system_clock_source_dfll_set_config(&dfll_conf);
-#endif
-
-
-    /* OSC8M */
-    struct system_clock_source_osc8m_config osc8m_conf;
-    system_clock_source_osc8m_get_config_defaults(&osc8m_conf);
-
-    osc8m_conf.prescaler       = CONF_CLOCK_OSC8M_PRESCALER;
-    osc8m_conf.on_demand       = CONF_CLOCK_OSC8M_ON_DEMAND;
-    osc8m_conf.run_in_standby  = CONF_CLOCK_OSC8M_RUN_IN_STANDBY;
-
-    system_clock_source_osc8m_set_config(&osc8m_conf);
-    system_clock_source_enable(SYSTEM_CLOCK_SOURCE_OSC8M);
-
-
-    /* GCLK */
-#if CONF_CLOCK_CONFIGURE_GCLK == true
-    system_gclk_init();
-
-    /* Configure all GCLK generators except for the main generator, which
-     * is configured later after all other clock systems are set up */
-    MREPEAT(8, _CONF_CLOCK_GCLK_CONFIG_NONMAIN, ~);
-
-#  if CONF_CLOCK_DFLL_ENABLE == true
-    /* Enable DFLL reference clock if in closed loop mode */
-    if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) {
-        struct system_gclk_chan_config dfll_gclk_chan_conf;
-
-        system_gclk_chan_get_config_defaults(&dfll_gclk_chan_conf);
-        dfll_gclk_chan_conf.source_generator = CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR;
-        system_gclk_chan_set_config(SYSCTRL_GCLK_ID_DFLL48, &dfll_gclk_chan_conf);
-        system_gclk_chan_enable(SYSCTRL_GCLK_ID_DFLL48);
-    }
-#  endif
-#endif
-
-
-    /* DFLL Enable (Open and Closed Loop) */
-#if CONF_CLOCK_DFLL_ENABLE == true
-    system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DFLL);
-    while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DFLL));
-    if (CONF_CLOCK_DFLL_ON_DEMAND) {
-        SYSCTRL->DFLLCTRL.bit.ONDEMAND = 1;
-    }
-#endif
-
-    /* DPLL */
-#ifdef FEATURE_SYSTEM_CLOCK_DPLL
-#  if (CONF_CLOCK_DPLL_ENABLE == true)
-
-    /* Enable DPLL reference clock */
-    if (CONF_CLOCK_DPLL_REFERENCE_CLOCK == SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_REF0) {
-        /* XOSC32K should have been enabled for DPLL_REF0 */
-        Assert(CONF_CLOCK_XOSC32K_ENABLE);
-    }
-
-    struct system_clock_source_dpll_config dpll_config;
-    system_clock_source_dpll_get_config_defaults(&dpll_config);
-
-    dpll_config.on_demand        = false;
-    dpll_config.run_in_standby   = CONF_CLOCK_DPLL_RUN_IN_STANDBY;
-    dpll_config.lock_bypass      = CONF_CLOCK_DPLL_LOCK_BYPASS;
-    dpll_config.wake_up_fast     = CONF_CLOCK_DPLL_WAKE_UP_FAST;
-    dpll_config.low_power_enable = CONF_CLOCK_DPLL_LOW_POWER_ENABLE;
-
-    dpll_config.filter           = CONF_CLOCK_DPLL_FILTER;
-
-    dpll_config.reference_clock     = CONF_CLOCK_DPLL_REFERENCE_CLOCK;
-    dpll_config.reference_frequency = CONF_CLOCK_DPLL_REFERENCE_FREQUENCY;
-    dpll_config.reference_divider   = CONF_CLOCK_DPLL_REFEREMCE_DIVIDER;
-    dpll_config.output_frequency    = CONF_CLOCK_DPLL_OUTPUT_FREQUENCY;
-
-    system_clock_source_dpll_set_config(&dpll_config);
-    system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DPLL);
-    while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DPLL));
-    if (CONF_CLOCK_DPLL_ON_DEMAND) {
-        SYSCTRL->DPLLCTRLA.bit.ONDEMAND = 1;
-    }
-
-#  endif
-#endif
-
-    /* CPU and BUS clocks */
-    system_cpu_clock_set_divider(CONF_CLOCK_CPU_DIVIDER);
-
-    system_apb_clock_set_divider(SYSTEM_CLOCK_APB_APBA, CONF_CLOCK_APBA_DIVIDER);
-    system_apb_clock_set_divider(SYSTEM_CLOCK_APB_APBB, CONF_CLOCK_APBB_DIVIDER);
-
-    /* GCLK 0 */
-#if CONF_CLOCK_CONFIGURE_GCLK == true
-    /* Configure the main GCLK last as it might depend on other generators */
-    _CONF_CLOCK_GCLK_CONFIG(0, ~);
-#endif
-}