1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Hisilicon Hi3559A clock driver |
4 | * |
5 | * Copyright (c) 2019-2020, Huawei Tech. Co., Ltd. |
6 | * |
7 | * Author: Dongjiu Geng <gengdongjiu@huawei.com> |
8 | */ |
9 | |
10 | #include <linux/clk-provider.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/slab.h> |
15 | |
16 | #include <dt-bindings/clock/hi3559av100-clock.h> |
17 | |
18 | #include "clk.h" |
19 | #include "crg.h" |
20 | #include "reset.h" |
21 | |
22 | #define CRG_BASE_ADDR 0x18020000 |
23 | #define PLL_MASK_WIDTH 24 |
24 | |
25 | struct hi3559av100_pll_clock { |
26 | u32 id; |
27 | const char *name; |
28 | const char *parent_name; |
29 | const u32 ctrl_reg1; |
30 | const u8 frac_shift; |
31 | const u8 frac_width; |
32 | const u8 postdiv1_shift; |
33 | const u8 postdiv1_width; |
34 | const u8 postdiv2_shift; |
35 | const u8 postdiv2_width; |
36 | const u32 ctrl_reg2; |
37 | const u8 fbdiv_shift; |
38 | const u8 fbdiv_width; |
39 | const u8 refdiv_shift; |
40 | const u8 refdiv_width; |
41 | }; |
42 | |
43 | struct hi3559av100_clk_pll { |
44 | struct clk_hw hw; |
45 | u32 id; |
46 | void __iomem *ctrl_reg1; |
47 | u8 frac_shift; |
48 | u8 frac_width; |
49 | u8 postdiv1_shift; |
50 | u8 postdiv1_width; |
51 | u8 postdiv2_shift; |
52 | u8 postdiv2_width; |
53 | void __iomem *ctrl_reg2; |
54 | u8 fbdiv_shift; |
55 | u8 fbdiv_width; |
56 | u8 refdiv_shift; |
57 | u8 refdiv_width; |
58 | }; |
59 | |
60 | /* soc clk config */ |
61 | static const struct hisi_fixed_rate_clock hi3559av100_fixed_rate_clks_crg[] = { |
62 | { HI3559AV100_FIXED_1188M, "1188m" , NULL, 0, 1188000000, }, |
63 | { HI3559AV100_FIXED_1000M, "1000m" , NULL, 0, 1000000000, }, |
64 | { HI3559AV100_FIXED_842M, "842m" , NULL, 0, 842000000, }, |
65 | { HI3559AV100_FIXED_792M, "792m" , NULL, 0, 792000000, }, |
66 | { HI3559AV100_FIXED_750M, "750m" , NULL, 0, 750000000, }, |
67 | { HI3559AV100_FIXED_710M, "710m" , NULL, 0, 710000000, }, |
68 | { HI3559AV100_FIXED_680M, "680m" , NULL, 0, 680000000, }, |
69 | { HI3559AV100_FIXED_667M, "667m" , NULL, 0, 667000000, }, |
70 | { HI3559AV100_FIXED_631M, "631m" , NULL, 0, 631000000, }, |
71 | { HI3559AV100_FIXED_600M, "600m" , NULL, 0, 600000000, }, |
72 | { HI3559AV100_FIXED_568M, "568m" , NULL, 0, 568000000, }, |
73 | { HI3559AV100_FIXED_500M, "500m" , NULL, 0, 500000000, }, |
74 | { HI3559AV100_FIXED_475M, "475m" , NULL, 0, 475000000, }, |
75 | { HI3559AV100_FIXED_428M, "428m" , NULL, 0, 428000000, }, |
76 | { HI3559AV100_FIXED_400M, "400m" , NULL, 0, 400000000, }, |
77 | { HI3559AV100_FIXED_396M, "396m" , NULL, 0, 396000000, }, |
78 | { HI3559AV100_FIXED_300M, "300m" , NULL, 0, 300000000, }, |
79 | { HI3559AV100_FIXED_250M, "250m" , NULL, 0, 250000000, }, |
80 | { HI3559AV100_FIXED_200M, "200m" , NULL, 0, 200000000, }, |
81 | { HI3559AV100_FIXED_198M, "198m" , NULL, 0, 198000000, }, |
82 | { HI3559AV100_FIXED_187p5M, "187p5m" , NULL, 0, 187500000, }, |
83 | { HI3559AV100_FIXED_150M, "150m" , NULL, 0, 150000000, }, |
84 | { HI3559AV100_FIXED_148p5M, "148p5m" , NULL, 0, 1485000000, }, |
85 | { HI3559AV100_FIXED_125M, "125m" , NULL, 0, 125000000, }, |
86 | { HI3559AV100_FIXED_107M, "107m" , NULL, 0, 107000000, }, |
87 | { HI3559AV100_FIXED_100M, "100m" , NULL, 0, 100000000, }, |
88 | { HI3559AV100_FIXED_99M, "99m" , NULL, 0, 99000000, }, |
89 | { HI3559AV100_FIXED_75M, "75m" , NULL, 0, 75000000, }, |
90 | { HI3559AV100_FIXED_74p25M, "74p25m" , NULL, 0, 74250000, }, |
91 | { HI3559AV100_FIXED_72M, "72m" , NULL, 0, 72000000, }, |
92 | { HI3559AV100_FIXED_60M, "60m" , NULL, 0, 60000000, }, |
93 | { HI3559AV100_FIXED_54M, "54m" , NULL, 0, 54000000, }, |
94 | { HI3559AV100_FIXED_50M, "50m" , NULL, 0, 50000000, }, |
95 | { HI3559AV100_FIXED_49p5M, "49p5m" , NULL, 0, 49500000, }, |
96 | { HI3559AV100_FIXED_37p125M, "37p125m" , NULL, 0, 37125000, }, |
97 | { HI3559AV100_FIXED_36M, "36m" , NULL, 0, 36000000, }, |
98 | { HI3559AV100_FIXED_32p4M, "32p4m" , NULL, 0, 32400000, }, |
99 | { HI3559AV100_FIXED_27M, "27m" , NULL, 0, 27000000, }, |
100 | { HI3559AV100_FIXED_25M, "25m" , NULL, 0, 25000000, }, |
101 | { HI3559AV100_FIXED_24M, "24m" , NULL, 0, 24000000, }, |
102 | { HI3559AV100_FIXED_12M, "12m" , NULL, 0, 12000000, }, |
103 | { HI3559AV100_FIXED_3M, "3m" , NULL, 0, 3000000, }, |
104 | { HI3559AV100_FIXED_1p6M, "1p6m" , NULL, 0, 1600000, }, |
105 | { HI3559AV100_FIXED_400K, "400k" , NULL, 0, 400000, }, |
106 | { HI3559AV100_FIXED_100K, "100k" , NULL, 0, 100000, }, |
107 | }; |
108 | |
109 | |
110 | static const char *fmc_mux_p[] = { |
111 | "24m" , "75m" , "125m" , "150m" , "200m" , "250m" , "300m" , "400m" |
112 | }; |
113 | |
114 | static const char *mmc_mux_p[] = { |
115 | "100k" , "25m" , "49p5m" , "99m" , "187p5m" , "150m" , "198m" , "400k" |
116 | }; |
117 | |
118 | static const char *sysapb_mux_p[] = { |
119 | "24m" , "50m" , |
120 | }; |
121 | |
122 | static const char *sysbus_mux_p[] = { |
123 | "24m" , "300m" |
124 | }; |
125 | |
126 | static const char *uart_mux_p[] = { "50m" , "24m" , "3m" }; |
127 | |
128 | static const char *a73_clksel_mux_p[] = { |
129 | "24m" , "apll" , "1000m" |
130 | }; |
131 | |
132 | static const u32 fmc_mux_table[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; |
133 | static const u32 mmc_mux_table[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; |
134 | static const u32 sysapb_mux_table[] = { 0, 1 }; |
135 | static const u32 sysbus_mux_table[] = { 0, 1 }; |
136 | static const u32 uart_mux_table[] = { 0, 1, 2 }; |
137 | static const u32 a73_clksel_mux_table[] = { 0, 1, 2 }; |
138 | |
139 | static struct hisi_mux_clock hi3559av100_mux_clks_crg[] = { |
140 | { |
141 | HI3559AV100_FMC_MUX, "fmc_mux" , fmc_mux_p, ARRAY_SIZE(fmc_mux_p), |
142 | CLK_SET_RATE_PARENT, 0x170, 2, 3, 0, fmc_mux_table, |
143 | }, |
144 | { |
145 | HI3559AV100_MMC0_MUX, "mmc0_mux" , mmc_mux_p, ARRAY_SIZE(mmc_mux_p), |
146 | CLK_SET_RATE_PARENT, 0x1a8, 24, 3, 0, mmc_mux_table, |
147 | }, |
148 | { |
149 | HI3559AV100_MMC1_MUX, "mmc1_mux" , mmc_mux_p, ARRAY_SIZE(mmc_mux_p), |
150 | CLK_SET_RATE_PARENT, 0x1ec, 24, 3, 0, mmc_mux_table, |
151 | }, |
152 | |
153 | { |
154 | HI3559AV100_MMC2_MUX, "mmc2_mux" , mmc_mux_p, ARRAY_SIZE(mmc_mux_p), |
155 | CLK_SET_RATE_PARENT, 0x214, 24, 3, 0, mmc_mux_table, |
156 | }, |
157 | |
158 | { |
159 | HI3559AV100_MMC3_MUX, "mmc3_mux" , mmc_mux_p, ARRAY_SIZE(mmc_mux_p), |
160 | CLK_SET_RATE_PARENT, 0x23c, 24, 3, 0, mmc_mux_table, |
161 | }, |
162 | |
163 | { |
164 | HI3559AV100_SYSAPB_MUX, "sysapb_mux" , sysapb_mux_p, ARRAY_SIZE(sysapb_mux_p), |
165 | CLK_SET_RATE_PARENT, 0xe8, 3, 1, 0, sysapb_mux_table |
166 | }, |
167 | |
168 | { |
169 | HI3559AV100_SYSBUS_MUX, "sysbus_mux" , sysbus_mux_p, ARRAY_SIZE(sysbus_mux_p), |
170 | CLK_SET_RATE_PARENT, 0xe8, 0, 1, 0, sysbus_mux_table |
171 | }, |
172 | |
173 | { |
174 | HI3559AV100_UART_MUX, "uart_mux" , uart_mux_p, ARRAY_SIZE(uart_mux_p), |
175 | CLK_SET_RATE_PARENT, 0x198, 28, 2, 0, uart_mux_table |
176 | }, |
177 | |
178 | { |
179 | HI3559AV100_A73_MUX, "a73_mux" , a73_clksel_mux_p, ARRAY_SIZE(a73_clksel_mux_p), |
180 | CLK_SET_RATE_PARENT, 0xe4, 0, 2, 0, a73_clksel_mux_table |
181 | }, |
182 | }; |
183 | |
184 | static struct hisi_gate_clock hi3559av100_gate_clks[] = { |
185 | { |
186 | HI3559AV100_FMC_CLK, "clk_fmc" , "fmc_mux" , |
187 | CLK_SET_RATE_PARENT, 0x170, 1, 0, |
188 | }, |
189 | { |
190 | HI3559AV100_MMC0_CLK, "clk_mmc0" , "mmc0_mux" , |
191 | CLK_SET_RATE_PARENT, 0x1a8, 28, 0, |
192 | }, |
193 | { |
194 | HI3559AV100_MMC1_CLK, "clk_mmc1" , "mmc1_mux" , |
195 | CLK_SET_RATE_PARENT, 0x1ec, 28, 0, |
196 | }, |
197 | { |
198 | HI3559AV100_MMC2_CLK, "clk_mmc2" , "mmc2_mux" , |
199 | CLK_SET_RATE_PARENT, 0x214, 28, 0, |
200 | }, |
201 | { |
202 | HI3559AV100_MMC3_CLK, "clk_mmc3" , "mmc3_mux" , |
203 | CLK_SET_RATE_PARENT, 0x23c, 28, 0, |
204 | }, |
205 | { |
206 | HI3559AV100_UART0_CLK, "clk_uart0" , "uart_mux" , |
207 | CLK_SET_RATE_PARENT, 0x198, 23, 0, |
208 | }, |
209 | { |
210 | HI3559AV100_UART1_CLK, "clk_uart1" , "uart_mux" , |
211 | CLK_SET_RATE_PARENT, 0x198, 24, 0, |
212 | }, |
213 | { |
214 | HI3559AV100_UART2_CLK, "clk_uart2" , "uart_mux" , |
215 | CLK_SET_RATE_PARENT, 0x198, 25, 0, |
216 | }, |
217 | { |
218 | HI3559AV100_UART3_CLK, "clk_uart3" , "uart_mux" , |
219 | CLK_SET_RATE_PARENT, 0x198, 26, 0, |
220 | }, |
221 | { |
222 | HI3559AV100_UART4_CLK, "clk_uart4" , "uart_mux" , |
223 | CLK_SET_RATE_PARENT, 0x198, 27, 0, |
224 | }, |
225 | { |
226 | HI3559AV100_ETH_CLK, "clk_eth" , NULL, |
227 | CLK_SET_RATE_PARENT, 0x0174, 1, 0, |
228 | }, |
229 | { |
230 | HI3559AV100_ETH_MACIF_CLK, "clk_eth_macif" , NULL, |
231 | CLK_SET_RATE_PARENT, 0x0174, 5, 0, |
232 | }, |
233 | { |
234 | HI3559AV100_ETH1_CLK, "clk_eth1" , NULL, |
235 | CLK_SET_RATE_PARENT, 0x0174, 3, 0, |
236 | }, |
237 | { |
238 | HI3559AV100_ETH1_MACIF_CLK, "clk_eth1_macif" , NULL, |
239 | CLK_SET_RATE_PARENT, 0x0174, 7, 0, |
240 | }, |
241 | { |
242 | HI3559AV100_I2C0_CLK, "clk_i2c0" , "50m" , |
243 | CLK_SET_RATE_PARENT, 0x01a0, 16, 0, |
244 | }, |
245 | { |
246 | HI3559AV100_I2C1_CLK, "clk_i2c1" , "50m" , |
247 | CLK_SET_RATE_PARENT, 0x01a0, 17, 0, |
248 | }, |
249 | { |
250 | HI3559AV100_I2C2_CLK, "clk_i2c2" , "50m" , |
251 | CLK_SET_RATE_PARENT, 0x01a0, 18, 0, |
252 | }, |
253 | { |
254 | HI3559AV100_I2C3_CLK, "clk_i2c3" , "50m" , |
255 | CLK_SET_RATE_PARENT, 0x01a0, 19, 0, |
256 | }, |
257 | { |
258 | HI3559AV100_I2C4_CLK, "clk_i2c4" , "50m" , |
259 | CLK_SET_RATE_PARENT, 0x01a0, 20, 0, |
260 | }, |
261 | { |
262 | HI3559AV100_I2C5_CLK, "clk_i2c5" , "50m" , |
263 | CLK_SET_RATE_PARENT, 0x01a0, 21, 0, |
264 | }, |
265 | { |
266 | HI3559AV100_I2C6_CLK, "clk_i2c6" , "50m" , |
267 | CLK_SET_RATE_PARENT, 0x01a0, 22, 0, |
268 | }, |
269 | { |
270 | HI3559AV100_I2C7_CLK, "clk_i2c7" , "50m" , |
271 | CLK_SET_RATE_PARENT, 0x01a0, 23, 0, |
272 | }, |
273 | { |
274 | HI3559AV100_I2C8_CLK, "clk_i2c8" , "50m" , |
275 | CLK_SET_RATE_PARENT, 0x01a0, 24, 0, |
276 | }, |
277 | { |
278 | HI3559AV100_I2C9_CLK, "clk_i2c9" , "50m" , |
279 | CLK_SET_RATE_PARENT, 0x01a0, 25, 0, |
280 | }, |
281 | { |
282 | HI3559AV100_I2C10_CLK, "clk_i2c10" , "50m" , |
283 | CLK_SET_RATE_PARENT, 0x01a0, 26, 0, |
284 | }, |
285 | { |
286 | HI3559AV100_I2C11_CLK, "clk_i2c11" , "50m" , |
287 | CLK_SET_RATE_PARENT, 0x01a0, 27, 0, |
288 | }, |
289 | { |
290 | HI3559AV100_SPI0_CLK, "clk_spi0" , "100m" , |
291 | CLK_SET_RATE_PARENT, 0x0198, 16, 0, |
292 | }, |
293 | { |
294 | HI3559AV100_SPI1_CLK, "clk_spi1" , "100m" , |
295 | CLK_SET_RATE_PARENT, 0x0198, 17, 0, |
296 | }, |
297 | { |
298 | HI3559AV100_SPI2_CLK, "clk_spi2" , "100m" , |
299 | CLK_SET_RATE_PARENT, 0x0198, 18, 0, |
300 | }, |
301 | { |
302 | HI3559AV100_SPI3_CLK, "clk_spi3" , "100m" , |
303 | CLK_SET_RATE_PARENT, 0x0198, 19, 0, |
304 | }, |
305 | { |
306 | HI3559AV100_SPI4_CLK, "clk_spi4" , "100m" , |
307 | CLK_SET_RATE_PARENT, 0x0198, 20, 0, |
308 | }, |
309 | { |
310 | HI3559AV100_SPI5_CLK, "clk_spi5" , "100m" , |
311 | CLK_SET_RATE_PARENT, 0x0198, 21, 0, |
312 | }, |
313 | { |
314 | HI3559AV100_SPI6_CLK, "clk_spi6" , "100m" , |
315 | CLK_SET_RATE_PARENT, 0x0198, 22, 0, |
316 | }, |
317 | { |
318 | HI3559AV100_EDMAC_AXICLK, "axi_clk_edmac" , NULL, |
319 | CLK_SET_RATE_PARENT, 0x16c, 6, 0, |
320 | }, |
321 | { |
322 | HI3559AV100_EDMAC_CLK, "clk_edmac" , NULL, |
323 | CLK_SET_RATE_PARENT, 0x16c, 5, 0, |
324 | }, |
325 | { |
326 | HI3559AV100_EDMAC1_AXICLK, "axi_clk_edmac1" , NULL, |
327 | CLK_SET_RATE_PARENT, 0x16c, 9, 0, |
328 | }, |
329 | { |
330 | HI3559AV100_EDMAC1_CLK, "clk_edmac1" , NULL, |
331 | CLK_SET_RATE_PARENT, 0x16c, 8, 0, |
332 | }, |
333 | { |
334 | HI3559AV100_VDMAC_CLK, "clk_vdmac" , NULL, |
335 | CLK_SET_RATE_PARENT, 0x14c, 5, 0, |
336 | }, |
337 | }; |
338 | |
339 | static struct hi3559av100_pll_clock hi3559av100_pll_clks[] = { |
340 | { |
341 | HI3559AV100_APLL_CLK, "apll" , NULL, 0x0, 0, 24, 24, 3, 28, 3, |
342 | 0x4, 0, 12, 12, 6 |
343 | }, |
344 | { |
345 | HI3559AV100_GPLL_CLK, "gpll" , NULL, 0x20, 0, 24, 24, 3, 28, 3, |
346 | 0x24, 0, 12, 12, 6 |
347 | }, |
348 | }; |
349 | |
350 | #define to_pll_clk(_hw) container_of(_hw, struct hi3559av100_clk_pll, hw) |
351 | static void hi3559av100_calc_pll(u32 *frac_val, u32 *postdiv1_val, |
352 | u32 *postdiv2_val, |
353 | u32 *fbdiv_val, u32 *refdiv_val, u64 rate) |
354 | { |
355 | u64 rem; |
356 | |
357 | *postdiv1_val = 2; |
358 | *postdiv2_val = 1; |
359 | |
360 | rate = rate * ((*postdiv1_val) * (*postdiv2_val)); |
361 | |
362 | *frac_val = 0; |
363 | rem = do_div(rate, 1000000); |
364 | rem = do_div(rate, PLL_MASK_WIDTH); |
365 | *fbdiv_val = rate; |
366 | *refdiv_val = 1; |
367 | rem = rem * (1 << PLL_MASK_WIDTH); |
368 | do_div(rem, PLL_MASK_WIDTH); |
369 | *frac_val = rem; |
370 | } |
371 | |
372 | static int clk_pll_set_rate(struct clk_hw *hw, |
373 | unsigned long rate, |
374 | unsigned long parent_rate) |
375 | { |
376 | struct hi3559av100_clk_pll *clk = to_pll_clk(hw); |
377 | u32 frac_val, postdiv1_val, postdiv2_val, fbdiv_val, refdiv_val; |
378 | u32 val; |
379 | |
380 | postdiv1_val = postdiv2_val = 0; |
381 | |
382 | hi3559av100_calc_pll(frac_val: &frac_val, postdiv1_val: &postdiv1_val, postdiv2_val: &postdiv2_val, |
383 | fbdiv_val: &fbdiv_val, refdiv_val: &refdiv_val, rate: (u64)rate); |
384 | |
385 | val = readl_relaxed(clk->ctrl_reg1); |
386 | val &= ~(((1 << clk->frac_width) - 1) << clk->frac_shift); |
387 | val &= ~(((1 << clk->postdiv1_width) - 1) << clk->postdiv1_shift); |
388 | val &= ~(((1 << clk->postdiv2_width) - 1) << clk->postdiv2_shift); |
389 | |
390 | val |= frac_val << clk->frac_shift; |
391 | val |= postdiv1_val << clk->postdiv1_shift; |
392 | val |= postdiv2_val << clk->postdiv2_shift; |
393 | writel_relaxed(val, clk->ctrl_reg1); |
394 | |
395 | val = readl_relaxed(clk->ctrl_reg2); |
396 | val &= ~(((1 << clk->fbdiv_width) - 1) << clk->fbdiv_shift); |
397 | val &= ~(((1 << clk->refdiv_width) - 1) << clk->refdiv_shift); |
398 | |
399 | val |= fbdiv_val << clk->fbdiv_shift; |
400 | val |= refdiv_val << clk->refdiv_shift; |
401 | writel_relaxed(val, clk->ctrl_reg2); |
402 | |
403 | return 0; |
404 | } |
405 | |
406 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, |
407 | unsigned long parent_rate) |
408 | { |
409 | struct hi3559av100_clk_pll *clk = to_pll_clk(hw); |
410 | u64 frac_val, fbdiv_val, refdiv_val; |
411 | u32 postdiv1_val, postdiv2_val; |
412 | u32 val; |
413 | u64 tmp, rate; |
414 | |
415 | val = readl_relaxed(clk->ctrl_reg1); |
416 | val = val >> clk->frac_shift; |
417 | val &= ((1 << clk->frac_width) - 1); |
418 | frac_val = val; |
419 | |
420 | val = readl_relaxed(clk->ctrl_reg1); |
421 | val = val >> clk->postdiv1_shift; |
422 | val &= ((1 << clk->postdiv1_width) - 1); |
423 | postdiv1_val = val; |
424 | |
425 | val = readl_relaxed(clk->ctrl_reg1); |
426 | val = val >> clk->postdiv2_shift; |
427 | val &= ((1 << clk->postdiv2_width) - 1); |
428 | postdiv2_val = val; |
429 | |
430 | val = readl_relaxed(clk->ctrl_reg2); |
431 | val = val >> clk->fbdiv_shift; |
432 | val &= ((1 << clk->fbdiv_width) - 1); |
433 | fbdiv_val = val; |
434 | |
435 | val = readl_relaxed(clk->ctrl_reg2); |
436 | val = val >> clk->refdiv_shift; |
437 | val &= ((1 << clk->refdiv_width) - 1); |
438 | refdiv_val = val; |
439 | |
440 | /* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv */ |
441 | rate = 0; |
442 | tmp = 24000000 * fbdiv_val + (24000000 * frac_val) / (1 << 24); |
443 | rate += tmp; |
444 | do_div(rate, refdiv_val); |
445 | do_div(rate, postdiv1_val * postdiv2_val); |
446 | |
447 | return rate; |
448 | } |
449 | |
450 | static const struct clk_ops hisi_clk_pll_ops = { |
451 | .set_rate = clk_pll_set_rate, |
452 | .recalc_rate = clk_pll_recalc_rate, |
453 | }; |
454 | |
455 | static void hisi_clk_register_pll(struct hi3559av100_pll_clock *clks, |
456 | int nums, struct hisi_clock_data *data, struct device *dev) |
457 | { |
458 | void __iomem *base = data->base; |
459 | struct hi3559av100_clk_pll *p_clk = NULL; |
460 | struct clk *clk = NULL; |
461 | struct clk_init_data init; |
462 | int i; |
463 | |
464 | p_clk = devm_kcalloc(dev, n: nums, size: sizeof(*p_clk), GFP_KERNEL); |
465 | if (!p_clk) |
466 | return; |
467 | |
468 | for (i = 0; i < nums; i++) { |
469 | init.name = clks[i].name; |
470 | init.flags = 0; |
471 | init.parent_names = |
472 | (clks[i].parent_name ? &clks[i].parent_name : NULL); |
473 | init.num_parents = (clks[i].parent_name ? 1 : 0); |
474 | init.ops = &hisi_clk_pll_ops; |
475 | |
476 | p_clk->ctrl_reg1 = base + clks[i].ctrl_reg1; |
477 | p_clk->frac_shift = clks[i].frac_shift; |
478 | p_clk->frac_width = clks[i].frac_width; |
479 | p_clk->postdiv1_shift = clks[i].postdiv1_shift; |
480 | p_clk->postdiv1_width = clks[i].postdiv1_width; |
481 | p_clk->postdiv2_shift = clks[i].postdiv2_shift; |
482 | p_clk->postdiv2_width = clks[i].postdiv2_width; |
483 | |
484 | p_clk->ctrl_reg2 = base + clks[i].ctrl_reg2; |
485 | p_clk->fbdiv_shift = clks[i].fbdiv_shift; |
486 | p_clk->fbdiv_width = clks[i].fbdiv_width; |
487 | p_clk->refdiv_shift = clks[i].refdiv_shift; |
488 | p_clk->refdiv_width = clks[i].refdiv_width; |
489 | p_clk->hw.init = &init; |
490 | |
491 | clk = clk_register(NULL, hw: &p_clk->hw); |
492 | if (IS_ERR(ptr: clk)) { |
493 | dev_err(dev, "%s: failed to register clock %s\n" , |
494 | __func__, clks[i].name); |
495 | continue; |
496 | } |
497 | |
498 | data->clk_data.clks[clks[i].id] = clk; |
499 | p_clk++; |
500 | } |
501 | } |
502 | |
503 | static struct hisi_clock_data *hi3559av100_clk_register( |
504 | struct platform_device *pdev) |
505 | { |
506 | struct hisi_clock_data *clk_data; |
507 | int ret; |
508 | |
509 | clk_data = hisi_clk_alloc(pdev, HI3559AV100_CRG_NR_CLKS); |
510 | if (!clk_data) |
511 | return ERR_PTR(error: -ENOMEM); |
512 | |
513 | ret = hisi_clk_register_fixed_rate(hi3559av100_fixed_rate_clks_crg, |
514 | ARRAY_SIZE(hi3559av100_fixed_rate_clks_crg), clk_data); |
515 | if (ret) |
516 | return ERR_PTR(error: ret); |
517 | |
518 | hisi_clk_register_pll(clks: hi3559av100_pll_clks, |
519 | ARRAY_SIZE(hi3559av100_pll_clks), data: clk_data, dev: &pdev->dev); |
520 | |
521 | ret = hisi_clk_register_mux(hi3559av100_mux_clks_crg, |
522 | ARRAY_SIZE(hi3559av100_mux_clks_crg), clk_data); |
523 | if (ret) |
524 | goto unregister_fixed_rate; |
525 | |
526 | ret = hisi_clk_register_gate(hi3559av100_gate_clks, |
527 | ARRAY_SIZE(hi3559av100_gate_clks), clk_data); |
528 | if (ret) |
529 | goto unregister_mux; |
530 | |
531 | ret = of_clk_add_provider(np: pdev->dev.of_node, |
532 | clk_src_get: of_clk_src_onecell_get, data: &clk_data->clk_data); |
533 | if (ret) |
534 | goto unregister_gate; |
535 | |
536 | return clk_data; |
537 | |
538 | unregister_gate: |
539 | hisi_clk_unregister_gate(clks: hi3559av100_gate_clks, |
540 | ARRAY_SIZE(hi3559av100_gate_clks), data: clk_data); |
541 | unregister_mux: |
542 | hisi_clk_unregister_mux(clks: hi3559av100_mux_clks_crg, |
543 | ARRAY_SIZE(hi3559av100_mux_clks_crg), data: clk_data); |
544 | unregister_fixed_rate: |
545 | hisi_clk_unregister_fixed_rate(clks: hi3559av100_fixed_rate_clks_crg, |
546 | ARRAY_SIZE(hi3559av100_fixed_rate_clks_crg), data: clk_data); |
547 | return ERR_PTR(error: ret); |
548 | } |
549 | |
550 | static void hi3559av100_clk_unregister(struct platform_device *pdev) |
551 | { |
552 | struct hisi_crg_dev *crg = platform_get_drvdata(pdev); |
553 | |
554 | of_clk_del_provider(np: pdev->dev.of_node); |
555 | |
556 | hisi_clk_unregister_gate(clks: hi3559av100_gate_clks, |
557 | ARRAY_SIZE(hi3559av100_gate_clks), data: crg->clk_data); |
558 | hisi_clk_unregister_mux(clks: hi3559av100_mux_clks_crg, |
559 | ARRAY_SIZE(hi3559av100_mux_clks_crg), data: crg->clk_data); |
560 | hisi_clk_unregister_fixed_rate(clks: hi3559av100_fixed_rate_clks_crg, |
561 | ARRAY_SIZE(hi3559av100_fixed_rate_clks_crg), data: crg->clk_data); |
562 | } |
563 | |
564 | static const struct hisi_crg_funcs hi3559av100_crg_funcs = { |
565 | .register_clks = hi3559av100_clk_register, |
566 | .unregister_clks = hi3559av100_clk_unregister, |
567 | }; |
568 | |
569 | static struct hisi_fixed_rate_clock hi3559av100_shub_fixed_rate_clks[] = { |
570 | { HI3559AV100_SHUB_SOURCE_SOC_24M, "clk_source_24M" , NULL, 0, 24000000UL, }, |
571 | { HI3559AV100_SHUB_SOURCE_SOC_200M, "clk_source_200M" , NULL, 0, 200000000UL, }, |
572 | { HI3559AV100_SHUB_SOURCE_SOC_300M, "clk_source_300M" , NULL, 0, 300000000UL, }, |
573 | { HI3559AV100_SHUB_SOURCE_PLL, "clk_source_PLL" , NULL, 0, 192000000UL, }, |
574 | { HI3559AV100_SHUB_I2C0_CLK, "clk_shub_i2c0" , NULL, 0, 48000000UL, }, |
575 | { HI3559AV100_SHUB_I2C1_CLK, "clk_shub_i2c1" , NULL, 0, 48000000UL, }, |
576 | { HI3559AV100_SHUB_I2C2_CLK, "clk_shub_i2c2" , NULL, 0, 48000000UL, }, |
577 | { HI3559AV100_SHUB_I2C3_CLK, "clk_shub_i2c3" , NULL, 0, 48000000UL, }, |
578 | { HI3559AV100_SHUB_I2C4_CLK, "clk_shub_i2c4" , NULL, 0, 48000000UL, }, |
579 | { HI3559AV100_SHUB_I2C5_CLK, "clk_shub_i2c5" , NULL, 0, 48000000UL, }, |
580 | { HI3559AV100_SHUB_I2C6_CLK, "clk_shub_i2c6" , NULL, 0, 48000000UL, }, |
581 | { HI3559AV100_SHUB_I2C7_CLK, "clk_shub_i2c7" , NULL, 0, 48000000UL, }, |
582 | { HI3559AV100_SHUB_UART_CLK_32K, "clk_uart_32K" , NULL, 0, 32000UL, }, |
583 | }; |
584 | |
585 | /* shub mux clk */ |
586 | static u32 shub_source_clk_mux_table[] = {0, 1, 2, 3}; |
587 | static const char *shub_source_clk_mux_p[] = { |
588 | "clk_source_24M" , "clk_source_200M" , "clk_source_300M" , "clk_source_PLL" |
589 | }; |
590 | |
591 | static u32 shub_uart_source_clk_mux_table[] = {0, 1, 2, 3}; |
592 | static const char *shub_uart_source_clk_mux_p[] = { |
593 | "clk_uart_32K" , "clk_uart_div_clk" , "clk_uart_div_clk" , "clk_source_24M" |
594 | }; |
595 | |
596 | static struct hisi_mux_clock hi3559av100_shub_mux_clks[] = { |
597 | { |
598 | HI3559AV100_SHUB_SOURCE_CLK, .name: "shub_clk" , .parent_names: shub_source_clk_mux_p, |
599 | ARRAY_SIZE(shub_source_clk_mux_p), |
600 | .flags: 0, .offset: 0x0, .shift: 0, .width: 2, .mux_flags: 0, .table: shub_source_clk_mux_table, |
601 | }, |
602 | |
603 | { |
604 | HI3559AV100_SHUB_UART_SOURCE_CLK, "shub_uart_source_clk" , |
605 | shub_uart_source_clk_mux_p, ARRAY_SIZE(shub_uart_source_clk_mux_p), |
606 | 0, 0x1c, 28, 2, 0, shub_uart_source_clk_mux_table, |
607 | }, |
608 | }; |
609 | |
610 | |
611 | /* shub div clk */ |
612 | static struct clk_div_table shub_spi_clk_table[] = {{0, 8}, {1, 4}, {2, 2}, {/*sentinel*/}}; |
613 | static struct clk_div_table shub_uart_div_clk_table[] = {{1, 8}, {2, 4}, {/*sentinel*/}}; |
614 | |
615 | static struct hisi_divider_clock hi3559av100_shub_div_clks[] = { |
616 | { HI3559AV100_SHUB_SPI_SOURCE_CLK, "clk_spi_clk" , "shub_clk" , 0, 0x20, 24, 2, |
617 | CLK_DIVIDER_ALLOW_ZERO, shub_spi_clk_table, |
618 | }, |
619 | { HI3559AV100_SHUB_UART_DIV_CLK, "clk_uart_div_clk" , "shub_clk" , 0, 0x1c, 28, 2, |
620 | CLK_DIVIDER_ALLOW_ZERO, shub_uart_div_clk_table, |
621 | }, |
622 | }; |
623 | |
624 | /* shub gate clk */ |
625 | static struct hisi_gate_clock hi3559av100_shub_gate_clks[] = { |
626 | { |
627 | HI3559AV100_SHUB_SPI0_CLK, "clk_shub_spi0" , "clk_spi_clk" , |
628 | 0, 0x20, 1, 0, |
629 | }, |
630 | { |
631 | HI3559AV100_SHUB_SPI1_CLK, "clk_shub_spi1" , "clk_spi_clk" , |
632 | 0, 0x20, 5, 0, |
633 | }, |
634 | { |
635 | HI3559AV100_SHUB_SPI2_CLK, "clk_shub_spi2" , "clk_spi_clk" , |
636 | 0, 0x20, 9, 0, |
637 | }, |
638 | |
639 | { |
640 | HI3559AV100_SHUB_UART0_CLK, "clk_shub_uart0" , "shub_uart_source_clk" , |
641 | 0, 0x1c, 1, 0, |
642 | }, |
643 | { |
644 | HI3559AV100_SHUB_UART1_CLK, "clk_shub_uart1" , "shub_uart_source_clk" , |
645 | 0, 0x1c, 5, 0, |
646 | }, |
647 | { |
648 | HI3559AV100_SHUB_UART2_CLK, "clk_shub_uart2" , "shub_uart_source_clk" , |
649 | 0, 0x1c, 9, 0, |
650 | }, |
651 | { |
652 | HI3559AV100_SHUB_UART3_CLK, "clk_shub_uart3" , "shub_uart_source_clk" , |
653 | 0, 0x1c, 13, 0, |
654 | }, |
655 | { |
656 | HI3559AV100_SHUB_UART4_CLK, "clk_shub_uart4" , "shub_uart_source_clk" , |
657 | 0, 0x1c, 17, 0, |
658 | }, |
659 | { |
660 | HI3559AV100_SHUB_UART5_CLK, "clk_shub_uart5" , "shub_uart_source_clk" , |
661 | 0, 0x1c, 21, 0, |
662 | }, |
663 | { |
664 | HI3559AV100_SHUB_UART6_CLK, "clk_shub_uart6" , "shub_uart_source_clk" , |
665 | 0, 0x1c, 25, 0, |
666 | }, |
667 | |
668 | { |
669 | HI3559AV100_SHUB_EDMAC_CLK, "clk_shub_dmac" , "shub_clk" , |
670 | 0, 0x24, 4, 0, |
671 | }, |
672 | }; |
673 | |
674 | static int hi3559av100_shub_default_clk_set(void) |
675 | { |
676 | void __iomem *crg_base; |
677 | unsigned int val; |
678 | |
679 | crg_base = ioremap(CRG_BASE_ADDR, size: SZ_4K); |
680 | |
681 | /* SSP: 192M/2 */ |
682 | val = readl_relaxed(crg_base + 0x20); |
683 | val |= (0x2 << 24); |
684 | writel_relaxed(val, crg_base + 0x20); |
685 | |
686 | /* UART: 192M/8 */ |
687 | val = readl_relaxed(crg_base + 0x1C); |
688 | val |= (0x1 << 28); |
689 | writel_relaxed(val, crg_base + 0x1C); |
690 | |
691 | iounmap(addr: crg_base); |
692 | crg_base = NULL; |
693 | |
694 | return 0; |
695 | } |
696 | |
697 | static struct hisi_clock_data *hi3559av100_shub_clk_register( |
698 | struct platform_device *pdev) |
699 | { |
700 | struct hisi_clock_data *clk_data = NULL; |
701 | int ret; |
702 | |
703 | hi3559av100_shub_default_clk_set(); |
704 | |
705 | clk_data = hisi_clk_alloc(pdev, HI3559AV100_SHUB_NR_CLKS); |
706 | if (!clk_data) |
707 | return ERR_PTR(error: -ENOMEM); |
708 | |
709 | ret = hisi_clk_register_fixed_rate(hi3559av100_shub_fixed_rate_clks, |
710 | ARRAY_SIZE(hi3559av100_shub_fixed_rate_clks), clk_data); |
711 | if (ret) |
712 | return ERR_PTR(error: ret); |
713 | |
714 | ret = hisi_clk_register_mux(hi3559av100_shub_mux_clks, |
715 | ARRAY_SIZE(hi3559av100_shub_mux_clks), clk_data); |
716 | if (ret) |
717 | goto unregister_fixed_rate; |
718 | |
719 | ret = hisi_clk_register_divider(hi3559av100_shub_div_clks, |
720 | ARRAY_SIZE(hi3559av100_shub_div_clks), clk_data); |
721 | if (ret) |
722 | goto unregister_mux; |
723 | |
724 | ret = hisi_clk_register_gate(hi3559av100_shub_gate_clks, |
725 | ARRAY_SIZE(hi3559av100_shub_gate_clks), clk_data); |
726 | if (ret) |
727 | goto unregister_factor; |
728 | |
729 | ret = of_clk_add_provider(np: pdev->dev.of_node, |
730 | clk_src_get: of_clk_src_onecell_get, data: &clk_data->clk_data); |
731 | if (ret) |
732 | goto unregister_gate; |
733 | |
734 | return clk_data; |
735 | |
736 | unregister_gate: |
737 | hisi_clk_unregister_gate(clks: hi3559av100_shub_gate_clks, |
738 | ARRAY_SIZE(hi3559av100_shub_gate_clks), data: clk_data); |
739 | unregister_factor: |
740 | hisi_clk_unregister_divider(clks: hi3559av100_shub_div_clks, |
741 | ARRAY_SIZE(hi3559av100_shub_div_clks), data: clk_data); |
742 | unregister_mux: |
743 | hisi_clk_unregister_mux(clks: hi3559av100_shub_mux_clks, |
744 | ARRAY_SIZE(hi3559av100_shub_mux_clks), data: clk_data); |
745 | unregister_fixed_rate: |
746 | hisi_clk_unregister_fixed_rate(clks: hi3559av100_shub_fixed_rate_clks, |
747 | ARRAY_SIZE(hi3559av100_shub_fixed_rate_clks), data: clk_data); |
748 | return ERR_PTR(error: ret); |
749 | } |
750 | |
751 | static void hi3559av100_shub_clk_unregister(struct platform_device *pdev) |
752 | { |
753 | struct hisi_crg_dev *crg = platform_get_drvdata(pdev); |
754 | |
755 | of_clk_del_provider(np: pdev->dev.of_node); |
756 | |
757 | hisi_clk_unregister_gate(clks: hi3559av100_shub_gate_clks, |
758 | ARRAY_SIZE(hi3559av100_shub_gate_clks), data: crg->clk_data); |
759 | hisi_clk_unregister_divider(clks: hi3559av100_shub_div_clks, |
760 | ARRAY_SIZE(hi3559av100_shub_div_clks), data: crg->clk_data); |
761 | hisi_clk_unregister_mux(clks: hi3559av100_shub_mux_clks, |
762 | ARRAY_SIZE(hi3559av100_shub_mux_clks), data: crg->clk_data); |
763 | hisi_clk_unregister_fixed_rate(clks: hi3559av100_shub_fixed_rate_clks, |
764 | ARRAY_SIZE(hi3559av100_shub_fixed_rate_clks), data: crg->clk_data); |
765 | } |
766 | |
767 | static const struct hisi_crg_funcs hi3559av100_shub_crg_funcs = { |
768 | .register_clks = hi3559av100_shub_clk_register, |
769 | .unregister_clks = hi3559av100_shub_clk_unregister, |
770 | }; |
771 | |
772 | static const struct of_device_id hi3559av100_crg_match_table[] = { |
773 | { |
774 | .compatible = "hisilicon,hi3559av100-clock" , |
775 | .data = &hi3559av100_crg_funcs |
776 | }, |
777 | { |
778 | .compatible = "hisilicon,hi3559av100-shub-clock" , |
779 | .data = &hi3559av100_shub_crg_funcs |
780 | }, |
781 | { } |
782 | }; |
783 | MODULE_DEVICE_TABLE(of, hi3559av100_crg_match_table); |
784 | |
785 | static int hi3559av100_crg_probe(struct platform_device *pdev) |
786 | { |
787 | struct hisi_crg_dev *crg; |
788 | |
789 | crg = devm_kmalloc(dev: &pdev->dev, size: sizeof(*crg), GFP_KERNEL); |
790 | if (!crg) |
791 | return -ENOMEM; |
792 | |
793 | crg->funcs = of_device_get_match_data(dev: &pdev->dev); |
794 | if (!crg->funcs) |
795 | return -ENOENT; |
796 | |
797 | crg->rstc = hisi_reset_init(pdev); |
798 | if (!crg->rstc) |
799 | return -ENOMEM; |
800 | |
801 | crg->clk_data = crg->funcs->register_clks(pdev); |
802 | if (IS_ERR(ptr: crg->clk_data)) { |
803 | hisi_reset_exit(rstc: crg->rstc); |
804 | return PTR_ERR(ptr: crg->clk_data); |
805 | } |
806 | |
807 | platform_set_drvdata(pdev, data: crg); |
808 | return 0; |
809 | } |
810 | |
811 | static void hi3559av100_crg_remove(struct platform_device *pdev) |
812 | { |
813 | struct hisi_crg_dev *crg = platform_get_drvdata(pdev); |
814 | |
815 | hisi_reset_exit(rstc: crg->rstc); |
816 | crg->funcs->unregister_clks(pdev); |
817 | } |
818 | |
819 | static struct platform_driver hi3559av100_crg_driver = { |
820 | .probe = hi3559av100_crg_probe, |
821 | .remove_new = hi3559av100_crg_remove, |
822 | .driver = { |
823 | .name = "hi3559av100-clock" , |
824 | .of_match_table = hi3559av100_crg_match_table, |
825 | }, |
826 | }; |
827 | |
828 | static int __init hi3559av100_crg_init(void) |
829 | { |
830 | return platform_driver_register(&hi3559av100_crg_driver); |
831 | } |
832 | core_initcall(hi3559av100_crg_init); |
833 | |
834 | static void __exit hi3559av100_crg_exit(void) |
835 | { |
836 | platform_driver_unregister(&hi3559av100_crg_driver); |
837 | } |
838 | module_exit(hi3559av100_crg_exit); |
839 | |
840 | |
841 | MODULE_DESCRIPTION("HiSilicon Hi3559AV100 CRG Driver" ); |
842 | |