Commit | Line | Data |
---|---|---|
55b8fd4f VK |
1 | /* |
2 | * Copyright (C) 2012 ST Microelectronics | |
10d8935f | 3 | * Viresh Kumar <viresh.linux@gmail.com> |
55b8fd4f VK |
4 | * |
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. | |
8 | * | |
9 | * VCO-PLL clock implementation | |
10 | */ | |
11 | ||
12 | #define pr_fmt(fmt) "clk-vco-pll: " fmt | |
13 | ||
14 | #include <linux/clk-provider.h> | |
15 | #include <linux/slab.h> | |
16 | #include <linux/io.h> | |
17 | #include <linux/err.h> | |
18 | #include "clk.h" | |
19 | ||
20 | /* | |
21 | * DOC: VCO-PLL clock | |
22 | * | |
23 | * VCO and PLL rate are derived from following equations: | |
24 | * | |
25 | * In normal mode | |
26 | * vco = (2 * M[15:8] * Fin)/N | |
27 | * | |
28 | * In Dithered mode | |
29 | * vco = (2 * M[15:0] * Fin)/(256 * N) | |
30 | * | |
31 | * pll_rate = pll/2^p | |
32 | * | |
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 | |
35 | * logic. | |
36 | * | |
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. | |
41 | */ | |
42 | ||
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 | |
50 | #define PLL_ENABLE 2 | |
51 | ||
52 | #define PLL_LOCK_SHIFT 0 | |
53 | #define PLL_LOCK_MASK 1 | |
54 | ||
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 | |
64 | ||
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) | |
67 | ||
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) | |
71 | { | |
72 | unsigned long rate = prate; | |
73 | unsigned int mode; | |
74 | ||
75 | mode = rtbl[index].mode ? 256 : 1; | |
76 | rate = (((2 * rate / 10000) * rtbl[index].m) / (mode * rtbl[index].n)); | |
77 | ||
78 | if (pll_rate) | |
79 | *pll_rate = (rate / (1 << rtbl[index].p)) * 10000; | |
80 | ||
81 | return rate * 10000; | |
82 | } | |
83 | ||
84 | static long clk_pll_round_rate_index(struct clk_hw *hw, unsigned long drate, | |
85 | unsigned long *prate, int *index) | |
86 | { | |
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_get_rate(__clk_get_parent(__clk_get_parent(hw->clk))); | |
91 | ||
92 | if (!prate) { | |
93 | pr_err("%s: prate is must for pll clk\n", __func__); | |
94 | return -EINVAL; | |
95 | } | |
96 | ||
97 | for (*index = 0; *index < pll->vco->rtbl_cnt; (*index)++) { | |
98 | prev_rate = rate; | |
99 | vco_prev_rate = *prate; | |
100 | *prate = pll_calc_rate(pll->vco->rtbl, vco_parent_rate, *index, | |
101 | &rate); | |
102 | if (drate < rate) { | |
103 | /* previous clock was best */ | |
104 | if (*index) { | |
105 | rate = prev_rate; | |
106 | *prate = vco_prev_rate; | |
107 | (*index)--; | |
108 | } | |
109 | break; | |
110 | } | |
111 | } | |
112 | ||
113 | return rate; | |
114 | } | |
115 | ||
116 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long drate, | |
117 | unsigned long *prate) | |
118 | { | |
119 | int unused; | |
120 | ||
121 | return clk_pll_round_rate_index(hw, drate, prate, &unused); | |
122 | } | |
123 | ||
124 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long | |
125 | parent_rate) | |
126 | { | |
127 | struct clk_pll *pll = to_clk_pll(hw); | |
128 | unsigned long flags = 0; | |
129 | unsigned int p; | |
130 | ||
131 | if (pll->vco->lock) | |
132 | spin_lock_irqsave(pll->vco->lock, flags); | |
133 | ||
134 | p = readl_relaxed(pll->vco->cfg_reg); | |
135 | ||
136 | if (pll->vco->lock) | |
137 | spin_unlock_irqrestore(pll->vco->lock, flags); | |
138 | ||
139 | p = (p >> PLL_DIV_P_SHIFT) & PLL_DIV_P_MASK; | |
140 | ||
141 | return parent_rate / (1 << p); | |
142 | } | |
143 | ||
144 | static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate, | |
145 | unsigned long prate) | |
146 | { | |
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 i; | |
151 | ||
152 | clk_pll_round_rate_index(hw, drate, NULL, &i); | |
153 | ||
154 | if (pll->vco->lock) | |
155 | spin_lock_irqsave(pll->vco->lock, flags); | |
156 | ||
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); | |
161 | ||
162 | if (pll->vco->lock) | |
163 | spin_unlock_irqrestore(pll->vco->lock, flags); | |
164 | ||
165 | return 0; | |
166 | } | |
167 | ||
168 | static 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, | |
172 | }; | |
173 | ||
174 | static inline unsigned long vco_calc_rate(struct clk_hw *hw, | |
175 | unsigned long prate, int index) | |
176 | { | |
177 | struct clk_vco *vco = to_clk_vco(hw); | |
178 | ||
179 | return pll_calc_rate(vco->rtbl, prate, index, NULL); | |
180 | } | |
181 | ||
182 | static long clk_vco_round_rate(struct clk_hw *hw, unsigned long drate, | |
183 | unsigned long *prate) | |
184 | { | |
185 | struct clk_vco *vco = to_clk_vco(hw); | |
186 | int unused; | |
187 | ||
188 | return clk_round_rate_index(hw, drate, *prate, vco_calc_rate, | |
189 | vco->rtbl_cnt, &unused); | |
190 | } | |
191 | ||
192 | static unsigned long clk_vco_recalc_rate(struct clk_hw *hw, | |
193 | unsigned long parent_rate) | |
194 | { | |
195 | struct clk_vco *vco = to_clk_vco(hw); | |
196 | unsigned long flags = 0; | |
197 | unsigned int num = 2, den = 0, val, mode = 0; | |
198 | ||
199 | if (vco->lock) | |
200 | spin_lock_irqsave(vco->lock, flags); | |
201 | ||
202 | mode = (readl_relaxed(vco->mode_reg) >> PLL_MODE_SHIFT) & PLL_MODE_MASK; | |
203 | ||
204 | val = readl_relaxed(vco->cfg_reg); | |
205 | ||
206 | if (vco->lock) | |
207 | spin_unlock_irqrestore(vco->lock, flags); | |
208 | ||
209 | den = (val >> PLL_DIV_N_SHIFT) & PLL_DIV_N_MASK; | |
210 | ||
211 | /* calculate numerator & denominator */ | |
212 | if (!mode) { | |
213 | /* Normal mode */ | |
214 | num *= (val >> PLL_NORM_FDBK_M_SHIFT) & PLL_NORM_FDBK_M_MASK; | |
215 | } else { | |
216 | /* Dithered mode */ | |
217 | num *= (val >> PLL_DITH_FDBK_M_SHIFT) & PLL_DITH_FDBK_M_MASK; | |
218 | den *= 256; | |
219 | } | |
220 | ||
221 | if (!den) { | |
222 | WARN(1, "%s: denominator can't be zero\n", __func__); | |
223 | return 0; | |
224 | } | |
225 | ||
226 | return (((parent_rate / 10000) * num) / den) * 10000; | |
227 | } | |
228 | ||
229 | /* Configures new clock rate of vco */ | |
230 | static int clk_vco_set_rate(struct clk_hw *hw, unsigned long drate, | |
231 | unsigned long prate) | |
232 | { | |
233 | struct clk_vco *vco = to_clk_vco(hw); | |
234 | struct pll_rate_tbl *rtbl = vco->rtbl; | |
235 | unsigned long flags = 0, val; | |
236 | int i; | |
237 | ||
238 | clk_round_rate_index(hw, drate, prate, vco_calc_rate, vco->rtbl_cnt, | |
239 | &i); | |
240 | ||
241 | if (vco->lock) | |
242 | spin_lock_irqsave(vco->lock, flags); | |
243 | ||
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); | |
248 | ||
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; | |
252 | ||
253 | val &= ~(PLL_DITH_FDBK_M_MASK << PLL_DITH_FDBK_M_SHIFT); | |
254 | if (rtbl[i].mode) | |
255 | val |= (rtbl[i].m & PLL_DITH_FDBK_M_MASK) << | |
256 | PLL_DITH_FDBK_M_SHIFT; | |
257 | else | |
258 | val |= (rtbl[i].m & PLL_NORM_FDBK_M_MASK) << | |
259 | PLL_NORM_FDBK_M_SHIFT; | |
260 | ||
261 | writel_relaxed(val, vco->cfg_reg); | |
262 | ||
263 | if (vco->lock) | |
264 | spin_unlock_irqrestore(vco->lock, flags); | |
265 | ||
266 | return 0; | |
267 | } | |
268 | ||
269 | static 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, | |
273 | }; | |
274 | ||
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) | |
281 | { | |
282 | struct clk_vco *vco; | |
283 | struct clk_pll *pll; | |
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; | |
287 | ||
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); | |
292 | } | |
293 | ||
294 | vco = kzalloc(sizeof(*vco), GFP_KERNEL); | |
295 | if (!vco) { | |
296 | pr_err("could not allocate vco clk\n"); | |
297 | return ERR_PTR(-ENOMEM); | |
298 | } | |
299 | ||
300 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | |
301 | if (!pll) { | |
302 | pr_err("could not allocate pll clk\n"); | |
303 | goto free_vco; | |
304 | } | |
305 | ||
306 | /* struct clk_vco assignments */ | |
307 | vco->mode_reg = mode_reg; | |
308 | vco->cfg_reg = cfg_reg; | |
309 | vco->rtbl = rtbl; | |
310 | vco->rtbl_cnt = rtbl_cnt; | |
311 | vco->lock = lock; | |
312 | vco->hw.init = &vco_init; | |
313 | ||
314 | pll->vco = vco; | |
315 | pll->hw.init = &pll_init; | |
316 | ||
317 | if (vco_gate_name) { | |
318 | tvco_gate_clk = clk_register_gate(NULL, vco_gate_name, | |
319 | parent_name, 0, mode_reg, PLL_ENABLE, 0, lock); | |
320 | if (IS_ERR_OR_NULL(tvco_gate_clk)) | |
321 | goto free_pll; | |
322 | ||
323 | if (vco_gate_clk) | |
324 | *vco_gate_clk = tvco_gate_clk; | |
325 | vco_parent_name = &vco_gate_name; | |
326 | } else { | |
327 | vco_parent_name = &parent_name; | |
328 | } | |
329 | ||
330 | vco_init.name = vco_name; | |
331 | vco_init.ops = &clk_vco_ops; | |
332 | vco_init.flags = flags; | |
333 | vco_init.parent_names = vco_parent_name; | |
334 | vco_init.num_parents = 1; | |
335 | ||
336 | pll_init.name = pll_name; | |
337 | pll_init.ops = &clk_pll_ops; | |
338 | pll_init.flags = CLK_SET_RATE_PARENT; | |
339 | pll_init.parent_names = &vco_name; | |
340 | pll_init.num_parents = 1; | |
341 | ||
342 | vco_clk = clk_register(NULL, &vco->hw); | |
343 | if (IS_ERR_OR_NULL(vco_clk)) | |
344 | goto free_pll; | |
345 | ||
346 | tpll_clk = clk_register(NULL, &pll->hw); | |
347 | if (IS_ERR_OR_NULL(tpll_clk)) | |
348 | goto free_pll; | |
349 | ||
350 | if (pll_clk) | |
351 | *pll_clk = tpll_clk; | |
352 | ||
353 | return vco_clk; | |
354 | ||
355 | free_pll: | |
356 | kfree(pll); | |
357 | free_vco: | |
358 | kfree(vco); | |
359 | ||
360 | pr_err("Failed to register vco pll clock\n"); | |
361 | ||
362 | return ERR_PTR(-ENOMEM); | |
363 | } |