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