linux/drivers/clk/clk-axm5516.c
<<
>>
Prefs
   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