root/drivers/clk/clk-axm5516.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. axxia_pllclk_recalc
  2. axxia_divclk_recalc_rate
  3. axxia_clkmux_get_parent
  4. of_clk_axmclk_get
  5. axmclk_probe
  6. axmclk_remove
  7. axmclk_init
  8. axmclk_exit

   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");

/* [<][>][^][v][top][bottom][index][help] */