1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Amlogic C3 PLL Controller Driver 4 * 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 0x50 17 #define ANACTRL_GP0PLL_CTRL0 0x80 18 #define ANACTRL_GP0PLL_CTRL1 0x84 19 #define ANACTRL_GP0PLL_CTRL2 0x88 20 #define ANACTRL_GP0PLL_CTRL3 0x8c 21 #define ANACTRL_GP0PLL_CTRL4 0x90 22 #define ANACTRL_GP0PLL_CTRL5 0x94 23 #define ANACTRL_GP0PLL_CTRL6 0x98 24 #define ANACTRL_HIFIPLL_CTRL0 0x100 25 #define ANACTRL_HIFIPLL_CTRL1 0x104 26 #define ANACTRL_HIFIPLL_CTRL2 0x108 27 #define ANACTRL_HIFIPLL_CTRL3 0x10c 28 #define ANACTRL_HIFIPLL_CTRL4 0x110 29 #define ANACTRL_HIFIPLL_CTRL5 0x114 30 #define ANACTRL_HIFIPLL_CTRL6 0x118 31 #define ANACTRL_MPLL_CTRL0 0x180 32 #define ANACTRL_MPLL_CTRL1 0x184 33 #define ANACTRL_MPLL_CTRL2 0x188 34 #define ANACTRL_MPLL_CTRL3 0x18c 35 #define ANACTRL_MPLL_CTRL4 0x190 36 37 static 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 52 static 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.hw 60 }, 61 .num_parents = 1, 62 }, 63 }; 64 65 static 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 78 static 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.hw 88 }, 89 .num_parents = 1, 90 }, 91 }; 92 93 static 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 106 static 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.hw 116 }, 117 .num_parents = 1, 118 }, 119 }; 120 121 static 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 134 static 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.hw 144 }, 145 .num_parents = 1, 146 }, 147 }; 148 149 static 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 162 static 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.hw 172 }, 173 .num_parents = 1, 174 }, 175 }; 176 177 static 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 190 static 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.hw 200 }, 201 .num_parents = 1, 202 }, 203 }; 204 205 static 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 218 static 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.hw 228 }, 229 .num_parents = 1, 230 }, 231 }; 232 233 static 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 241 static const struct pll_mult_range c3_gp0_pll_mult_range = { 242 .min = 125, 243 .max = 250, 244 }; 245 246 static 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) */ 293 static 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 303 static 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.hw 315 }, 316 .num_parents = 1, 317 .flags = CLK_SET_RATE_PARENT, 318 }, 319 }; 320 321 static 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 329 static 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 .frac_max = 100000, 365 }, 366 .hw.init = &(struct clk_init_data) { 367 .name = "hifi_pll_dco", 368 .ops = &meson_clk_pll_ops, 369 .parent_data = &(const struct clk_parent_data) { 370 .fw_name = "top", 371 }, 372 .num_parents = 1, 373 }, 374 }; 375 376 static struct clk_regmap hifi_pll = { 377 .data = &(struct clk_regmap_div_data) { 378 .offset = ANACTRL_HIFIPLL_CTRL0, 379 .shift = 16, 380 .width = 2, 381 .flags = CLK_DIVIDER_POWER_OF_TWO, 382 }, 383 .hw.init = &(struct clk_init_data) { 384 .name = "hifi_pll", 385 .ops = &clk_regmap_divider_ops, 386 .parent_hws = (const struct clk_hw *[]) { 387 &hifi_pll_dco.hw 388 }, 389 .num_parents = 1, 390 .flags = CLK_SET_RATE_PARENT, 391 }, 392 }; 393 394 static const struct reg_sequence c3_mclk_init_regs[] = { 395 { .reg = ANACTRL_MPLL_CTRL1, .def = 0x1420500f }, 396 { .reg = ANACTRL_MPLL_CTRL2, .def = 0x00023041 }, 397 { .reg = ANACTRL_MPLL_CTRL3, .def = 0x18180000 }, 398 { .reg = ANACTRL_MPLL_CTRL2, .def = 0x00023001 } 399 }; 400 401 static const struct pll_mult_range c3_mclk_pll_mult_range = { 402 .min = 67, 403 .max = 133, 404 }; 405 406 static struct clk_regmap mclk_pll_dco = { 407 .data = &(struct meson_clk_pll_data) { 408 .en = { 409 .reg_off = ANACTRL_MPLL_CTRL0, 410 .shift = 28, 411 .width = 1, 412 }, 413 .m = { 414 .reg_off = ANACTRL_MPLL_CTRL0, 415 .shift = 0, 416 .width = 8, 417 }, 418 .n = { 419 .reg_off = ANACTRL_MPLL_CTRL0, 420 .shift = 16, 421 .width = 5, 422 }, 423 .l = { 424 .reg_off = ANACTRL_MPLL_CTRL0, 425 .shift = 31, 426 .width = 1, 427 }, 428 .rst = { 429 .reg_off = ANACTRL_MPLL_CTRL0, 430 .shift = 29, 431 .width = 1, 432 }, 433 .range = &c3_mclk_pll_mult_range, 434 .init_regs = c3_mclk_init_regs, 435 .init_count = ARRAY_SIZE(c3_mclk_init_regs), 436 }, 437 .hw.init = &(struct clk_init_data) { 438 .name = "mclk_pll_dco", 439 .ops = &meson_clk_pll_ops, 440 .parent_data = &(const struct clk_parent_data) { 441 .fw_name = "mclk", 442 }, 443 .num_parents = 1, 444 }, 445 }; 446 447 static const struct clk_div_table c3_mpll_od_table[] = { 448 { 0, 1 }, 449 { 1, 2 }, 450 { 2, 4 }, 451 { 3, 8 }, 452 { 4, 16 }, 453 { /* sentinel */ } 454 }; 455 456 static struct clk_regmap mclk_pll_od = { 457 .data = &(struct clk_regmap_div_data) { 458 .offset = ANACTRL_MPLL_CTRL0, 459 .shift = 12, 460 .width = 3, 461 .table = c3_mpll_od_table, 462 }, 463 .hw.init = &(struct clk_init_data) { 464 .name = "mclk_pll_od", 465 .ops = &clk_regmap_divider_ops, 466 .parent_hws = (const struct clk_hw *[]) { 467 &mclk_pll_dco.hw }, 468 .num_parents = 1, 469 .flags = CLK_SET_RATE_PARENT, 470 }, 471 }; 472 473 /* both value 0 and 1 gives divide the input rate by one */ 474 static struct clk_regmap mclk_pll = { 475 .data = &(struct clk_regmap_div_data) { 476 .offset = ANACTRL_MPLL_CTRL4, 477 .shift = 16, 478 .width = 5, 479 .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, 480 }, 481 .hw.init = &(struct clk_init_data) { 482 .name = "mclk_pll", 483 .ops = &clk_regmap_divider_ops, 484 .parent_hws = (const struct clk_hw *[]) { 485 &mclk_pll_od.hw 486 }, 487 .num_parents = 1, 488 .flags = CLK_SET_RATE_PARENT, 489 }, 490 }; 491 492 static const struct clk_parent_data mclk_parent[] = { 493 { .hw = &mclk_pll.hw }, 494 { .fw_name = "mclk" }, 495 { .hw = &fclk_50m.hw } 496 }; 497 498 static struct clk_regmap mclk0_sel = { 499 .data = &(struct clk_regmap_mux_data) { 500 .offset = ANACTRL_MPLL_CTRL4, 501 .mask = 0x3, 502 .shift = 4, 503 }, 504 .hw.init = &(struct clk_init_data) { 505 .name = "mclk0_sel", 506 .ops = &clk_regmap_mux_ops, 507 .parent_data = mclk_parent, 508 .num_parents = ARRAY_SIZE(mclk_parent), 509 }, 510 }; 511 512 static struct clk_regmap mclk0_div_en = { 513 .data = &(struct clk_regmap_gate_data) { 514 .offset = ANACTRL_MPLL_CTRL4, 515 .bit_idx = 1, 516 }, 517 .hw.init = &(struct clk_init_data) { 518 .name = "mclk0_div_en", 519 .ops = &clk_regmap_gate_ops, 520 .parent_hws = (const struct clk_hw *[]) { 521 &mclk0_sel.hw 522 }, 523 .num_parents = 1, 524 .flags = CLK_SET_RATE_PARENT, 525 }, 526 }; 527 528 static struct clk_regmap mclk0_div = { 529 .data = &(struct clk_regmap_div_data) { 530 .offset = ANACTRL_MPLL_CTRL4, 531 .shift = 2, 532 .width = 1, 533 }, 534 .hw.init = &(struct clk_init_data) { 535 .name = "mclk0_div", 536 .ops = &clk_regmap_divider_ops, 537 .parent_hws = (const struct clk_hw *[]) { 538 &mclk0_div_en.hw 539 }, 540 .num_parents = 1, 541 .flags = CLK_SET_RATE_PARENT, 542 }, 543 }; 544 545 static struct clk_regmap mclk0 = { 546 .data = &(struct clk_regmap_gate_data) { 547 .offset = ANACTRL_MPLL_CTRL4, 548 .bit_idx = 0, 549 }, 550 .hw.init = &(struct clk_init_data) { 551 .name = "mclk0", 552 .ops = &clk_regmap_gate_ops, 553 .parent_hws = (const struct clk_hw *[]) { 554 &mclk0_div.hw 555 }, 556 .num_parents = 1, 557 .flags = CLK_SET_RATE_PARENT, 558 }, 559 }; 560 561 static struct clk_regmap mclk1_sel = { 562 .data = &(struct clk_regmap_mux_data) { 563 .offset = ANACTRL_MPLL_CTRL4, 564 .mask = 0x3, 565 .shift = 12, 566 }, 567 .hw.init = &(struct clk_init_data) { 568 .name = "mclk1_sel", 569 .ops = &clk_regmap_mux_ops, 570 .parent_data = mclk_parent, 571 .num_parents = ARRAY_SIZE(mclk_parent), 572 }, 573 }; 574 575 static struct clk_regmap mclk1_div_en = { 576 .data = &(struct clk_regmap_gate_data) { 577 .offset = ANACTRL_MPLL_CTRL4, 578 .bit_idx = 9, 579 }, 580 .hw.init = &(struct clk_init_data) { 581 .name = "mclk1_div_en", 582 .ops = &clk_regmap_gate_ops, 583 .parent_hws = (const struct clk_hw *[]) { 584 &mclk1_sel.hw 585 }, 586 .num_parents = 1, 587 .flags = CLK_SET_RATE_PARENT, 588 }, 589 }; 590 591 static struct clk_regmap mclk1_div = { 592 .data = &(struct clk_regmap_div_data) { 593 .offset = ANACTRL_MPLL_CTRL4, 594 .shift = 10, 595 .width = 1, 596 }, 597 .hw.init = &(struct clk_init_data) { 598 .name = "mclk1_div", 599 .ops = &clk_regmap_divider_ops, 600 .parent_hws = (const struct clk_hw *[]) { 601 &mclk1_div_en.hw 602 }, 603 .num_parents = 1, 604 .flags = CLK_SET_RATE_PARENT, 605 }, 606 }; 607 608 static struct clk_regmap mclk1 = { 609 .data = &(struct clk_regmap_gate_data) { 610 .offset = ANACTRL_MPLL_CTRL4, 611 .bit_idx = 8, 612 }, 613 .hw.init = &(struct clk_init_data) { 614 .name = "mclk1", 615 .ops = &clk_regmap_gate_ops, 616 .parent_hws = (const struct clk_hw *[]) { 617 &mclk1_div.hw 618 }, 619 .num_parents = 1, 620 .flags = CLK_SET_RATE_PARENT, 621 }, 622 }; 623 624 static struct clk_hw *c3_pll_hw_clks[] = { 625 [CLKID_FCLK_50M_EN] = &fclk_50m_en.hw, 626 [CLKID_FCLK_50M] = &fclk_50m.hw, 627 [CLKID_FCLK_DIV2_DIV] = &fclk_div2_div.hw, 628 [CLKID_FCLK_DIV2] = &fclk_div2.hw, 629 [CLKID_FCLK_DIV2P5_DIV] = &fclk_div2p5_div.hw, 630 [CLKID_FCLK_DIV2P5] = &fclk_div2p5.hw, 631 [CLKID_FCLK_DIV3_DIV] = &fclk_div3_div.hw, 632 [CLKID_FCLK_DIV3] = &fclk_div3.hw, 633 [CLKID_FCLK_DIV4_DIV] = &fclk_div4_div.hw, 634 [CLKID_FCLK_DIV4] = &fclk_div4.hw, 635 [CLKID_FCLK_DIV5_DIV] = &fclk_div5_div.hw, 636 [CLKID_FCLK_DIV5] = &fclk_div5.hw, 637 [CLKID_FCLK_DIV7_DIV] = &fclk_div7_div.hw, 638 [CLKID_FCLK_DIV7] = &fclk_div7.hw, 639 [CLKID_GP0_PLL_DCO] = &gp0_pll_dco.hw, 640 [CLKID_GP0_PLL] = &gp0_pll.hw, 641 [CLKID_HIFI_PLL_DCO] = &hifi_pll_dco.hw, 642 [CLKID_HIFI_PLL] = &hifi_pll.hw, 643 [CLKID_MCLK_PLL_DCO] = &mclk_pll_dco.hw, 644 [CLKID_MCLK_PLL_OD] = &mclk_pll_od.hw, 645 [CLKID_MCLK_PLL] = &mclk_pll.hw, 646 [CLKID_MCLK0_SEL] = &mclk0_sel.hw, 647 [CLKID_MCLK0_SEL_EN] = &mclk0_div_en.hw, 648 [CLKID_MCLK0_DIV] = &mclk0_div.hw, 649 [CLKID_MCLK0] = &mclk0.hw, 650 [CLKID_MCLK1_SEL] = &mclk1_sel.hw, 651 [CLKID_MCLK1_SEL_EN] = &mclk1_div_en.hw, 652 [CLKID_MCLK1_DIV] = &mclk1_div.hw, 653 [CLKID_MCLK1] = &mclk1.hw 654 }; 655 656 /* Convenience table to populate regmap in .probe */ 657 static struct clk_regmap *const c3_pll_clk_regmaps[] = { 658 &fclk_50m_en, 659 &fclk_div2, 660 &fclk_div2p5, 661 &fclk_div3, 662 &fclk_div4, 663 &fclk_div5, 664 &fclk_div7, 665 &gp0_pll_dco, 666 &gp0_pll, 667 &hifi_pll_dco, 668 &hifi_pll, 669 &mclk_pll_dco, 670 &mclk_pll_od, 671 &mclk_pll, 672 &mclk0_sel, 673 &mclk0_div_en, 674 &mclk0_div, 675 &mclk0, 676 &mclk1_sel, 677 &mclk1_div_en, 678 &mclk1_div, 679 &mclk1, 680 }; 681 682 static const struct regmap_config clkc_regmap_config = { 683 .reg_bits = 32, 684 .val_bits = 32, 685 .reg_stride = 4, 686 .max_register = ANACTRL_MPLL_CTRL4, 687 }; 688 689 static struct meson_clk_hw_data c3_pll_clks = { 690 .hws = c3_pll_hw_clks, 691 .num = ARRAY_SIZE(c3_pll_hw_clks), 692 }; 693 694 static int c3_pll_probe(struct platform_device *pdev) 695 { 696 struct device *dev = &pdev->dev; 697 struct regmap *regmap; 698 void __iomem *base; 699 int clkid, ret, i; 700 701 base = devm_platform_ioremap_resource(pdev, 0); 702 if (IS_ERR(base)) 703 return PTR_ERR(base); 704 705 regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config); 706 if (IS_ERR(regmap)) 707 return PTR_ERR(regmap); 708 709 /* Populate regmap for the regmap backed clocks */ 710 for (i = 0; i < ARRAY_SIZE(c3_pll_clk_regmaps); i++) 711 c3_pll_clk_regmaps[i]->map = regmap; 712 713 for (clkid = 0; clkid < c3_pll_clks.num; clkid++) { 714 /* array might be sparse */ 715 if (!c3_pll_clks.hws[clkid]) 716 continue; 717 718 ret = devm_clk_hw_register(dev, c3_pll_clks.hws[clkid]); 719 if (ret) { 720 dev_err(dev, "Clock registration failed\n"); 721 return ret; 722 } 723 } 724 725 return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, 726 &c3_pll_clks); 727 } 728 729 static const struct of_device_id c3_pll_clkc_match_table[] = { 730 { 731 .compatible = "amlogic,c3-pll-clkc", 732 }, 733 {} 734 }; 735 MODULE_DEVICE_TABLE(of, c3_pll_clkc_match_table); 736 737 static struct platform_driver c3_pll_driver = { 738 .probe = c3_pll_probe, 739 .driver = { 740 .name = "c3-pll-clkc", 741 .of_match_table = c3_pll_clkc_match_table, 742 }, 743 }; 744 module_platform_driver(c3_pll_driver); 745 746 MODULE_DESCRIPTION("Amlogic C3 PLL Clock Controller driver"); 747 MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>"); 748 MODULE_LICENSE("GPL"); 749 MODULE_IMPORT_NS(CLK_MESON); 750