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