1 /*
2  * Copyright 2021,2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_imx_ccm_rev2
8 #include <errno.h>
9 #include <zephyr/drivers/clock_control.h>
10 #include <zephyr/dt-bindings/clock/imx_ccm_rev2.h>
11 #include <fsl_clock.h>
12 
13 #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(clock_control);
16 
mcux_ccm_on(const struct device * dev,clock_control_subsys_t sub_system)17 static int mcux_ccm_on(const struct device *dev,
18 				  clock_control_subsys_t sub_system)
19 {
20 	uint32_t clock_name = (uintptr_t)sub_system;
21 	uint32_t peripheral, instance;
22 
23 	peripheral = (clock_name & IMX_CCM_PERIPHERAL_MASK);
24 	instance = (clock_name & IMX_CCM_INSTANCE_MASK);
25 	switch (peripheral) {
26 #ifdef CONFIG_ETH_NXP_ENET
27 
28 #ifdef CONFIG_SOC_MIMX9352
29 #define ENET1G_CLOCK	kCLOCK_Enet1
30 #else
31 #define ENET_CLOCK	kCLOCK_Enet
32 #define ENET1G_CLOCK	kCLOCK_Enet_1g
33 #endif
34 #ifdef ENET_CLOCK
35 	case IMX_CCM_ENET_CLK:
36 		CLOCK_EnableClock(ENET_CLOCK);
37 		return 0;
38 #endif
39 	case IMX_CCM_ENET1G_CLK:
40 		CLOCK_EnableClock(ENET1G_CLOCK);
41 		return 0;
42 #endif
43 	default:
44 		(void)instance;
45 		return 0;
46 	}
47 }
48 
mcux_ccm_off(const struct device * dev,clock_control_subsys_t sub_system)49 static int mcux_ccm_off(const struct device *dev,
50 				   clock_control_subsys_t sub_system)
51 {
52 	return 0;
53 }
54 
mcux_ccm_get_subsys_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)55 static int mcux_ccm_get_subsys_rate(const struct device *dev,
56 					clock_control_subsys_t sub_system,
57 					uint32_t *rate)
58 {
59 	uint32_t clock_name = (size_t) sub_system;
60 	uint32_t clock_root, peripheral, instance;
61 
62 	peripheral = (clock_name & IMX_CCM_PERIPHERAL_MASK);
63 	instance = (clock_name & IMX_CCM_INSTANCE_MASK);
64 	switch (peripheral) {
65 #ifdef CONFIG_I2C_MCUX_LPI2C
66 #if defined(CONFIG_SOC_SERIES_IMXRT118X)
67 	case IMX_CCM_LPI2C0102_CLK:
68 		clock_root = kCLOCK_Root_Lpi2c0102 + instance;
69 		break;
70 #else
71 	case IMX_CCM_LPI2C1_CLK:
72 		clock_root = kCLOCK_Root_Lpi2c1 + instance;
73 		break;
74 #endif
75 #endif
76 
77 #ifdef CONFIG_I3C_MCUX
78 	case IMX_CCM_I3C1_CLK:
79 	case IMX_CCM_I3C2_CLK:
80 		clock_root = kCLOCK_Root_I3c1 + instance;
81 		break;
82 #endif
83 
84 #ifdef CONFIG_SPI_MCUX_LPSPI
85 	case IMX_CCM_LPSPI1_CLK:
86 		clock_root = kCLOCK_Root_Lpspi1 + instance;
87 		break;
88 #endif
89 
90 #ifdef CONFIG_UART_MCUX_LPUART
91 #if defined(CONFIG_SOC_SERIES_IMXRT118X)
92 	case IMX_CCM_LPUART0102_CLK:
93 	case IMX_CCM_LPUART0304_CLK:
94 		clock_root = kCLOCK_Root_Lpuart0102 + instance;
95 		break;
96 #else
97 	case IMX_CCM_LPUART1_CLK:
98 	case IMX_CCM_LPUART2_CLK:
99 		clock_root = kCLOCK_Root_Lpuart1 + instance;
100 		break;
101 #endif
102 #endif
103 
104 #if CONFIG_IMX_USDHC
105 	case IMX_CCM_USDHC1_CLK:
106 	case IMX_CCM_USDHC2_CLK:
107 		clock_root = kCLOCK_Root_Usdhc1 + instance;
108 		break;
109 #endif
110 
111 #ifdef CONFIG_DMA_MCUX_EDMA
112 	case IMX_CCM_EDMA_CLK:
113 		clock_root = kCLOCK_Root_Bus;
114 		break;
115 	case IMX_CCM_EDMA_LPSR_CLK:
116 		clock_root = kCLOCK_Root_Bus_Lpsr;
117 		break;
118 #endif
119 
120 #ifdef CONFIG_PWM_MCUX
121 #if defined(CONFIG_SOC_SERIES_IMXRT118X)
122 	case IMX_CCM_PWM_CLK:
123 		clock_root = kCLOCK_Root_Bus_Aon;
124 		break;
125 #else
126 	case IMX_CCM_PWM_CLK:
127 		clock_root = kCLOCK_Root_Bus;
128 		break;
129 #endif /* CONFIG_SOC_SERIES_IMXRT118X */
130 #endif /* CONFIG_PWM_MCUX */
131 
132 #ifdef CONFIG_CAN_MCUX_FLEXCAN
133 	case IMX_CCM_CAN1_CLK:
134 		clock_root = kCLOCK_Root_Can1 + instance;
135 		break;
136 #endif
137 
138 #ifdef CONFIG_COUNTER_MCUX_GPT
139 	case IMX_CCM_GPT_CLK:
140 		clock_root = kCLOCK_Root_Gpt1 + instance;
141 		break;
142 #endif
143 
144 #ifdef CONFIG_I2S_MCUX_SAI
145 	case IMX_CCM_SAI1_CLK:
146 		clock_root =  kCLOCK_Root_Sai1;
147 		break;
148 	case IMX_CCM_SAI2_CLK:
149 		clock_root =  kCLOCK_Root_Sai2;
150 		break;
151 	case IMX_CCM_SAI3_CLK:
152 		clock_root =  kCLOCK_Root_Sai3;
153 		break;
154 	case IMX_CCM_SAI4_CLK:
155 		clock_root =  kCLOCK_Root_Sai4;
156 		break;
157 #endif
158 
159 #ifdef CONFIG_ETH_NXP_ENET
160 	case IMX_CCM_ENET_CLK:
161 	case IMX_CCM_ENET1G_CLK:
162 #ifdef CONFIG_SOC_MIMX9352
163 		clock_root = kCLOCK_Root_WakeupAxi;
164 #else
165 		clock_root = kCLOCK_Root_Bus;
166 #endif
167 		break;
168 #endif
169 
170 #if defined(CONFIG_SOC_MIMX9352) && defined(CONFIG_DAI_NXP_SAI)
171 	case IMX_CCM_SAI1_CLK:
172 	case IMX_CCM_SAI2_CLK:
173 	case IMX_CCM_SAI3_CLK:
174 		clock_root = kCLOCK_Root_Sai1 + instance;
175 		uint32_t mux = CLOCK_GetRootClockMux(clock_root);
176 		uint32_t divider = CLOCK_GetRootClockDiv(clock_root);
177 
178 		/* assumption: SAI's SRC is AUDIO_PLL */
179 		if (mux != 1) {
180 			return -EINVAL;
181 		}
182 
183 		/* assumption: AUDIO_PLL's frequency is 393216000 Hz */
184 		*rate = 393216000 / divider;
185 
186 		return 0;
187 #endif
188 #if defined(CONFIG_COUNTER_MCUX_TPM) || defined(CONFIG_PWM_MCUX_TPM)
189 #if defined(CONFIG_SOC_SERIES_IMXRT118X)
190 	case IMX_CCM_TPM_CLK:
191 		switch (instance) {
192 		case 0:
193 			clock_root = kCLOCK_Root_Bus_Aon;
194 			break;
195 		case 1:
196 			clock_root = kCLOCK_Root_Tpm2;
197 			break;
198 		case 2:
199 			clock_root = kCLOCK_Root_Bus_Wakeup;
200 			break;
201 		default:
202 			clock_root = (kCLOCK_Root_Tpm4 + instance - 3);
203 		}
204 		break;
205 #else
206 	case IMX_CCM_TPM_CLK:
207 		clock_root = kCLOCK_Root_Tpm1 + instance;
208 		break;
209 #endif
210 #endif
211 
212 #ifdef CONFIG_MCUX_FLEXIO
213 	case IMX_CCM_FLEXIO1_CLK:
214 		clock_root = kCLOCK_Root_Flexio1;
215 		break;
216 	case IMX_CCM_FLEXIO2_CLK:
217 		clock_root = kCLOCK_Root_Flexio2;
218 		break;
219 #endif
220 
221 #if defined(CONFIG_PWM_MCUX_QTMR) || defined(CONFIG_COUNTER_MCUX_QTMR)
222 #if defined(CONFIG_SOC_SERIES_IMXRT118X)
223 	case IMX_CCM_QTMR_CLK:
224 		clock_root = kCLOCK_Root_Bus_Aon;
225 		break;
226 #else
227 	case IMX_CCM_QTMR1_CLK:
228 	case IMX_CCM_QTMR2_CLK:
229 	case IMX_CCM_QTMR3_CLK:
230 	case IMX_CCM_QTMR4_CLK:
231 		clock_root = kCLOCK_Root_Bus;
232 		break;
233 #endif /* CONFIG_SOC_SERIES_IMXRT118X */
234 #endif /* CONFIG_PWM_MCUX_QTMR || CONFIG_COUNTER_MCUX_QTMR */
235 
236 #ifdef CONFIG_MEMC_MCUX_FLEXSPI
237 	case IMX_CCM_FLEXSPI_CLK:
238 	case IMX_CCM_FLEXSPI2_CLK:
239 		clock_root = kCLOCK_Root_Flexspi1 + instance;
240 		break;
241 #endif
242 #ifdef CONFIG_COUNTER_NXP_PIT
243 	case IMX_CCM_PIT_CLK:
244 		clock_root = kCLOCK_Root_Bus + instance;
245 		break;
246 #endif
247 
248 #ifdef CONFIG_ADC_MCUX_LPADC
249 	case IMX_CCM_LPADC1_CLK:
250 		clock_root = kCLOCK_Root_Adc1 + instance;
251 		break;
252 #endif
253 
254 #if defined(CONFIG_ETH_NXP_IMX_NETC)
255 	case IMX_CCM_NETC_CLK:
256 		clock_root = kCLOCK_Root_Netc;
257 		break;
258 #endif
259 
260 #if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX)
261 	case IMX_CCM_MIPI_CSI2RX_ROOT_CLK:
262 		clock_root = kCLOCK_Root_Csi2;
263 		break;
264 	case IMX_CCM_MIPI_CSI2RX_ESC_CLK:
265 		clock_root = kCLOCK_Root_Csi2_Esc;
266 		break;
267 	case IMX_CCM_MIPI_CSI2RX_UI_CLK:
268 		clock_root = kCLOCK_Root_Csi2_Ui;
269 		break;
270 #endif
271 
272 	default:
273 		return -EINVAL;
274 	}
275 #ifdef CONFIG_SOC_MIMX9352
276 	*rate = CLOCK_GetIpFreq(clock_root);
277 #else
278 	*rate = CLOCK_GetRootClockFreq(clock_root);
279 #endif
280 	return 0;
281 }
282 
283 /*
284  * Since this function is used to reclock the FlexSPI when running in
285  * XIP, it must be located in RAM when MEMC driver is enabled.
286  */
287 #ifdef CONFIG_MEMC_MCUX_FLEXSPI
288 #define CCM_SET_FUNC_ATTR __ramfunc
289 #else
290 #define CCM_SET_FUNC_ATTR
291 #endif
292 
mcux_ccm_set_subsys_rate(const struct device * dev,clock_control_subsys_t subsys,clock_control_subsys_rate_t rate)293 static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev,
294 			clock_control_subsys_t subsys,
295 			clock_control_subsys_rate_t rate)
296 {
297 	uint32_t clock_name = (uintptr_t)subsys;
298 	uint32_t clock_rate = (uintptr_t)rate;
299 
300 	switch (clock_name) {
301 	case IMX_CCM_FLEXSPI_CLK:
302 		__fallthrough;
303 	case IMX_CCM_FLEXSPI2_CLK:
304 #if (defined(CONFIG_SOC_SERIES_IMXRT11XX) || defined(CONFIG_SOC_SERIES_IMXRT118X)) \
305 		&& defined(CONFIG_MEMC_MCUX_FLEXSPI)
306 		/* The SOC is using the FlexSPI for XIP. Therefore,
307 		 * the FlexSPI itself must be managed within the function,
308 		 * which is SOC specific.
309 		 */
310 		return flexspi_clock_set_freq(clock_name, clock_rate);
311 #endif
312 
313 #if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX)
314 	case IMX_CCM_MIPI_CSI2RX_ROOT_CLK:
315 		return mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2, clock_rate);
316 	case IMX_CCM_MIPI_CSI2RX_UI_CLK:
317 		return mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2_Ui, clock_rate);
318 	case IMX_CCM_MIPI_CSI2RX_ESC_CLK:
319 		return mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2_Esc, clock_rate);
320 #endif
321 
322 	default:
323 		/* Silence unused variable warning */
324 		ARG_UNUSED(clock_rate);
325 		return -ENOTSUP;
326 	}
327 }
328 
329 static DEVICE_API(clock_control, mcux_ccm_driver_api) = {
330 	.on = mcux_ccm_on,
331 	.off = mcux_ccm_off,
332 	.get_rate = mcux_ccm_get_subsys_rate,
333 	.set_rate = mcux_ccm_set_subsys_rate,
334 };
335 
336 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1,
337 		      CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
338 		      &mcux_ccm_driver_api);
339