diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/atsamd/Kconfig | 1 | ||||
-rw-r--r-- | src/atsamd/clock.c | 84 |
2 files changed, 58 insertions, 27 deletions
diff --git a/src/atsamd/Kconfig b/src/atsamd/Kconfig index 8cc9bea0..b9bcbab2 100644 --- a/src/atsamd/Kconfig +++ b/src/atsamd/Kconfig @@ -54,7 +54,6 @@ config CLOCK_FREQ default 120000000 if MACH_SAMD51 choice - depends on MACH_SAMD51 prompt "Clock Reference" config CLOCK_REF_INTERNAL bool "Internal clock" diff --git a/src/atsamd/clock.c b/src/atsamd/clock.c index 46319f30..1a97fe52 100644 --- a/src/atsamd/clock.c +++ b/src/atsamd/clock.c @@ -9,7 +9,6 @@ // The "generic clock generators" that are configured #define CLKGEN_MAIN 0 -#define CLKGEN_32K 1 #define CLKGEN_ULP32K 2 #define FREQ_MAIN 48000000 @@ -49,41 +48,74 @@ get_pclock_frequency(uint32_t pclk_id) return FREQ_MAIN; } -void -SystemInit(void) +// Initialize the clocks using an external 32K crystal +static void +clock_init_32k(void) { - // Setup flash to work with 48Mhz clock - NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_RWS_HALF; - - // Reset GCLK - GCLK->CTRL.reg = GCLK_CTRL_SWRST; - while (GCLK->CTRL.reg & GCLK_CTRL_SWRST) - ; - - // Enable external 32Khz crystal and route to CLKGEN_32K + // Enable external 32Khz crystal uint32_t val = (SYSCTRL_XOSC32K_STARTUP(6) | SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K); SYSCTRL->XOSC32K.reg = val; SYSCTRL->XOSC32K.reg = val | SYSCTRL_XOSC32K_ENABLE; while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY)) ; - gen_clock(CLKGEN_32K, GCLK_GENCTRL_SRC_XOSC32K); - // Configure DFLL48M clock (with CLKGEN_32K as reference) - route_pclock(SYSCTRL_GCLK_ID_DFLL48, CLKGEN_32K); - SYSCTRL->DFLLCTRL.reg = 0; + // Generate 48Mhz clock on DPLL (with XOSC32K as reference) + SYSCTRL->DPLLCTRLA.reg = 0; uint32_t mul = DIV_ROUND_CLOSEST(FREQ_MAIN, FREQ_32K); - SYSCTRL->DFLLMUL.reg = (SYSCTRL_DFLLMUL_CSTEP(31) - | SYSCTRL_DFLLMUL_FSTEP(511) - | SYSCTRL_DFLLMUL_MUL(mul)); - SYSCTRL->DFLLCTRL.reg = (SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_WAITLOCK - | SYSCTRL_DFLLCTRL_QLDIS - | SYSCTRL_DFLLCTRL_ENABLE); - uint32_t ready = (SYSCTRL_PCLKSR_DFLLRDY | SYSCTRL_PCLKSR_DFLLLCKC - | SYSCTRL_PCLKSR_DFLLLCKF); - while ((SYSCTRL->PCLKSR.reg & ready) != ready) + SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR(mul - 1); + SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_LBYPASS; + SYSCTRL->DPLLCTRLA.reg = SYSCTRL_DPLLCTRLA_ENABLE; + uint32_t mask = SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK; + while ((SYSCTRL->DPLLSTATUS.reg & mask) != mask) + ; + + // Switch main clock to DPLL clock + gen_clock(CLKGEN_MAIN, GCLK_GENCTRL_SRC_DPLL96M); +} + +// Initialize clocks from factory calibrated internal clock +static void +clock_init_internal(void) +{ + // Configure DFLL48M clock in open loop mode + SYSCTRL->DFLLCTRL.reg = 0; + uint32_t coarse = GET_FUSE(FUSES_DFLL48M_COARSE_CAL); + uint32_t fine = GET_FUSE(FUSES_DFLL48M_FINE_CAL); + SYSCTRL->DFLLVAL.reg = (SYSCTRL_DFLLVAL_COARSE(coarse) + | SYSCTRL_DFLLVAL_FINE(fine)); + if (CONFIG_USBSERIAL) { + // Enable USB clock recovery mode + uint32_t mul = DIV_ROUND_CLOSEST(FREQ_MAIN, 1000); + SYSCTRL->DFLLMUL.reg = (SYSCTRL_DFLLMUL_FSTEP(10) + | SYSCTRL_DFLLMUL_MUL(mul)); + SYSCTRL->DFLLCTRL.reg = (SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_USBCRM + | SYSCTRL_DFLLCTRL_CCDIS + | SYSCTRL_DFLLCTRL_ENABLE); + } else { + SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE; + } + while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY)) ; // Switch main clock to DFLL48M clock - gen_clock(CLKGEN_MAIN, GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_IDC); + gen_clock(CLKGEN_MAIN, GCLK_GENCTRL_SRC_DFLL48M); +} + +void +SystemInit(void) +{ + // Setup flash to work with 48Mhz clock + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_RWS_HALF; + + // Reset GCLK + GCLK->CTRL.reg = GCLK_CTRL_SWRST; + while (GCLK->CTRL.reg & GCLK_CTRL_SWRST) + ; + + // Init clocks + if (CONFIG_CLOCK_REF_X32K) + clock_init_32k(); + else + clock_init_internal(); } |