1 /*
2  * Copyright 2020-2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_lpc_syscon
8 #include <errno.h>
9 #include <zephyr/drivers/clock_control.h>
10 #include <zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h>
11 #include <soc.h>
12 #include <fsl_clock.h>
13 
14 #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(clock_control);
17 
mcux_lpc_syscon_clock_control_on(const struct device * dev,clock_control_subsys_t sub_system)18 static int mcux_lpc_syscon_clock_control_on(const struct device *dev,
19 			      clock_control_subsys_t sub_system)
20 {
21 #if defined(CONFIG_CAN_MCUX_MCAN)
22 	if ((uint32_t)sub_system == MCUX_MCAN_CLK) {
23 		CLOCK_EnableClock(kCLOCK_Mcan);
24 	}
25 #endif /* defined(CONFIG_CAN_MCUX_MCAN) */
26 #if defined(CONFIG_COUNTER_NXP_MRT)
27 	if ((uint32_t)sub_system == MCUX_MRT_CLK) {
28 #if defined(CONFIG_SOC_FAMILY_LPC) || defined(CONFIG_SOC_SERIES_RW6XX)
29 		CLOCK_EnableClock(kCLOCK_Mrt);
30 #elif defined(CONFIG_SOC_FAMILY_NXP_IMXRT)
31 		CLOCK_EnableClock(kCLOCK_Mrt0);
32 #endif
33 	}
34 #if defined(CONFIG_SOC_SERIES_RW6XX)
35 	if ((uint32_t)sub_system == MCUX_FREEMRT_CLK) {
36 		CLOCK_EnableClock(kCLOCK_FreeMrt);
37 	}
38 #endif
39 #endif /* defined(CONFIG_COUNTER_NXP_MRT) */
40 #if defined(CONFIG_MIPI_DBI_NXP_LCDIC)
41 	if ((uint32_t)sub_system == MCUX_LCDIC_CLK) {
42 		CLOCK_EnableClock(kCLOCK_Lcdic);
43 	}
44 #endif
45 
46 #if defined(CONFIG_PINCTRL_NXP_KINETIS)
47 	switch ((uint32_t)sub_system) {
48 	case MCUX_PORT0_CLK:
49 		CLOCK_EnableClock(kCLOCK_Port0);
50 		break;
51 	case MCUX_PORT1_CLK:
52 		CLOCK_EnableClock(kCLOCK_Port1);
53 		break;
54 	case MCUX_PORT2_CLK:
55 		CLOCK_EnableClock(kCLOCK_Port2);
56 		break;
57 	case MCUX_PORT3_CLK:
58 		CLOCK_EnableClock(kCLOCK_Port3);
59 		break;
60 	case MCUX_PORT4_CLK:
61 		CLOCK_EnableClock(kCLOCK_Port4);
62 		break;
63 	default:
64 		break;
65 	}
66 #endif /* defined(CONFIG_PINCTRL_NXP_KINETIS) */
67 
68 #ifdef CONFIG_ETH_NXP_ENET_QOS
69 	if ((uint32_t)sub_system == MCUX_ENET_QOS_CLK) {
70 		CLOCK_EnableClock(kCLOCK_Enet);
71 	}
72 #endif
73 
74 #if defined(CONFIG_CAN_MCUX_FLEXCAN)
75 	switch ((uint32_t)sub_system) {
76 	case MCUX_FLEXCAN0_CLK:
77 		CLOCK_EnableClock(kCLOCK_Flexcan0);
78 		break;
79 	case MCUX_FLEXCAN1_CLK:
80 		CLOCK_EnableClock(kCLOCK_Flexcan1);
81 		break;
82 	default:
83 		break;
84 	}
85 #endif /* defined(CONFIG_CAN_MCUX_MCAN) */
86 
87 #ifdef CONFIG_ETH_NXP_ENET
88 	if ((uint32_t)sub_system == MCUX_ENET_CLK) {
89 #ifdef CONFIG_SOC_SERIES_RW6XX
90 		CLOCK_EnableClock(kCLOCK_TddrMciEnetClk);
91 		CLOCK_EnableClock(kCLOCK_EnetIpg);
92 		CLOCK_EnableClock(kCLOCK_EnetIpgS);
93 #endif
94 	}
95 #endif
96 
97 	return 0;
98 }
99 
mcux_lpc_syscon_clock_control_off(const struct device * dev,clock_control_subsys_t sub_system)100 static int mcux_lpc_syscon_clock_control_off(const struct device *dev,
101 			       clock_control_subsys_t sub_system)
102 {
103 	return 0;
104 }
105 
mcux_lpc_syscon_clock_control_get_subsys_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)106 static int mcux_lpc_syscon_clock_control_get_subsys_rate(
107 					const struct device *dev,
108 				    clock_control_subsys_t sub_system,
109 				    uint32_t *rate)
110 {
111 	uint32_t clock_name = (uint32_t) sub_system;
112 
113 	switch (clock_name) {
114 
115 #if defined(CONFIG_I2C_MCUX_FLEXCOMM) || \
116 		defined(CONFIG_SPI_MCUX_FLEXCOMM) || \
117 		defined(CONFIG_UART_MCUX_FLEXCOMM)
118 	case MCUX_FLEXCOMM0_CLK:
119 		*rate = CLOCK_GetFlexCommClkFreq(0);
120 		break;
121 	case MCUX_FLEXCOMM1_CLK:
122 		*rate = CLOCK_GetFlexCommClkFreq(1);
123 		break;
124 	case MCUX_FLEXCOMM2_CLK:
125 		*rate = CLOCK_GetFlexCommClkFreq(2);
126 		break;
127 	case MCUX_FLEXCOMM3_CLK:
128 		*rate = CLOCK_GetFlexCommClkFreq(3);
129 		break;
130 	case MCUX_FLEXCOMM4_CLK:
131 		*rate = CLOCK_GetFlexCommClkFreq(4);
132 		break;
133 	case MCUX_FLEXCOMM5_CLK:
134 		*rate = CLOCK_GetFlexCommClkFreq(5);
135 		break;
136 	case MCUX_FLEXCOMM6_CLK:
137 		*rate = CLOCK_GetFlexCommClkFreq(6);
138 		break;
139 	case MCUX_FLEXCOMM7_CLK:
140 		*rate = CLOCK_GetFlexCommClkFreq(7);
141 		break;
142 	case MCUX_FLEXCOMM8_CLK:
143 		*rate = CLOCK_GetFlexCommClkFreq(8);
144 		break;
145 	case MCUX_FLEXCOMM9_CLK:
146 		*rate = CLOCK_GetFlexCommClkFreq(9);
147 		break;
148 	case MCUX_FLEXCOMM10_CLK:
149 		*rate = CLOCK_GetFlexCommClkFreq(10);
150 		break;
151 	case MCUX_FLEXCOMM11_CLK:
152 		*rate = CLOCK_GetFlexCommClkFreq(11);
153 		break;
154 	case MCUX_FLEXCOMM12_CLK:
155 		*rate = CLOCK_GetFlexCommClkFreq(12);
156 		break;
157 	case MCUX_FLEXCOMM13_CLK:
158 		*rate = CLOCK_GetFlexCommClkFreq(13);
159 		break;
160 	case MCUX_PMIC_I2C_CLK:
161 		*rate = CLOCK_GetFlexCommClkFreq(15);
162 		break;
163 	case MCUX_HS_SPI_CLK:
164 #if defined(SYSCON_HSLSPICLKSEL_SEL_MASK)
165 		*rate = CLOCK_GetHsLspiClkFreq();
166 #else
167 		*rate = CLOCK_GetFlexCommClkFreq(14);
168 #endif
169 		break;
170 	case MCUX_HS_SPI1_CLK:
171 		*rate = CLOCK_GetFlexCommClkFreq(16);
172 		break;
173 #elif defined(CONFIG_NXP_LP_FLEXCOMM)
174 	case MCUX_FLEXCOMM0_CLK:
175 		*rate = CLOCK_GetLPFlexCommClkFreq(0);
176 		break;
177 	case MCUX_FLEXCOMM1_CLK:
178 		*rate = CLOCK_GetLPFlexCommClkFreq(1);
179 		break;
180 	case MCUX_FLEXCOMM2_CLK:
181 		*rate = CLOCK_GetLPFlexCommClkFreq(2);
182 		break;
183 	case MCUX_FLEXCOMM3_CLK:
184 		*rate = CLOCK_GetLPFlexCommClkFreq(3);
185 		break;
186 	case MCUX_FLEXCOMM4_CLK:
187 		*rate = CLOCK_GetLPFlexCommClkFreq(4);
188 		break;
189 	case MCUX_FLEXCOMM5_CLK:
190 		*rate = CLOCK_GetLPFlexCommClkFreq(5);
191 		break;
192 	case MCUX_FLEXCOMM6_CLK:
193 		*rate = CLOCK_GetLPFlexCommClkFreq(6);
194 		break;
195 	case MCUX_FLEXCOMM7_CLK:
196 		*rate = CLOCK_GetLPFlexCommClkFreq(7);
197 		break;
198 	case MCUX_FLEXCOMM8_CLK:
199 		*rate = CLOCK_GetLPFlexCommClkFreq(8);
200 		break;
201 	case MCUX_FLEXCOMM9_CLK:
202 		*rate = CLOCK_GetLPFlexCommClkFreq(9);
203 		break;
204 
205 #endif
206 
207 #if (defined(FSL_FEATURE_SOC_USDHC_COUNT) && FSL_FEATURE_SOC_USDHC_COUNT)
208 
209 #if CONFIG_SOC_FAMILY_NXP_MCX
210 	case MCUX_USDHC1_CLK:
211 		*rate = CLOCK_GetUsdhcClkFreq();
212 		break;
213 #else
214 	case MCUX_USDHC1_CLK:
215 		*rate = CLOCK_GetSdioClkFreq(0);
216 		break;
217 	case MCUX_USDHC2_CLK:
218 		*rate = CLOCK_GetSdioClkFreq(1);
219 		break;
220 #endif
221 
222 #endif
223 
224 #if (defined(FSL_FEATURE_SOC_SDIF_COUNT) && \
225 	(FSL_FEATURE_SOC_SDIF_COUNT)) && \
226 	CONFIG_MCUX_SDIF
227 	case MCUX_SDIF_CLK:
228 		*rate = CLOCK_GetSdioClkFreq();
229 		break;
230 #endif
231 
232 #if defined(CONFIG_CAN_MCUX_MCAN)
233 	case MCUX_MCAN_CLK:
234 		*rate = CLOCK_GetMCanClkFreq();
235 		break;
236 #endif /* defined(CONFIG_CAN_MCUX_MCAN) */
237 
238 #if defined(CONFIG_COUNTER_MCUX_CTIMER) || defined(CONFIG_PWM_MCUX_CTIMER)
239 	case MCUX_CTIMER0_CLK:
240 		*rate = CLOCK_GetCTimerClkFreq(0);
241 		break;
242 	case MCUX_CTIMER1_CLK:
243 		*rate = CLOCK_GetCTimerClkFreq(1);
244 		break;
245 	case MCUX_CTIMER2_CLK:
246 		*rate = CLOCK_GetCTimerClkFreq(2);
247 		break;
248 	case MCUX_CTIMER3_CLK:
249 		*rate = CLOCK_GetCTimerClkFreq(3);
250 		break;
251 	case MCUX_CTIMER4_CLK:
252 		*rate = CLOCK_GetCTimerClkFreq(4);
253 		break;
254 #endif
255 
256 #if defined(CONFIG_COUNTER_NXP_MRT)
257 	case MCUX_MRT_CLK:
258 #if defined(CONFIG_SOC_SERIES_RW6XX)
259 	case MCUX_FREEMRT_CLK:
260 #endif /* RW */
261 #endif /* MRT */
262 #if defined(CONFIG_PWM_MCUX_SCTIMER)
263 	case MCUX_SCTIMER_CLK:
264 #endif
265 #ifdef CONFIG_SOC_SERIES_RW6XX
266 		/* RW6XX uses core clock for SCTimer, not bus clock */
267 		*rate = CLOCK_GetCoreSysClkFreq();
268 		break;
269 #else
270 	case MCUX_BUS_CLK:
271 		*rate = CLOCK_GetFreq(kCLOCK_BusClk);
272 		break;
273 #endif
274 
275 #if defined(CONFIG_I3C_MCUX)
276 	case MCUX_I3C_CLK:
277 		*rate = CLOCK_GetI3cClkFreq();
278 		break;
279 #endif
280 
281 #if defined(CONFIG_MIPI_DSI_MCUX_2L)
282 	case MCUX_MIPI_DSI_DPHY_CLK:
283 		*rate = CLOCK_GetMipiDphyClkFreq();
284 		break;
285 	case MCUX_MIPI_DSI_ESC_CLK:
286 		*rate = CLOCK_GetMipiDphyEscTxClkFreq();
287 		break;
288 	case MCUX_LCDIF_PIXEL_CLK:
289 		*rate = CLOCK_GetDcPixelClkFreq();
290 		break;
291 #endif
292 #if defined(CONFIG_AUDIO_DMIC_MCUX)
293 	case MCUX_DMIC_CLK:
294 		*rate = CLOCK_GetDmicClkFreq();
295 		break;
296 #endif
297 #if defined(CONFIG_MEMC_MCUX_FLEXSPI)
298 	case MCUX_FLEXSPI_CLK:
299 #if (FSL_FEATURE_SOC_FLEXSPI_COUNT == 1)
300 		*rate = CLOCK_GetFlexspiClkFreq();
301 #else
302 		*rate = CLOCK_GetFlexspiClkFreq(0);
303 #endif
304 		break;
305 #if (FSL_FEATURE_SOC_FLEXSPI_COUNT == 2)
306 	case MCUX_FLEXSPI2_CLK:
307 		*rate = CLOCK_GetFlexspiClkFreq(1);
308 		break;
309 #endif
310 #endif /* CONFIG_MEMC_MCUX_FLEXSPI */
311 
312 #ifdef CONFIG_ETH_NXP_ENET_QOS
313 	case MCUX_ENET_QOS_CLK:
314 		*rate = CLOCK_GetFreq(kCLOCK_BusClk);
315 		break;
316 #endif
317 
318 #ifdef CONFIG_ETH_NXP_ENET
319 	case MCUX_ENET_CLK:
320 #ifdef CONFIG_SOC_SERIES_RW6XX
321 		*rate = CLOCK_GetTddrMciEnetClkFreq();
322 #endif
323 		break;
324 #endif
325 
326 #if defined(CONFIG_MIPI_DBI_NXP_LCDIC)
327 	case MCUX_LCDIC_CLK:
328 		*rate = CLOCK_GetLcdClkFreq();
329 		break;
330 #endif
331 
332 #if defined(CONFIG_ADC_MCUX_LPADC)
333 	case MCUX_LPADC1_CLK:
334 #if (FSL_FEATURE_SOC_LPADC_COUNT == 1)
335 		*rate = CLOCK_GetAdcClkFreq();
336 #else
337 		*rate = CLOCK_GetAdcClkFreq(0);
338 #endif
339 		break;
340 #if (FSL_FEATURE_SOC_LPADC_COUNT == 2)
341 	case MCUX_LPADC2_CLK:
342 		*rate = CLOCK_GetAdcClkFreq(1);
343 		break;
344 #endif
345 #endif /* CONFIG_ADC_MCUX_LPADC */
346 
347 #if defined(CONFIG_CAN_MCUX_FLEXCAN)
348 	case MCUX_FLEXCAN0_CLK:
349 		*rate = CLOCK_GetFlexcanClkFreq(0);
350 		break;
351 	case MCUX_FLEXCAN1_CLK:
352 		*rate = CLOCK_GetFlexcanClkFreq(1);
353 		break;
354 #endif /* defined(CONFIG_CAN_MCUX_FLEXCAN) */
355 
356 #if defined(CONFIG_MCUX_FLEXIO)
357 	case MCUX_FLEXIO0_CLK:
358 		*rate = CLOCK_GetFlexioClkFreq();
359 		break;
360 #endif /* defined(CONFIG_MCUX_FLEXIO) */
361 	}
362 
363 	return 0;
364 }
365 
366 #if defined(CONFIG_MEMC)
367 /*
368  * Weak implemenetation of flexspi_clock_set_freq- SOC implementations are
369  * expected to override this
370  */
flexspi_clock_set_freq(uint32_t clock_name,uint32_t freq)371 __weak int flexspi_clock_set_freq(uint32_t clock_name, uint32_t freq)
372 {
373 	ARG_UNUSED(clock_name);
374 	ARG_UNUSED(freq);
375 	return -ENOTSUP;
376 }
377 #endif
378 
379 /*
380  * Since this function is used to reclock the FlexSPI when running in
381  * XIP, it must be located in RAM when MEMC driver is enabled.
382  */
383 #ifdef CONFIG_MEMC
384 #define SYSCON_SET_FUNC_ATTR __ramfunc
385 #else
386 #define SYSCON_SET_FUNC_ATTR
387 #endif
388 
389 static int SYSCON_SET_FUNC_ATTR
mcux_lpc_syscon_clock_control_set_subsys_rate(const struct device * dev,clock_control_subsys_t subsys,clock_control_subsys_rate_t rate)390 	mcux_lpc_syscon_clock_control_set_subsys_rate(const struct device *dev,
391 			clock_control_subsys_t subsys,
392 			clock_control_subsys_rate_t rate)
393 {
394 	uint32_t clock_name = (uintptr_t)subsys;
395 	uint32_t clock_rate = (uintptr_t)rate;
396 
397 	switch (clock_name) {
398 	case MCUX_FLEXSPI_CLK:
399 #if defined(CONFIG_MEMC)
400 		/* The SOC is using the FlexSPI for XIP. Therefore,
401 		 * the FlexSPI itself must be managed within the function,
402 		 * which is SOC specific.
403 		 */
404 		return flexspi_clock_set_freq(clock_name, clock_rate);
405 #endif
406 #if defined(CONFIG_MIPI_DBI_NXP_LCDIC)
407 	case MCUX_LCDIC_CLK:
408 		/* Set LCDIC clock div */
409 		uint32_t root_rate = (CLOCK_GetLcdClkFreq() *
410 			((CLKCTL0->LCDFCLKDIV & CLKCTL0_LCDFCLKDIV_DIV_MASK) + 1));
411 		CLOCK_SetClkDiv(kCLOCK_DivLcdClk, (root_rate / clock_rate));
412 		return 0;
413 #endif
414 	default:
415 		/* Silence unused variable warning */
416 		ARG_UNUSED(clock_rate);
417 		return -ENOTSUP;
418 	}
419 }
420 
421 static const struct clock_control_driver_api mcux_lpc_syscon_api = {
422 	.on = mcux_lpc_syscon_clock_control_on,
423 	.off = mcux_lpc_syscon_clock_control_off,
424 	.get_rate = mcux_lpc_syscon_clock_control_get_subsys_rate,
425 	.set_rate = mcux_lpc_syscon_clock_control_set_subsys_rate,
426 };
427 
428 #define LPC_CLOCK_INIT(n) \
429 	\
430 DEVICE_DT_INST_DEFINE(n, \
431 		    NULL, \
432 		    NULL, \
433 		    NULL, NULL, \
434 		    PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \
435 		    &mcux_lpc_syscon_api);
436 
437 DT_INST_FOREACH_STATUS_OKAY(LPC_CLOCK_INIT)
438