From 544a78971434837ea2c9640df093a6f1b8dce5f0 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 21 May 2015 10:07:42 -0600 Subject: [PATCH] SAMD/L: Move GCLK configuration logic to its own C file --- arch/arm/src/samdl/Make.defs | 4 +- arch/arm/src/samdl/sam_gclk.c | 202 ++++++++++++++++++++++++++ arch/arm/src/samdl/sam_gclk.h | 31 ++++ arch/arm/src/samdl/samd_clockconfig.c | 161 +------------------- arch/arm/src/samdl/saml_clockconfig.c | 161 +------------------- 5 files changed, 237 insertions(+), 322 deletions(-) create mode 100644 arch/arm/src/samdl/sam_gclk.c diff --git a/arch/arm/src/samdl/Make.defs b/arch/arm/src/samdl/Make.defs index ed9169a3bd6..03457f76e08 100644 --- a/arch/arm/src/samdl/Make.defs +++ b/arch/arm/src/samdl/Make.defs @@ -68,8 +68,8 @@ CMN_CSRCS += up_dumpnvic.c endif CHIP_ASRCS = -CHIP_CSRCS = sam_idle.c sam_irq.c sam_lowputc.c sam_port.c sam_sercom.c -CHIP_CSRCS += sam_serial.c sam_start.c sam_usart.c +CHIP_CSRCS = sam_idle.c sam_irq.c sam_gclk.c sam_lowputc.c sam_port.c +CHIP_CSRCS += sam_sercom.c sam_serial.c sam_start.c sam_usart.c ifeq ($(CONFIG_ARCH_FAMILY_SAMD20),y) CHIP_CSRCS += samd_clockconfig.c diff --git a/arch/arm/src/samdl/sam_gclk.c b/arch/arm/src/samdl/sam_gclk.c new file mode 100644 index 00000000000..3ed25a72534 --- /dev/null +++ b/arch/arm/src/samdl/sam_gclk.c @@ -0,0 +1,202 @@ +/**************************************************************************** + * arch/arm/src/samdl/sam_glck.c + * + * Copyright (C) 2015 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 "up_arch.h" +#include "sam_gclk.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_gclck_waitsyncbusy + * + * Description: + * What until the SYNCBUSY bit is cleared. This bit is cleared when the + * synchronization of registers between the clock domains is complete. + * This bit is set when the synchronization of registers between clock + * domains is started. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void sam_gclck_waitsyncbusy(void) +{ + while ((getreg8(SAM_GCLK_STATUS) & GCLK_STATUS_SYNCBUSY) != 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_gclk_config + * + * Description: + * Configure a single GCLK(s) based on settings in the config structure. + * + * Input Parameters: + * config - An instance of struct sam_gclkconfig describing the GCLK + * configuration. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sam_gclk_config(FAR const struct sam_gclkconfig_s *config) +{ + uint32_t genctrl; + uint32_t gendiv; + + /* Select the requested source clock for the generator */ + + genctrl = ((uint32_t)config->gclk << GCLK_GENCTRL_ID_SHIFT) | + ((uint32_t)config->clksrc << GCLK_GENCTRL_SRC_SHIFT); + gendiv = ((uint32_t)config->gclk << GCLK_GENDIV_ID_SHIFT); + +#if 0 /* Not yet supported */ + /* Configure the clock to be either high or low when disabled */ + + if (config->level) + { + genctrl |= GCLK_GENCTRL_OOV; + } +#endif + + /* Configure if the clock output to I/O pin should be enabled */ + + if (config->output) + { + genctrl |= GCLK_GENCTRL_OE; + } + + /* Set the prescaler division factor */ + + if (config->prescaler > 1) + { + /* Check if division is a power of two */ + + if (((config->prescaler & (config->prescaler - 1)) == 0)) + { + /* Determine the index of the highest bit set to get the + * division factor that must be loaded into the division + * register. + */ + + uint32_t count = 0; + uint32_t mask; + + for (mask = 2; mask < (uint32_t)config->prescaler; mask <<= 1) + { + count++; + } + + /* Set binary divider power of 2 division factor */ + + gendiv |= count << GCLK_GENDIV_DIV_SHIFT; + genctrl |= GCLK_GENCTRL_DIVSEL; + } + else + { + /* Set integer division factor */ + + gendiv |= GCLK_GENDIV_DIV((uint32_t)config->prescaler); + + /* Enable non-binary division with increased duty cycle accuracy */ + + genctrl |= GCLK_GENCTRL_IDC; + } + } + + /* Enable or disable the clock in standby mode */ + + if (config->runstandby) + { + genctrl |= GCLK_GENCTRL_RUNSTDBY; + } + + /* Wait for synchronization */ + + sam_gclck_waitsyncbusy(); + + /* Select the generator */ + + putreg32(((uint32_t)config->gclk << GCLK_GENDIV_ID_SHIFT), + SAM_GCLK_GENDIV); + + /* Wait for synchronization */ + + sam_gclck_waitsyncbusy(); + + /* Write the new generator configuration */ + + putreg32(gendiv, SAM_GCLK_GENDIV); + + /* Wait for synchronization */ + + sam_gclck_waitsyncbusy(); + + /* Enable the clock generator */ + + genctrl |= GCLK_GENCTRL_GENEN; + putreg32(genctrl, SAM_GCLK_GENCTRL); + + /* Wait for synchronization */ + + sam_gclck_waitsyncbusy(); +} diff --git a/arch/arm/src/samdl/sam_gclk.h b/arch/arm/src/samdl/sam_gclk.h index 7c7d133d3e2..8292df0cbb5 100644 --- a/arch/arm/src/samdl/sam_gclk.h +++ b/arch/arm/src/samdl/sam_gclk.h @@ -42,6 +42,9 @@ #include +#include +#include + #include "sam_config.h" #if defined(CONFIG_ARCH_FAMILY_SAMD20) @@ -60,6 +63,17 @@ * Public Types ****************************************************************************/ +/* This structure describes the configuration of one GCLK */ + +struct sam_gclkconfig_s +{ + uint8_t gclk; /* Clock generator */ + bool runstandby; /* Run clock in standby */ + bool output; /* Output enable */ + uint8_t clksrc; /* Encoded clock source */ + uint16_t prescaler; /* Prescaler value */ +}; + /**************************************************************************** * Inline Functions ****************************************************************************/ @@ -83,6 +97,23 @@ extern "C" * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: sam_gclk_config + * + * Description: + * Configure a single GCLK(s) based on settings in the config structure. + * + * Input Parameters: + * config - An instance of struct sam_gclkconfig describing the GCLK + * configuration. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sam_gclk_config(FAR const struct sam_gclkconfig_s *config); + #undef EXTERN #if defined(__cplusplus) } diff --git a/arch/arm/src/samdl/samd_clockconfig.c b/arch/arm/src/samdl/samd_clockconfig.c index a19004e95e1..70b558b52cd 100644 --- a/arch/arm/src/samdl/samd_clockconfig.c +++ b/arch/arm/src/samdl/samd_clockconfig.c @@ -59,6 +59,7 @@ #include "chip/samd_gclk.h" #include "chip/samd_nvmctrl.h" #include "sam_fuses.h" +#include "sam_gclk.h" #include @@ -75,19 +76,6 @@ * Private Types ****************************************************************************/ -/* This structure describes the configuration of on GCLK */ - -#ifdef BOARD_GCLK_ENABLE -struct sam_gclkconfig_s -{ - uint8_t gclk; /* Clock generator */ - bool runstandby; /* Run clock in standby */ - bool output; /* Output enable */ - uint8_t clksrc; /* Encoded clock source */ - uint16_t prescaler; /* Prescaler value */ -}; -#endif - /**************************************************************************** * Private Data ****************************************************************************/ @@ -706,153 +694,6 @@ static inline void sam_dfll_reference(void) # define sam_dfll_reference() #endif -/**************************************************************************** - * Name: sam_gclck_waitsyncbusy - * - * Description: - * What until the SYNCBUSY bit is cleared. This bit is cleared when the - * synchronization of registers between the clock domains is complete. - * This bit is set when the synchronization of registers between clock - * domains is started. - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void sam_gclck_waitsyncbusy(void) -{ - while ((getreg8(SAM_GCLK_STATUS) & GCLK_STATUS_SYNCBUSY) != 0); -} - -/**************************************************************************** - * Name: sam_config_gclks - * - * Description: - * Configure a single GCLK(s) based on settings in the board.h header file. - * Depends on: - * - * BOARD_GCLKn_RUN_IN_STANDBY - Boolean (defined / not defined) - * BOARD_GCLKn_CLOCK_SOURCE - See GCLK_GENCTRL_SRC_* definitions - * BOARD_GCLKn_PRESCALER - Value - * BOARD_GCLKn_OUTPUT_ENABLE - Boolean (defined / not defined) - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef BOARD_GCLK_ENABLE -static inline void sam_gclk_config(FAR const struct sam_gclkconfig_s *config) -{ - uint32_t genctrl; - uint32_t gendiv; - - /* Select the requested source clock for the generator */ - - genctrl = ((uint32_t)config->gclk << GCLK_GENCTRL_ID_SHIFT) | - ((uint32_t)config->clksrc << GCLK_GENCTRL_SRC_SHIFT); - gendiv = ((uint32_t)config->gclk << GCLK_GENDIV_ID_SHIFT); - -#if 0 /* Not yet supported */ - /* Configure the clock to be either high or low when disabled */ - - if (config->level) - { - genctrl |= GCLK_GENCTRL_OOV; - } -#endif - - /* Configure if the clock output to I/O pin should be enabled */ - - if (config->output) - { - genctrl |= GCLK_GENCTRL_OE; - } - - /* Set the prescaler division factor */ - - if (config->prescaler > 1) - { - /* Check if division is a power of two */ - - if (((config->prescaler & (config->prescaler - 1)) == 0)) - { - /* Determine the index of the highest bit set to get the - * division factor that must be loaded into the division - * register. - */ - - uint32_t count = 0; - uint32_t mask; - - for (mask = 2; mask < (uint32_t)config->prescaler; mask <<= 1) - { - count++; - } - - /* Set binary divider power of 2 division factor */ - - gendiv |= count << GCLK_GENDIV_DIV_SHIFT; - genctrl |= GCLK_GENCTRL_DIVSEL; - } - else - { - /* Set integer division factor */ - - gendiv |= GCLK_GENDIV_DIV((uint32_t)config->prescaler); - - /* Enable non-binary division with increased duty cycle accuracy */ - - genctrl |= GCLK_GENCTRL_IDC; - } - } - - /* Enable or disable the clock in standby mode */ - - if (config->runstandby) - { - genctrl |= GCLK_GENCTRL_RUNSTDBY; - } - - /* Wait for synchronization */ - - sam_gclck_waitsyncbusy(); - - /* Select the generator */ - - putreg32(((uint32_t)config->gclk << GCLK_GENDIV_ID_SHIFT), - SAM_GCLK_GENDIV); - - /* Wait for synchronization */ - - sam_gclck_waitsyncbusy(); - - /* Write the new generator configuration */ - - putreg32(gendiv, SAM_GCLK_GENDIV); - - /* Wait for synchronization */ - - sam_gclck_waitsyncbusy(); - - /* Enable the clock generator */ - - genctrl |= GCLK_GENCTRL_GENEN; - putreg32(genctrl, SAM_GCLK_GENCTRL); - - /* Wait for synchronization */ - - sam_gclck_waitsyncbusy(); -} -#endif - /**************************************************************************** * Name: sam_config_gclks * diff --git a/arch/arm/src/samdl/saml_clockconfig.c b/arch/arm/src/samdl/saml_clockconfig.c index e2c77d6169d..6d5f53fc6c0 100644 --- a/arch/arm/src/samdl/saml_clockconfig.c +++ b/arch/arm/src/samdl/saml_clockconfig.c @@ -62,6 +62,7 @@ #include "chip/saml_osc32kctrl.h" #include "chip/saml_gclk.h" #include "chip/saml_nvmctrl.h" +#include "sam_gclk.h" #include @@ -95,19 +96,6 @@ * Private Types ****************************************************************************/ -/* This structure describes the configuration of on GCLK */ - -#ifdef BOARD_GCLK_ENABLE -struct sam_gclkconfig_s -{ - uint8_t gclk; /* Clock generator */ - bool runstandby; /* Run clock in standby */ - bool output; /* Output enable */ - uint8_t clksrc; /* Encoded clock source */ - uint16_t prescaler; /* Prescaler value */ -}; -#endif - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -136,8 +124,6 @@ static inline void sam_dfll48m_refclk(void); static inline void sam_fdpll96m_config(void); static inline void sam_fdpll96m_refclk(void); #endif -static void sam_gclck_waitsyncbusy(void); -static void sam_gclk_config(FAR const struct sam_gclkconfig_s *config); #ifdef BOARD_GCLK_ENABLE static inline void sam_config_gclks(void); #endif @@ -1061,151 +1047,6 @@ static inline void sam_fdpll96m_refclk(void) # define sam_fdpll96m_enable() #endif -/**************************************************************************** - * Name: sam_gclck_waitsyncbusy - * - * Description: - * What until the SYNCBUSY bit is cleared. This bit is cleared when the - * synchronization of registers between the clock domains is complete. - * This bit is set when the synchronization of registers between clock - * domains is started. - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void sam_gclck_waitsyncbusy(void) -{ - while ((getreg8(SAM_GCLK_SYNCHBUSY) & GCLK_SYNCHBUSY_SYNCBUSY) != 0); -} - -/**************************************************************************** - * Name: sam_config_gclks - * - * Description: - * Configure a single GCLK(s) based on settings in the board.h header file. - * Depends on: - * - * BOARD_GCLKn_RUN_IN_STANDBY - Boolean (defined / not defined) - * BOARD_GCLKn_CLOCK_SOURCE - See GCLK_GENCTRL_SRC_* definitions - * BOARD_GCLKn_PRESCALER - Value - * BOARD_GCLKn_OUTPUT_ENABLE - Boolean (defined / not defined) - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void sam_gclk_config(FAR const struct sam_gclkconfig_s *config) -{ - uint32_t genctrl; - uint32_t gendiv; - - /* Select the requested source clock for the generator */ - - genctrl = ((uint32_t)config->gclk << GCLK_GENCTRL_ID_SHIFT) | - ((uint32_t)config->clksrc << GCLK_GENCTRL_SRC_SHIFT); - gendiv = ((uint32_t)config->gclk << GCLK_GENDIV_ID_SHIFT); - -#if 0 /* Not yet supported */ - /* Configure the clock to be either high or low when disabled */ - - if (config->level) - { - genctrl |= GCLK_GENCTRL_OOV; - } -#endif - - /* Configure if the clock output to I/O pin should be enabled */ - - if (config->output) - { - genctrl |= GCLK_GENCTRL_OE; - } - - /* Set the prescaler division factor */ - - if (config->prescaler > 1) - { - /* Check if division is a power of two */ - - if (((config->prescaler & (config->prescaler - 1)) == 0)) - { - /* Determine the index of the highest bit set to get the - * division factor that must be loaded into the division - * register. - */ - - uint32_t count = 0; - uint32_t mask; - - for (mask = 2; mask < (uint32_t)config->prescaler; mask <<= 1) - { - count++; - } - - /* Set binary divider power of 2 division factor */ - - gendiv |= count << GCLK_GENDIV_DIV_SHIFT; - genctrl |= GCLK_GENCTRL_DIVSEL; - } - else - { - /* Set integer division factor */ - - gendiv |= GCLK_GENDIV_DIV((uint32_t)config->prescaler); - - /* Enable non-binary division with increased duty cycle accuracy */ - - genctrl |= GCLK_GENCTRL_IDC; - } - } - - /* Enable or disable the clock in standby mode */ - - if (config->runstandby) - { - genctrl |= GCLK_GENCTRL_RUNSTDBY; - } - - /* Wait for synchronization */ - - sam_gclck_waitsyncbusy(); - - /* Select the generator */ - - putreg32(((uint32_t)config->gclk << GCLK_GENDIV_ID_SHIFT), - SAM_GCLK_GENDIV); - - /* Wait for synchronization */ - - sam_gclck_waitsyncbusy(); - - /* Write the new generator configuration */ - - putreg32(gendiv, SAM_GCLK_GENDIV); - - /* Wait for synchronization */ - - sam_gclck_waitsyncbusy(); - - /* Enable the clock generator */ - - genctrl |= GCLK_GENCTRL_GENEN; - putreg32(genctrl, SAM_GCLK_GENCTRL); - - /* Wait for synchronization */ - - sam_gclck_waitsyncbusy(); -} - /**************************************************************************** * Name: sam_config_gclks *