aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/atsamd/Kconfig1
-rw-r--r--src/atsamd/clock.c84
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();
}