linux/drivers/clk/samsung/clk-pll.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
   3 * Copyright (c) 2013 Linaro Ltd.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 *
   9 * This file contains the utility functions to register the pll clocks.
  10*/
  11
  12#include <linux/errno.h>
  13#include "clk.h"
  14#include "clk-pll.h"
  15
  16/*
  17 * PLL35xx Clock Type
  18 */
  19
  20#define PLL35XX_MDIV_MASK       (0x3FF)
  21#define PLL35XX_PDIV_MASK       (0x3F)
  22#define PLL35XX_SDIV_MASK       (0x7)
  23#define PLL35XX_MDIV_SHIFT      (16)
  24#define PLL35XX_PDIV_SHIFT      (8)
  25#define PLL35XX_SDIV_SHIFT      (0)
  26
  27struct samsung_clk_pll35xx {
  28        struct clk_hw           hw;
  29        const void __iomem      *con_reg;
  30};
  31
  32#define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw)
  33
  34static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
  35                                unsigned long parent_rate)
  36{
  37        struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw);
  38        u32 mdiv, pdiv, sdiv, pll_con;
  39        u64 fvco = parent_rate;
  40
  41        pll_con = __raw_readl(pll->con_reg);
  42        mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
  43        pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
  44        sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
  45
  46        fvco *= mdiv;
  47        do_div(fvco, (pdiv << sdiv));
  48
  49        return (unsigned long)fvco;
  50}
  51
  52static const struct clk_ops samsung_pll35xx_clk_ops = {
  53        .recalc_rate = samsung_pll35xx_recalc_rate,
  54};
  55
  56struct clk * __init samsung_clk_register_pll35xx(const char *name,
  57                        const char *pname, const void __iomem *con_reg)
  58{
  59        struct samsung_clk_pll35xx *pll;
  60        struct clk *clk;
  61        struct clk_init_data init;
  62
  63        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
  64        if (!pll) {
  65                pr_err("%s: could not allocate pll clk %s\n", __func__, name);
  66                return NULL;
  67        }
  68
  69        init.name = name;
  70        init.ops = &samsung_pll35xx_clk_ops;
  71        init.flags = CLK_GET_RATE_NOCACHE;
  72        init.parent_names = &pname;
  73        init.num_parents = 1;
  74
  75        pll->hw.init = &init;
  76        pll->con_reg = con_reg;
  77
  78        clk = clk_register(NULL, &pll->hw);
  79        if (IS_ERR(clk)) {
  80                pr_err("%s: failed to register pll clock %s\n", __func__,
  81                                name);
  82                kfree(pll);
  83        }
  84
  85        if (clk_register_clkdev(clk, name, NULL))
  86                pr_err("%s: failed to register lookup for %s", __func__, name);
  87
  88        return clk;
  89}
  90
  91/*
  92 * PLL36xx Clock Type
  93 */
  94
  95#define PLL36XX_KDIV_MASK       (0xFFFF)
  96#define PLL36XX_MDIV_MASK       (0x1FF)
  97#define PLL36XX_PDIV_MASK       (0x3F)
  98#define PLL36XX_SDIV_MASK       (0x7)
  99#define PLL36XX_MDIV_SHIFT      (16)
 100#define PLL36XX_PDIV_SHIFT      (8)
 101#define PLL36XX_SDIV_SHIFT      (0)
 102
 103struct samsung_clk_pll36xx {
 104        struct clk_hw           hw;
 105        const void __iomem      *con_reg;
 106};
 107
 108#define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw)
 109
 110static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
 111                                unsigned long parent_rate)
 112{
 113        struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw);
 114        u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
 115        s16 kdiv;
 116        u64 fvco = parent_rate;
 117
 118        pll_con0 = __raw_readl(pll->con_reg);
 119        pll_con1 = __raw_readl(pll->con_reg + 4);
 120        mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
 121        pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
 122        sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
 123        kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK);
 124
 125        fvco *= (mdiv << 16) + kdiv;
 126        do_div(fvco, (pdiv << sdiv));
 127        fvco >>= 16;
 128
 129        return (unsigned long)fvco;
 130}
 131
 132static const struct clk_ops samsung_pll36xx_clk_ops = {
 133        .recalc_rate = samsung_pll36xx_recalc_rate,
 134};
 135
 136struct clk * __init samsung_clk_register_pll36xx(const char *name,
 137                        const char *pname, const void __iomem *con_reg)
 138{
 139        struct samsung_clk_pll36xx *pll;
 140        struct clk *clk;
 141        struct clk_init_data init;
 142
 143        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 144        if (!pll) {
 145                pr_err("%s: could not allocate pll clk %s\n", __func__, name);
 146                return NULL;
 147        }
 148
 149        init.name = name;
 150        init.ops = &samsung_pll36xx_clk_ops;
 151        init.flags = CLK_GET_RATE_NOCACHE;
 152        init.parent_names = &pname;
 153        init.num_parents = 1;
 154
 155        pll->hw.init = &init;
 156        pll->con_reg = con_reg;
 157
 158        clk = clk_register(NULL, &pll->hw);
 159        if (IS_ERR(clk)) {
 160                pr_err("%s: failed to register pll clock %s\n", __func__,
 161                                name);
 162                kfree(pll);
 163        }
 164
 165        if (clk_register_clkdev(clk, name, NULL))
 166                pr_err("%s: failed to register lookup for %s", __func__, name);
 167
 168        return clk;
 169}
 170
 171/*
 172 * PLL45xx Clock Type
 173 */
 174
 175#define PLL45XX_MDIV_MASK       (0x3FF)
 176#define PLL45XX_PDIV_MASK       (0x3F)
 177#define PLL45XX_SDIV_MASK       (0x7)
 178#define PLL45XX_MDIV_SHIFT      (16)
 179#define PLL45XX_PDIV_SHIFT      (8)
 180#define PLL45XX_SDIV_SHIFT      (0)
 181
 182struct samsung_clk_pll45xx {
 183        struct clk_hw           hw;
 184        enum pll45xx_type       type;
 185        const void __iomem      *con_reg;
 186};
 187
 188#define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw)
 189
 190static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
 191                                unsigned long parent_rate)
 192{
 193        struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw);
 194        u32 mdiv, pdiv, sdiv, pll_con;
 195        u64 fvco = parent_rate;
 196
 197        pll_con = __raw_readl(pll->con_reg);
 198        mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
 199        pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
 200        sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
 201
 202        if (pll->type == pll_4508)
 203                sdiv = sdiv - 1;
 204
 205        fvco *= mdiv;
 206        do_div(fvco, (pdiv << sdiv));
 207
 208        return (unsigned long)fvco;
 209}
 210
 211static const struct clk_ops samsung_pll45xx_clk_ops = {
 212        .recalc_rate = samsung_pll45xx_recalc_rate,
 213};
 214
 215struct clk * __init samsung_clk_register_pll45xx(const char *name,
 216                        const char *pname, const void __iomem *con_reg,
 217                        enum pll45xx_type type)
 218{
 219        struct samsung_clk_pll45xx *pll;
 220        struct clk *clk;
 221        struct clk_init_data init;
 222
 223        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 224        if (!pll) {
 225                pr_err("%s: could not allocate pll clk %s\n", __func__, name);
 226                return NULL;
 227        }
 228
 229        init.name = name;
 230        init.ops = &samsung_pll45xx_clk_ops;
 231        init.flags = CLK_GET_RATE_NOCACHE;
 232        init.parent_names = &pname;
 233        init.num_parents = 1;
 234
 235        pll->hw.init = &init;
 236        pll->con_reg = con_reg;
 237        pll->type = type;
 238
 239        clk = clk_register(NULL, &pll->hw);
 240        if (IS_ERR(clk)) {
 241                pr_err("%s: failed to register pll clock %s\n", __func__,
 242                                name);
 243                kfree(pll);
 244        }
 245
 246        if (clk_register_clkdev(clk, name, NULL))
 247                pr_err("%s: failed to register lookup for %s", __func__, name);
 248
 249        return clk;
 250}
 251
 252/*
 253 * PLL46xx Clock Type
 254 */
 255
 256#define PLL46XX_MDIV_MASK       (0x1FF)
 257#define PLL46XX_PDIV_MASK       (0x3F)
 258#define PLL46XX_SDIV_MASK       (0x7)
 259#define PLL46XX_MDIV_SHIFT      (16)
 260#define PLL46XX_PDIV_SHIFT      (8)
 261#define PLL46XX_SDIV_SHIFT      (0)
 262
 263#define PLL46XX_KDIV_MASK       (0xFFFF)
 264#define PLL4650C_KDIV_MASK      (0xFFF)
 265#define PLL46XX_KDIV_SHIFT      (0)
 266
 267struct samsung_clk_pll46xx {
 268        struct clk_hw           hw;
 269        enum pll46xx_type       type;
 270        const void __iomem      *con_reg;
 271};
 272
 273#define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw)
 274
 275static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
 276                                unsigned long parent_rate)
 277{
 278        struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw);
 279        u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
 280        u64 fvco = parent_rate;
 281
 282        pll_con0 = __raw_readl(pll->con_reg);
 283        pll_con1 = __raw_readl(pll->con_reg + 4);
 284        mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
 285        pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
 286        sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
 287        kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
 288                                        pll_con1 & PLL46XX_KDIV_MASK;
 289
 290        shift = pll->type == pll_4600 ? 16 : 10;
 291        fvco *= (mdiv << shift) + kdiv;
 292        do_div(fvco, (pdiv << sdiv));
 293        fvco >>= shift;
 294
 295        return (unsigned long)fvco;
 296}
 297
 298static const struct clk_ops samsung_pll46xx_clk_ops = {
 299        .recalc_rate = samsung_pll46xx_recalc_rate,
 300};
 301
 302struct clk * __init samsung_clk_register_pll46xx(const char *name,
 303                        const char *pname, const void __iomem *con_reg,
 304                        enum pll46xx_type type)
 305{
 306        struct samsung_clk_pll46xx *pll;
 307        struct clk *clk;
 308        struct clk_init_data init;
 309
 310        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 311        if (!pll) {
 312                pr_err("%s: could not allocate pll clk %s\n", __func__, name);
 313                return NULL;
 314        }
 315
 316        init.name = name;
 317        init.ops = &samsung_pll46xx_clk_ops;
 318        init.flags = CLK_GET_RATE_NOCACHE;
 319        init.parent_names = &pname;
 320        init.num_parents = 1;
 321
 322        pll->hw.init = &init;
 323        pll->con_reg = con_reg;
 324        pll->type = type;
 325
 326        clk = clk_register(NULL, &pll->hw);
 327        if (IS_ERR(clk)) {
 328                pr_err("%s: failed to register pll clock %s\n", __func__,
 329                                name);
 330                kfree(pll);
 331        }
 332
 333        if (clk_register_clkdev(clk, name, NULL))
 334                pr_err("%s: failed to register lookup for %s", __func__, name);
 335
 336        return clk;
 337}
 338
 339/*
 340 * PLL2550x Clock Type
 341 */
 342
 343#define PLL2550X_R_MASK       (0x1)
 344#define PLL2550X_P_MASK       (0x3F)
 345#define PLL2550X_M_MASK       (0x3FF)
 346#define PLL2550X_S_MASK       (0x7)
 347#define PLL2550X_R_SHIFT      (20)
 348#define PLL2550X_P_SHIFT      (14)
 349#define PLL2550X_M_SHIFT      (4)
 350#define PLL2550X_S_SHIFT      (0)
 351
 352struct samsung_clk_pll2550x {
 353        struct clk_hw           hw;
 354        const void __iomem      *reg_base;
 355        unsigned long           offset;
 356};
 357
 358#define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
 359
 360static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
 361                                unsigned long parent_rate)
 362{
 363        struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
 364        u32 r, p, m, s, pll_stat;
 365        u64 fvco = parent_rate;
 366
 367        pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
 368        r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
 369        if (!r)
 370                return 0;
 371        p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
 372        m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
 373        s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
 374
 375        fvco *= m;
 376        do_div(fvco, (p << s));
 377
 378        return (unsigned long)fvco;
 379}
 380
 381static const struct clk_ops samsung_pll2550x_clk_ops = {
 382        .recalc_rate = samsung_pll2550x_recalc_rate,
 383};
 384
 385struct clk * __init samsung_clk_register_pll2550x(const char *name,
 386                        const char *pname, const void __iomem *reg_base,
 387                        const unsigned long offset)
 388{
 389        struct samsung_clk_pll2550x *pll;
 390        struct clk *clk;
 391        struct clk_init_data init;
 392
 393        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 394        if (!pll) {
 395                pr_err("%s: could not allocate pll clk %s\n", __func__, name);
 396                return NULL;
 397        }
 398
 399        init.name = name;
 400        init.ops = &samsung_pll2550x_clk_ops;
 401        init.flags = CLK_GET_RATE_NOCACHE;
 402        init.parent_names = &pname;
 403        init.num_parents = 1;
 404
 405        pll->hw.init = &init;
 406        pll->reg_base = reg_base;
 407        pll->offset = offset;
 408
 409        clk = clk_register(NULL, &pll->hw);
 410        if (IS_ERR(clk)) {
 411                pr_err("%s: failed to register pll clock %s\n", __func__,
 412                                name);
 413                kfree(pll);
 414        }
 415
 416        if (clk_register_clkdev(clk, name, NULL))
 417                pr_err("%s: failed to register lookup for %s", __func__, name);
 418
 419        return clk;
 420}
 421