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    *tuner_en_addr;
  51        void __iomem    *pcw_addr;
  52        const struct mtk_pll_data *data;
  53};
  54
  55static inline struct mtk_clk_pll *to_mtk_clk_pll(struct clk_hw *hw)
  56{
  57        return container_of(hw, struct mtk_clk_pll, hw);
  58}
  59
  60static int mtk_pll_is_prepared(struct clk_hw *hw)
  61{
  62        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
  63
  64        return (readl(pll->base_addr + REG_CON0) & CON0_BASE_EN) != 0;
  65}
  66
  67static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
  68                u32 pcw, int postdiv)
  69{
  70        int pcwbits = pll->data->pcwbits;
  71        int pcwfbits;
  72        u64 vco;
  73        u8 c = 0;
  74
  75        /* The fractional part of the PLL divider. */
  76        pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0;
  77
  78        vco = (u64)fin * pcw;
  79
  80        if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0)))
  81                c = 1;
  82
  83        vco >>= pcwfbits;
  84
  85        if (c)
  86                vco++;
  87
  88        return ((unsigned long)vco + postdiv - 1) / postdiv;
  89}
  90
  91static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
  92                int postdiv)
  93{
  94        u32 con1, val;
  95        int pll_en;
  96
  97        pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN;
  98
  99        /* set postdiv */
 100        val = readl(pll->pd_addr);
 101        val &= ~(POSTDIV_MASK << pll->data->pd_shift);
 102        val |= (ffs(postdiv) - 1) << pll->data->pd_shift;
 103
 104        /* postdiv and pcw need to set at the same time if on same register */
 105        if (pll->pd_addr != pll->pcw_addr) {
 106                writel(val, pll->pd_addr);
 107                val = readl(pll->pcw_addr);
 108        }
 109
 110        /* set pcw */
 111        val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1,
 112                        pll->data->pcw_shift);
 113        val |= pcw << pll->data->pcw_shift;
 114        writel(val, pll->pcw_addr);
 115
 116        con1 = readl(pll->base_addr + REG_CON1);
 117
 118        if (pll_en)
 119                con1 |= CON0_PCW_CHG;
 120
 121        writel(con1, pll->base_addr + REG_CON1);
 122        if (pll->tuner_addr)
 123                writel(con1 + 1, pll->tuner_addr);
 124
 125        if (pll_en)
 126                udelay(20);
 127}
 128
 129/*
 130 * mtk_pll_calc_values - calculate good values for a given input frequency.
 131 * @pll:        The pll
 132 * @pcw:        The pcw value (output)
 133 * @postdiv:    The post divider (output)
 134 * @freq:       The desired target frequency
 135 * @fin:        The input frequency
 136 *
 137 */
 138static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv,
 139                u32 freq, u32 fin)
 140{
 141        unsigned long fmin = 1000 * MHZ;
 142        const struct mtk_pll_div_table *div_table = pll->data->div_table;
 143        u64 _pcw;
 144        u32 val;
 145
 146        if (freq > pll->data->fmax)
 147                freq = pll->data->fmax;
 148
 149        if (div_table) {
 150                if (freq > div_table[0].freq)
 151                        freq = div_table[0].freq;
 152
 153                for (val = 0; div_table[val + 1].freq != 0; val++) {
 154                        if (freq > div_table[val + 1].freq)
 155                                break;
 156                }
 157                *postdiv = 1 << val;
 158        } else {
 159                for (val = 0; val < 5; val++) {
 160                        *postdiv = 1 << val;
 161                        if ((u64)freq * *postdiv >= fmin)
 162                                break;
 163                }
 164        }
 165
 166        /* _pcw = freq * postdiv / fin * 2^pcwfbits */
 167        _pcw = ((u64)freq << val) << (pll->data->pcwbits - INTEGER_BITS);
 168        do_div(_pcw, fin);
 169
 170        *pcw = (u32)_pcw;
 171}
 172
 173static int mtk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 174                unsigned long parent_rate)
 175{
 176        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 177        u32 pcw = 0;
 178        u32 postdiv;
 179
 180        mtk_pll_calc_values(pll, &pcw, &postdiv, rate, parent_rate);
 181        mtk_pll_set_rate_regs(pll, pcw, postdiv);
 182
 183        return 0;
 184}
 185
 186static unsigned long mtk_pll_recalc_rate(struct clk_hw *hw,
 187                unsigned long parent_rate)
 188{
 189        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 190        u32 postdiv;
 191        u32 pcw;
 192
 193        postdiv = (readl(pll->pd_addr) >> pll->data->pd_shift) & POSTDIV_MASK;
 194        postdiv = 1 << postdiv;
 195
 196        pcw = readl(pll->pcw_addr) >> pll->data->pcw_shift;
 197        pcw &= GENMASK(pll->data->pcwbits - 1, 0);
 198
 199        return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv);
 200}
 201
 202static long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
 203                unsigned long *prate)
 204{
 205        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 206        u32 pcw = 0;
 207        int postdiv;
 208
 209        mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate);
 210
 211        return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv);
 212}
 213
 214static int mtk_pll_prepare(struct clk_hw *hw)
 215{
 216        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 217        u32 r;
 218
 219        r = readl(pll->pwr_addr) | CON0_PWR_ON;
 220        writel(r, pll->pwr_addr);
 221        udelay(1);
 222
 223        r = readl(pll->pwr_addr) & ~CON0_ISO_EN;
 224        writel(r, pll->pwr_addr);
 225        udelay(1);
 226
 227        r = readl(pll->base_addr + REG_CON0);
 228        r |= pll->data->en_mask;
 229        writel(r, pll->base_addr + REG_CON0);
 230
 231        if (pll->tuner_en_addr) {
 232                r = readl(pll->tuner_en_addr) | BIT(pll->data->tuner_en_bit);
 233                writel(r, pll->tuner_en_addr);
 234        } else if (pll->tuner_addr) {
 235                r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN;
 236                writel(r, pll->tuner_addr);
 237        }
 238
 239        udelay(20);
 240
 241        if (pll->data->flags & HAVE_RST_BAR) {
 242                r = readl(pll->base_addr + REG_CON0);
 243                r |= pll->data->rst_bar_mask;
 244                writel(r, pll->base_addr + REG_CON0);
 245        }
 246
 247        return 0;
 248}
 249
 250static void mtk_pll_unprepare(struct clk_hw *hw)
 251{
 252        struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
 253        u32 r;
 254
 255        if (pll->data->flags & HAVE_RST_BAR) {
 256                r = readl(pll->base_addr + REG_CON0);
 257                r &= ~pll->data->rst_bar_mask;
 258                writel(r, pll->base_addr + REG_CON0);
 259        }
 260
 261        if (pll->tuner_en_addr) {
 262                r = readl(pll->tuner_en_addr) & ~BIT(pll->data->tuner_en_bit);
 263                writel(r, pll->tuner_en_addr);
 264        } else if (pll->tuner_addr) {
 265                r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN;
 266                writel(r, pll->tuner_addr);
 267        }
 268
 269        r = readl(pll->base_addr + REG_CON0);
 270        r &= ~CON0_BASE_EN;
 271        writel(r, pll->base_addr + REG_CON0);
 272
 273        r = readl(pll->pwr_addr) | CON0_ISO_EN;
 274        writel(r, pll->pwr_addr);
 275
 276        r = readl(pll->pwr_addr) & ~CON0_PWR_ON;
 277        writel(r, pll->pwr_addr);
 278}
 279
 280static const struct clk_ops mtk_pll_ops = {
 281        .is_prepared    = mtk_pll_is_prepared,
 282        .prepare        = mtk_pll_prepare,
 283        .unprepare      = mtk_pll_unprepare,
 284        .recalc_rate    = mtk_pll_recalc_rate,
 285        .round_rate     = mtk_pll_round_rate,
 286        .set_rate       = mtk_pll_set_rate,
 287};
 288
 289static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data,
 290                void __iomem *base)
 291{
 292        struct mtk_clk_pll *pll;
 293        struct clk_init_data init = {};
 294        struct clk *clk;
 295        const char *parent_name = "clk26m";
 296
 297        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 298        if (!pll)
 299                return ERR_PTR(-ENOMEM);
 300
 301        pll->base_addr = base + data->reg;
 302        pll->pwr_addr = base + data->pwr_reg;
 303        pll->pd_addr = base + data->pd_reg;
 304        pll->pcw_addr = base + data->pcw_reg;
 305        if (data->tuner_reg)
 306                pll->tuner_addr = base + data->tuner_reg;
 307        if (data->tuner_en_reg)
 308                pll->tuner_en_addr = base + data->tuner_en_reg;
 309        pll->hw.init = &init;
 310        pll->data = data;
 311
 312        init.name = data->name;
 313        init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0;
 314        init.ops = &mtk_pll_ops;
 315        if (data->parent_name)
 316                init.parent_names = &data->parent_name;
 317        else
 318                init.parent_names = &parent_name;
 319        init.num_parents = 1;
 320
 321        clk = clk_register(NULL, &pll->hw);
 322
 323        if (IS_ERR(clk))
 324                kfree(pll);
 325
 326        return clk;
 327}
 328
 329void mtk_clk_register_plls(struct device_node *node,
 330                const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data)
 331{
 332        void __iomem *base;
 333        int i;
 334        struct clk *clk;
 335
 336        base = of_iomap(node, 0);
 337        if (!base) {
 338                pr_err("%s(): ioremap failed\n", __func__);
 339                return;
 340        }
 341
 342        for (i = 0; i < num_plls; i++) {
 343                const struct mtk_pll_data *pll = &plls[i];
 344
 345                clk = mtk_clk_register_pll(pll, base);
 346
 347                if (IS_ERR(clk)) {
 348                        pr_err("Failed to register clk %s: %ld\n",
 349                                        pll->name, PTR_ERR(clk));
 350                        continue;
 351                }
 352
 353                clk_data->clks[pll->id] = clk;
 354        }
 355}
 356