clk: samsung: Fix pll36xx_recalc_rate to handle kdiv properly
[cascardo/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 }