xref: /openbmc/linux/drivers/clk/samsung/clk-pll.c (revision 1dd24dae)
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3  * Copyright (c) 2013 Linaro Ltd.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * This file contains the utility functions to register the pll clocks.
10 */
11 
12 #include <linux/errno.h>
13 #include "clk.h"
14 #include "clk-pll.h"
15 
16 /*
17  * PLL35xx Clock Type
18  */
19 
20 #define PLL35XX_MDIV_MASK       (0x3FF)
21 #define PLL35XX_PDIV_MASK       (0x3F)
22 #define PLL35XX_SDIV_MASK       (0x7)
23 #define PLL35XX_MDIV_SHIFT      (16)
24 #define PLL35XX_PDIV_SHIFT      (8)
25 #define PLL35XX_SDIV_SHIFT      (0)
26 
27 struct samsung_clk_pll35xx {
28 	struct clk_hw		hw;
29 	const void __iomem	*con_reg;
30 };
31 
32 #define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw)
33 
34 static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
35 				unsigned long parent_rate)
36 {
37 	struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw);
38 	u32 mdiv, pdiv, sdiv, pll_con;
39 	u64 fvco = parent_rate;
40 
41 	pll_con = __raw_readl(pll->con_reg);
42 	mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
43 	pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
44 	sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
45 
46 	fvco *= mdiv;
47 	do_div(fvco, (pdiv << sdiv));
48 
49 	return (unsigned long)fvco;
50 }
51 
52 static const struct clk_ops samsung_pll35xx_clk_ops = {
53 	.recalc_rate = samsung_pll35xx_recalc_rate,
54 };
55 
56 struct clk * __init samsung_clk_register_pll35xx(const char *name,
57 			const char *pname, const void __iomem *con_reg)
58 {
59 	struct samsung_clk_pll35xx *pll;
60 	struct clk *clk;
61 	struct clk_init_data init;
62 
63 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
64 	if (!pll) {
65 		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
66 		return NULL;
67 	}
68 
69 	init.name = name;
70 	init.ops = &samsung_pll35xx_clk_ops;
71 	init.flags = CLK_GET_RATE_NOCACHE;
72 	init.parent_names = &pname;
73 	init.num_parents = 1;
74 
75 	pll->hw.init = &init;
76 	pll->con_reg = con_reg;
77 
78 	clk = clk_register(NULL, &pll->hw);
79 	if (IS_ERR(clk)) {
80 		pr_err("%s: failed to register pll clock %s\n", __func__,
81 				name);
82 		kfree(pll);
83 	}
84 
85 	if (clk_register_clkdev(clk, name, NULL))
86 		pr_err("%s: failed to register lookup for %s", __func__, name);
87 
88 	return clk;
89 }
90 
91 /*
92  * PLL36xx Clock Type
93  */
94 
95 #define PLL36XX_KDIV_MASK	(0xFFFF)
96 #define PLL36XX_MDIV_MASK	(0x1FF)
97 #define PLL36XX_PDIV_MASK	(0x3F)
98 #define PLL36XX_SDIV_MASK	(0x7)
99 #define PLL36XX_MDIV_SHIFT	(16)
100 #define PLL36XX_PDIV_SHIFT	(8)
101 #define PLL36XX_SDIV_SHIFT	(0)
102 
103 struct samsung_clk_pll36xx {
104 	struct clk_hw		hw;
105 	const void __iomem	*con_reg;
106 };
107 
108 #define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw)
109 
110 static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
111 				unsigned long parent_rate)
112 {
113 	struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw);
114 	u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
115 	u64 fvco = parent_rate;
116 
117 	pll_con0 = __raw_readl(pll->con_reg);
118 	pll_con1 = __raw_readl(pll->con_reg + 4);
119 	mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
120 	pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
121 	sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
122 	kdiv = pll_con1 & PLL36XX_KDIV_MASK;
123 
124 	fvco *= (mdiv << 16) + kdiv;
125 	do_div(fvco, (pdiv << sdiv));
126 	fvco >>= 16;
127 
128 	return (unsigned long)fvco;
129 }
130 
131 static const struct clk_ops samsung_pll36xx_clk_ops = {
132 	.recalc_rate = samsung_pll36xx_recalc_rate,
133 };
134 
135 struct clk * __init samsung_clk_register_pll36xx(const char *name,
136 			const char *pname, const void __iomem *con_reg)
137 {
138 	struct samsung_clk_pll36xx *pll;
139 	struct clk *clk;
140 	struct clk_init_data init;
141 
142 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
143 	if (!pll) {
144 		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
145 		return NULL;
146 	}
147 
148 	init.name = name;
149 	init.ops = &samsung_pll36xx_clk_ops;
150 	init.flags = CLK_GET_RATE_NOCACHE;
151 	init.parent_names = &pname;
152 	init.num_parents = 1;
153 
154 	pll->hw.init = &init;
155 	pll->con_reg = con_reg;
156 
157 	clk = clk_register(NULL, &pll->hw);
158 	if (IS_ERR(clk)) {
159 		pr_err("%s: failed to register pll clock %s\n", __func__,
160 				name);
161 		kfree(pll);
162 	}
163 
164 	if (clk_register_clkdev(clk, name, NULL))
165 		pr_err("%s: failed to register lookup for %s", __func__, name);
166 
167 	return clk;
168 }
169 
170 /*
171  * PLL45xx Clock Type
172  */
173 
174 #define PLL45XX_MDIV_MASK	(0x3FF)
175 #define PLL45XX_PDIV_MASK	(0x3F)
176 #define PLL45XX_SDIV_MASK	(0x7)
177 #define PLL45XX_MDIV_SHIFT	(16)
178 #define PLL45XX_PDIV_SHIFT	(8)
179 #define PLL45XX_SDIV_SHIFT	(0)
180 
181 struct samsung_clk_pll45xx {
182 	struct clk_hw		hw;
183 	enum pll45xx_type	type;
184 	const void __iomem	*con_reg;
185 };
186 
187 #define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw)
188 
189 static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
190 				unsigned long parent_rate)
191 {
192 	struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw);
193 	u32 mdiv, pdiv, sdiv, pll_con;
194 	u64 fvco = parent_rate;
195 
196 	pll_con = __raw_readl(pll->con_reg);
197 	mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
198 	pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
199 	sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
200 
201 	if (pll->type == pll_4508)
202 		sdiv = sdiv - 1;
203 
204 	fvco *= mdiv;
205 	do_div(fvco, (pdiv << sdiv));
206 
207 	return (unsigned long)fvco;
208 }
209 
210 static const struct clk_ops samsung_pll45xx_clk_ops = {
211 	.recalc_rate = samsung_pll45xx_recalc_rate,
212 };
213 
214 struct clk * __init samsung_clk_register_pll45xx(const char *name,
215 			const char *pname, const void __iomem *con_reg,
216 			enum pll45xx_type type)
217 {
218 	struct samsung_clk_pll45xx *pll;
219 	struct clk *clk;
220 	struct clk_init_data init;
221 
222 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
223 	if (!pll) {
224 		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
225 		return NULL;
226 	}
227 
228 	init.name = name;
229 	init.ops = &samsung_pll45xx_clk_ops;
230 	init.flags = CLK_GET_RATE_NOCACHE;
231 	init.parent_names = &pname;
232 	init.num_parents = 1;
233 
234 	pll->hw.init = &init;
235 	pll->con_reg = con_reg;
236 	pll->type = type;
237 
238 	clk = clk_register(NULL, &pll->hw);
239 	if (IS_ERR(clk)) {
240 		pr_err("%s: failed to register pll clock %s\n", __func__,
241 				name);
242 		kfree(pll);
243 	}
244 
245 	if (clk_register_clkdev(clk, name, NULL))
246 		pr_err("%s: failed to register lookup for %s", __func__, name);
247 
248 	return clk;
249 }
250 
251 /*
252  * PLL46xx Clock Type
253  */
254 
255 #define PLL46XX_MDIV_MASK	(0x1FF)
256 #define PLL46XX_PDIV_MASK	(0x3F)
257 #define PLL46XX_SDIV_MASK	(0x7)
258 #define PLL46XX_MDIV_SHIFT	(16)
259 #define PLL46XX_PDIV_SHIFT	(8)
260 #define PLL46XX_SDIV_SHIFT	(0)
261 
262 #define PLL46XX_KDIV_MASK	(0xFFFF)
263 #define PLL4650C_KDIV_MASK	(0xFFF)
264 #define PLL46XX_KDIV_SHIFT	(0)
265 
266 struct samsung_clk_pll46xx {
267 	struct clk_hw		hw;
268 	enum pll46xx_type	type;
269 	const void __iomem	*con_reg;
270 };
271 
272 #define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw)
273 
274 static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
275 				unsigned long parent_rate)
276 {
277 	struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw);
278 	u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
279 	u64 fvco = parent_rate;
280 
281 	pll_con0 = __raw_readl(pll->con_reg);
282 	pll_con1 = __raw_readl(pll->con_reg + 4);
283 	mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
284 	pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
285 	sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
286 	kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
287 					pll_con1 & PLL46XX_KDIV_MASK;
288 
289 	shift = pll->type == pll_4600 ? 16 : 10;
290 	fvco *= (mdiv << shift) + kdiv;
291 	do_div(fvco, (pdiv << sdiv));
292 	fvco >>= shift;
293 
294 	return (unsigned long)fvco;
295 }
296 
297 static const struct clk_ops samsung_pll46xx_clk_ops = {
298 	.recalc_rate = samsung_pll46xx_recalc_rate,
299 };
300 
301 struct clk * __init samsung_clk_register_pll46xx(const char *name,
302 			const char *pname, const void __iomem *con_reg,
303 			enum pll46xx_type type)
304 {
305 	struct samsung_clk_pll46xx *pll;
306 	struct clk *clk;
307 	struct clk_init_data init;
308 
309 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
310 	if (!pll) {
311 		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
312 		return NULL;
313 	}
314 
315 	init.name = name;
316 	init.ops = &samsung_pll46xx_clk_ops;
317 	init.flags = CLK_GET_RATE_NOCACHE;
318 	init.parent_names = &pname;
319 	init.num_parents = 1;
320 
321 	pll->hw.init = &init;
322 	pll->con_reg = con_reg;
323 	pll->type = type;
324 
325 	clk = clk_register(NULL, &pll->hw);
326 	if (IS_ERR(clk)) {
327 		pr_err("%s: failed to register pll clock %s\n", __func__,
328 				name);
329 		kfree(pll);
330 	}
331 
332 	if (clk_register_clkdev(clk, name, NULL))
333 		pr_err("%s: failed to register lookup for %s", __func__, name);
334 
335 	return clk;
336 }
337 
338 /*
339  * PLL2550x Clock Type
340  */
341 
342 #define PLL2550X_R_MASK       (0x1)
343 #define PLL2550X_P_MASK       (0x3F)
344 #define PLL2550X_M_MASK       (0x3FF)
345 #define PLL2550X_S_MASK       (0x7)
346 #define PLL2550X_R_SHIFT      (20)
347 #define PLL2550X_P_SHIFT      (14)
348 #define PLL2550X_M_SHIFT      (4)
349 #define PLL2550X_S_SHIFT      (0)
350 
351 struct samsung_clk_pll2550x {
352 	struct clk_hw		hw;
353 	const void __iomem	*reg_base;
354 	unsigned long		offset;
355 };
356 
357 #define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
358 
359 static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
360 				unsigned long parent_rate)
361 {
362 	struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
363 	u32 r, p, m, s, pll_stat;
364 	u64 fvco = parent_rate;
365 
366 	pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
367 	r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
368 	if (!r)
369 		return 0;
370 	p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
371 	m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
372 	s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
373 
374 	fvco *= m;
375 	do_div(fvco, (p << s));
376 
377 	return (unsigned long)fvco;
378 }
379 
380 static const struct clk_ops samsung_pll2550x_clk_ops = {
381 	.recalc_rate = samsung_pll2550x_recalc_rate,
382 };
383 
384 struct clk * __init samsung_clk_register_pll2550x(const char *name,
385 			const char *pname, const void __iomem *reg_base,
386 			const unsigned long offset)
387 {
388 	struct samsung_clk_pll2550x *pll;
389 	struct clk *clk;
390 	struct clk_init_data init;
391 
392 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
393 	if (!pll) {
394 		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
395 		return NULL;
396 	}
397 
398 	init.name = name;
399 	init.ops = &samsung_pll2550x_clk_ops;
400 	init.flags = CLK_GET_RATE_NOCACHE;
401 	init.parent_names = &pname;
402 	init.num_parents = 1;
403 
404 	pll->hw.init = &init;
405 	pll->reg_base = reg_base;
406 	pll->offset = offset;
407 
408 	clk = clk_register(NULL, &pll->hw);
409 	if (IS_ERR(clk)) {
410 		pr_err("%s: failed to register pll clock %s\n", __func__,
411 				name);
412 		kfree(pll);
413 	}
414 
415 	if (clk_register_clkdev(clk, name, NULL))
416 		pr_err("%s: failed to register lookup for %s", __func__, name);
417 
418 	return clk;
419 }
420