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 */ 29struct 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 */ 40struct 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 */ 50static unsigned long 51axxia_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 67static 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 */ 78struct 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 */ 89static unsigned long 90axxia_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 102static 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 */ 113struct 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 */ 124static 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 136static const struct clk_ops axxia_clkmux_ops = { 137 .get_parent = axxia_clkmux_get_parent, 138}; 139 140 141/* 142 * PLLs 143 */ 144 145static 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 157static 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 169static 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 181static 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 193static 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 209static 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 223static 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 237static 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 251static 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 265static 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 279static 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 293static 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 307static 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 322static 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 341static 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 358static 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 375static 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 392static 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 409static 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 426static 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 443static 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 460static 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 475static 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 */ 493static 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 519static const struct regmap_config axmclk_regmap_config = { 520 .reg_bits = 32, 521 .reg_stride = 4, 522 .val_bits = 32, 523 .max_register = 0x1fffc, 524 .fast_io = true, 525}; 526 527static const struct of_device_id axmclk_match_table[] = { 528 { .compatible = "lsi,axm5516-clks" }, 529 { } 530}; 531MODULE_DEVICE_TABLE(of, axmclk_match_table); 532 533struct axmclk_priv { 534 struct clk_onecell_data onecell; 535 struct clk *clks[]; 536}; 537 538static int axmclk_probe(struct platform_device *pdev) 539{ 540 void __iomem *base; 541 struct resource *res; 542 int i, ret; 543 struct device *dev = &pdev->dev; 544 struct clk *clk; 545 struct regmap *regmap; 546 size_t num_clks; 547 struct axmclk_priv *priv; 548 549 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 550 base = devm_ioremap_resource(dev, res); 551 if (IS_ERR(base)) 552 return PTR_ERR(base); 553 554 regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config); 555 if (IS_ERR(regmap)) 556 return PTR_ERR(regmap); 557 558 num_clks = ARRAY_SIZE(axmclk_clocks); 559 pr_info("axmclk: supporting %u clocks\n", num_clks); 560 priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks, 561 GFP_KERNEL); 562 if (!priv) 563 return -ENOMEM; 564 565 priv->onecell.clks = priv->clks; 566 priv->onecell.clk_num = num_clks; 567 568 /* Update each entry with the allocated regmap and register the clock 569 * with the common clock framework 570 */ 571 for (i = 0; i < num_clks; i++) { 572 axmclk_clocks[i]->regmap = regmap; 573 clk = devm_clk_register(dev, &axmclk_clocks[i]->hw); 574 if (IS_ERR(clk)) 575 return PTR_ERR(clk); 576 priv->clks[i] = clk; 577 } 578 579 ret = of_clk_add_provider(dev->of_node, 580 of_clk_src_onecell_get, &priv->onecell); 581 582 return ret; 583} 584 585static int axmclk_remove(struct platform_device *pdev) 586{ 587 of_clk_del_provider(pdev->dev.of_node); 588 return 0; 589} 590 591static struct platform_driver axmclk_driver = { 592 .probe = axmclk_probe, 593 .remove = axmclk_remove, 594 .driver = { 595 .name = "clk-axm5516", 596 .of_match_table = axmclk_match_table, 597 }, 598}; 599 600static int __init axmclk_init(void) 601{ 602 return platform_driver_register(&axmclk_driver); 603} 604core_initcall(axmclk_init); 605 606static void __exit axmclk_exit(void) 607{ 608 platform_driver_unregister(&axmclk_driver); 609} 610module_exit(axmclk_exit); 611 612MODULE_DESCRIPTION("AXM5516 clock driver"); 613MODULE_LICENSE("GPL v2"); 614MODULE_ALIAS("platform:clk-axm5516"); 615