749 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Amlogic C3 PLL Controller Driver4 *5 * Copyright (c) 2023 Amlogic, inc.6 * Author: Chuan Liu <chuan.liu@amlogic.com>7 */8 9#include <linux/clk-provider.h>10#include <linux/platform_device.h>11#include "clk-regmap.h"12#include "clk-pll.h"13#include "meson-clkc-utils.h"14#include <dt-bindings/clock/amlogic,c3-pll-clkc.h>15 16#define ANACTRL_FIXPLL_CTRL4 0x5017#define ANACTRL_GP0PLL_CTRL0 0x8018#define ANACTRL_GP0PLL_CTRL1 0x8419#define ANACTRL_GP0PLL_CTRL2 0x8820#define ANACTRL_GP0PLL_CTRL3 0x8c21#define ANACTRL_GP0PLL_CTRL4 0x9022#define ANACTRL_GP0PLL_CTRL5 0x9423#define ANACTRL_GP0PLL_CTRL6 0x9824#define ANACTRL_HIFIPLL_CTRL0 0x10025#define ANACTRL_HIFIPLL_CTRL1 0x10426#define ANACTRL_HIFIPLL_CTRL2 0x10827#define ANACTRL_HIFIPLL_CTRL3 0x10c28#define ANACTRL_HIFIPLL_CTRL4 0x11029#define ANACTRL_HIFIPLL_CTRL5 0x11430#define ANACTRL_HIFIPLL_CTRL6 0x11831#define ANACTRL_MPLL_CTRL0 0x18032#define ANACTRL_MPLL_CTRL1 0x18433#define ANACTRL_MPLL_CTRL2 0x18834#define ANACTRL_MPLL_CTRL3 0x18c35#define ANACTRL_MPLL_CTRL4 0x19036 37static struct clk_regmap fclk_50m_en = {38 .data = &(struct clk_regmap_gate_data) {39 .offset = ANACTRL_FIXPLL_CTRL4,40 .bit_idx = 0,41 },42 .hw.init = &(struct clk_init_data) {43 .name = "fclk_50m_en",44 .ops = &clk_regmap_gate_ro_ops,45 .parent_data = &(const struct clk_parent_data) {46 .fw_name = "fix"47 },48 .num_parents = 1,49 },50};51 52static struct clk_fixed_factor fclk_50m = {53 .mult = 1,54 .div = 40,55 .hw.init = &(struct clk_init_data) {56 .name = "fclk_50m",57 .ops = &clk_fixed_factor_ops,58 .parent_hws = (const struct clk_hw *[]) {59 &fclk_50m_en.hw60 },61 .num_parents = 1,62 },63};64 65static struct clk_fixed_factor fclk_div2_div = {66 .mult = 1,67 .div = 2,68 .hw.init = &(struct clk_init_data) {69 .name = "fclk_div2_div",70 .ops = &clk_fixed_factor_ops,71 .parent_data = &(const struct clk_parent_data) {72 .fw_name = "fix"73 },74 .num_parents = 1,75 },76};77 78static struct clk_regmap fclk_div2 = {79 .data = &(struct clk_regmap_gate_data) {80 .offset = ANACTRL_FIXPLL_CTRL4,81 .bit_idx = 24,82 },83 .hw.init = &(struct clk_init_data) {84 .name = "fclk_div2",85 .ops = &clk_regmap_gate_ro_ops,86 .parent_hws = (const struct clk_hw *[]) {87 &fclk_div2_div.hw88 },89 .num_parents = 1,90 },91};92 93static struct clk_fixed_factor fclk_div2p5_div = {94 .mult = 2,95 .div = 5,96 .hw.init = &(struct clk_init_data) {97 .name = "fclk_div2p5_div",98 .ops = &clk_fixed_factor_ops,99 .parent_data = &(const struct clk_parent_data) {100 .fw_name = "fix"101 },102 .num_parents = 1,103 },104};105 106static struct clk_regmap fclk_div2p5 = {107 .data = &(struct clk_regmap_gate_data) {108 .offset = ANACTRL_FIXPLL_CTRL4,109 .bit_idx = 4,110 },111 .hw.init = &(struct clk_init_data) {112 .name = "fclk_div2p5",113 .ops = &clk_regmap_gate_ro_ops,114 .parent_hws = (const struct clk_hw *[]) {115 &fclk_div2p5_div.hw116 },117 .num_parents = 1,118 },119};120 121static struct clk_fixed_factor fclk_div3_div = {122 .mult = 1,123 .div = 3,124 .hw.init = &(struct clk_init_data) {125 .name = "fclk_div3_div",126 .ops = &clk_fixed_factor_ops,127 .parent_data = &(const struct clk_parent_data) {128 .fw_name = "fix"129 },130 .num_parents = 1,131 },132};133 134static struct clk_regmap fclk_div3 = {135 .data = &(struct clk_regmap_gate_data) {136 .offset = ANACTRL_FIXPLL_CTRL4,137 .bit_idx = 20,138 },139 .hw.init = &(struct clk_init_data) {140 .name = "fclk_div3",141 .ops = &clk_regmap_gate_ro_ops,142 .parent_hws = (const struct clk_hw *[]) {143 &fclk_div3_div.hw144 },145 .num_parents = 1,146 },147};148 149static struct clk_fixed_factor fclk_div4_div = {150 .mult = 1,151 .div = 4,152 .hw.init = &(struct clk_init_data) {153 .name = "fclk_div4_div",154 .ops = &clk_fixed_factor_ops,155 .parent_data = &(const struct clk_parent_data) {156 .fw_name = "fix"157 },158 .num_parents = 1,159 },160};161 162static struct clk_regmap fclk_div4 = {163 .data = &(struct clk_regmap_gate_data) {164 .offset = ANACTRL_FIXPLL_CTRL4,165 .bit_idx = 21,166 },167 .hw.init = &(struct clk_init_data) {168 .name = "fclk_div4",169 .ops = &clk_regmap_gate_ro_ops,170 .parent_hws = (const struct clk_hw *[]) {171 &fclk_div4_div.hw172 },173 .num_parents = 1,174 },175};176 177static struct clk_fixed_factor fclk_div5_div = {178 .mult = 1,179 .div = 5,180 .hw.init = &(struct clk_init_data) {181 .name = "fclk_div5_div",182 .ops = &clk_fixed_factor_ops,183 .parent_data = &(const struct clk_parent_data) {184 .fw_name = "fix"185 },186 .num_parents = 1,187 },188};189 190static struct clk_regmap fclk_div5 = {191 .data = &(struct clk_regmap_gate_data) {192 .offset = ANACTRL_FIXPLL_CTRL4,193 .bit_idx = 22,194 },195 .hw.init = &(struct clk_init_data) {196 .name = "fclk_div5",197 .ops = &clk_regmap_gate_ro_ops,198 .parent_hws = (const struct clk_hw *[]) {199 &fclk_div5_div.hw200 },201 .num_parents = 1,202 },203};204 205static struct clk_fixed_factor fclk_div7_div = {206 .mult = 1,207 .div = 7,208 .hw.init = &(struct clk_init_data) {209 .name = "fclk_div7_div",210 .ops = &clk_fixed_factor_ops,211 .parent_data = &(const struct clk_parent_data) {212 .fw_name = "fix"213 },214 .num_parents = 1,215 },216};217 218static struct clk_regmap fclk_div7 = {219 .data = &(struct clk_regmap_gate_data) {220 .offset = ANACTRL_FIXPLL_CTRL4,221 .bit_idx = 23,222 },223 .hw.init = &(struct clk_init_data) {224 .name = "fclk_div7",225 .ops = &clk_regmap_gate_ro_ops,226 .parent_hws = (const struct clk_hw *[]) {227 &fclk_div7_div.hw228 },229 .num_parents = 1,230 },231};232 233static const struct reg_sequence c3_gp0_init_regs[] = {234 { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x0 },235 { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 },236 { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x88770290 },237 { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x3927200a },238 { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x56540000 },239};240 241static const struct pll_mult_range c3_gp0_pll_mult_range = {242 .min = 125,243 .max = 250,244};245 246static struct clk_regmap gp0_pll_dco = {247 .data = &(struct meson_clk_pll_data) {248 .en = {249 .reg_off = ANACTRL_GP0PLL_CTRL0,250 .shift = 28,251 .width = 1,252 },253 .m = {254 .reg_off = ANACTRL_GP0PLL_CTRL0,255 .shift = 0,256 .width = 9,257 },258 .frac = {259 .reg_off = ANACTRL_GP0PLL_CTRL1,260 .shift = 0,261 .width = 19,262 },263 .n = {264 .reg_off = ANACTRL_GP0PLL_CTRL0,265 .shift = 10,266 .width = 5,267 },268 .l = {269 .reg_off = ANACTRL_GP0PLL_CTRL0,270 .shift = 31,271 .width = 1,272 },273 .rst = {274 .reg_off = ANACTRL_GP0PLL_CTRL0,275 .shift = 29,276 .width = 1,277 },278 .range = &c3_gp0_pll_mult_range,279 .init_regs = c3_gp0_init_regs,280 .init_count = ARRAY_SIZE(c3_gp0_init_regs),281 },282 .hw.init = &(struct clk_init_data) {283 .name = "gp0_pll_dco",284 .ops = &meson_clk_pll_ops,285 .parent_data = &(const struct clk_parent_data) {286 .fw_name = "top",287 },288 .num_parents = 1,289 },290};291 292/* The maximum frequency divider supports is 32, not 128(2^7) */293static const struct clk_div_table c3_gp0_pll_od_table[] = {294 { 0, 1 },295 { 1, 2 },296 { 2, 4 },297 { 3, 8 },298 { 4, 16 },299 { 5, 32 },300 { /* sentinel */ }301};302 303static struct clk_regmap gp0_pll = {304 .data = &(struct clk_regmap_div_data) {305 .offset = ANACTRL_GP0PLL_CTRL0,306 .shift = 16,307 .width = 3,308 .table = c3_gp0_pll_od_table,309 },310 .hw.init = &(struct clk_init_data) {311 .name = "gp0_pll",312 .ops = &clk_regmap_divider_ops,313 .parent_hws = (const struct clk_hw *[]) {314 &gp0_pll_dco.hw315 },316 .num_parents = 1,317 .flags = CLK_SET_RATE_PARENT,318 },319};320 321static const struct reg_sequence c3_hifi_init_regs[] = {322 { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x0 },323 { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 },324 { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 },325 { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x3927200a },326 { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x56540000 },327};328 329static struct clk_regmap hifi_pll_dco = {330 .data = &(struct meson_clk_pll_data) {331 .en = {332 .reg_off = ANACTRL_HIFIPLL_CTRL0,333 .shift = 28,334 .width = 1,335 },336 .m = {337 .reg_off = ANACTRL_HIFIPLL_CTRL0,338 .shift = 0,339 .width = 8,340 },341 .frac = {342 .reg_off = ANACTRL_HIFIPLL_CTRL1,343 .shift = 0,344 .width = 19,345 },346 .n = {347 .reg_off = ANACTRL_HIFIPLL_CTRL0,348 .shift = 10,349 .width = 5,350 },351 .l = {352 .reg_off = ANACTRL_HIFIPLL_CTRL0,353 .shift = 31,354 .width = 1,355 },356 .rst = {357 .reg_off = ANACTRL_HIFIPLL_CTRL0,358 .shift = 29,359 .width = 1,360 },361 .range = &c3_gp0_pll_mult_range,362 .init_regs = c3_hifi_init_regs,363 .init_count = ARRAY_SIZE(c3_hifi_init_regs),364 },365 .hw.init = &(struct clk_init_data) {366 .name = "hifi_pll_dco",367 .ops = &meson_clk_pll_ops,368 .parent_data = &(const struct clk_parent_data) {369 .fw_name = "top",370 },371 .num_parents = 1,372 },373};374 375static struct clk_regmap hifi_pll = {376 .data = &(struct clk_regmap_div_data) {377 .offset = ANACTRL_HIFIPLL_CTRL0,378 .shift = 16,379 .width = 2,380 .flags = CLK_DIVIDER_POWER_OF_TWO,381 },382 .hw.init = &(struct clk_init_data) {383 .name = "hifi_pll",384 .ops = &clk_regmap_divider_ops,385 .parent_hws = (const struct clk_hw *[]) {386 &hifi_pll_dco.hw387 },388 .num_parents = 1,389 .flags = CLK_SET_RATE_PARENT,390 },391};392 393static const struct reg_sequence c3_mclk_init_regs[] = {394 { .reg = ANACTRL_MPLL_CTRL1, .def = 0x1420500f },395 { .reg = ANACTRL_MPLL_CTRL2, .def = 0x00023041 },396 { .reg = ANACTRL_MPLL_CTRL3, .def = 0x18180000 },397 { .reg = ANACTRL_MPLL_CTRL2, .def = 0x00023001 }398};399 400static const struct pll_mult_range c3_mclk_pll_mult_range = {401 .min = 67,402 .max = 133,403};404 405static struct clk_regmap mclk_pll_dco = {406 .data = &(struct meson_clk_pll_data) {407 .en = {408 .reg_off = ANACTRL_MPLL_CTRL0,409 .shift = 28,410 .width = 1,411 },412 .m = {413 .reg_off = ANACTRL_MPLL_CTRL0,414 .shift = 0,415 .width = 8,416 },417 .n = {418 .reg_off = ANACTRL_MPLL_CTRL0,419 .shift = 16,420 .width = 5,421 },422 .l = {423 .reg_off = ANACTRL_MPLL_CTRL0,424 .shift = 31,425 .width = 1,426 },427 .rst = {428 .reg_off = ANACTRL_MPLL_CTRL0,429 .shift = 29,430 .width = 1,431 },432 .range = &c3_mclk_pll_mult_range,433 .init_regs = c3_mclk_init_regs,434 .init_count = ARRAY_SIZE(c3_mclk_init_regs),435 },436 .hw.init = &(struct clk_init_data) {437 .name = "mclk_pll_dco",438 .ops = &meson_clk_pll_ops,439 .parent_data = &(const struct clk_parent_data) {440 .fw_name = "mclk",441 },442 .num_parents = 1,443 },444};445 446static const struct clk_div_table c3_mpll_od_table[] = {447 { 0, 1 },448 { 1, 2 },449 { 2, 4 },450 { 3, 8 },451 { 4, 16 },452 { /* sentinel */ }453};454 455static struct clk_regmap mclk_pll_od = {456 .data = &(struct clk_regmap_div_data) {457 .offset = ANACTRL_MPLL_CTRL0,458 .shift = 12,459 .width = 3,460 .table = c3_mpll_od_table,461 },462 .hw.init = &(struct clk_init_data) {463 .name = "mclk_pll_od",464 .ops = &clk_regmap_divider_ops,465 .parent_hws = (const struct clk_hw *[]) {466 &mclk_pll_dco.hw },467 .num_parents = 1,468 .flags = CLK_SET_RATE_PARENT,469 },470};471 472/* both value 0 and 1 gives divide the input rate by one */473static struct clk_regmap mclk_pll = {474 .data = &(struct clk_regmap_div_data) {475 .offset = ANACTRL_MPLL_CTRL4,476 .shift = 16,477 .width = 5,478 .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,479 },480 .hw.init = &(struct clk_init_data) {481 .name = "mclk_pll",482 .ops = &clk_regmap_divider_ops,483 .parent_hws = (const struct clk_hw *[]) {484 &mclk_pll_od.hw485 },486 .num_parents = 1,487 .flags = CLK_SET_RATE_PARENT,488 },489};490 491static const struct clk_parent_data mclk_parent[] = {492 { .hw = &mclk_pll.hw },493 { .fw_name = "mclk" },494 { .hw = &fclk_50m.hw }495};496 497static struct clk_regmap mclk0_sel = {498 .data = &(struct clk_regmap_mux_data) {499 .offset = ANACTRL_MPLL_CTRL4,500 .mask = 0x3,501 .shift = 4,502 },503 .hw.init = &(struct clk_init_data) {504 .name = "mclk0_sel",505 .ops = &clk_regmap_mux_ops,506 .parent_data = mclk_parent,507 .num_parents = ARRAY_SIZE(mclk_parent),508 },509};510 511static struct clk_regmap mclk0_div_en = {512 .data = &(struct clk_regmap_gate_data) {513 .offset = ANACTRL_MPLL_CTRL4,514 .bit_idx = 1,515 },516 .hw.init = &(struct clk_init_data) {517 .name = "mclk0_div_en",518 .ops = &clk_regmap_gate_ops,519 .parent_hws = (const struct clk_hw *[]) {520 &mclk0_sel.hw521 },522 .num_parents = 1,523 .flags = CLK_SET_RATE_PARENT,524 },525};526 527static struct clk_regmap mclk0_div = {528 .data = &(struct clk_regmap_div_data) {529 .offset = ANACTRL_MPLL_CTRL4,530 .shift = 2,531 .width = 1,532 },533 .hw.init = &(struct clk_init_data) {534 .name = "mclk0_div",535 .ops = &clk_regmap_divider_ops,536 .parent_hws = (const struct clk_hw *[]) {537 &mclk0_div_en.hw538 },539 .num_parents = 1,540 .flags = CLK_SET_RATE_PARENT,541 },542};543 544static struct clk_regmap mclk0 = {545 .data = &(struct clk_regmap_gate_data) {546 .offset = ANACTRL_MPLL_CTRL4,547 .bit_idx = 0,548 },549 .hw.init = &(struct clk_init_data) {550 .name = "mclk0",551 .ops = &clk_regmap_gate_ops,552 .parent_hws = (const struct clk_hw *[]) {553 &mclk0_div.hw554 },555 .num_parents = 1,556 .flags = CLK_SET_RATE_PARENT,557 },558};559 560static struct clk_regmap mclk1_sel = {561 .data = &(struct clk_regmap_mux_data) {562 .offset = ANACTRL_MPLL_CTRL4,563 .mask = 0x3,564 .shift = 12,565 },566 .hw.init = &(struct clk_init_data) {567 .name = "mclk1_sel",568 .ops = &clk_regmap_mux_ops,569 .parent_data = mclk_parent,570 .num_parents = ARRAY_SIZE(mclk_parent),571 },572};573 574static struct clk_regmap mclk1_div_en = {575 .data = &(struct clk_regmap_gate_data) {576 .offset = ANACTRL_MPLL_CTRL4,577 .bit_idx = 9,578 },579 .hw.init = &(struct clk_init_data) {580 .name = "mclk1_div_en",581 .ops = &clk_regmap_gate_ops,582 .parent_hws = (const struct clk_hw *[]) {583 &mclk1_sel.hw584 },585 .num_parents = 1,586 .flags = CLK_SET_RATE_PARENT,587 },588};589 590static struct clk_regmap mclk1_div = {591 .data = &(struct clk_regmap_div_data) {592 .offset = ANACTRL_MPLL_CTRL4,593 .shift = 10,594 .width = 1,595 },596 .hw.init = &(struct clk_init_data) {597 .name = "mclk1_div",598 .ops = &clk_regmap_divider_ops,599 .parent_hws = (const struct clk_hw *[]) {600 &mclk1_div_en.hw601 },602 .num_parents = 1,603 .flags = CLK_SET_RATE_PARENT,604 },605};606 607static struct clk_regmap mclk1 = {608 .data = &(struct clk_regmap_gate_data) {609 .offset = ANACTRL_MPLL_CTRL4,610 .bit_idx = 8,611 },612 .hw.init = &(struct clk_init_data) {613 .name = "mclk1",614 .ops = &clk_regmap_gate_ops,615 .parent_hws = (const struct clk_hw *[]) {616 &mclk1_div.hw617 },618 .num_parents = 1,619 .flags = CLK_SET_RATE_PARENT,620 },621};622 623static struct clk_hw *c3_pll_hw_clks[] = {624 [CLKID_FCLK_50M_EN] = &fclk_50m_en.hw,625 [CLKID_FCLK_50M] = &fclk_50m.hw,626 [CLKID_FCLK_DIV2_DIV] = &fclk_div2_div.hw,627 [CLKID_FCLK_DIV2] = &fclk_div2.hw,628 [CLKID_FCLK_DIV2P5_DIV] = &fclk_div2p5_div.hw,629 [CLKID_FCLK_DIV2P5] = &fclk_div2p5.hw,630 [CLKID_FCLK_DIV3_DIV] = &fclk_div3_div.hw,631 [CLKID_FCLK_DIV3] = &fclk_div3.hw,632 [CLKID_FCLK_DIV4_DIV] = &fclk_div4_div.hw,633 [CLKID_FCLK_DIV4] = &fclk_div4.hw,634 [CLKID_FCLK_DIV5_DIV] = &fclk_div5_div.hw,635 [CLKID_FCLK_DIV5] = &fclk_div5.hw,636 [CLKID_FCLK_DIV7_DIV] = &fclk_div7_div.hw,637 [CLKID_FCLK_DIV7] = &fclk_div7.hw,638 [CLKID_GP0_PLL_DCO] = &gp0_pll_dco.hw,639 [CLKID_GP0_PLL] = &gp0_pll.hw,640 [CLKID_HIFI_PLL_DCO] = &hifi_pll_dco.hw,641 [CLKID_HIFI_PLL] = &hifi_pll.hw,642 [CLKID_MCLK_PLL_DCO] = &mclk_pll_dco.hw,643 [CLKID_MCLK_PLL_OD] = &mclk_pll_od.hw,644 [CLKID_MCLK_PLL] = &mclk_pll.hw,645 [CLKID_MCLK0_SEL] = &mclk0_sel.hw,646 [CLKID_MCLK0_SEL_EN] = &mclk0_div_en.hw,647 [CLKID_MCLK0_DIV] = &mclk0_div.hw,648 [CLKID_MCLK0] = &mclk0.hw,649 [CLKID_MCLK1_SEL] = &mclk1_sel.hw,650 [CLKID_MCLK1_SEL_EN] = &mclk1_div_en.hw,651 [CLKID_MCLK1_DIV] = &mclk1_div.hw,652 [CLKID_MCLK1] = &mclk1.hw653};654 655/* Convenience table to populate regmap in .probe */656static struct clk_regmap *const c3_pll_clk_regmaps[] = {657 &fclk_50m_en,658 &fclk_div2,659 &fclk_div2p5,660 &fclk_div3,661 &fclk_div4,662 &fclk_div5,663 &fclk_div7,664 &gp0_pll_dco,665 &gp0_pll,666 &hifi_pll_dco,667 &hifi_pll,668 &mclk_pll_dco,669 &mclk_pll_od,670 &mclk_pll,671 &mclk0_sel,672 &mclk0_div_en,673 &mclk0_div,674 &mclk0,675 &mclk1_sel,676 &mclk1_div_en,677 &mclk1_div,678 &mclk1,679};680 681static const struct regmap_config clkc_regmap_config = {682 .reg_bits = 32,683 .val_bits = 32,684 .reg_stride = 4,685 .max_register = ANACTRL_MPLL_CTRL4,686};687 688static struct meson_clk_hw_data c3_pll_clks = {689 .hws = c3_pll_hw_clks,690 .num = ARRAY_SIZE(c3_pll_hw_clks),691};692 693static int c3_pll_probe(struct platform_device *pdev)694{695 struct device *dev = &pdev->dev;696 struct regmap *regmap;697 void __iomem *base;698 int clkid, ret, i;699 700 base = devm_platform_ioremap_resource(pdev, 0);701 if (IS_ERR(base))702 return PTR_ERR(base);703 704 regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);705 if (IS_ERR(regmap))706 return PTR_ERR(regmap);707 708 /* Populate regmap for the regmap backed clocks */709 for (i = 0; i < ARRAY_SIZE(c3_pll_clk_regmaps); i++)710 c3_pll_clk_regmaps[i]->map = regmap;711 712 for (clkid = 0; clkid < c3_pll_clks.num; clkid++) {713 /* array might be sparse */714 if (!c3_pll_clks.hws[clkid])715 continue;716 717 ret = devm_clk_hw_register(dev, c3_pll_clks.hws[clkid]);718 if (ret) {719 dev_err(dev, "Clock registration failed\n");720 return ret;721 }722 }723 724 return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,725 &c3_pll_clks);726}727 728static const struct of_device_id c3_pll_clkc_match_table[] = {729 {730 .compatible = "amlogic,c3-pll-clkc",731 },732 {}733};734MODULE_DEVICE_TABLE(of, c3_pll_clkc_match_table);735 736static struct platform_driver c3_pll_driver = {737 .probe = c3_pll_probe,738 .driver = {739 .name = "c3-pll-clkc",740 .of_match_table = c3_pll_clkc_match_table,741 },742};743module_platform_driver(c3_pll_driver);744 745MODULE_DESCRIPTION("Amlogic C3 PLL Clock Controller driver");746MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>");747MODULE_LICENSE("GPL");748MODULE_IMPORT_NS(CLK_MESON);749