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
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

View file

@ -1,4 +1,5 @@
# Copyright (c) 2019 ML!PA Consulting GmbH
# Copyright (c) 2024-2025 Gerson Fernando Budke <nandojve@gmail.com>
# 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

View file

@ -1,6 +1,6 @@
/*
* 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
*/
@ -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 <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <soc.h>
/* 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 */

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2017 Google LLC.
* 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
*/
@ -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 <zephyr/device.h>
@ -29,6 +30,8 @@
#include <soc.h>
#include <cmsis_core.h>
/* 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 */

View file

@ -1,6 +1,6 @@
/*
* 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
*/
@ -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 <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <soc.h>
/* 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 */

View file

@ -1,6 +1,6 @@
/*
* 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
*/
@ -16,6 +16,8 @@
#include <soc.h>
#include <cmsis_core.h>
/* 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 */