2 * Copyright (C) 2012 ST Microelectronics
3 * Viresh Kumar <vireshk@kernel.org>
5 * This file is licensed under the terms of the GNU General Public
6 * License version 2. This program is licensed "as is" without any
7 * warranty of any kind, whether express or implied.
9 * VCO-PLL clock implementation
12 #define pr_fmt(fmt) "clk-vco-pll: " fmt
14 #include <linux/clk-provider.h>
15 #include <linux/slab.h>
17 #include <linux/err.h>
23 * VCO and PLL rate are derived from following equations:
26 * vco = (2 * M[15:8] * Fin)/N
29 * vco = (2 * M[15:0] * Fin)/(256 * N)
33 * vco and pll are very closely bound to each other, "vco needs to program:
34 * mode, m & n" and "pll needs to program p", both share common enable/disable
37 * clk_register_vco_pll() registers instances of both vco & pll.
38 * CLK_SET_RATE_PARENT flag is forced for pll, as it will always pass its
39 * set_rate to vco. A single rate table exists for both the clocks, which
40 * configures m, n and p.
43 /* PLL_CTR register masks */
44 #define PLL_MODE_NORMAL 0
45 #define PLL_MODE_FRACTION 1
46 #define PLL_MODE_DITH_DSM 2
47 #define PLL_MODE_DITH_SSM 3
48 #define PLL_MODE_MASK 3
49 #define PLL_MODE_SHIFT 3
52 #define PLL_LOCK_SHIFT 0
53 #define PLL_LOCK_MASK 1
55 /* PLL FRQ register masks */
56 #define PLL_NORM_FDBK_M_MASK 0xFF
57 #define PLL_NORM_FDBK_M_SHIFT 24
58 #define PLL_DITH_FDBK_M_MASK 0xFFFF
59 #define PLL_DITH_FDBK_M_SHIFT 16
60 #define PLL_DIV_P_MASK 0x7
61 #define PLL_DIV_P_SHIFT 8
62 #define PLL_DIV_N_MASK 0xFF
63 #define PLL_DIV_N_SHIFT 0
65 #define to_clk_vco(_hw) container_of(_hw, struct clk_vco, hw)
66 #define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw)
68 /* Calculates pll clk rate for specific value of mode, m, n and p */
69 static unsigned long pll_calc_rate(struct pll_rate_tbl
*rtbl
,
70 unsigned long prate
, int index
, unsigned long *pll_rate
)
72 unsigned long rate
= prate
;
75 mode
= rtbl
[index
].mode
? 256 : 1;
76 rate
= (((2 * rate
/ 10000) * rtbl
[index
].m
) / (mode
* rtbl
[index
].n
));
79 *pll_rate
= (rate
/ (1 << rtbl
[index
].p
)) * 10000;
84 static long clk_pll_round_rate_index(struct clk_hw
*hw
, unsigned long drate
,
85 unsigned long *prate
, int *index
)
87 struct clk_pll
*pll
= to_clk_pll(hw
);
88 unsigned long prev_rate
, vco_prev_rate
, rate
= 0;
89 unsigned long vco_parent_rate
=
90 clk_hw_get_rate(clk_hw_get_parent(clk_hw_get_parent(hw
)));
93 pr_err("%s: prate is must for pll clk\n", __func__
);
97 for (*index
= 0; *index
< pll
->vco
->rtbl_cnt
; (*index
)++) {
99 vco_prev_rate
= *prate
;
100 *prate
= pll_calc_rate(pll
->vco
->rtbl
, vco_parent_rate
, *index
,
103 /* previous clock was best */
106 *prate
= vco_prev_rate
;
116 static long clk_pll_round_rate(struct clk_hw
*hw
, unsigned long drate
,
117 unsigned long *prate
)
121 return clk_pll_round_rate_index(hw
, drate
, prate
, &unused
);
124 static unsigned long clk_pll_recalc_rate(struct clk_hw
*hw
, unsigned long
127 struct clk_pll
*pll
= to_clk_pll(hw
);
128 unsigned long flags
= 0;
132 spin_lock_irqsave(pll
->vco
->lock
, flags
);
134 p
= readl_relaxed(pll
->vco
->cfg_reg
);
137 spin_unlock_irqrestore(pll
->vco
->lock
, flags
);
139 p
= (p
>> PLL_DIV_P_SHIFT
) & PLL_DIV_P_MASK
;
141 return parent_rate
/ (1 << p
);
144 static int clk_pll_set_rate(struct clk_hw
*hw
, unsigned long drate
,
147 struct clk_pll
*pll
= to_clk_pll(hw
);
148 struct pll_rate_tbl
*rtbl
= pll
->vco
->rtbl
;
149 unsigned long flags
= 0, val
;
150 int uninitialized_var(i
);
152 clk_pll_round_rate_index(hw
, drate
, NULL
, &i
);
155 spin_lock_irqsave(pll
->vco
->lock
, flags
);
157 val
= readl_relaxed(pll
->vco
->cfg_reg
);
158 val
&= ~(PLL_DIV_P_MASK
<< PLL_DIV_P_SHIFT
);
159 val
|= (rtbl
[i
].p
& PLL_DIV_P_MASK
) << PLL_DIV_P_SHIFT
;
160 writel_relaxed(val
, pll
->vco
->cfg_reg
);
163 spin_unlock_irqrestore(pll
->vco
->lock
, flags
);
168 static const struct clk_ops clk_pll_ops
= {
169 .recalc_rate
= clk_pll_recalc_rate
,
170 .round_rate
= clk_pll_round_rate
,
171 .set_rate
= clk_pll_set_rate
,
174 static inline unsigned long vco_calc_rate(struct clk_hw
*hw
,
175 unsigned long prate
, int index
)
177 struct clk_vco
*vco
= to_clk_vco(hw
);
179 return pll_calc_rate(vco
->rtbl
, prate
, index
, NULL
);
182 static long clk_vco_round_rate(struct clk_hw
*hw
, unsigned long drate
,
183 unsigned long *prate
)
185 struct clk_vco
*vco
= to_clk_vco(hw
);
188 return clk_round_rate_index(hw
, drate
, *prate
, vco_calc_rate
,
189 vco
->rtbl_cnt
, &unused
);
192 static unsigned long clk_vco_recalc_rate(struct clk_hw
*hw
,
193 unsigned long parent_rate
)
195 struct clk_vco
*vco
= to_clk_vco(hw
);
196 unsigned long flags
= 0;
197 unsigned int num
= 2, den
= 0, val
, mode
= 0;
200 spin_lock_irqsave(vco
->lock
, flags
);
202 mode
= (readl_relaxed(vco
->mode_reg
) >> PLL_MODE_SHIFT
) & PLL_MODE_MASK
;
204 val
= readl_relaxed(vco
->cfg_reg
);
207 spin_unlock_irqrestore(vco
->lock
, flags
);
209 den
= (val
>> PLL_DIV_N_SHIFT
) & PLL_DIV_N_MASK
;
211 /* calculate numerator & denominator */
214 num
*= (val
>> PLL_NORM_FDBK_M_SHIFT
) & PLL_NORM_FDBK_M_MASK
;
217 num
*= (val
>> PLL_DITH_FDBK_M_SHIFT
) & PLL_DITH_FDBK_M_MASK
;
222 WARN(1, "%s: denominator can't be zero\n", __func__
);
226 return (((parent_rate
/ 10000) * num
) / den
) * 10000;
229 /* Configures new clock rate of vco */
230 static int clk_vco_set_rate(struct clk_hw
*hw
, unsigned long drate
,
233 struct clk_vco
*vco
= to_clk_vco(hw
);
234 struct pll_rate_tbl
*rtbl
= vco
->rtbl
;
235 unsigned long flags
= 0, val
;
238 clk_round_rate_index(hw
, drate
, prate
, vco_calc_rate
, vco
->rtbl_cnt
,
242 spin_lock_irqsave(vco
->lock
, flags
);
244 val
= readl_relaxed(vco
->mode_reg
);
245 val
&= ~(PLL_MODE_MASK
<< PLL_MODE_SHIFT
);
246 val
|= (rtbl
[i
].mode
& PLL_MODE_MASK
) << PLL_MODE_SHIFT
;
247 writel_relaxed(val
, vco
->mode_reg
);
249 val
= readl_relaxed(vco
->cfg_reg
);
250 val
&= ~(PLL_DIV_N_MASK
<< PLL_DIV_N_SHIFT
);
251 val
|= (rtbl
[i
].n
& PLL_DIV_N_MASK
) << PLL_DIV_N_SHIFT
;
253 val
&= ~(PLL_DITH_FDBK_M_MASK
<< PLL_DITH_FDBK_M_SHIFT
);
255 val
|= (rtbl
[i
].m
& PLL_DITH_FDBK_M_MASK
) <<
256 PLL_DITH_FDBK_M_SHIFT
;
258 val
|= (rtbl
[i
].m
& PLL_NORM_FDBK_M_MASK
) <<
259 PLL_NORM_FDBK_M_SHIFT
;
261 writel_relaxed(val
, vco
->cfg_reg
);
264 spin_unlock_irqrestore(vco
->lock
, flags
);
269 static const struct clk_ops clk_vco_ops
= {
270 .recalc_rate
= clk_vco_recalc_rate
,
271 .round_rate
= clk_vco_round_rate
,
272 .set_rate
= clk_vco_set_rate
,
275 struct clk
*clk_register_vco_pll(const char *vco_name
, const char *pll_name
,
276 const char *vco_gate_name
, const char *parent_name
,
277 unsigned long flags
, void __iomem
*mode_reg
, void __iomem
278 *cfg_reg
, struct pll_rate_tbl
*rtbl
, u8 rtbl_cnt
,
279 spinlock_t
*lock
, struct clk
**pll_clk
,
280 struct clk
**vco_gate_clk
)
284 struct clk
*vco_clk
, *tpll_clk
, *tvco_gate_clk
;
285 struct clk_init_data vco_init
, pll_init
;
286 const char **vco_parent_name
;
288 if (!vco_name
|| !pll_name
|| !parent_name
|| !mode_reg
|| !cfg_reg
||
289 !rtbl
|| !rtbl_cnt
) {
290 pr_err("Invalid arguments passed");
291 return ERR_PTR(-EINVAL
);
294 vco
= kzalloc(sizeof(*vco
), GFP_KERNEL
);
296 return ERR_PTR(-ENOMEM
);
298 pll
= kzalloc(sizeof(*pll
), GFP_KERNEL
);
302 /* struct clk_vco assignments */
303 vco
->mode_reg
= mode_reg
;
304 vco
->cfg_reg
= cfg_reg
;
306 vco
->rtbl_cnt
= rtbl_cnt
;
308 vco
->hw
.init
= &vco_init
;
311 pll
->hw
.init
= &pll_init
;
314 tvco_gate_clk
= clk_register_gate(NULL
, vco_gate_name
,
315 parent_name
, 0, mode_reg
, PLL_ENABLE
, 0, lock
);
316 if (IS_ERR_OR_NULL(tvco_gate_clk
))
320 *vco_gate_clk
= tvco_gate_clk
;
321 vco_parent_name
= &vco_gate_name
;
323 vco_parent_name
= &parent_name
;
326 vco_init
.name
= vco_name
;
327 vco_init
.ops
= &clk_vco_ops
;
328 vco_init
.flags
= flags
;
329 vco_init
.parent_names
= vco_parent_name
;
330 vco_init
.num_parents
= 1;
332 pll_init
.name
= pll_name
;
333 pll_init
.ops
= &clk_pll_ops
;
334 pll_init
.flags
= CLK_SET_RATE_PARENT
;
335 pll_init
.parent_names
= &vco_name
;
336 pll_init
.num_parents
= 1;
338 vco_clk
= clk_register(NULL
, &vco
->hw
);
339 if (IS_ERR_OR_NULL(vco_clk
))
342 tpll_clk
= clk_register(NULL
, &pll
->hw
);
343 if (IS_ERR_OR_NULL(tpll_clk
))
356 pr_err("Failed to register vco pll clock\n");
358 return ERR_PTR(-ENOMEM
);