linux/drivers/clk/qcom/clk-pll.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
   3 *
   4 * This software is licensed under the terms of the GNU General Public
   5 * License version 2, as published by the Free Software Foundation, and
   6 * may be copied, distributed, and modified under those terms.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/bitops.h>
  16#include <linux/err.h>
  17#include <linux/bug.h>
  18#include <linux/delay.h>
  19#include <linux/export.h>
  20#include <linux/clk-provider.h>
  21#include <linux/regmap.h>
  22
  23#include <asm/div64.h>
  24
  25#include "clk-pll.h"
  26
  27#define PLL_OUTCTRL             BIT(0)
  28#define PLL_BYPASSNL            BIT(1)
  29#define PLL_RESET_N             BIT(2)
  30#define PLL_LOCK_COUNT_SHIFT    8
  31#define PLL_LOCK_COUNT_MASK     0x3f
  32#define PLL_BIAS_COUNT_SHIFT    14
  33#define PLL_BIAS_COUNT_MASK     0x3f
  34#define PLL_VOTE_FSM_ENA        BIT(20)
  35#define PLL_VOTE_FSM_RESET      BIT(21)
  36
  37static int clk_pll_enable(struct clk_hw *hw)
  38{
  39        struct clk_pll *pll = to_clk_pll(hw);
  40        int ret;
  41        u32 mask, val;
  42
  43        mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
  44        ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &val);
  45        if (ret)
  46                return ret;
  47
  48        /* Skip if already enabled or in FSM mode */
  49        if ((val & mask) == mask || val & PLL_VOTE_FSM_ENA)
  50                return 0;
  51
  52        /* Disable PLL bypass mode. */
  53        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL,
  54                                 PLL_BYPASSNL);
  55        if (ret)
  56                return ret;
  57
  58        /*
  59         * H/W requires a 5us delay between disabling the bypass and
  60         * de-asserting the reset. Delay 10us just to be safe.
  61         */
  62        udelay(10);
  63
  64        /* De-assert active-low PLL reset. */
  65        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N,
  66                                 PLL_RESET_N);
  67        if (ret)
  68                return ret;
  69
  70        /* Wait until PLL is locked. */
  71        udelay(50);
  72
  73        /* Enable PLL output. */
  74        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL,
  75                                 PLL_OUTCTRL);
  76        if (ret)
  77                return ret;
  78
  79        return 0;
  80}
  81
  82static void clk_pll_disable(struct clk_hw *hw)
  83{
  84        struct clk_pll *pll = to_clk_pll(hw);
  85        u32 mask;
  86        u32 val;
  87
  88        regmap_read(pll->clkr.regmap, pll->mode_reg, &val);
  89        /* Skip if in FSM mode */
  90        if (val & PLL_VOTE_FSM_ENA)
  91                return;
  92        mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
  93        regmap_update_bits(pll->clkr.regmap, pll->mode_reg, mask, 0);
  94}
  95
  96static unsigned long
  97clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
  98{
  99        struct clk_pll *pll = to_clk_pll(hw);
 100        u32 l, m, n, config;
 101        unsigned long rate;
 102        u64 tmp;
 103
 104        regmap_read(pll->clkr.regmap, pll->l_reg, &l);
 105        regmap_read(pll->clkr.regmap, pll->m_reg, &m);
 106        regmap_read(pll->clkr.regmap, pll->n_reg, &n);
 107
 108        l &= 0x3ff;
 109        m &= 0x7ffff;
 110        n &= 0x7ffff;
 111
 112        rate = parent_rate * l;
 113        if (n) {
 114                tmp = parent_rate;
 115                tmp *= m;
 116                do_div(tmp, n);
 117                rate += tmp;
 118        }
 119        if (pll->post_div_width) {
 120                regmap_read(pll->clkr.regmap, pll->config_reg, &config);
 121                config >>= pll->post_div_shift;
 122                config &= BIT(pll->post_div_width) - 1;
 123                rate /= config + 1;
 124        }
 125
 126        return rate;
 127}
 128
 129static const
 130struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
 131{
 132        if (!f)
 133                return NULL;
 134
 135        for (; f->freq; f++)
 136                if (rate <= f->freq)
 137                        return f;
 138
 139        return NULL;
 140}
 141
 142static long
 143clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
 144                       unsigned long min_rate, unsigned long max_rate,
 145                       unsigned long *p_rate, struct clk_hw **p)
 146{
 147        struct clk_pll *pll = to_clk_pll(hw);
 148        const struct pll_freq_tbl *f;
 149
 150        f = find_freq(pll->freq_tbl, rate);
 151        if (!f)
 152                return clk_pll_recalc_rate(hw, *p_rate);
 153
 154        return f->freq;
 155}
 156
 157static int
 158clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
 159{
 160        struct clk_pll *pll = to_clk_pll(hw);
 161        const struct pll_freq_tbl *f;
 162        bool enabled;
 163        u32 mode;
 164        u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
 165
 166        f = find_freq(pll->freq_tbl, rate);
 167        if (!f)
 168                return -EINVAL;
 169
 170        regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
 171        enabled = (mode & enable_mask) == enable_mask;
 172
 173        if (enabled)
 174                clk_pll_disable(hw);
 175
 176        regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
 177        regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
 178        regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
 179        regmap_write(pll->clkr.regmap, pll->config_reg, f->ibits);
 180
 181        if (enabled)
 182                clk_pll_enable(hw);
 183
 184        return 0;
 185}
 186
 187const struct clk_ops clk_pll_ops = {
 188        .enable = clk_pll_enable,
 189        .disable = clk_pll_disable,
 190        .recalc_rate = clk_pll_recalc_rate,
 191        .determine_rate = clk_pll_determine_rate,
 192        .set_rate = clk_pll_set_rate,
 193};
 194EXPORT_SYMBOL_GPL(clk_pll_ops);
 195
 196static int wait_for_pll(struct clk_pll *pll)
 197{
 198        u32 val;
 199        int count;
 200        int ret;
 201        const char *name = __clk_get_name(pll->clkr.hw.clk);
 202
 203        /* Wait for pll to enable. */
 204        for (count = 200; count > 0; count--) {
 205                ret = regmap_read(pll->clkr.regmap, pll->status_reg, &val);
 206                if (ret)
 207                        return ret;
 208                if (val & BIT(pll->status_bit))
 209                        return 0;
 210                udelay(1);
 211        }
 212
 213        WARN(1, "%s didn't enable after voting for it!\n", name);
 214        return -ETIMEDOUT;
 215}
 216
 217static int clk_pll_vote_enable(struct clk_hw *hw)
 218{
 219        int ret;
 220        struct clk_pll *p = to_clk_pll(__clk_get_hw(__clk_get_parent(hw->clk)));
 221
 222        ret = clk_enable_regmap(hw);
 223        if (ret)
 224                return ret;
 225
 226        return wait_for_pll(p);
 227}
 228
 229const struct clk_ops clk_pll_vote_ops = {
 230        .enable = clk_pll_vote_enable,
 231        .disable = clk_disable_regmap,
 232};
 233EXPORT_SYMBOL_GPL(clk_pll_vote_ops);
 234
 235static void
 236clk_pll_set_fsm_mode(struct clk_pll *pll, struct regmap *regmap, u8 lock_count)
 237{
 238        u32 val;
 239        u32 mask;
 240
 241        /* De-assert reset to FSM */
 242        regmap_update_bits(regmap, pll->mode_reg, PLL_VOTE_FSM_RESET, 0);
 243
 244        /* Program bias count and lock count */
 245        val = 1 << PLL_BIAS_COUNT_SHIFT | lock_count << PLL_LOCK_COUNT_SHIFT;
 246        mask = PLL_BIAS_COUNT_MASK << PLL_BIAS_COUNT_SHIFT;
 247        mask |= PLL_LOCK_COUNT_MASK << PLL_LOCK_COUNT_SHIFT;
 248        regmap_update_bits(regmap, pll->mode_reg, mask, val);
 249
 250        /* Enable PLL FSM voting */
 251        regmap_update_bits(regmap, pll->mode_reg, PLL_VOTE_FSM_ENA,
 252                PLL_VOTE_FSM_ENA);
 253}
 254
 255static void clk_pll_configure(struct clk_pll *pll, struct regmap *regmap,
 256        const struct pll_config *config)
 257{
 258        u32 val;
 259        u32 mask;
 260
 261        regmap_write(regmap, pll->l_reg, config->l);
 262        regmap_write(regmap, pll->m_reg, config->m);
 263        regmap_write(regmap, pll->n_reg, config->n);
 264
 265        val = config->vco_val;
 266        val |= config->pre_div_val;
 267        val |= config->post_div_val;
 268        val |= config->mn_ena_mask;
 269        val |= config->main_output_mask;
 270        val |= config->aux_output_mask;
 271
 272        mask = config->vco_mask;
 273        mask |= config->pre_div_mask;
 274        mask |= config->post_div_mask;
 275        mask |= config->mn_ena_mask;
 276        mask |= config->main_output_mask;
 277        mask |= config->aux_output_mask;
 278
 279        regmap_update_bits(regmap, pll->config_reg, mask, val);
 280}
 281
 282void clk_pll_configure_sr(struct clk_pll *pll, struct regmap *regmap,
 283                const struct pll_config *config, bool fsm_mode)
 284{
 285        clk_pll_configure(pll, regmap, config);
 286        if (fsm_mode)
 287                clk_pll_set_fsm_mode(pll, regmap, 8);
 288}
 289EXPORT_SYMBOL_GPL(clk_pll_configure_sr);
 290
 291void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap,
 292                const struct pll_config *config, bool fsm_mode)
 293{
 294        clk_pll_configure(pll, regmap, config);
 295        if (fsm_mode)
 296                clk_pll_set_fsm_mode(pll, regmap, 0);
 297}
 298EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp);
 299