From de6eb5c02bc12c6de378b0bc3515b548db72be15 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 22 May 2015 07:28:19 -0600 Subject: [PATCH] SAML21: Rename sam_gclk.c to samd_gclk.c. Create saml_gclk.c with corrected logic for the SAML21 --- arch/arm/src/samdl/Make.defs | 8 +- arch/arm/src/samdl/chip/saml_gclk.h | 1 - arch/arm/src/samdl/samd_gclk.c | 208 ++++++++++++++++++ .../arm/src/samdl/{sam_gclk.c => saml_gclk.c} | 56 +++-- 4 files changed, 238 insertions(+), 35 deletions(-) create mode 100644 arch/arm/src/samdl/samd_gclk.c rename arch/arm/src/samdl/{sam_gclk.c => saml_gclk.c} (89%) diff --git a/arch/arm/src/samdl/Make.defs b/arch/arm/src/samdl/Make.defs index 03457f76e0..e2db74e315 100644 --- a/arch/arm/src/samdl/Make.defs +++ b/arch/arm/src/samdl/Make.defs @@ -68,13 +68,13 @@ CMN_CSRCS += up_dumpnvic.c endif CHIP_ASRCS = -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 +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 ifeq ($(CONFIG_ARCH_FAMILY_SAMD20),y) -CHIP_CSRCS += samd_clockconfig.c +CHIP_CSRCS += samd_clockconfig.c samd_gclk.c else ifeq ($(CONFIG_ARCH_FAMILY_SAML21),y) -CHIP_CSRCS += saml_clockconfig.c +CHIP_CSRCS += saml_clockconfig.c saml_gclk.c endif ifneq ($(CONFIG_SCHED_TICKLESS),y) diff --git a/arch/arm/src/samdl/chip/saml_gclk.h b/arch/arm/src/samdl/chip/saml_gclk.h index 7c65d65acb..22d01ace76 100644 --- a/arch/arm/src/samdl/chip/saml_gclk.h +++ b/arch/arm/src/samdl/chip/saml_gclk.h @@ -69,7 +69,6 @@ #define SAM_GCLK_GENCTRL(n) (SAM_GCLK_BASE+SAM_GCLK_GENCTRL_OFFSET(n)) #define SAM_GCLK_PCHCTRL(m) (SAM_GCLK_BASE+SAM_GCLK_PCHCTRL_OFFSET(m)) - /* GCLK register bit definitions ************************************************************/ /* Control register */ diff --git a/arch/arm/src/samdl/samd_gclk.c b/arch/arm/src/samdl/samd_gclk.c new file mode 100644 index 0000000000..cc0cd94589 --- /dev/null +++ b/arch/arm/src/samdl/samd_gclk.c @@ -0,0 +1,208 @@ +/**************************************************************************** + * arch/arm/src/samdl/samd_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 + +#include "up_arch.h" +#include "sam_gclk.h" + +#ifdef CONFIG_ARCH_FAMILY_SAMD20 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_gclck_waitsyncbusy + * + * Description: + * What until the SYNCBUSY bit is cleared. The SYNCBUSY bit was set when + * the synchronization of registers between clock domains is started. The + * SYNCBUSY bit is cleared when the synchronization of registers between + * the clock domains is complete. + * + * 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(); +} + +#endif /* CONFIG_ARCH_FAMILY_SAMD20 */ diff --git a/arch/arm/src/samdl/sam_gclk.c b/arch/arm/src/samdl/saml_gclk.c similarity index 89% rename from arch/arm/src/samdl/sam_gclk.c rename to arch/arm/src/samdl/saml_gclk.c index 56d978a68c..e854bc4f5c 100644 --- a/arch/arm/src/samdl/sam_gclk.c +++ b/arch/arm/src/samdl/saml_gclk.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/samdl/sam_glck.c + * arch/arm/src/samdl/saml_glck.c * * Copyright (C) 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -47,6 +47,8 @@ #include "up_arch.h" #include "sam_gclk.h" +#ifdef CONFIG_ARCH_FAMILY_SAML21 + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -78,16 +80,8 @@ static void sam_gclck_waitsyncbusy(uint8_t gclk) { -#if defined(CONFIG_ARCH_FAMILY_SAMD20) - while ((getreg8(SAM_GCLK_STATUS) & GCLK_STATUS_SYNCBUSY) != 0); - -#elif defined(CONFIG_ARCH_FAMILY_SAML21) uintptr_t gclkbit = GCLK_SYNCHBUSY_GENCTRL(gclk); while ((getreg8(SAM_GCLK_SYNCHBUSY) & gclkbit) != 0); - -#else -# error Unrecognized SAMD/L architecture -#endif } /**************************************************************************** @@ -111,14 +105,14 @@ static void sam_gclck_waitsyncbusy(uint8_t gclk) void sam_gclk_config(FAR const struct sam_gclkconfig_s *config) { + irqstate_t flags; + uintptr_t regaddr; + uint32_t regval; 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); + genctrl = ((uint32_t)config->clksrc << GCLK_GENCTRL_SRC_SHIFT); #if 0 /* Not yet supported */ /* Configure the clock to be either high or low when disabled */ @@ -159,14 +153,14 @@ void sam_gclk_config(FAR const struct sam_gclkconfig_s *config) /* Set binary divider power of 2 division factor */ - gendiv |= count << GCLK_GENDIV_DIV_SHIFT; + genctrl |= count << GCLK_GENCTRL_DIV_SHIFT; genctrl |= GCLK_GENCTRL_DIVSEL; } else { /* Set integer division factor */ - gendiv |= GCLK_GENDIV_DIV((uint32_t)config->prescaler); + genctrl |= GCLK_GENCTRL_DIV((uint32_t)config->prescaler); /* Enable non-binary division with increased duty cycle accuracy */ @@ -185,31 +179,35 @@ void sam_gclk_config(FAR const struct sam_gclkconfig_s *config) sam_gclck_waitsyncbusy(config->gclk); - /* Select the generator */ + /* Preserve the GENEN bit */ - putreg32(((uint32_t)config->gclk << GCLK_GENDIV_ID_SHIFT), - SAM_GCLK_GENDIV); + regaddr = SAM_GCLK_GENCTRL(config->gclk); + + flags = irqsave(); + regval = getreg32(regaddr); + regval &= GCLK_GENCTRL_GENEN; + genctrl |= regval; + + /* Configure the generator */ + + putreg32(genctrl, regaddr); /* Wait for synchronization */ sam_gclck_waitsyncbusy(config->gclk); - - /* Write the new generator configuration */ - - putreg32(gendiv, SAM_GCLK_GENDIV); - - /* Wait for synchronization */ - + irqrestore(flags); sam_gclck_waitsyncbusy(config->gclk); /* Enable the clock generator */ + flags = irqsave(); genctrl |= GCLK_GENCTRL_GENEN; - putreg32(genctrl, SAM_GCLK_GENCTRL); + putreg32(genctrl, regaddr); /* Wait for synchronization */ sam_gclck_waitsyncbusy(config->gclk); + irqrestore(flags); } /**************************************************************************** @@ -227,7 +225,6 @@ void sam_gclk_config(FAR const struct sam_gclkconfig_s *config) * ****************************************************************************/ -#ifdef CONFIG_ARCH_FAMILY_SAML21 void sam_gclk_chan_enable(uint8_t channel, uint8_t srcgen) { irqstate_t flags; @@ -258,7 +255,6 @@ void sam_gclk_chan_enable(uint8_t channel, uint8_t srcgen) while ((getreg32(regaddr) &GCLK_PCHCTRL_CHEN) == 0); irqrestore(flags); } -#endif /**************************************************************************** * Name: sam_gclk_chan_disable @@ -274,7 +270,6 @@ void sam_gclk_chan_enable(uint8_t channel, uint8_t srcgen) * ****************************************************************************/ -#ifdef CONFIG_ARCH_FAMILY_SAML21 void sam_gclk_chan_disable(uint8_t channel) { irqstate_t flags; @@ -297,4 +292,5 @@ void sam_gclk_chan_disable(uint8_t channel) while ((getreg32(regaddr) &GCLK_PCHCTRL_CHEN) != 0); irqrestore(flags); } -#endif + +#endif /* CONFIG_ARCH_FAMILY_SAML21 */