blob: f80efb6bc0b3eef224644c0915b5232f3f05632b [file] [log] [blame]
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +09001/*
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
Yadwinder Singh Brar079dbea2013-06-11 15:01:06 +053016struct samsung_clk_pll {
17 struct clk_hw hw;
18 void __iomem *lock_reg;
19 void __iomem *con_reg;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +053020 enum samsung_pll_type type;
Yadwinder Singh Brar3ff6e0d2013-06-11 15:01:12 +053021 unsigned int rate_count;
22 const struct samsung_pll_rate_table *rate_table;
Yadwinder Singh Brar079dbea2013-06-11 15:01:06 +053023};
24
25#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
26
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +053027static const struct samsung_pll_rate_table *samsung_get_pll_settings(
28 struct samsung_clk_pll *pll, unsigned long rate)
29{
30 const struct samsung_pll_rate_table *rate_table = pll->rate_table;
31 int i;
32
33 for (i = 0; i < pll->rate_count; i++) {
34 if (rate == rate_table[i].rate)
35 return &rate_table[i];
36 }
37
38 return NULL;
39}
40
41static long samsung_pll_round_rate(struct clk_hw *hw,
42 unsigned long drate, unsigned long *prate)
43{
44 struct samsung_clk_pll *pll = to_clk_pll(hw);
45 const struct samsung_pll_rate_table *rate_table = pll->rate_table;
46 int i;
47
48 /* Assumming rate_table is in descending order */
49 for (i = 0; i < pll->rate_count; i++) {
50 if (drate >= rate_table[i].rate)
51 return rate_table[i].rate;
52 }
53
54 /* return minimum supported value */
55 return rate_table[i - 1].rate;
56}
57
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +090058/*
59 * PLL35xx Clock Type
60 */
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +053061/* Maximum lock time can be 270 * PDIV cycles */
62#define PLL35XX_LOCK_FACTOR (270)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +090063
64#define PLL35XX_MDIV_MASK (0x3FF)
65#define PLL35XX_PDIV_MASK (0x3F)
66#define PLL35XX_SDIV_MASK (0x7)
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +053067#define PLL35XX_LOCK_STAT_MASK (0x1)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +090068#define PLL35XX_MDIV_SHIFT (16)
69#define PLL35XX_PDIV_SHIFT (8)
70#define PLL35XX_SDIV_SHIFT (0)
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +053071#define PLL35XX_LOCK_STAT_SHIFT (29)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +090072
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +090073static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
74 unsigned long parent_rate)
75{
Yadwinder Singh Brar079dbea2013-06-11 15:01:06 +053076 struct samsung_clk_pll *pll = to_clk_pll(hw);
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +090077 u32 mdiv, pdiv, sdiv, pll_con;
78 u64 fvco = parent_rate;
79
80 pll_con = __raw_readl(pll->con_reg);
81 mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
82 pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
83 sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
84
85 fvco *= mdiv;
86 do_div(fvco, (pdiv << sdiv));
87
88 return (unsigned long)fvco;
89}
90
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +053091static inline bool samsung_pll35xx_mp_change(
92 const struct samsung_pll_rate_table *rate, u32 pll_con)
93{
94 u32 old_mdiv, old_pdiv;
95
96 old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
97 old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
98
99 return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv);
100}
101
102static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
103 unsigned long prate)
104{
105 struct samsung_clk_pll *pll = to_clk_pll(hw);
106 const struct samsung_pll_rate_table *rate;
107 u32 tmp;
108
109 /* Get required rate settings from table */
110 rate = samsung_get_pll_settings(pll, drate);
111 if (!rate) {
112 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
113 drate, __clk_get_name(hw->clk));
114 return -EINVAL;
115 }
116
117 tmp = __raw_readl(pll->con_reg);
118
119 if (!(samsung_pll35xx_mp_change(rate, tmp))) {
120 /* If only s change, change just s value only*/
121 tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
122 tmp |= rate->sdiv << PLL35XX_SDIV_SHIFT;
123 __raw_writel(tmp, pll->con_reg);
124
125 return 0;
126 }
127
128 /* Set PLL lock time. */
129 __raw_writel(rate->pdiv * PLL35XX_LOCK_FACTOR,
130 pll->lock_reg);
131
132 /* Change PLL PMS values */
133 tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) |
134 (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) |
135 (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT));
136 tmp |= (rate->mdiv << PLL35XX_MDIV_SHIFT) |
137 (rate->pdiv << PLL35XX_PDIV_SHIFT) |
138 (rate->sdiv << PLL35XX_SDIV_SHIFT);
139 __raw_writel(tmp, pll->con_reg);
140
141 /* wait_lock_time */
142 do {
143 cpu_relax();
144 tmp = __raw_readl(pll->con_reg);
145 } while (!(tmp & (PLL35XX_LOCK_STAT_MASK
146 << PLL35XX_LOCK_STAT_SHIFT)));
147 return 0;
148}
149
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900150static const struct clk_ops samsung_pll35xx_clk_ops = {
151 .recalc_rate = samsung_pll35xx_recalc_rate,
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +0530152 .round_rate = samsung_pll_round_rate,
153 .set_rate = samsung_pll35xx_set_rate,
154};
155
156static const struct clk_ops samsung_pll35xx_clk_min_ops = {
157 .recalc_rate = samsung_pll35xx_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900158};
159
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900160/*
161 * PLL36xx Clock Type
162 */
Vikas Sajjanbb4278d2013-06-11 15:01:14 +0530163/* Maximum lock time can be 3000 * PDIV cycles */
164#define PLL36XX_LOCK_FACTOR (3000)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900165
166#define PLL36XX_KDIV_MASK (0xFFFF)
167#define PLL36XX_MDIV_MASK (0x1FF)
168#define PLL36XX_PDIV_MASK (0x3F)
169#define PLL36XX_SDIV_MASK (0x7)
170#define PLL36XX_MDIV_SHIFT (16)
171#define PLL36XX_PDIV_SHIFT (8)
172#define PLL36XX_SDIV_SHIFT (0)
Vikas Sajjanbb4278d2013-06-11 15:01:14 +0530173#define PLL36XX_KDIV_SHIFT (0)
174#define PLL36XX_LOCK_STAT_SHIFT (29)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900175
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900176static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
177 unsigned long parent_rate)
178{
Yadwinder Singh Brar079dbea2013-06-11 15:01:06 +0530179 struct samsung_clk_pll *pll = to_clk_pll(hw);
Doug Anderson071ff9a2013-06-11 08:24:05 -0700180 u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
181 s16 kdiv;
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900182 u64 fvco = parent_rate;
183
184 pll_con0 = __raw_readl(pll->con_reg);
185 pll_con1 = __raw_readl(pll->con_reg + 4);
186 mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
187 pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
188 sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
Doug Anderson071ff9a2013-06-11 08:24:05 -0700189 kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK);
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900190
191 fvco *= (mdiv << 16) + kdiv;
192 do_div(fvco, (pdiv << sdiv));
193 fvco >>= 16;
194
195 return (unsigned long)fvco;
196}
197
Vikas Sajjanbb4278d2013-06-11 15:01:14 +0530198static inline bool samsung_pll36xx_mpk_change(
199 const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1)
200{
201 u32 old_mdiv, old_pdiv, old_kdiv;
202
203 old_mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
204 old_pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
205 old_kdiv = (pll_con1 >> PLL36XX_KDIV_SHIFT) & PLL36XX_KDIV_MASK;
206
207 return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
208 rate->kdiv != old_kdiv);
209}
210
211static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
212 unsigned long parent_rate)
213{
214 struct samsung_clk_pll *pll = to_clk_pll(hw);
215 u32 tmp, pll_con0, pll_con1;
216 const struct samsung_pll_rate_table *rate;
217
218 rate = samsung_get_pll_settings(pll, drate);
219 if (!rate) {
220 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
221 drate, __clk_get_name(hw->clk));
222 return -EINVAL;
223 }
224
225 pll_con0 = __raw_readl(pll->con_reg);
226 pll_con1 = __raw_readl(pll->con_reg + 4);
227
228 if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) {
229 /* If only s change, change just s value only*/
230 pll_con0 &= ~(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT);
231 pll_con0 |= (rate->sdiv << PLL36XX_SDIV_SHIFT);
232 __raw_writel(pll_con0, pll->con_reg);
233
234 return 0;
235 }
236
237 /* Set PLL lock time. */
238 __raw_writel(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg);
239
240 /* Change PLL PMS values */
241 pll_con0 &= ~((PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT) |
242 (PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT) |
243 (PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT));
244 pll_con0 |= (rate->mdiv << PLL36XX_MDIV_SHIFT) |
245 (rate->pdiv << PLL36XX_PDIV_SHIFT) |
246 (rate->sdiv << PLL36XX_SDIV_SHIFT);
247 __raw_writel(pll_con0, pll->con_reg);
248
249 pll_con1 &= ~(PLL36XX_KDIV_MASK << PLL36XX_KDIV_SHIFT);
250 pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
251 __raw_writel(pll_con1, pll->con_reg + 4);
252
253 /* wait_lock_time */
254 do {
255 cpu_relax();
256 tmp = __raw_readl(pll->con_reg);
257 } while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT)));
258
259 return 0;
260}
261
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900262static const struct clk_ops samsung_pll36xx_clk_ops = {
263 .recalc_rate = samsung_pll36xx_recalc_rate,
Vikas Sajjanbb4278d2013-06-11 15:01:14 +0530264 .set_rate = samsung_pll36xx_set_rate,
265 .round_rate = samsung_pll_round_rate,
266};
267
268static const struct clk_ops samsung_pll36xx_clk_min_ops = {
269 .recalc_rate = samsung_pll36xx_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900270};
271
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900272/*
273 * PLL45xx Clock Type
274 */
275
276#define PLL45XX_MDIV_MASK (0x3FF)
277#define PLL45XX_PDIV_MASK (0x3F)
278#define PLL45XX_SDIV_MASK (0x7)
279#define PLL45XX_MDIV_SHIFT (16)
280#define PLL45XX_PDIV_SHIFT (8)
281#define PLL45XX_SDIV_SHIFT (0)
282
283struct samsung_clk_pll45xx {
284 struct clk_hw hw;
285 enum pll45xx_type type;
286 const void __iomem *con_reg;
287};
288
289#define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw)
290
291static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
292 unsigned long parent_rate)
293{
294 struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw);
295 u32 mdiv, pdiv, sdiv, pll_con;
296 u64 fvco = parent_rate;
297
298 pll_con = __raw_readl(pll->con_reg);
299 mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
300 pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
301 sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
302
303 if (pll->type == pll_4508)
304 sdiv = sdiv - 1;
305
306 fvco *= mdiv;
307 do_div(fvco, (pdiv << sdiv));
308
309 return (unsigned long)fvco;
310}
311
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900312static const struct clk_ops samsung_pll45xx_clk_ops = {
313 .recalc_rate = samsung_pll45xx_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900314};
315
316struct clk * __init samsung_clk_register_pll45xx(const char *name,
317 const char *pname, const void __iomem *con_reg,
318 enum pll45xx_type type)
319{
320 struct samsung_clk_pll45xx *pll;
321 struct clk *clk;
322 struct clk_init_data init;
323
324 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
325 if (!pll) {
326 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
327 return NULL;
328 }
329
330 init.name = name;
331 init.ops = &samsung_pll45xx_clk_ops;
332 init.flags = CLK_GET_RATE_NOCACHE;
333 init.parent_names = &pname;
334 init.num_parents = 1;
335
336 pll->hw.init = &init;
337 pll->con_reg = con_reg;
338 pll->type = type;
339
340 clk = clk_register(NULL, &pll->hw);
341 if (IS_ERR(clk)) {
342 pr_err("%s: failed to register pll clock %s\n", __func__,
343 name);
344 kfree(pll);
345 }
346
347 if (clk_register_clkdev(clk, name, NULL))
348 pr_err("%s: failed to register lookup for %s", __func__, name);
349
350 return clk;
351}
352
353/*
354 * PLL46xx Clock Type
355 */
356
357#define PLL46XX_MDIV_MASK (0x1FF)
358#define PLL46XX_PDIV_MASK (0x3F)
359#define PLL46XX_SDIV_MASK (0x7)
360#define PLL46XX_MDIV_SHIFT (16)
361#define PLL46XX_PDIV_SHIFT (8)
362#define PLL46XX_SDIV_SHIFT (0)
363
364#define PLL46XX_KDIV_MASK (0xFFFF)
365#define PLL4650C_KDIV_MASK (0xFFF)
366#define PLL46XX_KDIV_SHIFT (0)
367
368struct samsung_clk_pll46xx {
369 struct clk_hw hw;
370 enum pll46xx_type type;
371 const void __iomem *con_reg;
372};
373
374#define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw)
375
376static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
377 unsigned long parent_rate)
378{
379 struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw);
380 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
381 u64 fvco = parent_rate;
382
383 pll_con0 = __raw_readl(pll->con_reg);
384 pll_con1 = __raw_readl(pll->con_reg + 4);
385 mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
386 pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
387 sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
388 kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
389 pll_con1 & PLL46XX_KDIV_MASK;
390
391 shift = pll->type == pll_4600 ? 16 : 10;
392 fvco *= (mdiv << shift) + kdiv;
393 do_div(fvco, (pdiv << sdiv));
394 fvco >>= shift;
395
396 return (unsigned long)fvco;
397}
398
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900399static const struct clk_ops samsung_pll46xx_clk_ops = {
400 .recalc_rate = samsung_pll46xx_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900401};
402
403struct clk * __init samsung_clk_register_pll46xx(const char *name,
404 const char *pname, const void __iomem *con_reg,
405 enum pll46xx_type type)
406{
407 struct samsung_clk_pll46xx *pll;
408 struct clk *clk;
409 struct clk_init_data init;
410
411 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
412 if (!pll) {
413 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
414 return NULL;
415 }
416
417 init.name = name;
418 init.ops = &samsung_pll46xx_clk_ops;
419 init.flags = CLK_GET_RATE_NOCACHE;
420 init.parent_names = &pname;
421 init.num_parents = 1;
422
423 pll->hw.init = &init;
424 pll->con_reg = con_reg;
425 pll->type = type;
426
427 clk = clk_register(NULL, &pll->hw);
428 if (IS_ERR(clk)) {
429 pr_err("%s: failed to register pll clock %s\n", __func__,
430 name);
431 kfree(pll);
432 }
433
434 if (clk_register_clkdev(clk, name, NULL))
435 pr_err("%s: failed to register lookup for %s", __func__, name);
436
437 return clk;
438}
439
440/*
441 * PLL2550x Clock Type
442 */
443
444#define PLL2550X_R_MASK (0x1)
445#define PLL2550X_P_MASK (0x3F)
446#define PLL2550X_M_MASK (0x3FF)
447#define PLL2550X_S_MASK (0x7)
448#define PLL2550X_R_SHIFT (20)
449#define PLL2550X_P_SHIFT (14)
450#define PLL2550X_M_SHIFT (4)
451#define PLL2550X_S_SHIFT (0)
452
453struct samsung_clk_pll2550x {
454 struct clk_hw hw;
455 const void __iomem *reg_base;
456 unsigned long offset;
457};
458
459#define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
460
461static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
462 unsigned long parent_rate)
463{
464 struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
465 u32 r, p, m, s, pll_stat;
466 u64 fvco = parent_rate;
467
468 pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
469 r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
470 if (!r)
471 return 0;
472 p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
473 m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
474 s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
475
476 fvco *= m;
477 do_div(fvco, (p << s));
478
479 return (unsigned long)fvco;
480}
481
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900482static const struct clk_ops samsung_pll2550x_clk_ops = {
483 .recalc_rate = samsung_pll2550x_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900484};
485
486struct clk * __init samsung_clk_register_pll2550x(const char *name,
487 const char *pname, const void __iomem *reg_base,
488 const unsigned long offset)
489{
490 struct samsung_clk_pll2550x *pll;
491 struct clk *clk;
492 struct clk_init_data init;
493
494 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
495 if (!pll) {
496 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
497 return NULL;
498 }
499
500 init.name = name;
501 init.ops = &samsung_pll2550x_clk_ops;
502 init.flags = CLK_GET_RATE_NOCACHE;
503 init.parent_names = &pname;
504 init.num_parents = 1;
505
506 pll->hw.init = &init;
507 pll->reg_base = reg_base;
508 pll->offset = offset;
509
510 clk = clk_register(NULL, &pll->hw);
511 if (IS_ERR(clk)) {
512 pr_err("%s: failed to register pll clock %s\n", __func__,
513 name);
514 kfree(pll);
515 }
516
517 if (clk_register_clkdev(clk, name, NULL))
518 pr_err("%s: failed to register lookup for %s", __func__, name);
519
520 return clk;
521}
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +0530522
523static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
524 void __iomem *base)
525{
526 struct samsung_clk_pll *pll;
527 struct clk *clk;
528 struct clk_init_data init;
Yadwinder Singh Brar3ff6e0d2013-06-11 15:01:12 +0530529 int ret, len;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +0530530
531 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
532 if (!pll) {
533 pr_err("%s: could not allocate pll clk %s\n",
534 __func__, pll_clk->name);
535 return;
536 }
537
538 init.name = pll_clk->name;
539 init.flags = pll_clk->flags;
540 init.parent_names = &pll_clk->parent_name;
541 init.num_parents = 1;
542
Yadwinder Singh Brar3ff6e0d2013-06-11 15:01:12 +0530543 if (pll_clk->rate_table) {
544 /* find count of rates in rate_table */
545 for (len = 0; pll_clk->rate_table[len].rate != 0; )
546 len++;
547
548 pll->rate_count = len;
549 pll->rate_table = kmemdup(pll_clk->rate_table,
550 pll->rate_count *
551 sizeof(struct samsung_pll_rate_table),
552 GFP_KERNEL);
553 WARN(!pll->rate_table,
554 "%s: could not allocate rate table for %s\n",
555 __func__, pll_clk->name);
556 }
557
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +0530558 switch (pll_clk->type) {
559 /* clk_ops for 35xx and 2550 are similar */
560 case pll_35xx:
561 case pll_2550:
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +0530562 if (!pll->rate_table)
563 init.ops = &samsung_pll35xx_clk_min_ops;
564 else
565 init.ops = &samsung_pll35xx_clk_ops;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +0530566 break;
567 /* clk_ops for 36xx and 2650 are similar */
568 case pll_36xx:
569 case pll_2650:
Vikas Sajjanbb4278d2013-06-11 15:01:14 +0530570 if (!pll->rate_table)
571 init.ops = &samsung_pll36xx_clk_min_ops;
572 else
573 init.ops = &samsung_pll36xx_clk_ops;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +0530574 break;
575 default:
576 pr_warn("%s: Unknown pll type for pll clk %s\n",
577 __func__, pll_clk->name);
578 }
579
580 pll->hw.init = &init;
581 pll->type = pll_clk->type;
582 pll->lock_reg = base + pll_clk->lock_offset;
583 pll->con_reg = base + pll_clk->con_offset;
584
585 clk = clk_register(NULL, &pll->hw);
586 if (IS_ERR(clk)) {
587 pr_err("%s: failed to register pll clock %s : %ld\n",
588 __func__, pll_clk->name, PTR_ERR(clk));
589 kfree(pll);
590 return;
591 }
592
593 samsung_clk_add_lookup(clk, pll_clk->id);
594
595 if (!pll_clk->alias)
596 return;
597
598 ret = clk_register_clkdev(clk, pll_clk->alias, pll_clk->dev_name);
599 if (ret)
600 pr_err("%s: failed to register lookup for %s : %d",
601 __func__, pll_clk->name, ret);
602}
603
604void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
605 unsigned int nr_pll, void __iomem *base)
606{
607 int cnt;
608
609 for (cnt = 0; cnt < nr_pll; cnt++)
610 _samsung_clk_register_pll(&pll_list[cnt], base);
611}