xref: /OK3568_Linux_fs/kernel/drivers/clk/rockchip/regmap/clk-regmap-pll.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
5*4882a593Smuzhiyun  * it under the terms of the GNU General Public License as published by
6*4882a593Smuzhiyun  * the Free Software Foundation; either version 2 of the License, or
7*4882a593Smuzhiyun  * (at your option) any later version.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful,
10*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*4882a593Smuzhiyun  * GNU General Public License for more details.
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "clk-regmap.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define PLLCON_OFFSET(x)	(x * 4)
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define PLL_BYPASS(x)			HIWORD_UPDATE(x, 15, 15)
20*4882a593Smuzhiyun #define PLL_BYPASS_MASK			BIT(15)
21*4882a593Smuzhiyun #define PLL_BYPASS_SHIFT		15
22*4882a593Smuzhiyun #define PLL_POSTDIV1(x)			HIWORD_UPDATE(x, 14, 12)
23*4882a593Smuzhiyun #define PLL_POSTDIV1_MASK		GENMASK(14, 12)
24*4882a593Smuzhiyun #define PLL_POSTDIV1_SHIFT		12
25*4882a593Smuzhiyun #define PLL_FBDIV(x)			HIWORD_UPDATE(x, 11, 0)
26*4882a593Smuzhiyun #define PLL_FBDIV_MASK			GENMASK(11, 0)
27*4882a593Smuzhiyun #define PLL_FBDIV_SHIFT			0
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define PLL_POSTDIV2(x)			HIWORD_UPDATE(x, 8, 6)
30*4882a593Smuzhiyun #define PLL_POSTDIV2_MASK		GENMASK(8, 6)
31*4882a593Smuzhiyun #define PLL_POSTDIV2_SHIFT		6
32*4882a593Smuzhiyun #define PLL_REFDIV(x)			HIWORD_UPDATE(x, 5, 0)
33*4882a593Smuzhiyun #define PLL_REFDIV_MASK			GENMASK(5, 0)
34*4882a593Smuzhiyun #define PLL_REFDIV_SHIFT		0
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define PLL_FOUT_4PHASE_CLK_POWER_DOWN	BIT(27)
37*4882a593Smuzhiyun #define PLL_FOUT_VCO_CLK_POWER_DOWN	BIT(26)
38*4882a593Smuzhiyun #define PLL_FOUT_POST_DIV_POWER_DOWN	BIT(25)
39*4882a593Smuzhiyun #define PLL_DAC_POWER_DOWN		BIT(24)
40*4882a593Smuzhiyun #define PLL_FRAC(x)			UPDATE(x, 23, 0)
41*4882a593Smuzhiyun #define PLL_FRAC_MASK			GENMASK(23, 0)
42*4882a593Smuzhiyun #define PLL_FRAC_SHIFT			0
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define MIN_FREF_RATE		10000000UL
45*4882a593Smuzhiyun #define MAX_FREF_RATE		800000000UL
46*4882a593Smuzhiyun #define MIN_FREFDIV_RATE	1000000UL
47*4882a593Smuzhiyun #define MAX_FREFDIV_RATE	40000000UL
48*4882a593Smuzhiyun #define MIN_FVCO_RATE		400000000UL
49*4882a593Smuzhiyun #define MAX_FVCO_RATE		1600000000UL
50*4882a593Smuzhiyun #define MIN_FOUTPOSTDIV_RATE	8000000UL
51*4882a593Smuzhiyun #define MAX_FOUTPOSTDIV_RATE	1600000000UL
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun struct clk_regmap_pll {
54*4882a593Smuzhiyun 	struct clk_hw hw;
55*4882a593Smuzhiyun 	struct device *dev;
56*4882a593Smuzhiyun 	struct regmap *regmap;
57*4882a593Smuzhiyun 	unsigned int reg;
58*4882a593Smuzhiyun 	u8 pd_shift;
59*4882a593Smuzhiyun 	u8 dsmpd_shift;
60*4882a593Smuzhiyun 	u8 lock_shift;
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #define to_clk_regmap_pll(_hw)	container_of(_hw, struct clk_regmap_pll, hw)
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun static unsigned long
clk_regmap_pll_recalc_rate(struct clk_hw * hw,unsigned long prate)66*4882a593Smuzhiyun clk_regmap_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
69*4882a593Smuzhiyun 	unsigned int postdiv1, fbdiv, dsmpd, postdiv2, refdiv, frac, bypass;
70*4882a593Smuzhiyun 	unsigned int con0, con1, con2;
71*4882a593Smuzhiyun 	u64 foutvco, foutpostdiv;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	regmap_read(pll->regmap, pll->reg + PLLCON_OFFSET(0), &con0);
74*4882a593Smuzhiyun 	regmap_read(pll->regmap, pll->reg + PLLCON_OFFSET(1), &con1);
75*4882a593Smuzhiyun 	regmap_read(pll->regmap, pll->reg + PLLCON_OFFSET(2), &con2);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	bypass = (con0 & PLL_BYPASS_MASK) >> PLL_BYPASS_SHIFT;
78*4882a593Smuzhiyun 	postdiv1 = (con0 & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
79*4882a593Smuzhiyun 	fbdiv = (con0 & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
80*4882a593Smuzhiyun 	dsmpd = (con1 & BIT(pll->dsmpd_shift)) >> pll->dsmpd_shift;
81*4882a593Smuzhiyun 	postdiv2 = (con1 & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
82*4882a593Smuzhiyun 	refdiv = (con1 & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
83*4882a593Smuzhiyun 	frac = (con2 & PLL_FRAC_MASK) >> PLL_FRAC_SHIFT;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (bypass)
86*4882a593Smuzhiyun 		return prate;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	foutvco = prate * fbdiv;
89*4882a593Smuzhiyun 	do_div(foutvco, refdiv);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (!dsmpd) {
92*4882a593Smuzhiyun 		u64 frac_rate = (u64)prate * frac;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 		do_div(frac_rate, refdiv);
95*4882a593Smuzhiyun 		foutvco += frac_rate >> 24;
96*4882a593Smuzhiyun 	}
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	foutpostdiv = foutvco;
99*4882a593Smuzhiyun 	do_div(foutpostdiv, postdiv1);
100*4882a593Smuzhiyun 	do_div(foutpostdiv, postdiv2);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	return foutpostdiv;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
clk_pll_round_rate(unsigned long fin,unsigned long fout,u8 * refdiv,u16 * fbdiv,u8 * postdiv1,u8 * postdiv2,u32 * frac,u8 * dsmpd,u8 * bypass)105*4882a593Smuzhiyun static long clk_pll_round_rate(unsigned long fin, unsigned long fout,
106*4882a593Smuzhiyun 			       u8 *refdiv, u16 *fbdiv,
107*4882a593Smuzhiyun 			       u8 *postdiv1, u8 *postdiv2,
108*4882a593Smuzhiyun 			       u32 *frac, u8 *dsmpd, u8 *bypass)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	u8 min_refdiv, max_refdiv, postdiv;
111*4882a593Smuzhiyun 	u8 _dsmpd = 1, _postdiv1 = 0, _postdiv2 = 0, _refdiv = 0;
112*4882a593Smuzhiyun 	u16 _fbdiv = 0;
113*4882a593Smuzhiyun 	u32 _frac = 0;
114*4882a593Smuzhiyun 	u64 foutvco, foutpostdiv;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	/*
117*4882a593Smuzhiyun 	 * FREF : 10MHz ~ 800MHz
118*4882a593Smuzhiyun 	 * FREFDIV : 1MHz ~ 40MHz
119*4882a593Smuzhiyun 	 * FOUTVCO : 400MHz ~ 1.6GHz
120*4882a593Smuzhiyun 	 * FOUTPOSTDIV : 8MHz ~ 1.6GHz
121*4882a593Smuzhiyun 	 */
122*4882a593Smuzhiyun 	if (fin < MIN_FREF_RATE || fin > MAX_FREF_RATE)
123*4882a593Smuzhiyun 		return -EINVAL;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	if (fout < MIN_FOUTPOSTDIV_RATE || fout > MAX_FOUTPOSTDIV_RATE)
126*4882a593Smuzhiyun 		return -EINVAL;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	if (fin == fout) {
129*4882a593Smuzhiyun 		if (bypass)
130*4882a593Smuzhiyun 			*bypass = true;
131*4882a593Smuzhiyun 		return fin;
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	min_refdiv = DIV_ROUND_UP(fin, MAX_FREFDIV_RATE);
135*4882a593Smuzhiyun 	max_refdiv = fin / MIN_FREFDIV_RATE;
136*4882a593Smuzhiyun 	if (max_refdiv > 64)
137*4882a593Smuzhiyun 		max_refdiv = 64;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (fout < MIN_FVCO_RATE) {
140*4882a593Smuzhiyun 		postdiv = DIV_ROUND_UP_ULL(MIN_FVCO_RATE, fout);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 		for (_postdiv2 = 1; _postdiv2 < 8; _postdiv2++) {
143*4882a593Smuzhiyun 			if (postdiv % _postdiv2)
144*4882a593Smuzhiyun 				continue;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 			_postdiv1 = postdiv / _postdiv2;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 			if (_postdiv1 > 0 && _postdiv1 < 8)
149*4882a593Smuzhiyun 				break;
150*4882a593Smuzhiyun 		}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		if (_postdiv2 > 7)
153*4882a593Smuzhiyun 			return -EINVAL;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		fout *= _postdiv1 * _postdiv2;
156*4882a593Smuzhiyun 	} else {
157*4882a593Smuzhiyun 		_postdiv1 = 1;
158*4882a593Smuzhiyun 		_postdiv2 = 1;
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	for (_refdiv = min_refdiv; _refdiv <= max_refdiv; _refdiv++) {
162*4882a593Smuzhiyun 		u64 tmp, frac_rate;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 		if (fin % _refdiv)
165*4882a593Smuzhiyun 			continue;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 		tmp = (u64)fout * _refdiv;
168*4882a593Smuzhiyun 		do_div(tmp, fin);
169*4882a593Smuzhiyun 		_fbdiv = tmp;
170*4882a593Smuzhiyun 		if (_fbdiv < 10 || _fbdiv > 1600)
171*4882a593Smuzhiyun 			continue;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 		tmp = (u64)_fbdiv * fin;
174*4882a593Smuzhiyun 		do_div(tmp, _refdiv);
175*4882a593Smuzhiyun 		if (fout < MIN_FVCO_RATE || fout > MAX_FVCO_RATE)
176*4882a593Smuzhiyun 			continue;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 		frac_rate = fout - tmp;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		if (frac_rate) {
181*4882a593Smuzhiyun 			tmp = (u64)frac_rate * _refdiv;
182*4882a593Smuzhiyun 			tmp <<= 24;
183*4882a593Smuzhiyun 			do_div(tmp, fin);
184*4882a593Smuzhiyun 			_frac = tmp;
185*4882a593Smuzhiyun 			_dsmpd = 0;
186*4882a593Smuzhiyun 		}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 		break;
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	/*
192*4882a593Smuzhiyun 	 * If DSMPD = 1 (DSM is disabled, "integer mode")
193*4882a593Smuzhiyun 	 * FOUTVCO = FREF / REFDIV * FBDIV
194*4882a593Smuzhiyun 	 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
195*4882a593Smuzhiyun 	 *
196*4882a593Smuzhiyun 	 * If DSMPD = 0 (DSM is enabled, "fractional mode")
197*4882a593Smuzhiyun 	 * FOUTVCO = FREF / REFDIV * (FBDIV + FRAC / 2^24)
198*4882a593Smuzhiyun 	 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
199*4882a593Smuzhiyun 	 */
200*4882a593Smuzhiyun 	foutvco = fin * _fbdiv;
201*4882a593Smuzhiyun 	do_div(foutvco, _refdiv);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (!_dsmpd) {
204*4882a593Smuzhiyun 		u64 frac_rate = (u64)fin * _frac;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 		do_div(frac_rate, _refdiv);
207*4882a593Smuzhiyun 		foutvco += frac_rate >> 24;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	foutpostdiv = foutvco;
211*4882a593Smuzhiyun 	do_div(foutpostdiv, _postdiv1);
212*4882a593Smuzhiyun 	do_div(foutpostdiv, _postdiv2);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	if (refdiv)
215*4882a593Smuzhiyun 		*refdiv = _refdiv;
216*4882a593Smuzhiyun 	if (fbdiv)
217*4882a593Smuzhiyun 		*fbdiv = _fbdiv;
218*4882a593Smuzhiyun 	if (postdiv1)
219*4882a593Smuzhiyun 		*postdiv1 = _postdiv1;
220*4882a593Smuzhiyun 	if (postdiv2)
221*4882a593Smuzhiyun 		*postdiv2 = _postdiv2;
222*4882a593Smuzhiyun 	if (frac)
223*4882a593Smuzhiyun 		*frac = _frac;
224*4882a593Smuzhiyun 	if (dsmpd)
225*4882a593Smuzhiyun 		*dsmpd = _dsmpd;
226*4882a593Smuzhiyun 	if (bypass)
227*4882a593Smuzhiyun 		*bypass = false;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	return (unsigned long)foutpostdiv;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun static long
clk_regmap_pll_round_rate(struct clk_hw * hw,unsigned long drate,unsigned long * prate)233*4882a593Smuzhiyun clk_regmap_pll_round_rate(struct clk_hw *hw, unsigned long drate,
234*4882a593Smuzhiyun 			  unsigned long *prate)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
237*4882a593Smuzhiyun 	long rate;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	rate = clk_pll_round_rate(*prate, drate, NULL, NULL, NULL, NULL, NULL,
240*4882a593Smuzhiyun 				  NULL, NULL);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	dev_dbg(pll->dev, "%s: prate=%ld, drate=%ld, rate=%ld\n",
243*4882a593Smuzhiyun 		clk_hw_get_name(hw), *prate, drate, rate);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	return rate;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun static int
clk_regmap_pll_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)249*4882a593Smuzhiyun clk_regmap_pll_set_rate(struct clk_hw *hw, unsigned long drate,
250*4882a593Smuzhiyun 			unsigned long prate)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
253*4882a593Smuzhiyun 	u8 refdiv, postdiv1, postdiv2, dsmpd, bypass;
254*4882a593Smuzhiyun 	u16 fbdiv;
255*4882a593Smuzhiyun 	u32 frac;
256*4882a593Smuzhiyun 	long rate;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	rate = clk_pll_round_rate(prate, drate, &refdiv, &fbdiv, &postdiv1,
259*4882a593Smuzhiyun 				  &postdiv2, &frac, &dsmpd, &bypass);
260*4882a593Smuzhiyun 	if (rate < 0)
261*4882a593Smuzhiyun 		return rate;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	dev_dbg(pll->dev, "%s: rate=%ld, bypass=%d\n",
264*4882a593Smuzhiyun 		clk_hw_get_name(hw), drate, bypass);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	if (bypass) {
267*4882a593Smuzhiyun 		regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(0),
268*4882a593Smuzhiyun 			     PLL_BYPASS(1));
269*4882a593Smuzhiyun 	} else {
270*4882a593Smuzhiyun 		regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(0),
271*4882a593Smuzhiyun 			     PLL_BYPASS(0) | PLL_POSTDIV1(postdiv1) |
272*4882a593Smuzhiyun 			     PLL_FBDIV(fbdiv));
273*4882a593Smuzhiyun 		regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(1),
274*4882a593Smuzhiyun 			     HIWORD_UPDATE(dsmpd, pll->dsmpd_shift, pll->dsmpd_shift) |
275*4882a593Smuzhiyun 			     PLL_POSTDIV2(postdiv2) | PLL_REFDIV(refdiv));
276*4882a593Smuzhiyun 		regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(2),
277*4882a593Smuzhiyun 			     PLL_FRAC(frac));
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 		dev_dbg(pll->dev, "refdiv=%d, fbdiv=%d, frac=%d\n",
280*4882a593Smuzhiyun 			refdiv, fbdiv, frac);
281*4882a593Smuzhiyun 		dev_dbg(pll->dev, "postdiv1=%d, postdiv2=%d\n",
282*4882a593Smuzhiyun 			postdiv1, postdiv2);
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	return 0;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
clk_regmap_pll_prepare(struct clk_hw * hw)288*4882a593Smuzhiyun static int clk_regmap_pll_prepare(struct clk_hw *hw)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
291*4882a593Smuzhiyun 	u32 v;
292*4882a593Smuzhiyun 	int ret;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(1),
295*4882a593Smuzhiyun 		     HIWORD_UPDATE(0, pll->pd_shift, pll->pd_shift));
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	ret = regmap_read_poll_timeout(pll->regmap,
298*4882a593Smuzhiyun 				       pll->reg + PLLCON_OFFSET(1),
299*4882a593Smuzhiyun 				       v, v & BIT(pll->lock_shift), 50, 50000);
300*4882a593Smuzhiyun 	if (ret)
301*4882a593Smuzhiyun 		dev_err(pll->dev, "%s is not lock\n", clk_hw_get_name(hw));
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	return 0;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
clk_regmap_pll_unprepare(struct clk_hw * hw)306*4882a593Smuzhiyun static void clk_regmap_pll_unprepare(struct clk_hw *hw)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun 	struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(1),
311*4882a593Smuzhiyun 		     HIWORD_UPDATE(1, pll->pd_shift, pll->pd_shift));
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
clk_regmap_pll_is_prepared(struct clk_hw * hw)314*4882a593Smuzhiyun static int clk_regmap_pll_is_prepared(struct clk_hw *hw)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun 	struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
317*4882a593Smuzhiyun 	unsigned int con1;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	regmap_read(pll->regmap, pll->reg + PLLCON_OFFSET(1), &con1);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	return !(con1 & BIT(pll->pd_shift));
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun static const struct clk_ops clk_regmap_pll_ops = {
325*4882a593Smuzhiyun 	.recalc_rate = clk_regmap_pll_recalc_rate,
326*4882a593Smuzhiyun 	.round_rate = clk_regmap_pll_round_rate,
327*4882a593Smuzhiyun 	.set_rate = clk_regmap_pll_set_rate,
328*4882a593Smuzhiyun 	.prepare = clk_regmap_pll_prepare,
329*4882a593Smuzhiyun 	.unprepare = clk_regmap_pll_unprepare,
330*4882a593Smuzhiyun 	.is_prepared = clk_regmap_pll_is_prepared,
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun struct clk *
devm_clk_regmap_register_pll(struct device * dev,const char * name,const char * parent_name,struct regmap * regmap,u32 reg,u8 pd_shift,u8 dsmpd_shift,u8 lock_shift,unsigned long flags)334*4882a593Smuzhiyun devm_clk_regmap_register_pll(struct device *dev, const char *name,
335*4882a593Smuzhiyun 			     const char *parent_name,
336*4882a593Smuzhiyun 			     struct regmap *regmap, u32 reg, u8 pd_shift,
337*4882a593Smuzhiyun 			     u8 dsmpd_shift, u8 lock_shift,
338*4882a593Smuzhiyun 			     unsigned long flags)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun 	struct clk_regmap_pll *pll;
341*4882a593Smuzhiyun 	struct clk_init_data init = {};
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
344*4882a593Smuzhiyun 	if (!pll)
345*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	init.name = name;
348*4882a593Smuzhiyun 	init.ops = &clk_regmap_pll_ops;
349*4882a593Smuzhiyun 	init.flags = flags;
350*4882a593Smuzhiyun 	init.parent_names = (parent_name ? &parent_name : NULL);
351*4882a593Smuzhiyun 	init.num_parents = (parent_name ? 1 : 0);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	pll->dev = dev;
354*4882a593Smuzhiyun 	pll->regmap = regmap;
355*4882a593Smuzhiyun 	pll->reg = reg;
356*4882a593Smuzhiyun 	pll->pd_shift = pd_shift;
357*4882a593Smuzhiyun 	pll->dsmpd_shift = dsmpd_shift;
358*4882a593Smuzhiyun 	pll->lock_shift = lock_shift;
359*4882a593Smuzhiyun 	pll->hw.init = &init;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	return devm_clk_register(dev, &pll->hw);
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(devm_clk_regmap_register_pll);
364