Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: at91: add sam9x60 PLL driver

The PLLs on the sam9x60 (PLLA and USB PLL) use a different register set and
programming model than the previous SoCs.

Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Alexandre Belloni and committed by
Stephen Boyd
a436c2a4 e5be5370

+337
+1
drivers/clk/at91/Makefile
··· 14 14 obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o 15 15 obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o 16 16 obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o 17 + obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o 17 18 obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o 18 19 obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o 19 20 obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o
+330
drivers/clk/at91/clk-sam9x60-pll.c
··· 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 +
+6
drivers/clk/at91/pmc.h
··· 69 69 struct clk_range *output; 70 70 u16 *icpll; 71 71 u8 *out; 72 + u8 upll : 1; 72 73 }; 73 74 74 75 struct clk_programmable_layout { ··· 169 168 struct clk_hw * __init 170 169 at91_clk_register_plldiv(struct regmap *regmap, const char *name, 171 170 const char *parent_name); 171 + 172 + struct clk_hw * __init 173 + sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock, 174 + const char *name, const char *parent_name, u8 id, 175 + const struct clk_pll_characteristics *characteristics); 172 176 173 177 struct clk_hw * __init 174 178 at91_clk_register_programmable(struct regmap *regmap, const char *name,