#include "clock.h" #include "types.h" #include "peripherals.h" #define WRITE_CLK_REG(reg, value) (WRITE_REGISTER(CLOCK, reg, value)) #define READ_CLK_REG(reg) (READ_REGISTER(CLOCK, reg)) enum hfclk_src { HFINT = 0, HFXO = 1, }; enum lfclk_src { LFRC = 0, LFXO = 1, LFSYNT = 2, }; /** * Memory-mapped registers for the CLOCK peripheral with their offset from its base address, * Check the nrf52832's manual for their description. */ enum clock_registers { TASKS_HFCLKSTART = 0x000, TASKS_HFCLKSTOP = 0x004, TASKS_LFCLKSTART = 0x008, TASKS_LFCLKSTOP = 0x00c, TASKS_CAL = 0x010, TASKS_CTSTART = 0x014, TASKS_CTSTOP = 0x018, EVENTS_HFCLKSTARTED = 0x100, EVENTS_LFCLKSTARTED = 0x104, EVENTS_DONE = 0x10c, EVENTS_CTTO = 0x110, INTENSET = 0x304, INTENCLR = 0x308, HFCLKRUN = 0x408, HFCLKSTAT = 0x40c, LFCLKRUN = 0x414, LFCLKSTAT = 0x418, LFCLKSRCCOPY = 0x41c, LFCLKSRC = 0x518, CTIV = 0x538, TRACECONFIG = 0x55c, }; static bool init_hfclk() { /* We just assert that the source clock is running with the CPU internal clock * as source */ u32 hfclk_status = READ_CLK_REG(HFCLKSTAT); int clk_src = hfclk_status & 0x1; bool clk_running = (hfclk_status >> 16) & 0x1; return (clk_src == HFINT) && clk_running; } static bool init_lfclk() { bool clk_started = false; enum lfclk_src src = LFRC; /* LFCLK use the LFRC clock by default, so it should be ready * to be started directly */ WRITE_CLK_REG(TASKS_LFCLKSTART, 0x1); /* Wait for the LFCLK to be started */ /* TODO: We should rely on the IRQ for the LFCLKSTARTED event instead */ do { u32 lfclk_stat = READ_CLK_REG(LFCLKSTAT); clk_started = (lfclk_stat >> 16) & 0x1; src = lfclk_stat & 0x2; } while (!clk_started); return src == LFRC; } bool init_clock() { return init_hfclk() && init_lfclk(); }