[go: nahoru, domu]

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 <linux/hrtimer.h>
14#include <linux/delay.h>
15#include "clk.h"
16#include "clk-pll.h"
17
18#define PLL_TIMEOUT_MS		10
19
20struct 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;
27};
28
29#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
30
31static const struct samsung_pll_rate_table *samsung_get_pll_settings(
32				struct samsung_clk_pll *pll, unsigned long rate)
33{
34	const struct samsung_pll_rate_table  *rate_table = pll->rate_table;
35	int i;
36
37	for (i = 0; i < pll->rate_count; i++) {
38		if (rate == rate_table[i].rate)
39			return &rate_table[i];
40	}
41
42	return NULL;
43}
44
45static long samsung_pll_round_rate(struct clk_hw *hw,
46			unsigned long drate, unsigned long *prate)
47{
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;
51
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;
56	}
57
58	/* return minimum supported value */
59	return rate_table[i - 1].rate;
60}
61
62/*
63 * PLL2126 Clock Type
64 */
65
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)
72
73static unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw,
74				unsigned long parent_rate)
75{
76	struct samsung_clk_pll *pll = to_clk_pll(hw);
77	u32 pll_con, mdiv, pdiv, sdiv;
78	u64 fvco = parent_rate;
79
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;
84
85	fvco *= (mdiv + 8);
86	do_div(fvco, (pdiv + 2) << sdiv);
87
88	return (unsigned long)fvco;
89}
90
91static const struct clk_ops samsung_pll2126_clk_ops = {
92	.recalc_rate = samsung_pll2126_recalc_rate,
93};
94
95/*
96 * PLL3000 Clock Type
97 */
98
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)
105
106static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw,
107				unsigned long parent_rate)
108{
109	struct samsung_clk_pll *pll = to_clk_pll(hw);
110	u32 pll_con, mdiv, pdiv, sdiv;
111	u64 fvco = parent_rate;
112
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;
117
118	fvco *= (2 * (mdiv + 8));
119	do_div(fvco, pdiv << sdiv);
120
121	return (unsigned long)fvco;
122}
123
124static const struct clk_ops samsung_pll3000_clk_ops = {
125	.recalc_rate = samsung_pll3000_recalc_rate,
126};
127
128/*
129 * PLL35xx Clock Type
130 */
131/* Maximum lock time can be 270 * PDIV cycles */
132#define PLL35XX_LOCK_FACTOR	(270)
133
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)
142
143static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
144				unsigned long parent_rate)
145{
146	struct samsung_clk_pll *pll = to_clk_pll(hw);
147	u32 mdiv, pdiv, sdiv, pll_con;
148	u64 fvco = parent_rate;
149
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;
154
155	fvco *= mdiv;
156	do_div(fvco, (pdiv << sdiv));
157
158	return (unsigned long)fvco;
159}
160
161static inline bool samsung_pll35xx_mp_change(
162		const struct samsung_pll_rate_table *rate, u32 pll_con)
163{
164	u32 old_mdiv, old_pdiv;
165
166	old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
167	old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
168
169	return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv);
170}
171
172static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
173					unsigned long prate)
174{
175	struct samsung_clk_pll *pll = to_clk_pll(hw);
176	const struct samsung_pll_rate_table *rate;
177	u32 tmp;
178
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;
185	}
186
187	tmp = __raw_readl(pll->con_reg);
188
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);
194
195		return 0;
196	}
197
198	/* Set PLL lock time. */
199	__raw_writel(rate->pdiv * PLL35XX_LOCK_FACTOR,
200			pll->lock_reg);
201
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);
210
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;
218}
219
220static 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,
224};
225
226static const struct clk_ops samsung_pll35xx_clk_min_ops = {
227	.recalc_rate = samsung_pll35xx_recalc_rate,
228};
229
230/*
231 * PLL36xx Clock Type
232 */
233/* Maximum lock time can be 3000 * PDIV cycles */
234#define PLL36XX_LOCK_FACTOR    (3000)
235
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)
245
246static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
247				unsigned long parent_rate)
248{
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;
253
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);
260
261	fvco *= (mdiv << 16) + kdiv;
262	do_div(fvco, (pdiv << sdiv));
263	fvco >>= 16;
264
265	return (unsigned long)fvco;
266}
267
268static inline bool samsung_pll36xx_mpk_change(
269	const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1)
270{
271	u32 old_mdiv, old_pdiv, old_kdiv;
272
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;
276
277	return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
278		rate->kdiv != old_kdiv);
279}
280
281static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
282					unsigned long parent_rate)
283{
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;
287
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;
293	}
294
295	pll_con0 = __raw_readl(pll->con_reg);
296	pll_con1 = __raw_readl(pll->con_reg + 4);
297
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);
303
304		return 0;
305	}
306
307	/* Set PLL lock time. */
308	__raw_writel(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg);
309
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);
318
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);
322
323	/* wait_lock_time */
324	do {
325		cpu_relax();
326		tmp = __raw_readl(pll->con_reg);
327	} while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT)));
328
329	return 0;
330}
331
332static 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,
336};
337
338static const struct clk_ops samsung_pll36xx_clk_min_ops = {
339	.recalc_rate = samsung_pll36xx_recalc_rate,
340};
341
342/*
343 * PLL45xx Clock Type
344 */
345#define PLL4502_LOCK_FACTOR	400
346#define PLL4508_LOCK_FACTOR	240
347
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)
356
357#define PLL45XX_ENABLE		BIT(31)
358#define PLL45XX_LOCKED		BIT(29)
359
360static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
361				unsigned long parent_rate)
362{
363	struct samsung_clk_pll *pll = to_clk_pll(hw);
364	u32 mdiv, pdiv, sdiv, pll_con;
365	u64 fvco = parent_rate;
366
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;
371
372	if (pll->type == pll_4508)
373		sdiv = sdiv - 1;
374
375	fvco *= mdiv;
376	do_div(fvco, (pdiv << sdiv));
377
378	return (unsigned long)fvco;
379}
380
381static bool samsung_pll45xx_mp_change(u32 pll_con0, u32 pll_con1,
382				const struct samsung_pll_rate_table *rate)
383{
384	u32 old_mdiv, old_pdiv, old_afc;
385
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;
389
390	return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
391		|| old_afc != rate->afc);
392}
393
394static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
395					unsigned long prate)
396{
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;
401
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;
408	}
409
410	con0 = __raw_readl(pll->con_reg);
411	con1 = __raw_readl(pll->con_reg + 0x4);
412
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);
418
419		return 0;
420	}
421
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);
429
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);
434
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;
445	}
446
447	/* Set new configuration. */
448	__raw_writel(con1, pll->con_reg + 0x4);
449	__raw_writel(con0, pll->con_reg);
450
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);
455
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;
460		}
461
462		cpu_relax();
463	}
464
465	return 0;
466}
467
468static 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,
472};
473
474static const struct clk_ops samsung_pll45xx_clk_min_ops = {
475	.recalc_rate = samsung_pll45xx_recalc_rate,
476};
477
478/*
479 * PLL46xx Clock Type
480 */
481#define PLL46XX_LOCK_FACTOR	3000
482
483#define PLL46XX_VSEL_MASK	(1)
484#define PLL46XX_MDIV_MASK	(0x1FF)
485#define PLL46XX_PDIV_MASK	(0x3F)
486#define PLL46XX_SDIV_MASK	(0x7)
487#define PLL46XX_VSEL_SHIFT	(27)
488#define PLL46XX_MDIV_SHIFT	(16)
489#define PLL46XX_PDIV_SHIFT	(8)
490#define PLL46XX_SDIV_SHIFT	(0)
491
492#define PLL46XX_KDIV_MASK	(0xFFFF)
493#define PLL4650C_KDIV_MASK	(0xFFF)
494#define PLL46XX_KDIV_SHIFT	(0)
495#define PLL46XX_MFR_MASK	(0x3F)
496#define PLL46XX_MRR_MASK	(0x1F)
497#define PLL46XX_KDIV_SHIFT	(0)
498#define PLL46XX_MFR_SHIFT	(16)
499#define PLL46XX_MRR_SHIFT	(24)
500
501#define PLL46XX_ENABLE		BIT(31)
502#define PLL46XX_LOCKED		BIT(29)
503#define PLL46XX_VSEL		BIT(27)
504
505static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
506				unsigned long parent_rate)
507{
508	struct samsung_clk_pll *pll = to_clk_pll(hw);
509	u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
510	u64 fvco = parent_rate;
511
512	pll_con0 = __raw_readl(pll->con_reg);
513	pll_con1 = __raw_readl(pll->con_reg + 4);
514	mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
515	pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
516	sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
517	kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
518					pll_con1 & PLL46XX_KDIV_MASK;
519
520	shift = pll->type == pll_4600 ? 16 : 10;
521	fvco *= (mdiv << shift) + kdiv;
522	do_div(fvco, (pdiv << sdiv));
523	fvco >>= shift;
524
525	return (unsigned long)fvco;
526}
527
528static bool samsung_pll46xx_mpk_change(u32 pll_con0, u32 pll_con1,
529				const struct samsung_pll_rate_table *rate)
530{
531	u32 old_mdiv, old_pdiv, old_kdiv;
532
533	old_mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
534	old_pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
535	old_kdiv = (pll_con1 >> PLL46XX_KDIV_SHIFT) & PLL46XX_KDIV_MASK;
536
537	return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
538		|| old_kdiv != rate->kdiv);
539}
540
541static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
542					unsigned long prate)
543{
544	struct samsung_clk_pll *pll = to_clk_pll(hw);
545	const struct samsung_pll_rate_table *rate;
546	u32 con0, con1, lock;
547	ktime_t start;
548
549	/* Get required rate settings from table */
550	rate = samsung_get_pll_settings(pll, drate);
551	if (!rate) {
552		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
553			drate, __clk_get_name(hw->clk));
554		return -EINVAL;
555	}
556
557	con0 = __raw_readl(pll->con_reg);
558	con1 = __raw_readl(pll->con_reg + 0x4);
559
560	if (!(samsung_pll46xx_mpk_change(con0, con1, rate))) {
561		/* If only s change, change just s value only*/
562		con0 &= ~(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
563		con0 |= rate->sdiv << PLL46XX_SDIV_SHIFT;
564		__raw_writel(con0, pll->con_reg);
565
566		return 0;
567	}
568
569	/* Set PLL lock time. */
570	lock = rate->pdiv * PLL46XX_LOCK_FACTOR;
571	if (lock > 0xffff)
572		/* Maximum lock time bitfield is 16-bit. */
573		lock = 0xffff;
574
575	/* Set PLL PMS and VSEL values. */
576	con0 &= ~((PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
577			(PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
578			(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT) |
579			(PLL46XX_VSEL_MASK << PLL46XX_VSEL_SHIFT));
580	con0 |= (rate->mdiv << PLL46XX_MDIV_SHIFT) |
581			(rate->pdiv << PLL46XX_PDIV_SHIFT) |
582			(rate->sdiv << PLL46XX_SDIV_SHIFT) |
583			(rate->vsel << PLL46XX_VSEL_SHIFT);
584
585	/* Set PLL K, MFR and MRR values. */
586	con1 = __raw_readl(pll->con_reg + 0x4);
587	con1 &= ~((PLL46XX_KDIV_MASK << PLL46XX_KDIV_SHIFT) |
588			(PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT) |
589			(PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT));
590	con1 |= (rate->kdiv << PLL46XX_KDIV_SHIFT) |
591			(rate->mfr << PLL46XX_MFR_SHIFT) |
592			(rate->mrr << PLL46XX_MRR_SHIFT);
593
594	/* Write configuration to PLL */
595	__raw_writel(lock, pll->lock_reg);
596	__raw_writel(con0, pll->con_reg);
597	__raw_writel(con1, pll->con_reg + 0x4);
598
599	/* Wait for locking. */
600	start = ktime_get();
601	while (!(__raw_readl(pll->con_reg) & PLL46XX_LOCKED)) {
602		ktime_t delta = ktime_sub(ktime_get(), start);
603
604		if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
605			pr_err("%s: could not lock PLL %s\n",
606					__func__, __clk_get_name(hw->clk));
607			return -EFAULT;
608		}
609
610		cpu_relax();
611	}
612
613	return 0;
614}
615
616static const struct clk_ops samsung_pll46xx_clk_ops = {
617	.recalc_rate = samsung_pll46xx_recalc_rate,
618	.round_rate = samsung_pll_round_rate,
619	.set_rate = samsung_pll46xx_set_rate,
620};
621
622static const struct clk_ops samsung_pll46xx_clk_min_ops = {
623	.recalc_rate = samsung_pll46xx_recalc_rate,
624};
625
626/*
627 * PLL6552 Clock Type
628 */
629
630#define PLL6552_MDIV_MASK	0x3ff
631#define PLL6552_PDIV_MASK	0x3f
632#define PLL6552_SDIV_MASK	0x7
633#define PLL6552_MDIV_SHIFT	16
634#define PLL6552_MDIV_SHIFT_2416	14
635#define PLL6552_PDIV_SHIFT	8
636#define PLL6552_PDIV_SHIFT_2416	5
637#define PLL6552_SDIV_SHIFT	0
638
639static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
640						unsigned long parent_rate)
641{
642	struct samsung_clk_pll *pll = to_clk_pll(hw);
643	u32 mdiv, pdiv, sdiv, pll_con;
644	u64 fvco = parent_rate;
645
646	pll_con = __raw_readl(pll->con_reg);
647	if (pll->type == pll_6552_s3c2416) {
648		mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK;
649		pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK;
650	} else {
651		mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
652		pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
653	}
654	sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;
655
656	fvco *= mdiv;
657	do_div(fvco, (pdiv << sdiv));
658
659	return (unsigned long)fvco;
660}
661
662static const struct clk_ops samsung_pll6552_clk_ops = {
663	.recalc_rate = samsung_pll6552_recalc_rate,
664};
665
666/*
667 * PLL6553 Clock Type
668 */
669
670#define PLL6553_MDIV_MASK	0xff
671#define PLL6553_PDIV_MASK	0x3f
672#define PLL6553_SDIV_MASK	0x7
673#define PLL6553_KDIV_MASK	0xffff
674#define PLL6553_MDIV_SHIFT	16
675#define PLL6553_PDIV_SHIFT	8
676#define PLL6553_SDIV_SHIFT	0
677#define PLL6553_KDIV_SHIFT	0
678
679static unsigned long samsung_pll6553_recalc_rate(struct clk_hw *hw,
680						unsigned long parent_rate)
681{
682	struct samsung_clk_pll *pll = to_clk_pll(hw);
683	u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
684	u64 fvco = parent_rate;
685
686	pll_con0 = __raw_readl(pll->con_reg);
687	pll_con1 = __raw_readl(pll->con_reg + 0x4);
688	mdiv = (pll_con0 >> PLL6553_MDIV_SHIFT) & PLL6553_MDIV_MASK;
689	pdiv = (pll_con0 >> PLL6553_PDIV_SHIFT) & PLL6553_PDIV_MASK;
690	sdiv = (pll_con0 >> PLL6553_SDIV_SHIFT) & PLL6553_SDIV_MASK;
691	kdiv = (pll_con1 >> PLL6553_KDIV_SHIFT) & PLL6553_KDIV_MASK;
692
693	fvco *= (mdiv << 16) + kdiv;
694	do_div(fvco, (pdiv << sdiv));
695	fvco >>= 16;
696
697	return (unsigned long)fvco;
698}
699
700static const struct clk_ops samsung_pll6553_clk_ops = {
701	.recalc_rate = samsung_pll6553_recalc_rate,
702};
703
704/*
705 * PLL Clock Type of S3C24XX before S3C2443
706 */
707
708#define PLLS3C2410_MDIV_MASK		(0xff)
709#define PLLS3C2410_PDIV_MASK		(0x1f)
710#define PLLS3C2410_SDIV_MASK		(0x3)
711#define PLLS3C2410_MDIV_SHIFT		(12)
712#define PLLS3C2410_PDIV_SHIFT		(4)
713#define PLLS3C2410_SDIV_SHIFT		(0)
714
715#define PLLS3C2410_ENABLE_REG_OFFSET	0x10
716
717static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw,
718					unsigned long parent_rate)
719{
720	struct samsung_clk_pll *pll = to_clk_pll(hw);
721	u32 pll_con, mdiv, pdiv, sdiv;
722	u64 fvco = parent_rate;
723
724	pll_con = __raw_readl(pll->con_reg);
725	mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
726	pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
727	sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
728
729	fvco *= (mdiv + 8);
730	do_div(fvco, (pdiv + 2) << sdiv);
731
732	return (unsigned int)fvco;
733}
734
735static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw,
736					unsigned long parent_rate)
737{
738	struct samsung_clk_pll *pll = to_clk_pll(hw);
739	u32 pll_con, mdiv, pdiv, sdiv;
740	u64 fvco = parent_rate;
741
742	pll_con = __raw_readl(pll->con_reg);
743	mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
744	pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
745	sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
746
747	fvco *= (2 * (mdiv + 8));
748	do_div(fvco, (pdiv + 2) << sdiv);
749
750	return (unsigned int)fvco;
751}
752
753static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate,
754					unsigned long prate)
755{
756	struct samsung_clk_pll *pll = to_clk_pll(hw);
757	const struct samsung_pll_rate_table *rate;
758	u32 tmp;
759
760	/* Get required rate settings from table */
761	rate = samsung_get_pll_settings(pll, drate);
762	if (!rate) {
763		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
764			drate, __clk_get_name(hw->clk));
765		return -EINVAL;
766	}
767
768	tmp = __raw_readl(pll->con_reg);
769
770	/* Change PLL PMS values */
771	tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) |
772			(PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) |
773			(PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT));
774	tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) |
775			(rate->pdiv << PLLS3C2410_PDIV_SHIFT) |
776			(rate->sdiv << PLLS3C2410_SDIV_SHIFT);
777	__raw_writel(tmp, pll->con_reg);
778
779	/* Time to settle according to the manual */
780	udelay(300);
781
782	return 0;
783}
784
785static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable)
786{
787	struct samsung_clk_pll *pll = to_clk_pll(hw);
788	u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
789	u32 pll_en_orig = pll_en;
790
791	if (enable)
792		pll_en &= ~BIT(bit);
793	else
794		pll_en |= BIT(bit);
795
796	__raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
797
798	/* if we started the UPLL, then allow to settle */
799	if (enable && (pll_en_orig & BIT(bit)))
800		udelay(300);
801
802	return 0;
803}
804
805static int samsung_s3c2410_mpll_enable(struct clk_hw *hw)
806{
807	return samsung_s3c2410_pll_enable(hw, 5, true);
808}
809
810static void samsung_s3c2410_mpll_disable(struct clk_hw *hw)
811{
812	samsung_s3c2410_pll_enable(hw, 5, false);
813}
814
815static int samsung_s3c2410_upll_enable(struct clk_hw *hw)
816{
817	return samsung_s3c2410_pll_enable(hw, 7, true);
818}
819
820static void samsung_s3c2410_upll_disable(struct clk_hw *hw)
821{
822	samsung_s3c2410_pll_enable(hw, 7, false);
823}
824
825static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = {
826	.recalc_rate = samsung_s3c2410_pll_recalc_rate,
827	.enable = samsung_s3c2410_mpll_enable,
828	.disable = samsung_s3c2410_mpll_disable,
829};
830
831static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = {
832	.recalc_rate = samsung_s3c2410_pll_recalc_rate,
833	.enable = samsung_s3c2410_upll_enable,
834	.disable = samsung_s3c2410_upll_disable,
835};
836
837static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = {
838	.recalc_rate = samsung_s3c2440_mpll_recalc_rate,
839	.enable = samsung_s3c2410_mpll_enable,
840	.disable = samsung_s3c2410_mpll_disable,
841};
842
843static const struct clk_ops samsung_s3c2410_mpll_clk_ops = {
844	.recalc_rate = samsung_s3c2410_pll_recalc_rate,
845	.enable = samsung_s3c2410_mpll_enable,
846	.disable = samsung_s3c2410_mpll_disable,
847	.round_rate = samsung_pll_round_rate,
848	.set_rate = samsung_s3c2410_pll_set_rate,
849};
850
851static const struct clk_ops samsung_s3c2410_upll_clk_ops = {
852	.recalc_rate = samsung_s3c2410_pll_recalc_rate,
853	.enable = samsung_s3c2410_upll_enable,
854	.disable = samsung_s3c2410_upll_disable,
855	.round_rate = samsung_pll_round_rate,
856	.set_rate = samsung_s3c2410_pll_set_rate,
857};
858
859static const struct clk_ops samsung_s3c2440_mpll_clk_ops = {
860	.recalc_rate = samsung_s3c2440_mpll_recalc_rate,
861	.enable = samsung_s3c2410_mpll_enable,
862	.disable = samsung_s3c2410_mpll_disable,
863	.round_rate = samsung_pll_round_rate,
864	.set_rate = samsung_s3c2410_pll_set_rate,
865};
866
867/*
868 * PLL2550x Clock Type
869 */
870
871#define PLL2550X_R_MASK       (0x1)
872#define PLL2550X_P_MASK       (0x3F)
873#define PLL2550X_M_MASK       (0x3FF)
874#define PLL2550X_S_MASK       (0x7)
875#define PLL2550X_R_SHIFT      (20)
876#define PLL2550X_P_SHIFT      (14)
877#define PLL2550X_M_SHIFT      (4)
878#define PLL2550X_S_SHIFT      (0)
879
880struct samsung_clk_pll2550x {
881	struct clk_hw		hw;
882	const void __iomem	*reg_base;
883	unsigned long		offset;
884};
885
886#define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
887
888static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
889				unsigned long parent_rate)
890{
891	struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
892	u32 r, p, m, s, pll_stat;
893	u64 fvco = parent_rate;
894
895	pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
896	r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
897	if (!r)
898		return 0;
899	p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
900	m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
901	s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
902
903	fvco *= m;
904	do_div(fvco, (p << s));
905
906	return (unsigned long)fvco;
907}
908
909static const struct clk_ops samsung_pll2550x_clk_ops = {
910	.recalc_rate = samsung_pll2550x_recalc_rate,
911};
912
913struct clk * __init samsung_clk_register_pll2550x(const char *name,
914			const char *pname, const void __iomem *reg_base,
915			const unsigned long offset)
916{
917	struct samsung_clk_pll2550x *pll;
918	struct clk *clk;
919	struct clk_init_data init;
920
921	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
922	if (!pll) {
923		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
924		return NULL;
925	}
926
927	init.name = name;
928	init.ops = &samsung_pll2550x_clk_ops;
929	init.flags = CLK_GET_RATE_NOCACHE;
930	init.parent_names = &pname;
931	init.num_parents = 1;
932
933	pll->hw.init = &init;
934	pll->reg_base = reg_base;
935	pll->offset = offset;
936
937	clk = clk_register(NULL, &pll->hw);
938	if (IS_ERR(clk)) {
939		pr_err("%s: failed to register pll clock %s\n", __func__,
940				name);
941		kfree(pll);
942	}
943
944	if (clk_register_clkdev(clk, name, NULL))
945		pr_err("%s: failed to register lookup for %s", __func__, name);
946
947	return clk;
948}
949
950/*
951 * PLL2550xx Clock Type
952 */
953
954/* Maximum lock time can be 270 * PDIV cycles */
955#define PLL2550XX_LOCK_FACTOR 270
956
957#define PLL2550XX_M_MASK		0x3FF
958#define PLL2550XX_P_MASK		0x3F
959#define PLL2550XX_S_MASK		0x7
960#define PLL2550XX_LOCK_STAT_MASK	0x1
961#define PLL2550XX_M_SHIFT		9
962#define PLL2550XX_P_SHIFT		3
963#define PLL2550XX_S_SHIFT		0
964#define PLL2550XX_LOCK_STAT_SHIFT	21
965
966static unsigned long samsung_pll2550xx_recalc_rate(struct clk_hw *hw,
967				unsigned long parent_rate)
968{
969	struct samsung_clk_pll *pll = to_clk_pll(hw);
970	u32 mdiv, pdiv, sdiv, pll_con;
971	u64 fvco = parent_rate;
972
973	pll_con = __raw_readl(pll->con_reg);
974	mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
975	pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
976	sdiv = (pll_con >> PLL2550XX_S_SHIFT) & PLL2550XX_S_MASK;
977
978	fvco *= mdiv;
979	do_div(fvco, (pdiv << sdiv));
980
981	return (unsigned long)fvco;
982}
983
984static inline bool samsung_pll2550xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con)
985{
986	u32 old_mdiv, old_pdiv;
987
988	old_mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
989	old_pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
990
991	return mdiv != old_mdiv || pdiv != old_pdiv;
992}
993
994static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
995					unsigned long prate)
996{
997	struct samsung_clk_pll *pll = to_clk_pll(hw);
998	const struct samsung_pll_rate_table *rate;
999	u32 tmp;
1000
1001	/* Get required rate settings from table */
1002	rate = samsung_get_pll_settings(pll, drate);
1003	if (!rate) {
1004		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1005			drate, __clk_get_name(hw->clk));
1006		return -EINVAL;
1007	}
1008
1009	tmp = __raw_readl(pll->con_reg);
1010
1011	if (!(samsung_pll2550xx_mp_change(rate->mdiv, rate->pdiv, tmp))) {
1012		/* If only s change, change just s value only*/
1013		tmp &= ~(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT);
1014		tmp |= rate->sdiv << PLL2550XX_S_SHIFT;
1015		__raw_writel(tmp, pll->con_reg);
1016
1017		return 0;
1018	}
1019
1020	/* Set PLL lock time. */
1021	__raw_writel(rate->pdiv * PLL2550XX_LOCK_FACTOR, pll->lock_reg);
1022
1023	/* Change PLL PMS values */
1024	tmp &= ~((PLL2550XX_M_MASK << PLL2550XX_M_SHIFT) |
1025			(PLL2550XX_P_MASK << PLL2550XX_P_SHIFT) |
1026			(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT));
1027	tmp |= (rate->mdiv << PLL2550XX_M_SHIFT) |
1028			(rate->pdiv << PLL2550XX_P_SHIFT) |
1029			(rate->sdiv << PLL2550XX_S_SHIFT);
1030	__raw_writel(tmp, pll->con_reg);
1031
1032	/* wait_lock_time */
1033	do {
1034		cpu_relax();
1035		tmp = __raw_readl(pll->con_reg);
1036	} while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
1037			<< PLL2550XX_LOCK_STAT_SHIFT)));
1038
1039	return 0;
1040}
1041
1042static const struct clk_ops samsung_pll2550xx_clk_ops = {
1043	.recalc_rate = samsung_pll2550xx_recalc_rate,
1044	.round_rate = samsung_pll_round_rate,
1045	.set_rate = samsung_pll2550xx_set_rate,
1046};
1047
1048static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
1049	.recalc_rate = samsung_pll2550xx_recalc_rate,
1050};
1051
1052/*
1053 * PLL2650XX Clock Type
1054 */
1055
1056/* Maximum lock time can be 3000 * PDIV cycles */
1057#define PLL2650XX_LOCK_FACTOR 3000
1058
1059#define PLL2650XX_MDIV_SHIFT		9
1060#define PLL2650XX_PDIV_SHIFT		3
1061#define PLL2650XX_SDIV_SHIFT		0
1062#define PLL2650XX_KDIV_SHIFT		0
1063#define PLL2650XX_MDIV_MASK		0x1ff
1064#define PLL2650XX_PDIV_MASK		0x3f
1065#define PLL2650XX_SDIV_MASK		0x7
1066#define PLL2650XX_KDIV_MASK		0xffff
1067#define PLL2650XX_PLL_ENABLE_SHIFT	23
1068#define PLL2650XX_PLL_LOCKTIME_SHIFT	21
1069#define PLL2650XX_PLL_FOUTMASK_SHIFT	31
1070
1071static unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw,
1072				unsigned long parent_rate)
1073{
1074	struct samsung_clk_pll *pll = to_clk_pll(hw);
1075	u32 mdiv, pdiv, sdiv, pll_con0, pll_con2;
1076	s16 kdiv;
1077	u64 fvco = parent_rate;
1078
1079	pll_con0 = __raw_readl(pll->con_reg);
1080	pll_con2 = __raw_readl(pll->con_reg + 8);
1081	mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK;
1082	pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK;
1083	sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK;
1084	kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK);
1085
1086	fvco *= (mdiv << 16) + kdiv;
1087	do_div(fvco, (pdiv << sdiv));
1088	fvco >>= 16;
1089
1090	return (unsigned long)fvco;
1091}
1092
1093static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
1094					unsigned long parent_rate)
1095{
1096	struct samsung_clk_pll *pll = to_clk_pll(hw);
1097	u32 tmp, pll_con0, pll_con2;
1098	const struct samsung_pll_rate_table *rate;
1099
1100	rate = samsung_get_pll_settings(pll, drate);
1101	if (!rate) {
1102		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1103			drate, __clk_get_name(hw->clk));
1104		return -EINVAL;
1105	}
1106
1107	pll_con0 = __raw_readl(pll->con_reg);
1108	pll_con2 = __raw_readl(pll->con_reg + 8);
1109
1110	 /* Change PLL PMS values */
1111	pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT |
1112			PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT |
1113			PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT);
1114	pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT;
1115	pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT;
1116	pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT;
1117	pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT;
1118	pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT;
1119
1120	pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT);
1121	pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK)
1122			<< PLL2650XX_KDIV_SHIFT;
1123
1124	/* Set PLL lock time. */
1125	__raw_writel(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg);
1126
1127	__raw_writel(pll_con0, pll->con_reg);
1128	__raw_writel(pll_con2, pll->con_reg + 8);
1129
1130	do {
1131		tmp = __raw_readl(pll->con_reg);
1132	} while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
1133
1134	return 0;
1135}
1136
1137static const struct clk_ops samsung_pll2650xx_clk_ops = {
1138	.recalc_rate = samsung_pll2650xx_recalc_rate,
1139	.set_rate = samsung_pll2650xx_set_rate,
1140	.round_rate = samsung_pll_round_rate,
1141};
1142
1143static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
1144	.recalc_rate = samsung_pll2650xx_recalc_rate,
1145};
1146
1147static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1148				struct samsung_pll_clock *pll_clk,
1149				void __iomem *base)
1150{
1151	struct samsung_clk_pll *pll;
1152	struct clk *clk;
1153	struct clk_init_data init;
1154	int ret, len;
1155
1156	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
1157	if (!pll) {
1158		pr_err("%s: could not allocate pll clk %s\n",
1159			__func__, pll_clk->name);
1160		return;
1161	}
1162
1163	init.name = pll_clk->name;
1164	init.flags = pll_clk->flags;
1165	init.parent_names = &pll_clk->parent_name;
1166	init.num_parents = 1;
1167
1168	if (pll_clk->rate_table) {
1169		/* find count of rates in rate_table */
1170		for (len = 0; pll_clk->rate_table[len].rate != 0; )
1171			len++;
1172
1173		pll->rate_count = len;
1174		pll->rate_table = kmemdup(pll_clk->rate_table,
1175					pll->rate_count *
1176					sizeof(struct samsung_pll_rate_table),
1177					GFP_KERNEL);
1178		WARN(!pll->rate_table,
1179			"%s: could not allocate rate table for %s\n",
1180			__func__, pll_clk->name);
1181	}
1182
1183	switch (pll_clk->type) {
1184	case pll_2126:
1185		init.ops = &samsung_pll2126_clk_ops;
1186		break;
1187	case pll_3000:
1188		init.ops = &samsung_pll3000_clk_ops;
1189		break;
1190	/* clk_ops for 35xx and 2550 are similar */
1191	case pll_35xx:
1192	case pll_2550:
1193		if (!pll->rate_table)
1194			init.ops = &samsung_pll35xx_clk_min_ops;
1195		else
1196			init.ops = &samsung_pll35xx_clk_ops;
1197		break;
1198	case pll_4500:
1199		init.ops = &samsung_pll45xx_clk_min_ops;
1200		break;
1201	case pll_4502:
1202	case pll_4508:
1203		if (!pll->rate_table)
1204			init.ops = &samsung_pll45xx_clk_min_ops;
1205		else
1206			init.ops = &samsung_pll45xx_clk_ops;
1207		break;
1208	/* clk_ops for 36xx and 2650 are similar */
1209	case pll_36xx:
1210	case pll_2650:
1211		if (!pll->rate_table)
1212			init.ops = &samsung_pll36xx_clk_min_ops;
1213		else
1214			init.ops = &samsung_pll36xx_clk_ops;
1215		break;
1216	case pll_6552:
1217	case pll_6552_s3c2416:
1218		init.ops = &samsung_pll6552_clk_ops;
1219		break;
1220	case pll_6553:
1221		init.ops = &samsung_pll6553_clk_ops;
1222		break;
1223	case pll_4600:
1224	case pll_4650:
1225	case pll_4650c:
1226		if (!pll->rate_table)
1227			init.ops = &samsung_pll46xx_clk_min_ops;
1228		else
1229			init.ops = &samsung_pll46xx_clk_ops;
1230		break;
1231	case pll_s3c2410_mpll:
1232		if (!pll->rate_table)
1233			init.ops = &samsung_s3c2410_mpll_clk_min_ops;
1234		else
1235			init.ops = &samsung_s3c2410_mpll_clk_ops;
1236		break;
1237	case pll_s3c2410_upll:
1238		if (!pll->rate_table)
1239			init.ops = &samsung_s3c2410_upll_clk_min_ops;
1240		else
1241			init.ops = &samsung_s3c2410_upll_clk_ops;
1242		break;
1243	case pll_s3c2440_mpll:
1244		if (!pll->rate_table)
1245			init.ops = &samsung_s3c2440_mpll_clk_min_ops;
1246		else
1247			init.ops = &samsung_s3c2440_mpll_clk_ops;
1248		break;
1249	case pll_2550xx:
1250		if (!pll->rate_table)
1251			init.ops = &samsung_pll2550xx_clk_min_ops;
1252		else
1253			init.ops = &samsung_pll2550xx_clk_ops;
1254		break;
1255	case pll_2650xx:
1256		if (!pll->rate_table)
1257			init.ops = &samsung_pll2650xx_clk_min_ops;
1258		else
1259			init.ops = &samsung_pll2650xx_clk_ops;
1260		break;
1261	default:
1262		pr_warn("%s: Unknown pll type for pll clk %s\n",
1263			__func__, pll_clk->name);
1264	}
1265
1266	pll->hw.init = &init;
1267	pll->type = pll_clk->type;
1268	pll->lock_reg = base + pll_clk->lock_offset;
1269	pll->con_reg = base + pll_clk->con_offset;
1270
1271	clk = clk_register(NULL, &pll->hw);
1272	if (IS_ERR(clk)) {
1273		pr_err("%s: failed to register pll clock %s : %ld\n",
1274			__func__, pll_clk->name, PTR_ERR(clk));
1275		kfree(pll);
1276		return;
1277	}
1278
1279	samsung_clk_add_lookup(ctx, clk, pll_clk->id);
1280
1281	if (!pll_clk->alias)
1282		return;
1283
1284	ret = clk_register_clkdev(clk, pll_clk->alias, pll_clk->dev_name);
1285	if (ret)
1286		pr_err("%s: failed to register lookup for %s : %d",
1287			__func__, pll_clk->name, ret);
1288}
1289
1290void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1291			struct samsung_pll_clock *pll_list,
1292			unsigned int nr_pll, void __iomem *base)
1293{
1294	int cnt;
1295
1296	for (cnt = 0; cnt < nr_pll; cnt++)
1297		_samsung_clk_register_pll(ctx, &pll_list[cnt], base);
1298}
1299