linux/drivers/clk/mediatek/clk-pll.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014 MediaTek Inc.
   3 * Author: James Liao <jamesjj.liao@mediatek.com>
   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 program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 */
  14
  15#include <linux/of.h>
  16#include <linux/of_address.h>
  17#include <linux/io.h>
  18#include <linux/slab.h>
  19#include <linux/clkdev.h>
  20#include <linux/delay.h>
  21
  22#include "clk-mtk.h"
  23
  24#define REG_CON0                0
  25#define REG_CON1                4
  26
  27#define CON0_BASE_EN            BIT(0)
  28#define CON0_PWR_ON             BIT(0)
  29#define CON0_ISO_EN             BIT(1)
  30#define CON0_PCW_CHG            BIT(31)
  31
  32#define AUDPLL_TUNER_EN         BIT(31)
  33
  34#define POSTDIV_MASK            0x7
  35#define INTEGER_BITS            7
  36
  37/*
  38 * MediaTek PLLs are configured through their pcw value. The pcw value describes
  39 * a divider in the PLL feedback loop which consists of 7 bits for the integer
  40 * part and the remaining bits (if present) for the fractional part. Also they
  41 * have a 3 bit power-of-two post divider.
  42 */
  43
  44struct mtk_clk_pll {
  45        struct clk_hw   hw;
  46        void __iomem    *base_addr;
  47        void __iomem    *pd_addr;
  48        void __iomem    *pwr_addr;
  49        void __iomem    *tuner_addr;
  50        void __iomem    *pcw_addr;
  51        const struct mtk_pll_data *data;
  52};
  53
  54static inline struct mtk_clk_pll *to_mtk_clk_pll(struct clk_hw *hw)
  55{
  56        return container_of(hw, struct mtk_clk_pll, hw);
  57}
  58
  59static int mtk_pll_is_prepared(struct clk_hw *hw)
  60{
  61        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
  62
  63        return (readl(pll->base_addr + REG_CON0) & CON0_BASE_EN) != 0;
  64}
  65
  66static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
  67                u32 pcw, int postdiv)
  68{
  69        int pcwbits = pll->data->pcwbits;
  70        int pcwfbits;
  71        u64 vco;
  72        u8 c = 0;
  73
  74        /* The fractional part of the PLL divider. */
  75        pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0;
  76
  77        vco = (u64)fin * pcw;
  78
  79        if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0)))
  80                c = 1;
  81
  82        vco >>= pcwfbits;
  83
  84        if (c)
  85                vco++;
  86
  87        return ((unsigned long)vco + postdiv - 1) / postdiv;
  88}
  89
  90static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
  91                int postdiv)
  92{
  93        u32 con1, pd, val;
  94        int pll_en;
  95
  96        /* set postdiv */
  97        pd = readl(pll->pd_addr);
  98        pd &= ~(POSTDIV_MASK << pll->data->pd_shift);
  99        pd |= (ffs(postdiv) - 1) << pll->data->pd_shift;
 100        writel(pd, pll->pd_addr);
 101
 102        pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN;
 103
 104        /* set pcw */
 105        val = readl(pll->pcw_addr);
 106
 107        val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1,
 108                        pll->data->pcw_shift);
 109        val |= pcw << pll->data->pcw_shift;
 110        writel(val, pll->pcw_addr);
 111
 112        con1 = readl(pll->base_addr + REG_CON1);
 113
 114        if (pll_en)
 115                con1 |= CON0_PCW_CHG;
 116
 117        writel(con1, pll->base_addr + REG_CON1);
 118        if (pll->tuner_addr)
 119                writel(con1 + 1, pll->tuner_addr);
 120
 121        if (pll_en)
 122                udelay(20);
 123}
 124
 125/*
 126 * mtk_pll_calc_values - calculate good values for a given input frequency.
 127 * @pll:        The pll
 128 * @pcw:        The pcw value (output)
 129 * @postdiv:    The post divider (output)
 130 * @freq:       The desired target frequency
 131 * @fin:        The input frequency
 132 *
 133 */
 134static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv,
 135                u32 freq, u32 fin)
 136{
 137        unsigned long fmin = 1000 * MHZ;
 138        u64 _pcw;
 139        u32 val;
 140
 141        if (freq > pll->data->fmax)
 142                freq = pll->data->fmax;
 143
 144        for (val = 0; val < 4; val++) {
 145                *postdiv = 1 << val;
 146                if (freq * *postdiv >= fmin)
 147                        break;
 148        }
 149
 150        /* _pcw = freq * postdiv / fin * 2^pcwfbits */
 151        _pcw = ((u64)freq << val) << (pll->data->pcwbits - INTEGER_BITS);
 152        do_div(_pcw, fin);
 153
 154        *pcw = (u32)_pcw;
 155}
 156
 157static int mtk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 158                unsigned long parent_rate)
 159{
 160        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 161        u32 pcw = 0;
 162        u32 postdiv;
 163
 164        mtk_pll_calc_values(pll, &pcw, &postdiv, rate, parent_rate);
 165        mtk_pll_set_rate_regs(pll, pcw, postdiv);
 166
 167        return 0;
 168}
 169
 170static unsigned long mtk_pll_recalc_rate(struct clk_hw *hw,
 171                unsigned long parent_rate)
 172{
 173        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 174        u32 postdiv;
 175        u32 pcw;
 176
 177        postdiv = (readl(pll->pd_addr) >> pll->data->pd_shift) & POSTDIV_MASK;
 178        postdiv = 1 << postdiv;
 179
 180        pcw = readl(pll->pcw_addr) >> pll->data->pcw_shift;
 181        pcw &= GENMASK(pll->data->pcwbits - 1, 0);
 182
 183        return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv);
 184}
 185
 186static long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
 187                unsigned long *prate)
 188{
 189        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 190        u32 pcw = 0;
 191        int postdiv;
 192
 193        mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate);
 194
 195        return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv);
 196}
 197
 198static int mtk_pll_prepare(struct clk_hw *hw)
 199{
 200        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 201        u32 r;
 202
 203        r = readl(pll->pwr_addr) | CON0_PWR_ON;
 204        writel(r, pll->pwr_addr);
 205        udelay(1);
 206
 207        r = readl(pll->pwr_addr) & ~CON0_ISO_EN;
 208        writel(r, pll->pwr_addr);
 209        udelay(1);
 210
 211        r = readl(pll->base_addr + REG_CON0);
 212        r |= pll->data->en_mask;
 213        writel(r, pll->base_addr + REG_CON0);
 214
 215        if (pll->tuner_addr) {
 216                r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN;
 217                writel(r, pll->tuner_addr);
 218        }
 219
 220        udelay(20);
 221
 222        if (pll->data->flags & HAVE_RST_BAR) {
 223                r = readl(pll->base_addr + REG_CON0);
 224                r |= pll->data->rst_bar_mask;
 225                writel(r, pll->base_addr + REG_CON0);
 226        }
 227
 228        return 0;
 229}
 230
 231static void mtk_pll_unprepare(struct clk_hw *hw)
 232{
 233        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 234        u32 r;
 235
 236        if (pll->data->flags & HAVE_RST_BAR) {
 237                r = readl(pll->base_addr + REG_CON0);
 238                r &= ~pll->data->rst_bar_mask;
 239                writel(r, pll->base_addr + REG_CON0);
 240        }
 241
 242        if (pll->tuner_addr) {
 243                r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN;
 244                writel(r, pll->tuner_addr);
 245        }
 246
 247        r = readl(pll->base_addr + REG_CON0);
 248        r &= ~CON0_BASE_EN;
 249        writel(r, pll->base_addr + REG_CON0);
 250
 251        r = readl(pll->pwr_addr) | CON0_ISO_EN;
 252        writel(r, pll->pwr_addr);
 253
 254        r = readl(pll->pwr_addr) & ~CON0_PWR_ON;
 255        writel(r, pll->pwr_addr);
 256}
 257
 258static const struct clk_ops mtk_pll_ops = {
 259        .is_prepared    = mtk_pll_is_prepared,
 260        .prepare        = mtk_pll_prepare,
 261        .unprepare      = mtk_pll_unprepare,
 262        .recalc_rate    = mtk_pll_recalc_rate,
 263        .round_rate     = mtk_pll_round_rate,
 264        .set_rate       = mtk_pll_set_rate,
 265};
 266
 267static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data,
 268                void __iomem *base)
 269{
 270        struct mtk_clk_pll *pll;
 271        struct clk_init_data init = {};
 272        struct clk *clk;
 273        const char *parent_name = "clk26m";
 274
 275        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 276        if (!pll)
 277                return ERR_PTR(-ENOMEM);
 278
 279        pll->base_addr = base + data->reg;
 280        pll->pwr_addr = base + data->pwr_reg;
 281        pll->pd_addr = base + data->pd_reg;
 282        pll->pcw_addr = base + data->pcw_reg;
 283        if (data->tuner_reg)
 284                pll->tuner_addr = base + data->tuner_reg;
 285        pll->hw.init = &init;
 286        pll->data = data;
 287
 288        init.name = data->name;
 289        init.ops = &mtk_pll_ops;
 290        init.parent_names = &parent_name;
 291        init.num_parents = 1;
 292
 293        clk = clk_register(NULL, &pll->hw);
 294
 295        if (IS_ERR(clk))
 296                kfree(pll);
 297
 298        return clk;
 299}
 300
 301void __init mtk_clk_register_plls(struct device_node *node,
 302                const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data)
 303{
 304        void __iomem *base;
 305        int r, i;
 306        struct clk *clk;
 307
 308        base = of_iomap(node, 0);
 309        if (!base) {
 310                pr_err("%s(): ioremap failed\n", __func__);
 311                return;
 312        }
 313
 314        for (i = 0; i < num_plls; i++) {
 315                const struct mtk_pll_data *pll = &plls[i];
 316
 317                clk = mtk_clk_register_pll(pll, base);
 318
 319                if (IS_ERR(clk)) {
 320                        pr_err("Failed to register clk %s: %ld\n",
 321                                        pll->name, PTR_ERR(clk));
 322                        continue;
 323                }
 324
 325                clk_data->clks[pll->id] = clk;
 326        }
 327
 328        r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
 329        if (r)
 330                pr_err("%s(): could not register clock provider: %d\n",
 331                        __func__, r);
 332}
 333