ARM: dts: add 'dr_mode' property to hsotg devices for exynos boards
[linux/fpc-iii.git] / drivers / clk / samsung / clk-pll.c
blob9d70e5c03804cee247ee54ff4faed549bbf7ea12
1 /*
2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3 * Copyright (c) 2013 Linaro Ltd.
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.
9 * This file contains the utility functions to register the pll clocks.
12 #include <linux/errno.h>
13 #include <linux/hrtimer.h>
14 #include <linux/delay.h>
15 #include "clk.h"
16 #include "clk-pll.h"
18 #define PLL_TIMEOUT_MS 10
20 struct samsung_clk_pll {
21 struct clk_hw hw;
22 void __iomem *lock_reg;
23 void __iomem *con_reg;
24 enum samsung_pll_type type;
25 unsigned int rate_count;
26 const struct samsung_pll_rate_table *rate_table;
29 #define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
31 static const struct samsung_pll_rate_table *samsung_get_pll_settings(
32 struct samsung_clk_pll *pll, unsigned long rate)
34 const struct samsung_pll_rate_table *rate_table = pll->rate_table;
35 int i;
37 for (i = 0; i < pll->rate_count; i++) {
38 if (rate == rate_table[i].rate)
39 return &rate_table[i];
42 return NULL;
45 static long samsung_pll_round_rate(struct clk_hw *hw,
46 unsigned long drate, unsigned long *prate)
48 struct samsung_clk_pll *pll = to_clk_pll(hw);
49 const struct samsung_pll_rate_table *rate_table = pll->rate_table;
50 int i;
52 /* Assumming rate_table is in descending order */
53 for (i = 0; i < pll->rate_count; i++) {
54 if (drate >= rate_table[i].rate)
55 return rate_table[i].rate;
58 /* return minimum supported value */
59 return rate_table[i - 1].rate;
63 * PLL2126 Clock Type
66 #define PLL2126_MDIV_MASK (0xff)
67 #define PLL2126_PDIV_MASK (0x3f)
68 #define PLL2126_SDIV_MASK (0x3)
69 #define PLL2126_MDIV_SHIFT (16)
70 #define PLL2126_PDIV_SHIFT (8)
71 #define PLL2126_SDIV_SHIFT (0)
73 static unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw,
74 unsigned long parent_rate)
76 struct samsung_clk_pll *pll = to_clk_pll(hw);
77 u32 pll_con, mdiv, pdiv, sdiv;
78 u64 fvco = parent_rate;
80 pll_con = __raw_readl(pll->con_reg);
81 mdiv = (pll_con >> PLL2126_MDIV_SHIFT) & PLL2126_MDIV_MASK;
82 pdiv = (pll_con >> PLL2126_PDIV_SHIFT) & PLL2126_PDIV_MASK;
83 sdiv = (pll_con >> PLL2126_SDIV_SHIFT) & PLL2126_SDIV_MASK;
85 fvco *= (mdiv + 8);
86 do_div(fvco, (pdiv + 2) << sdiv);
88 return (unsigned long)fvco;
91 static const struct clk_ops samsung_pll2126_clk_ops = {
92 .recalc_rate = samsung_pll2126_recalc_rate,
96 * PLL3000 Clock Type
99 #define PLL3000_MDIV_MASK (0xff)
100 #define PLL3000_PDIV_MASK (0x3)
101 #define PLL3000_SDIV_MASK (0x3)
102 #define PLL3000_MDIV_SHIFT (16)
103 #define PLL3000_PDIV_SHIFT (8)
104 #define PLL3000_SDIV_SHIFT (0)
106 static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw,
107 unsigned long parent_rate)
109 struct samsung_clk_pll *pll = to_clk_pll(hw);
110 u32 pll_con, mdiv, pdiv, sdiv;
111 u64 fvco = parent_rate;
113 pll_con = __raw_readl(pll->con_reg);
114 mdiv = (pll_con >> PLL3000_MDIV_SHIFT) & PLL3000_MDIV_MASK;
115 pdiv = (pll_con >> PLL3000_PDIV_SHIFT) & PLL3000_PDIV_MASK;
116 sdiv = (pll_con >> PLL3000_SDIV_SHIFT) & PLL3000_SDIV_MASK;
118 fvco *= (2 * (mdiv + 8));
119 do_div(fvco, pdiv << sdiv);
121 return (unsigned long)fvco;
124 static const struct clk_ops samsung_pll3000_clk_ops = {
125 .recalc_rate = samsung_pll3000_recalc_rate,
129 * PLL35xx Clock Type
131 /* Maximum lock time can be 270 * PDIV cycles */
132 #define PLL35XX_LOCK_FACTOR (270)
134 #define PLL35XX_MDIV_MASK (0x3FF)
135 #define PLL35XX_PDIV_MASK (0x3F)
136 #define PLL35XX_SDIV_MASK (0x7)
137 #define PLL35XX_LOCK_STAT_MASK (0x1)
138 #define PLL35XX_MDIV_SHIFT (16)
139 #define PLL35XX_PDIV_SHIFT (8)
140 #define PLL35XX_SDIV_SHIFT (0)
141 #define PLL35XX_LOCK_STAT_SHIFT (29)
143 static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
144 unsigned long parent_rate)
146 struct samsung_clk_pll *pll = to_clk_pll(hw);
147 u32 mdiv, pdiv, sdiv, pll_con;
148 u64 fvco = parent_rate;
150 pll_con = __raw_readl(pll->con_reg);
151 mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
152 pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
153 sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
155 fvco *= mdiv;
156 do_div(fvco, (pdiv << sdiv));
158 return (unsigned long)fvco;
161 static inline bool samsung_pll35xx_mp_change(
162 const struct samsung_pll_rate_table *rate, u32 pll_con)
164 u32 old_mdiv, old_pdiv;
166 old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
167 old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
169 return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv);
172 static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
173 unsigned long prate)
175 struct samsung_clk_pll *pll = to_clk_pll(hw);
176 const struct samsung_pll_rate_table *rate;
177 u32 tmp;
179 /* Get required rate settings from table */
180 rate = samsung_get_pll_settings(pll, drate);
181 if (!rate) {
182 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
183 drate, __clk_get_name(hw->clk));
184 return -EINVAL;
187 tmp = __raw_readl(pll->con_reg);
189 if (!(samsung_pll35xx_mp_change(rate, tmp))) {
190 /* If only s change, change just s value only*/
191 tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
192 tmp |= rate->sdiv << PLL35XX_SDIV_SHIFT;
193 __raw_writel(tmp, pll->con_reg);
195 return 0;
198 /* Set PLL lock time. */
199 __raw_writel(rate->pdiv * PLL35XX_LOCK_FACTOR,
200 pll->lock_reg);
202 /* Change PLL PMS values */
203 tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) |
204 (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) |
205 (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT));
206 tmp |= (rate->mdiv << PLL35XX_MDIV_SHIFT) |
207 (rate->pdiv << PLL35XX_PDIV_SHIFT) |
208 (rate->sdiv << PLL35XX_SDIV_SHIFT);
209 __raw_writel(tmp, pll->con_reg);
211 /* wait_lock_time */
212 do {
213 cpu_relax();
214 tmp = __raw_readl(pll->con_reg);
215 } while (!(tmp & (PLL35XX_LOCK_STAT_MASK
216 << PLL35XX_LOCK_STAT_SHIFT)));
217 return 0;
220 static const struct clk_ops samsung_pll35xx_clk_ops = {
221 .recalc_rate = samsung_pll35xx_recalc_rate,
222 .round_rate = samsung_pll_round_rate,
223 .set_rate = samsung_pll35xx_set_rate,
226 static const struct clk_ops samsung_pll35xx_clk_min_ops = {
227 .recalc_rate = samsung_pll35xx_recalc_rate,
231 * PLL36xx Clock Type
233 /* Maximum lock time can be 3000 * PDIV cycles */
234 #define PLL36XX_LOCK_FACTOR (3000)
236 #define PLL36XX_KDIV_MASK (0xFFFF)
237 #define PLL36XX_MDIV_MASK (0x1FF)
238 #define PLL36XX_PDIV_MASK (0x3F)
239 #define PLL36XX_SDIV_MASK (0x7)
240 #define PLL36XX_MDIV_SHIFT (16)
241 #define PLL36XX_PDIV_SHIFT (8)
242 #define PLL36XX_SDIV_SHIFT (0)
243 #define PLL36XX_KDIV_SHIFT (0)
244 #define PLL36XX_LOCK_STAT_SHIFT (29)
246 static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
247 unsigned long parent_rate)
249 struct samsung_clk_pll *pll = to_clk_pll(hw);
250 u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
251 s16 kdiv;
252 u64 fvco = parent_rate;
254 pll_con0 = __raw_readl(pll->con_reg);
255 pll_con1 = __raw_readl(pll->con_reg + 4);
256 mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
257 pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
258 sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
259 kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK);
261 fvco *= (mdiv << 16) + kdiv;
262 do_div(fvco, (pdiv << sdiv));
263 fvco >>= 16;
265 return (unsigned long)fvco;
268 static inline bool samsung_pll36xx_mpk_change(
269 const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1)
271 u32 old_mdiv, old_pdiv, old_kdiv;
273 old_mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
274 old_pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
275 old_kdiv = (pll_con1 >> PLL36XX_KDIV_SHIFT) & PLL36XX_KDIV_MASK;
277 return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
278 rate->kdiv != old_kdiv);
281 static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
282 unsigned long parent_rate)
284 struct samsung_clk_pll *pll = to_clk_pll(hw);
285 u32 tmp, pll_con0, pll_con1;
286 const struct samsung_pll_rate_table *rate;
288 rate = samsung_get_pll_settings(pll, drate);
289 if (!rate) {
290 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
291 drate, __clk_get_name(hw->clk));
292 return -EINVAL;
295 pll_con0 = __raw_readl(pll->con_reg);
296 pll_con1 = __raw_readl(pll->con_reg + 4);
298 if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) {
299 /* If only s change, change just s value only*/
300 pll_con0 &= ~(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT);
301 pll_con0 |= (rate->sdiv << PLL36XX_SDIV_SHIFT);
302 __raw_writel(pll_con0, pll->con_reg);
304 return 0;
307 /* Set PLL lock time. */
308 __raw_writel(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg);
310 /* Change PLL PMS values */
311 pll_con0 &= ~((PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT) |
312 (PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT) |
313 (PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT));
314 pll_con0 |= (rate->mdiv << PLL36XX_MDIV_SHIFT) |
315 (rate->pdiv << PLL36XX_PDIV_SHIFT) |
316 (rate->sdiv << PLL36XX_SDIV_SHIFT);
317 __raw_writel(pll_con0, pll->con_reg);
319 pll_con1 &= ~(PLL36XX_KDIV_MASK << PLL36XX_KDIV_SHIFT);
320 pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
321 __raw_writel(pll_con1, pll->con_reg + 4);
323 /* wait_lock_time */
324 do {
325 cpu_relax();
326 tmp = __raw_readl(pll->con_reg);
327 } while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT)));
329 return 0;
332 static const struct clk_ops samsung_pll36xx_clk_ops = {
333 .recalc_rate = samsung_pll36xx_recalc_rate,
334 .set_rate = samsung_pll36xx_set_rate,
335 .round_rate = samsung_pll_round_rate,
338 static const struct clk_ops samsung_pll36xx_clk_min_ops = {
339 .recalc_rate = samsung_pll36xx_recalc_rate,
343 * PLL45xx Clock Type
345 #define PLL4502_LOCK_FACTOR 400
346 #define PLL4508_LOCK_FACTOR 240
348 #define PLL45XX_MDIV_MASK (0x3FF)
349 #define PLL45XX_PDIV_MASK (0x3F)
350 #define PLL45XX_SDIV_MASK (0x7)
351 #define PLL45XX_AFC_MASK (0x1F)
352 #define PLL45XX_MDIV_SHIFT (16)
353 #define PLL45XX_PDIV_SHIFT (8)
354 #define PLL45XX_SDIV_SHIFT (0)
355 #define PLL45XX_AFC_SHIFT (0)
357 #define PLL45XX_ENABLE BIT(31)
358 #define PLL45XX_LOCKED BIT(29)
360 static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
361 unsigned long parent_rate)
363 struct samsung_clk_pll *pll = to_clk_pll(hw);
364 u32 mdiv, pdiv, sdiv, pll_con;
365 u64 fvco = parent_rate;
367 pll_con = __raw_readl(pll->con_reg);
368 mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
369 pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
370 sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
372 if (pll->type == pll_4508)
373 sdiv = sdiv - 1;
375 fvco *= mdiv;
376 do_div(fvco, (pdiv << sdiv));
378 return (unsigned long)fvco;
381 static bool samsung_pll45xx_mp_change(u32 pll_con0, u32 pll_con1,
382 const struct samsung_pll_rate_table *rate)
384 u32 old_mdiv, old_pdiv, old_afc;
386 old_mdiv = (pll_con0 >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
387 old_pdiv = (pll_con0 >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
388 old_afc = (pll_con1 >> PLL45XX_AFC_SHIFT) & PLL45XX_AFC_MASK;
390 return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
391 || old_afc != rate->afc);
394 static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
395 unsigned long prate)
397 struct samsung_clk_pll *pll = to_clk_pll(hw);
398 const struct samsung_pll_rate_table *rate;
399 u32 con0, con1;
400 ktime_t start;
402 /* Get required rate settings from table */
403 rate = samsung_get_pll_settings(pll, drate);
404 if (!rate) {
405 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
406 drate, __clk_get_name(hw->clk));
407 return -EINVAL;
410 con0 = __raw_readl(pll->con_reg);
411 con1 = __raw_readl(pll->con_reg + 0x4);
413 if (!(samsung_pll45xx_mp_change(con0, con1, rate))) {
414 /* If only s change, change just s value only*/
415 con0 &= ~(PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT);
416 con0 |= rate->sdiv << PLL45XX_SDIV_SHIFT;
417 __raw_writel(con0, pll->con_reg);
419 return 0;
422 /* Set PLL PMS values. */
423 con0 &= ~((PLL45XX_MDIV_MASK << PLL45XX_MDIV_SHIFT) |
424 (PLL45XX_PDIV_MASK << PLL45XX_PDIV_SHIFT) |
425 (PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT));
426 con0 |= (rate->mdiv << PLL45XX_MDIV_SHIFT) |
427 (rate->pdiv << PLL45XX_PDIV_SHIFT) |
428 (rate->sdiv << PLL45XX_SDIV_SHIFT);
430 /* Set PLL AFC value. */
431 con1 = __raw_readl(pll->con_reg + 0x4);
432 con1 &= ~(PLL45XX_AFC_MASK << PLL45XX_AFC_SHIFT);
433 con1 |= (rate->afc << PLL45XX_AFC_SHIFT);
435 /* Set PLL lock time. */
436 switch (pll->type) {
437 case pll_4502:
438 __raw_writel(rate->pdiv * PLL4502_LOCK_FACTOR, pll->lock_reg);
439 break;
440 case pll_4508:
441 __raw_writel(rate->pdiv * PLL4508_LOCK_FACTOR, pll->lock_reg);
442 break;
443 default:
444 break;
447 /* Set new configuration. */
448 __raw_writel(con1, pll->con_reg + 0x4);
449 __raw_writel(con0, pll->con_reg);
451 /* Wait for locking. */
452 start = ktime_get();
453 while (!(__raw_readl(pll->con_reg) & PLL45XX_LOCKED)) {
454 ktime_t delta = ktime_sub(ktime_get(), start);
456 if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
457 pr_err("%s: could not lock PLL %s\n",
458 __func__, __clk_get_name(hw->clk));
459 return -EFAULT;
462 cpu_relax();
465 return 0;
468 static const struct clk_ops samsung_pll45xx_clk_ops = {
469 .recalc_rate = samsung_pll45xx_recalc_rate,
470 .round_rate = samsung_pll_round_rate,
471 .set_rate = samsung_pll45xx_set_rate,
474 static const struct clk_ops samsung_pll45xx_clk_min_ops = {
475 .recalc_rate = samsung_pll45xx_recalc_rate,
479 * PLL46xx Clock Type
481 #define PLL46XX_LOCK_FACTOR 3000
483 #define PLL46XX_VSEL_MASK (1)
484 #define PLL46XX_MDIV_MASK (0x1FF)
485 #define PLL1460X_MDIV_MASK (0x3FF)
487 #define PLL46XX_PDIV_MASK (0x3F)
488 #define PLL46XX_SDIV_MASK (0x7)
489 #define PLL46XX_VSEL_SHIFT (27)
490 #define PLL46XX_MDIV_SHIFT (16)
491 #define PLL46XX_PDIV_SHIFT (8)
492 #define PLL46XX_SDIV_SHIFT (0)
494 #define PLL46XX_KDIV_MASK (0xFFFF)
495 #define PLL4650C_KDIV_MASK (0xFFF)
496 #define PLL46XX_KDIV_SHIFT (0)
497 #define PLL46XX_MFR_MASK (0x3F)
498 #define PLL46XX_MRR_MASK (0x1F)
499 #define PLL46XX_KDIV_SHIFT (0)
500 #define PLL46XX_MFR_SHIFT (16)
501 #define PLL46XX_MRR_SHIFT (24)
503 #define PLL46XX_ENABLE BIT(31)
504 #define PLL46XX_LOCKED BIT(29)
505 #define PLL46XX_VSEL BIT(27)
507 static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
508 unsigned long parent_rate)
510 struct samsung_clk_pll *pll = to_clk_pll(hw);
511 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
512 u64 fvco = parent_rate;
514 pll_con0 = __raw_readl(pll->con_reg);
515 pll_con1 = __raw_readl(pll->con_reg + 4);
516 mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & ((pll->type == pll_1460x) ?
517 PLL1460X_MDIV_MASK : PLL46XX_MDIV_MASK);
518 pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
519 sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
520 kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
521 pll_con1 & PLL46XX_KDIV_MASK;
523 shift = ((pll->type == pll_4600) || (pll->type == pll_1460x)) ? 16 : 10;
525 fvco *= (mdiv << shift) + kdiv;
526 do_div(fvco, (pdiv << sdiv));
527 fvco >>= shift;
529 return (unsigned long)fvco;
532 static bool samsung_pll46xx_mpk_change(u32 pll_con0, u32 pll_con1,
533 const struct samsung_pll_rate_table *rate)
535 u32 old_mdiv, old_pdiv, old_kdiv;
537 old_mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
538 old_pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
539 old_kdiv = (pll_con1 >> PLL46XX_KDIV_SHIFT) & PLL46XX_KDIV_MASK;
541 return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
542 || old_kdiv != rate->kdiv);
545 static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
546 unsigned long prate)
548 struct samsung_clk_pll *pll = to_clk_pll(hw);
549 const struct samsung_pll_rate_table *rate;
550 u32 con0, con1, lock;
551 ktime_t start;
553 /* Get required rate settings from table */
554 rate = samsung_get_pll_settings(pll, drate);
555 if (!rate) {
556 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
557 drate, __clk_get_name(hw->clk));
558 return -EINVAL;
561 con0 = __raw_readl(pll->con_reg);
562 con1 = __raw_readl(pll->con_reg + 0x4);
564 if (!(samsung_pll46xx_mpk_change(con0, con1, rate))) {
565 /* If only s change, change just s value only*/
566 con0 &= ~(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
567 con0 |= rate->sdiv << PLL46XX_SDIV_SHIFT;
568 __raw_writel(con0, pll->con_reg);
570 return 0;
573 /* Set PLL lock time. */
574 lock = rate->pdiv * PLL46XX_LOCK_FACTOR;
575 if (lock > 0xffff)
576 /* Maximum lock time bitfield is 16-bit. */
577 lock = 0xffff;
579 /* Set PLL PMS and VSEL values. */
580 if (pll->type == pll_1460x) {
581 con0 &= ~((PLL1460X_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
582 (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
583 (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT));
584 } else {
585 con0 &= ~((PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
586 (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
587 (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT) |
588 (PLL46XX_VSEL_MASK << PLL46XX_VSEL_SHIFT));
589 con0 |= rate->vsel << PLL46XX_VSEL_SHIFT;
592 con0 |= (rate->mdiv << PLL46XX_MDIV_SHIFT) |
593 (rate->pdiv << PLL46XX_PDIV_SHIFT) |
594 (rate->sdiv << PLL46XX_SDIV_SHIFT);
596 /* Set PLL K, MFR and MRR values. */
597 con1 = __raw_readl(pll->con_reg + 0x4);
598 con1 &= ~((PLL46XX_KDIV_MASK << PLL46XX_KDIV_SHIFT) |
599 (PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT) |
600 (PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT));
601 con1 |= (rate->kdiv << PLL46XX_KDIV_SHIFT) |
602 (rate->mfr << PLL46XX_MFR_SHIFT) |
603 (rate->mrr << PLL46XX_MRR_SHIFT);
605 /* Write configuration to PLL */
606 __raw_writel(lock, pll->lock_reg);
607 __raw_writel(con0, pll->con_reg);
608 __raw_writel(con1, pll->con_reg + 0x4);
610 /* Wait for locking. */
611 start = ktime_get();
612 while (!(__raw_readl(pll->con_reg) & PLL46XX_LOCKED)) {
613 ktime_t delta = ktime_sub(ktime_get(), start);
615 if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
616 pr_err("%s: could not lock PLL %s\n",
617 __func__, __clk_get_name(hw->clk));
618 return -EFAULT;
621 cpu_relax();
624 return 0;
627 static const struct clk_ops samsung_pll46xx_clk_ops = {
628 .recalc_rate = samsung_pll46xx_recalc_rate,
629 .round_rate = samsung_pll_round_rate,
630 .set_rate = samsung_pll46xx_set_rate,
633 static const struct clk_ops samsung_pll46xx_clk_min_ops = {
634 .recalc_rate = samsung_pll46xx_recalc_rate,
638 * PLL6552 Clock Type
641 #define PLL6552_MDIV_MASK 0x3ff
642 #define PLL6552_PDIV_MASK 0x3f
643 #define PLL6552_SDIV_MASK 0x7
644 #define PLL6552_MDIV_SHIFT 16
645 #define PLL6552_MDIV_SHIFT_2416 14
646 #define PLL6552_PDIV_SHIFT 8
647 #define PLL6552_PDIV_SHIFT_2416 5
648 #define PLL6552_SDIV_SHIFT 0
650 static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
651 unsigned long parent_rate)
653 struct samsung_clk_pll *pll = to_clk_pll(hw);
654 u32 mdiv, pdiv, sdiv, pll_con;
655 u64 fvco = parent_rate;
657 pll_con = __raw_readl(pll->con_reg);
658 if (pll->type == pll_6552_s3c2416) {
659 mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK;
660 pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK;
661 } else {
662 mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
663 pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
665 sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;
667 fvco *= mdiv;
668 do_div(fvco, (pdiv << sdiv));
670 return (unsigned long)fvco;
673 static const struct clk_ops samsung_pll6552_clk_ops = {
674 .recalc_rate = samsung_pll6552_recalc_rate,
678 * PLL6553 Clock Type
681 #define PLL6553_MDIV_MASK 0xff
682 #define PLL6553_PDIV_MASK 0x3f
683 #define PLL6553_SDIV_MASK 0x7
684 #define PLL6553_KDIV_MASK 0xffff
685 #define PLL6553_MDIV_SHIFT 16
686 #define PLL6553_PDIV_SHIFT 8
687 #define PLL6553_SDIV_SHIFT 0
688 #define PLL6553_KDIV_SHIFT 0
690 static unsigned long samsung_pll6553_recalc_rate(struct clk_hw *hw,
691 unsigned long parent_rate)
693 struct samsung_clk_pll *pll = to_clk_pll(hw);
694 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
695 u64 fvco = parent_rate;
697 pll_con0 = __raw_readl(pll->con_reg);
698 pll_con1 = __raw_readl(pll->con_reg + 0x4);
699 mdiv = (pll_con0 >> PLL6553_MDIV_SHIFT) & PLL6553_MDIV_MASK;
700 pdiv = (pll_con0 >> PLL6553_PDIV_SHIFT) & PLL6553_PDIV_MASK;
701 sdiv = (pll_con0 >> PLL6553_SDIV_SHIFT) & PLL6553_SDIV_MASK;
702 kdiv = (pll_con1 >> PLL6553_KDIV_SHIFT) & PLL6553_KDIV_MASK;
704 fvco *= (mdiv << 16) + kdiv;
705 do_div(fvco, (pdiv << sdiv));
706 fvco >>= 16;
708 return (unsigned long)fvco;
711 static const struct clk_ops samsung_pll6553_clk_ops = {
712 .recalc_rate = samsung_pll6553_recalc_rate,
716 * PLL Clock Type of S3C24XX before S3C2443
719 #define PLLS3C2410_MDIV_MASK (0xff)
720 #define PLLS3C2410_PDIV_MASK (0x1f)
721 #define PLLS3C2410_SDIV_MASK (0x3)
722 #define PLLS3C2410_MDIV_SHIFT (12)
723 #define PLLS3C2410_PDIV_SHIFT (4)
724 #define PLLS3C2410_SDIV_SHIFT (0)
726 #define PLLS3C2410_ENABLE_REG_OFFSET 0x10
728 static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw,
729 unsigned long parent_rate)
731 struct samsung_clk_pll *pll = to_clk_pll(hw);
732 u32 pll_con, mdiv, pdiv, sdiv;
733 u64 fvco = parent_rate;
735 pll_con = __raw_readl(pll->con_reg);
736 mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
737 pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
738 sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
740 fvco *= (mdiv + 8);
741 do_div(fvco, (pdiv + 2) << sdiv);
743 return (unsigned int)fvco;
746 static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw,
747 unsigned long parent_rate)
749 struct samsung_clk_pll *pll = to_clk_pll(hw);
750 u32 pll_con, mdiv, pdiv, sdiv;
751 u64 fvco = parent_rate;
753 pll_con = __raw_readl(pll->con_reg);
754 mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
755 pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
756 sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
758 fvco *= (2 * (mdiv + 8));
759 do_div(fvco, (pdiv + 2) << sdiv);
761 return (unsigned int)fvco;
764 static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate,
765 unsigned long prate)
767 struct samsung_clk_pll *pll = to_clk_pll(hw);
768 const struct samsung_pll_rate_table *rate;
769 u32 tmp;
771 /* Get required rate settings from table */
772 rate = samsung_get_pll_settings(pll, drate);
773 if (!rate) {
774 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
775 drate, __clk_get_name(hw->clk));
776 return -EINVAL;
779 tmp = __raw_readl(pll->con_reg);
781 /* Change PLL PMS values */
782 tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) |
783 (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) |
784 (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT));
785 tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) |
786 (rate->pdiv << PLLS3C2410_PDIV_SHIFT) |
787 (rate->sdiv << PLLS3C2410_SDIV_SHIFT);
788 __raw_writel(tmp, pll->con_reg);
790 /* Time to settle according to the manual */
791 udelay(300);
793 return 0;
796 static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable)
798 struct samsung_clk_pll *pll = to_clk_pll(hw);
799 u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
800 u32 pll_en_orig = pll_en;
802 if (enable)
803 pll_en &= ~BIT(bit);
804 else
805 pll_en |= BIT(bit);
807 __raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
809 /* if we started the UPLL, then allow to settle */
810 if (enable && (pll_en_orig & BIT(bit)))
811 udelay(300);
813 return 0;
816 static int samsung_s3c2410_mpll_enable(struct clk_hw *hw)
818 return samsung_s3c2410_pll_enable(hw, 5, true);
821 static void samsung_s3c2410_mpll_disable(struct clk_hw *hw)
823 samsung_s3c2410_pll_enable(hw, 5, false);
826 static int samsung_s3c2410_upll_enable(struct clk_hw *hw)
828 return samsung_s3c2410_pll_enable(hw, 7, true);
831 static void samsung_s3c2410_upll_disable(struct clk_hw *hw)
833 samsung_s3c2410_pll_enable(hw, 7, false);
836 static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = {
837 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
838 .enable = samsung_s3c2410_mpll_enable,
839 .disable = samsung_s3c2410_mpll_disable,
842 static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = {
843 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
844 .enable = samsung_s3c2410_upll_enable,
845 .disable = samsung_s3c2410_upll_disable,
848 static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = {
849 .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
850 .enable = samsung_s3c2410_mpll_enable,
851 .disable = samsung_s3c2410_mpll_disable,
854 static const struct clk_ops samsung_s3c2410_mpll_clk_ops = {
855 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
856 .enable = samsung_s3c2410_mpll_enable,
857 .disable = samsung_s3c2410_mpll_disable,
858 .round_rate = samsung_pll_round_rate,
859 .set_rate = samsung_s3c2410_pll_set_rate,
862 static const struct clk_ops samsung_s3c2410_upll_clk_ops = {
863 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
864 .enable = samsung_s3c2410_upll_enable,
865 .disable = samsung_s3c2410_upll_disable,
866 .round_rate = samsung_pll_round_rate,
867 .set_rate = samsung_s3c2410_pll_set_rate,
870 static const struct clk_ops samsung_s3c2440_mpll_clk_ops = {
871 .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
872 .enable = samsung_s3c2410_mpll_enable,
873 .disable = samsung_s3c2410_mpll_disable,
874 .round_rate = samsung_pll_round_rate,
875 .set_rate = samsung_s3c2410_pll_set_rate,
879 * PLL2550x Clock Type
882 #define PLL2550X_R_MASK (0x1)
883 #define PLL2550X_P_MASK (0x3F)
884 #define PLL2550X_M_MASK (0x3FF)
885 #define PLL2550X_S_MASK (0x7)
886 #define PLL2550X_R_SHIFT (20)
887 #define PLL2550X_P_SHIFT (14)
888 #define PLL2550X_M_SHIFT (4)
889 #define PLL2550X_S_SHIFT (0)
891 struct samsung_clk_pll2550x {
892 struct clk_hw hw;
893 const void __iomem *reg_base;
894 unsigned long offset;
897 #define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
899 static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
900 unsigned long parent_rate)
902 struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
903 u32 r, p, m, s, pll_stat;
904 u64 fvco = parent_rate;
906 pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
907 r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
908 if (!r)
909 return 0;
910 p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
911 m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
912 s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
914 fvco *= m;
915 do_div(fvco, (p << s));
917 return (unsigned long)fvco;
920 static const struct clk_ops samsung_pll2550x_clk_ops = {
921 .recalc_rate = samsung_pll2550x_recalc_rate,
924 struct clk * __init samsung_clk_register_pll2550x(const char *name,
925 const char *pname, const void __iomem *reg_base,
926 const unsigned long offset)
928 struct samsung_clk_pll2550x *pll;
929 struct clk *clk;
930 struct clk_init_data init;
932 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
933 if (!pll) {
934 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
935 return NULL;
938 init.name = name;
939 init.ops = &samsung_pll2550x_clk_ops;
940 init.flags = CLK_GET_RATE_NOCACHE;
941 init.parent_names = &pname;
942 init.num_parents = 1;
944 pll->hw.init = &init;
945 pll->reg_base = reg_base;
946 pll->offset = offset;
948 clk = clk_register(NULL, &pll->hw);
949 if (IS_ERR(clk)) {
950 pr_err("%s: failed to register pll clock %s\n", __func__,
951 name);
952 kfree(pll);
955 if (clk_register_clkdev(clk, name, NULL))
956 pr_err("%s: failed to register lookup for %s", __func__, name);
958 return clk;
962 * PLL2550xx Clock Type
965 /* Maximum lock time can be 270 * PDIV cycles */
966 #define PLL2550XX_LOCK_FACTOR 270
968 #define PLL2550XX_M_MASK 0x3FF
969 #define PLL2550XX_P_MASK 0x3F
970 #define PLL2550XX_S_MASK 0x7
971 #define PLL2550XX_LOCK_STAT_MASK 0x1
972 #define PLL2550XX_M_SHIFT 9
973 #define PLL2550XX_P_SHIFT 3
974 #define PLL2550XX_S_SHIFT 0
975 #define PLL2550XX_LOCK_STAT_SHIFT 21
977 static unsigned long samsung_pll2550xx_recalc_rate(struct clk_hw *hw,
978 unsigned long parent_rate)
980 struct samsung_clk_pll *pll = to_clk_pll(hw);
981 u32 mdiv, pdiv, sdiv, pll_con;
982 u64 fvco = parent_rate;
984 pll_con = __raw_readl(pll->con_reg);
985 mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
986 pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
987 sdiv = (pll_con >> PLL2550XX_S_SHIFT) & PLL2550XX_S_MASK;
989 fvco *= mdiv;
990 do_div(fvco, (pdiv << sdiv));
992 return (unsigned long)fvco;
995 static inline bool samsung_pll2550xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con)
997 u32 old_mdiv, old_pdiv;
999 old_mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
1000 old_pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
1002 return mdiv != old_mdiv || pdiv != old_pdiv;
1005 static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
1006 unsigned long prate)
1008 struct samsung_clk_pll *pll = to_clk_pll(hw);
1009 const struct samsung_pll_rate_table *rate;
1010 u32 tmp;
1012 /* Get required rate settings from table */
1013 rate = samsung_get_pll_settings(pll, drate);
1014 if (!rate) {
1015 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1016 drate, __clk_get_name(hw->clk));
1017 return -EINVAL;
1020 tmp = __raw_readl(pll->con_reg);
1022 if (!(samsung_pll2550xx_mp_change(rate->mdiv, rate->pdiv, tmp))) {
1023 /* If only s change, change just s value only*/
1024 tmp &= ~(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT);
1025 tmp |= rate->sdiv << PLL2550XX_S_SHIFT;
1026 __raw_writel(tmp, pll->con_reg);
1028 return 0;
1031 /* Set PLL lock time. */
1032 __raw_writel(rate->pdiv * PLL2550XX_LOCK_FACTOR, pll->lock_reg);
1034 /* Change PLL PMS values */
1035 tmp &= ~((PLL2550XX_M_MASK << PLL2550XX_M_SHIFT) |
1036 (PLL2550XX_P_MASK << PLL2550XX_P_SHIFT) |
1037 (PLL2550XX_S_MASK << PLL2550XX_S_SHIFT));
1038 tmp |= (rate->mdiv << PLL2550XX_M_SHIFT) |
1039 (rate->pdiv << PLL2550XX_P_SHIFT) |
1040 (rate->sdiv << PLL2550XX_S_SHIFT);
1041 __raw_writel(tmp, pll->con_reg);
1043 /* wait_lock_time */
1044 do {
1045 cpu_relax();
1046 tmp = __raw_readl(pll->con_reg);
1047 } while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
1048 << PLL2550XX_LOCK_STAT_SHIFT)));
1050 return 0;
1053 static const struct clk_ops samsung_pll2550xx_clk_ops = {
1054 .recalc_rate = samsung_pll2550xx_recalc_rate,
1055 .round_rate = samsung_pll_round_rate,
1056 .set_rate = samsung_pll2550xx_set_rate,
1059 static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
1060 .recalc_rate = samsung_pll2550xx_recalc_rate,
1064 * PLL2650XX Clock Type
1067 /* Maximum lock time can be 3000 * PDIV cycles */
1068 #define PLL2650XX_LOCK_FACTOR 3000
1070 #define PLL2650XX_MDIV_SHIFT 9
1071 #define PLL2650XX_PDIV_SHIFT 3
1072 #define PLL2650XX_SDIV_SHIFT 0
1073 #define PLL2650XX_KDIV_SHIFT 0
1074 #define PLL2650XX_MDIV_MASK 0x1ff
1075 #define PLL2650XX_PDIV_MASK 0x3f
1076 #define PLL2650XX_SDIV_MASK 0x7
1077 #define PLL2650XX_KDIV_MASK 0xffff
1078 #define PLL2650XX_PLL_ENABLE_SHIFT 23
1079 #define PLL2650XX_PLL_LOCKTIME_SHIFT 21
1080 #define PLL2650XX_PLL_FOUTMASK_SHIFT 31
1082 static unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw,
1083 unsigned long parent_rate)
1085 struct samsung_clk_pll *pll = to_clk_pll(hw);
1086 u32 mdiv, pdiv, sdiv, pll_con0, pll_con2;
1087 s16 kdiv;
1088 u64 fvco = parent_rate;
1090 pll_con0 = __raw_readl(pll->con_reg);
1091 pll_con2 = __raw_readl(pll->con_reg + 8);
1092 mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK;
1093 pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK;
1094 sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK;
1095 kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK);
1097 fvco *= (mdiv << 16) + kdiv;
1098 do_div(fvco, (pdiv << sdiv));
1099 fvco >>= 16;
1101 return (unsigned long)fvco;
1104 static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
1105 unsigned long parent_rate)
1107 struct samsung_clk_pll *pll = to_clk_pll(hw);
1108 u32 tmp, pll_con0, pll_con2;
1109 const struct samsung_pll_rate_table *rate;
1111 rate = samsung_get_pll_settings(pll, drate);
1112 if (!rate) {
1113 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1114 drate, __clk_get_name(hw->clk));
1115 return -EINVAL;
1118 pll_con0 = __raw_readl(pll->con_reg);
1119 pll_con2 = __raw_readl(pll->con_reg + 8);
1121 /* Change PLL PMS values */
1122 pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT |
1123 PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT |
1124 PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT);
1125 pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT;
1126 pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT;
1127 pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT;
1128 pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT;
1129 pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT;
1131 pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT);
1132 pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK)
1133 << PLL2650XX_KDIV_SHIFT;
1135 /* Set PLL lock time. */
1136 __raw_writel(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg);
1138 __raw_writel(pll_con0, pll->con_reg);
1139 __raw_writel(pll_con2, pll->con_reg + 8);
1141 do {
1142 tmp = __raw_readl(pll->con_reg);
1143 } while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
1145 return 0;
1148 static const struct clk_ops samsung_pll2650xx_clk_ops = {
1149 .recalc_rate = samsung_pll2650xx_recalc_rate,
1150 .set_rate = samsung_pll2650xx_set_rate,
1151 .round_rate = samsung_pll_round_rate,
1154 static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
1155 .recalc_rate = samsung_pll2650xx_recalc_rate,
1158 static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1159 struct samsung_pll_clock *pll_clk,
1160 void __iomem *base)
1162 struct samsung_clk_pll *pll;
1163 struct clk *clk;
1164 struct clk_init_data init;
1165 int ret, len;
1167 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
1168 if (!pll) {
1169 pr_err("%s: could not allocate pll clk %s\n",
1170 __func__, pll_clk->name);
1171 return;
1174 init.name = pll_clk->name;
1175 init.flags = pll_clk->flags;
1176 init.parent_names = &pll_clk->parent_name;
1177 init.num_parents = 1;
1179 if (pll_clk->rate_table) {
1180 /* find count of rates in rate_table */
1181 for (len = 0; pll_clk->rate_table[len].rate != 0; )
1182 len++;
1184 pll->rate_count = len;
1185 pll->rate_table = kmemdup(pll_clk->rate_table,
1186 pll->rate_count *
1187 sizeof(struct samsung_pll_rate_table),
1188 GFP_KERNEL);
1189 WARN(!pll->rate_table,
1190 "%s: could not allocate rate table for %s\n",
1191 __func__, pll_clk->name);
1194 switch (pll_clk->type) {
1195 case pll_2126:
1196 init.ops = &samsung_pll2126_clk_ops;
1197 break;
1198 case pll_3000:
1199 init.ops = &samsung_pll3000_clk_ops;
1200 break;
1201 /* clk_ops for 35xx and 2550 are similar */
1202 case pll_35xx:
1203 case pll_2550:
1204 case pll_1450x:
1205 case pll_1451x:
1206 case pll_1452x:
1207 if (!pll->rate_table)
1208 init.ops = &samsung_pll35xx_clk_min_ops;
1209 else
1210 init.ops = &samsung_pll35xx_clk_ops;
1211 break;
1212 case pll_4500:
1213 init.ops = &samsung_pll45xx_clk_min_ops;
1214 break;
1215 case pll_4502:
1216 case pll_4508:
1217 if (!pll->rate_table)
1218 init.ops = &samsung_pll45xx_clk_min_ops;
1219 else
1220 init.ops = &samsung_pll45xx_clk_ops;
1221 break;
1222 /* clk_ops for 36xx and 2650 are similar */
1223 case pll_36xx:
1224 case pll_2650:
1225 if (!pll->rate_table)
1226 init.ops = &samsung_pll36xx_clk_min_ops;
1227 else
1228 init.ops = &samsung_pll36xx_clk_ops;
1229 break;
1230 case pll_6552:
1231 case pll_6552_s3c2416:
1232 init.ops = &samsung_pll6552_clk_ops;
1233 break;
1234 case pll_6553:
1235 init.ops = &samsung_pll6553_clk_ops;
1236 break;
1237 case pll_4600:
1238 case pll_4650:
1239 case pll_4650c:
1240 case pll_1460x:
1241 if (!pll->rate_table)
1242 init.ops = &samsung_pll46xx_clk_min_ops;
1243 else
1244 init.ops = &samsung_pll46xx_clk_ops;
1245 break;
1246 case pll_s3c2410_mpll:
1247 if (!pll->rate_table)
1248 init.ops = &samsung_s3c2410_mpll_clk_min_ops;
1249 else
1250 init.ops = &samsung_s3c2410_mpll_clk_ops;
1251 break;
1252 case pll_s3c2410_upll:
1253 if (!pll->rate_table)
1254 init.ops = &samsung_s3c2410_upll_clk_min_ops;
1255 else
1256 init.ops = &samsung_s3c2410_upll_clk_ops;
1257 break;
1258 case pll_s3c2440_mpll:
1259 if (!pll->rate_table)
1260 init.ops = &samsung_s3c2440_mpll_clk_min_ops;
1261 else
1262 init.ops = &samsung_s3c2440_mpll_clk_ops;
1263 break;
1264 case pll_2550xx:
1265 if (!pll->rate_table)
1266 init.ops = &samsung_pll2550xx_clk_min_ops;
1267 else
1268 init.ops = &samsung_pll2550xx_clk_ops;
1269 break;
1270 case pll_2650xx:
1271 if (!pll->rate_table)
1272 init.ops = &samsung_pll2650xx_clk_min_ops;
1273 else
1274 init.ops = &samsung_pll2650xx_clk_ops;
1275 break;
1276 default:
1277 pr_warn("%s: Unknown pll type for pll clk %s\n",
1278 __func__, pll_clk->name);
1281 pll->hw.init = &init;
1282 pll->type = pll_clk->type;
1283 pll->lock_reg = base + pll_clk->lock_offset;
1284 pll->con_reg = base + pll_clk->con_offset;
1286 clk = clk_register(NULL, &pll->hw);
1287 if (IS_ERR(clk)) {
1288 pr_err("%s: failed to register pll clock %s : %ld\n",
1289 __func__, pll_clk->name, PTR_ERR(clk));
1290 kfree(pll);
1291 return;
1294 samsung_clk_add_lookup(ctx, clk, pll_clk->id);
1296 if (!pll_clk->alias)
1297 return;
1299 ret = clk_register_clkdev(clk, pll_clk->alias, pll_clk->dev_name);
1300 if (ret)
1301 pr_err("%s: failed to register lookup for %s : %d",
1302 __func__, pll_clk->name, ret);
1305 void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1306 struct samsung_pll_clock *pll_list,
1307 unsigned int nr_pll, void __iomem *base)
1309 int cnt;
1311 for (cnt = 0; cnt < nr_pll; cnt++)
1312 _samsung_clk_register_pll(ctx, &pll_list[cnt], base);