clk: samsung: Fix pll36xx_recalc_rate to handle kdiv properly
[deliverable/linux.git] / drivers / clk / samsung / clk-pll.c
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, pll_con0, pll_con1;
115 s16 kdiv;
116 u64 fvco = parent_rate;
117
118 pll_con0 = __raw_readl(pll->con_reg);
119 pll_con1 = __raw_readl(pll->con_reg + 4);
120 mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
121 pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
122 sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
123 kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK);
124
125 fvco *= (mdiv << 16) + kdiv;
126 do_div(fvco, (pdiv << sdiv));
127 fvco >>= 16;
128
129 return (unsigned long)fvco;
130 }
131
132 static const struct clk_ops samsung_pll36xx_clk_ops = {
133 .recalc_rate = samsung_pll36xx_recalc_rate,
134 };
135
136 struct clk * __init samsung_clk_register_pll36xx(const char *name,
137 const char *pname, const void __iomem *con_reg)
138 {
139 struct samsung_clk_pll36xx *pll;
140 struct clk *clk;
141 struct clk_init_data init;
142
143 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
144 if (!pll) {
145 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
146 return NULL;
147 }
148
149 init.name = name;
150 init.ops = &samsung_pll36xx_clk_ops;
151 init.flags = CLK_GET_RATE_NOCACHE;
152 init.parent_names = &pname;
153 init.num_parents = 1;
154
155 pll->hw.init = &init;
156 pll->con_reg = con_reg;
157
158 clk = clk_register(NULL, &pll->hw);
159 if (IS_ERR(clk)) {
160 pr_err("%s: failed to register pll clock %s\n", __func__,
161 name);
162 kfree(pll);
163 }
164
165 if (clk_register_clkdev(clk, name, NULL))
166 pr_err("%s: failed to register lookup for %s", __func__, name);
167
168 return clk;
169 }
170
171 /*
172 * PLL45xx Clock Type
173 */
174
175 #define PLL45XX_MDIV_MASK (0x3FF)
176 #define PLL45XX_PDIV_MASK (0x3F)
177 #define PLL45XX_SDIV_MASK (0x7)
178 #define PLL45XX_MDIV_SHIFT (16)
179 #define PLL45XX_PDIV_SHIFT (8)
180 #define PLL45XX_SDIV_SHIFT (0)
181
182 struct samsung_clk_pll45xx {
183 struct clk_hw hw;
184 enum pll45xx_type type;
185 const void __iomem *con_reg;
186 };
187
188 #define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw)
189
190 static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
191 unsigned long parent_rate)
192 {
193 struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw);
194 u32 mdiv, pdiv, sdiv, pll_con;
195 u64 fvco = parent_rate;
196
197 pll_con = __raw_readl(pll->con_reg);
198 mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
199 pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
200 sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
201
202 if (pll->type == pll_4508)
203 sdiv = sdiv - 1;
204
205 fvco *= mdiv;
206 do_div(fvco, (pdiv << sdiv));
207
208 return (unsigned long)fvco;
209 }
210
211 static const struct clk_ops samsung_pll45xx_clk_ops = {
212 .recalc_rate = samsung_pll45xx_recalc_rate,
213 };
214
215 struct clk * __init samsung_clk_register_pll45xx(const char *name,
216 const char *pname, const void __iomem *con_reg,
217 enum pll45xx_type type)
218 {
219 struct samsung_clk_pll45xx *pll;
220 struct clk *clk;
221 struct clk_init_data init;
222
223 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
224 if (!pll) {
225 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
226 return NULL;
227 }
228
229 init.name = name;
230 init.ops = &samsung_pll45xx_clk_ops;
231 init.flags = CLK_GET_RATE_NOCACHE;
232 init.parent_names = &pname;
233 init.num_parents = 1;
234
235 pll->hw.init = &init;
236 pll->con_reg = con_reg;
237 pll->type = type;
238
239 clk = clk_register(NULL, &pll->hw);
240 if (IS_ERR(clk)) {
241 pr_err("%s: failed to register pll clock %s\n", __func__,
242 name);
243 kfree(pll);
244 }
245
246 if (clk_register_clkdev(clk, name, NULL))
247 pr_err("%s: failed to register lookup for %s", __func__, name);
248
249 return clk;
250 }
251
252 /*
253 * PLL46xx Clock Type
254 */
255
256 #define PLL46XX_MDIV_MASK (0x1FF)
257 #define PLL46XX_PDIV_MASK (0x3F)
258 #define PLL46XX_SDIV_MASK (0x7)
259 #define PLL46XX_MDIV_SHIFT (16)
260 #define PLL46XX_PDIV_SHIFT (8)
261 #define PLL46XX_SDIV_SHIFT (0)
262
263 #define PLL46XX_KDIV_MASK (0xFFFF)
264 #define PLL4650C_KDIV_MASK (0xFFF)
265 #define PLL46XX_KDIV_SHIFT (0)
266
267 struct samsung_clk_pll46xx {
268 struct clk_hw hw;
269 enum pll46xx_type type;
270 const void __iomem *con_reg;
271 };
272
273 #define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw)
274
275 static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
276 unsigned long parent_rate)
277 {
278 struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw);
279 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
280 u64 fvco = parent_rate;
281
282 pll_con0 = __raw_readl(pll->con_reg);
283 pll_con1 = __raw_readl(pll->con_reg + 4);
284 mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
285 pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
286 sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
287 kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
288 pll_con1 & PLL46XX_KDIV_MASK;
289
290 shift = pll->type == pll_4600 ? 16 : 10;
291 fvco *= (mdiv << shift) + kdiv;
292 do_div(fvco, (pdiv << sdiv));
293 fvco >>= shift;
294
295 return (unsigned long)fvco;
296 }
297
298 static const struct clk_ops samsung_pll46xx_clk_ops = {
299 .recalc_rate = samsung_pll46xx_recalc_rate,
300 };
301
302 struct clk * __init samsung_clk_register_pll46xx(const char *name,
303 const char *pname, const void __iomem *con_reg,
304 enum pll46xx_type type)
305 {
306 struct samsung_clk_pll46xx *pll;
307 struct clk *clk;
308 struct clk_init_data init;
309
310 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
311 if (!pll) {
312 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
313 return NULL;
314 }
315
316 init.name = name;
317 init.ops = &samsung_pll46xx_clk_ops;
318 init.flags = CLK_GET_RATE_NOCACHE;
319 init.parent_names = &pname;
320 init.num_parents = 1;
321
322 pll->hw.init = &init;
323 pll->con_reg = con_reg;
324 pll->type = type;
325
326 clk = clk_register(NULL, &pll->hw);
327 if (IS_ERR(clk)) {
328 pr_err("%s: failed to register pll clock %s\n", __func__,
329 name);
330 kfree(pll);
331 }
332
333 if (clk_register_clkdev(clk, name, NULL))
334 pr_err("%s: failed to register lookup for %s", __func__, name);
335
336 return clk;
337 }
338
339 /*
340 * PLL2550x Clock Type
341 */
342
343 #define PLL2550X_R_MASK (0x1)
344 #define PLL2550X_P_MASK (0x3F)
345 #define PLL2550X_M_MASK (0x3FF)
346 #define PLL2550X_S_MASK (0x7)
347 #define PLL2550X_R_SHIFT (20)
348 #define PLL2550X_P_SHIFT (14)
349 #define PLL2550X_M_SHIFT (4)
350 #define PLL2550X_S_SHIFT (0)
351
352 struct samsung_clk_pll2550x {
353 struct clk_hw hw;
354 const void __iomem *reg_base;
355 unsigned long offset;
356 };
357
358 #define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
359
360 static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
361 unsigned long parent_rate)
362 {
363 struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
364 u32 r, p, m, s, pll_stat;
365 u64 fvco = parent_rate;
366
367 pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
368 r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
369 if (!r)
370 return 0;
371 p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
372 m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
373 s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
374
375 fvco *= m;
376 do_div(fvco, (p << s));
377
378 return (unsigned long)fvco;
379 }
380
381 static const struct clk_ops samsung_pll2550x_clk_ops = {
382 .recalc_rate = samsung_pll2550x_recalc_rate,
383 };
384
385 struct clk * __init samsung_clk_register_pll2550x(const char *name,
386 const char *pname, const void __iomem *reg_base,
387 const unsigned long offset)
388 {
389 struct samsung_clk_pll2550x *pll;
390 struct clk *clk;
391 struct clk_init_data init;
392
393 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
394 if (!pll) {
395 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
396 return NULL;
397 }
398
399 init.name = name;
400 init.ops = &samsung_pll2550x_clk_ops;
401 init.flags = CLK_GET_RATE_NOCACHE;
402 init.parent_names = &pname;
403 init.num_parents = 1;
404
405 pll->hw.init = &init;
406 pll->reg_base = reg_base;
407 pll->offset = offset;
408
409 clk = clk_register(NULL, &pll->hw);
410 if (IS_ERR(clk)) {
411 pr_err("%s: failed to register pll clock %s\n", __func__,
412 name);
413 kfree(pll);
414 }
415
416 if (clk_register_clkdev(clk, name, NULL))
417 pr_err("%s: failed to register lookup for %s", __func__, name);
418
419 return clk;
420 }
This page took 0.050124 seconds and 5 git commands to generate.