| /* |
| * Copyright (c) 2022 Microchip Technology Inc. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include <errno.h> |
| #include <zephyr/device.h> |
| #include <soc.h> |
| #include <zephyr/drivers/clock_control.h> |
| #include <zephyr/drivers/clock_control/mchp_xec_clock_control.h> |
| #include <zephyr/dt-bindings/clock/mchp_xec_pcr.h> |
| #include <zephyr/dt-bindings/pinctrl/mchp-xec-pinctrl.h> |
| #include <zephyr/kernel.h> |
| #include <zephyr/logging/log.h> |
| #include <zephyr/sys/printk.h> |
| LOG_MODULE_REGISTER(clock32k, CONFIG_CLOCK_CONTROL_LOG_LEVEL); |
| |
| #include <soc.h> |
| |
| #ifdef CONFIG_SOC_SERIES_MEC1501X |
| static void pcr_clock_regs(void) |
| { |
| struct pcr_regs *pcr = ((struct pcr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 0)); |
| uint32_t r = pcr->PWR_RST_STS; |
| |
| LOG_INF("MEC152x PCR registers"); |
| |
| LOG_INF("PCR Power Reset Status register(bit[10] is 32K_ACTIVE) = 0x%x", r); |
| |
| r = pcr->OSC_ID; |
| LOG_INF("PCR Oscillator ID register(bit[8]=PLL Lock) = 0x%x", r); |
| |
| r = pcr->PROC_CLK_CTRL; |
| LOG_INF("PCR Processor Clock Control register = 0x%x", r); |
| |
| r = pcr->SLOW_CLK_CTRL; |
| LOG_INF("PCR Slow Clock Control register = 0x%x", r); |
| } |
| |
| static void vbat_clock_regs(void) |
| { |
| struct vbatr_regs *vbr = ((struct vbatr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 1)); |
| uint32_t cken = vbr->CLK32_EN; |
| |
| LOG_INF("MEC152x VBAT Clock registers"); |
| LOG_INF("ClockEnable = 0x%08x", cken); |
| if (cken & BIT(2)) { |
| LOG_INF("32KHz clock source is XTAL"); |
| if (cken & BIT(3)) { |
| LOG_INF("XTAL configured for single-ended using XTAL2 pin" |
| " (external 32KHz waveform)"); |
| } else { |
| LOG_INF("XTAL configured for parallel resonant crystal circuit on" |
| " XTAL1 and XTAL2 pins"); |
| } |
| } else { |
| LOG_INF("32KHz clock source is the Internal Silicon 32KHz OSC"); |
| } |
| if (cken & BIT(1)) { |
| LOG_INF("32KHz clock domain uses the 32KHZ_IN pin(GPIO_0165 F1)"); |
| } else { |
| LOG_INF("32KHz clock domain uses the 32KHz clock source"); |
| } |
| |
| LOG_INF("32KHz trim = 0x%08x", vbr->CKK32_TRIM); |
| } |
| |
| static void vbat_power_fail(void) |
| { |
| struct vbatr_regs *vbr = ((struct vbatr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 1)); |
| uint32_t pfrs = vbr->PFRS; |
| |
| LOG_INF("MEC152x VBAT Power-Fail-Reset-Status = 0x%x", pfrs); |
| |
| if (pfrs & MCHP_VBATR_PFRS_VBAT_RST_POS) { |
| LOG_INF("WARNING: VBAT POR. Clock control register settings lost during" |
| " power cycle"); |
| } |
| |
| vbr->PFRS = 0xffffffffU; |
| } |
| #else |
| static void print_pll_clock_src(uint32_t pcr_clk_src) |
| { |
| uint32_t temp = pcr_clk_src & MCHP_PCR_VTR_32K_SRC_MASK; |
| |
| if (temp == MCHP_PCR_VTR_32K_SRC_SILOSC) { |
| LOG_INF("PLL 32K clock source is Internal Silicon OSC(VTR)"); |
| } else if (temp == MCHP_PCR_VTR_32K_SRC_XTAL) { |
| LOG_INF("PLL 32K clock source is XTAL input(VTR)"); |
| } else if (temp == MCHP_PCR_VTR_32K_SRC_PIN) { |
| LOG_INF("PLL 32K clock source is 32KHZ_IN pin(VTR)"); |
| } else { |
| LOG_INF("PLL 32K clock source is OFF. PLL disabled. Running on Ring OSC"); |
| } |
| } |
| |
| static void print_periph_clock_src(uint32_t vb_clk_src) |
| { |
| uint32_t temp = (vb_clk_src & MCHP_VBATR_CS_PCS_MSK) >> MCHP_VBATR_CS_PCS_POS; |
| |
| if (temp == MCHP_VBATR_CS_PCR_VTR_VBAT_SO_VAL) { |
| LOG_INF("Periph 32K clock source is InternalOSC(VTR) and InternalOSC(VBAT)"); |
| } else if (temp == MCHP_VBATR_CS_PCS_VTR_VBAT_XTAL_VAL) { |
| LOG_INF("Periph 32K clock source is XTAL(VTR) and XTAL(VBAT)"); |
| } else if (temp == MCHP_VBATR_CS_PCS_VTR_PIN_SO_VAL) { |
| LOG_INF("Periph 32K clock source is 32KHZ_PIN(VTR) and InternalOSC(VBAT)"); |
| } else { |
| LOG_INF("Periph 32K clock source is 32KHZ_PIN fallback to XTAL when VTR is off"); |
| } |
| } |
| |
| static void pcr_clock_regs(void) |
| { |
| struct pcr_regs *pcr = ((struct pcr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 0)); |
| uint32_t pcr_clk_src = pcr->CLK32K_SRC_VTR; |
| uint32_t r = pcr->PWR_RST_STS; |
| |
| LOG_INF("MEC172x PCR registers"); |
| |
| print_pll_clock_src(pcr_clk_src); |
| |
| LOG_INF("PCR Power Reset Status register(b[10] is 32K_ACTIVE) = 0x%x", r); |
| |
| r = pcr->OSC_ID; |
| LOG_INF("PCR Oscillator ID register(bit[8]=PLL Lock) = 0x%x", r); |
| |
| r = pcr->PROC_CLK_CTRL; |
| LOG_INF("PCR Processor Clock Control register = 0x%x", r); |
| |
| r = pcr->SLOW_CLK_CTRL; |
| LOG_INF("PCR Slow Clock Control register = 0x%x", r); |
| |
| r = pcr->CNT32K_PER; |
| LOG_INF("PCR 32KHz Clock Monitor Pulse High Count register = 0x%x", r); |
| |
| r = pcr->CNT32K_PER_MIN; |
| LOG_INF("PCR 32KHz Clock Monitor Period Maximum Count register = 0x%x", r); |
| |
| r = pcr->CNT32K_DV; |
| LOG_INF("PCR 32KHz Clock Monitor Duty Cycle Variation register = 0x%x", r); |
| |
| r = pcr->CNT32K_DV_MAX; |
| LOG_INF("PCR 32KHz Clock Monitor Duty Cycle Variation Max register = 0x%x", r); |
| |
| r = pcr->CNT32K_VALID; |
| LOG_INF("PCR 32KHz Clock Monitor Valid register = 0x%x", r); |
| |
| r = pcr->CNT32K_VALID_MIN; |
| LOG_INF("PCR 32KHz Clock Monitor Valid Min register = 0x%x", r); |
| |
| r = pcr->CNT32K_CTRL; |
| LOG_INF("PCR 32KHz Clock Monitor Control register = 0x%x", r); |
| |
| r = pcr->CLK32K_MON_ISTS; |
| LOG_INF("PCR 32KHz Clock Monitor Control Status register = 0x%x", r); |
| } |
| |
| static void vbat_clock_regs(void) |
| { |
| struct vbatr_regs *vbr = ((struct vbatr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 1)); |
| uint32_t vb_clk_src = vbr->CLK32_SRC; |
| |
| print_periph_clock_src(vb_clk_src); |
| } |
| |
| static void vbat_power_fail(void) |
| { |
| struct vbatr_regs *vbr = ((struct vbatr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 1)); |
| uint32_t pfrs = vbr->PFRS; |
| |
| LOG_INF("MEC172x VBAT Power-Fail-Reset-Status = 0x%x", pfrs); |
| |
| if (pfrs & MCHP_VBATR_PFRS_VBAT_RST_POS) { |
| LOG_INF("WARNING: VBAT POR. Clock control register settings" |
| " lost during power cycle"); |
| } |
| |
| /* clear VBAT powered status */ |
| vbr->PFRS = 0xffffffffU; |
| } |
| #endif |
| |
| static const struct gpio_regs * const gpio = |
| (struct gpio_regs *)(DT_REG_ADDR(DT_NODELABEL(gpio_000_036))); |
| static const struct device *clkdev = DEVICE_DT_GET(DT_NODELABEL(pcr)); |
| |
| struct sys_clk { |
| uint32_t id; |
| char *name; |
| }; |
| |
| static const struct sys_clk sys_clocks[] = { |
| { .id = MCHP_XEC_PCR_CLK_CORE, .name = "Core" }, |
| { .id = MCHP_XEC_PCR_CLK_CPU, .name = "CPU" }, |
| { .id = MCHP_XEC_PCR_CLK_BUS, .name = "Bus" }, |
| { .id = MCHP_XEC_PCR_CLK_PERIPH, .name = "Periph" }, |
| { .id = MCHP_XEC_PCR_CLK_PERIPH_FAST, .name = "Periph-fast" }, |
| { .id = MCHP_XEC_PCR_CLK_PERIPH_SLOW, .name = "Periph-slow" }, |
| }; |
| |
| int main(void) |
| { |
| int rc = 0; |
| uint32_t rate = 0U; |
| uint32_t r = 0U; |
| clock_control_subsys_t sys = NULL; |
| |
| LOG_INF("XEC Clock control driver sample"); |
| |
| if (!device_is_ready(clkdev)) { |
| LOG_ERR("XEC clock control driver is not ready!"); |
| return 0; |
| } |
| |
| vbat_power_fail(); |
| |
| LOG_INF("32KHZ_IN is function 1 of GPIO 0165"); |
| r = gpio->CTRL[MCHP_XEC_PINCTRL_REG_IDX(0165)]; |
| LOG_INF("XEC GPIO 0165 Control = 0x%x", r); |
| r = (r & MCHP_GPIO_CTRL_MUX_MASK) >> MCHP_GPIO_CTRL_MUX_POS; |
| LOG_INF("Pin function = %u", r); |
| vbat_clock_regs(); |
| pcr_clock_regs(); |
| |
| for (size_t i = 0; i < ARRAY_SIZE(sys_clocks); i++) { |
| LOG_INF("API get rate for %s", sys_clocks[i].name); |
| sys = (clock_control_subsys_t)sys_clocks[i].id; |
| rate = 0U; |
| rc = clock_control_get_rate(clkdev, sys, &rate); |
| if (rc) { |
| LOG_ERR("API error: %d", rc); |
| } else { |
| LOG_INF("rate = %u", rate); |
| } |
| } |
| return 0; |
| } |