1 /*
2  * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or
3  * an affiliate of Cypress Semiconductor Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @brief Clock control driver for Infineon CAT1 MCU family.
10  */
11 
12 #include <zephyr/drivers/clock_control.h>
13 #include <cyhal_clock.h>
14 #include <cyhal_utils.h>
15 #include <cyhal_clock_impl.h>
16 
17 #define GET_CLK_SOURCE_ORD(N)  DT_DEP_ORD(DT_CLOCKS_CTLR_BY_IDX(DT_NODELABEL(N), 0))
18 
19 /* Enumeration of enabled in device tree Clock, uses for indexing clock info table */
20 enum {
21 	INFINEON_CAT1_CLOCK_IMO,
22 
23 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux0), okay)
24 	INFINEON_CAT1_CLOCK_PATHMUX0,
25 #endif
26 
27 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux1), okay)
28 	INFINEON_CAT1_CLOCK_PATHMUX1,
29 #endif
30 
31 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux2), okay)
32 	INFINEON_CAT1_CLOCK_PATHMUX2,
33 #endif
34 
35 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux3), okay)
36 	INFINEON_CAT1_CLOCK_PATHMUX3,
37 #endif
38 
39 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux4), okay)
40 	INFINEON_CAT1_CLOCK_PATHMUX4,
41 #endif
42 
43 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf0), okay)
44 	INFINEON_CAT1_CLOCK_HF0,
45 #endif
46 
47 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf1), okay)
48 	INFINEON_CAT1_CLOCK_HF1,
49 #endif
50 
51 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf2), okay)
52 	INFINEON_CAT1_CLOCK_HF2,
53 #endif
54 
55 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf3), okay)
56 	INFINEON_CAT1_CLOCK_HF3,
57 #endif
58 
59 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf4), okay)
60 	INFINEON_CAT1_CLOCK_HF4,
61 #endif
62 
63 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_fast), okay)
64 	INFINEON_CAT1_CLOCK_FAST,
65 #endif
66 
67 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_slow), okay)
68 	INFINEON_CAT1_CLOCK_SLOW,
69 #endif
70 
71 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_peri), okay)
72 	INFINEON_CAT1_CLOCK_PERI,
73 #endif
74 
75 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pll0), okay)
76 	INFINEON_CAT1_CLOCK_PLL0,
77 #endif
78 
79 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pll1), okay)
80 	INFINEON_CAT1_CLOCK_PLL1,
81 #endif
82 
83 #if DT_NODE_HAS_STATUS(DT_NODELABEL(fll0), okay)
84 	INFINEON_CAT1_CLOCK_FLL0,
85 #endif
86 
87 	/* Count of enabled clock */
88 	INFINEON_CAT1_ENABLED_CLOCK_COUNT
89 }; /* infineon_cat1_clock_info_name_t */
90 
91 /* Clock info structure */
92 struct infineon_cat1_clock_info_t {
93 	cyhal_clock_t obj;      /* Hal Clock object */
94 	uint32_t dt_ord;        /* Device tree node's dependency ordinal */
95 };
96 
97 /* Lookup table which presents  clock objects (cyhal_clock_t) correspondence to ordinal
98  * number of device tree clock nodes.
99  */
100 static struct infineon_cat1_clock_info_t
101 	clock_info_table[INFINEON_CAT1_ENABLED_CLOCK_COUNT] = {
102 	/* We always have IMO */
103 	[INFINEON_CAT1_CLOCK_IMO] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(clk_imo)) },
104 
105 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux0), okay)
106 	[INFINEON_CAT1_CLOCK_PATHMUX0] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(path_mux0)) },
107 #endif
108 
109 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux1), okay)
110 	[INFINEON_CAT1_CLOCK_PATHMUX1] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(path_mux1)) },
111 #endif
112 
113 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux2), okay)
114 	[INFINEON_CAT1_CLOCK_PATHMUX2] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(path_mux2)) },
115 #endif
116 
117 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux3), okay)
118 	[INFINEON_CAT1_CLOCK_PATHMUX3] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(path_mux3)) },
119 #endif
120 
121 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux4), okay)
122 	[INFINEON_CAT1_CLOCK_PATHMUX4] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(path_mux4)) },
123 #endif
124 
125 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf0), okay)
126 	[INFINEON_CAT1_CLOCK_HF0] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(clk_hf0)) },
127 #endif
128 
129 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf1), okay)
130 	[INFINEON_CAT1_CLOCK_HF1] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(clk_hf1)) },
131 #endif
132 
133 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf2), okay)
134 	[INFINEON_CAT1_CLOCK_HF2] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(clk_hf2)) },
135 #endif
136 
137 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf3), okay)
138 	[INFINEON_CAT1_CLOCK_HF3] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(clk_hf3)) },
139 #endif
140 
141 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf4), okay)
142 	[INFINEON_CAT1_CLOCK_HF4] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(clk_hf4)) },
143 #endif
144 
145 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_fast), okay)
146 	[INFINEON_CAT1_CLOCK_FAST] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(clk_fast)) },
147 #endif
148 
149 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_slow), okay)
150 	[INFINEON_CAT1_CLOCK_SLOW] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(clk_slow)) },
151 #endif
152 
153 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_peri), okay)
154 	[INFINEON_CAT1_CLOCK_PERI] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(clk_peri)) },
155 #endif
156 
157 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pll0), okay)
158 	[INFINEON_CAT1_CLOCK_PLL0] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(pll0)) },
159 #endif
160 
161 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pll1), okay)
162 	[INFINEON_CAT1_CLOCK_PLL1] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(pll1)) },
163 #endif
164 
165 #if DT_NODE_HAS_STATUS(DT_NODELABEL(fll0), okay)
166 	[INFINEON_CAT1_CLOCK_FLL0] = { .dt_ord = DT_DEP_ORD(DT_NODELABEL(fll0)) },
167 #endif
168 };
169 
_configure_path_mux(cyhal_clock_t * clock_obj,cyhal_clock_t * clock_source_obj,const cyhal_clock_t * reserve_obj)170 static cy_rslt_t _configure_path_mux(cyhal_clock_t *clock_obj,
171 				     cyhal_clock_t *clock_source_obj,
172 				     const cyhal_clock_t *reserve_obj)
173 {
174 	cy_rslt_t rslt;
175 
176 	ARG_UNUSED(clock_source_obj);
177 
178 	rslt = cyhal_clock_reserve(clock_obj, reserve_obj);
179 
180 	if (rslt == CY_RSLT_SUCCESS) {
181 		rslt = cyhal_clock_set_source(clock_obj, clock_source_obj);
182 	}
183 
184 	return rslt;
185 }
186 
_configure_clk_hf(cyhal_clock_t * clock_obj,cyhal_clock_t * clock_source_obj,const cyhal_clock_t * reserve_obj,uint32_t clock_div)187 static cy_rslt_t _configure_clk_hf(cyhal_clock_t *clock_obj,
188 				   cyhal_clock_t *clock_source_obj,
189 				   const cyhal_clock_t *reserve_obj,
190 				   uint32_t clock_div)
191 {
192 	cy_rslt_t rslt;
193 
194 	rslt = cyhal_clock_reserve(clock_obj, reserve_obj);
195 
196 	if (rslt == CY_RSLT_SUCCESS) {
197 		rslt = cyhal_clock_set_source(clock_obj, clock_source_obj);
198 	}
199 
200 	if (rslt == CY_RSLT_SUCCESS) {
201 		rslt = cyhal_clock_set_divider(clock_obj, clock_div);
202 	}
203 
204 	if (rslt == CY_RSLT_SUCCESS) {
205 		rslt = cyhal_clock_set_enabled(clock_obj, true, true);
206 	}
207 
208 	return rslt;
209 }
210 
_configure_clk_frequency_and_enable(cyhal_clock_t * clock_obj,cyhal_clock_t * clock_source_obj,const cyhal_clock_t * reserve_obj,uint32_t frequency)211 static cy_rslt_t _configure_clk_frequency_and_enable(cyhal_clock_t *clock_obj,
212 						     cyhal_clock_t *clock_source_obj,
213 						     const cyhal_clock_t *reserve_obj,
214 						     uint32_t frequency)
215 {
216 	ARG_UNUSED(clock_source_obj);
217 	cy_rslt_t rslt;
218 
219 	rslt = cyhal_clock_reserve(clock_obj, reserve_obj);
220 
221 	if (rslt == CY_RSLT_SUCCESS) {
222 		rslt = cyhal_clock_set_frequency(clock_obj, frequency, NULL);
223 	}
224 
225 	if (rslt == CY_RSLT_SUCCESS) {
226 		rslt = cyhal_clock_set_enabled(clock_obj, true, true);
227 	}
228 
229 	return rslt;
230 }
231 
_get_hal_obj_from_ord(uint32_t dt_ord)232 static cyhal_clock_t *_get_hal_obj_from_ord(uint32_t dt_ord)
233 {
234 	cyhal_clock_t *ret_obj = NULL;
235 
236 	for (uint32_t i = 0u; i < INFINEON_CAT1_ENABLED_CLOCK_COUNT; i++) {
237 		if (clock_info_table[i].dt_ord == dt_ord) {
238 			ret_obj = &clock_info_table[i].obj;
239 			return ret_obj;
240 		}
241 	}
242 	return ret_obj;
243 }
244 
clock_control_infineon_cat1_init(const struct device * dev)245 static int clock_control_infineon_cat1_init(const struct device *dev)
246 {
247 	ARG_UNUSED(dev);
248 	cy_rslt_t rslt;
249 	cyhal_clock_t *clock_obj = NULL;
250 	cyhal_clock_t *clock_source_obj = NULL;
251 	uint32 frequency;
252 	uint32 clock_div;
253 
254 	/* Configure IMO */
255 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_imo), okay)
256 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_IMO].obj;
257 	if (cyhal_clock_get(clock_obj, &CYHAL_CLOCK_RSC_IMO)) {
258 		return -EIO;
259 	}
260 #else
261 	#error "IMO clock must be enabled"
262 #endif
263 
264 	/* Configure the PathMux[0] to source defined in tree device 'path_mux0' node */
265 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux0), okay)
266 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_PATHMUX0].obj;
267 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(path_mux0));
268 
269 	if (_configure_path_mux(clock_obj, clock_source_obj, &CYHAL_CLOCK_PATHMUX[0])) {
270 		return -EIO;
271 	}
272 #endif
273 
274 	/* Configure the PathMux[1] to source defined in tree device 'path_mux1' node */
275 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux1), okay)
276 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_PATHMUX1].obj;
277 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(path_mux1));
278 
279 	if (_configure_path_mux(clock_obj, clock_source_obj, &CYHAL_CLOCK_PATHMUX[1])) {
280 		return -EIO;
281 	}
282 #endif
283 
284 	/* Configure the PathMux[2] to source defined in tree device 'path_mux2' node */
285 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux2), okay)
286 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_PATHMUX2].obj;
287 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(path_mux2));
288 
289 	if (_configure_path_mux(clock_obj, clock_source_obj, &CYHAL_CLOCK_PATHMUX[2])) {
290 		return -EIO;
291 	}
292 #endif
293 
294 	/* Configure the PathMux[3] to source defined in tree device 'path_mux3' node */
295 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux3), okay)
296 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_PATHMUX3].obj;
297 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(path_mux3));
298 
299 	if (_configure_path_mux(clock_obj, clock_source_obj, &CYHAL_CLOCK_PATHMUX[3])) {
300 		return -EIO;
301 	}
302 #endif
303 
304 	/* Configure the PathMux[4] to source defined in tree device 'path_mux4' node */
305 #if DT_NODE_HAS_STATUS(DT_NODELABEL(path_mux4), okay)
306 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_PATHMUX4].obj;
307 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(path_mux4));
308 
309 	if (_configure_path_mux(clock_obj, clock_source_obj, &CYHAL_CLOCK_PATHMUX[4])) {
310 		return -EIO;
311 	}
312 #endif
313 
314 	/* Configure FLL0 */
315 #if DT_NODE_HAS_STATUS(DT_NODELABEL(fll0), okay)
316 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_FLL0].obj;
317 	frequency = DT_PROP(DT_NODELABEL(fll0), clock_frequency);
318 
319 	rslt = _configure_clk_frequency_and_enable(clock_obj, clock_source_obj,
320 						   &CYHAL_CLOCK_FLL, frequency);
321 	if (rslt) {
322 		return -EIO;
323 	}
324 #endif
325 
326 	/* Configure PLL0 */
327 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pll0), okay)
328 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_PLL0].obj;
329 	frequency = DT_PROP(DT_NODELABEL(pll0), clock_frequency);
330 
331 	rslt = _configure_clk_frequency_and_enable(clock_obj, clock_source_obj,
332 						   &CYHAL_CLOCK_PLL[0], frequency);
333 
334 	if (rslt) {
335 		return -EIO;
336 	}
337 #endif
338 
339 	/* Configure PLL1 */
340 #if DT_NODE_HAS_STATUS(DT_NODELABEL(pll1), okay)
341 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_PLL1].obj;
342 	frequency = DT_PROP(DT_NODELABEL(pll1), clock_frequency);
343 
344 	rslt = _configure_clk_frequency_and_enable(clock_obj, clock_source_obj,
345 						   &CYHAL_CLOCK_PLL[1], frequency);
346 	if (rslt) {
347 		return -EIO;
348 	}
349 #endif
350 
351 	/* Configure the HF[0] to source defined in tree device 'clk_hf0' node */
352 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf0), okay)
353 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_HF0].obj;
354 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(clk_hf0));
355 	clock_div = DT_PROP(DT_NODELABEL(clk_hf0), clock_div);
356 
357 	if (_configure_clk_hf(clock_obj, clock_source_obj, &CYHAL_CLOCK_HF[0], clock_div)) {
358 		return -EIO;
359 	}
360 #endif
361 
362 	/* Configure the HF[1] to source defined in tree device 'clk_hf1' node */
363 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf1), okay)
364 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_HF1].obj;
365 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(clk_hf1));
366 	clock_div = DT_PROP(DT_NODELABEL(clk_hf1), clock_div);
367 
368 	if (_configure_clk_hf(clock_obj, clock_source_obj, &CYHAL_CLOCK_HF[1], clock_div)) {
369 		return -EIO;
370 	}
371 #endif
372 
373 	/* Configure the HF[2] to source defined in tree device 'clk_hf2' node */
374 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf2), okay)
375 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_HF2].obj;
376 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(clk_hf2));
377 	clock_div = DT_PROP(DT_NODELABEL(clk_hf2), clock_div);
378 
379 	if (_configure_clk_hf(clock_obj, clock_source_obj, &CYHAL_CLOCK_HF[2], clock_div)) {
380 		return -EIO;
381 	}
382 #endif
383 
384 	/* Configure the HF[3] to source defined in tree device 'clk_hf3' node */
385 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf3), okay)
386 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_HF3].obj;
387 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(clk_hf3));
388 	clock_div = DT_PROP(DT_NODELABEL(clk_hf3), clock_div);
389 
390 	if (_configure_clk_hf(clock_obj, clock_source_obj, &CYHAL_CLOCK_HF[3], clock_div)) {
391 		return -EIO;
392 	}
393 #endif
394 
395 	/* Configure the HF[4] to source defined in tree device 'clk_hf4' node */
396 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_hf4), okay)
397 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_HF4].obj;
398 	clock_source_obj = _get_hal_obj_from_ord(GET_CLK_SOURCE_ORD(clk_hf4));
399 	clock_div = DT_PROP(DT_NODELABEL(clk_hf4), clock_div);
400 
401 	if (_configure_clk_hf(clock_obj, clock_source_obj, &CYHAL_CLOCK_HF[4], clock_div)) {
402 		return -EIO;
403 	}
404 #endif
405 
406 	/* Configure the clock fast to source defined in tree device 'clk_fast' node */
407 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_fast), okay)
408 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_FAST].obj;
409 	clock_div = DT_PROP(DT_NODELABEL(clk_fast), clock_div);
410 
411 	rslt = cyhal_clock_reserve(clock_obj, &CYHAL_CLOCK_FAST);
412 	if (rslt == CY_RSLT_SUCCESS) {
413 		rslt = cyhal_clock_set_divider(clock_obj, clock_div);
414 	}
415 	if (rslt) {
416 		return -EIO;
417 	}
418 #endif
419 
420 	/* Configure the clock peri to source defined in tree device 'clk_peri' node */
421 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_peri), okay)
422 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_PERI].obj;
423 	clock_div = DT_PROP(DT_NODELABEL(clk_peri), clock_div);
424 
425 	rslt = cyhal_clock_reserve(clock_obj, &CYHAL_CLOCK_PERI);
426 	if (rslt == CY_RSLT_SUCCESS) {
427 		rslt = cyhal_clock_set_divider(clock_obj, clock_div);
428 	}
429 	if (rslt) {
430 		return -EIO;
431 	}
432 #endif
433 
434 	/* Configure the clock slow to source defined in tree device 'clk_slow' node */
435 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_slow), okay)
436 	clock_obj = &clock_info_table[INFINEON_CAT1_CLOCK_SLOW].obj;
437 	clock_div = DT_PROP(DT_NODELABEL(clk_slow), clock_div);
438 
439 	rslt = cyhal_clock_reserve(clock_obj, &CYHAL_CLOCK_SLOW);
440 	if (rslt == CY_RSLT_SUCCESS) {
441 		rslt = cyhal_clock_set_divider(clock_obj, clock_div);
442 	}
443 	if (rslt) {
444 		return -EIO;
445 	}
446 #endif
447 
448 	return (int) rslt;
449 }
450 
clock_control_infineon_cat_on_off(const struct device * dev,clock_control_subsys_t sys)451 static int clock_control_infineon_cat_on_off(const struct device *dev,
452 					     clock_control_subsys_t sys)
453 {
454 	ARG_UNUSED(dev);
455 	ARG_UNUSED(sys);
456 
457 	/* On/off functionality are not supported */
458 	return -ENOSYS;
459 }
460 
461 static const struct clock_control_driver_api clock_control_infineon_cat1_api = {
462 	.on = clock_control_infineon_cat_on_off,
463 	.off = clock_control_infineon_cat_on_off
464 };
465 
466 DEVICE_DT_DEFINE(DT_NODELABEL(clk_imo),
467 		 &clock_control_infineon_cat1_init,
468 		 NULL,
469 		 NULL,
470 		 NULL,
471 		 PRE_KERNEL_1,
472 		 CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
473 		 &clock_control_infineon_cat1_api);
474