1 /*
2 * Copyright 2017, 2024-2025 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_imx_ccm
8 #include <errno.h>
9 #include <zephyr/arch/cpu.h>
10 #include <zephyr/sys/util.h>
11 #include <zephyr/drivers/clock_control.h>
12 #include <zephyr/dt-bindings/clock/imx_ccm.h>
13 #include <fsl_clock.h>
14
15 #if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
16 #include <main/ipc.h>
17 #endif
18
19 #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(clock_control);
22
23 #if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
24 #define AUD_PLL_DIV_CLK0_LPCG UINT_TO_POINTER(0x59D20000)
25 static sc_ipc_t ipc_handle;
26 #endif
27
28 #ifdef CONFIG_SPI_NXP_LPSPI
29 static const clock_name_t lpspi_clocks[] = {
30 kCLOCK_Usb1PllPfd1Clk,
31 kCLOCK_Usb1PllPfd0Clk,
32 kCLOCK_SysPllClk,
33 kCLOCK_SysPllPfd2Clk,
34 };
35 #endif
36 #ifdef CONFIG_UART_MCUX_IUART
37 static const clock_root_control_t uart_clk_root[] = {
38 kCLOCK_RootUart1,
39 kCLOCK_RootUart2,
40 kCLOCK_RootUart3,
41 kCLOCK_RootUart4,
42 };
43
44 static const clock_ip_name_t uart_clocks[] = {
45 kCLOCK_Uart1,
46 kCLOCK_Uart2,
47 kCLOCK_Uart3,
48 kCLOCK_Uart4,
49 };
50 #endif
51
52 #ifdef CONFIG_UART_MCUX_LPUART
53
54 #ifdef CONFIG_SOC_MIMX8QM6_ADSP
55 static const clock_ip_name_t lpuart_clocks[] = {
56 kCLOCK_DMA_Lpuart0,
57 kCLOCK_DMA_Lpuart1,
58 kCLOCK_DMA_Lpuart2,
59 kCLOCK_DMA_Lpuart3,
60 kCLOCK_DMA_Lpuart4,
61 };
62
63 static const uint32_t lpuart_rate = MHZ(80);
64 #endif /* CONFIG_SOC_MIMX8QM6_ADSP */
65
66 #ifdef CONFIG_SOC_MIMX8QX6_ADSP
67 static const clock_ip_name_t lpuart_clocks[] = {
68 kCLOCK_DMA_Lpuart0,
69 kCLOCK_DMA_Lpuart1,
70 kCLOCK_DMA_Lpuart2,
71 kCLOCK_DMA_Lpuart3,
72 };
73
74 static const uint32_t lpuart_rate = MHZ(80);
75 #endif /* CONFIG_SOC_MIMX8QX6_ADSP */
76
77 #endif /* CONFIG_UART_MCUX_LPUART */
78
79 #ifdef CONFIG_DAI_NXP_SAI
80 #if defined(CONFIG_SOC_MIMX8QX6_ADSP) || defined(CONFIG_SOC_MIMX8QM6_ADSP)
81 static const clock_ip_name_t sai_clocks[] = {
82 kCLOCK_AUDIO_Sai1,
83 kCLOCK_AUDIO_Sai2,
84 kCLOCK_AUDIO_Sai3,
85 };
86 #endif
87 #endif /* CONFIG_DAI_NXP_SAI */
88
89 #ifdef CONFIG_DAI_NXP_ESAI
90 #if defined(CONFIG_SOC_MIMX8QX6_ADSP) || defined(CONFIG_SOC_MIMX8QM6_ADSP)
91 static const clock_ip_name_t esai_clocks[] = {
92 kCLOCK_AUDIO_Esai0,
93 kCLOCK_AUDIO_Esai1,
94 };
95 #endif
96 #endif /* CONFIG_DAI_NXP_ESAI */
97
98 #if defined(CONFIG_I2C_NXP_II2C)
99 static const clock_ip_name_t i2c_clk_root[] = {
100 kCLOCK_RootI2c1,
101 kCLOCK_RootI2c2,
102 kCLOCK_RootI2c3,
103 kCLOCK_RootI2c4,
104 #ifdef CONFIG_SOC_MIMX8ML8
105 kCLOCK_RootI2c5,
106 kCLOCK_RootI2c6,
107 #endif
108 };
109 #endif
110
111 #if defined(CONFIG_CAN_MCUX_FLEXCAN) && defined(CONFIG_SOC_MIMX8ML8)
112 static const clock_ip_name_t flexcan_clk_root[] = {
113 kCLOCK_RootFlexCan1,
114 kCLOCK_RootFlexCan2,
115 };
116 #endif
117
mcux_ccm_on(const struct device * dev,clock_control_subsys_t sub_system)118 static int mcux_ccm_on(const struct device *dev,
119 clock_control_subsys_t sub_system)
120 {
121 uint32_t clock_name = (uintptr_t)sub_system;
122 uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
123
124 switch (clock_name) {
125 #ifdef CONFIG_UART_MCUX_IUART
126 case IMX_CCM_UART1_CLK:
127 case IMX_CCM_UART2_CLK:
128 case IMX_CCM_UART3_CLK:
129 case IMX_CCM_UART4_CLK:
130 CLOCK_EnableClock(uart_clocks[instance]);
131 return 0;
132 #endif
133
134 #if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX8QM6_ADSP)
135 case IMX_CCM_LPUART1_CLK:
136 case IMX_CCM_LPUART2_CLK:
137 case IMX_CCM_LPUART3_CLK:
138 case IMX_CCM_LPUART4_CLK:
139 case IMX_CCM_LPUART5_CLK:
140 CLOCK_EnableClock(lpuart_clocks[instance]);
141 return 0;
142 #endif
143
144 #if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX8QX6_ADSP)
145 case IMX_CCM_LPUART1_CLK:
146 case IMX_CCM_LPUART2_CLK:
147 case IMX_CCM_LPUART3_CLK:
148 case IMX_CCM_LPUART4_CLK:
149 CLOCK_EnableClock(lpuart_clocks[instance]);
150 return 0;
151 #endif
152
153 #ifdef CONFIG_DAI_NXP_SAI
154 #if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
155 case IMX_CCM_SAI1_CLK:
156 case IMX_CCM_SAI2_CLK:
157 case IMX_CCM_SAI3_CLK:
158 CLOCK_EnableClock(sai_clocks[instance]);
159 return 0;
160 #endif
161 #endif /* CONFIG_DAI_NXP_SAI */
162
163 #ifdef CONFIG_DAI_NXP_ESAI
164 #if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
165 case IMX_CCM_ESAI0_CLK:
166 case IMX_CCM_ESAI1_CLK:
167 CLOCK_EnableClock(esai_clocks[instance]);
168 return 0;
169 #endif
170 #endif /* CONFIG_DAI_NXP_ESAI */
171
172 #if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
173 case IMX_CCM_AUD_PLL_DIV_CLK0:
174 /* ungate PLL parent */
175 sc_pm_clock_enable(ipc_handle, SC_R_AUDIO_PLL_0,
176 SC_PM_CLK_MISC0, true, false);
177
178 /* ungate the clock itself */
179 CLOCK_SetLpcgGate(AUD_PLL_DIV_CLK0_LPCG, true, false, 0xa);
180
181 return 0;
182 #endif
183
184 #if defined(CONFIG_ETH_NXP_ENET)
185 #ifdef CONFIG_SOC_SERIES_IMX8M
186 #define ENET_CLOCK kCLOCK_Enet1
187 #else
188 #define ENET_CLOCK kCLOCK_Enet
189 #endif
190 case IMX_CCM_ENET_CLK:
191 CLOCK_EnableClock(ENET_CLOCK);
192 return 0;
193 #endif
194 default:
195 (void)instance;
196 return 0;
197 }
198 }
199
mcux_ccm_off(const struct device * dev,clock_control_subsys_t sub_system)200 static int mcux_ccm_off(const struct device *dev,
201 clock_control_subsys_t sub_system)
202 {
203 uint32_t clock_name = (uintptr_t)sub_system;
204 uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
205
206 switch (clock_name) {
207 #ifdef CONFIG_UART_MCUX_IUART
208 case IMX_CCM_UART1_CLK:
209 case IMX_CCM_UART2_CLK:
210 case IMX_CCM_UART3_CLK:
211 case IMX_CCM_UART4_CLK:
212 CLOCK_DisableClock(uart_clocks[instance]);
213 return 0;
214 #endif
215
216 #ifdef CONFIG_DAI_NXP_SAI
217 #if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
218 case IMX_CCM_SAI1_CLK:
219 case IMX_CCM_SAI2_CLK:
220 case IMX_CCM_SAI3_CLK:
221 CLOCK_DisableClock(sai_clocks[instance]);
222 return 0;
223 #endif
224 #endif /* CONFIG_DAI_NXP_SAI */
225
226 #ifdef CONFIG_DAI_NXP_ESAI
227 #if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
228 case IMX_CCM_ESAI0_CLK:
229 case IMX_CCM_ESAI1_CLK:
230 CLOCK_DisableClock(esai_clocks[instance]);
231 return 0;
232 #endif
233 #endif /* CONFIG_DAI_NXP_ESAI */
234
235 #if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
236 case IMX_CCM_AUD_PLL_DIV_CLK0:
237 /* gate the clock itself */
238 CLOCK_SetLpcgGate(AUD_PLL_DIV_CLK0_LPCG, false, false, 0xa);
239
240 /* gate PLL parent */
241 sc_pm_clock_enable(ipc_handle, SC_R_AUDIO_PLL_0,
242 SC_PM_CLK_MISC0, false, false);
243
244 return 0;
245 #endif
246 default:
247 (void)instance;
248 return 0;
249 }
250 }
251
mcux_ccm_get_subsys_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)252 static int mcux_ccm_get_subsys_rate(const struct device *dev,
253 clock_control_subsys_t sub_system,
254 uint32_t *rate)
255 {
256 uint32_t clock_name = (uintptr_t)sub_system;
257
258 switch (clock_name) {
259
260 #ifdef CONFIG_I2C_MCUX_LPI2C
261 case IMX_CCM_LPI2C_CLK:
262 if (CLOCK_GetMux(kCLOCK_Lpi2cMux) == 0) {
263 *rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 8
264 / (CLOCK_GetDiv(kCLOCK_Lpi2cDiv) + 1);
265 } else {
266 *rate = CLOCK_GetOscFreq()
267 / (CLOCK_GetDiv(kCLOCK_Lpi2cDiv) + 1);
268 }
269
270 break;
271 #endif
272
273 #ifdef CONFIG_SPI_NXP_LPSPI
274 case IMX_CCM_LPSPI_CLK:
275 {
276 uint32_t lpspi_mux = CLOCK_GetMux(kCLOCK_LpspiMux);
277 clock_name_t lpspi_clock = lpspi_clocks[lpspi_mux];
278
279 *rate = CLOCK_GetFreq(lpspi_clock)
280 / (CLOCK_GetDiv(kCLOCK_LpspiDiv) + 1);
281 break;
282 }
283 #endif
284
285 #ifdef CONFIG_UART_MCUX_LPUART
286
287 #if defined(CONFIG_SOC_MIMX8QM6_ADSP)
288 case IMX_CCM_LPUART1_CLK:
289 case IMX_CCM_LPUART2_CLK:
290 case IMX_CCM_LPUART3_CLK:
291 case IMX_CCM_LPUART4_CLK:
292 case IMX_CCM_LPUART5_CLK:
293 uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
294
295 CLOCK_SetIpFreq(lpuart_clocks[instance], lpuart_rate);
296 *rate = CLOCK_GetIpFreq(lpuart_clocks[instance]);
297 break;
298
299 #elif defined(CONFIG_SOC_MIMX8QX6_ADSP)
300 case IMX_CCM_LPUART1_CLK:
301 case IMX_CCM_LPUART2_CLK:
302 case IMX_CCM_LPUART3_CLK:
303 case IMX_CCM_LPUART4_CLK:
304 uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
305
306 CLOCK_SetIpFreq(lpuart_clocks[instance], lpuart_rate);
307 *rate = CLOCK_GetIpFreq(lpuart_clocks[instance]);
308 break;
309
310 #else
311 case IMX_CCM_LPUART_CLK:
312 if (CLOCK_GetMux(kCLOCK_UartMux) == 0) {
313 *rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6
314 / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1);
315 } else {
316 *rate = CLOCK_GetOscFreq()
317 / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1);
318 }
319
320 break;
321 #endif
322 #endif
323
324 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usdhc1)) && CONFIG_IMX_USDHC
325 case IMX_CCM_USDHC1_CLK:
326 *rate = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0) /
327 (CLOCK_GetDiv(kCLOCK_Usdhc1Div) + 1U);
328 break;
329 #endif
330
331 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usdhc2)) && CONFIG_IMX_USDHC
332 case IMX_CCM_USDHC2_CLK:
333 *rate = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0) /
334 (CLOCK_GetDiv(kCLOCK_Usdhc2Div) + 1U);
335 break;
336 #endif
337
338 #ifdef CONFIG_DMA_MCUX_EDMA
339 case IMX_CCM_EDMA_CLK:
340 *rate = CLOCK_GetIpgFreq();
341 break;
342 #endif
343
344 #ifdef CONFIG_PWM_MCUX
345 case IMX_CCM_PWM_CLK:
346 *rate = CLOCK_GetIpgFreq();
347 break;
348 #endif
349
350 #ifdef CONFIG_ETH_NXP_ENET
351 case IMX_CCM_ENET_CLK:
352 #ifdef CONFIG_SOC_SERIES_IMX8M
353 *rate = CLOCK_GetFreq(kCLOCK_EnetIpgClk);
354 #else
355 *rate = CLOCK_GetIpgFreq();
356 #endif
357 #endif
358 break;
359
360 #ifdef CONFIG_PTP_CLOCK_NXP_ENET
361 case IMX_CCM_ENET_PLL:
362 #if defined(CONFIG_SOC_SERIES_IMXRT10XX)
363 *rate = CLOCK_GetPllFreq(kCLOCK_PllEnet25M);
364 #else
365 *rate = CLOCK_GetPllFreq(kCLOCK_PllEnet);
366 #endif
367 break;
368 #endif
369
370 #ifdef CONFIG_UART_MCUX_IUART
371 case IMX_CCM_UART1_CLK:
372 case IMX_CCM_UART2_CLK:
373 case IMX_CCM_UART3_CLK:
374 case IMX_CCM_UART4_CLK:
375 {
376 uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
377 clock_root_control_t clk_root = uart_clk_root[instance];
378 uint32_t uart_mux = CLOCK_GetRootMux(clk_root);
379
380 if (uart_mux == 0) {
381 *rate = MHZ(24);
382 } else if (uart_mux == 1) {
383 *rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
384 (CLOCK_GetRootPreDivider(clk_root)) /
385 (CLOCK_GetRootPostDivider(clk_root)) /
386 10;
387 }
388
389 } break;
390 #endif
391
392 #ifdef CONFIG_CAN_MCUX_FLEXCAN
393 #ifdef CONFIG_SOC_MIMX8ML8
394 case IMX_CCM_CAN1_CLK:
395 case IMX_CCM_CAN2_CLK:
396 {
397 uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
398 uint32_t can_mux = CLOCK_GetRootMux(flexcan_clk_root[instance]);
399
400 if (can_mux == 0) {
401 *rate = MHZ(24);
402 } else if (can_mux == 4) { /* SYSTEM_PLL1_CLK */
403 *rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
404 (CLOCK_GetRootPreDivider(flexcan_clk_root[instance])) /
405 (CLOCK_GetRootPostDivider(flexcan_clk_root[instance]));
406 }
407 } break;
408 #else
409 case IMX_CCM_CAN_CLK:
410 {
411 uint32_t can_mux = CLOCK_GetMux(kCLOCK_CanMux);
412
413 if (can_mux == 0) {
414 *rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 8
415 / (CLOCK_GetDiv(kCLOCK_CanDiv) + 1);
416 } else if (can_mux == 1) {
417 *rate = CLOCK_GetOscFreq()
418 / (CLOCK_GetDiv(kCLOCK_CanDiv) + 1);
419 } else {
420 *rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6
421 / (CLOCK_GetDiv(kCLOCK_CanDiv) + 1);
422 }
423 } break;
424 #endif
425 #endif
426
427 #ifdef CONFIG_COUNTER_MCUX_GPT
428 case IMX_CCM_GPT_CLK:
429 *rate = CLOCK_GetFreq(kCLOCK_PerClk);
430 break;
431 #ifdef CONFIG_SOC_SERIES_IMX8M
432 case IMX_CCM_GPT_IPG_CLK:
433 {
434 uint32_t mux = CLOCK_GetRootMux(kCLOCK_RootGpt1);
435
436 if (mux == 0) {
437 *rate = OSC24M_CLK_FREQ;
438 } else {
439 *rate = 0;
440 }
441 } break;
442 #endif
443 #endif
444
445 #ifdef CONFIG_COUNTER_MCUX_QTMR
446 case IMX_CCM_QTMR_CLK:
447 *rate = CLOCK_GetIpgFreq();
448 break;
449 #endif
450
451 #ifdef CONFIG_I2S_MCUX_SAI
452 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai1))
453 case IMX_CCM_SAI1_CLK:
454 *rate = CLOCK_GetFreq(kCLOCK_AudioPllClk)
455 / (CLOCK_GetDiv(kCLOCK_Sai1PreDiv) + 1)
456 / (CLOCK_GetDiv(kCLOCK_Sai1Div) + 1);
457 break;
458 #endif
459 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai2))
460 case IMX_CCM_SAI2_CLK:
461 *rate = CLOCK_GetFreq(kCLOCK_AudioPllClk)
462 / (CLOCK_GetDiv(kCLOCK_Sai2PreDiv) + 1)
463 / (CLOCK_GetDiv(kCLOCK_Sai2Div) + 1);
464 break;
465 #endif
466 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai3))
467 case IMX_CCM_SAI3_CLK:
468 *rate = CLOCK_GetFreq(kCLOCK_AudioPllClk)
469 / (CLOCK_GetDiv(kCLOCK_Sai3PreDiv) + 1)
470 / (CLOCK_GetDiv(kCLOCK_Sai3Div) + 1);
471 break;
472 #endif
473 #endif
474 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexspi))
475 case IMX_CCM_FLEXSPI_CLK:
476 *rate = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot);
477 break;
478 #endif
479 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexspi2))
480 case IMX_CCM_FLEXSPI2_CLK:
481 *rate = CLOCK_GetClockRootFreq(kCLOCK_Flexspi2ClkRoot);
482 break;
483 #endif
484 #ifdef CONFIG_COUNTER_NXP_PIT
485 case IMX_CCM_PIT_CLK:
486 *rate = CLOCK_GetFreq(kCLOCK_PerClk);
487 break;
488 #endif
489 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio1)) && CONFIG_MCUX_FLEXIO
490 case IMX_CCM_FLEXIO1_CLK:
491 {
492 uint32_t flexio_mux = CLOCK_GetMux(kCLOCK_Flexio1Mux);
493 uint32_t source_clk_freq = 0;
494
495 if (flexio_mux == 0) {
496 source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
497 } else if (flexio_mux == 1) {
498 source_clk_freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);
499 #ifdef PLL_VIDEO_OFFSET /* fsl_clock.h */
500 } else if (flexio_mux == 2) {
501 source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllVideo);
502 #endif
503 } else {
504 source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
505 }
506
507 *rate = source_clk_freq / (CLOCK_GetDiv(kCLOCK_Flexio1PreDiv) + 1)
508 / (CLOCK_GetDiv(kCLOCK_Flexio1Div) + 1);
509 } break;
510 #endif
511 #if (DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio2)) \
512 || DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio3))) && CONFIG_MCUX_FLEXIO
513 case IMX_CCM_FLEXIO2_3_CLK:
514 {
515 uint32_t flexio_mux = CLOCK_GetMux(kCLOCK_Flexio2Mux);
516 uint32_t source_clk_freq = 0;
517
518 if (flexio_mux == 0) {
519 source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
520 } else if (flexio_mux == 1) {
521 source_clk_freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);
522 #ifdef PLL_VIDEO_OFFSET /* fsl_clock.h */
523 } else if (flexio_mux == 2) {
524 source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllVideo);
525 #endif
526 } else {
527 source_clk_freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
528 }
529
530 *rate = source_clk_freq / (CLOCK_GetDiv(kCLOCK_Flexio2PreDiv) + 1)
531 / (CLOCK_GetDiv(kCLOCK_Flexio2Div) + 1);
532 } break;
533 #endif
534
535 #ifdef CONFIG_SPI_MCUX_ECSPI
536 case IMX_CCM_ECSPI1_CLK:
537 *rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
538 (CLOCK_GetRootPreDivider(kCLOCK_RootEcspi1)) /
539 (CLOCK_GetRootPostDivider(kCLOCK_RootEcspi1));
540 break;
541 case IMX_CCM_ECSPI2_CLK:
542 *rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
543 (CLOCK_GetRootPreDivider(kCLOCK_RootEcspi2)) /
544 (CLOCK_GetRootPostDivider(kCLOCK_RootEcspi2));
545 break;
546 case IMX_CCM_ECSPI3_CLK:
547 *rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
548 (CLOCK_GetRootPreDivider(kCLOCK_RootEcspi3)) /
549 (CLOCK_GetRootPostDivider(kCLOCK_RootEcspi3));
550 break;
551 #endif /* CONFIG_SPI_MCUX_ECSPI */
552
553 #if defined(CONFIG_I2C_NXP_II2C)
554 case IMX_CCM_I2C1_CLK:
555 case IMX_CCM_I2C2_CLK:
556 case IMX_CCM_I2C3_CLK:
557 case IMX_CCM_I2C4_CLK:
558 #ifdef CONFIG_SOC_MIMX8ML8
559 case IMX_CCM_I2C5_CLK:
560 case IMX_CCM_I2C6_CLK:
561 #endif
562 {
563 uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
564 uint32_t i2c_mux = CLOCK_GetRootMux(i2c_clk_root[instance]);
565
566 if (i2c_mux == 0) {
567 *rate = MHZ(24);
568 } else if (i2c_mux == 1) {
569 *rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
570 (CLOCK_GetRootPreDivider(i2c_clk_root[instance])) /
571 (CLOCK_GetRootPostDivider(i2c_clk_root[instance])) /
572 5; /* SYSTEM PLL1 DIV5 */
573 }
574
575 } break;
576 #endif
577 }
578
579 return 0;
580 }
581
582 /*
583 * Since this function is used to reclock the FlexSPI when running in
584 * XIP, it must be located in RAM when MEMC Flexspi driver is enabled.
585 */
586 #ifdef CONFIG_MEMC_MCUX_FLEXSPI
587 #define CCM_SET_FUNC_ATTR __ramfunc
588 #else
589 #define CCM_SET_FUNC_ATTR
590 #endif
591
mcux_ccm_set_subsys_rate(const struct device * dev,clock_control_subsys_t subsys,clock_control_subsys_rate_t rate)592 static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev,
593 clock_control_subsys_t subsys,
594 clock_control_subsys_rate_t rate)
595 {
596 uint32_t clock_name = (uintptr_t)subsys;
597 uint32_t clock_rate = (uintptr_t)rate;
598
599 switch (clock_name) {
600 case IMX_CCM_FLEXSPI_CLK:
601 __fallthrough;
602 case IMX_CCM_FLEXSPI2_CLK:
603 #if defined(CONFIG_SOC_SERIES_IMXRT10XX) && defined(CONFIG_MEMC_MCUX_FLEXSPI)
604 /* The SOC is using the FlexSPI for XIP. Therefore,
605 * the FlexSPI itself must be managed within the function,
606 * which is SOC specific.
607 */
608 return flexspi_clock_set_freq(clock_name, clock_rate);
609 #endif
610 default:
611 /* Silence unused variable warning */
612 ARG_UNUSED(clock_rate);
613 return -ENOTSUP;
614 }
615 }
616
617
618
619 static DEVICE_API(clock_control, mcux_ccm_driver_api) = {
620 .on = mcux_ccm_on,
621 .off = mcux_ccm_off,
622 .get_rate = mcux_ccm_get_subsys_rate,
623 .set_rate = mcux_ccm_set_subsys_rate,
624 };
625
mcux_ccm_init(const struct device * dev)626 static int mcux_ccm_init(const struct device *dev)
627 {
628 #if defined(CONFIG_SOC_MIMX8QM6_ADSP) || defined(CONFIG_SOC_MIMX8QX6_ADSP)
629 int ret;
630
631 ret = sc_ipc_open(&ipc_handle, DT_REG_ADDR(DT_NODELABEL(scu_mu)));
632 if (ret != SC_ERR_NONE) {
633 return -ENODEV;
634 }
635
636 CLOCK_Init(ipc_handle);
637 #endif
638 return 0;
639 }
640
641 DEVICE_DT_INST_DEFINE(0, mcux_ccm_init, NULL, NULL, NULL,
642 PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
643 &mcux_ccm_driver_api);
644