xref: /linux/drivers/clk/meson/s4-pll.c (revision 746680ec6696585e30db3e18c93a63df9cbec39c)
1 // SPDX-License-Identifier: (GPL-2.0-only OR MIT)
2 /*
3  * Amlogic S4 PLL Clock Controller Driver
4  *
5  * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved
6  * Author: Yu Tu <yu.tu@amlogic.com>
7  */
8 
9 #include <linux/clk-provider.h>
10 #include <linux/of_device.h>
11 #include <linux/platform_device.h>
12 
13 #include "clk-mpll.h"
14 #include "clk-pll.h"
15 #include "clk-regmap.h"
16 #include "meson-clkc-utils.h"
17 #include <dt-bindings/clock/amlogic,s4-pll-clkc.h>
18 
19 #define ANACTRL_FIXPLL_CTRL0                       0x040
20 #define ANACTRL_FIXPLL_CTRL1                       0x044
21 #define ANACTRL_FIXPLL_CTRL3                       0x04c
22 #define ANACTRL_GP0PLL_CTRL0                       0x080
23 #define ANACTRL_GP0PLL_CTRL1                       0x084
24 #define ANACTRL_GP0PLL_CTRL2                       0x088
25 #define ANACTRL_GP0PLL_CTRL3                       0x08c
26 #define ANACTRL_GP0PLL_CTRL4                       0x090
27 #define ANACTRL_GP0PLL_CTRL5                       0x094
28 #define ANACTRL_GP0PLL_CTRL6                       0x098
29 #define ANACTRL_HIFIPLL_CTRL0                      0x100
30 #define ANACTRL_HIFIPLL_CTRL1                      0x104
31 #define ANACTRL_HIFIPLL_CTRL2                      0x108
32 #define ANACTRL_HIFIPLL_CTRL3                      0x10c
33 #define ANACTRL_HIFIPLL_CTRL4                      0x110
34 #define ANACTRL_HIFIPLL_CTRL5                      0x114
35 #define ANACTRL_HIFIPLL_CTRL6                      0x118
36 #define ANACTRL_MPLL_CTRL0                         0x180
37 #define ANACTRL_MPLL_CTRL1                         0x184
38 #define ANACTRL_MPLL_CTRL2                         0x188
39 #define ANACTRL_MPLL_CTRL3                         0x18c
40 #define ANACTRL_MPLL_CTRL4                         0x190
41 #define ANACTRL_MPLL_CTRL5                         0x194
42 #define ANACTRL_MPLL_CTRL6                         0x198
43 #define ANACTRL_MPLL_CTRL7                         0x19c
44 #define ANACTRL_MPLL_CTRL8                         0x1a0
45 #define ANACTRL_HDMIPLL_CTRL0                      0x1c0
46 
47 /*
48  * These clock are a fixed value (fixed_pll is 2GHz) that is initialized by ROMcode.
49  * The chip was changed fixed pll for security reasons. Fixed PLL registers are not writable
50  * in the kernel phase. Write of fixed PLL-related register will cause the system to crash.
51  * Meanwhile, these clock won't ever change at runtime.
52  * For the above reasons, we can only use ro_ops for fixed PLL related clocks.
53  */
54 static struct clk_regmap s4_fixed_pll_dco = {
55 	.data = &(struct meson_clk_pll_data){
56 		.en = {
57 			.reg_off = ANACTRL_FIXPLL_CTRL0,
58 			.shift   = 28,
59 			.width   = 1,
60 		},
61 		.m = {
62 			.reg_off = ANACTRL_FIXPLL_CTRL0,
63 			.shift   = 0,
64 			.width   = 8,
65 		},
66 		.frac = {
67 			.reg_off = ANACTRL_FIXPLL_CTRL1,
68 			.shift   = 0,
69 			.width   = 17,
70 		},
71 		.n = {
72 			.reg_off = ANACTRL_FIXPLL_CTRL0,
73 			.shift   = 10,
74 			.width   = 5,
75 		},
76 		.l = {
77 			.reg_off = ANACTRL_FIXPLL_CTRL0,
78 			.shift   = 31,
79 			.width   = 1,
80 		},
81 		.rst = {
82 			.reg_off = ANACTRL_FIXPLL_CTRL0,
83 			.shift   = 29,
84 			.width   = 1,
85 		},
86 	},
87 	.hw.init = &(struct clk_init_data){
88 		.name = "fixed_pll_dco",
89 		.ops = &meson_clk_pll_ro_ops,
90 		.parent_data = (const struct clk_parent_data []) {
91 			{ .fw_name = "xtal", }
92 		},
93 		.num_parents = 1,
94 	},
95 };
96 
97 static struct clk_regmap s4_fixed_pll = {
98 	.data = &(struct clk_regmap_div_data){
99 		.offset = ANACTRL_FIXPLL_CTRL0,
100 		.shift = 16,
101 		.width = 2,
102 		.flags = CLK_DIVIDER_POWER_OF_TWO,
103 	},
104 	.hw.init = &(struct clk_init_data){
105 		.name = "fixed_pll",
106 		.ops = &clk_regmap_divider_ro_ops,
107 		.parent_hws = (const struct clk_hw *[]) {
108 			&s4_fixed_pll_dco.hw
109 		},
110 		.num_parents = 1,
111 		/*
112 		 * This clock won't ever change at runtime so
113 		 * CLK_SET_RATE_PARENT is not required
114 		 */
115 	},
116 };
117 
118 static struct clk_fixed_factor s4_fclk_div2_div = {
119 	.mult = 1,
120 	.div = 2,
121 	.hw.init = &(struct clk_init_data){
122 		.name = "fclk_div2_div",
123 		.ops = &clk_fixed_factor_ops,
124 		.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
125 		.num_parents = 1,
126 	},
127 };
128 
129 static struct clk_regmap s4_fclk_div2 = {
130 	.data = &(struct clk_regmap_gate_data){
131 		.offset = ANACTRL_FIXPLL_CTRL1,
132 		.bit_idx = 24,
133 	},
134 	.hw.init = &(struct clk_init_data){
135 		.name = "fclk_div2",
136 		.ops = &clk_regmap_gate_ro_ops,
137 		.parent_hws = (const struct clk_hw *[]) {
138 			&s4_fclk_div2_div.hw
139 		},
140 		.num_parents = 1,
141 	},
142 };
143 
144 static struct clk_fixed_factor s4_fclk_div3_div = {
145 	.mult = 1,
146 	.div = 3,
147 	.hw.init = &(struct clk_init_data){
148 		.name = "fclk_div3_div",
149 		.ops = &clk_fixed_factor_ops,
150 		.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
151 		.num_parents = 1,
152 	},
153 };
154 
155 static struct clk_regmap s4_fclk_div3 = {
156 	.data = &(struct clk_regmap_gate_data){
157 		.offset = ANACTRL_FIXPLL_CTRL1,
158 		.bit_idx = 20,
159 	},
160 	.hw.init = &(struct clk_init_data){
161 		.name = "fclk_div3",
162 		.ops = &clk_regmap_gate_ro_ops,
163 		.parent_hws = (const struct clk_hw *[]) {
164 			&s4_fclk_div3_div.hw
165 		},
166 		.num_parents = 1,
167 	},
168 };
169 
170 static struct clk_fixed_factor s4_fclk_div4_div = {
171 	.mult = 1,
172 	.div = 4,
173 	.hw.init = &(struct clk_init_data){
174 		.name = "fclk_div4_div",
175 		.ops = &clk_fixed_factor_ops,
176 		.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
177 		.num_parents = 1,
178 	},
179 };
180 
181 static struct clk_regmap s4_fclk_div4 = {
182 	.data = &(struct clk_regmap_gate_data){
183 		.offset = ANACTRL_FIXPLL_CTRL1,
184 		.bit_idx = 21,
185 	},
186 	.hw.init = &(struct clk_init_data){
187 		.name = "fclk_div4",
188 		.ops = &clk_regmap_gate_ro_ops,
189 		.parent_hws = (const struct clk_hw *[]) {
190 			&s4_fclk_div4_div.hw
191 		},
192 		.num_parents = 1,
193 	},
194 };
195 
196 static struct clk_fixed_factor s4_fclk_div5_div = {
197 	.mult = 1,
198 	.div = 5,
199 	.hw.init = &(struct clk_init_data){
200 		.name = "fclk_div5_div",
201 		.ops = &clk_fixed_factor_ops,
202 		.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
203 		.num_parents = 1,
204 	},
205 };
206 
207 static struct clk_regmap s4_fclk_div5 = {
208 	.data = &(struct clk_regmap_gate_data){
209 		.offset = ANACTRL_FIXPLL_CTRL1,
210 		.bit_idx = 22,
211 	},
212 	.hw.init = &(struct clk_init_data){
213 		.name = "fclk_div5",
214 		.ops = &clk_regmap_gate_ro_ops,
215 		.parent_hws = (const struct clk_hw *[]) {
216 			&s4_fclk_div5_div.hw
217 		},
218 		.num_parents = 1,
219 	},
220 };
221 
222 static struct clk_fixed_factor s4_fclk_div7_div = {
223 	.mult = 1,
224 	.div = 7,
225 	.hw.init = &(struct clk_init_data){
226 		.name = "fclk_div7_div",
227 		.ops = &clk_fixed_factor_ops,
228 		.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
229 		.num_parents = 1,
230 	},
231 };
232 
233 static struct clk_regmap s4_fclk_div7 = {
234 	.data = &(struct clk_regmap_gate_data){
235 		.offset = ANACTRL_FIXPLL_CTRL1,
236 		.bit_idx = 23,
237 	},
238 	.hw.init = &(struct clk_init_data){
239 		.name = "fclk_div7",
240 		.ops = &clk_regmap_gate_ro_ops,
241 		.parent_hws = (const struct clk_hw *[]) {
242 			&s4_fclk_div7_div.hw
243 		},
244 		.num_parents = 1,
245 	},
246 };
247 
248 static struct clk_fixed_factor s4_fclk_div2p5_div = {
249 	.mult = 2,
250 	.div = 5,
251 	.hw.init = &(struct clk_init_data){
252 		.name = "fclk_div2p5_div",
253 		.ops = &clk_fixed_factor_ops,
254 		.parent_hws = (const struct clk_hw *[]) {
255 			&s4_fixed_pll.hw
256 		},
257 		.num_parents = 1,
258 	},
259 };
260 
261 static struct clk_regmap s4_fclk_div2p5 = {
262 	.data = &(struct clk_regmap_gate_data){
263 		.offset = ANACTRL_FIXPLL_CTRL1,
264 		.bit_idx = 25,
265 	},
266 	.hw.init = &(struct clk_init_data){
267 		.name = "fclk_div2p5",
268 		.ops = &clk_regmap_gate_ro_ops,
269 		.parent_hws = (const struct clk_hw *[]) {
270 			&s4_fclk_div2p5_div.hw
271 		},
272 		.num_parents = 1,
273 	},
274 };
275 
276 static const struct pll_mult_range s4_gp0_pll_mult_range = {
277 	.min = 125,
278 	.max = 250,
279 };
280 
281 /*
282  * Internal gp0 pll emulation configuration parameters
283  */
284 static const struct reg_sequence s4_gp0_init_regs[] = {
285 	{ .reg = ANACTRL_GP0PLL_CTRL1,	.def = 0x00000000 },
286 	{ .reg = ANACTRL_GP0PLL_CTRL2,	.def = 0x00000000 },
287 	{ .reg = ANACTRL_GP0PLL_CTRL3,	.def = 0x48681c00 },
288 	{ .reg = ANACTRL_GP0PLL_CTRL4,	.def = 0x88770290 },
289 	{ .reg = ANACTRL_GP0PLL_CTRL5,	.def = 0x39272000 },
290 	{ .reg = ANACTRL_GP0PLL_CTRL6,	.def = 0x56540000 }
291 };
292 
293 static struct clk_regmap s4_gp0_pll_dco = {
294 	.data = &(struct meson_clk_pll_data){
295 		.en = {
296 			.reg_off = ANACTRL_GP0PLL_CTRL0,
297 			.shift   = 28,
298 			.width   = 1,
299 		},
300 		.m = {
301 			.reg_off = ANACTRL_GP0PLL_CTRL0,
302 			.shift   = 0,
303 			.width   = 8,
304 		},
305 		.n = {
306 			.reg_off = ANACTRL_GP0PLL_CTRL0,
307 			.shift   = 10,
308 			.width   = 5,
309 		},
310 		.l = {
311 			.reg_off = ANACTRL_GP0PLL_CTRL0,
312 			.shift   = 31,
313 			.width   = 1,
314 		},
315 		.rst = {
316 			.reg_off = ANACTRL_GP0PLL_CTRL0,
317 			.shift   = 29,
318 			.width   = 1,
319 		},
320 		.range = &s4_gp0_pll_mult_range,
321 		.init_regs = s4_gp0_init_regs,
322 		.init_count = ARRAY_SIZE(s4_gp0_init_regs),
323 	},
324 	.hw.init = &(struct clk_init_data){
325 		.name = "gp0_pll_dco",
326 		.ops = &meson_clk_pll_ops,
327 		.parent_data = (const struct clk_parent_data []) {
328 			{ .fw_name = "xtal", }
329 		},
330 		.num_parents = 1,
331 	},
332 };
333 
334 static struct clk_regmap s4_gp0_pll = {
335 	.data = &(struct clk_regmap_div_data){
336 		.offset = ANACTRL_GP0PLL_CTRL0,
337 		.shift = 16,
338 		.width = 3,
339 		.flags = (CLK_DIVIDER_POWER_OF_TWO |
340 			  CLK_DIVIDER_ROUND_CLOSEST),
341 	},
342 	.hw.init = &(struct clk_init_data){
343 		.name = "gp0_pll",
344 		.ops = &clk_regmap_divider_ops,
345 		.parent_hws = (const struct clk_hw *[]) {
346 			&s4_gp0_pll_dco.hw
347 		},
348 		.num_parents = 1,
349 		.flags = CLK_SET_RATE_PARENT,
350 	},
351 };
352 
353 /*
354  * Internal hifi pll emulation configuration parameters
355  */
356 static const struct reg_sequence s4_hifi_init_regs[] = {
357 	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00000000 },
358 	{ .reg = ANACTRL_HIFIPLL_CTRL3,	.def = 0x6a285c00 },
359 	{ .reg = ANACTRL_HIFIPLL_CTRL4,	.def = 0x65771290 },
360 	{ .reg = ANACTRL_HIFIPLL_CTRL5,	.def = 0x39272000 },
361 	{ .reg = ANACTRL_HIFIPLL_CTRL6,	.def = 0x56540000 }
362 };
363 
364 static struct clk_regmap s4_hifi_pll_dco = {
365 	.data = &(struct meson_clk_pll_data){
366 		.en = {
367 			.reg_off = ANACTRL_HIFIPLL_CTRL0,
368 			.shift   = 28,
369 			.width   = 1,
370 		},
371 		.m = {
372 			.reg_off = ANACTRL_HIFIPLL_CTRL0,
373 			.shift   = 0,
374 			.width   = 8,
375 		},
376 		.n = {
377 			.reg_off = ANACTRL_HIFIPLL_CTRL0,
378 			.shift   = 10,
379 			.width   = 5,
380 		},
381 		.frac = {
382 			.reg_off = ANACTRL_HIFIPLL_CTRL1,
383 			.shift   = 0,
384 			.width   = 17,
385 		},
386 		.l = {
387 			.reg_off = ANACTRL_HIFIPLL_CTRL0,
388 			.shift   = 31,
389 			.width   = 1,
390 		},
391 		.rst = {
392 			.reg_off = ANACTRL_HIFIPLL_CTRL0,
393 			.shift   = 29,
394 			.width   = 1,
395 		},
396 		.range = &s4_gp0_pll_mult_range,
397 		.init_regs = s4_hifi_init_regs,
398 		.init_count = ARRAY_SIZE(s4_hifi_init_regs),
399 		.frac_max = 100000,
400 		.flags = CLK_MESON_PLL_ROUND_CLOSEST,
401 	},
402 	.hw.init = &(struct clk_init_data){
403 		.name = "hifi_pll_dco",
404 		.ops = &meson_clk_pll_ops,
405 		.parent_data = (const struct clk_parent_data []) {
406 			{ .fw_name = "xtal", }
407 		},
408 		.num_parents = 1,
409 	},
410 };
411 
412 static struct clk_regmap s4_hifi_pll = {
413 	.data = &(struct clk_regmap_div_data){
414 		.offset = ANACTRL_HIFIPLL_CTRL0,
415 		.shift = 16,
416 		.width = 2,
417 		.flags = (CLK_DIVIDER_POWER_OF_TWO |
418 			  CLK_DIVIDER_ROUND_CLOSEST),
419 	},
420 	.hw.init = &(struct clk_init_data){
421 		.name = "hifi_pll",
422 		.ops = &clk_regmap_divider_ops,
423 		.parent_hws = (const struct clk_hw *[]) {
424 			&s4_hifi_pll_dco.hw
425 		},
426 		.num_parents = 1,
427 		.flags = CLK_SET_RATE_PARENT,
428 	},
429 };
430 
431 static struct clk_regmap s4_hdmi_pll_dco = {
432 	.data = &(struct meson_clk_pll_data){
433 		.en = {
434 			.reg_off = ANACTRL_HDMIPLL_CTRL0,
435 			.shift   = 28,
436 			.width   = 1,
437 		},
438 		.m = {
439 			.reg_off = ANACTRL_HDMIPLL_CTRL0,
440 			.shift   = 0,
441 			.width   = 8,
442 		},
443 		.n = {
444 			.reg_off = ANACTRL_HDMIPLL_CTRL0,
445 			.shift   = 10,
446 			.width   = 5,
447 		},
448 		.l = {
449 			.reg_off = ANACTRL_HDMIPLL_CTRL0,
450 			.shift   = 31,
451 			.width   = 1,
452 		},
453 		.rst = {
454 			.reg_off = ANACTRL_HDMIPLL_CTRL0,
455 			.shift   = 29,
456 			.width   = 1,
457 		},
458 		.range = &s4_gp0_pll_mult_range,
459 	},
460 	.hw.init = &(struct clk_init_data){
461 		.name = "hdmi_pll_dco",
462 		.ops = &meson_clk_pll_ops,
463 		.parent_data = (const struct clk_parent_data []) {
464 			{ .fw_name = "xtal", }
465 		},
466 		.num_parents = 1,
467 	},
468 };
469 
470 static struct clk_regmap s4_hdmi_pll_od = {
471 	.data = &(struct clk_regmap_div_data){
472 		.offset = ANACTRL_HDMIPLL_CTRL0,
473 		.shift = 16,
474 		.width = 4,
475 		.flags = CLK_DIVIDER_POWER_OF_TWO,
476 	},
477 	.hw.init = &(struct clk_init_data){
478 		.name = "hdmi_pll_od",
479 		.ops = &clk_regmap_divider_ops,
480 		.parent_hws = (const struct clk_hw *[]) {
481 			&s4_hdmi_pll_dco.hw
482 		},
483 		.num_parents = 1,
484 		.flags = CLK_SET_RATE_PARENT,
485 	},
486 };
487 
488 static struct clk_regmap s4_hdmi_pll = {
489 	.data = &(struct clk_regmap_div_data){
490 		.offset = ANACTRL_HDMIPLL_CTRL0,
491 		.shift = 20,
492 		.width = 2,
493 		.flags = CLK_DIVIDER_POWER_OF_TWO,
494 	},
495 	.hw.init = &(struct clk_init_data){
496 		.name = "hdmi_pll",
497 		.ops = &clk_regmap_divider_ops,
498 		.parent_hws = (const struct clk_hw *[]) {
499 			&s4_hdmi_pll_od.hw
500 		},
501 		.num_parents = 1,
502 		.flags = CLK_SET_RATE_PARENT,
503 	},
504 };
505 
506 static struct clk_fixed_factor s4_mpll_50m_div = {
507 	.mult = 1,
508 	.div = 80,
509 	.hw.init = &(struct clk_init_data){
510 		.name = "mpll_50m_div",
511 		.ops = &clk_fixed_factor_ops,
512 		.parent_hws = (const struct clk_hw *[]) {
513 			&s4_fixed_pll_dco.hw
514 		},
515 		.num_parents = 1,
516 	},
517 };
518 
519 static struct clk_regmap s4_mpll_50m = {
520 	.data = &(struct clk_regmap_mux_data){
521 		.offset = ANACTRL_FIXPLL_CTRL3,
522 		.mask = 0x1,
523 		.shift = 5,
524 	},
525 	.hw.init = &(struct clk_init_data){
526 		.name = "mpll_50m",
527 		.ops = &clk_regmap_mux_ro_ops,
528 		.parent_data = (const struct clk_parent_data []) {
529 			{ .fw_name = "xtal", },
530 			{ .hw = &s4_mpll_50m_div.hw },
531 		},
532 		.num_parents = 2,
533 	},
534 };
535 
536 static struct clk_fixed_factor s4_mpll_prediv = {
537 	.mult = 1,
538 	.div = 2,
539 	.hw.init = &(struct clk_init_data){
540 		.name = "mpll_prediv",
541 		.ops = &clk_fixed_factor_ops,
542 		.parent_hws = (const struct clk_hw *[]) {
543 			&s4_fixed_pll_dco.hw
544 		},
545 		.num_parents = 1,
546 	},
547 };
548 
549 static const struct reg_sequence s4_mpll0_init_regs[] = {
550 	{ .reg = ANACTRL_MPLL_CTRL2, .def = 0x40000033 }
551 };
552 
553 static struct clk_regmap s4_mpll0_div = {
554 	.data = &(struct meson_clk_mpll_data){
555 		.sdm = {
556 			.reg_off = ANACTRL_MPLL_CTRL1,
557 			.shift   = 0,
558 			.width   = 14,
559 		},
560 		.sdm_en = {
561 			.reg_off = ANACTRL_MPLL_CTRL1,
562 			.shift   = 30,
563 			.width	 = 1,
564 		},
565 		.n2 = {
566 			.reg_off = ANACTRL_MPLL_CTRL1,
567 			.shift   = 20,
568 			.width   = 9,
569 		},
570 		.ssen = {
571 			.reg_off = ANACTRL_MPLL_CTRL1,
572 			.shift   = 29,
573 			.width	 = 1,
574 		},
575 		.init_regs = s4_mpll0_init_regs,
576 		.init_count = ARRAY_SIZE(s4_mpll0_init_regs),
577 	},
578 	.hw.init = &(struct clk_init_data){
579 		.name = "mpll0_div",
580 		.ops = &meson_clk_mpll_ops,
581 		.parent_hws = (const struct clk_hw *[]) {
582 			&s4_mpll_prediv.hw
583 		},
584 		.num_parents = 1,
585 	},
586 };
587 
588 static struct clk_regmap s4_mpll0 = {
589 	.data = &(struct clk_regmap_gate_data){
590 		.offset = ANACTRL_MPLL_CTRL1,
591 		.bit_idx = 31,
592 	},
593 	.hw.init = &(struct clk_init_data){
594 		.name = "mpll0",
595 		.ops = &clk_regmap_gate_ops,
596 		.parent_hws = (const struct clk_hw *[]) { &s4_mpll0_div.hw },
597 		.num_parents = 1,
598 		.flags = CLK_SET_RATE_PARENT,
599 	},
600 };
601 
602 static const struct reg_sequence s4_mpll1_init_regs[] = {
603 	{ .reg = ANACTRL_MPLL_CTRL4,	.def = 0x40000033 }
604 };
605 
606 static struct clk_regmap s4_mpll1_div = {
607 	.data = &(struct meson_clk_mpll_data){
608 		.sdm = {
609 			.reg_off = ANACTRL_MPLL_CTRL3,
610 			.shift   = 0,
611 			.width   = 14,
612 		},
613 		.sdm_en = {
614 			.reg_off = ANACTRL_MPLL_CTRL3,
615 			.shift   = 30,
616 			.width	 = 1,
617 		},
618 		.n2 = {
619 			.reg_off = ANACTRL_MPLL_CTRL3,
620 			.shift   = 20,
621 			.width   = 9,
622 		},
623 		.ssen = {
624 			.reg_off = ANACTRL_MPLL_CTRL3,
625 			.shift   = 29,
626 			.width	 = 1,
627 		},
628 		.init_regs = s4_mpll1_init_regs,
629 		.init_count = ARRAY_SIZE(s4_mpll1_init_regs),
630 	},
631 	.hw.init = &(struct clk_init_data){
632 		.name = "mpll1_div",
633 		.ops = &meson_clk_mpll_ops,
634 		.parent_hws = (const struct clk_hw *[]) {
635 			&s4_mpll_prediv.hw
636 		},
637 		.num_parents = 1,
638 	},
639 };
640 
641 static struct clk_regmap s4_mpll1 = {
642 	.data = &(struct clk_regmap_gate_data){
643 		.offset = ANACTRL_MPLL_CTRL3,
644 		.bit_idx = 31,
645 	},
646 	.hw.init = &(struct clk_init_data){
647 		.name = "mpll1",
648 		.ops = &clk_regmap_gate_ops,
649 		.parent_hws = (const struct clk_hw *[]) { &s4_mpll1_div.hw },
650 		.num_parents = 1,
651 		.flags = CLK_SET_RATE_PARENT,
652 	},
653 };
654 
655 static const struct reg_sequence s4_mpll2_init_regs[] = {
656 	{ .reg = ANACTRL_MPLL_CTRL6, .def = 0x40000033 }
657 };
658 
659 static struct clk_regmap s4_mpll2_div = {
660 	.data = &(struct meson_clk_mpll_data){
661 		.sdm = {
662 			.reg_off = ANACTRL_MPLL_CTRL5,
663 			.shift   = 0,
664 			.width   = 14,
665 		},
666 		.sdm_en = {
667 			.reg_off = ANACTRL_MPLL_CTRL5,
668 			.shift   = 30,
669 			.width	 = 1,
670 		},
671 		.n2 = {
672 			.reg_off = ANACTRL_MPLL_CTRL5,
673 			.shift   = 20,
674 			.width   = 9,
675 		},
676 		.ssen = {
677 			.reg_off = ANACTRL_MPLL_CTRL5,
678 			.shift   = 29,
679 			.width	 = 1,
680 		},
681 		.init_regs = s4_mpll2_init_regs,
682 		.init_count = ARRAY_SIZE(s4_mpll2_init_regs),
683 	},
684 	.hw.init = &(struct clk_init_data){
685 		.name = "mpll2_div",
686 		.ops = &meson_clk_mpll_ops,
687 		.parent_hws = (const struct clk_hw *[]) {
688 			&s4_mpll_prediv.hw
689 		},
690 		.num_parents = 1,
691 	},
692 };
693 
694 static struct clk_regmap s4_mpll2 = {
695 	.data = &(struct clk_regmap_gate_data){
696 		.offset = ANACTRL_MPLL_CTRL5,
697 		.bit_idx = 31,
698 	},
699 	.hw.init = &(struct clk_init_data){
700 		.name = "mpll2",
701 		.ops = &clk_regmap_gate_ops,
702 		.parent_hws = (const struct clk_hw *[]) { &s4_mpll2_div.hw },
703 		.num_parents = 1,
704 		.flags = CLK_SET_RATE_PARENT,
705 	},
706 };
707 
708 static const struct reg_sequence s4_mpll3_init_regs[] = {
709 	{ .reg = ANACTRL_MPLL_CTRL8, .def = 0x40000033 }
710 };
711 
712 static struct clk_regmap s4_mpll3_div = {
713 	.data = &(struct meson_clk_mpll_data){
714 		.sdm = {
715 			.reg_off = ANACTRL_MPLL_CTRL7,
716 			.shift   = 0,
717 			.width   = 14,
718 		},
719 		.sdm_en = {
720 			.reg_off = ANACTRL_MPLL_CTRL7,
721 			.shift   = 30,
722 			.width	 = 1,
723 		},
724 		.n2 = {
725 			.reg_off = ANACTRL_MPLL_CTRL7,
726 			.shift   = 20,
727 			.width   = 9,
728 		},
729 		.ssen = {
730 			.reg_off = ANACTRL_MPLL_CTRL7,
731 			.shift   = 29,
732 			.width	 = 1,
733 		},
734 		.init_regs = s4_mpll3_init_regs,
735 		.init_count = ARRAY_SIZE(s4_mpll3_init_regs),
736 	},
737 	.hw.init = &(struct clk_init_data){
738 		.name = "mpll3_div",
739 		.ops = &meson_clk_mpll_ops,
740 		.parent_hws = (const struct clk_hw *[]) {
741 			&s4_mpll_prediv.hw
742 		},
743 		.num_parents = 1,
744 	},
745 };
746 
747 static struct clk_regmap s4_mpll3 = {
748 	.data = &(struct clk_regmap_gate_data){
749 		.offset = ANACTRL_MPLL_CTRL7,
750 		.bit_idx = 31,
751 	},
752 	.hw.init = &(struct clk_init_data){
753 		.name = "mpll3",
754 		.ops = &clk_regmap_gate_ops,
755 		.parent_hws = (const struct clk_hw *[]) { &s4_mpll3_div.hw },
756 		.num_parents = 1,
757 		.flags = CLK_SET_RATE_PARENT,
758 	},
759 };
760 
761 /* Array of all clocks provided by this provider */
762 static struct clk_hw *s4_pll_hw_clks[] = {
763 	[CLKID_FIXED_PLL_DCO]		= &s4_fixed_pll_dco.hw,
764 	[CLKID_FIXED_PLL]		= &s4_fixed_pll.hw,
765 	[CLKID_FCLK_DIV2_DIV]		= &s4_fclk_div2_div.hw,
766 	[CLKID_FCLK_DIV2]		= &s4_fclk_div2.hw,
767 	[CLKID_FCLK_DIV3_DIV]		= &s4_fclk_div3_div.hw,
768 	[CLKID_FCLK_DIV3]		= &s4_fclk_div3.hw,
769 	[CLKID_FCLK_DIV4_DIV]		= &s4_fclk_div4_div.hw,
770 	[CLKID_FCLK_DIV4]		= &s4_fclk_div4.hw,
771 	[CLKID_FCLK_DIV5_DIV]		= &s4_fclk_div5_div.hw,
772 	[CLKID_FCLK_DIV5]		= &s4_fclk_div5.hw,
773 	[CLKID_FCLK_DIV7_DIV]		= &s4_fclk_div7_div.hw,
774 	[CLKID_FCLK_DIV7]		= &s4_fclk_div7.hw,
775 	[CLKID_FCLK_DIV2P5_DIV]		= &s4_fclk_div2p5_div.hw,
776 	[CLKID_FCLK_DIV2P5]		= &s4_fclk_div2p5.hw,
777 	[CLKID_GP0_PLL_DCO]		= &s4_gp0_pll_dco.hw,
778 	[CLKID_GP0_PLL]			= &s4_gp0_pll.hw,
779 	[CLKID_HIFI_PLL_DCO]		= &s4_hifi_pll_dco.hw,
780 	[CLKID_HIFI_PLL]		= &s4_hifi_pll.hw,
781 	[CLKID_HDMI_PLL_DCO]		= &s4_hdmi_pll_dco.hw,
782 	[CLKID_HDMI_PLL_OD]		= &s4_hdmi_pll_od.hw,
783 	[CLKID_HDMI_PLL]		= &s4_hdmi_pll.hw,
784 	[CLKID_MPLL_50M_DIV]		= &s4_mpll_50m_div.hw,
785 	[CLKID_MPLL_50M]		= &s4_mpll_50m.hw,
786 	[CLKID_MPLL_PREDIV]		= &s4_mpll_prediv.hw,
787 	[CLKID_MPLL0_DIV]		= &s4_mpll0_div.hw,
788 	[CLKID_MPLL0]			= &s4_mpll0.hw,
789 	[CLKID_MPLL1_DIV]		= &s4_mpll1_div.hw,
790 	[CLKID_MPLL1]			= &s4_mpll1.hw,
791 	[CLKID_MPLL2_DIV]		= &s4_mpll2_div.hw,
792 	[CLKID_MPLL2]			= &s4_mpll2.hw,
793 	[CLKID_MPLL3_DIV]		= &s4_mpll3_div.hw,
794 	[CLKID_MPLL3]			= &s4_mpll3.hw,
795 };
796 
797 static const struct reg_sequence s4_init_regs[] = {
798 	{ .reg = ANACTRL_MPLL_CTRL0,	.def = 0x00000543 },
799 };
800 
801 static const struct regmap_config clkc_regmap_config = {
802 	.reg_bits       = 32,
803 	.val_bits       = 32,
804 	.reg_stride     = 4,
805 	.max_register   = ANACTRL_HDMIPLL_CTRL0,
806 };
807 
808 static struct meson_clk_hw_data s4_pll_clks = {
809 	.hws = s4_pll_hw_clks,
810 	.num = ARRAY_SIZE(s4_pll_hw_clks),
811 };
812 
813 static int meson_s4_pll_probe(struct platform_device *pdev)
814 {
815 	struct device *dev = &pdev->dev;
816 	struct regmap *regmap;
817 	void __iomem *base;
818 	int ret, i;
819 
820 	base = devm_platform_ioremap_resource(pdev, 0);
821 	if (IS_ERR(base))
822 		return dev_err_probe(dev, PTR_ERR(base),
823 				     "can't ioremap resource\n");
824 
825 	regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
826 	if (IS_ERR(regmap))
827 		return dev_err_probe(dev, PTR_ERR(regmap),
828 				     "can't init regmap mmio region\n");
829 
830 	ret = regmap_multi_reg_write(regmap, s4_init_regs, ARRAY_SIZE(s4_init_regs));
831 	if (ret)
832 		return dev_err_probe(dev, ret,
833 				     "Failed to init registers\n");
834 
835 	/* Register clocks */
836 	for (i = 0; i < s4_pll_clks.num; i++) {
837 		/* array might be sparse */
838 		if (!s4_pll_clks.hws[i])
839 			continue;
840 
841 		ret = devm_clk_hw_register(dev, s4_pll_clks.hws[i]);
842 		if (ret)
843 			return dev_err_probe(dev, ret,
844 					     "clock[%d] registration failed\n", i);
845 	}
846 
847 	return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
848 					   &s4_pll_clks);
849 }
850 
851 static const struct of_device_id clkc_match_table[] = {
852 	{
853 		.compatible = "amlogic,s4-pll-clkc",
854 	},
855 	{}
856 };
857 MODULE_DEVICE_TABLE(of, clkc_match_table);
858 
859 static struct platform_driver s4_driver = {
860 	.probe		= meson_s4_pll_probe,
861 	.driver		= {
862 		.name	= "s4-pll-clkc",
863 		.of_match_table = clkc_match_table,
864 	},
865 };
866 module_platform_driver(s4_driver);
867 
868 MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver");
869 MODULE_AUTHOR("Yu Tu <yu.tu@amlogic.com>");
870 MODULE_LICENSE("GPL");
871 MODULE_IMPORT_NS("CLK_MESON");
872