linux/drivers/clk/at91/clk-sam9x60-pll.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  Copyright (C) 2019 Microchip Technology Inc.
   4 *
   5 */
   6
   7#include <linux/bitfield.h>
   8#include <linux/clk-provider.h>
   9#include <linux/clkdev.h>
  10#include <linux/clk/at91_pmc.h>
  11#include <linux/of.h>
  12#include <linux/mfd/syscon.h>
  13#include <linux/regmap.h>
  14
  15#include "pmc.h"
  16
  17#define PMC_PLL_CTRL0   0xc
  18#define         PMC_PLL_CTRL0_DIV_MSK           GENMASK(7, 0)
  19#define         PMC_PLL_CTRL0_ENPLL             BIT(28)
  20#define         PMC_PLL_CTRL0_ENPLLCK           BIT(29)
  21#define         PMC_PLL_CTRL0_ENLOCK            BIT(31)
  22
  23#define PMC_PLL_CTRL1   0x10
  24#define         PMC_PLL_CTRL1_FRACR_MSK         GENMASK(21, 0)
  25#define         PMC_PLL_CTRL1_MUL_MSK           GENMASK(30, 24)
  26
  27#define PMC_PLL_ACR     0x18
  28#define         PMC_PLL_ACR_DEFAULT             0x1b040010UL
  29#define         PMC_PLL_ACR_UTMIVR              BIT(12)
  30#define         PMC_PLL_ACR_UTMIBG              BIT(13)
  31#define         PMC_PLL_ACR_LOOP_FILTER_MSK     GENMASK(31, 24)
  32
  33#define PMC_PLL_UPDT    0x1c
  34#define         PMC_PLL_UPDT_UPDATE             BIT(8)
  35
  36#define PMC_PLL_ISR0    0xec
  37
  38#define PLL_DIV_MAX             (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
  39#define UPLL_DIV                2
  40#define PLL_MUL_MAX             (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
  41
  42#define PLL_MAX_ID              1
  43
  44struct sam9x60_pll {
  45        struct clk_hw hw;
  46        struct regmap *regmap;
  47        spinlock_t *lock;
  48        const struct clk_pll_characteristics *characteristics;
  49        u32 frac;
  50        u8 id;
  51        u8 div;
  52        u16 mul;
  53};
  54
  55#define to_sam9x60_pll(hw) container_of(hw, struct sam9x60_pll, hw)
  56
  57static inline bool sam9x60_pll_ready(struct regmap *regmap, int id)
  58{
  59        unsigned int status;
  60
  61        regmap_read(regmap, PMC_PLL_ISR0, &status);
  62
  63        return !!(status & BIT(id));
  64}
  65
  66static int sam9x60_pll_prepare(struct clk_hw *hw)
  67{
  68        struct sam9x60_pll *pll = to_sam9x60_pll(hw);
  69        struct regmap *regmap = pll->regmap;
  70        unsigned long flags;
  71        u8 div;
  72        u16 mul;
  73        u32 val;
  74
  75        spin_lock_irqsave(pll->lock, flags);
  76        regmap_write(regmap, PMC_PLL_UPDT, pll->id);
  77
  78        regmap_read(regmap, PMC_PLL_CTRL0, &val);
  79        div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val);
  80
  81        regmap_read(regmap, PMC_PLL_CTRL1, &val);
  82        mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val);
  83
  84        if (sam9x60_pll_ready(regmap, pll->id) &&
  85            (div == pll->div && mul == pll->mul)) {
  86                spin_unlock_irqrestore(pll->lock, flags);
  87                return 0;
  88        }
  89
  90        /* Recommended value for PMC_PLL_ACR */
  91        val = PMC_PLL_ACR_DEFAULT;
  92        regmap_write(regmap, PMC_PLL_ACR, val);
  93
  94        regmap_write(regmap, PMC_PLL_CTRL1,
  95                     FIELD_PREP(PMC_PLL_CTRL1_MUL_MSK, pll->mul));
  96
  97        if (pll->characteristics->upll) {
  98                /* Enable the UTMI internal bandgap */
  99                val |= PMC_PLL_ACR_UTMIBG;
 100                regmap_write(regmap, PMC_PLL_ACR, val);
 101
 102                udelay(10);
 103
 104                /* Enable the UTMI internal regulator */
 105                val |= PMC_PLL_ACR_UTMIVR;
 106                regmap_write(regmap, PMC_PLL_ACR, val);
 107
 108                udelay(10);
 109        }
 110
 111        regmap_update_bits(regmap, PMC_PLL_UPDT,
 112                           PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
 113
 114        regmap_write(regmap, PMC_PLL_CTRL0,
 115                     PMC_PLL_CTRL0_ENLOCK | PMC_PLL_CTRL0_ENPLL |
 116                     PMC_PLL_CTRL0_ENPLLCK | pll->div);
 117
 118        regmap_update_bits(regmap, PMC_PLL_UPDT,
 119                           PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
 120
 121        while (!sam9x60_pll_ready(regmap, pll->id))
 122                cpu_relax();
 123
 124        spin_unlock_irqrestore(pll->lock, flags);
 125
 126        return 0;
 127}
 128
 129static int sam9x60_pll_is_prepared(struct clk_hw *hw)
 130{
 131        struct sam9x60_pll *pll = to_sam9x60_pll(hw);
 132
 133        return sam9x60_pll_ready(pll->regmap, pll->id);
 134}
 135
 136static void sam9x60_pll_unprepare(struct clk_hw *hw)
 137{
 138        struct sam9x60_pll *pll = to_sam9x60_pll(hw);
 139        unsigned long flags;
 140
 141        spin_lock_irqsave(pll->lock, flags);
 142
 143        regmap_write(pll->regmap, PMC_PLL_UPDT, pll->id);
 144
 145        regmap_update_bits(pll->regmap, PMC_PLL_CTRL0,
 146                           PMC_PLL_CTRL0_ENPLLCK, 0);
 147
 148        regmap_update_bits(pll->regmap, PMC_PLL_UPDT,
 149                           PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
 150
 151        regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, PMC_PLL_CTRL0_ENPLL, 0);
 152
 153        if (pll->characteristics->upll)
 154                regmap_update_bits(pll->regmap, PMC_PLL_ACR,
 155                                   PMC_PLL_ACR_UTMIBG | PMC_PLL_ACR_UTMIVR, 0);
 156
 157        regmap_update_bits(pll->regmap, PMC_PLL_UPDT,
 158                           PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
 159
 160        spin_unlock_irqrestore(pll->lock, flags);
 161}
 162
 163static unsigned long sam9x60_pll_recalc_rate(struct clk_hw *hw,
 164                                             unsigned long parent_rate)
 165{
 166        struct sam9x60_pll *pll = to_sam9x60_pll(hw);
 167
 168        return (parent_rate * (pll->mul + 1)) / (pll->div + 1);
 169}
 170
 171static long sam9x60_pll_get_best_div_mul(struct sam9x60_pll *pll,
 172                                         unsigned long rate,
 173                                         unsigned long parent_rate,
 174                                         bool update)
 175{
 176        const struct clk_pll_characteristics *characteristics =
 177                                                        pll->characteristics;
 178        unsigned long bestremainder = ULONG_MAX;
 179        unsigned long maxdiv, mindiv, tmpdiv;
 180        long bestrate = -ERANGE;
 181        unsigned long bestdiv = 0;
 182        unsigned long bestmul = 0;
 183        unsigned long bestfrac = 0;
 184
 185        if (rate < characteristics->output[0].min ||
 186            rate > characteristics->output[0].max)
 187                return -ERANGE;
 188
 189        if (!pll->characteristics->upll) {
 190                mindiv = parent_rate / rate;
 191                if (mindiv < 2)
 192                        mindiv = 2;
 193
 194                maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX, rate);
 195                if (maxdiv > PLL_DIV_MAX)
 196                        maxdiv = PLL_DIV_MAX;
 197        } else {
 198                mindiv = maxdiv = UPLL_DIV;
 199        }
 200
 201        for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) {
 202                unsigned long remainder;
 203                unsigned long tmprate;
 204                unsigned long tmpmul;
 205                unsigned long tmpfrac = 0;
 206
 207                /*
 208                 * Calculate the multiplier associated with the current
 209                 * divider that provide the closest rate to the requested one.
 210                 */
 211                tmpmul = mult_frac(rate, tmpdiv, parent_rate);
 212                tmprate = mult_frac(parent_rate, tmpmul, tmpdiv);
 213                remainder = rate - tmprate;
 214
 215                if (remainder) {
 216                        tmpfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * tmpdiv * (1 << 22),
 217                                                        parent_rate);
 218
 219                        tmprate += DIV_ROUND_CLOSEST_ULL((u64)tmpfrac * parent_rate,
 220                                                         tmpdiv * (1 << 22));
 221
 222                        if (tmprate > rate)
 223                                remainder = tmprate - rate;
 224                        else
 225                                remainder = rate - tmprate;
 226                }
 227
 228                /*
 229                 * Compare the remainder with the best remainder found until
 230                 * now and elect a new best multiplier/divider pair if the
 231                 * current remainder is smaller than the best one.
 232                 */
 233                if (remainder < bestremainder) {
 234                        bestremainder = remainder;
 235                        bestdiv = tmpdiv;
 236                        bestmul = tmpmul;
 237                        bestrate = tmprate;
 238                        bestfrac = tmpfrac;
 239                }
 240
 241                /* We've found a perfect match!  */
 242                if (!remainder)
 243                        break;
 244        }
 245
 246        /* Check if bestrate is a valid output rate  */
 247        if (bestrate < characteristics->output[0].min &&
 248            bestrate > characteristics->output[0].max)
 249                return -ERANGE;
 250
 251        if (update) {
 252                pll->div = bestdiv - 1;
 253                pll->mul = bestmul - 1;
 254                pll->frac = bestfrac;
 255        }
 256
 257        return bestrate;
 258}
 259
 260static long sam9x60_pll_round_rate(struct clk_hw *hw, unsigned long rate,
 261                                   unsigned long *parent_rate)
 262{
 263        struct sam9x60_pll *pll = to_sam9x60_pll(hw);
 264
 265        return sam9x60_pll_get_best_div_mul(pll, rate, *parent_rate, false);
 266}
 267
 268static int sam9x60_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 269                                unsigned long parent_rate)
 270{
 271        struct sam9x60_pll *pll = to_sam9x60_pll(hw);
 272
 273        return sam9x60_pll_get_best_div_mul(pll, rate, parent_rate, true);
 274}
 275
 276static const struct clk_ops pll_ops = {
 277        .prepare = sam9x60_pll_prepare,
 278        .unprepare = sam9x60_pll_unprepare,
 279        .is_prepared = sam9x60_pll_is_prepared,
 280        .recalc_rate = sam9x60_pll_recalc_rate,
 281        .round_rate = sam9x60_pll_round_rate,
 282        .set_rate = sam9x60_pll_set_rate,
 283};
 284
 285struct clk_hw * __init
 286sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock,
 287                         const char *name, const char *parent_name, u8 id,
 288                         const struct clk_pll_characteristics *characteristics)
 289{
 290        struct sam9x60_pll *pll;
 291        struct clk_hw *hw;
 292        struct clk_init_data init;
 293        unsigned int pllr;
 294        int ret;
 295
 296        if (id > PLL_MAX_ID)
 297                return ERR_PTR(-EINVAL);
 298
 299        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 300        if (!pll)
 301                return ERR_PTR(-ENOMEM);
 302
 303        init.name = name;
 304        init.ops = &pll_ops;
 305        init.parent_names = &parent_name;
 306        init.num_parents = 1;
 307        init.flags = CLK_SET_RATE_GATE;
 308
 309        pll->id = id;
 310        pll->hw.init = &init;
 311        pll->characteristics = characteristics;
 312        pll->regmap = regmap;
 313        pll->lock = lock;
 314
 315        regmap_write(regmap, PMC_PLL_UPDT, id);
 316        regmap_read(regmap, PMC_PLL_CTRL0, &pllr);
 317        pll->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, pllr);
 318        regmap_read(regmap, PMC_PLL_CTRL1, &pllr);
 319        pll->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, pllr);
 320
 321        hw = &pll->hw;
 322        ret = clk_hw_register(NULL, hw);
 323        if (ret) {
 324                kfree(pll);
 325                hw = ERR_PTR(ret);
 326        }
 327
 328        return hw;
 329}
 330
 331