clk: imx8qxp: extend to support getting I2C IPG clock
[oweals/u-boot.git] / drivers / clk / imx / clk-imx8qxp.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2018 NXP
4  * Peng Fan <peng.fan@nxp.com>
5  */
6
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <asm/arch/sci/sci.h>
11 #include <asm/arch/clock.h>
12 #include <dt-bindings/clock/imx8qxp-clock.h>
13 #include <dt-bindings/soc/imx_rsrc.h>
14 #include <misc.h>
15
16 #include "clk-imx8.h"
17
18 #if CONFIG_IS_ENABLED(CMD_CLK)
19 struct imx8_clks imx8_clk_names[] = {
20         { IMX8QXP_A35_DIV, "A35_DIV" },
21         { IMX8QXP_I2C0_CLK, "I2C0" },
22         { IMX8QXP_I2C1_CLK, "I2C1" },
23         { IMX8QXP_I2C2_CLK, "I2C2" },
24         { IMX8QXP_I2C3_CLK, "I2C3" },
25         { IMX8QXP_UART0_CLK, "UART0" },
26         { IMX8QXP_UART1_CLK, "UART1" },
27         { IMX8QXP_UART2_CLK, "UART2" },
28         { IMX8QXP_UART3_CLK, "UART3" },
29         { IMX8QXP_SDHC0_CLK, "SDHC0" },
30         { IMX8QXP_SDHC1_CLK, "SDHC1" },
31         { IMX8QXP_ENET0_AHB_CLK, "ENET0_AHB" },
32         { IMX8QXP_ENET0_IPG_CLK, "ENET0_IPG" },
33         { IMX8QXP_ENET0_REF_DIV, "ENET0_REF" },
34         { IMX8QXP_ENET0_PTP_CLK, "ENET0_PTP" },
35         { IMX8QXP_ENET1_AHB_CLK, "ENET1_AHB" },
36         { IMX8QXP_ENET1_IPG_CLK, "ENET1_IPG" },
37         { IMX8QXP_ENET1_REF_DIV, "ENET1_REF" },
38         { IMX8QXP_ENET1_PTP_CLK, "ENET1_PTP" },
39 };
40
41 int num_clks = ARRAY_SIZE(imx8_clk_names);
42 #endif
43
44 ulong imx8_clk_get_rate(struct clk *clk)
45 {
46         sc_pm_clk_t pm_clk;
47         ulong rate;
48         u16 resource;
49         int ret;
50
51         debug("%s(#%lu)\n", __func__, clk->id);
52
53         switch (clk->id) {
54         case IMX8QXP_A35_DIV:
55                 resource = SC_R_A35;
56                 pm_clk = SC_PM_CLK_CPU;
57                 break;
58         case IMX8QXP_I2C0_CLK:
59         case IMX8QXP_I2C0_IPG_CLK:
60                 resource = SC_R_I2C_0;
61                 pm_clk = SC_PM_CLK_PER;
62                 break;
63         case IMX8QXP_I2C1_CLK:
64         case IMX8QXP_I2C1_IPG_CLK:
65                 resource = SC_R_I2C_1;
66                 pm_clk = SC_PM_CLK_PER;
67                 break;
68         case IMX8QXP_I2C2_CLK:
69         case IMX8QXP_I2C2_IPG_CLK:
70                 resource = SC_R_I2C_2;
71                 pm_clk = SC_PM_CLK_PER;
72                 break;
73         case IMX8QXP_I2C3_CLK:
74         case IMX8QXP_I2C3_IPG_CLK:
75                 resource = SC_R_I2C_3;
76                 pm_clk = SC_PM_CLK_PER;
77                 break;
78         case IMX8QXP_SDHC0_IPG_CLK:
79         case IMX8QXP_SDHC0_CLK:
80         case IMX8QXP_SDHC0_DIV:
81                 resource = SC_R_SDHC_0;
82                 pm_clk = SC_PM_CLK_PER;
83                 break;
84         case IMX8QXP_SDHC1_IPG_CLK:
85         case IMX8QXP_SDHC1_CLK:
86         case IMX8QXP_SDHC1_DIV:
87                 resource = SC_R_SDHC_1;
88                 pm_clk = SC_PM_CLK_PER;
89                 break;
90         case IMX8QXP_UART0_IPG_CLK:
91         case IMX8QXP_UART0_CLK:
92                 resource = SC_R_UART_0;
93                 pm_clk = SC_PM_CLK_PER;
94                 break;
95         case IMX8QXP_UART1_CLK:
96                 resource = SC_R_UART_1;
97                 pm_clk = SC_PM_CLK_PER;
98                 break;
99         case IMX8QXP_UART2_CLK:
100                 resource = SC_R_UART_2;
101                 pm_clk = SC_PM_CLK_PER;
102                 break;
103         case IMX8QXP_UART3_CLK:
104                 resource = SC_R_UART_3;
105                 pm_clk = SC_PM_CLK_PER;
106                 break;
107         case IMX8QXP_ENET0_IPG_CLK:
108         case IMX8QXP_ENET0_AHB_CLK:
109         case IMX8QXP_ENET0_REF_DIV:
110         case IMX8QXP_ENET0_PTP_CLK:
111                 resource = SC_R_ENET_0;
112                 pm_clk = SC_PM_CLK_PER;
113                 break;
114         case IMX8QXP_ENET1_IPG_CLK:
115         case IMX8QXP_ENET1_AHB_CLK:
116         case IMX8QXP_ENET1_REF_DIV:
117         case IMX8QXP_ENET1_PTP_CLK:
118                 resource = SC_R_ENET_1;
119                 pm_clk = SC_PM_CLK_PER;
120                 break;
121         default:
122                 if (clk->id < IMX8QXP_UART0_IPG_CLK ||
123                     clk->id >= IMX8QXP_CLK_END) {
124                         printf("%s(Invalid clk ID #%lu)\n",
125                                __func__, clk->id);
126                         return -EINVAL;
127                 }
128                 return -ENOTSUPP;
129         };
130
131         ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
132                                    (sc_pm_clock_rate_t *)&rate);
133         if (ret) {
134                 printf("%s err %d\n", __func__, ret);
135                 return ret;
136         }
137
138         return rate;
139 }
140
141 ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
142 {
143         sc_pm_clk_t pm_clk;
144         u32 new_rate = rate;
145         u16 resource;
146         int ret;
147
148         debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
149
150         switch (clk->id) {
151         case IMX8QXP_I2C0_CLK:
152         case IMX8QXP_I2C0_IPG_CLK:
153                 resource = SC_R_I2C_0;
154                 pm_clk = SC_PM_CLK_PER;
155                 break;
156         case IMX8QXP_I2C1_CLK:
157         case IMX8QXP_I2C1_IPG_CLK:
158                 resource = SC_R_I2C_1;
159                 pm_clk = SC_PM_CLK_PER;
160                 break;
161         case IMX8QXP_I2C2_CLK:
162         case IMX8QXP_I2C2_IPG_CLK:
163                 resource = SC_R_I2C_2;
164                 pm_clk = SC_PM_CLK_PER;
165                 break;
166         case IMX8QXP_I2C3_CLK:
167         case IMX8QXP_I2C3_IPG_CLK:
168                 resource = SC_R_I2C_3;
169                 pm_clk = SC_PM_CLK_PER;
170                 break;
171         case IMX8QXP_UART0_CLK:
172                 resource = SC_R_UART_0;
173                 pm_clk = SC_PM_CLK_PER;
174                 break;
175         case IMX8QXP_UART1_CLK:
176                 resource = SC_R_UART_1;
177                 pm_clk = SC_PM_CLK_PER;
178                 break;
179         case IMX8QXP_UART2_CLK:
180                 resource = SC_R_UART_2;
181                 pm_clk = SC_PM_CLK_PER;
182                 break;
183         case IMX8QXP_UART3_CLK:
184                 resource = SC_R_UART_3;
185                 pm_clk = SC_PM_CLK_PER;
186                 break;
187         case IMX8QXP_SDHC0_IPG_CLK:
188         case IMX8QXP_SDHC0_CLK:
189         case IMX8QXP_SDHC0_DIV:
190                 resource = SC_R_SDHC_0;
191                 pm_clk = SC_PM_CLK_PER;
192                 break;
193         case IMX8QXP_SDHC1_SEL:
194         case IMX8QXP_SDHC0_SEL:
195                 return 0;
196         case IMX8QXP_SDHC1_IPG_CLK:
197         case IMX8QXP_SDHC1_CLK:
198         case IMX8QXP_SDHC1_DIV:
199                 resource = SC_R_SDHC_1;
200                 pm_clk = SC_PM_CLK_PER;
201                 break;
202         case IMX8QXP_ENET0_IPG_CLK:
203         case IMX8QXP_ENET0_AHB_CLK:
204         case IMX8QXP_ENET0_REF_DIV:
205         case IMX8QXP_ENET0_PTP_CLK:
206                 resource = SC_R_ENET_0;
207                 pm_clk = SC_PM_CLK_PER;
208                 break;
209         case IMX8QXP_ENET1_IPG_CLK:
210         case IMX8QXP_ENET1_AHB_CLK:
211         case IMX8QXP_ENET1_REF_DIV:
212         case IMX8QXP_ENET1_PTP_CLK:
213                 resource = SC_R_ENET_1;
214                 pm_clk = SC_PM_CLK_PER;
215                 break;
216         default:
217                 if (clk->id < IMX8QXP_UART0_IPG_CLK ||
218                     clk->id >= IMX8QXP_CLK_END) {
219                         printf("%s(Invalid clk ID #%lu)\n",
220                                __func__, clk->id);
221                         return -EINVAL;
222                 }
223                 return -ENOTSUPP;
224         };
225
226         ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
227         if (ret) {
228                 printf("%s err %d\n", __func__, ret);
229                 return ret;
230         }
231
232         return new_rate;
233 }
234
235 int __imx8_clk_enable(struct clk *clk, bool enable)
236 {
237         sc_pm_clk_t pm_clk;
238         u16 resource;
239         int ret;
240
241         debug("%s(#%lu)\n", __func__, clk->id);
242
243         switch (clk->id) {
244         case IMX8QXP_I2C0_CLK:
245         case IMX8QXP_I2C0_IPG_CLK:
246                 resource = SC_R_I2C_0;
247                 pm_clk = SC_PM_CLK_PER;
248                 break;
249         case IMX8QXP_I2C1_CLK:
250         case IMX8QXP_I2C1_IPG_CLK:
251                 resource = SC_R_I2C_1;
252                 pm_clk = SC_PM_CLK_PER;
253                 break;
254         case IMX8QXP_I2C2_CLK:
255         case IMX8QXP_I2C2_IPG_CLK:
256                 resource = SC_R_I2C_2;
257                 pm_clk = SC_PM_CLK_PER;
258                 break;
259         case IMX8QXP_I2C3_CLK:
260         case IMX8QXP_I2C3_IPG_CLK:
261                 resource = SC_R_I2C_3;
262                 pm_clk = SC_PM_CLK_PER;
263                 break;
264         case IMX8QXP_UART0_CLK:
265                 resource = SC_R_UART_0;
266                 pm_clk = SC_PM_CLK_PER;
267                 break;
268         case IMX8QXP_UART1_CLK:
269                 resource = SC_R_UART_1;
270                 pm_clk = SC_PM_CLK_PER;
271                 break;
272         case IMX8QXP_UART2_CLK:
273                 resource = SC_R_UART_2;
274                 pm_clk = SC_PM_CLK_PER;
275                 break;
276         case IMX8QXP_UART3_CLK:
277                 resource = SC_R_UART_3;
278                 pm_clk = SC_PM_CLK_PER;
279                 break;
280         case IMX8QXP_SDHC0_IPG_CLK:
281         case IMX8QXP_SDHC0_CLK:
282         case IMX8QXP_SDHC0_DIV:
283                 resource = SC_R_SDHC_0;
284                 pm_clk = SC_PM_CLK_PER;
285                 break;
286         case IMX8QXP_SDHC1_IPG_CLK:
287         case IMX8QXP_SDHC1_CLK:
288         case IMX8QXP_SDHC1_DIV:
289                 resource = SC_R_SDHC_1;
290                 pm_clk = SC_PM_CLK_PER;
291                 break;
292         case IMX8QXP_ENET0_IPG_CLK:
293         case IMX8QXP_ENET0_AHB_CLK:
294         case IMX8QXP_ENET0_REF_DIV:
295         case IMX8QXP_ENET0_PTP_CLK:
296                 resource = SC_R_ENET_0;
297                 pm_clk = SC_PM_CLK_PER;
298                 break;
299         case IMX8QXP_ENET1_IPG_CLK:
300         case IMX8QXP_ENET1_AHB_CLK:
301         case IMX8QXP_ENET1_REF_DIV:
302         case IMX8QXP_ENET1_PTP_CLK:
303                 resource = SC_R_ENET_1;
304                 pm_clk = SC_PM_CLK_PER;
305                 break;
306         default:
307                 if (clk->id < IMX8QXP_UART0_IPG_CLK ||
308                     clk->id >= IMX8QXP_CLK_END) {
309                         printf("%s(Invalid clk ID #%lu)\n",
310                                __func__, clk->id);
311                         return -EINVAL;
312                 }
313                 return -ENOTSUPP;
314         }
315
316         ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
317         if (ret) {
318                 printf("%s err %d\n", __func__, ret);
319                 return ret;
320         }
321
322         return 0;
323 }