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