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