1 /*
2 * Copyright (c) 2021, 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 #ifdef CONFIG_ETH_NXP_ENET
21 if ((uint32_t)sub_system == IMX_CCM_ENET_CLK) {
22 CLOCK_EnableClock(kCLOCK_Enet);
23 }
24 #endif
25 return 0;
26 }
27
mcux_ccm_off(const struct device * dev,clock_control_subsys_t sub_system)28 static int mcux_ccm_off(const struct device *dev,
29 clock_control_subsys_t sub_system)
30 {
31 return 0;
32 }
33
mcux_ccm_get_subsys_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)34 static int mcux_ccm_get_subsys_rate(const struct device *dev,
35 clock_control_subsys_t sub_system,
36 uint32_t *rate)
37 {
38 uint32_t clock_name = (size_t) sub_system;
39 uint32_t clock_root, peripheral, instance;
40
41 peripheral = (clock_name & IMX_CCM_PERIPHERAL_MASK);
42 instance = (clock_name & IMX_CCM_INSTANCE_MASK);
43 switch (peripheral) {
44 #ifdef CONFIG_I2C_MCUX_LPI2C
45 case IMX_CCM_LPI2C1_CLK:
46 clock_root = kCLOCK_Root_Lpi2c1 + instance;
47 break;
48 #endif
49
50 #ifdef CONFIG_SPI_MCUX_LPSPI
51 case IMX_CCM_LPSPI1_CLK:
52 clock_root = kCLOCK_Root_Lpspi1 + instance;
53 break;
54 #endif
55
56 #ifdef CONFIG_UART_MCUX_LPUART
57 case IMX_CCM_LPUART1_CLK:
58 case IMX_CCM_LPUART2_CLK:
59 clock_root = kCLOCK_Root_Lpuart1 + instance;
60 break;
61 #endif
62
63 #if CONFIG_IMX_USDHC
64 case IMX_CCM_USDHC1_CLK:
65 case IMX_CCM_USDHC2_CLK:
66 clock_root = kCLOCK_Root_Usdhc1 + instance;
67 break;
68 #endif
69
70 #ifdef CONFIG_DMA_MCUX_EDMA
71 case IMX_CCM_EDMA_CLK:
72 clock_root = kCLOCK_Root_Bus;
73 break;
74 case IMX_CCM_EDMA_LPSR_CLK:
75 clock_root = kCLOCK_Root_Bus_Lpsr;
76 break;
77 #endif
78
79 #ifdef CONFIG_PWM_MCUX
80 case IMX_CCM_PWM_CLK:
81 clock_root = kCLOCK_Root_Bus;
82 break;
83 #endif
84
85 #ifdef CONFIG_CAN_MCUX_FLEXCAN
86 case IMX_CCM_CAN1_CLK:
87 clock_root = kCLOCK_Root_Can1 + instance;
88 break;
89 #endif
90
91 #ifdef CONFIG_COUNTER_MCUX_GPT
92 case IMX_CCM_GPT_CLK:
93 clock_root = kCLOCK_Root_Gpt1 + instance;
94 break;
95 #endif
96
97 #ifdef CONFIG_I2S_MCUX_SAI
98 case IMX_CCM_SAI1_CLK:
99 clock_root = kCLOCK_Root_Sai1;
100 break;
101 case IMX_CCM_SAI2_CLK:
102 clock_root = kCLOCK_Root_Sai2;
103 break;
104 case IMX_CCM_SAI3_CLK:
105 clock_root = kCLOCK_Root_Sai3;
106 break;
107 case IMX_CCM_SAI4_CLK:
108 clock_root = kCLOCK_Root_Sai4;
109 break;
110 #endif
111
112 #ifdef CONFIG_ETH_NXP_ENET
113 case IMX_CCM_ENET_CLK:
114 clock_root = kCLOCK_Root_Bus;
115 break;
116 #endif
117
118 #if defined(CONFIG_SOC_MIMX93_A55) && defined(CONFIG_DAI_NXP_SAI)
119 case IMX_CCM_SAI1_CLK:
120 case IMX_CCM_SAI2_CLK:
121 case IMX_CCM_SAI3_CLK:
122 clock_root = kCLOCK_Root_Sai1 + instance;
123 uint32_t mux = CLOCK_GetRootClockMux(clock_root);
124 uint32_t divider = CLOCK_GetRootClockDiv(clock_root);
125
126 /* assumption: SAI's SRC is AUDIO_PLL */
127 if (mux != 1) {
128 return -EINVAL;
129 }
130
131 /* assumption: AUDIO_PLL's frequency is 393216000 Hz */
132 *rate = 393216000 / divider;
133
134 return 0;
135 #endif
136 #ifdef CONFIG_MEMC_MCUX_FLEXSPI
137 case IMX_CCM_FLEXSPI_CLK:
138 clock_root = kCLOCK_Root_Flexspi1;
139 break;
140 case IMX_CCM_FLEXSPI2_CLK:
141 clock_root = kCLOCK_Root_Flexspi2;
142 break;
143 #endif
144 default:
145 return -EINVAL;
146 }
147 #ifdef CONFIG_SOC_MIMX93_A55
148 *rate = CLOCK_GetIpFreq(clock_root);
149 #else
150 *rate = CLOCK_GetRootClockFreq(clock_root);
151 #endif
152 return 0;
153 }
154
155 /*
156 * Since this function is used to reclock the FlexSPI when running in
157 * XIP, it must be located in RAM when MEMC driver is enabled.
158 */
159 #ifdef CONFIG_MEMC_MCUX_FLEXSPI
160 #define CCM_SET_FUNC_ATTR __ramfunc
161 #else
162 #define CCM_SET_FUNC_ATTR
163 #endif
164
mcux_ccm_set_subsys_rate(const struct device * dev,clock_control_subsys_t subsys,clock_control_subsys_rate_t rate)165 static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev,
166 clock_control_subsys_t subsys,
167 clock_control_subsys_rate_t rate)
168 {
169 uint32_t clock_name = (uintptr_t)subsys;
170 uint32_t clock_rate = (uintptr_t)rate;
171
172 switch (clock_name) {
173 case IMX_CCM_FLEXSPI_CLK:
174 __fallthrough;
175 case IMX_CCM_FLEXSPI2_CLK:
176 #if defined(CONFIG_SOC_SERIES_IMX_RT11XX) && defined(CONFIG_MEMC_MCUX_FLEXSPI)
177 /* The SOC is using the FlexSPI for XIP. Therefore,
178 * the FlexSPI itself must be managed within the function,
179 * which is SOC specific.
180 */
181 return flexspi_clock_set_freq(clock_name, clock_rate);
182 #endif
183 default:
184 /* Silence unused variable warning */
185 ARG_UNUSED(clock_rate);
186 return -ENOTSUP;
187 }
188 }
189
190 static const struct clock_control_driver_api mcux_ccm_driver_api = {
191 .on = mcux_ccm_on,
192 .off = mcux_ccm_off,
193 .get_rate = mcux_ccm_get_subsys_rate,
194 .set_rate = mcux_ccm_set_subsys_rate,
195 };
196
197 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1,
198 CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
199 &mcux_ccm_driver_api);
200