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 }, 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 375 static 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.hw 387 }, 388 .num_parents = 1, 389 .flags = CLK_SET_RATE_PARENT, 390 }, 391 }; 392 393 static 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 400 static const struct pll_mult_range c3_mclk_pll_mult_range = { 401 .min = 67, 402 .max = 133, 403 }; 404 405 static 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 446 static 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 455 static 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 */ 473 static 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.hw 485 }, 486 .num_parents = 1, 487 .flags = CLK_SET_RATE_PARENT, 488 }, 489 }; 490 491 static const struct clk_parent_data mclk_parent[] = { 492 { .hw = &mclk_pll.hw }, 493 { .fw_name = "mclk" }, 494 { .hw = &fclk_50m.hw } 495 }; 496 497 static 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 511 static 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.hw 521 }, 522 .num_parents = 1, 523 .flags = CLK_SET_RATE_PARENT, 524 }, 525 }; 526 527 static 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.hw 538 }, 539 .num_parents = 1, 540 .flags = CLK_SET_RATE_PARENT, 541 }, 542 }; 543 544 static 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.hw 554 }, 555 .num_parents = 1, 556 .flags = CLK_SET_RATE_PARENT, 557 }, 558 }; 559 560 static 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 574 static 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.hw 584 }, 585 .num_parents = 1, 586 .flags = CLK_SET_RATE_PARENT, 587 }, 588 }; 589 590 static 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.hw 601 }, 602 .num_parents = 1, 603 .flags = CLK_SET_RATE_PARENT, 604 }, 605 }; 606 607 static 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.hw 617 }, 618 .num_parents = 1, 619 .flags = CLK_SET_RATE_PARENT, 620 }, 621 }; 622 623 static 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.hw 653 }; 654 655 /* Convenience table to populate regmap in .probe */ 656 static 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 681 static 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 688 static struct meson_clk_hw_data c3_pll_clks = { 689 .hws = c3_pll_hw_clks, 690 .num = ARRAY_SIZE(c3_pll_hw_clks), 691 }; 692 693 static 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 728 static const struct of_device_id c3_pll_clkc_match_table[] = { 729 { 730 .compatible = "amlogic,c3-pll-clkc", 731 }, 732 {} 733 }; 734 MODULE_DEVICE_TABLE(of, c3_pll_clkc_match_table); 735 736 static 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 }; 743 module_platform_driver(c3_pll_driver); 744 745 MODULE_DESCRIPTION("Amlogic C3 PLL Clock Controller driver"); 746 MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>"); 747 MODULE_LICENSE("GPL"); 748