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