1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * drivers/clk/clk-axm5516.c 4 * 5 * Provides clock implementations for three different types of clock devices on 6 * the Axxia device: PLL clock, a clock divider and a clock mux. 7 * 8 * Copyright (C) 2014 LSI Corporation 9 */ 10 #include <linux/module.h> 11 #include <linux/kernel.h> 12 #include <linux/slab.h> 13 #include <linux/platform_device.h> 14 #include <linux/of.h> 15 #include <linux/of_address.h> 16 #include <linux/clk-provider.h> 17 #include <linux/regmap.h> 18 #include <dt-bindings/clock/lsi,axm5516-clks.h> 19 20 21 /** 22 * struct axxia_clk - Common struct to all Axxia clocks. 23 * @hw: clk_hw for the common clk framework 24 * @regmap: Regmap for the clock control registers 25 */ 26 struct axxia_clk { 27 struct clk_hw hw; 28 struct regmap *regmap; 29 }; 30 #define to_axxia_clk(_hw) container_of(_hw, struct axxia_clk, hw) 31 32 /** 33 * struct axxia_pllclk - Axxia PLL generated clock. 34 * @aclk: Common struct 35 * @reg: Offset into regmap for PLL control register 36 */ 37 struct axxia_pllclk { 38 struct axxia_clk aclk; 39 u32 reg; 40 }; 41 #define to_axxia_pllclk(_aclk) container_of(_aclk, struct axxia_pllclk, aclk) 42 43 /** 44 * axxia_pllclk_recalc - Calculate the PLL generated clock rate given the 45 * parent clock rate. 46 */ 47 static unsigned long 48 axxia_pllclk_recalc(struct clk_hw *hw, unsigned long parent_rate) 49 { 50 struct axxia_clk *aclk = to_axxia_clk(hw); 51 struct axxia_pllclk *pll = to_axxia_pllclk(aclk); 52 unsigned long rate, fbdiv, refdiv, postdiv; 53 u32 control; 54 55 regmap_read(aclk->regmap, pll->reg, &control); 56 postdiv = ((control >> 0) & 0xf) + 1; 57 fbdiv = ((control >> 4) & 0xfff) + 3; 58 refdiv = ((control >> 16) & 0x1f) + 1; 59 rate = (parent_rate / (refdiv * postdiv)) * fbdiv; 60 61 return rate; 62 } 63 64 static const struct clk_ops axxia_pllclk_ops = { 65 .recalc_rate = axxia_pllclk_recalc, 66 }; 67 68 /** 69 * struct axxia_divclk - Axxia clock divider 70 * @aclk: Common struct 71 * @reg: Offset into regmap for PLL control register 72 * @shift: Bit position for divider value 73 * @width: Number of bits in divider value 74 */ 75 struct axxia_divclk { 76 struct axxia_clk aclk; 77 u32 reg; 78 u32 shift; 79 u32 width; 80 }; 81 #define to_axxia_divclk(_aclk) container_of(_aclk, struct axxia_divclk, aclk) 82 83 /** 84 * axxia_divclk_recalc_rate - Calculate clock divider output rage 85 */ 86 static unsigned long 87 axxia_divclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 88 { 89 struct axxia_clk *aclk = to_axxia_clk(hw); 90 struct axxia_divclk *divclk = to_axxia_divclk(aclk); 91 u32 ctrl, div; 92 93 regmap_read(aclk->regmap, divclk->reg, &ctrl); 94 div = 1 + ((ctrl >> divclk->shift) & ((1 << divclk->width)-1)); 95 96 return parent_rate / div; 97 } 98 99 static const struct clk_ops axxia_divclk_ops = { 100 .recalc_rate = axxia_divclk_recalc_rate, 101 }; 102 103 /** 104 * struct axxia_clkmux - Axxia clock mux 105 * @aclk: Common struct 106 * @reg: Offset into regmap for PLL control register 107 * @shift: Bit position for selection value 108 * @width: Number of bits in selection value 109 */ 110 struct axxia_clkmux { 111 struct axxia_clk aclk; 112 u32 reg; 113 u32 shift; 114 u32 width; 115 }; 116 #define to_axxia_clkmux(_aclk) container_of(_aclk, struct axxia_clkmux, aclk) 117 118 /** 119 * axxia_clkmux_get_parent - Return the index of selected parent clock 120 */ 121 static u8 axxia_clkmux_get_parent(struct clk_hw *hw) 122 { 123 struct axxia_clk *aclk = to_axxia_clk(hw); 124 struct axxia_clkmux *mux = to_axxia_clkmux(aclk); 125 u32 ctrl, parent; 126 127 regmap_read(aclk->regmap, mux->reg, &ctrl); 128 parent = (ctrl >> mux->shift) & ((1 << mux->width) - 1); 129 130 return (u8) parent; 131 } 132 133 static const struct clk_ops axxia_clkmux_ops = { 134 .get_parent = axxia_clkmux_get_parent, 135 }; 136 137 138 /* 139 * PLLs 140 */ 141 142 static struct axxia_pllclk clk_fab_pll = { 143 .aclk.hw.init = &(struct clk_init_data){ 144 .name = "clk_fab_pll", 145 .parent_names = (const char *[]){ 146 "clk_ref0" 147 }, 148 .num_parents = 1, 149 .ops = &axxia_pllclk_ops, 150 }, 151 .reg = 0x01800, 152 }; 153 154 static struct axxia_pllclk clk_cpu_pll = { 155 .aclk.hw.init = &(struct clk_init_data){ 156 .name = "clk_cpu_pll", 157 .parent_names = (const char *[]){ 158 "clk_ref0" 159 }, 160 .num_parents = 1, 161 .ops = &axxia_pllclk_ops, 162 }, 163 .reg = 0x02000, 164 }; 165 166 static struct axxia_pllclk clk_sys_pll = { 167 .aclk.hw.init = &(struct clk_init_data){ 168 .name = "clk_sys_pll", 169 .parent_names = (const char *[]){ 170 "clk_ref0" 171 }, 172 .num_parents = 1, 173 .ops = &axxia_pllclk_ops, 174 }, 175 .reg = 0x02800, 176 }; 177 178 static struct axxia_pllclk clk_sm0_pll = { 179 .aclk.hw.init = &(struct clk_init_data){ 180 .name = "clk_sm0_pll", 181 .parent_names = (const char *[]){ 182 "clk_ref2" 183 }, 184 .num_parents = 1, 185 .ops = &axxia_pllclk_ops, 186 }, 187 .reg = 0x03000, 188 }; 189 190 static struct axxia_pllclk clk_sm1_pll = { 191 .aclk.hw.init = &(struct clk_init_data){ 192 .name = "clk_sm1_pll", 193 .parent_names = (const char *[]){ 194 "clk_ref1" 195 }, 196 .num_parents = 1, 197 .ops = &axxia_pllclk_ops, 198 }, 199 .reg = 0x03800, 200 }; 201 202 /* 203 * Clock dividers 204 */ 205 206 static struct axxia_divclk clk_cpu0_div = { 207 .aclk.hw.init = &(struct clk_init_data){ 208 .name = "clk_cpu0_div", 209 .parent_names = (const char *[]){ 210 "clk_cpu_pll" 211 }, 212 .num_parents = 1, 213 .ops = &axxia_divclk_ops, 214 }, 215 .reg = 0x10008, 216 .shift = 0, 217 .width = 4, 218 }; 219 220 static struct axxia_divclk clk_cpu1_div = { 221 .aclk.hw.init = &(struct clk_init_data){ 222 .name = "clk_cpu1_div", 223 .parent_names = (const char *[]){ 224 "clk_cpu_pll" 225 }, 226 .num_parents = 1, 227 .ops = &axxia_divclk_ops, 228 }, 229 .reg = 0x10008, 230 .shift = 4, 231 .width = 4, 232 }; 233 234 static struct axxia_divclk clk_cpu2_div = { 235 .aclk.hw.init = &(struct clk_init_data){ 236 .name = "clk_cpu2_div", 237 .parent_names = (const char *[]){ 238 "clk_cpu_pll" 239 }, 240 .num_parents = 1, 241 .ops = &axxia_divclk_ops, 242 }, 243 .reg = 0x10008, 244 .shift = 8, 245 .width = 4, 246 }; 247 248 static struct axxia_divclk clk_cpu3_div = { 249 .aclk.hw.init = &(struct clk_init_data){ 250 .name = "clk_cpu3_div", 251 .parent_names = (const char *[]){ 252 "clk_cpu_pll" 253 }, 254 .num_parents = 1, 255 .ops = &axxia_divclk_ops, 256 }, 257 .reg = 0x10008, 258 .shift = 12, 259 .width = 4, 260 }; 261 262 static struct axxia_divclk clk_nrcp_div = { 263 .aclk.hw.init = &(struct clk_init_data){ 264 .name = "clk_nrcp_div", 265 .parent_names = (const char *[]){ 266 "clk_sys_pll" 267 }, 268 .num_parents = 1, 269 .ops = &axxia_divclk_ops, 270 }, 271 .reg = 0x1000c, 272 .shift = 0, 273 .width = 4, 274 }; 275 276 static struct axxia_divclk clk_sys_div = { 277 .aclk.hw.init = &(struct clk_init_data){ 278 .name = "clk_sys_div", 279 .parent_names = (const char *[]){ 280 "clk_sys_pll" 281 }, 282 .num_parents = 1, 283 .ops = &axxia_divclk_ops, 284 }, 285 .reg = 0x1000c, 286 .shift = 4, 287 .width = 4, 288 }; 289 290 static struct axxia_divclk clk_fab_div = { 291 .aclk.hw.init = &(struct clk_init_data){ 292 .name = "clk_fab_div", 293 .parent_names = (const char *[]){ 294 "clk_fab_pll" 295 }, 296 .num_parents = 1, 297 .ops = &axxia_divclk_ops, 298 }, 299 .reg = 0x1000c, 300 .shift = 8, 301 .width = 4, 302 }; 303 304 static struct axxia_divclk clk_per_div = { 305 .aclk.hw.init = &(struct clk_init_data){ 306 .name = "clk_per_div", 307 .parent_names = (const char *[]){ 308 "clk_sm1_pll" 309 }, 310 .num_parents = 1, 311 .ops = &axxia_divclk_ops, 312 }, 313 .reg = 0x1000c, 314 .shift = 12, 315 .width = 4, 316 }; 317 318 static struct axxia_divclk clk_mmc_div = { 319 .aclk.hw.init = &(struct clk_init_data){ 320 .name = "clk_mmc_div", 321 .parent_names = (const char *[]){ 322 "clk_sm1_pll" 323 }, 324 .num_parents = 1, 325 .ops = &axxia_divclk_ops, 326 }, 327 .reg = 0x1000c, 328 .shift = 16, 329 .width = 4, 330 }; 331 332 /* 333 * Clock MUXes 334 */ 335 336 static struct axxia_clkmux clk_cpu0_mux = { 337 .aclk.hw.init = &(struct clk_init_data){ 338 .name = "clk_cpu0", 339 .parent_names = (const char *[]){ 340 "clk_ref0", 341 "clk_cpu_pll", 342 "clk_cpu0_div", 343 "clk_cpu0_div" 344 }, 345 .num_parents = 4, 346 .ops = &axxia_clkmux_ops, 347 }, 348 .reg = 0x10000, 349 .shift = 0, 350 .width = 2, 351 }; 352 353 static struct axxia_clkmux clk_cpu1_mux = { 354 .aclk.hw.init = &(struct clk_init_data){ 355 .name = "clk_cpu1", 356 .parent_names = (const char *[]){ 357 "clk_ref0", 358 "clk_cpu_pll", 359 "clk_cpu1_div", 360 "clk_cpu1_div" 361 }, 362 .num_parents = 4, 363 .ops = &axxia_clkmux_ops, 364 }, 365 .reg = 0x10000, 366 .shift = 2, 367 .width = 2, 368 }; 369 370 static struct axxia_clkmux clk_cpu2_mux = { 371 .aclk.hw.init = &(struct clk_init_data){ 372 .name = "clk_cpu2", 373 .parent_names = (const char *[]){ 374 "clk_ref0", 375 "clk_cpu_pll", 376 "clk_cpu2_div", 377 "clk_cpu2_div" 378 }, 379 .num_parents = 4, 380 .ops = &axxia_clkmux_ops, 381 }, 382 .reg = 0x10000, 383 .shift = 4, 384 .width = 2, 385 }; 386 387 static struct axxia_clkmux clk_cpu3_mux = { 388 .aclk.hw.init = &(struct clk_init_data){ 389 .name = "clk_cpu3", 390 .parent_names = (const char *[]){ 391 "clk_ref0", 392 "clk_cpu_pll", 393 "clk_cpu3_div", 394 "clk_cpu3_div" 395 }, 396 .num_parents = 4, 397 .ops = &axxia_clkmux_ops, 398 }, 399 .reg = 0x10000, 400 .shift = 6, 401 .width = 2, 402 }; 403 404 static struct axxia_clkmux clk_nrcp_mux = { 405 .aclk.hw.init = &(struct clk_init_data){ 406 .name = "clk_nrcp", 407 .parent_names = (const char *[]){ 408 "clk_ref0", 409 "clk_sys_pll", 410 "clk_nrcp_div", 411 "clk_nrcp_div" 412 }, 413 .num_parents = 4, 414 .ops = &axxia_clkmux_ops, 415 }, 416 .reg = 0x10004, 417 .shift = 0, 418 .width = 2, 419 }; 420 421 static struct axxia_clkmux clk_sys_mux = { 422 .aclk.hw.init = &(struct clk_init_data){ 423 .name = "clk_sys", 424 .parent_names = (const char *[]){ 425 "clk_ref0", 426 "clk_sys_pll", 427 "clk_sys_div", 428 "clk_sys_div" 429 }, 430 .num_parents = 4, 431 .ops = &axxia_clkmux_ops, 432 }, 433 .reg = 0x10004, 434 .shift = 2, 435 .width = 2, 436 }; 437 438 static struct axxia_clkmux clk_fab_mux = { 439 .aclk.hw.init = &(struct clk_init_data){ 440 .name = "clk_fab", 441 .parent_names = (const char *[]){ 442 "clk_ref0", 443 "clk_fab_pll", 444 "clk_fab_div", 445 "clk_fab_div" 446 }, 447 .num_parents = 4, 448 .ops = &axxia_clkmux_ops, 449 }, 450 .reg = 0x10004, 451 .shift = 4, 452 .width = 2, 453 }; 454 455 static struct axxia_clkmux clk_per_mux = { 456 .aclk.hw.init = &(struct clk_init_data){ 457 .name = "clk_per", 458 .parent_names = (const char *[]){ 459 "clk_ref1", 460 "clk_per_div" 461 }, 462 .num_parents = 2, 463 .ops = &axxia_clkmux_ops, 464 }, 465 .reg = 0x10004, 466 .shift = 6, 467 .width = 1, 468 }; 469 470 static struct axxia_clkmux clk_mmc_mux = { 471 .aclk.hw.init = &(struct clk_init_data){ 472 .name = "clk_mmc", 473 .parent_names = (const char *[]){ 474 "clk_ref1", 475 "clk_mmc_div" 476 }, 477 .num_parents = 2, 478 .ops = &axxia_clkmux_ops, 479 }, 480 .reg = 0x10004, 481 .shift = 9, 482 .width = 1, 483 }; 484 485 /* Table of all supported clocks indexed by the clock identifiers from the 486 * device tree binding 487 */ 488 static struct axxia_clk *axmclk_clocks[] = { 489 [AXXIA_CLK_FAB_PLL] = &clk_fab_pll.aclk, 490 [AXXIA_CLK_CPU_PLL] = &clk_cpu_pll.aclk, 491 [AXXIA_CLK_SYS_PLL] = &clk_sys_pll.aclk, 492 [AXXIA_CLK_SM0_PLL] = &clk_sm0_pll.aclk, 493 [AXXIA_CLK_SM1_PLL] = &clk_sm1_pll.aclk, 494 [AXXIA_CLK_FAB_DIV] = &clk_fab_div.aclk, 495 [AXXIA_CLK_SYS_DIV] = &clk_sys_div.aclk, 496 [AXXIA_CLK_NRCP_DIV] = &clk_nrcp_div.aclk, 497 [AXXIA_CLK_CPU0_DIV] = &clk_cpu0_div.aclk, 498 [AXXIA_CLK_CPU1_DIV] = &clk_cpu1_div.aclk, 499 [AXXIA_CLK_CPU2_DIV] = &clk_cpu2_div.aclk, 500 [AXXIA_CLK_CPU3_DIV] = &clk_cpu3_div.aclk, 501 [AXXIA_CLK_PER_DIV] = &clk_per_div.aclk, 502 [AXXIA_CLK_MMC_DIV] = &clk_mmc_div.aclk, 503 [AXXIA_CLK_FAB] = &clk_fab_mux.aclk, 504 [AXXIA_CLK_SYS] = &clk_sys_mux.aclk, 505 [AXXIA_CLK_NRCP] = &clk_nrcp_mux.aclk, 506 [AXXIA_CLK_CPU0] = &clk_cpu0_mux.aclk, 507 [AXXIA_CLK_CPU1] = &clk_cpu1_mux.aclk, 508 [AXXIA_CLK_CPU2] = &clk_cpu2_mux.aclk, 509 [AXXIA_CLK_CPU3] = &clk_cpu3_mux.aclk, 510 [AXXIA_CLK_PER] = &clk_per_mux.aclk, 511 [AXXIA_CLK_MMC] = &clk_mmc_mux.aclk, 512 }; 513 514 static struct clk_hw * 515 of_clk_axmclk_get(struct of_phandle_args *clkspec, void *unused) 516 { 517 unsigned int idx = clkspec->args[0]; 518 519 if (idx >= ARRAY_SIZE(axmclk_clocks)) { 520 pr_err("%s: invalid index %u\n", __func__, idx); 521 return ERR_PTR(-EINVAL); 522 } 523 524 return &axmclk_clocks[idx]->hw; 525 } 526 527 static const struct regmap_config axmclk_regmap_config = { 528 .reg_bits = 32, 529 .reg_stride = 4, 530 .val_bits = 32, 531 .max_register = 0x1fffc, 532 .fast_io = true, 533 }; 534 535 static const struct of_device_id axmclk_match_table[] = { 536 { .compatible = "lsi,axm5516-clks" }, 537 { } 538 }; 539 MODULE_DEVICE_TABLE(of, axmclk_match_table); 540 541 static int axmclk_probe(struct platform_device *pdev) 542 { 543 void __iomem *base; 544 struct resource *res; 545 int i, ret; 546 struct device *dev = &pdev->dev; 547 struct regmap *regmap; 548 size_t num_clks; 549 550 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 551 base = devm_ioremap_resource(dev, res); 552 if (IS_ERR(base)) 553 return PTR_ERR(base); 554 555 regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config); 556 if (IS_ERR(regmap)) 557 return PTR_ERR(regmap); 558 559 num_clks = ARRAY_SIZE(axmclk_clocks); 560 pr_info("axmclk: supporting %zu clocks\n", num_clks); 561 562 /* Update each entry with the allocated regmap and register the clock 563 * with the common clock framework 564 */ 565 for (i = 0; i < num_clks; i++) { 566 axmclk_clocks[i]->regmap = regmap; 567 ret = devm_clk_hw_register(dev, &axmclk_clocks[i]->hw); 568 if (ret) 569 return ret; 570 } 571 572 return of_clk_add_hw_provider(dev->of_node, of_clk_axmclk_get, NULL); 573 } 574 575 static int axmclk_remove(struct platform_device *pdev) 576 { 577 of_clk_del_provider(pdev->dev.of_node); 578 return 0; 579 } 580 581 static struct platform_driver axmclk_driver = { 582 .probe = axmclk_probe, 583 .remove = axmclk_remove, 584 .driver = { 585 .name = "clk-axm5516", 586 .of_match_table = axmclk_match_table, 587 }, 588 }; 589 590 static int __init axmclk_init(void) 591 { 592 return platform_driver_register(&axmclk_driver); 593 } 594 core_initcall(axmclk_init); 595 596 static void __exit axmclk_exit(void) 597 { 598 platform_driver_unregister(&axmclk_driver); 599 } 600 module_exit(axmclk_exit); 601 602 MODULE_DESCRIPTION("AXM5516 clock driver"); 603 MODULE_LICENSE("GPL v2"); 604 MODULE_ALIAS("platform:clk-axm5516"); 605