linux/drivers/clk/spear/clk-vco-pll.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 ST Microelectronics
   3 * Viresh Kumar <vireshk@kernel.org>
   4 *
   5 * This file is licensed under the terms of the GNU General Public
   6 * License version 2. This program is licensed "as is" without any
   7 * warranty of any kind, whether express or implied.
   8 *
   9 * VCO-PLL clock implementation
  10 */
  11
  12#define pr_fmt(fmt) "clk-vco-pll: " fmt
  13
  14#include <linux/clk-provider.h>
  15#include <linux/slab.h>
  16#include <linux/io.h>
  17#include <linux/err.h>
  18#include "clk.h"
  19
  20/*
  21 * DOC: VCO-PLL clock
  22 *
  23 * VCO and PLL rate are derived from following equations:
  24 *
  25 * In normal mode
  26 * vco = (2 * M[15:8] * Fin)/N
  27 *
  28 * In Dithered mode
  29 * vco = (2 * M[15:0] * Fin)/(256 * N)
  30 *
  31 * pll_rate = pll/2^p
  32 *
  33 * vco and pll are very closely bound to each other, "vco needs to program:
  34 * mode, m & n" and "pll needs to program p", both share common enable/disable
  35 * logic.
  36 *
  37 * clk_register_vco_pll() registers instances of both vco & pll.
  38 * CLK_SET_RATE_PARENT flag is forced for pll, as it will always pass its
  39 * set_rate to vco. A single rate table exists for both the clocks, which
  40 * configures m, n and p.
  41 */
  42
  43/* PLL_CTR register masks */
  44#define PLL_MODE_NORMAL         0
  45#define PLL_MODE_FRACTION       1
  46#define PLL_MODE_DITH_DSM       2
  47#define PLL_MODE_DITH_SSM       3
  48#define PLL_MODE_MASK           3
  49#define PLL_MODE_SHIFT          3
  50#define PLL_ENABLE              2
  51
  52#define PLL_LOCK_SHIFT          0
  53#define PLL_LOCK_MASK           1
  54
  55/* PLL FRQ register masks */
  56#define PLL_NORM_FDBK_M_MASK    0xFF
  57#define PLL_NORM_FDBK_M_SHIFT   24
  58#define PLL_DITH_FDBK_M_MASK    0xFFFF
  59#define PLL_DITH_FDBK_M_SHIFT   16
  60#define PLL_DIV_P_MASK          0x7
  61#define PLL_DIV_P_SHIFT         8
  62#define PLL_DIV_N_MASK          0xFF
  63#define PLL_DIV_N_SHIFT         0
  64
  65#define to_clk_vco(_hw) container_of(_hw, struct clk_vco, hw)
  66#define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw)
  67
  68/* Calculates pll clk rate for specific value of mode, m, n and p */
  69static unsigned long pll_calc_rate(struct pll_rate_tbl *rtbl,
  70                unsigned long prate, int index, unsigned long *pll_rate)
  71{
  72        unsigned long rate = prate;
  73        unsigned int mode;
  74
  75        mode = rtbl[index].mode ? 256 : 1;
  76        rate = (((2 * rate / 10000) * rtbl[index].m) / (mode * rtbl[index].n));
  77
  78        if (pll_rate)
  79                *pll_rate = (rate / (1 << rtbl[index].p)) * 10000;
  80
  81        return rate * 10000;
  82}
  83
  84static long clk_pll_round_rate_index(struct clk_hw *hw, unsigned long drate,
  85                                unsigned long *prate, int *index)
  86{
  87        struct clk_pll *pll = to_clk_pll(hw);
  88        unsigned long prev_rate, vco_prev_rate, rate = 0;
  89        unsigned long vco_parent_rate =
  90                clk_hw_get_rate(clk_hw_get_parent(clk_hw_get_parent(hw)));
  91
  92        if (!prate) {
  93                pr_err("%s: prate is must for pll clk\n", __func__);
  94                return -EINVAL;
  95        }
  96
  97        for (*index = 0; *index < pll->vco->rtbl_cnt; (*index)++) {
  98                prev_rate = rate;
  99                vco_prev_rate = *prate;
 100                *prate = pll_calc_rate(pll->vco->rtbl, vco_parent_rate, *index,
 101                                &rate);
 102                if (drate < rate) {
 103                        /* previous clock was best */
 104                        if (*index) {
 105                                rate = prev_rate;
 106                                *prate = vco_prev_rate;
 107                                (*index)--;
 108                        }
 109                        break;
 110                }
 111        }
 112
 113        return rate;
 114}
 115
 116static long clk_pll_round_rate(struct clk_hw *hw, unsigned long drate,
 117                                unsigned long *prate)
 118{
 119        int unused;
 120
 121        return clk_pll_round_rate_index(hw, drate, prate, &unused);
 122}
 123
 124static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long
 125                parent_rate)
 126{
 127        struct clk_pll *pll = to_clk_pll(hw);
 128        unsigned long flags = 0;
 129        unsigned int p;
 130
 131        if (pll->vco->lock)
 132                spin_lock_irqsave(pll->vco->lock, flags);
 133
 134        p = readl_relaxed(pll->vco->cfg_reg);
 135
 136        if (pll->vco->lock)
 137                spin_unlock_irqrestore(pll->vco->lock, flags);
 138
 139        p = (p >> PLL_DIV_P_SHIFT) & PLL_DIV_P_MASK;
 140
 141        return parent_rate / (1 << p);
 142}
 143
 144static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate,
 145                                unsigned long prate)
 146{
 147        struct clk_pll *pll = to_clk_pll(hw);
 148        struct pll_rate_tbl *rtbl = pll->vco->rtbl;
 149        unsigned long flags = 0, val;
 150        int uninitialized_var(i);
 151
 152        clk_pll_round_rate_index(hw, drate, NULL, &i);
 153
 154        if (pll->vco->lock)
 155                spin_lock_irqsave(pll->vco->lock, flags);
 156
 157        val = readl_relaxed(pll->vco->cfg_reg);
 158        val &= ~(PLL_DIV_P_MASK << PLL_DIV_P_SHIFT);
 159        val |= (rtbl[i].p & PLL_DIV_P_MASK) << PLL_DIV_P_SHIFT;
 160        writel_relaxed(val, pll->vco->cfg_reg);
 161
 162        if (pll->vco->lock)
 163                spin_unlock_irqrestore(pll->vco->lock, flags);
 164
 165        return 0;
 166}
 167
 168static const struct clk_ops clk_pll_ops = {
 169        .recalc_rate = clk_pll_recalc_rate,
 170        .round_rate = clk_pll_round_rate,
 171        .set_rate = clk_pll_set_rate,
 172};
 173
 174static inline unsigned long vco_calc_rate(struct clk_hw *hw,
 175                unsigned long prate, int index)
 176{
 177        struct clk_vco *vco = to_clk_vco(hw);
 178
 179        return pll_calc_rate(vco->rtbl, prate, index, NULL);
 180}
 181
 182static long clk_vco_round_rate(struct clk_hw *hw, unsigned long drate,
 183                unsigned long *prate)
 184{
 185        struct clk_vco *vco = to_clk_vco(hw);
 186        int unused;
 187
 188        return clk_round_rate_index(hw, drate, *prate, vco_calc_rate,
 189                        vco->rtbl_cnt, &unused);
 190}
 191
 192static unsigned long clk_vco_recalc_rate(struct clk_hw *hw,
 193                unsigned long parent_rate)
 194{
 195        struct clk_vco *vco = to_clk_vco(hw);
 196        unsigned long flags = 0;
 197        unsigned int num = 2, den = 0, val, mode = 0;
 198
 199        if (vco->lock)
 200                spin_lock_irqsave(vco->lock, flags);
 201
 202        mode = (readl_relaxed(vco->mode_reg) >> PLL_MODE_SHIFT) & PLL_MODE_MASK;
 203
 204        val = readl_relaxed(vco->cfg_reg);
 205
 206        if (vco->lock)
 207                spin_unlock_irqrestore(vco->lock, flags);
 208
 209        den = (val >> PLL_DIV_N_SHIFT) & PLL_DIV_N_MASK;
 210
 211        /* calculate numerator & denominator */
 212        if (!mode) {
 213                /* Normal mode */
 214                num *= (val >> PLL_NORM_FDBK_M_SHIFT) & PLL_NORM_FDBK_M_MASK;
 215        } else {
 216                /* Dithered mode */
 217                num *= (val >> PLL_DITH_FDBK_M_SHIFT) & PLL_DITH_FDBK_M_MASK;
 218                den *= 256;
 219        }
 220
 221        if (!den) {
 222                WARN(1, "%s: denominator can't be zero\n", __func__);
 223                return 0;
 224        }
 225
 226        return (((parent_rate / 10000) * num) / den) * 10000;
 227}
 228
 229/* Configures new clock rate of vco */
 230static int clk_vco_set_rate(struct clk_hw *hw, unsigned long drate,
 231                                unsigned long prate)
 232{
 233        struct clk_vco *vco = to_clk_vco(hw);
 234        struct pll_rate_tbl *rtbl = vco->rtbl;
 235        unsigned long flags = 0, val;
 236        int i;
 237
 238        clk_round_rate_index(hw, drate, prate, vco_calc_rate, vco->rtbl_cnt,
 239                        &i);
 240
 241        if (vco->lock)
 242                spin_lock_irqsave(vco->lock, flags);
 243
 244        val = readl_relaxed(vco->mode_reg);
 245        val &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT);
 246        val |= (rtbl[i].mode & PLL_MODE_MASK) << PLL_MODE_SHIFT;
 247        writel_relaxed(val, vco->mode_reg);
 248
 249        val = readl_relaxed(vco->cfg_reg);
 250        val &= ~(PLL_DIV_N_MASK << PLL_DIV_N_SHIFT);
 251        val |= (rtbl[i].n & PLL_DIV_N_MASK) << PLL_DIV_N_SHIFT;
 252
 253        val &= ~(PLL_DITH_FDBK_M_MASK << PLL_DITH_FDBK_M_SHIFT);
 254        if (rtbl[i].mode)
 255                val |= (rtbl[i].m & PLL_DITH_FDBK_M_MASK) <<
 256                        PLL_DITH_FDBK_M_SHIFT;
 257        else
 258                val |= (rtbl[i].m & PLL_NORM_FDBK_M_MASK) <<
 259                        PLL_NORM_FDBK_M_SHIFT;
 260
 261        writel_relaxed(val, vco->cfg_reg);
 262
 263        if (vco->lock)
 264                spin_unlock_irqrestore(vco->lock, flags);
 265
 266        return 0;
 267}
 268
 269static const struct clk_ops clk_vco_ops = {
 270        .recalc_rate = clk_vco_recalc_rate,
 271        .round_rate = clk_vco_round_rate,
 272        .set_rate = clk_vco_set_rate,
 273};
 274
 275struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name,
 276                const char *vco_gate_name, const char *parent_name,
 277                unsigned long flags, void __iomem *mode_reg, void __iomem
 278                *cfg_reg, struct pll_rate_tbl *rtbl, u8 rtbl_cnt,
 279                spinlock_t *lock, struct clk **pll_clk,
 280                struct clk **vco_gate_clk)
 281{
 282        struct clk_vco *vco;
 283        struct clk_pll *pll;
 284        struct clk *vco_clk, *tpll_clk, *tvco_gate_clk;
 285        struct clk_init_data vco_init, pll_init;
 286        const char **vco_parent_name;
 287
 288        if (!vco_name || !pll_name || !parent_name || !mode_reg || !cfg_reg ||
 289                        !rtbl || !rtbl_cnt) {
 290                pr_err("Invalid arguments passed");
 291                return ERR_PTR(-EINVAL);
 292        }
 293
 294        vco = kzalloc(sizeof(*vco), GFP_KERNEL);
 295        if (!vco)
 296                return ERR_PTR(-ENOMEM);
 297
 298        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 299        if (!pll)
 300                goto free_vco;
 301
 302        /* struct clk_vco assignments */
 303        vco->mode_reg = mode_reg;
 304        vco->cfg_reg = cfg_reg;
 305        vco->rtbl = rtbl;
 306        vco->rtbl_cnt = rtbl_cnt;
 307        vco->lock = lock;
 308        vco->hw.init = &vco_init;
 309
 310        pll->vco = vco;
 311        pll->hw.init = &pll_init;
 312
 313        if (vco_gate_name) {
 314                tvco_gate_clk = clk_register_gate(NULL, vco_gate_name,
 315                                parent_name, 0, mode_reg, PLL_ENABLE, 0, lock);
 316                if (IS_ERR_OR_NULL(tvco_gate_clk))
 317                        goto free_pll;
 318
 319                if (vco_gate_clk)
 320                        *vco_gate_clk = tvco_gate_clk;
 321                vco_parent_name = &vco_gate_name;
 322        } else {
 323                vco_parent_name = &parent_name;
 324        }
 325
 326        vco_init.name = vco_name;
 327        vco_init.ops = &clk_vco_ops;
 328        vco_init.flags = flags;
 329        vco_init.parent_names = vco_parent_name;
 330        vco_init.num_parents = 1;
 331
 332        pll_init.name = pll_name;
 333        pll_init.ops = &clk_pll_ops;
 334        pll_init.flags = CLK_SET_RATE_PARENT;
 335        pll_init.parent_names = &vco_name;
 336        pll_init.num_parents = 1;
 337
 338        vco_clk = clk_register(NULL, &vco->hw);
 339        if (IS_ERR_OR_NULL(vco_clk))
 340                goto free_pll;
 341
 342        tpll_clk = clk_register(NULL, &pll->hw);
 343        if (IS_ERR_OR_NULL(tpll_clk))
 344                goto free_pll;
 345
 346        if (pll_clk)
 347                *pll_clk = tpll_clk;
 348
 349        return vco_clk;
 350
 351free_pll:
 352        kfree(pll);
 353free_vco:
 354        kfree(vco);
 355
 356        pr_err("Failed to register vco pll clock\n");
 357
 358        return ERR_PTR(-ENOMEM);
 359}
 360