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