xref: /openbmc/linux/drivers/clk/at91/clk-sam9x60-pll.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1a436c2a4SAlexandre Belloni // SPDX-License-Identifier: GPL-2.0+
2a436c2a4SAlexandre Belloni /*
3a436c2a4SAlexandre Belloni  *  Copyright (C) 2019 Microchip Technology Inc.
4a436c2a4SAlexandre Belloni  *
5a436c2a4SAlexandre Belloni  */
6a436c2a4SAlexandre Belloni 
7a436c2a4SAlexandre Belloni #include <linux/bitfield.h>
81e229c21SClaudiu Beznea #include <linux/clk.h>
9a436c2a4SAlexandre Belloni #include <linux/clk-provider.h>
10a436c2a4SAlexandre Belloni #include <linux/clkdev.h>
11a436c2a4SAlexandre Belloni #include <linux/clk/at91_pmc.h>
12a436c2a4SAlexandre Belloni #include <linux/of.h>
13a436c2a4SAlexandre Belloni #include <linux/mfd/syscon.h>
14a436c2a4SAlexandre Belloni #include <linux/regmap.h>
15a436c2a4SAlexandre Belloni 
16a436c2a4SAlexandre Belloni #include "pmc.h"
17a436c2a4SAlexandre Belloni 
18a436c2a4SAlexandre Belloni #define	PMC_PLL_CTRL0_DIV_MSK	GENMASK(7, 0)
193bf639a6SClaudiu Beznea #define	PMC_PLL_CTRL1_MUL_MSK	GENMASK(31, 24)
2035d06f74SClaudiu Beznea #define	PMC_PLL_CTRL1_FRACR_MSK	GENMASK(21, 0)
21a436c2a4SAlexandre Belloni 
22a436c2a4SAlexandre Belloni #define PLL_DIV_MAX		(FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
23a436c2a4SAlexandre Belloni #define UPLL_DIV		2
24a436c2a4SAlexandre Belloni #define PLL_MUL_MAX		(FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
25a436c2a4SAlexandre Belloni 
26390227dcSClaudiu Beznea #define FCORE_MIN		(600000000)
27390227dcSClaudiu Beznea #define FCORE_MAX		(1200000000)
28390227dcSClaudiu Beznea 
2943b1bb4aSClaudiu Beznea #define PLL_MAX_ID		7
30a436c2a4SAlexandre Belloni 
3143b1bb4aSClaudiu Beznea struct sam9x60_pll_core {
32a436c2a4SAlexandre Belloni 	struct regmap *regmap;
33a436c2a4SAlexandre Belloni 	spinlock_t *lock;
34a436c2a4SAlexandre Belloni 	const struct clk_pll_characteristics *characteristics;
3543b1bb4aSClaudiu Beznea 	const struct clk_pll_layout *layout;
3643b1bb4aSClaudiu Beznea 	struct clk_hw hw;
37a436c2a4SAlexandre Belloni 	u8 id;
3843b1bb4aSClaudiu Beznea };
3943b1bb4aSClaudiu Beznea 
4043b1bb4aSClaudiu Beznea struct sam9x60_frac {
4143b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core core;
4236971566SClaudiu Beznea 	struct at91_clk_pms pms;
4343b1bb4aSClaudiu Beznea 	u32 frac;
44a436c2a4SAlexandre Belloni 	u16 mul;
45a436c2a4SAlexandre Belloni };
46a436c2a4SAlexandre Belloni 
4743b1bb4aSClaudiu Beznea struct sam9x60_div {
4843b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core core;
4936971566SClaudiu Beznea 	struct at91_clk_pms pms;
5043b1bb4aSClaudiu Beznea 	u8 div;
511e229c21SClaudiu Beznea 	u8 safe_div;
5243b1bb4aSClaudiu Beznea };
5343b1bb4aSClaudiu Beznea 
5443b1bb4aSClaudiu Beznea #define to_sam9x60_pll_core(hw)	container_of(hw, struct sam9x60_pll_core, hw)
5543b1bb4aSClaudiu Beznea #define to_sam9x60_frac(core)	container_of(core, struct sam9x60_frac, core)
5643b1bb4aSClaudiu Beznea #define to_sam9x60_div(core)	container_of(core, struct sam9x60_div, core)
57a436c2a4SAlexandre Belloni 
581e229c21SClaudiu Beznea static struct sam9x60_div *notifier_div;
591e229c21SClaudiu Beznea 
sam9x60_pll_ready(struct regmap * regmap,int id)60a436c2a4SAlexandre Belloni static inline bool sam9x60_pll_ready(struct regmap *regmap, int id)
61a436c2a4SAlexandre Belloni {
62a436c2a4SAlexandre Belloni 	unsigned int status;
63a436c2a4SAlexandre Belloni 
64e13208abSClaudiu Beznea 	regmap_read(regmap, AT91_PMC_PLL_ISR0, &status);
65a436c2a4SAlexandre Belloni 
66a436c2a4SAlexandre Belloni 	return !!(status & BIT(id));
67a436c2a4SAlexandre Belloni }
68a436c2a4SAlexandre Belloni 
sam9x60_frac_pll_ready(struct regmap * regmap,u8 id)6943b1bb4aSClaudiu Beznea static bool sam9x60_frac_pll_ready(struct regmap *regmap, u8 id)
70a436c2a4SAlexandre Belloni {
7143b1bb4aSClaudiu Beznea 	return sam9x60_pll_ready(regmap, id);
72a436c2a4SAlexandre Belloni }
73a436c2a4SAlexandre Belloni 
sam9x60_frac_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)7443b1bb4aSClaudiu Beznea static unsigned long sam9x60_frac_pll_recalc_rate(struct clk_hw *hw,
7543b1bb4aSClaudiu Beznea 						  unsigned long parent_rate)
7643b1bb4aSClaudiu Beznea {
7743b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
7843b1bb4aSClaudiu Beznea 	struct sam9x60_frac *frac = to_sam9x60_frac(core);
7943b1bb4aSClaudiu Beznea 
80f12d028bSClaudiu Beznea 	return parent_rate * (frac->mul + 1) +
81f12d028bSClaudiu Beznea 		DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22));
8243b1bb4aSClaudiu Beznea }
8343b1bb4aSClaudiu Beznea 
sam9x60_frac_pll_set(struct sam9x60_pll_core * core)8436971566SClaudiu Beznea static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core)
8543b1bb4aSClaudiu Beznea {
8643b1bb4aSClaudiu Beznea 	struct sam9x60_frac *frac = to_sam9x60_frac(core);
8743b1bb4aSClaudiu Beznea 	struct regmap *regmap = core->regmap;
8843b1bb4aSClaudiu Beznea 	unsigned int val, cfrac, cmul;
8943b1bb4aSClaudiu Beznea 	unsigned long flags;
9043b1bb4aSClaudiu Beznea 
9143b1bb4aSClaudiu Beznea 	spin_lock_irqsave(core->lock, flags);
9243b1bb4aSClaudiu Beznea 
9343b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
9443b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);
9543b1bb4aSClaudiu Beznea 	regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);
9643b1bb4aSClaudiu Beznea 	cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;
9743b1bb4aSClaudiu Beznea 	cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;
9843b1bb4aSClaudiu Beznea 
9943b1bb4aSClaudiu Beznea 	if (sam9x60_frac_pll_ready(regmap, core->id) &&
10043b1bb4aSClaudiu Beznea 	    (cmul == frac->mul && cfrac == frac->frac))
10143b1bb4aSClaudiu Beznea 		goto unlock;
10243b1bb4aSClaudiu Beznea 
10343b1bb4aSClaudiu Beznea 	/* Recommended value for PMC_PLL_ACR */
10443b1bb4aSClaudiu Beznea 	if (core->characteristics->upll)
105e13208abSClaudiu Beznea 		val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
106db2f4482SEugen Hristev 	else
107e13208abSClaudiu Beznea 		val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
108e13208abSClaudiu Beznea 	regmap_write(regmap, AT91_PMC_PLL_ACR, val);
109a436c2a4SAlexandre Belloni 
110e13208abSClaudiu Beznea 	regmap_write(regmap, AT91_PMC_PLL_CTRL1,
11143b1bb4aSClaudiu Beznea 		     (frac->mul << core->layout->mul_shift) |
11243b1bb4aSClaudiu Beznea 		     (frac->frac << core->layout->frac_shift));
113a436c2a4SAlexandre Belloni 
11443b1bb4aSClaudiu Beznea 	if (core->characteristics->upll) {
115a436c2a4SAlexandre Belloni 		/* Enable the UTMI internal bandgap */
116e13208abSClaudiu Beznea 		val |= AT91_PMC_PLL_ACR_UTMIBG;
117e13208abSClaudiu Beznea 		regmap_write(regmap, AT91_PMC_PLL_ACR, val);
118a436c2a4SAlexandre Belloni 
119a436c2a4SAlexandre Belloni 		udelay(10);
120a436c2a4SAlexandre Belloni 
121a436c2a4SAlexandre Belloni 		/* Enable the UTMI internal regulator */
122e13208abSClaudiu Beznea 		val |= AT91_PMC_PLL_ACR_UTMIVR;
123e13208abSClaudiu Beznea 		regmap_write(regmap, AT91_PMC_PLL_ACR, val);
124a436c2a4SAlexandre Belloni 
125a436c2a4SAlexandre Belloni 		udelay(10);
126a436c2a4SAlexandre Belloni 	}
127a436c2a4SAlexandre Belloni 
128e13208abSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
12943b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
13043b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | core->id);
131a436c2a4SAlexandre Belloni 
13243b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
13343b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
13443b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL);
135a436c2a4SAlexandre Belloni 
136e13208abSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
13743b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
13843b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | core->id);
139a436c2a4SAlexandre Belloni 
14043b1bb4aSClaudiu Beznea 	while (!sam9x60_pll_ready(regmap, core->id))
141a436c2a4SAlexandre Belloni 		cpu_relax();
142a436c2a4SAlexandre Belloni 
14343b1bb4aSClaudiu Beznea unlock:
14443b1bb4aSClaudiu Beznea 	spin_unlock_irqrestore(core->lock, flags);
145a436c2a4SAlexandre Belloni 
146a436c2a4SAlexandre Belloni 	return 0;
147a436c2a4SAlexandre Belloni }
148a436c2a4SAlexandre Belloni 
sam9x60_frac_pll_prepare(struct clk_hw * hw)14936971566SClaudiu Beznea static int sam9x60_frac_pll_prepare(struct clk_hw *hw)
15036971566SClaudiu Beznea {
15136971566SClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
15236971566SClaudiu Beznea 
15336971566SClaudiu Beznea 	return sam9x60_frac_pll_set(core);
15436971566SClaudiu Beznea }
15536971566SClaudiu Beznea 
sam9x60_frac_pll_unprepare(struct clk_hw * hw)15643b1bb4aSClaudiu Beznea static void sam9x60_frac_pll_unprepare(struct clk_hw *hw)
157a436c2a4SAlexandre Belloni {
15843b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
15943b1bb4aSClaudiu Beznea 	struct regmap *regmap = core->regmap;
160a436c2a4SAlexandre Belloni 	unsigned long flags;
161a436c2a4SAlexandre Belloni 
16243b1bb4aSClaudiu Beznea 	spin_lock_irqsave(core->lock, flags);
163a436c2a4SAlexandre Belloni 
16443b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
16543b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);
166a436c2a4SAlexandre Belloni 
16743b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, AT91_PMC_PLL_CTRL0_ENPLL, 0);
168a436c2a4SAlexandre Belloni 
16943b1bb4aSClaudiu Beznea 	if (core->characteristics->upll)
17043b1bb4aSClaudiu Beznea 		regmap_update_bits(regmap, AT91_PMC_PLL_ACR,
17143b1bb4aSClaudiu Beznea 				   AT91_PMC_PLL_ACR_UTMIBG | AT91_PMC_PLL_ACR_UTMIVR, 0);
172a436c2a4SAlexandre Belloni 
17343b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
17443b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
17543b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | core->id);
176a436c2a4SAlexandre Belloni 
17743b1bb4aSClaudiu Beznea 	spin_unlock_irqrestore(core->lock, flags);
178a436c2a4SAlexandre Belloni }
179a436c2a4SAlexandre Belloni 
sam9x60_frac_pll_is_prepared(struct clk_hw * hw)18043b1bb4aSClaudiu Beznea static int sam9x60_frac_pll_is_prepared(struct clk_hw *hw)
181a436c2a4SAlexandre Belloni {
18243b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
183a436c2a4SAlexandre Belloni 
18443b1bb4aSClaudiu Beznea 	return sam9x60_pll_ready(core->regmap, core->id);
185a436c2a4SAlexandre Belloni }
186a436c2a4SAlexandre Belloni 
sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core * core,unsigned long rate,unsigned long parent_rate,bool update)18743b1bb4aSClaudiu Beznea static long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core,
188a436c2a4SAlexandre Belloni 					      unsigned long rate,
189a436c2a4SAlexandre Belloni 					      unsigned long parent_rate,
190a436c2a4SAlexandre Belloni 					      bool update)
191a436c2a4SAlexandre Belloni {
19243b1bb4aSClaudiu Beznea 	struct sam9x60_frac *frac = to_sam9x60_frac(core);
19343b1bb4aSClaudiu Beznea 	unsigned long tmprate, remainder;
19443b1bb4aSClaudiu Beznea 	unsigned long nmul = 0;
19543b1bb4aSClaudiu Beznea 	unsigned long nfrac = 0;
196a436c2a4SAlexandre Belloni 
19743b1bb4aSClaudiu Beznea 	if (rate < FCORE_MIN || rate > FCORE_MAX)
198a436c2a4SAlexandre Belloni 		return -ERANGE;
199a436c2a4SAlexandre Belloni 
200a436c2a4SAlexandre Belloni 	/*
201a436c2a4SAlexandre Belloni 	 * Calculate the multiplier associated with the current
202a436c2a4SAlexandre Belloni 	 * divider that provide the closest rate to the requested one.
203a436c2a4SAlexandre Belloni 	 */
20443b1bb4aSClaudiu Beznea 	nmul = mult_frac(rate, 1, parent_rate);
20543b1bb4aSClaudiu Beznea 	tmprate = mult_frac(parent_rate, nmul, 1);
206a436c2a4SAlexandre Belloni 	remainder = rate - tmprate;
207a436c2a4SAlexandre Belloni 
208a436c2a4SAlexandre Belloni 	if (remainder) {
20943b1bb4aSClaudiu Beznea 		nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22),
210a436c2a4SAlexandre Belloni 					      parent_rate);
211a436c2a4SAlexandre Belloni 
21243b1bb4aSClaudiu Beznea 		tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate,
21343b1bb4aSClaudiu Beznea 						 (1 << 22));
214a436c2a4SAlexandre Belloni 	}
215a436c2a4SAlexandre Belloni 
21643b1bb4aSClaudiu Beznea 	/* Check if resulted rate is a valid.  */
21743b1bb4aSClaudiu Beznea 	if (tmprate < FCORE_MIN || tmprate > FCORE_MAX)
218a436c2a4SAlexandre Belloni 		return -ERANGE;
219a436c2a4SAlexandre Belloni 
220a436c2a4SAlexandre Belloni 	if (update) {
22143b1bb4aSClaudiu Beznea 		frac->mul = nmul - 1;
22243b1bb4aSClaudiu Beznea 		frac->frac = nfrac;
223a436c2a4SAlexandre Belloni 	}
224a436c2a4SAlexandre Belloni 
22543b1bb4aSClaudiu Beznea 	return tmprate;
226a436c2a4SAlexandre Belloni }
227a436c2a4SAlexandre Belloni 
sam9x60_frac_pll_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)22843b1bb4aSClaudiu Beznea static long sam9x60_frac_pll_round_rate(struct clk_hw *hw, unsigned long rate,
229a436c2a4SAlexandre Belloni 					unsigned long *parent_rate)
230a436c2a4SAlexandre Belloni {
23143b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
232a436c2a4SAlexandre Belloni 
23343b1bb4aSClaudiu Beznea 	return sam9x60_frac_pll_compute_mul_frac(core, rate, *parent_rate, false);
234a436c2a4SAlexandre Belloni }
235a436c2a4SAlexandre Belloni 
sam9x60_frac_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)23643b1bb4aSClaudiu Beznea static int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate,
237a436c2a4SAlexandre Belloni 				     unsigned long parent_rate)
238a436c2a4SAlexandre Belloni {
23943b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
240a436c2a4SAlexandre Belloni 
24143b1bb4aSClaudiu Beznea 	return sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);
242a436c2a4SAlexandre Belloni }
243a436c2a4SAlexandre Belloni 
sam9x60_frac_pll_set_rate_chg(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)2448dc4af8bSClaudiu Beznea static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
2458dc4af8bSClaudiu Beznea 					 unsigned long parent_rate)
2468dc4af8bSClaudiu Beznea {
2478dc4af8bSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
2488dc4af8bSClaudiu Beznea 	struct sam9x60_frac *frac = to_sam9x60_frac(core);
2498dc4af8bSClaudiu Beznea 	struct regmap *regmap = core->regmap;
2508dc4af8bSClaudiu Beznea 	unsigned long irqflags;
2518dc4af8bSClaudiu Beznea 	unsigned int val, cfrac, cmul;
2528dc4af8bSClaudiu Beznea 	long ret;
2538dc4af8bSClaudiu Beznea 
2548dc4af8bSClaudiu Beznea 	ret = sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);
2558dc4af8bSClaudiu Beznea 	if (ret <= 0)
2568dc4af8bSClaudiu Beznea 		return ret;
2578dc4af8bSClaudiu Beznea 
2588dc4af8bSClaudiu Beznea 	spin_lock_irqsave(core->lock, irqflags);
2598dc4af8bSClaudiu Beznea 
2608dc4af8bSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
2618dc4af8bSClaudiu Beznea 			   core->id);
2628dc4af8bSClaudiu Beznea 	regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);
2638dc4af8bSClaudiu Beznea 	cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;
2648dc4af8bSClaudiu Beznea 	cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;
2658dc4af8bSClaudiu Beznea 
2668dc4af8bSClaudiu Beznea 	if (cmul == frac->mul && cfrac == frac->frac)
2678dc4af8bSClaudiu Beznea 		goto unlock;
2688dc4af8bSClaudiu Beznea 
2698dc4af8bSClaudiu Beznea 	regmap_write(regmap, AT91_PMC_PLL_CTRL1,
2708dc4af8bSClaudiu Beznea 		     (frac->mul << core->layout->mul_shift) |
2718dc4af8bSClaudiu Beznea 		     (frac->frac << core->layout->frac_shift));
2728dc4af8bSClaudiu Beznea 
2738dc4af8bSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
2748dc4af8bSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
2758dc4af8bSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | core->id);
2768dc4af8bSClaudiu Beznea 
2778dc4af8bSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
2788dc4af8bSClaudiu Beznea 			   AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
2798dc4af8bSClaudiu Beznea 			   AT91_PMC_PLL_CTRL0_ENLOCK |
2808dc4af8bSClaudiu Beznea 			   AT91_PMC_PLL_CTRL0_ENPLL);
2818dc4af8bSClaudiu Beznea 
2828dc4af8bSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
2838dc4af8bSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
2848dc4af8bSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | core->id);
2858dc4af8bSClaudiu Beznea 
2868dc4af8bSClaudiu Beznea 	while (!sam9x60_pll_ready(regmap, core->id))
2878dc4af8bSClaudiu Beznea 		cpu_relax();
2888dc4af8bSClaudiu Beznea 
2898dc4af8bSClaudiu Beznea unlock:
2908dc4af8bSClaudiu Beznea 	spin_unlock_irqrestore(core->lock, irqflags);
2918dc4af8bSClaudiu Beznea 
2928dc4af8bSClaudiu Beznea 	return ret;
2938dc4af8bSClaudiu Beznea }
2948dc4af8bSClaudiu Beznea 
sam9x60_frac_pll_save_context(struct clk_hw * hw)29536971566SClaudiu Beznea static int sam9x60_frac_pll_save_context(struct clk_hw *hw)
29636971566SClaudiu Beznea {
29736971566SClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
29836971566SClaudiu Beznea 	struct sam9x60_frac *frac = to_sam9x60_frac(core);
29936971566SClaudiu Beznea 
30036971566SClaudiu Beznea 	frac->pms.status = sam9x60_pll_ready(core->regmap, core->id);
30136971566SClaudiu Beznea 
30236971566SClaudiu Beznea 	return 0;
30336971566SClaudiu Beznea }
30436971566SClaudiu Beznea 
sam9x60_frac_pll_restore_context(struct clk_hw * hw)30536971566SClaudiu Beznea static void sam9x60_frac_pll_restore_context(struct clk_hw *hw)
30636971566SClaudiu Beznea {
30736971566SClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
30836971566SClaudiu Beznea 	struct sam9x60_frac *frac = to_sam9x60_frac(core);
30936971566SClaudiu Beznea 
31036971566SClaudiu Beznea 	if (frac->pms.status)
31136971566SClaudiu Beznea 		sam9x60_frac_pll_set(core);
31236971566SClaudiu Beznea }
31336971566SClaudiu Beznea 
31443b1bb4aSClaudiu Beznea static const struct clk_ops sam9x60_frac_pll_ops = {
31543b1bb4aSClaudiu Beznea 	.prepare = sam9x60_frac_pll_prepare,
31643b1bb4aSClaudiu Beznea 	.unprepare = sam9x60_frac_pll_unprepare,
31743b1bb4aSClaudiu Beznea 	.is_prepared = sam9x60_frac_pll_is_prepared,
31843b1bb4aSClaudiu Beznea 	.recalc_rate = sam9x60_frac_pll_recalc_rate,
31943b1bb4aSClaudiu Beznea 	.round_rate = sam9x60_frac_pll_round_rate,
32043b1bb4aSClaudiu Beznea 	.set_rate = sam9x60_frac_pll_set_rate,
32136971566SClaudiu Beznea 	.save_context = sam9x60_frac_pll_save_context,
32236971566SClaudiu Beznea 	.restore_context = sam9x60_frac_pll_restore_context,
32343b1bb4aSClaudiu Beznea };
32443b1bb4aSClaudiu Beznea 
3258dc4af8bSClaudiu Beznea static const struct clk_ops sam9x60_frac_pll_ops_chg = {
3268dc4af8bSClaudiu Beznea 	.prepare = sam9x60_frac_pll_prepare,
3278dc4af8bSClaudiu Beznea 	.unprepare = sam9x60_frac_pll_unprepare,
3288dc4af8bSClaudiu Beznea 	.is_prepared = sam9x60_frac_pll_is_prepared,
3298dc4af8bSClaudiu Beznea 	.recalc_rate = sam9x60_frac_pll_recalc_rate,
3308dc4af8bSClaudiu Beznea 	.round_rate = sam9x60_frac_pll_round_rate,
3318dc4af8bSClaudiu Beznea 	.set_rate = sam9x60_frac_pll_set_rate_chg,
33236971566SClaudiu Beznea 	.save_context = sam9x60_frac_pll_save_context,
33336971566SClaudiu Beznea 	.restore_context = sam9x60_frac_pll_restore_context,
3348dc4af8bSClaudiu Beznea };
3358dc4af8bSClaudiu Beznea 
3361e229c21SClaudiu Beznea /* This function should be called with spinlock acquired. */
sam9x60_div_pll_set_div(struct sam9x60_pll_core * core,u32 div,bool enable)3371e229c21SClaudiu Beznea static void sam9x60_div_pll_set_div(struct sam9x60_pll_core *core, u32 div,
3381e229c21SClaudiu Beznea 				    bool enable)
3391e229c21SClaudiu Beznea {
3401e229c21SClaudiu Beznea 	struct regmap *regmap = core->regmap;
3411e229c21SClaudiu Beznea 	u32 ena_msk = enable ? core->layout->endiv_mask : 0;
3421e229c21SClaudiu Beznea 	u32 ena_val = enable ? (1 << core->layout->endiv_shift) : 0;
3431e229c21SClaudiu Beznea 
3441e229c21SClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
3451e229c21SClaudiu Beznea 			   core->layout->div_mask | ena_msk,
3461e229c21SClaudiu Beznea 			   (div << core->layout->div_shift) | ena_val);
3471e229c21SClaudiu Beznea 
3481e229c21SClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
3491e229c21SClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
3501e229c21SClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | core->id);
3511e229c21SClaudiu Beznea 
3521e229c21SClaudiu Beznea 	while (!sam9x60_pll_ready(regmap, core->id))
3531e229c21SClaudiu Beznea 		cpu_relax();
3541e229c21SClaudiu Beznea }
3551e229c21SClaudiu Beznea 
sam9x60_div_pll_set(struct sam9x60_pll_core * core)35636971566SClaudiu Beznea static int sam9x60_div_pll_set(struct sam9x60_pll_core *core)
35743b1bb4aSClaudiu Beznea {
35843b1bb4aSClaudiu Beznea 	struct sam9x60_div *div = to_sam9x60_div(core);
35943b1bb4aSClaudiu Beznea 	struct regmap *regmap = core->regmap;
36043b1bb4aSClaudiu Beznea 	unsigned long flags;
36143b1bb4aSClaudiu Beznea 	unsigned int val, cdiv;
36243b1bb4aSClaudiu Beznea 
36343b1bb4aSClaudiu Beznea 	spin_lock_irqsave(core->lock, flags);
36443b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
36543b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);
36643b1bb4aSClaudiu Beznea 	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
36743b1bb4aSClaudiu Beznea 	cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;
36843b1bb4aSClaudiu Beznea 
36943b1bb4aSClaudiu Beznea 	/* Stop if enabled an nothing changed. */
37043b1bb4aSClaudiu Beznea 	if (!!(val & core->layout->endiv_mask) && cdiv == div->div)
37143b1bb4aSClaudiu Beznea 		goto unlock;
37243b1bb4aSClaudiu Beznea 
3731e229c21SClaudiu Beznea 	sam9x60_div_pll_set_div(core, div->div, 1);
37443b1bb4aSClaudiu Beznea 
37543b1bb4aSClaudiu Beznea unlock:
37643b1bb4aSClaudiu Beznea 	spin_unlock_irqrestore(core->lock, flags);
37743b1bb4aSClaudiu Beznea 
37843b1bb4aSClaudiu Beznea 	return 0;
37943b1bb4aSClaudiu Beznea }
38043b1bb4aSClaudiu Beznea 
sam9x60_div_pll_prepare(struct clk_hw * hw)38136971566SClaudiu Beznea static int sam9x60_div_pll_prepare(struct clk_hw *hw)
38236971566SClaudiu Beznea {
38336971566SClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
38436971566SClaudiu Beznea 
38536971566SClaudiu Beznea 	return sam9x60_div_pll_set(core);
38636971566SClaudiu Beznea }
38736971566SClaudiu Beznea 
sam9x60_div_pll_unprepare(struct clk_hw * hw)38843b1bb4aSClaudiu Beznea static void sam9x60_div_pll_unprepare(struct clk_hw *hw)
38943b1bb4aSClaudiu Beznea {
39043b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
39143b1bb4aSClaudiu Beznea 	struct regmap *regmap = core->regmap;
39243b1bb4aSClaudiu Beznea 	unsigned long flags;
39343b1bb4aSClaudiu Beznea 
39443b1bb4aSClaudiu Beznea 	spin_lock_irqsave(core->lock, flags);
39543b1bb4aSClaudiu Beznea 
39643b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
39743b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);
39843b1bb4aSClaudiu Beznea 
39943b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
40043b1bb4aSClaudiu Beznea 			   core->layout->endiv_mask, 0);
40143b1bb4aSClaudiu Beznea 
40243b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
40343b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
40443b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_UPDATE | core->id);
40543b1bb4aSClaudiu Beznea 
40643b1bb4aSClaudiu Beznea 	spin_unlock_irqrestore(core->lock, flags);
40743b1bb4aSClaudiu Beznea }
40843b1bb4aSClaudiu Beznea 
sam9x60_div_pll_is_prepared(struct clk_hw * hw)40943b1bb4aSClaudiu Beznea static int sam9x60_div_pll_is_prepared(struct clk_hw *hw)
41043b1bb4aSClaudiu Beznea {
41143b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
41243b1bb4aSClaudiu Beznea 	struct regmap *regmap = core->regmap;
41343b1bb4aSClaudiu Beznea 	unsigned long flags;
41443b1bb4aSClaudiu Beznea 	unsigned int val;
41543b1bb4aSClaudiu Beznea 
41643b1bb4aSClaudiu Beznea 	spin_lock_irqsave(core->lock, flags);
41743b1bb4aSClaudiu Beznea 
41843b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
41943b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);
42043b1bb4aSClaudiu Beznea 	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
42143b1bb4aSClaudiu Beznea 
42243b1bb4aSClaudiu Beznea 	spin_unlock_irqrestore(core->lock, flags);
42343b1bb4aSClaudiu Beznea 
42443b1bb4aSClaudiu Beznea 	return !!(val & core->layout->endiv_mask);
42543b1bb4aSClaudiu Beznea }
42643b1bb4aSClaudiu Beznea 
sam9x60_div_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)42743b1bb4aSClaudiu Beznea static unsigned long sam9x60_div_pll_recalc_rate(struct clk_hw *hw,
42843b1bb4aSClaudiu Beznea 						 unsigned long parent_rate)
42943b1bb4aSClaudiu Beznea {
43043b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
43143b1bb4aSClaudiu Beznea 	struct sam9x60_div *div = to_sam9x60_div(core);
43243b1bb4aSClaudiu Beznea 
43343b1bb4aSClaudiu Beznea 	return DIV_ROUND_CLOSEST_ULL(parent_rate, (div->div + 1));
43443b1bb4aSClaudiu Beznea }
43543b1bb4aSClaudiu Beznea 
sam9x60_div_pll_compute_div(struct sam9x60_pll_core * core,unsigned long * parent_rate,unsigned long rate)43643b1bb4aSClaudiu Beznea static long sam9x60_div_pll_compute_div(struct sam9x60_pll_core *core,
43743b1bb4aSClaudiu Beznea 					unsigned long *parent_rate,
43843b1bb4aSClaudiu Beznea 					unsigned long rate)
43943b1bb4aSClaudiu Beznea {
44043b1bb4aSClaudiu Beznea 	const struct clk_pll_characteristics *characteristics =
44143b1bb4aSClaudiu Beznea 							core->characteristics;
44243b1bb4aSClaudiu Beznea 	struct clk_hw *parent = clk_hw_get_parent(&core->hw);
44343b1bb4aSClaudiu Beznea 	unsigned long tmp_rate, tmp_parent_rate, tmp_diff;
44443b1bb4aSClaudiu Beznea 	long best_diff = -1, best_rate = -EINVAL;
445c6968ac0SClaudiu Beznea 	u32 divid;
44643b1bb4aSClaudiu Beznea 
44743b1bb4aSClaudiu Beznea 	if (!rate)
44843b1bb4aSClaudiu Beznea 		return 0;
44943b1bb4aSClaudiu Beznea 
45043b1bb4aSClaudiu Beznea 	if (rate < characteristics->output[0].min ||
45143b1bb4aSClaudiu Beznea 	    rate > characteristics->output[0].max)
45243b1bb4aSClaudiu Beznea 		return -ERANGE;
45343b1bb4aSClaudiu Beznea 
45443b1bb4aSClaudiu Beznea 	for (divid = 1; divid < core->layout->div_mask; divid++) {
45543b1bb4aSClaudiu Beznea 		tmp_parent_rate = clk_hw_round_rate(parent, rate * divid);
45643b1bb4aSClaudiu Beznea 		if (!tmp_parent_rate)
45743b1bb4aSClaudiu Beznea 			continue;
45843b1bb4aSClaudiu Beznea 
45943b1bb4aSClaudiu Beznea 		tmp_rate = DIV_ROUND_CLOSEST_ULL(tmp_parent_rate, divid);
46043b1bb4aSClaudiu Beznea 		tmp_diff = abs(rate - tmp_rate);
46143b1bb4aSClaudiu Beznea 
46243b1bb4aSClaudiu Beznea 		if (best_diff < 0 || best_diff > tmp_diff) {
46343b1bb4aSClaudiu Beznea 			*parent_rate = tmp_parent_rate;
46443b1bb4aSClaudiu Beznea 			best_rate = tmp_rate;
46543b1bb4aSClaudiu Beznea 			best_diff = tmp_diff;
46643b1bb4aSClaudiu Beznea 		}
46743b1bb4aSClaudiu Beznea 
46843b1bb4aSClaudiu Beznea 		if (!best_diff)
46943b1bb4aSClaudiu Beznea 			break;
47043b1bb4aSClaudiu Beznea 	}
47143b1bb4aSClaudiu Beznea 
47243b1bb4aSClaudiu Beznea 	if (best_rate < characteristics->output[0].min ||
47343b1bb4aSClaudiu Beznea 	    best_rate > characteristics->output[0].max)
47443b1bb4aSClaudiu Beznea 		return -ERANGE;
47543b1bb4aSClaudiu Beznea 
47643b1bb4aSClaudiu Beznea 	return best_rate;
47743b1bb4aSClaudiu Beznea }
47843b1bb4aSClaudiu Beznea 
sam9x60_div_pll_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)47943b1bb4aSClaudiu Beznea static long sam9x60_div_pll_round_rate(struct clk_hw *hw, unsigned long rate,
48043b1bb4aSClaudiu Beznea 				       unsigned long *parent_rate)
48143b1bb4aSClaudiu Beznea {
48243b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
48343b1bb4aSClaudiu Beznea 
48443b1bb4aSClaudiu Beznea 	return sam9x60_div_pll_compute_div(core, parent_rate, rate);
48543b1bb4aSClaudiu Beznea }
48643b1bb4aSClaudiu Beznea 
sam9x60_div_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)48743b1bb4aSClaudiu Beznea static int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate,
48843b1bb4aSClaudiu Beznea 				    unsigned long parent_rate)
48943b1bb4aSClaudiu Beznea {
49043b1bb4aSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
49143b1bb4aSClaudiu Beznea 	struct sam9x60_div *div = to_sam9x60_div(core);
49243b1bb4aSClaudiu Beznea 
49343b1bb4aSClaudiu Beznea 	div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1;
49443b1bb4aSClaudiu Beznea 
49543b1bb4aSClaudiu Beznea 	return 0;
49643b1bb4aSClaudiu Beznea }
49743b1bb4aSClaudiu Beznea 
sam9x60_div_pll_set_rate_chg(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)4988dc4af8bSClaudiu Beznea static int sam9x60_div_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
4998dc4af8bSClaudiu Beznea 					unsigned long parent_rate)
5008dc4af8bSClaudiu Beznea {
5018dc4af8bSClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
5028dc4af8bSClaudiu Beznea 	struct sam9x60_div *div = to_sam9x60_div(core);
5038dc4af8bSClaudiu Beznea 	struct regmap *regmap = core->regmap;
5048dc4af8bSClaudiu Beznea 	unsigned long irqflags;
5058dc4af8bSClaudiu Beznea 	unsigned int val, cdiv;
5068dc4af8bSClaudiu Beznea 
5078dc4af8bSClaudiu Beznea 	div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1;
5088dc4af8bSClaudiu Beznea 
5098dc4af8bSClaudiu Beznea 	spin_lock_irqsave(core->lock, irqflags);
5108dc4af8bSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
5118dc4af8bSClaudiu Beznea 			   core->id);
5128dc4af8bSClaudiu Beznea 	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
5138dc4af8bSClaudiu Beznea 	cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;
5148dc4af8bSClaudiu Beznea 
5158dc4af8bSClaudiu Beznea 	/* Stop if nothing changed. */
5168dc4af8bSClaudiu Beznea 	if (cdiv == div->div)
5178dc4af8bSClaudiu Beznea 		goto unlock;
5188dc4af8bSClaudiu Beznea 
5191e229c21SClaudiu Beznea 	sam9x60_div_pll_set_div(core, div->div, 0);
5208dc4af8bSClaudiu Beznea 
5218dc4af8bSClaudiu Beznea unlock:
5228dc4af8bSClaudiu Beznea 	spin_unlock_irqrestore(core->lock, irqflags);
5238dc4af8bSClaudiu Beznea 
5248dc4af8bSClaudiu Beznea 	return 0;
5258dc4af8bSClaudiu Beznea }
5268dc4af8bSClaudiu Beznea 
sam9x60_div_pll_save_context(struct clk_hw * hw)52736971566SClaudiu Beznea static int sam9x60_div_pll_save_context(struct clk_hw *hw)
52836971566SClaudiu Beznea {
52936971566SClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
53036971566SClaudiu Beznea 	struct sam9x60_div *div = to_sam9x60_div(core);
53136971566SClaudiu Beznea 
53236971566SClaudiu Beznea 	div->pms.status = sam9x60_div_pll_is_prepared(hw);
53336971566SClaudiu Beznea 
53436971566SClaudiu Beznea 	return 0;
53536971566SClaudiu Beznea }
53636971566SClaudiu Beznea 
sam9x60_div_pll_restore_context(struct clk_hw * hw)53736971566SClaudiu Beznea static void sam9x60_div_pll_restore_context(struct clk_hw *hw)
53836971566SClaudiu Beznea {
53936971566SClaudiu Beznea 	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
54036971566SClaudiu Beznea 	struct sam9x60_div *div = to_sam9x60_div(core);
54136971566SClaudiu Beznea 
54236971566SClaudiu Beznea 	if (div->pms.status)
54336971566SClaudiu Beznea 		sam9x60_div_pll_set(core);
54436971566SClaudiu Beznea }
54536971566SClaudiu Beznea 
sam9x60_div_pll_notifier_fn(struct notifier_block * notifier,unsigned long code,void * data)5461e229c21SClaudiu Beznea static int sam9x60_div_pll_notifier_fn(struct notifier_block *notifier,
5471e229c21SClaudiu Beznea 				       unsigned long code, void *data)
5481e229c21SClaudiu Beznea {
5491e229c21SClaudiu Beznea 	struct sam9x60_div *div = notifier_div;
5501e229c21SClaudiu Beznea 	struct sam9x60_pll_core core = div->core;
5511e229c21SClaudiu Beznea 	struct regmap *regmap = core.regmap;
5521e229c21SClaudiu Beznea 	unsigned long irqflags;
5531e229c21SClaudiu Beznea 	u32 val, cdiv;
5541e229c21SClaudiu Beznea 	int ret = NOTIFY_DONE;
5551e229c21SClaudiu Beznea 
5561e229c21SClaudiu Beznea 	if (code != PRE_RATE_CHANGE)
5571e229c21SClaudiu Beznea 		return ret;
5581e229c21SClaudiu Beznea 
5591e229c21SClaudiu Beznea 	/*
5601e229c21SClaudiu Beznea 	 * We switch to safe divider to avoid overclocking of other domains
5611e229c21SClaudiu Beznea 	 * feed by us while the frac PLL (our parent) is changed.
5621e229c21SClaudiu Beznea 	 */
5631e229c21SClaudiu Beznea 	div->div = div->safe_div;
5641e229c21SClaudiu Beznea 
5651e229c21SClaudiu Beznea 	spin_lock_irqsave(core.lock, irqflags);
5661e229c21SClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
5671e229c21SClaudiu Beznea 			   core.id);
5681e229c21SClaudiu Beznea 	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
5691e229c21SClaudiu Beznea 	cdiv = (val & core.layout->div_mask) >> core.layout->div_shift;
5701e229c21SClaudiu Beznea 
5711e229c21SClaudiu Beznea 	/* Stop if nothing changed. */
5721e229c21SClaudiu Beznea 	if (cdiv == div->safe_div)
5731e229c21SClaudiu Beznea 		goto unlock;
5741e229c21SClaudiu Beznea 
5751e229c21SClaudiu Beznea 	sam9x60_div_pll_set_div(&core, div->div, 0);
5761e229c21SClaudiu Beznea 	ret = NOTIFY_OK;
5771e229c21SClaudiu Beznea 
5781e229c21SClaudiu Beznea unlock:
5791e229c21SClaudiu Beznea 	spin_unlock_irqrestore(core.lock, irqflags);
5801e229c21SClaudiu Beznea 
5811e229c21SClaudiu Beznea 	return ret;
5821e229c21SClaudiu Beznea }
5831e229c21SClaudiu Beznea 
5841e229c21SClaudiu Beznea static struct notifier_block sam9x60_div_pll_notifier = {
5851e229c21SClaudiu Beznea 	.notifier_call = sam9x60_div_pll_notifier_fn,
5861e229c21SClaudiu Beznea };
5871e229c21SClaudiu Beznea 
58843b1bb4aSClaudiu Beznea static const struct clk_ops sam9x60_div_pll_ops = {
58943b1bb4aSClaudiu Beznea 	.prepare = sam9x60_div_pll_prepare,
59043b1bb4aSClaudiu Beznea 	.unprepare = sam9x60_div_pll_unprepare,
59143b1bb4aSClaudiu Beznea 	.is_prepared = sam9x60_div_pll_is_prepared,
59243b1bb4aSClaudiu Beznea 	.recalc_rate = sam9x60_div_pll_recalc_rate,
59343b1bb4aSClaudiu Beznea 	.round_rate = sam9x60_div_pll_round_rate,
59443b1bb4aSClaudiu Beznea 	.set_rate = sam9x60_div_pll_set_rate,
59536971566SClaudiu Beznea 	.save_context = sam9x60_div_pll_save_context,
59636971566SClaudiu Beznea 	.restore_context = sam9x60_div_pll_restore_context,
597a436c2a4SAlexandre Belloni };
598a436c2a4SAlexandre Belloni 
5998dc4af8bSClaudiu Beznea static const struct clk_ops sam9x60_div_pll_ops_chg = {
6008dc4af8bSClaudiu Beznea 	.prepare = sam9x60_div_pll_prepare,
6018dc4af8bSClaudiu Beznea 	.unprepare = sam9x60_div_pll_unprepare,
6028dc4af8bSClaudiu Beznea 	.is_prepared = sam9x60_div_pll_is_prepared,
6038dc4af8bSClaudiu Beznea 	.recalc_rate = sam9x60_div_pll_recalc_rate,
6048dc4af8bSClaudiu Beznea 	.round_rate = sam9x60_div_pll_round_rate,
6058dc4af8bSClaudiu Beznea 	.set_rate = sam9x60_div_pll_set_rate_chg,
60636971566SClaudiu Beznea 	.save_context = sam9x60_div_pll_save_context,
60736971566SClaudiu Beznea 	.restore_context = sam9x60_div_pll_restore_context,
6088dc4af8bSClaudiu Beznea };
6098dc4af8bSClaudiu Beznea 
610a436c2a4SAlexandre Belloni struct clk_hw * __init
sam9x60_clk_register_frac_pll(struct regmap * regmap,spinlock_t * lock,const char * name,const char * parent_name,struct clk_hw * parent_hw,u8 id,const struct clk_pll_characteristics * characteristics,const struct clk_pll_layout * layout,u32 flags)61143b1bb4aSClaudiu Beznea sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
61243b1bb4aSClaudiu Beznea 			      const char *name, const char *parent_name,
61343b1bb4aSClaudiu Beznea 			      struct clk_hw *parent_hw, u8 id,
61443b1bb4aSClaudiu Beznea 			      const struct clk_pll_characteristics *characteristics,
6158dc4af8bSClaudiu Beznea 			      const struct clk_pll_layout *layout, u32 flags)
616a436c2a4SAlexandre Belloni {
61743b1bb4aSClaudiu Beznea 	struct sam9x60_frac *frac;
618a436c2a4SAlexandre Belloni 	struct clk_hw *hw;
619a436c2a4SAlexandre Belloni 	struct clk_init_data init = {};
6208dc4af8bSClaudiu Beznea 	unsigned long parent_rate, irqflags;
62143b1bb4aSClaudiu Beznea 	unsigned int val;
622a436c2a4SAlexandre Belloni 	int ret;
623a436c2a4SAlexandre Belloni 
62443b1bb4aSClaudiu Beznea 	if (id > PLL_MAX_ID || !lock || !parent_hw)
625a436c2a4SAlexandre Belloni 		return ERR_PTR(-EINVAL);
626a436c2a4SAlexandre Belloni 
62743b1bb4aSClaudiu Beznea 	frac = kzalloc(sizeof(*frac), GFP_KERNEL);
62843b1bb4aSClaudiu Beznea 	if (!frac)
629a436c2a4SAlexandre Belloni 		return ERR_PTR(-ENOMEM);
630a436c2a4SAlexandre Belloni 
631a436c2a4SAlexandre Belloni 	init.name = name;
632a436c2a4SAlexandre Belloni 	if (parent_name)
633a436c2a4SAlexandre Belloni 		init.parent_names = &parent_name;
6348dc4af8bSClaudiu Beznea 	else
63543b1bb4aSClaudiu Beznea 		init.parent_hws = (const struct clk_hw **)&parent_hw;
6368dc4af8bSClaudiu Beznea 	init.num_parents = 1;
6378dc4af8bSClaudiu Beznea 	if (flags & CLK_SET_RATE_GATE)
6388dc4af8bSClaudiu Beznea 		init.ops = &sam9x60_frac_pll_ops;
6398dc4af8bSClaudiu Beznea 	else
640a436c2a4SAlexandre Belloni 		init.ops = &sam9x60_frac_pll_ops_chg;
64143b1bb4aSClaudiu Beznea 
64243b1bb4aSClaudiu Beznea 	init.flags = flags;
64343b1bb4aSClaudiu Beznea 
64443b1bb4aSClaudiu Beznea 	frac->core.id = id;
64543b1bb4aSClaudiu Beznea 	frac->core.hw.init = &init;
64643b1bb4aSClaudiu Beznea 	frac->core.characteristics = characteristics;
647a436c2a4SAlexandre Belloni 	frac->core.layout = layout;
6488dc4af8bSClaudiu Beznea 	frac->core.regmap = regmap;
64943b1bb4aSClaudiu Beznea 	frac->core.lock = lock;
65043b1bb4aSClaudiu Beznea 
65143b1bb4aSClaudiu Beznea 	spin_lock_irqsave(frac->core.lock, irqflags);
65243b1bb4aSClaudiu Beznea 	if (sam9x60_pll_ready(regmap, id)) {
65343b1bb4aSClaudiu Beznea 		regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
65443b1bb4aSClaudiu Beznea 				   AT91_PMC_PLL_UPDT_ID_MSK, id);
65543b1bb4aSClaudiu Beznea 		regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);
65643b1bb4aSClaudiu Beznea 		frac->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val);
65743b1bb4aSClaudiu Beznea 		frac->frac = FIELD_GET(PMC_PLL_CTRL1_FRACR_MSK, val);
65843b1bb4aSClaudiu Beznea 	} else {
65943b1bb4aSClaudiu Beznea 		/*
66043b1bb4aSClaudiu Beznea 		 * This means the PLL is not setup by bootloaders. In this
66143b1bb4aSClaudiu Beznea 		 * case we need to set the minimum rate for it. Otherwise
66243b1bb4aSClaudiu Beznea 		 * a clock child of this PLL may be enabled before setting
66343b1bb4aSClaudiu Beznea 		 * its rate leading to enabling this PLL with unsupported
66443b1bb4aSClaudiu Beznea 		 * rate. This will lead to PLL not being locked at all.
66543b1bb4aSClaudiu Beznea 		 */
66643b1bb4aSClaudiu Beznea 		parent_rate = clk_hw_get_rate(parent_hw);
66743b1bb4aSClaudiu Beznea 		if (!parent_rate) {
668a436c2a4SAlexandre Belloni 			hw = ERR_PTR(-EINVAL);
66943b1bb4aSClaudiu Beznea 			goto free;
67043b1bb4aSClaudiu Beznea 		}
671*1bd8e27fSClaudiu Beznea 
67243b1bb4aSClaudiu Beznea 		ret = sam9x60_frac_pll_compute_mul_frac(&frac->core, FCORE_MIN,
67343b1bb4aSClaudiu Beznea 							parent_rate, true);
67443b1bb4aSClaudiu Beznea 		if (ret < 0) {
67543b1bb4aSClaudiu Beznea 			hw = ERR_PTR(ret);
6768dc4af8bSClaudiu Beznea 			goto free;
67743b1bb4aSClaudiu Beznea 		}
67843b1bb4aSClaudiu Beznea 	}
679a436c2a4SAlexandre Belloni 	spin_unlock_irqrestore(frac->core.lock, irqflags);
680a436c2a4SAlexandre Belloni 
68143b1bb4aSClaudiu Beznea 	hw = &frac->core.hw;
68243b1bb4aSClaudiu Beznea 	ret = clk_hw_register(NULL, hw);
68343b1bb4aSClaudiu Beznea 	if (ret) {
68443b1bb4aSClaudiu Beznea 		kfree(frac);
68543b1bb4aSClaudiu Beznea 		hw = ERR_PTR(ret);
68643b1bb4aSClaudiu Beznea 	}
68743b1bb4aSClaudiu Beznea 
6888dc4af8bSClaudiu Beznea 	return hw;
68943b1bb4aSClaudiu Beznea 
69043b1bb4aSClaudiu Beznea free:
69143b1bb4aSClaudiu Beznea 	spin_unlock_irqrestore(frac->core.lock, irqflags);
69243b1bb4aSClaudiu Beznea 	kfree(frac);
69343b1bb4aSClaudiu Beznea 	return hw;
69443b1bb4aSClaudiu Beznea }
69543b1bb4aSClaudiu Beznea 
69643b1bb4aSClaudiu Beznea struct clk_hw * __init
sam9x60_clk_register_div_pll(struct regmap * regmap,spinlock_t * lock,const char * name,const char * parent_name,struct clk_hw * parent_hw,u8 id,const struct clk_pll_characteristics * characteristics,const struct clk_pll_layout * layout,u32 flags,u32 safe_div)6971e229c21SClaudiu Beznea sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
6981e229c21SClaudiu Beznea 			     const char *name, const char *parent_name,
69943b1bb4aSClaudiu Beznea 			     struct clk_hw *parent_hw, u8 id,
70043b1bb4aSClaudiu Beznea 			     const struct clk_pll_characteristics *characteristics,
70143b1bb4aSClaudiu Beznea 			     const struct clk_pll_layout *layout, u32 flags,
70243b1bb4aSClaudiu Beznea 			     u32 safe_div)
7038dc4af8bSClaudiu Beznea {
70443b1bb4aSClaudiu Beznea 	struct sam9x60_div *div;
70543b1bb4aSClaudiu Beznea 	struct clk_hw *hw;
70643b1bb4aSClaudiu Beznea 	struct clk_init_data init = {};
7071e229c21SClaudiu Beznea 	unsigned long irqflags;
7081e229c21SClaudiu Beznea 	unsigned int val;
70943b1bb4aSClaudiu Beznea 	int ret;
71043b1bb4aSClaudiu Beznea 
7111e229c21SClaudiu Beznea 	/* We only support one changeable PLL. */
7121e229c21SClaudiu Beznea 	if (id > PLL_MAX_ID || !lock || (safe_div && notifier_div))
7131e229c21SClaudiu Beznea 		return ERR_PTR(-EINVAL);
71443b1bb4aSClaudiu Beznea 
71543b1bb4aSClaudiu Beznea 	if (safe_div >= PLL_DIV_MAX)
71643b1bb4aSClaudiu Beznea 		safe_div = PLL_DIV_MAX - 1;
71743b1bb4aSClaudiu Beznea 
71843b1bb4aSClaudiu Beznea 	div = kzalloc(sizeof(*div), GFP_KERNEL);
71943b1bb4aSClaudiu Beznea 	if (!div)
72043b1bb4aSClaudiu Beznea 		return ERR_PTR(-ENOMEM);
7218dc4af8bSClaudiu Beznea 
72243b1bb4aSClaudiu Beznea 	init.name = name;
7238dc4af8bSClaudiu Beznea 	if (parent_hw)
7248dc4af8bSClaudiu Beznea 		init.parent_hws = (const struct clk_hw **)&parent_hw;
7258dc4af8bSClaudiu Beznea 	else
72643b1bb4aSClaudiu Beznea 		init.parent_names = &parent_name;
72743b1bb4aSClaudiu Beznea 	init.num_parents = 1;
72843b1bb4aSClaudiu Beznea 	if (flags & CLK_SET_RATE_GATE)
72943b1bb4aSClaudiu Beznea 		init.ops = &sam9x60_div_pll_ops;
73043b1bb4aSClaudiu Beznea 	else
73143b1bb4aSClaudiu Beznea 		init.ops = &sam9x60_div_pll_ops_chg;
73243b1bb4aSClaudiu Beznea 	init.flags = flags;
7331e229c21SClaudiu Beznea 
73443b1bb4aSClaudiu Beznea 	div->core.id = id;
7358dc4af8bSClaudiu Beznea 	div->core.hw.init = &init;
73643b1bb4aSClaudiu Beznea 	div->core.characteristics = characteristics;
73743b1bb4aSClaudiu Beznea 	div->core.layout = layout;
73843b1bb4aSClaudiu Beznea 	div->core.regmap = regmap;
73943b1bb4aSClaudiu Beznea 	div->core.lock = lock;
74043b1bb4aSClaudiu Beznea 	div->safe_div = safe_div;
74143b1bb4aSClaudiu Beznea 
7428dc4af8bSClaudiu Beznea 	spin_lock_irqsave(div->core.lock, irqflags);
74343b1bb4aSClaudiu Beznea 
74443b1bb4aSClaudiu Beznea 	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
74543b1bb4aSClaudiu Beznea 			   AT91_PMC_PLL_UPDT_ID_MSK, id);
74643b1bb4aSClaudiu Beznea 	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
74743b1bb4aSClaudiu Beznea 	div->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val);
748a436c2a4SAlexandre Belloni 
7491e229c21SClaudiu Beznea 	spin_unlock_irqrestore(div->core.lock, irqflags);
7501e229c21SClaudiu Beznea 
7511e229c21SClaudiu Beznea 	hw = &div->core.hw;
752a436c2a4SAlexandre Belloni 	ret = clk_hw_register(NULL, hw);
753a436c2a4SAlexandre Belloni 	if (ret) {
754a436c2a4SAlexandre Belloni 		kfree(div);
755a436c2a4SAlexandre Belloni 		hw = ERR_PTR(ret);
756a436c2a4SAlexandre Belloni 	} else if (div->safe_div) {
757 		notifier_div = div;
758 		clk_notifier_register(hw->clk, &sam9x60_div_pll_notifier);
759 	}
760 
761 	return hw;
762 }
763 
764