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#include "common.h"
  27
  28#define PLL_OUTCTRL             BIT(0)
  29#define PLL_BYPASSNL            BIT(1)
  30#define PLL_RESET_N             BIT(2)
  31
  32static int clk_pll_enable(struct clk_hw *hw)
  33{
  34        struct clk_pll *pll = to_clk_pll(hw);
  35        int ret;
  36        u32 mask, val;
  37
  38        mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
  39        ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &val);
  40        if (ret)
  41                return ret;
  42
  43        /* Skip if already enabled or in FSM mode */
  44        if ((val & mask) == mask || val & PLL_VOTE_FSM_ENA)
  45                return 0;
  46
  47        /* Disable PLL bypass mode. */
  48        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL,
  49                                 PLL_BYPASSNL);
  50        if (ret)
  51                return ret;
  52
  53        /*
  54         * H/W requires a 5us delay between disabling the bypass and
  55         * de-asserting the reset. Delay 10us just to be safe.
  56         */
  57        udelay(10);
  58
  59        /* De-assert active-low PLL reset. */
  60        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N,
  61                                 PLL_RESET_N);
  62        if (ret)
  63                return ret;
  64
  65        /* Wait until PLL is locked. */
  66        udelay(50);
  67
  68        /* Enable PLL output. */
  69        return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL,
  70                                 PLL_OUTCTRL);
  71}
  72
  73static void clk_pll_disable(struct clk_hw *hw)
  74{
  75        struct clk_pll *pll = to_clk_pll(hw);
  76        u32 mask;
  77        u32 val;
  78
  79        regmap_read(pll->clkr.regmap, pll->mode_reg, &val);
  80        /* Skip if in FSM mode */
  81        if (val & PLL_VOTE_FSM_ENA)
  82                return;
  83        mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
  84        regmap_update_bits(pll->clkr.regmap, pll->mode_reg, mask, 0);
  85}
  86
  87static unsigned long
  88clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
  89{
  90        struct clk_pll *pll = to_clk_pll(hw);
  91        u32 l, m, n, config;
  92        unsigned long rate;
  93        u64 tmp;
  94
  95        regmap_read(pll->clkr.regmap, pll->l_reg, &l);
  96        regmap_read(pll->clkr.regmap, pll->m_reg, &m);
  97        regmap_read(pll->clkr.regmap, pll->n_reg, &n);
  98
  99        l &= 0x3ff;
 100        m &= 0x7ffff;
 101        n &= 0x7ffff;
 102
 103        rate = parent_rate * l;
 104        if (n) {
 105                tmp = parent_rate;
 106                tmp *= m;
 107                do_div(tmp, n);
 108                rate += tmp;
 109        }
 110        if (pll->post_div_width) {
 111                regmap_read(pll->clkr.regmap, pll->config_reg, &config);
 112                config >>= pll->post_div_shift;
 113                config &= BIT(pll->post_div_width) - 1;
 114                rate /= config + 1;
 115        }
 116
 117        return rate;
 118}
 119
 120static const
 121struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
 122{
 123        if (!f)
 124                return NULL;
 125
 126        for (; f->freq; f++)
 127                if (rate <= f->freq)
 128                        return f;
 129
 130        return NULL;
 131}
 132
 133static int
 134clk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 135{
 136        struct clk_pll *pll = to_clk_pll(hw);
 137        const struct pll_freq_tbl *f;
 138
 139        f = find_freq(pll->freq_tbl, req->rate);
 140        if (!f)
 141                req->rate = clk_pll_recalc_rate(hw, req->best_parent_rate);
 142        else
 143                req->rate = f->freq;
 144
 145        return 0;
 146}
 147
 148static int
 149clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
 150{
 151        struct clk_pll *pll = to_clk_pll(hw);
 152        const struct pll_freq_tbl *f;
 153        bool enabled;
 154        u32 mode;
 155        u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
 156
 157        f = find_freq(pll->freq_tbl, rate);
 158        if (!f)
 159                return -EINVAL;
 160
 161        regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
 162        enabled = (mode & enable_mask) == enable_mask;
 163
 164        if (enabled)
 165                clk_pll_disable(hw);
 166
 167        regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
 168        regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
 169        regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
 170        regmap_write(pll->clkr.regmap, pll->config_reg, f->ibits);
 171
 172        if (enabled)
 173                clk_pll_enable(hw);
 174
 175        return 0;
 176}
 177
 178const struct clk_ops clk_pll_ops = {
 179        .enable = clk_pll_enable,
 180        .disable = clk_pll_disable,
 181        .recalc_rate = clk_pll_recalc_rate,
 182        .determine_rate = clk_pll_determine_rate,
 183        .set_rate = clk_pll_set_rate,
 184};
 185EXPORT_SYMBOL_GPL(clk_pll_ops);
 186
 187static int wait_for_pll(struct clk_pll *pll)
 188{
 189        u32 val;
 190        int count;
 191        int ret;
 192        const char *name = clk_hw_get_name(&pll->clkr.hw);
 193
 194        /* Wait for pll to enable. */
 195        for (count = 200; count > 0; count--) {
 196                ret = regmap_read(pll->clkr.regmap, pll->status_reg, &val);
 197                if (ret)
 198                        return ret;
 199                if (val & BIT(pll->status_bit))
 200                        return 0;
 201                udelay(1);
 202        }
 203
 204        WARN(1, "%s didn't enable after voting for it!\n", name);
 205        return -ETIMEDOUT;
 206}
 207
 208static int clk_pll_vote_enable(struct clk_hw *hw)
 209{
 210        int ret;
 211        struct clk_pll *p = to_clk_pll(clk_hw_get_parent(hw));
 212
 213        ret = clk_enable_regmap(hw);
 214        if (ret)
 215                return ret;
 216
 217        return wait_for_pll(p);
 218}
 219
 220const struct clk_ops clk_pll_vote_ops = {
 221        .enable = clk_pll_vote_enable,
 222        .disable = clk_disable_regmap,
 223};
 224EXPORT_SYMBOL_GPL(clk_pll_vote_ops);
 225
 226static void clk_pll_configure(struct clk_pll *pll, struct regmap *regmap,
 227        const struct pll_config *config)
 228{
 229        u32 val;
 230        u32 mask;
 231
 232        regmap_write(regmap, pll->l_reg, config->l);
 233        regmap_write(regmap, pll->m_reg, config->m);
 234        regmap_write(regmap, pll->n_reg, config->n);
 235
 236        val = config->vco_val;
 237        val |= config->pre_div_val;
 238        val |= config->post_div_val;
 239        val |= config->mn_ena_mask;
 240        val |= config->main_output_mask;
 241        val |= config->aux_output_mask;
 242
 243        mask = config->vco_mask;
 244        mask |= config->pre_div_mask;
 245        mask |= config->post_div_mask;
 246        mask |= config->mn_ena_mask;
 247        mask |= config->main_output_mask;
 248        mask |= config->aux_output_mask;
 249
 250        regmap_update_bits(regmap, pll->config_reg, mask, val);
 251}
 252
 253void clk_pll_configure_sr(struct clk_pll *pll, struct regmap *regmap,
 254                const struct pll_config *config, bool fsm_mode)
 255{
 256        clk_pll_configure(pll, regmap, config);
 257        if (fsm_mode)
 258                qcom_pll_set_fsm_mode(regmap, pll->mode_reg, 1, 8);
 259}
 260EXPORT_SYMBOL_GPL(clk_pll_configure_sr);
 261
 262void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap,
 263                const struct pll_config *config, bool fsm_mode)
 264{
 265        clk_pll_configure(pll, regmap, config);
 266        if (fsm_mode)
 267                qcom_pll_set_fsm_mode(regmap, pll->mode_reg, 1, 0);
 268}
 269EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp);
 270
 271static int clk_pll_sr2_enable(struct clk_hw *hw)
 272{
 273        struct clk_pll *pll = to_clk_pll(hw);
 274        int ret;
 275        u32 mode;
 276
 277        ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
 278        if (ret)
 279                return ret;
 280
 281        /* Disable PLL bypass mode. */
 282        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL,
 283                                 PLL_BYPASSNL);
 284        if (ret)
 285                return ret;
 286
 287        /*
 288         * H/W requires a 5us delay between disabling the bypass and
 289         * de-asserting the reset. Delay 10us just to be safe.
 290         */
 291        udelay(10);
 292
 293        /* De-assert active-low PLL reset. */
 294        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N,
 295                                 PLL_RESET_N);
 296        if (ret)
 297                return ret;
 298
 299        ret = wait_for_pll(pll);
 300        if (ret)
 301                return ret;
 302
 303        /* Enable PLL output. */
 304        return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL,
 305                                 PLL_OUTCTRL);
 306}
 307
 308static int
 309clk_pll_sr2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
 310{
 311        struct clk_pll *pll = to_clk_pll(hw);
 312        const struct pll_freq_tbl *f;
 313        bool enabled;
 314        u32 mode;
 315        u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
 316
 317        f = find_freq(pll->freq_tbl, rate);
 318        if (!f)
 319                return -EINVAL;
 320
 321        regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
 322        enabled = (mode & enable_mask) == enable_mask;
 323
 324        if (enabled)
 325                clk_pll_disable(hw);
 326
 327        regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
 328        regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
 329        regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
 330
 331        if (enabled)
 332                clk_pll_sr2_enable(hw);
 333
 334        return 0;
 335}
 336
 337const struct clk_ops clk_pll_sr2_ops = {
 338        .enable = clk_pll_sr2_enable,
 339        .disable = clk_pll_disable,
 340        .set_rate = clk_pll_sr2_set_rate,
 341        .recalc_rate = clk_pll_recalc_rate,
 342        .determine_rate = clk_pll_determine_rate,
 343};
 344EXPORT_SYMBOL_GPL(clk_pll_sr2_ops);
 345