From d4fe29c5421359c7d4c7a65cc5a39708e3760a24 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Fri, 1 Nov 2024 16:49:53 +0100 Subject: [PATCH] soc: atmel: sam0: Configure GCLK[4] to RTC Configure the Generic Clock Generator to be used as source to RTC. The index 4 is now reserved to RTC. Signed-off-by: Gerson Fernando Budke --- soc/atmel/sam0/common/Kconfig.samd2x | 16 ++++ soc/atmel/sam0/common/Kconfig.samd5x | 29 +++++++ soc/atmel/sam0/common/soc_samc2x.c | 12 ++- soc/atmel/sam0/common/soc_samd2x.c | 108 +++++++++++---------------- soc/atmel/sam0/common/soc_samd5x.c | 49 ++++++++++-- soc/atmel/sam0/common/soc_saml2x.c | 9 ++- 6 files changed, 150 insertions(+), 73 deletions(-) diff --git a/soc/atmel/sam0/common/Kconfig.samd2x b/soc/atmel/sam0/common/Kconfig.samd2x index f23b6557963..11f76f608a1 100644 --- a/soc/atmel/sam0/common/Kconfig.samd2x +++ b/soc/atmel/sam0/common/Kconfig.samd2x @@ -1,3 +1,4 @@ +# Copyright (c) 2024-2025 Gerson Fernando Budke # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_SAMD20 || SOC_SERIES_SAMD21 || SOC_SERIES_SAMR21 @@ -35,6 +36,21 @@ config SOC_ATMEL_SAMD_XOSC32K_CRYSTAL Enable the crystal oscillator (if disabled, expect a clock signal on XIN32). +DT_ATMEL_RTC := $(dt_nodelabel_path,rtc) +DT_ATMEL_RTC_COUNTER_CLOCK_MODE := $(dt_node_str_prop_equals,$(DT_ATMEL_RTC),counter-mode,clock) + +config SOC_ATMEL_SAMD_XOSC32K_PRESCALER + int "XOSC32 Generic Clock Prescaler" + range 1 512 + default 32 if "$(DT_ATMEL_RTC_COUNTER_CLOCK_MODE)" + default 1 + depends on SOC_ATMEL_SAMD_XOSC32K + help + Configure the prescaler for the generic clock output + connected on the xosc32. When using RTC in calendar mode + the GCLK should be divided by 32 to RTC receive the + 1024 Hz reference clock. + config SOC_ATMEL_SAMD_XOSC bool "External 0.4..32 MHz clock source" help diff --git a/soc/atmel/sam0/common/Kconfig.samd5x b/soc/atmel/sam0/common/Kconfig.samd5x index 969887e99da..e18616862e1 100644 --- a/soc/atmel/sam0/common/Kconfig.samd5x +++ b/soc/atmel/sam0/common/Kconfig.samd5x @@ -1,4 +1,5 @@ # Copyright (c) 2019 ML!PA Consulting GmbH +# Copyright (c) 2024-2025 Gerson Fernando Budke # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_SAMD51 || SOC_SERIES_SAME51 || SOC_SERIES_SAME53 || SOC_SERIES_SAME54 @@ -18,6 +19,34 @@ config SOC_ATMEL_SAMD5X_XOSC32K_STARTUP help Selects the startup time for the external 32 kHz crystal oscillator. +config SOC_ATMEL_SAMD5X_XOSC32K_CRYSTAL + bool "External 32.768 kHz clock is a crystal oscillator" + depends on SOC_ATMEL_SAMD5X_XOSC32K + default y + help + Enable the crystal oscillator (if disabled, expect a clock + signal on XIN32). + +config SOC_ATMEL_SAMD5X_XOSC32K_GAIN_HS + bool "XOSC32 High Speed gain" + depends on SOC_ATMEL_SAMD5X_XOSC32K + help + When this option is selected the gain is set High Speed + instead standard. + +DT_ATMEL_RTC := $(dt_nodelabel_path,rtc) +DT_ATMEL_RTC_COUNTER_CLOCK_MODE := $(dt_node_str_prop_equals,$(DT_ATMEL_RTC),counter-mode,clock) + +config SOC_ATMEL_SAMD5X_OSC32K_PRESCALER + int "XOSC32 Generic Clock Prescaler" + range 1 512 + default 32 if "$(DT_ATMEL_RTC_COUNTER_CLOCK_MODE)" + default 1 + help + Configure the prescaler for the generic clock output connected on the + xosc32 or osculp32k. When using RTC in calendar mode the GCLK should + be divided by 32 to RTC receive the 1024 Hz reference clock. + choice prompt "Main clock source" default SOC_ATMEL_SAMD5X_DEFAULT_AS_MAIN diff --git a/soc/atmel/sam0/common/soc_samc2x.c b/soc/atmel/sam0/common/soc_samc2x.c index 1581b62eef2..bfcb111b0c2 100644 --- a/soc/atmel/sam0/common/soc_samc2x.c +++ b/soc/atmel/sam0/common/soc_samc2x.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2022 Kamil Serwus - * Copyright (c) 2023 Gerson Fernando Budke + * Copyright (c) 2023-2025 Gerson Fernando Budke * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,11 +10,19 @@ * @brief Atmel SAMC MCU series initialization code */ +/* GCLK Gen 0 -> GCLK_MAIN @ OSC48M + * GCLK Gen 2 -> WDT @ reserved + * GCLK Gen 0 -> ADC @ OSC48M + * GCLK Gen 4 -> RTC @ reserved + */ + #include #include #include #include +/* clang-format off */ + static void flash_waitstates_init(void) { /* Two wait state at 48 MHz. */ @@ -50,3 +58,5 @@ void soc_reset_hook(void) mclk_init(); gclks_init(); } + +/* clang-format on */ diff --git a/soc/atmel/sam0/common/soc_samd2x.c b/soc/atmel/sam0/common/soc_samd2x.c index f915459a576..f332100bf64 100644 --- a/soc/atmel/sam0/common/soc_samd2x.c +++ b/soc/atmel/sam0/common/soc_samd2x.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2017 Google LLC. * Copyright (c) 2023 Ionut Catalin Pavel - * Copyright (c) 2023 Gerson Fernando Budke + * Copyright (c) 2023-2025 Gerson Fernando Budke * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,7 @@ * GCLK Gen 1 -> DFLL48M (variable) * GCLK Gen 2 -> WDT @ 32768 Hz * GCLK Gen 3 -> ADC @ 8 MHz + * GCLK Gen 4 -> RTC @ xtal 32768 Hz */ #include @@ -29,6 +30,8 @@ #include #include +/* clang-format off */ + /** * Fix different naming conventions for SAMD20 */ @@ -38,6 +41,23 @@ #define FUSES_OSC32K_CAL_Msk FUSES_OSC32KCAL_Msk #endif +static void gclk_connect(uint8_t gclk, uint32_t src, uint32_t div, uint32_t flags) +{ + GCLK->GENDIV.reg = GCLK_GENDIV_ID(gclk) + | GCLK_GENDIV_DIV(div); + + while (GCLK->STATUS.bit.SYNCBUSY) { + } + + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(gclk) + | GCLK_GENCTRL_GENEN + | src + | flags; + + while (GCLK->STATUS.bit.SYNCBUSY) { + } +} + static inline void osc8m_init(void) { uint32_t reg; @@ -57,19 +77,7 @@ static inline void osc8m_init(void) /* Use 8Mhz clock as gclk_main to allow switching between clocks * when using bootloaders */ - GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) - | GCLK_GENDIV_DIV(0); - - while (GCLK->STATUS.bit.SYNCBUSY) { - } - - GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(0) - | GCLK_GENCTRL_SRC_OSC8M - | GCLK_GENCTRL_IDC - | GCLK_GENCTRL_GENEN; - - while (GCLK->STATUS.bit.SYNCBUSY) { - } + gclk_connect(0, GCLK_GENCTRL_SRC_OSC8M, 0, 0); } #if !CONFIG_SOC_ATMEL_SAMD_OSC32K || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN @@ -149,28 +157,17 @@ static inline void dfll48m_init(void) { uint32_t fcal, ccal; - GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(1) + gclk_connect(1, #if CONFIG_SOC_ATMEL_SAMD_OSC32K_AS_MAIN - | GCLK_GENCTRL_SRC_OSC32K + GCLK_GENCTRL_SRC_OSC32K, #elif CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN - | GCLK_GENCTRL_SRC_XOSC32K + GCLK_GENCTRL_SRC_XOSC32K, #elif CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN - | GCLK_GENCTRL_SRC_OSC8M + GCLK_GENCTRL_SRC_OSC8M, #elif CONFIG_SOC_ATMEL_SAMD_XOSC_AS_MAIN - | GCLK_GENCTRL_SRC_XOSC + GCLK_GENCTRL_SRC_XOSC, #endif - | GCLK_GENCTRL_IDC - | GCLK_GENCTRL_RUNSTDBY - | GCLK_GENCTRL_GENEN; - - while (GCLK->STATUS.bit.SYNCBUSY) { - } - - GCLK->GENDIV.reg = GCLK_GENDIV_ID(1) - | GCLK_GENDIV_DIV(SOC_ATMEL_SAM0_GCLK1_DIV); - - while (GCLK->STATUS.bit.SYNCBUSY) { - } + SOC_ATMEL_SAM0_GCLK1_DIV, GCLK_GENCTRL_RUNSTDBY); /* Route multiplexer 0 to DFLL48M */ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(0) @@ -222,19 +219,7 @@ static inline void flash_waitstates_init(void) #else static inline void gclk_main_configure(void) { - GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) - | GCLK_GENDIV_DIV(SOC_ATMEL_SAM0_GCLK0_DIV); - - while (GCLK->STATUS.bit.SYNCBUSY) { - } - - GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(0) - | GCLK_GENCTRL_SRC_DFLL48M - | GCLK_GENCTRL_IDC - | GCLK_GENCTRL_GENEN; - - while (GCLK->STATUS.bit.SYNCBUSY) { - } + gclk_connect(0, GCLK_GENCTRL_SRC_DFLL48M, SOC_ATMEL_SAM0_GCLK0_DIV, 0); } #endif @@ -243,19 +228,16 @@ static inline void gclk_main_configure(void) #else static inline void gclk_adc_configure(void) { - GCLK->GENDIV.reg = GCLK_GENDIV_ID(3) - | GCLK_GENDIV_DIV(SOC_ATMEL_SAM0_GCLK3_DIV); + gclk_connect(3, GCLK_GENCTRL_SRC_DFLL48M, SOC_ATMEL_SAM0_GCLK3_DIV, 0); +} +#endif - while (GCLK->STATUS.bit.SYNCBUSY) { - } - - GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(3) - | GCLK_GENCTRL_SRC_DFLL48M - | GCLK_GENCTRL_IDC - | GCLK_GENCTRL_GENEN; - - while (GCLK->STATUS.bit.SYNCBUSY) { - } +#if !CONFIG_RTC_ATMEL_SAM0 || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN +#define gclk_rtc_configure() +#else +static inline void gclk_rtc_configure(void) +{ + gclk_connect(4, GCLK_GENCTRL_SRC_XOSC32K, CONFIG_SOC_ATMEL_SAMD_XOSC32K_PRESCALER, 0); } #endif @@ -264,16 +246,7 @@ static inline void gclk_adc_configure(void) #else static inline void gclk_wdt_configure(void) { - GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) - | GCLK_GENDIV_DIV(4); - - GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) - | GCLK_GENCTRL_GENEN - | GCLK_GENCTRL_SRC_OSCULP32K - | GCLK_GENCTRL_DIVSEL; - - while (GCLK->STATUS.bit.SYNCBUSY) { - } + gclk_connect(2, GCLK_GENCTRL_SRC_OSCULP32K, 4, GCLK_GENCTRL_DIVSEL); } #endif @@ -296,6 +269,9 @@ void soc_reset_hook(void) flash_waitstates_init(); gclk_main_configure(); gclk_adc_configure(); + gclk_rtc_configure(); gclk_wdt_configure(); osc8m_disable(); } + +/* clang-format on */ diff --git a/soc/atmel/sam0/common/soc_samd5x.c b/soc/atmel/sam0/common/soc_samd5x.c index a12d3891ea8..77ac12e1d13 100644 --- a/soc/atmel/sam0/common/soc_samd5x.c +++ b/soc/atmel/sam0/common/soc_samd5x.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2019 ML!PA Consulting GmbH - * Copyright (c) 2023 Gerson Fernando Budke + * Copyright (c) 2023-2025 Gerson Fernando Budke * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,30 +10,57 @@ * @brief Atmel SAMD MCU series initialization code */ +/* The CPU clock will be configured to the DT requested value, + * and run via DFLL48M. + * + * Reference -> GCLK Gen 1 -> DFLL48M -> GCLK Gen 0 -> GCLK_MAIN + * + * GCLK Gen 0 -> GCLK_MAIN @ DPLL0 + * GCLK Gen 1 -> DFLL48M @ 32768 Hz + * GCLK Gen 2 -> USB @ DFLL48M + * GCLK Gen 3 -> ADC @ reserved + * GCLK Gen 4 -> RTC @ xtal 32768 Hz + */ + #include #include #include #include +/* clang-format off */ + #define SAM0_DFLL_FREQ_HZ (48000000U) #define SAM0_DPLL_FREQ_MIN_HZ (96000000U) #define SAM0_DPLL_FREQ_MAX_HZ (200000000U) #define SAM0_XOSC32K_STARTUP_TIME CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_STARTUP -#if CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_AS_MAIN -static void osc32k_init(void) +#if !CONFIG_SOC_ATMEL_SAMD5X_XOSC32K +#define xosc32k_init() +#else +static inline void xosc32k_init(void) { OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_ENABLE +#if CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_CRYSTAL | OSC32KCTRL_XOSC32K_XTALEN +#endif +#if CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_GAIN_HS + | OSC32KCTRL_XOSC32K_CGM_HS +#else | OSC32KCTRL_XOSC32K_CGM_XT +#endif | OSC32KCTRL_XOSC32K_EN32K + | OSC32KCTRL_XOSC32K_EN1K | OSC32KCTRL_XOSC32K_RUNSTDBY - | OSC32KCTRL_XOSC32K_STARTUP(SAM0_XOSC32K_STARTUP_TIME) - ; + | OSC32KCTRL_XOSC32K_STARTUP(SAM0_XOSC32K_STARTUP_TIME); while (!OSC32KCTRL->STATUS.bit.XOSC32KRDY) { } +} +#endif +#if CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_AS_MAIN +static void osc32k_init(void) +{ GCLK->GENCTRL[1].reg = GCLK_GENCTRL_SRC(GCLK_SOURCE_XOSC32K) | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN; @@ -132,6 +159,7 @@ void soc_reset_hook(void) CMCC->CTRL.bit.CEN = 0; gclk_reset(); + xosc32k_init(); osc32k_init(); dfll_init(); dpll_init(0, dfll_div * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); @@ -141,4 +169,15 @@ void soc_reset_hook(void) /* connect GCLK2 to 48 MHz DFLL for USB */ gclk_connect(2, GCLK_SOURCE_DFLL48M, 0); + + /* connect GCLK4 to xosc32k for RTC. The output is 1024 Hz*/ + gclk_connect(4, +#if CONFIG_SOC_ATMEL_SAMD5X_XOSC32K + GCLK_SOURCE_XOSC32K, +#else + GCLK_SOURCE_OSCULP32K, +#endif + CONFIG_SOC_ATMEL_SAMD5X_OSC32K_PRESCALER); } + +/* clang-format on */ diff --git a/soc/atmel/sam0/common/soc_saml2x.c b/soc/atmel/sam0/common/soc_saml2x.c index 3dd657a52f2..d65831f785a 100644 --- a/soc/atmel/sam0/common/soc_saml2x.c +++ b/soc/atmel/sam0/common/soc_saml2x.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2021 Argentum Systems Ltd. - * Copyright (c) 2023 Gerson Fernando Budke + * Copyright (c) 2023-2025 Gerson Fernando Budke * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,8 @@ #include #include +/* clang-format off */ + /* the SAML21 currently operates only in Performance Level 2... sleep * and low-power operation are not currently supported by the BSP * @@ -27,6 +29,7 @@ * GCLK Gen 1 -> DFLL48M (variable) * GCLK Gen 2 -> USB @ 48 MHz * GCLK Gen 3 -> ADC @ 24 MHz (further /2 in the ADC peripheral) + * GCLK Gen 4 -> RTC @ reserved */ static inline void gclk_reset(void) @@ -57,6 +60,7 @@ static inline void osc32k_init(void) | !OSC32KCTRL_OSC32K_ONDEMAND | OSC32KCTRL_OSC32K_RUNSTDBY | OSC32KCTRL_OSC32K_EN32K + | OSC32KCTRL_OSC32K_EN1K | OSC32KCTRL_OSC32K_ENABLE; /* wait for ready */ @@ -75,6 +79,7 @@ static inline void xosc32k_init(void) | !OSC32KCTRL_XOSC32K_ONDEMAND | OSC32KCTRL_XOSC32K_RUNSTDBY | OSC32KCTRL_XOSC32K_EN32K + | OSC32KCTRL_XOSC32K_EN1K #if CONFIG_SOC_ATMEL_SAML_XOSC32K_CRYSTAL | OSC32KCTRL_XOSC32K_XTALEN #endif @@ -266,3 +271,5 @@ void soc_reset_hook(void) gclk_usb_configure(); gclk_adc_configure(); } + +/* clang-format on */