1 // SPDX-License-Identifier: (GPL-2.0-only OR MIT)
3 * Amlogic S4 PLL Clock Controller Driver
5 * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved
6 * Author: Yu Tu <yu.tu@amlogic.com>
9 #include <linux/clk-provider.h>
10 #include <linux/of_device.h>
11 #include <linux/platform_device.h>
15 #include "clk-regmap.h"
17 #include "meson-clkc-utils.h"
18 #include <dt-bindings/clock/amlogic,s4-pll-clkc.h>
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.
27 static struct clk_regmap s4_fixed_pll_dco
= {
28 .data
= &(struct meson_clk_pll_data
){
30 .reg_off
= ANACTRL_FIXPLL_CTRL0
,
35 .reg_off
= ANACTRL_FIXPLL_CTRL0
,
40 .reg_off
= ANACTRL_FIXPLL_CTRL1
,
45 .reg_off
= ANACTRL_FIXPLL_CTRL0
,
50 .reg_off
= ANACTRL_FIXPLL_CTRL0
,
55 .reg_off
= ANACTRL_FIXPLL_CTRL0
,
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", }
70 static struct clk_regmap s4_fixed_pll
= {
71 .data
= &(struct clk_regmap_div_data
){
72 .offset
= ANACTRL_FIXPLL_CTRL0
,
75 .flags
= CLK_DIVIDER_POWER_OF_TWO
,
77 .hw
.init
= &(struct clk_init_data
){
79 .ops
= &clk_regmap_divider_ro_ops
,
80 .parent_hws
= (const struct clk_hw
*[]) {
85 * This clock won't ever change at runtime so
86 * CLK_SET_RATE_PARENT is not required
91 static struct clk_fixed_factor s4_fclk_div2_div
= {
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
},
102 static struct clk_regmap s4_fclk_div2
= {
103 .data
= &(struct clk_regmap_gate_data
){
104 .offset
= ANACTRL_FIXPLL_CTRL1
,
107 .hw
.init
= &(struct clk_init_data
){
109 .ops
= &clk_regmap_gate_ro_ops
,
110 .parent_hws
= (const struct clk_hw
*[]) {
117 static struct clk_fixed_factor s4_fclk_div3_div
= {
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
},
128 static struct clk_regmap s4_fclk_div3
= {
129 .data
= &(struct clk_regmap_gate_data
){
130 .offset
= ANACTRL_FIXPLL_CTRL1
,
133 .hw
.init
= &(struct clk_init_data
){
135 .ops
= &clk_regmap_gate_ro_ops
,
136 .parent_hws
= (const struct clk_hw
*[]) {
143 static struct clk_fixed_factor s4_fclk_div4_div
= {
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
},
154 static struct clk_regmap s4_fclk_div4
= {
155 .data
= &(struct clk_regmap_gate_data
){
156 .offset
= ANACTRL_FIXPLL_CTRL1
,
159 .hw
.init
= &(struct clk_init_data
){
161 .ops
= &clk_regmap_gate_ro_ops
,
162 .parent_hws
= (const struct clk_hw
*[]) {
169 static struct clk_fixed_factor s4_fclk_div5_div
= {
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
},
180 static struct clk_regmap s4_fclk_div5
= {
181 .data
= &(struct clk_regmap_gate_data
){
182 .offset
= ANACTRL_FIXPLL_CTRL1
,
185 .hw
.init
= &(struct clk_init_data
){
187 .ops
= &clk_regmap_gate_ro_ops
,
188 .parent_hws
= (const struct clk_hw
*[]) {
195 static struct clk_fixed_factor s4_fclk_div7_div
= {
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
},
206 static struct clk_regmap s4_fclk_div7
= {
207 .data
= &(struct clk_regmap_gate_data
){
208 .offset
= ANACTRL_FIXPLL_CTRL1
,
211 .hw
.init
= &(struct clk_init_data
){
213 .ops
= &clk_regmap_gate_ro_ops
,
214 .parent_hws
= (const struct clk_hw
*[]) {
221 static struct clk_fixed_factor s4_fclk_div2p5_div
= {
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
*[]) {
234 static struct clk_regmap s4_fclk_div2p5
= {
235 .data
= &(struct clk_regmap_gate_data
){
236 .offset
= ANACTRL_FIXPLL_CTRL1
,
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
249 static const struct pll_mult_range s4_gp0_pll_mult_range
= {
255 * Internal gp0 pll emulation configuration parameters
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 }
266 static struct clk_regmap s4_gp0_pll_dco
= {
267 .data
= &(struct meson_clk_pll_data
){
269 .reg_off
= ANACTRL_GP0PLL_CTRL0
,
274 .reg_off
= ANACTRL_GP0PLL_CTRL0
,
279 .reg_off
= ANACTRL_GP0PLL_CTRL0
,
284 .reg_off
= ANACTRL_GP0PLL_CTRL0
,
289 .reg_off
= ANACTRL_GP0PLL_CTRL0
,
293 .range
= &s4_gp0_pll_mult_range
,
294 .init_regs
= s4_gp0_init_regs
,
295 .init_count
= ARRAY_SIZE(s4_gp0_init_regs
),
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", }
307 static struct clk_regmap s4_gp0_pll
= {
308 .data
= &(struct clk_regmap_div_data
){
309 .offset
= ANACTRL_GP0PLL_CTRL0
,
312 .flags
= (CLK_DIVIDER_POWER_OF_TWO
|
313 CLK_DIVIDER_ROUND_CLOSEST
),
315 .hw
.init
= &(struct clk_init_data
){
317 .ops
= &clk_regmap_divider_ops
,
318 .parent_hws
= (const struct clk_hw
*[]) {
322 .flags
= CLK_SET_RATE_PARENT
,
327 * Internal hifi pll emulation configuration parameters
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 }
337 static struct clk_regmap s4_hifi_pll_dco
= {
338 .data
= &(struct meson_clk_pll_data
){
340 .reg_off
= ANACTRL_HIFIPLL_CTRL0
,
345 .reg_off
= ANACTRL_HIFIPLL_CTRL0
,
350 .reg_off
= ANACTRL_HIFIPLL_CTRL0
,
355 .reg_off
= ANACTRL_HIFIPLL_CTRL1
,
360 .reg_off
= ANACTRL_HIFIPLL_CTRL0
,
365 .reg_off
= ANACTRL_HIFIPLL_CTRL0
,
369 .range
= &s4_gp0_pll_mult_range
,
370 .init_regs
= s4_hifi_init_regs
,
371 .init_count
= ARRAY_SIZE(s4_hifi_init_regs
),
373 .flags
= CLK_MESON_PLL_ROUND_CLOSEST
,
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", }
385 static struct clk_regmap s4_hifi_pll
= {
386 .data
= &(struct clk_regmap_div_data
){
387 .offset
= ANACTRL_HIFIPLL_CTRL0
,
390 .flags
= (CLK_DIVIDER_POWER_OF_TWO
|
391 CLK_DIVIDER_ROUND_CLOSEST
),
393 .hw
.init
= &(struct clk_init_data
){
395 .ops
= &clk_regmap_divider_ops
,
396 .parent_hws
= (const struct clk_hw
*[]) {
400 .flags
= CLK_SET_RATE_PARENT
,
404 static struct clk_regmap s4_hdmi_pll_dco
= {
405 .data
= &(struct meson_clk_pll_data
){
407 .reg_off
= ANACTRL_HDMIPLL_CTRL0
,
412 .reg_off
= ANACTRL_HDMIPLL_CTRL0
,
417 .reg_off
= ANACTRL_HDMIPLL_CTRL0
,
422 .reg_off
= ANACTRL_HDMIPLL_CTRL0
,
427 .reg_off
= ANACTRL_HDMIPLL_CTRL0
,
431 .range
= &s4_gp0_pll_mult_range
,
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", }
443 static struct clk_regmap s4_hdmi_pll_od
= {
444 .data
= &(struct clk_regmap_div_data
){
445 .offset
= ANACTRL_HDMIPLL_CTRL0
,
448 .flags
= CLK_DIVIDER_POWER_OF_TWO
,
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
*[]) {
457 .flags
= CLK_SET_RATE_PARENT
,
461 static struct clk_regmap s4_hdmi_pll
= {
462 .data
= &(struct clk_regmap_div_data
){
463 .offset
= ANACTRL_HDMIPLL_CTRL0
,
466 .flags
= CLK_DIVIDER_POWER_OF_TWO
,
468 .hw
.init
= &(struct clk_init_data
){
470 .ops
= &clk_regmap_divider_ops
,
471 .parent_hws
= (const struct clk_hw
*[]) {
475 .flags
= CLK_SET_RATE_PARENT
,
479 static struct clk_fixed_factor s4_mpll_50m_div
= {
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
*[]) {
492 static struct clk_regmap s4_mpll_50m
= {
493 .data
= &(struct clk_regmap_mux_data
){
494 .offset
= ANACTRL_FIXPLL_CTRL3
,
498 .hw
.init
= &(struct clk_init_data
){
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
},
509 static struct clk_fixed_factor s4_mpll_prediv
= {
512 .hw
.init
= &(struct clk_init_data
){
513 .name
= "mpll_prediv",
514 .ops
= &clk_fixed_factor_ops
,
515 .parent_hws
= (const struct clk_hw
*[]) {
522 static const struct reg_sequence s4_mpll0_init_regs
[] = {
523 { .reg
= ANACTRL_MPLL_CTRL2
, .def
= 0x40000033 }
526 static struct clk_regmap s4_mpll0_div
= {
527 .data
= &(struct meson_clk_mpll_data
){
529 .reg_off
= ANACTRL_MPLL_CTRL1
,
534 .reg_off
= ANACTRL_MPLL_CTRL1
,
539 .reg_off
= ANACTRL_MPLL_CTRL1
,
544 .reg_off
= ANACTRL_MPLL_CTRL1
,
548 .init_regs
= s4_mpll0_init_regs
,
549 .init_count
= ARRAY_SIZE(s4_mpll0_init_regs
),
551 .hw
.init
= &(struct clk_init_data
){
553 .ops
= &meson_clk_mpll_ops
,
554 .parent_hws
= (const struct clk_hw
*[]) {
561 static struct clk_regmap s4_mpll0
= {
562 .data
= &(struct clk_regmap_gate_data
){
563 .offset
= ANACTRL_MPLL_CTRL1
,
566 .hw
.init
= &(struct clk_init_data
){
568 .ops
= &clk_regmap_gate_ops
,
569 .parent_hws
= (const struct clk_hw
*[]) { &s4_mpll0_div
.hw
},
571 .flags
= CLK_SET_RATE_PARENT
,
575 static const struct reg_sequence s4_mpll1_init_regs
[] = {
576 { .reg
= ANACTRL_MPLL_CTRL4
, .def
= 0x40000033 }
579 static struct clk_regmap s4_mpll1_div
= {
580 .data
= &(struct meson_clk_mpll_data
){
582 .reg_off
= ANACTRL_MPLL_CTRL3
,
587 .reg_off
= ANACTRL_MPLL_CTRL3
,
592 .reg_off
= ANACTRL_MPLL_CTRL3
,
597 .reg_off
= ANACTRL_MPLL_CTRL3
,
601 .init_regs
= s4_mpll1_init_regs
,
602 .init_count
= ARRAY_SIZE(s4_mpll1_init_regs
),
604 .hw
.init
= &(struct clk_init_data
){
606 .ops
= &meson_clk_mpll_ops
,
607 .parent_hws
= (const struct clk_hw
*[]) {
614 static struct clk_regmap s4_mpll1
= {
615 .data
= &(struct clk_regmap_gate_data
){
616 .offset
= ANACTRL_MPLL_CTRL3
,
619 .hw
.init
= &(struct clk_init_data
){
621 .ops
= &clk_regmap_gate_ops
,
622 .parent_hws
= (const struct clk_hw
*[]) { &s4_mpll1_div
.hw
},
624 .flags
= CLK_SET_RATE_PARENT
,
628 static const struct reg_sequence s4_mpll2_init_regs
[] = {
629 { .reg
= ANACTRL_MPLL_CTRL6
, .def
= 0x40000033 }
632 static struct clk_regmap s4_mpll2_div
= {
633 .data
= &(struct meson_clk_mpll_data
){
635 .reg_off
= ANACTRL_MPLL_CTRL5
,
640 .reg_off
= ANACTRL_MPLL_CTRL5
,
645 .reg_off
= ANACTRL_MPLL_CTRL5
,
650 .reg_off
= ANACTRL_MPLL_CTRL5
,
654 .init_regs
= s4_mpll2_init_regs
,
655 .init_count
= ARRAY_SIZE(s4_mpll2_init_regs
),
657 .hw
.init
= &(struct clk_init_data
){
659 .ops
= &meson_clk_mpll_ops
,
660 .parent_hws
= (const struct clk_hw
*[]) {
667 static struct clk_regmap s4_mpll2
= {
668 .data
= &(struct clk_regmap_gate_data
){
669 .offset
= ANACTRL_MPLL_CTRL5
,
672 .hw
.init
= &(struct clk_init_data
){
674 .ops
= &clk_regmap_gate_ops
,
675 .parent_hws
= (const struct clk_hw
*[]) { &s4_mpll2_div
.hw
},
677 .flags
= CLK_SET_RATE_PARENT
,
681 static const struct reg_sequence s4_mpll3_init_regs
[] = {
682 { .reg
= ANACTRL_MPLL_CTRL8
, .def
= 0x40000033 }
685 static struct clk_regmap s4_mpll3_div
= {
686 .data
= &(struct meson_clk_mpll_data
){
688 .reg_off
= ANACTRL_MPLL_CTRL7
,
693 .reg_off
= ANACTRL_MPLL_CTRL7
,
698 .reg_off
= ANACTRL_MPLL_CTRL7
,
703 .reg_off
= ANACTRL_MPLL_CTRL7
,
707 .init_regs
= s4_mpll3_init_regs
,
708 .init_count
= ARRAY_SIZE(s4_mpll3_init_regs
),
710 .hw
.init
= &(struct clk_init_data
){
712 .ops
= &meson_clk_mpll_ops
,
713 .parent_hws
= (const struct clk_hw
*[]) {
720 static struct clk_regmap s4_mpll3
= {
721 .data
= &(struct clk_regmap_gate_data
){
722 .offset
= ANACTRL_MPLL_CTRL7
,
725 .hw
.init
= &(struct clk_init_data
){
727 .ops
= &clk_regmap_gate_ops
,
728 .parent_hws
= (const struct clk_hw
*[]) { &s4_mpll3_div
.hw
},
730 .flags
= CLK_SET_RATE_PARENT
,
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
,
770 static struct clk_regmap
*const s4_pll_clk_regmaps
[] = {
797 static const struct reg_sequence s4_init_regs
[] = {
798 { .reg
= ANACTRL_MPLL_CTRL0
, .def
= 0x00000543 },
801 static const struct regmap_config clkc_regmap_config
= {
805 .max_register
= ANACTRL_HDMIPLL_CTRL0
,
808 static struct meson_clk_hw_data s4_pll_clks
= {
809 .hws
= s4_pll_hw_clks
,
810 .num
= ARRAY_SIZE(s4_pll_hw_clks
),
813 static int meson_s4_pll_probe(struct platform_device
*pdev
)
815 struct device
*dev
= &pdev
->dev
;
816 struct regmap
*regmap
;
820 base
= devm_platform_ioremap_resource(pdev
, 0);
822 return dev_err_probe(dev
, PTR_ERR(base
),
823 "can't ioremap resource\n");
825 regmap
= devm_regmap_init_mmio(dev
, base
, &clkc_regmap_config
);
827 return dev_err_probe(dev
, PTR_ERR(regmap
),
828 "can't init regmap mmio region\n");
830 ret
= regmap_multi_reg_write(regmap
, s4_init_regs
, ARRAY_SIZE(s4_init_regs
));
832 return dev_err_probe(dev
, ret
,
833 "Failed to init registers\n");
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
;
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
])
845 ret
= devm_clk_hw_register(dev
, s4_pll_clks
.hws
[i
]);
847 return dev_err_probe(dev
, ret
,
848 "clock[%d] registration failed\n", i
);
851 return devm_of_clk_add_hw_provider(dev
, meson_clk_hw_get
,
855 static const struct of_device_id clkc_match_table
[] = {
857 .compatible
= "amlogic,s4-pll-clkc",
861 MODULE_DEVICE_TABLE(of
, clkc_match_table
);
863 static struct platform_driver s4_driver
= {
864 .probe
= meson_s4_pll_probe
,
866 .name
= "s4-pll-clkc",
867 .of_match_table
= clkc_match_table
,
870 module_platform_driver(s4_driver
);
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
);