linux/drivers/clk/at91/clk-pll.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
   4 */
   5
   6#include <linux/clk-provider.h>
   7#include <linux/clkdev.h>
   8#include <linux/clk/at91_pmc.h>
   9#include <linux/of.h>
  10#include <linux/mfd/syscon.h>
  11#include <linux/regmap.h>
  12
  13#include "pmc.h"
  14
  15#define PLL_STATUS_MASK(id)     (1 << (1 + (id)))
  16#define PLL_REG(id)             (AT91_CKGR_PLLAR + ((id) * 4))
  17#define PLL_DIV_MASK            0xff
  18#define PLL_DIV_MAX             PLL_DIV_MASK
  19#define PLL_DIV(reg)            ((reg) & PLL_DIV_MASK)
  20#define PLL_MUL(reg, layout)    (((reg) >> (layout)->mul_shift) & \
  21                                 (layout)->mul_mask)
  22#define PLL_MUL_MIN             2
  23#define PLL_MUL_MASK(layout)    ((layout)->mul_mask)
  24#define PLL_MUL_MAX(layout)     (PLL_MUL_MASK(layout) + 1)
  25#define PLL_ICPR_SHIFT(id)      ((id) * 16)
  26#define PLL_ICPR_MASK(id)       (0xffff << PLL_ICPR_SHIFT(id))
  27#define PLL_MAX_COUNT           0x3f
  28#define PLL_COUNT_SHIFT         8
  29#define PLL_OUT_SHIFT           14
  30#define PLL_MAX_ID              1
  31
  32#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw)
  33
  34struct clk_pll {
  35        struct clk_hw hw;
  36        struct regmap *regmap;
  37        u8 id;
  38        u8 div;
  39        u8 range;
  40        u16 mul;
  41        const struct clk_pll_layout *layout;
  42        const struct clk_pll_characteristics *characteristics;
  43};
  44
  45static inline bool clk_pll_ready(struct regmap *regmap, int id)
  46{
  47        unsigned int status;
  48
  49        regmap_read(regmap, AT91_PMC_SR, &status);
  50
  51        return status & PLL_STATUS_MASK(id) ? 1 : 0;
  52}
  53
  54static int clk_pll_prepare(struct clk_hw *hw)
  55{
  56        struct clk_pll *pll = to_clk_pll(hw);
  57        struct regmap *regmap = pll->regmap;
  58        const struct clk_pll_layout *layout = pll->layout;
  59        const struct clk_pll_characteristics *characteristics =
  60                                                        pll->characteristics;
  61        u8 id = pll->id;
  62        u32 mask = PLL_STATUS_MASK(id);
  63        int offset = PLL_REG(id);
  64        u8 out = 0;
  65        unsigned int pllr;
  66        unsigned int status;
  67        u8 div;
  68        u16 mul;
  69
  70        regmap_read(regmap, offset, &pllr);
  71        div = PLL_DIV(pllr);
  72        mul = PLL_MUL(pllr, layout);
  73
  74        regmap_read(regmap, AT91_PMC_SR, &status);
  75        if ((status & mask) &&
  76            (div == pll->div && mul == pll->mul))
  77                return 0;
  78
  79        if (characteristics->out)
  80                out = characteristics->out[pll->range];
  81
  82        if (characteristics->icpll)
  83                regmap_update_bits(regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id),
  84                        characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id));
  85
  86        regmap_update_bits(regmap, offset, layout->pllr_mask,
  87                        pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
  88                        (out << PLL_OUT_SHIFT) |
  89                        ((pll->mul & layout->mul_mask) << layout->mul_shift));
  90
  91        while (!clk_pll_ready(regmap, pll->id))
  92                cpu_relax();
  93
  94        return 0;
  95}
  96
  97static int clk_pll_is_prepared(struct clk_hw *hw)
  98{
  99        struct clk_pll *pll = to_clk_pll(hw);
 100
 101        return clk_pll_ready(pll->regmap, pll->id);
 102}
 103
 104static void clk_pll_unprepare(struct clk_hw *hw)
 105{
 106        struct clk_pll *pll = to_clk_pll(hw);
 107        unsigned int mask = pll->layout->pllr_mask;
 108
 109        regmap_update_bits(pll->regmap, PLL_REG(pll->id), mask, ~mask);
 110}
 111
 112static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
 113                                         unsigned long parent_rate)
 114{
 115        struct clk_pll *pll = to_clk_pll(hw);
 116
 117        if (!pll->div || !pll->mul)
 118                return 0;
 119
 120        return (parent_rate / pll->div) * (pll->mul + 1);
 121}
 122
 123static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
 124                                     unsigned long parent_rate,
 125                                     u32 *div, u32 *mul,
 126                                     u32 *index) {
 127        const struct clk_pll_layout *layout = pll->layout;
 128        const struct clk_pll_characteristics *characteristics =
 129                                                        pll->characteristics;
 130        unsigned long bestremainder = ULONG_MAX;
 131        unsigned long maxdiv, mindiv, tmpdiv;
 132        long bestrate = -ERANGE;
 133        unsigned long bestdiv;
 134        unsigned long bestmul;
 135        int i = 0;
 136
 137        /* Check if parent_rate is a valid input rate */
 138        if (parent_rate < characteristics->input.min)
 139                return -ERANGE;
 140
 141        /*
 142         * Calculate minimum divider based on the minimum multiplier, the
 143         * parent_rate and the requested rate.
 144         * Should always be 2 according to the input and output characteristics
 145         * of the PLL blocks.
 146         */
 147        mindiv = (parent_rate * PLL_MUL_MIN) / rate;
 148        if (!mindiv)
 149                mindiv = 1;
 150
 151        if (parent_rate > characteristics->input.max) {
 152                tmpdiv = DIV_ROUND_UP(parent_rate, characteristics->input.max);
 153                if (tmpdiv > PLL_DIV_MAX)
 154                        return -ERANGE;
 155
 156                if (tmpdiv > mindiv)
 157                        mindiv = tmpdiv;
 158        }
 159
 160        /*
 161         * Calculate the maximum divider which is limited by PLL register
 162         * layout (limited by the MUL or DIV field size).
 163         */
 164        maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX(layout), rate);
 165        if (maxdiv > PLL_DIV_MAX)
 166                maxdiv = PLL_DIV_MAX;
 167
 168        /*
 169         * Iterate over the acceptable divider values to find the best
 170         * divider/multiplier pair (the one that generates the closest
 171         * rate to the requested one).
 172         */
 173        for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) {
 174                unsigned long remainder;
 175                unsigned long tmprate;
 176                unsigned long tmpmul;
 177
 178                /*
 179                 * Calculate the multiplier associated with the current
 180                 * divider that provide the closest rate to the requested one.
 181                 */
 182                tmpmul = DIV_ROUND_CLOSEST(rate, parent_rate / tmpdiv);
 183                tmprate = (parent_rate / tmpdiv) * tmpmul;
 184                if (tmprate > rate)
 185                        remainder = tmprate - rate;
 186                else
 187                        remainder = rate - tmprate;
 188
 189                /*
 190                 * Compare the remainder with the best remainder found until
 191                 * now and elect a new best multiplier/divider pair if the
 192                 * current remainder is smaller than the best one.
 193                 */
 194                if (remainder < bestremainder) {
 195                        bestremainder = remainder;
 196                        bestdiv = tmpdiv;
 197                        bestmul = tmpmul;
 198                        bestrate = tmprate;
 199                }
 200
 201                /*
 202                 * We've found a perfect match!
 203                 * Stop searching now and use this multiplier/divider pair.
 204                 */
 205                if (!remainder)
 206                        break;
 207        }
 208
 209        /* We haven't found any multiplier/divider pair => return -ERANGE */
 210        if (bestrate < 0)
 211                return bestrate;
 212
 213        /* Check if bestrate is a valid output rate  */
 214        for (i = 0; i < characteristics->num_output; i++) {
 215                if (bestrate >= characteristics->output[i].min &&
 216                    bestrate <= characteristics->output[i].max)
 217                        break;
 218        }
 219
 220        if (i >= characteristics->num_output)
 221                return -ERANGE;
 222
 223        if (div)
 224                *div = bestdiv;
 225        if (mul)
 226                *mul = bestmul - 1;
 227        if (index)
 228                *index = i;
 229
 230        return bestrate;
 231}
 232
 233static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
 234                                        unsigned long *parent_rate)
 235{
 236        struct clk_pll *pll = to_clk_pll(hw);
 237
 238        return clk_pll_get_best_div_mul(pll, rate, *parent_rate,
 239                                        NULL, NULL, NULL);
 240}
 241
 242static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 243                            unsigned long parent_rate)
 244{
 245        struct clk_pll *pll = to_clk_pll(hw);
 246        long ret;
 247        u32 div;
 248        u32 mul;
 249        u32 index;
 250
 251        ret = clk_pll_get_best_div_mul(pll, rate, parent_rate,
 252                                       &div, &mul, &index);
 253        if (ret < 0)
 254                return ret;
 255
 256        pll->range = index;
 257        pll->div = div;
 258        pll->mul = mul;
 259
 260        return 0;
 261}
 262
 263static const struct clk_ops pll_ops = {
 264        .prepare = clk_pll_prepare,
 265        .unprepare = clk_pll_unprepare,
 266        .is_prepared = clk_pll_is_prepared,
 267        .recalc_rate = clk_pll_recalc_rate,
 268        .round_rate = clk_pll_round_rate,
 269        .set_rate = clk_pll_set_rate,
 270};
 271
 272struct clk_hw * __init
 273at91_clk_register_pll(struct regmap *regmap, const char *name,
 274                      const char *parent_name, u8 id,
 275                      const struct clk_pll_layout *layout,
 276                      const struct clk_pll_characteristics *characteristics)
 277{
 278        struct clk_pll *pll;
 279        struct clk_hw *hw;
 280        struct clk_init_data init;
 281        int offset = PLL_REG(id);
 282        unsigned int pllr;
 283        int ret;
 284
 285        if (id > PLL_MAX_ID)
 286                return ERR_PTR(-EINVAL);
 287
 288        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 289        if (!pll)
 290                return ERR_PTR(-ENOMEM);
 291
 292        init.name = name;
 293        init.ops = &pll_ops;
 294        init.parent_names = &parent_name;
 295        init.num_parents = 1;
 296        init.flags = CLK_SET_RATE_GATE;
 297
 298        pll->id = id;
 299        pll->hw.init = &init;
 300        pll->layout = layout;
 301        pll->characteristics = characteristics;
 302        pll->regmap = regmap;
 303        regmap_read(regmap, offset, &pllr);
 304        pll->div = PLL_DIV(pllr);
 305        pll->mul = PLL_MUL(pllr, layout);
 306
 307        hw = &pll->hw;
 308        ret = clk_hw_register(NULL, &pll->hw);
 309        if (ret) {
 310                kfree(pll);
 311                hw = ERR_PTR(ret);
 312        }
 313
 314        return hw;
 315}
 316
 317
 318const struct clk_pll_layout at91rm9200_pll_layout = {
 319        .pllr_mask = 0x7FFFFFF,
 320        .mul_shift = 16,
 321        .mul_mask = 0x7FF,
 322};
 323
 324const struct clk_pll_layout at91sam9g45_pll_layout = {
 325        .pllr_mask = 0xFFFFFF,
 326        .mul_shift = 16,
 327        .mul_mask = 0xFF,
 328};
 329
 330const struct clk_pll_layout at91sam9g20_pllb_layout = {
 331        .pllr_mask = 0x3FFFFF,
 332        .mul_shift = 16,
 333        .mul_mask = 0x3F,
 334};
 335
 336const struct clk_pll_layout sama5d3_pll_layout = {
 337        .pllr_mask = 0x1FFFFFF,
 338        .mul_shift = 18,
 339        .mul_mask = 0x7F,
 340};
 341