1 /*
2  * Copyright (c) 2017, 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/sys/util.h>
10 #include <zephyr/drivers/clock_control.h>
11 #include <zephyr/dt-bindings/clock/imx_ccm.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 
18 #ifdef CONFIG_SPI_MCUX_LPSPI
19 static const clock_name_t lpspi_clocks[] = {
20 	kCLOCK_Usb1PllPfd1Clk,
21 	kCLOCK_Usb1PllPfd0Clk,
22 	kCLOCK_SysPllClk,
23 	kCLOCK_SysPllPfd2Clk,
24 };
25 #endif
26 #ifdef CONFIG_UART_MCUX_IUART
27 static const clock_root_control_t uart_clk_root[] = {
28 	kCLOCK_RootUart1,
29 	kCLOCK_RootUart2,
30 	kCLOCK_RootUart3,
31 	kCLOCK_RootUart4,
32 };
33 
34 static const clock_ip_name_t uart_clocks[] = {
35 	kCLOCK_Uart1,
36 	kCLOCK_Uart2,
37 	kCLOCK_Uart3,
38 	kCLOCK_Uart4,
39 };
40 #endif
41 #if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX93_A55)
42 static const clock_root_t lpuart_clk_root[] = {
43 	kCLOCK_Root_Lpuart1,
44 	kCLOCK_Root_Lpuart2,
45 	kCLOCK_Root_Lpuart3,
46 	kCLOCK_Root_Lpuart4,
47 	kCLOCK_Root_Lpuart5,
48 	kCLOCK_Root_Lpuart6,
49 	kCLOCK_Root_Lpuart7,
50 	kCLOCK_Root_Lpuart8,
51 };
52 #endif
53 
mcux_ccm_on(const struct device * dev,clock_control_subsys_t sub_system)54 static int mcux_ccm_on(const struct device *dev,
55 			      clock_control_subsys_t sub_system)
56 {
57 	uint32_t clock_name = (uintptr_t)sub_system;
58 	uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
59 
60 	switch (clock_name) {
61 #ifdef CONFIG_UART_MCUX_IUART
62 	case IMX_CCM_UART1_CLK:
63 	case IMX_CCM_UART2_CLK:
64 	case IMX_CCM_UART3_CLK:
65 	case IMX_CCM_UART4_CLK:
66 		CLOCK_EnableClock(uart_clocks[instance]);
67 		return 0;
68 #endif
69 	default:
70 		(void)instance;
71 		return 0;
72 	}
73 }
74 
mcux_ccm_off(const struct device * dev,clock_control_subsys_t sub_system)75 static int mcux_ccm_off(const struct device *dev,
76 			       clock_control_subsys_t sub_system)
77 {
78 	uint32_t clock_name = (uintptr_t)sub_system;
79 	uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
80 
81 	switch (clock_name) {
82 #ifdef CONFIG_UART_MCUX_IUART
83 	case IMX_CCM_UART1_CLK:
84 	case IMX_CCM_UART2_CLK:
85 	case IMX_CCM_UART3_CLK:
86 	case IMX_CCM_UART4_CLK:
87 		CLOCK_DisableClock(uart_clocks[instance]);
88 		return 0;
89 #endif
90 	default:
91 		(void)instance;
92 		return 0;
93 	}
94 }
95 
mcux_ccm_get_subsys_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)96 static int mcux_ccm_get_subsys_rate(const struct device *dev,
97 				    clock_control_subsys_t sub_system,
98 				    uint32_t *rate)
99 {
100 	uint32_t clock_name = (uintptr_t)sub_system;
101 
102 	switch (clock_name) {
103 
104 #ifdef CONFIG_I2C_MCUX_LPI2C
105 	case IMX_CCM_LPI2C_CLK:
106 		if (CLOCK_GetMux(kCLOCK_Lpi2cMux) == 0) {
107 			*rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 8
108 				/ (CLOCK_GetDiv(kCLOCK_Lpi2cDiv) + 1);
109 		} else {
110 			*rate = CLOCK_GetOscFreq()
111 				/ (CLOCK_GetDiv(kCLOCK_Lpi2cDiv) + 1);
112 		}
113 
114 		break;
115 #endif
116 
117 #ifdef CONFIG_SPI_MCUX_LPSPI
118 	case IMX_CCM_LPSPI_CLK:
119 	{
120 		uint32_t lpspi_mux = CLOCK_GetMux(kCLOCK_LpspiMux);
121 		clock_name_t lpspi_clock = lpspi_clocks[lpspi_mux];
122 
123 		*rate = CLOCK_GetFreq(lpspi_clock)
124 			/ (CLOCK_GetDiv(kCLOCK_LpspiDiv) + 1);
125 		break;
126 	}
127 #endif
128 
129 #ifdef CONFIG_UART_MCUX_LPUART
130 #ifdef CONFIG_SOC_MIMX93_A55
131 	case IMX_CCM_LPUART1_CLK:
132 	case IMX_CCM_LPUART2_CLK:
133 	case IMX_CCM_LPUART3_CLK:
134 	case IMX_CCM_LPUART4_CLK:
135 	case IMX_CCM_LPUART5_CLK:
136 	case IMX_CCM_LPUART6_CLK:
137 	case IMX_CCM_LPUART7_CLK:
138 	case IMX_CCM_LPUART8_CLK:
139 	{
140 		uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
141 		clock_root_t clk_root = lpuart_clk_root[instance];
142 		uint32_t uart_mux = CLOCK_GetRootClockMux(clk_root);
143 		uint32_t divider = CLOCK_GetRootClockDiv(clk_root);
144 
145 		if (uart_mux == 0)
146 			*rate = MHZ(24) / divider;
147 		else
148 			LOG_ERR("LPUART Clock is not supported\r\n");
149 
150 	} break;
151 
152 #else
153 	case IMX_CCM_LPUART_CLK:
154 		if (CLOCK_GetMux(kCLOCK_UartMux) == 0) {
155 			*rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6
156 				/ (CLOCK_GetDiv(kCLOCK_UartDiv) + 1);
157 		} else {
158 			*rate = CLOCK_GetOscFreq()
159 				/ (CLOCK_GetDiv(kCLOCK_UartDiv) + 1);
160 		}
161 
162 		break;
163 #endif
164 #endif
165 
166 #if DT_NODE_HAS_STATUS(DT_NODELABEL(usdhc1), okay) && CONFIG_IMX_USDHC
167 	case IMX_CCM_USDHC1_CLK:
168 		*rate = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0) /
169 				(CLOCK_GetDiv(kCLOCK_Usdhc1Div) + 1U);
170 		break;
171 #endif
172 
173 #if DT_NODE_HAS_STATUS(DT_NODELABEL(usdhc2), okay) && CONFIG_IMX_USDHC
174 	case IMX_CCM_USDHC2_CLK:
175 		*rate = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0) /
176 				(CLOCK_GetDiv(kCLOCK_Usdhc2Div) + 1U);
177 		break;
178 #endif
179 
180 #ifdef CONFIG_DMA_MCUX_EDMA
181 	case IMX_CCM_EDMA_CLK:
182 		*rate = CLOCK_GetIpgFreq();
183 		break;
184 #endif
185 
186 #ifdef CONFIG_PWM_MCUX
187 	case IMX_CCM_PWM_CLK:
188 		*rate = CLOCK_GetIpgFreq();
189 		break;
190 #endif
191 
192 #ifdef CONFIG_UART_MCUX_IUART
193 	case IMX_CCM_UART1_CLK:
194 	case IMX_CCM_UART2_CLK:
195 	case IMX_CCM_UART3_CLK:
196 	case IMX_CCM_UART4_CLK:
197 	{
198 		uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK;
199 		clock_root_control_t clk_root = uart_clk_root[instance];
200 		uint32_t uart_mux = CLOCK_GetRootMux(clk_root);
201 
202 		if (uart_mux == 0) {
203 			*rate = MHZ(24);
204 		} else if (uart_mux == 1) {
205 			*rate = CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) /
206 				(CLOCK_GetRootPreDivider(clk_root)) /
207 				(CLOCK_GetRootPostDivider(clk_root)) /
208 				10;
209 		}
210 
211 	} break;
212 #endif
213 
214 #ifdef CONFIG_CAN_MCUX_FLEXCAN
215 	case IMX_CCM_CAN_CLK:
216 	{
217 		uint32_t can_mux = CLOCK_GetMux(kCLOCK_CanMux);
218 
219 		if (can_mux == 0) {
220 			*rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 8
221 				/ (CLOCK_GetDiv(kCLOCK_CanDiv) + 1);
222 		} else if  (can_mux == 1) {
223 			*rate = CLOCK_GetOscFreq()
224 				/ (CLOCK_GetDiv(kCLOCK_CanDiv) + 1);
225 		} else {
226 			*rate = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6
227 				/ (CLOCK_GetDiv(kCLOCK_CanDiv) + 1);
228 		}
229 	} break;
230 #endif
231 
232 #ifdef CONFIG_COUNTER_MCUX_GPT
233 	case IMX_CCM_GPT_CLK:
234 		*rate = CLOCK_GetFreq(kCLOCK_PerClk);
235 		break;
236 #endif
237 
238 #ifdef CONFIG_COUNTER_MCUX_QTMR
239 	case IMX_CCM_QTMR_CLK:
240 		*rate = CLOCK_GetIpgFreq();
241 		break;
242 #endif
243 
244 #ifdef CONFIG_I2S_MCUX_SAI
245 	case IMX_CCM_SAI1_CLK:
246 		*rate = CLOCK_GetFreq(kCLOCK_AudioPllClk)
247 				/ (CLOCK_GetDiv(kCLOCK_Sai1PreDiv) + 1)
248 				/ (CLOCK_GetDiv(kCLOCK_Sai1Div) + 1);
249 		break;
250 	case IMX_CCM_SAI2_CLK:
251 		*rate = CLOCK_GetFreq(kCLOCK_AudioPllClk)
252 				/ (CLOCK_GetDiv(kCLOCK_Sai2PreDiv) + 1)
253 				/ (CLOCK_GetDiv(kCLOCK_Sai2Div) + 1);
254 		break;
255 	case IMX_CCM_SAI3_CLK:
256 		*rate = CLOCK_GetFreq(kCLOCK_AudioPllClk)
257 				/ (CLOCK_GetDiv(kCLOCK_Sai3PreDiv) + 1)
258 				/ (CLOCK_GetDiv(kCLOCK_Sai3Div) + 1);
259 		break;
260 #endif
261 	}
262 
263 	return 0;
264 }
265 
266 static const struct clock_control_driver_api mcux_ccm_driver_api = {
267 	.on = mcux_ccm_on,
268 	.off = mcux_ccm_off,
269 	.get_rate = mcux_ccm_get_subsys_rate,
270 };
271 
272 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL,
273 		      PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
274 		      &mcux_ccm_driver_api);
275