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 <nandojve@gmail.com>
This commit is contained in:
Gerson Fernando Budke 2024-11-01 16:49:53 +01:00 committed by Benjamin Cabé
commit d4fe29c542
6 changed files with 150 additions and 73 deletions

View file

@ -1,3 +1,4 @@
# Copyright (c) 2024-2025 Gerson Fernando Budke <nandojve@gmail.com>
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
if SOC_SERIES_SAMD20 || SOC_SERIES_SAMD21 || SOC_SERIES_SAMR21 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 Enable the crystal oscillator (if disabled, expect a clock signal on
XIN32). 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 config SOC_ATMEL_SAMD_XOSC
bool "External 0.4..32 MHz clock source" bool "External 0.4..32 MHz clock source"
help help

View file

@ -1,4 +1,5 @@
# Copyright (c) 2019 ML!PA Consulting GmbH # Copyright (c) 2019 ML!PA Consulting GmbH
# Copyright (c) 2024-2025 Gerson Fernando Budke <nandojve@gmail.com>
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
if SOC_SERIES_SAMD51 || SOC_SERIES_SAME51 || SOC_SERIES_SAME53 || SOC_SERIES_SAME54 if SOC_SERIES_SAMD51 || SOC_SERIES_SAME51 || SOC_SERIES_SAME53 || SOC_SERIES_SAME54
@ -18,6 +19,34 @@ config SOC_ATMEL_SAMD5X_XOSC32K_STARTUP
help help
Selects the startup time for the external 32 kHz crystal oscillator. 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 choice
prompt "Main clock source" prompt "Main clock source"
default SOC_ATMEL_SAMD5X_DEFAULT_AS_MAIN default SOC_ATMEL_SAMD5X_DEFAULT_AS_MAIN

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2022 Kamil Serwus * Copyright (c) 2022 Kamil Serwus
* Copyright (c) 2023 Gerson Fernando Budke <nandojve@gmail.com> * Copyright (c) 2023-2025 Gerson Fernando Budke <nandojve@gmail.com>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -10,11 +10,19 @@
* @brief Atmel SAMC MCU series initialization code * @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 <zephyr/device.h> #include <zephyr/device.h>
#include <zephyr/init.h> #include <zephyr/init.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <soc.h> #include <soc.h>
/* clang-format off */
static void flash_waitstates_init(void) static void flash_waitstates_init(void)
{ {
/* Two wait state at 48 MHz. */ /* Two wait state at 48 MHz. */
@ -50,3 +58,5 @@ void soc_reset_hook(void)
mclk_init(); mclk_init();
gclks_init(); gclks_init();
} }
/* clang-format on */

View file

@ -1,7 +1,7 @@
/* /*
* Copyright (c) 2017 Google LLC. * Copyright (c) 2017 Google LLC.
* Copyright (c) 2023 Ionut Catalin Pavel <iocapa@iocapa.com> * Copyright (c) 2023 Ionut Catalin Pavel <iocapa@iocapa.com>
* Copyright (c) 2023 Gerson Fernando Budke <nandojve@gmail.com> * Copyright (c) 2023-2025 Gerson Fernando Budke <nandojve@gmail.com>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -20,6 +20,7 @@
* GCLK Gen 1 -> DFLL48M (variable) * GCLK Gen 1 -> DFLL48M (variable)
* GCLK Gen 2 -> WDT @ 32768 Hz * GCLK Gen 2 -> WDT @ 32768 Hz
* GCLK Gen 3 -> ADC @ 8 MHz * GCLK Gen 3 -> ADC @ 8 MHz
* GCLK Gen 4 -> RTC @ xtal 32768 Hz
*/ */
#include <zephyr/device.h> #include <zephyr/device.h>
@ -29,6 +30,8 @@
#include <soc.h> #include <soc.h>
#include <cmsis_core.h> #include <cmsis_core.h>
/* clang-format off */
/** /**
* Fix different naming conventions for SAMD20 * Fix different naming conventions for SAMD20
*/ */
@ -38,6 +41,23 @@
#define FUSES_OSC32K_CAL_Msk FUSES_OSC32KCAL_Msk #define FUSES_OSC32K_CAL_Msk FUSES_OSC32KCAL_Msk
#endif #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) static inline void osc8m_init(void)
{ {
uint32_t reg; uint32_t reg;
@ -57,19 +77,7 @@ static inline void osc8m_init(void)
/* Use 8Mhz clock as gclk_main to allow switching between clocks /* Use 8Mhz clock as gclk_main to allow switching between clocks
* when using bootloaders * when using bootloaders
*/ */
GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) gclk_connect(0, GCLK_GENCTRL_SRC_OSC8M, 0, 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) {
}
} }
#if !CONFIG_SOC_ATMEL_SAMD_OSC32K || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN #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; uint32_t fcal, ccal;
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(1) gclk_connect(1,
#if CONFIG_SOC_ATMEL_SAMD_OSC32K_AS_MAIN #if CONFIG_SOC_ATMEL_SAMD_OSC32K_AS_MAIN
| GCLK_GENCTRL_SRC_OSC32K GCLK_GENCTRL_SRC_OSC32K,
#elif CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN #elif CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN
| GCLK_GENCTRL_SRC_XOSC32K GCLK_GENCTRL_SRC_XOSC32K,
#elif CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN #elif CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN
| GCLK_GENCTRL_SRC_OSC8M GCLK_GENCTRL_SRC_OSC8M,
#elif CONFIG_SOC_ATMEL_SAMD_XOSC_AS_MAIN #elif CONFIG_SOC_ATMEL_SAMD_XOSC_AS_MAIN
| GCLK_GENCTRL_SRC_XOSC GCLK_GENCTRL_SRC_XOSC,
#endif #endif
| GCLK_GENCTRL_IDC SOC_ATMEL_SAM0_GCLK1_DIV, GCLK_GENCTRL_RUNSTDBY);
| 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) {
}
/* Route multiplexer 0 to DFLL48M */ /* Route multiplexer 0 to DFLL48M */
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(0) GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(0)
@ -222,19 +219,7 @@ static inline void flash_waitstates_init(void)
#else #else
static inline void gclk_main_configure(void) static inline void gclk_main_configure(void)
{ {
GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) gclk_connect(0, GCLK_GENCTRL_SRC_DFLL48M, SOC_ATMEL_SAM0_GCLK0_DIV, 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) {
}
} }
#endif #endif
@ -243,19 +228,16 @@ static inline void gclk_main_configure(void)
#else #else
static inline void gclk_adc_configure(void) static inline void gclk_adc_configure(void)
{ {
GCLK->GENDIV.reg = GCLK_GENDIV_ID(3) gclk_connect(3, GCLK_GENCTRL_SRC_DFLL48M, SOC_ATMEL_SAM0_GCLK3_DIV, 0);
| GCLK_GENDIV_DIV(SOC_ATMEL_SAM0_GCLK3_DIV);
while (GCLK->STATUS.bit.SYNCBUSY) {
} }
#endif
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(3) #if !CONFIG_RTC_ATMEL_SAM0 || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
| GCLK_GENCTRL_SRC_DFLL48M #define gclk_rtc_configure()
| GCLK_GENCTRL_IDC #else
| GCLK_GENCTRL_GENEN; static inline void gclk_rtc_configure(void)
{
while (GCLK->STATUS.bit.SYNCBUSY) { gclk_connect(4, GCLK_GENCTRL_SRC_XOSC32K, CONFIG_SOC_ATMEL_SAMD_XOSC32K_PRESCALER, 0);
}
} }
#endif #endif
@ -264,16 +246,7 @@ static inline void gclk_adc_configure(void)
#else #else
static inline void gclk_wdt_configure(void) static inline void gclk_wdt_configure(void)
{ {
GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) gclk_connect(2, GCLK_GENCTRL_SRC_OSCULP32K, 4, GCLK_GENCTRL_DIVSEL);
| 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) {
}
} }
#endif #endif
@ -296,6 +269,9 @@ void soc_reset_hook(void)
flash_waitstates_init(); flash_waitstates_init();
gclk_main_configure(); gclk_main_configure();
gclk_adc_configure(); gclk_adc_configure();
gclk_rtc_configure();
gclk_wdt_configure(); gclk_wdt_configure();
osc8m_disable(); osc8m_disable();
} }
/* clang-format on */

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2019 ML!PA Consulting GmbH * Copyright (c) 2019 ML!PA Consulting GmbH
* Copyright (c) 2023 Gerson Fernando Budke <nandojve@gmail.com> * Copyright (c) 2023-2025 Gerson Fernando Budke <nandojve@gmail.com>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -10,30 +10,57 @@
* @brief Atmel SAMD MCU series initialization code * @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 <zephyr/device.h> #include <zephyr/device.h>
#include <zephyr/init.h> #include <zephyr/init.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <soc.h> #include <soc.h>
/* clang-format off */
#define SAM0_DFLL_FREQ_HZ (48000000U) #define SAM0_DFLL_FREQ_HZ (48000000U)
#define SAM0_DPLL_FREQ_MIN_HZ (96000000U) #define SAM0_DPLL_FREQ_MIN_HZ (96000000U)
#define SAM0_DPLL_FREQ_MAX_HZ (200000000U) #define SAM0_DPLL_FREQ_MAX_HZ (200000000U)
#define SAM0_XOSC32K_STARTUP_TIME CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_STARTUP #define SAM0_XOSC32K_STARTUP_TIME CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_STARTUP
#if CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_AS_MAIN #if !CONFIG_SOC_ATMEL_SAMD5X_XOSC32K
static void osc32k_init(void) #define xosc32k_init()
#else
static inline void xosc32k_init(void)
{ {
OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_ENABLE OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_ENABLE
#if CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_CRYSTAL
| OSC32KCTRL_XOSC32K_XTALEN | OSC32KCTRL_XOSC32K_XTALEN
#endif
#if CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_GAIN_HS
| OSC32KCTRL_XOSC32K_CGM_HS
#else
| OSC32KCTRL_XOSC32K_CGM_XT | OSC32KCTRL_XOSC32K_CGM_XT
#endif
| OSC32KCTRL_XOSC32K_EN32K | OSC32KCTRL_XOSC32K_EN32K
| OSC32KCTRL_XOSC32K_EN1K
| OSC32KCTRL_XOSC32K_RUNSTDBY | OSC32KCTRL_XOSC32K_RUNSTDBY
| OSC32KCTRL_XOSC32K_STARTUP(SAM0_XOSC32K_STARTUP_TIME) | OSC32KCTRL_XOSC32K_STARTUP(SAM0_XOSC32K_STARTUP_TIME);
;
while (!OSC32KCTRL->STATUS.bit.XOSC32KRDY) { 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[1].reg = GCLK_GENCTRL_SRC(GCLK_SOURCE_XOSC32K)
| GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN; | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN;
@ -132,6 +159,7 @@ void soc_reset_hook(void)
CMCC->CTRL.bit.CEN = 0; CMCC->CTRL.bit.CEN = 0;
gclk_reset(); gclk_reset();
xosc32k_init();
osc32k_init(); osc32k_init();
dfll_init(); dfll_init();
dpll_init(0, dfll_div * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); 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 */ /* connect GCLK2 to 48 MHz DFLL for USB */
gclk_connect(2, GCLK_SOURCE_DFLL48M, 0); 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 */

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2021 Argentum Systems Ltd. * Copyright (c) 2021 Argentum Systems Ltd.
* Copyright (c) 2023 Gerson Fernando Budke <nandojve@gmail.com> * Copyright (c) 2023-2025 Gerson Fernando Budke <nandojve@gmail.com>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -16,6 +16,8 @@
#include <soc.h> #include <soc.h>
#include <cmsis_core.h> #include <cmsis_core.h>
/* clang-format off */
/* the SAML21 currently operates only in Performance Level 2... sleep /* the SAML21 currently operates only in Performance Level 2... sleep
* and low-power operation are not currently supported by the BSP * and low-power operation are not currently supported by the BSP
* *
@ -27,6 +29,7 @@
* GCLK Gen 1 -> DFLL48M (variable) * GCLK Gen 1 -> DFLL48M (variable)
* GCLK Gen 2 -> USB @ 48 MHz * GCLK Gen 2 -> USB @ 48 MHz
* GCLK Gen 3 -> ADC @ 24 MHz (further /2 in the ADC peripheral) * GCLK Gen 3 -> ADC @ 24 MHz (further /2 in the ADC peripheral)
* GCLK Gen 4 -> RTC @ reserved
*/ */
static inline void gclk_reset(void) static inline void gclk_reset(void)
@ -57,6 +60,7 @@ static inline void osc32k_init(void)
| !OSC32KCTRL_OSC32K_ONDEMAND | !OSC32KCTRL_OSC32K_ONDEMAND
| OSC32KCTRL_OSC32K_RUNSTDBY | OSC32KCTRL_OSC32K_RUNSTDBY
| OSC32KCTRL_OSC32K_EN32K | OSC32KCTRL_OSC32K_EN32K
| OSC32KCTRL_OSC32K_EN1K
| OSC32KCTRL_OSC32K_ENABLE; | OSC32KCTRL_OSC32K_ENABLE;
/* wait for ready */ /* wait for ready */
@ -75,6 +79,7 @@ static inline void xosc32k_init(void)
| !OSC32KCTRL_XOSC32K_ONDEMAND | !OSC32KCTRL_XOSC32K_ONDEMAND
| OSC32KCTRL_XOSC32K_RUNSTDBY | OSC32KCTRL_XOSC32K_RUNSTDBY
| OSC32KCTRL_XOSC32K_EN32K | OSC32KCTRL_XOSC32K_EN32K
| OSC32KCTRL_XOSC32K_EN1K
#if CONFIG_SOC_ATMEL_SAML_XOSC32K_CRYSTAL #if CONFIG_SOC_ATMEL_SAML_XOSC32K_CRYSTAL
| OSC32KCTRL_XOSC32K_XTALEN | OSC32KCTRL_XOSC32K_XTALEN
#endif #endif
@ -266,3 +271,5 @@ void soc_reset_hook(void)
gclk_usb_configure(); gclk_usb_configure();
gclk_adc_configure(); gclk_adc_configure();
} }
/* clang-format on */