soc: arm: atmel_sam0: improved samd20/samd21/samr21 clocking mechanism

There are some issues with the current version of the code, mainly the
improper use of the internal OSC8M as a source for the DFLL48m without
division. The DFLL48M is designed to accept a maximum of ~33KHz
at it's input, as higher values will bring the multiplier down,
leading to instability.

Also added the following features:
* Support for external HF oscillator (XOSC)
* Support for crystal/external oscillators on XOSC32K/XOSC
* Automatic dividers/multiplier computation based on DT cpu frequency
* Support for user configurable NVM wait states
* Added option to skip clock (re)initialization (bootloader usecase).

Tests were performed on a custom SAMD20G18 board using different clock
sources and cpu frequencies.
Clocks were routed to GPIO pins and observed on a scope.
According to the datasheet, architecture is identical on D21/R21.

Due to the nature of the internal architecture and the fact that
DFLL48M is not really meant to output anything other than 48MHZ
some combinations of requested DT cpu frequency and source
frequency will not result in a perfect match.

Mostly insipred by the SAML21 implementation.

Signed-off-by: Ionut Catalin Pavel <iocapa@iocapa.com>
This commit is contained in:
Ionut Catalin Pavel 2023-02-05 16:46:40 +02:00 committed by Carles Cufí
commit f450153c64
7 changed files with 423 additions and 167 deletions

View file

@ -3,6 +3,7 @@
CONFIG_SOC_SERIES_SAMD21=y
CONFIG_SOC_PART_NUMBER_SAMD21E18A=y
CONFIG_BOARD_ADAFRUIT_TRINKET_M0=y
CONFIG_SOC_ATMEL_SAMD_OSC8M=y
CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y

View file

@ -3,6 +3,7 @@
CONFIG_SOC_SERIES_SAMD21=y
CONFIG_SOC_PART_NUMBER_SAMD21G18A=y
CONFIG_BOARD_ARDUINO_NANO_33_IOT=y
CONFIG_SOC_ATMEL_SAMD_OSC8M=y
CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y

View file

@ -2,35 +2,91 @@
if SOC_SERIES_SAMD20 || SOC_SERIES_SAMD21 || SOC_SERIES_SAMR21
config SOC_ATMEL_SAMD_XOSC32K
bool "External 32 kHz crystal oscillator"
config SOC_ATMEL_SAMD_NVM_WAIT_STATES
int "NVM wait states"
default 1
help
Say y to enable the external 32 kHZ crystal oscillator at
startup. This can then be selected as the main clock source
for the SOC.
Wait states to set for NVM. Consult the datasheet as these are highly
dependent on the device operationg conditions.
config SOC_ATMEL_SAMD_OSC32K
bool "Internal 32.768 kHz RC oscillator"
help
Enable the internal 32.768 kHz RC oscillator at startup.
This can then be selected as the main clock reference for the SOC.
config SOC_ATMEL_SAMD_OSC8M
bool "Internal 8 MHz RC oscillator"
help
Enable the internal 8 MHz RC oscillator at startup.
This can then be selected as the main clock reference for the SOC.
config SOC_ATMEL_SAMD_XOSC32K
bool "External 32.768 kHz clock source"
help
Enable the external 32.768 kHz clock source at startup.
This can then be selected as the main clock reference for the SOC.
config SOC_ATMEL_SAMD_XOSC32K_CRYSTAL
bool "External 32.768 kHz clock is a crystal oscillator"
depends on SOC_ATMEL_SAMD_XOSC32K
default y
help
Enable the crystal oscillator (if disabled, expect a clock signal on
XIN32).
config SOC_ATMEL_SAMD_XOSC
bool "External crystal oscillator"
bool "External 0.4..32 MHz clock source"
help
Say y to enable the external crystal oscillator at startup.
Enable the external 0.4..32 MHz clock source at startup.
This can then be selected as the main clock reference for the SOC.
config SOC_ATMEL_SAMD_XOSC_CRYSTAL
bool "External 0.4..32 MHz clock is a crystal oscillator"
depends on SOC_ATMEL_SAMD_XOSC
default y
help
Enable the crystal oscillator (if disabled, expect a clock signal on
XIN).
config SOC_ATMEL_SAMD_XOSC_FREQ_HZ
int "External 0.4..32 MHz clock oscillator frequency"
range 400000 32000000
default 8000000
depends on SOC_ATMEL_SAMD_XOSC
help
External 0.4..32 MHz clock oscillator reference frequency.
choice
prompt "Main clock source"
prompt "Main clock reference"
default SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
help
Selects the clock that the main clocks, such as the CPU
clock and AHB clock, will be derived from.
Selects the clock that will be used for the DFLL48M's reference.
Main clocks, such as the CPU and AHB clocks will be derived from
DFLL48M.
config SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
bool "DEFAULT"
help
This choice will leave all clocks to their current state.
This can be the default reset state or a state set by a bootloader.
config SOC_ATMEL_SAMD_OSC32K_AS_MAIN
bool "OSC32K"
depends on SOC_ATMEL_SAMD_OSC32K
config SOC_ATMEL_SAMD_XOSC32K_AS_MAIN
depends on SOC_ATMEL_SAMD_XOSC32K
bool "XOSC32K"
config SOC_ATMEL_SAMD_XOSC_AS_MAIN
depends on SOC_ATMEL_SAMD_XOSC
bool "XOSC"
depends on SOC_ATMEL_SAMD_XOSC32K
config SOC_ATMEL_SAMD_OSC8M_AS_MAIN
bool "OSC8M"
depends on SOC_ATMEL_SAMD_OSC8M
config SOC_ATMEL_SAMD_XOSC_AS_MAIN
bool "XOSC"
depends on SOC_ATMEL_SAMD_XOSC
endchoice
endif # SOC_SERIES_SAMD20 || SOC_SERIES_SAMD21
endif # SOC_SERIES_SAMD20 || SOC_SERIES_SAMD21 || SOC_SERIES_SAMR21

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2017 Google LLC.
* Copyright (c) 2023 Ionut Catalin Pavel <iocapa@iocapa.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -9,168 +10,250 @@
* @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
* GCLK Gen 1 -> DFLL48M (variable)
* GCLK Gen 2 -> WDT @ 32768 Hz
* GCLK Gen 3 -> ADC @ 8 MHz
*/
#include <zephyr/arch/cpu.h>
#include <zephyr/arch/arm/aarch32/cortex_m/cmsis.h>
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <soc.h>
static void flash_waitstates_init(void)
{
/* One wait state at 48 MHz. */
NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val;
}
/* Follows the same structure as the Arduino Zero, namely:
* XOSC32K -> GCLK1 -> DFLL48M -> GCLK0
* OSC8M -> 8 MHz -> GCLK3
/**
* Fix different naming conventions for SAMD20
*/
static void xosc_init(void)
{
#ifdef CONFIG_SOC_ATMEL_SAMD_XOSC
#error External oscillator support is not implemented.
#ifdef FUSES_OSC32KCAL_ADDR
#define FUSES_OSC32K_CAL_ADDR FUSES_OSC32KCAL_ADDR
#define FUSES_OSC32K_CAL_Pos FUSES_OSC32KCAL_Pos
#define FUSES_OSC32K_CAL_Msk FUSES_OSC32KCAL_Msk
#endif
}
static void wait_gclk_synchronization(void)
{
while (GCLK->STATUS.bit.SYNCBUSY) {
}
}
static void xosc32k_init(void)
{
#ifdef CONFIG_SOC_ATMEL_SAMD_XOSC32K
SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP(6) |
SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K;
SYSCTRL->XOSC32K.bit.ENABLE = 1;
/* Wait for the crystal to stabalise. */
while (!SYSCTRL->PCLKSR.bit.XOSC32KRDY) {
}
#endif
}
static void osc32k_init(void)
{
#ifdef FUSES_OSC32K_CAL_ADDR
uint32_t fuse = *(uint32_t *)FUSES_OSC32K_CAL_ADDR;
uint32_t calib = (fuse & FUSES_OSC32K_CAL_Msk) >> FUSES_OSC32K_CAL_Pos;
#if !CONFIG_SOC_ATMEL_SAMD_OSC8M || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
#define osc8m_init()
#else
uint32_t fuse = *(uint32_t *)FUSES_OSC32KCAL_ADDR;
uint32_t calib = (fuse & FUSES_OSC32KCAL_Msk) >> FUSES_OSC32KCAL_Pos;
static inline void osc8m_init(void)
{
uint32_t reg;
/* Save calibration */
reg = SYSCTRL->OSC8M.reg
& (SYSCTRL_OSC8M_FRANGE_Msk | SYSCTRL_OSC8M_CALIB_Msk);
SYSCTRL->OSC8M.reg = reg
| SYSCTRL_OSC8M_RUNSTDBY
| SYSCTRL_OSC8M_PRESC(0) /* 8MHz (/1) */
| SYSCTRL_OSC8M_ENABLE;
while (!SYSCTRL->PCLKSR.bit.OSC8MRDY) {
}
}
#endif
SYSCTRL->OSC32K.reg = SYSCTRL_OSC32K_CALIB(calib) |
SYSCTRL_OSC32K_STARTUP(0x6u) |
SYSCTRL_OSC32K_EN32K | SYSCTRL_OSC32K_ENABLE;
#if !CONFIG_SOC_ATMEL_SAMD_OSC32K || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
#define osc32k_init()
#else
static inline void osc32k_init(void)
{
uint32_t cal;
/* Get calibration value */
cal = (*((uint32_t *)FUSES_OSC32K_CAL_ADDR)
& FUSES_OSC32K_CAL_Msk) >> FUSES_OSC32K_CAL_Pos;
SYSCTRL->OSC32K.reg = SYSCTRL_OSC32K_CALIB(cal)
| SYSCTRL_OSC32K_STARTUP(0x5) /* 34 cycles / ~1ms */
| SYSCTRL_OSC32K_RUNSTDBY
| SYSCTRL_OSC32K_EN32K
| SYSCTRL_OSC32K_ENABLE;
/* Wait for the oscillator to stabilise. */
while (!SYSCTRL->PCLKSR.bit.OSC32KRDY) {
}
}
#endif
static void dfll_init(void)
{
/* No prescaler */
GCLK->GENDIV.reg = GCLK_GENDIV_ID(1) | GCLK_GENDIV_DIV(0);
wait_gclk_synchronization();
#if defined(CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN)
/* Route XOSC32K to GCLK1 */
GCLK->GENCTRL.reg =
GCLK_GENCTRL_ID(1) | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_GENEN;
#elif defined(CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN)
/* Route OSC8M to GCLK1 */
GCLK->GENCTRL.reg =
GCLK_GENCTRL_ID(1) | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_GENEN;
#if !CONFIG_SOC_ATMEL_SAMD_XOSC || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
#define xosc_init()
#else
#error Unsupported main clock source.
static inline void xosc_init(void)
{
SYSCTRL->XOSC.reg = SYSCTRL_XOSC_STARTUP(0x5) /* 32 cycles / ~1ms */
| SYSCTRL_XOSC_RUNSTDBY
| SYSCTRL_XOSC_AMPGC
#if CONFIG_SOC_ATMEL_SAMD_XOSC_FREQ_HZ <= 2000000
| SYSCTRL_XOSC_GAIN(0x0)
#elif CONFIG_SOC_ATMEL_SAMD_XOSC_FREQ_HZ <= 4000000
| SYSCTRL_XOSC_GAIN(0x1)
#elif CONFIG_SOC_ATMEL_SAMD_XOSC_FREQ_HZ <= 8000000
| SYSCTRL_XOSC_GAIN(0x2)
#elif CONFIG_SOC_ATMEL_SAMD_XOSC_FREQ_HZ <= 16000000
| SYSCTRL_XOSC_GAIN(0x3)
#elif CONFIG_SOC_ATMEL_SAMD_XOSC_FREQ_HZ <= 32000000
| SYSCTRL_XOSC_GAIN(0x4)
#endif
#if CONFIG_SOC_ATMEL_SAMD_XOSC_CRYSTAL
| SYSCTRL_XOSC_XTALEN
#endif
| SYSCTRL_XOSC_ENABLE;
while (!SYSCTRL->PCLKSR.bit.XOSCRDY) {
}
}
#endif
wait_gclk_synchronization();
/* Route GCLK1 to multiplexer 1 */
GCLK->CLKCTRL.reg =
GCLK_CLKCTRL_ID(0) | GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_CLKEN;
wait_gclk_synchronization();
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
}
uint32_t mul = (SOC_ATMEL_SAM0_MCK_FREQ_HZ +
SOC_ATMEL_SAM0_GCLK1_FREQ_HZ / 2) /
SOC_ATMEL_SAM0_GCLK1_FREQ_HZ;
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(31) |
SYSCTRL_DFLLMUL_FSTEP(511) |
SYSCTRL_DFLLMUL_MUL(mul);
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
}
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE |
#ifdef SYSCTRL_DFLLCTRL_WAITLOCK
SYSCTRL_DFLLCTRL_WAITLOCK |
#if !CONFIG_SOC_ATMEL_SAMD_XOSC32K || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
#define xosc32k_init()
#else
static inline void xosc32k_init(void)
{
SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP(0x1) /* 4096 cycles / ~0.13s */
| SYSCTRL_XOSC32K_RUNSTDBY
| SYSCTRL_XOSC32K_EN32K
| SYSCTRL_XOSC32K_AAMPEN
#if CONFIG_SOC_ATMEL_SAMD_XOSC32K_CRYSTAL
| SYSCTRL_XOSC32K_XTALEN
#endif
SYSCTRL_DFLLCTRL_QLDIS;
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
| SYSCTRL_XOSC32K_ENABLE;
while (!SYSCTRL->PCLKSR.bit.XOSC32KRDY) {
}
}
#endif
#if CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
#define dfll48m_init()
#else
static inline void dfll48m_init(void)
{
uint32_t fcal, ccal;
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(1)
#if CONFIG_SOC_ATMEL_SAMD_OSC32K_AS_MAIN
| GCLK_GENCTRL_SRC_OSC32K
#elif CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN
| GCLK_GENCTRL_SRC_XOSC32K
#elif CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN
| GCLK_GENCTRL_SRC_OSC8M
#elif CONFIG_SOC_ATMEL_SAMD_XOSC_AS_MAIN
| GCLK_GENCTRL_SRC_XOSC
#endif
| GCLK_GENCTRL_IDC
| GCLK_GENCTRL_RUNSTDBY
| GCLK_GENCTRL_GENEN;
while (GCLK->STATUS.bit.SYNCBUSY) {
}
/* Enable the DFLL */
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 */
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(0)
| GCLK_CLKCTRL_GEN_GCLK1
| GCLK_CLKCTRL_CLKEN;
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_MODE
| SYSCTRL_DFLLCTRL_QLDIS
| SYSCTRL_DFLLCTRL_RUNSTDBY;
/* Get calibration values */
ccal = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR)
& FUSES_DFLL48M_COARSE_CAL_Msk) >> FUSES_DFLL48M_COARSE_CAL_Pos;
fcal = (*((uint32_t *)FUSES_DFLL48M_FINE_CAL_ADDR)
& FUSES_DFLL48M_FINE_CAL_Msk) >> FUSES_DFLL48M_FINE_CAL_Pos;
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(ccal)
| SYSCTRL_DFLLVAL_FINE(fcal);
/* Use half of maximum for both */
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(31)
| SYSCTRL_DFLLMUL_FSTEP(511)
| SYSCTRL_DFLLMUL_MUL(SOC_ATMEL_SAM0_DFLL48M_MUL);
/* Enable */
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
}
SYSCTRL->DFLLCTRL.bit.ENABLE = 1;
/* Wait for synchronization. */
while (!SYSCTRL->PCLKSR.bit.DFLLLCKC || !SYSCTRL->PCLKSR.bit.DFLLLCKF) {
}
}
#endif
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
#if CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
#define flash_waitstates_init()
#else
static inline void flash_waitstates_init(void)
{
NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS(CONFIG_SOC_ATMEL_SAMD_NVM_WAIT_STATES);
}
#endif
#if CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
#define gclk_main_configure()
#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) {
}
}
#endif
static void osc8m_init(void)
#if !CONFIG_ADC_SAM0 || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
#define gclk_adc_configure()
#else
static inline void gclk_adc_configure(void)
{
/* Turn off the prescaler */
SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC(0);
SYSCTRL->OSC8M.bit.ONDEMAND = 0;
}
GCLK->GENDIV.reg = GCLK_GENDIV_ID(3)
| GCLK_GENDIV_DIV(SOC_ATMEL_SAM0_GCLK3_DIV);
static void gclks_init(void)
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) {
}
}
#endif
#if CONFIG_SOC_ATMEL_SAMD_OSC8M || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN
#define osc8m_disable()
#else
static inline void osc8m_disable(void)
{
/* DFLL/1 -> GCLK0 */
GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) | GCLK_GENDIV_DIV(0);
wait_gclk_synchronization();
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(0) | GCLK_GENCTRL_SRC_DFLL48M |
GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN;
wait_gclk_synchronization();
/* OSC8M/1 -> GCLK3 */
GCLK->GENCTRL.reg =
GCLK_GENCTRL_ID(3) | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_GENEN;
wait_gclk_synchronization();
/* OSCULP32K/32 -> GCLK2 */
GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(32 - 1);
wait_gclk_synchronization();
GCLK->GENCTRL.reg =
GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_SRC_OSC32K | GCLK_GENCTRL_GENEN;
wait_gclk_synchronization();
}
static void dividers_init(void)
{
/* Set the CPU, APBA, B, and C dividers */
PM->CPUSEL.reg = PM_CPUSEL_CPUDIV_DIV1;
PM->APBASEL.reg = PM_APBASEL_APBADIV_DIV1_Val;
PM->APBBSEL.reg = PM_APBBSEL_APBBDIV_DIV1_Val;
PM->APBCSEL.reg = PM_APBCSEL_APBCDIV_DIV1_Val;
/* TODO(mlhx): enable clock failure detection? */
SYSCTRL->OSC8M.bit.ENABLE = 0;
}
#endif
static int atmel_samd_init(const struct device *arg)
{
@ -180,14 +263,15 @@ static int atmel_samd_init(const struct device *arg)
key = irq_lock();
flash_waitstates_init();
osc8m_init();
osc32k_init();
xosc_init();
xosc32k_init();
dfll_init();
gclks_init();
dividers_init();
dfll48m_init();
flash_waitstates_init();
gclk_main_configure();
gclk_adc_configure();
osc8m_disable();
/* Install default handler that simply resets the CPU
* if configured in the kernel, NOP otherwise

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 Sean Nyekjaer
* Copyright (c) 2023 Ionut Catalin Pavel <iocapa@iocapa.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -13,7 +14,6 @@
#include <zephyr/types.h>
#if defined(CONFIG_SOC_PART_NUMBER_SAMD20E14)
#include <samd20e14.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD20E15)
@ -63,19 +63,57 @@
/** Master Clock (MCK) Frequency */
#define SOC_ATMEL_SAM0_MCK_FREQ_HZ SOC_ATMEL_SAM0_HCLK_FREQ_HZ
#define SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_OSC8M_FREQ_HZ 8000000
#define SOC_ATMEL_SAM0_GCLK0_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#if defined(CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ
/** Known values */
#define SOC_ATMEL_SAM0_DFLL48M_MAX_FREQ_HZ 48000000
#define SOC_ATMEL_SAM0_OSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_OSC8M_FREQ_HZ 8000000
#define SOC_ATMEL_SAM0_OSCULP32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_GCLK1_TARGET_FREQ_HZ 31250
/** GCLK1 source frequency selector */
#if defined(CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_GCLK1_TARGET_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_OSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_OSC32K_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_XOSC_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ CONFIG_SOC_ATMEL_SAMD_XOSC_FREQ_HZ
#else
#error Unsupported GCLK1 clock source.
#endif
/** Dividers and frequency for GCLK0 */
#define SOC_ATMEL_SAM0_GCLK0_DIV \
(SOC_ATMEL_SAM0_DFLL48M_MAX_FREQ_HZ / SOC_ATMEL_SAM0_MCK_FREQ_HZ)
#define SOC_ATMEL_SAM0_GCLK0_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
/** DFLL48M output frequency */
#define SOC_ATMEL_SAM0_DFLL48M_FREQ_HZ \
(SOC_ATMEL_SAM0_MCK_FREQ_HZ * SOC_ATMEL_SAM0_GCLK0_DIV)
/** Dividers and frequency for GCLK1 */
#define SOC_ATMEL_SAM0_GCLK1_DIV \
(SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ / SOC_ATMEL_SAM0_GCLK1_TARGET_FREQ_HZ)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ \
(SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ / SOC_ATMEL_SAM0_GCLK1_DIV)
/** DFLL48M output multiplier */
#define SOC_ATMEL_SAM0_DFLL48M_MUL \
(SOC_ATMEL_SAM0_DFLL48M_FREQ_HZ / SOC_ATMEL_SAM0_GCLK1_FREQ_HZ)
/** Frequency for GCLK2 */
#define SOC_ATMEL_SAM0_GCLK2_FREQ_HZ SOC_ATMEL_SAM0_OSCULP32K_FREQ_HZ
/** Dividers and frequency for GCLK3 */
#define SOC_ATMEL_SAM0_GCLK3_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#define SOC_ATMEL_SAM0_GCLK3_DIV \
(SOC_ATMEL_SAM0_DFLL48M_FREQ_HZ / SOC_ATMEL_SAM0_GCLK3_FREQ_HZ)
#define SOC_ATMEL_SAM0_APBA_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#define SOC_ATMEL_SAM0_APBB_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#define SOC_ATMEL_SAM0_APBC_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2017 Google LLC.
* Copyright (c) 2023 Ionut Catalin Pavel <iocapa@iocapa.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -13,7 +14,6 @@
#include <zephyr/types.h>
#if defined(CONFIG_SOC_PART_NUMBER_SAMD21E15A)
#include <samd21e15a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21E16A)
@ -57,19 +57,57 @@
/** Master Clock (MCK) Frequency */
#define SOC_ATMEL_SAM0_MCK_FREQ_HZ SOC_ATMEL_SAM0_HCLK_FREQ_HZ
#define SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_OSC8M_FREQ_HZ 8000000
#define SOC_ATMEL_SAM0_GCLK0_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#if defined(CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ
/** Known values */
#define SOC_ATMEL_SAM0_DFLL48M_MAX_FREQ_HZ 48000000
#define SOC_ATMEL_SAM0_OSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_OSC8M_FREQ_HZ 8000000
#define SOC_ATMEL_SAM0_OSCULP32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_GCLK1_TARGET_FREQ_HZ 31250
/** GCLK1 source frequency selector */
#if defined(CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_GCLK1_TARGET_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_OSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_OSC32K_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_XOSC_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ CONFIG_SOC_ATMEL_SAMD_XOSC_FREQ_HZ
#else
#error Unsupported GCLK1 clock source.
#endif
/** Dividers and frequency for GCLK0 */
#define SOC_ATMEL_SAM0_GCLK0_DIV \
(SOC_ATMEL_SAM0_DFLL48M_MAX_FREQ_HZ / SOC_ATMEL_SAM0_MCK_FREQ_HZ)
#define SOC_ATMEL_SAM0_GCLK0_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
/** DFLL48M output frequency */
#define SOC_ATMEL_SAM0_DFLL48M_FREQ_HZ \
(SOC_ATMEL_SAM0_MCK_FREQ_HZ * SOC_ATMEL_SAM0_GCLK0_DIV)
/** Dividers and frequency for GCLK1 */
#define SOC_ATMEL_SAM0_GCLK1_DIV \
(SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ / SOC_ATMEL_SAM0_GCLK1_TARGET_FREQ_HZ)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ \
(SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ / SOC_ATMEL_SAM0_GCLK1_DIV)
/** DFLL48M output multiplier */
#define SOC_ATMEL_SAM0_DFLL48M_MUL \
(SOC_ATMEL_SAM0_DFLL48M_FREQ_HZ / SOC_ATMEL_SAM0_GCLK1_FREQ_HZ)
/** Frequency for GCLK2 */
#define SOC_ATMEL_SAM0_GCLK2_FREQ_HZ SOC_ATMEL_SAM0_OSCULP32K_FREQ_HZ
/** Dividers and frequency for GCLK3 */
#define SOC_ATMEL_SAM0_GCLK3_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#define SOC_ATMEL_SAM0_GCLK3_DIV \
(SOC_ATMEL_SAM0_DFLL48M_FREQ_HZ / SOC_ATMEL_SAM0_GCLK3_FREQ_HZ)
#define SOC_ATMEL_SAM0_APBA_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#define SOC_ATMEL_SAM0_APBB_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#define SOC_ATMEL_SAM0_APBC_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2017 Google LLC.
* Copyright (c) 2023 Ionut Catalin Pavel <iocapa@iocapa.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -13,7 +14,6 @@
#include <zephyr/types.h>
#if defined(CONFIG_SOC_PART_NUMBER_SAMR21E16A)
#include <samr21e16a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMR21E17A)
@ -43,19 +43,57 @@
/** Master Clock (MCK) Frequency */
#define SOC_ATMEL_SAM0_MCK_FREQ_HZ SOC_ATMEL_SAM0_HCLK_FREQ_HZ
#define SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_OSC8M_FREQ_HZ 8000000
#define SOC_ATMEL_SAM0_GCLK0_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#if defined(CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ
/** Known values */
#define SOC_ATMEL_SAM0_DFLL48M_MAX_FREQ_HZ 48000000
#define SOC_ATMEL_SAM0_OSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_OSC8M_FREQ_HZ 8000000
#define SOC_ATMEL_SAM0_OSCULP32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_GCLK1_TARGET_FREQ_HZ 31250
/** GCLK1 source frequency selector */
#if defined(CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_GCLK1_TARGET_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_OSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_OSC32K_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_XOSC_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ CONFIG_SOC_ATMEL_SAMD_XOSC_FREQ_HZ
#else
#error Unsupported GCLK1 clock source.
#endif
/** Dividers and frequency for GCLK0 */
#define SOC_ATMEL_SAM0_GCLK0_DIV \
(SOC_ATMEL_SAM0_DFLL48M_MAX_FREQ_HZ / SOC_ATMEL_SAM0_MCK_FREQ_HZ)
#define SOC_ATMEL_SAM0_GCLK0_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
/** DFLL48M output frequency */
#define SOC_ATMEL_SAM0_DFLL48M_FREQ_HZ \
(SOC_ATMEL_SAM0_MCK_FREQ_HZ * SOC_ATMEL_SAM0_GCLK0_DIV)
/** Dividers and frequency for GCLK1 */
#define SOC_ATMEL_SAM0_GCLK1_DIV \
(SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ / SOC_ATMEL_SAM0_GCLK1_TARGET_FREQ_HZ)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ \
(SOC_ATMEL_SAM0_GCLK1_SRC_FREQ_HZ / SOC_ATMEL_SAM0_GCLK1_DIV)
/** DFLL48M output multiplier */
#define SOC_ATMEL_SAM0_DFLL48M_MUL \
(SOC_ATMEL_SAM0_DFLL48M_FREQ_HZ / SOC_ATMEL_SAM0_GCLK1_FREQ_HZ)
/** Frequency for GCLK2 */
#define SOC_ATMEL_SAM0_GCLK2_FREQ_HZ SOC_ATMEL_SAM0_OSCULP32K_FREQ_HZ
/** Dividers and frequency for GCLK3 */
#define SOC_ATMEL_SAM0_GCLK3_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#define SOC_ATMEL_SAM0_GCLK3_DIV \
(SOC_ATMEL_SAM0_DFLL48M_FREQ_HZ / SOC_ATMEL_SAM0_GCLK3_FREQ_HZ)
#define SOC_ATMEL_SAM0_APBA_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#define SOC_ATMEL_SAM0_APBB_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#define SOC_ATMEL_SAM0_APBC_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ