root/drivers/clk/at91/clk-sam9x60-pll.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sam9x60_pll_ready
  2. sam9x60_pll_prepare
  3. sam9x60_pll_is_prepared
  4. sam9x60_pll_unprepare
  5. sam9x60_pll_recalc_rate
  6. sam9x60_pll_get_best_div_mul
  7. sam9x60_pll_round_rate
  8. sam9x60_pll_set_rate
  9. sam9x60_clk_register_pll

   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 
  44 struct 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 
  57 static 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 
  66 static 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 
 129 static 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 
 136 static 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 
 163 static 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 
 171 static 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 
 260 static 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 
 268 static 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 
 276 static 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 
 285 struct clk_hw * __init
 286 sam9x60_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 

/* [<][>][^][v][top][bottom][index][help] */