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