From bd65c37ed5caac04857493518b07eda083659977 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Fri, 4 Jun 2021 17:03:46 -0400 Subject: [PATCH] atsamd: Add support for 25Mhz crystals Needed for the Duet3 Mini 5+ board. Reported by @lukeslaboratory. Signed-off-by: Kevin O'Connor --- src/atsamd/Kconfig | 2 ++ src/atsamd/samd51_clock.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/atsamd/Kconfig b/src/atsamd/Kconfig index 44ded6ca..5684ff6f 100644 --- a/src/atsamd/Kconfig +++ b/src/atsamd/Kconfig @@ -89,6 +89,8 @@ choice prompt "Clock Reference" config CLOCK_REF_X32K bool "32.768Khz crystal" + config CLOCK_REF_X25M + bool "25Mhz crystal" if MACH_SAMD51 config CLOCK_REF_INTERNAL bool "Internal clock" endchoice diff --git a/src/atsamd/samd51_clock.c b/src/atsamd/samd51_clock.c index 046f5744..cf7402e5 100644 --- a/src/atsamd/samd51_clock.c +++ b/src/atsamd/samd51_clock.c @@ -97,6 +97,8 @@ config_dfll(uint32_t dfllmul, uint32_t ctrlb) #if CONFIG_CLOCK_REF_X32K DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PA0,PA1"); +#elif CONFIG_CLOCK_REF_X25M +DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PB22,PB23"); #endif // Initialize the clocks using an external 32K crystal @@ -123,6 +125,33 @@ clock_init_32k(void) gen_clock(CLKGEN_48M, GCLK_GENCTRL_SRC_DPLL1); } +// Initialize the clocks using an external 25M crystal +static void +clock_init_25m(void) +{ + // Enable XOSC1 + uint32_t freq_xosc = 25000000; + uint32_t val = (OSCCTRL_XOSCCTRL_ENABLE | OSCCTRL_XOSCCTRL_XTALEN + | OSCCTRL_XOSCCTRL_IPTAT(3) | OSCCTRL_XOSCCTRL_IMULT(6)); + OSCCTRL->XOSCCTRL[1].reg = val; + while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_XOSCRDY1)) + ; + + // Generate 120Mhz clock on PLL0 (with XOSC1 as reference) + uint32_t p0div = 10, p0mul = DIV_ROUND_CLOSEST(FREQ_MAIN, freq_xosc/p0div); + uint32_t p0ctrlb = OSCCTRL_DPLLCTRLB_DIV(p0div / 2 - 1); + config_dpll(0, p0mul, p0ctrlb | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1); + + // Switch main clock to 120Mhz PLL0 + gen_clock(CLKGEN_MAIN, GCLK_GENCTRL_SRC_DPLL0); + + // Generate 48Mhz clock on PLL1 (with XOSC1 as reference) + uint32_t p1div = 50, p1mul = DIV_ROUND_CLOSEST(FREQ_48M, freq_xosc/p1div); + uint32_t p1ctrlb = OSCCTRL_DPLLCTRLB_DIV(p1div / 2 - 1); + config_dpll(1, p1mul, p1ctrlb | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1); + gen_clock(CLKGEN_48M, GCLK_GENCTRL_SRC_DPLL1); +} + // Initialize clocks from factory calibrated internal clock static void clock_init_internal(void) @@ -167,6 +196,8 @@ SystemInit(void) // Init clocks if (CONFIG_CLOCK_REF_X32K) clock_init_32k(); + else if (CONFIG_CLOCK_REF_X25M) + clock_init_25m(); else clock_init_internal();