1 /*
2 * Copyright (c) 2022 Microchip Technology Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <errno.h>
7 #include <zephyr/device.h>
8 #include <soc.h>
9 #include <zephyr/drivers/clock_control.h>
10 #include <zephyr/drivers/clock_control/mchp_xec_clock_control.h>
11 #include <zephyr/dt-bindings/clock/mchp_xec_pcr.h>
12 #include <zephyr/dt-bindings/pinctrl/mchp-xec-pinctrl.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/sys/printk.h>
16 LOG_MODULE_REGISTER(clock32k, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
17
18
19 #ifdef CONFIG_SOC_SERIES_MEC15XX
pcr_clock_regs(void)20 static void pcr_clock_regs(void)
21 {
22 struct pcr_regs *pcr = ((struct pcr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 0));
23 uint32_t r = pcr->PWR_RST_STS;
24
25 LOG_INF("MEC152x PCR registers");
26
27 LOG_INF("PCR Power Reset Status register(bit[10] is 32K_ACTIVE) = 0x%x", r);
28
29 r = pcr->OSC_ID;
30 LOG_INF("PCR Oscillator ID register(bit[8]=PLL Lock) = 0x%x", r);
31
32 r = pcr->PROC_CLK_CTRL;
33 LOG_INF("PCR Processor Clock Control register = 0x%x", r);
34
35 r = pcr->SLOW_CLK_CTRL;
36 LOG_INF("PCR Slow Clock Control register = 0x%x", r);
37 }
38
vbat_clock_regs(void)39 static void vbat_clock_regs(void)
40 {
41 struct vbatr_regs *vbr = ((struct vbatr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 1));
42 uint32_t cken = vbr->CLK32_EN;
43
44 LOG_INF("MEC152x VBAT Clock registers");
45 LOG_INF("ClockEnable = 0x%08x", cken);
46 if (cken & BIT(2)) {
47 LOG_INF("32KHz clock source is XTAL");
48 if (cken & BIT(3)) {
49 LOG_INF("XTAL configured for single-ended using XTAL2 pin"
50 " (external 32KHz waveform)");
51 } else {
52 LOG_INF("XTAL configured for parallel resonant crystal circuit on"
53 " XTAL1 and XTAL2 pins");
54 }
55 } else {
56 LOG_INF("32KHz clock source is the Internal Silicon 32KHz OSC");
57 }
58 if (cken & BIT(1)) {
59 LOG_INF("32KHz clock domain uses the 32KHZ_IN pin(GPIO_0165 F1)");
60 } else {
61 LOG_INF("32KHz clock domain uses the 32KHz clock source");
62 }
63
64 LOG_INF("32KHz trim = 0x%08x", vbr->CKK32_TRIM);
65 }
66
vbat_power_fail(void)67 static void vbat_power_fail(void)
68 {
69 struct vbatr_regs *vbr = ((struct vbatr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 1));
70 uint32_t pfrs = vbr->PFRS;
71
72 LOG_INF("MEC152x VBAT Power-Fail-Reset-Status = 0x%x", pfrs);
73
74 if (pfrs & MCHP_VBATR_PFRS_VBAT_RST_POS) {
75 LOG_INF("WARNING: VBAT POR. Clock control register settings lost during"
76 " power cycle");
77 }
78
79 vbr->PFRS = 0xffffffffU;
80 }
81 #else
print_pll_clock_src(uint32_t pcr_clk_src)82 static void print_pll_clock_src(uint32_t pcr_clk_src)
83 {
84 uint32_t temp = pcr_clk_src & MCHP_PCR_VTR_32K_SRC_MASK;
85
86 if (temp == MCHP_PCR_VTR_32K_SRC_SILOSC) {
87 LOG_INF("PLL 32K clock source is Internal Silicon OSC(VTR)");
88 } else if (temp == MCHP_PCR_VTR_32K_SRC_XTAL) {
89 LOG_INF("PLL 32K clock source is XTAL input(VTR)");
90 } else if (temp == MCHP_PCR_VTR_32K_SRC_PIN) {
91 LOG_INF("PLL 32K clock source is 32KHZ_IN pin(VTR)");
92 } else {
93 LOG_INF("PLL 32K clock source is OFF. PLL disabled. Running on Ring OSC");
94 }
95 }
96
print_periph_clock_src(uint32_t vb_clk_src)97 static void print_periph_clock_src(uint32_t vb_clk_src)
98 {
99 uint32_t temp = (vb_clk_src & MCHP_VBATR_CS_PCS_MSK) >> MCHP_VBATR_CS_PCS_POS;
100
101 if (temp == MCHP_VBATR_CS_PCR_VTR_VBAT_SO_VAL) {
102 LOG_INF("Periph 32K clock source is InternalOSC(VTR) and InternalOSC(VBAT)");
103 } else if (temp == MCHP_VBATR_CS_PCS_VTR_VBAT_XTAL_VAL) {
104 LOG_INF("Periph 32K clock source is XTAL(VTR) and XTAL(VBAT)");
105 } else if (temp == MCHP_VBATR_CS_PCS_VTR_PIN_SO_VAL) {
106 LOG_INF("Periph 32K clock source is 32KHZ_PIN(VTR) and InternalOSC(VBAT)");
107 } else {
108 LOG_INF("Periph 32K clock source is 32KHZ_PIN fallback to XTAL when VTR is off");
109 }
110 }
111
pcr_clock_regs(void)112 static void pcr_clock_regs(void)
113 {
114 struct pcr_regs *pcr = ((struct pcr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 0));
115 uint32_t pcr_clk_src = pcr->CLK32K_SRC_VTR;
116 uint32_t r = pcr->PWR_RST_STS;
117
118 LOG_INF("MEC172x PCR registers");
119
120 print_pll_clock_src(pcr_clk_src);
121
122 LOG_INF("PCR Power Reset Status register(b[10] is 32K_ACTIVE) = 0x%x", r);
123
124 r = pcr->OSC_ID;
125 LOG_INF("PCR Oscillator ID register(bit[8]=PLL Lock) = 0x%x", r);
126
127 r = pcr->PROC_CLK_CTRL;
128 LOG_INF("PCR Processor Clock Control register = 0x%x", r);
129
130 r = pcr->SLOW_CLK_CTRL;
131 LOG_INF("PCR Slow Clock Control register = 0x%x", r);
132
133 r = pcr->CNT32K_PER;
134 LOG_INF("PCR 32KHz Clock Monitor Pulse High Count register = 0x%x", r);
135
136 r = pcr->CNT32K_PER_MIN;
137 LOG_INF("PCR 32KHz Clock Monitor Period Maximum Count register = 0x%x", r);
138
139 r = pcr->CNT32K_DV;
140 LOG_INF("PCR 32KHz Clock Monitor Duty Cycle Variation register = 0x%x", r);
141
142 r = pcr->CNT32K_DV_MAX;
143 LOG_INF("PCR 32KHz Clock Monitor Duty Cycle Variation Max register = 0x%x", r);
144
145 r = pcr->CNT32K_VALID;
146 LOG_INF("PCR 32KHz Clock Monitor Valid register = 0x%x", r);
147
148 r = pcr->CNT32K_VALID_MIN;
149 LOG_INF("PCR 32KHz Clock Monitor Valid Min register = 0x%x", r);
150
151 r = pcr->CNT32K_CTRL;
152 LOG_INF("PCR 32KHz Clock Monitor Control register = 0x%x", r);
153
154 r = pcr->CLK32K_MON_ISTS;
155 LOG_INF("PCR 32KHz Clock Monitor Control Status register = 0x%x", r);
156 }
157
vbat_clock_regs(void)158 static void vbat_clock_regs(void)
159 {
160 struct vbatr_regs *vbr = ((struct vbatr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 1));
161 uint32_t vb_clk_src = vbr->CLK32_SRC;
162
163 print_periph_clock_src(vb_clk_src);
164 }
165
vbat_power_fail(void)166 static void vbat_power_fail(void)
167 {
168 struct vbatr_regs *vbr = ((struct vbatr_regs *)DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 1));
169 uint32_t pfrs = vbr->PFRS;
170
171 LOG_INF("MEC172x VBAT Power-Fail-Reset-Status = 0x%x", pfrs);
172
173 if (pfrs & MCHP_VBATR_PFRS_VBAT_RST_POS) {
174 LOG_INF("WARNING: VBAT POR. Clock control register settings"
175 " lost during power cycle");
176 }
177
178 /* clear VBAT powered status */
179 vbr->PFRS = 0xffffffffU;
180 }
181 #endif
182
183 static const struct gpio_regs * const gpio =
184 (struct gpio_regs *)(DT_REG_ADDR(DT_NODELABEL(gpio_000_036)));
185 static const struct device *clkdev = DEVICE_DT_GET(DT_NODELABEL(pcr));
186
187 struct sys_clk {
188 uint32_t id;
189 char *name;
190 };
191
192 static const struct sys_clk sys_clocks[] = {
193 { .id = MCHP_XEC_PCR_CLK_CORE, .name = "Core" },
194 { .id = MCHP_XEC_PCR_CLK_CPU, .name = "CPU" },
195 { .id = MCHP_XEC_PCR_CLK_BUS, .name = "Bus" },
196 { .id = MCHP_XEC_PCR_CLK_PERIPH, .name = "Periph" },
197 { .id = MCHP_XEC_PCR_CLK_PERIPH_FAST, .name = "Periph-fast" },
198 { .id = MCHP_XEC_PCR_CLK_PERIPH_SLOW, .name = "Periph-slow" },
199 };
200
main(void)201 int main(void)
202 {
203 int rc = 0;
204 uint32_t rate = 0U;
205 uint32_t r = 0U;
206 clock_control_subsys_t sys = NULL;
207
208 LOG_INF("XEC Clock control driver sample");
209
210 if (!device_is_ready(clkdev)) {
211 LOG_ERR("XEC clock control driver is not ready!");
212 return 0;
213 }
214
215 vbat_power_fail();
216
217 LOG_INF("32KHZ_IN is function 1 of GPIO 0165");
218 r = gpio->CTRL[MCHP_XEC_PINCTRL_REG_IDX(0165)];
219 LOG_INF("XEC GPIO 0165 Control = 0x%x", r);
220 r = (r & MCHP_GPIO_CTRL_MUX_MASK) >> MCHP_GPIO_CTRL_MUX_POS;
221 LOG_INF("Pin function = %u", r);
222 vbat_clock_regs();
223 pcr_clock_regs();
224
225 for (size_t i = 0; i < ARRAY_SIZE(sys_clocks); i++) {
226 LOG_INF("API get rate for %s", sys_clocks[i].name);
227 sys = (clock_control_subsys_t)sys_clocks[i].id;
228 rate = 0U;
229 rc = clock_control_get_rate(clkdev, sys, &rate);
230 if (rc) {
231 LOG_ERR("API error: %d", rc);
232 } else {
233 LOG_INF("rate = %u", rate);
234 }
235 }
236 return 0;
237 }
238