atsamd: Add support for 25Mhz crystals

Needed for the Duet3 Mini 5+ board.  Reported by @lukeslaboratory.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2021-06-04 17:03:46 -04:00
parent 6266e7c259
commit bd65c37ed5
2 changed files with 33 additions and 0 deletions

View File

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

View File

@ -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();