diff options
Diffstat (limited to 'drivers/clk/qcom')
-rw-r--r-- | drivers/clk/qcom/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg.c | 517 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg.h | 159 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg2.c | 291 |
4 files changed, 969 insertions, 0 deletions
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 7871e235c2b1..5d0a6e0ac01f 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile | |||
@@ -2,3 +2,5 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o | |||
2 | 2 | ||
3 | clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-regmap.o | 3 | clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-regmap.o |
4 | clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-pll.o | 4 | clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-pll.o |
5 | clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-rcg.o | ||
6 | clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-rcg2.o | ||
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c new file mode 100644 index 000000000000..abfc2b675aea --- /dev/null +++ b/drivers/clk/qcom/clk-rcg.c | |||
@@ -0,0 +1,517 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/bitops.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/export.h> | ||
18 | #include <linux/clk-provider.h> | ||
19 | #include <linux/regmap.h> | ||
20 | |||
21 | #include <asm/div64.h> | ||
22 | |||
23 | #include "clk-rcg.h" | ||
24 | |||
25 | static u32 ns_to_src(struct src_sel *s, u32 ns) | ||
26 | { | ||
27 | ns >>= s->src_sel_shift; | ||
28 | ns &= SRC_SEL_MASK; | ||
29 | return ns; | ||
30 | } | ||
31 | |||
32 | static u32 src_to_ns(struct src_sel *s, u8 src, u32 ns) | ||
33 | { | ||
34 | u32 mask; | ||
35 | |||
36 | mask = SRC_SEL_MASK; | ||
37 | mask <<= s->src_sel_shift; | ||
38 | ns &= ~mask; | ||
39 | |||
40 | ns |= src << s->src_sel_shift; | ||
41 | return ns; | ||
42 | } | ||
43 | |||
44 | static u8 clk_rcg_get_parent(struct clk_hw *hw) | ||
45 | { | ||
46 | struct clk_rcg *rcg = to_clk_rcg(hw); | ||
47 | int num_parents = __clk_get_num_parents(hw->clk); | ||
48 | u32 ns; | ||
49 | int i; | ||
50 | |||
51 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | ||
52 | ns = ns_to_src(&rcg->s, ns); | ||
53 | for (i = 0; i < num_parents; i++) | ||
54 | if (ns == rcg->s.parent_map[i]) | ||
55 | return i; | ||
56 | |||
57 | return -EINVAL; | ||
58 | } | ||
59 | |||
60 | static int reg_to_bank(struct clk_dyn_rcg *rcg, u32 bank) | ||
61 | { | ||
62 | bank &= BIT(rcg->mux_sel_bit); | ||
63 | return !!bank; | ||
64 | } | ||
65 | |||
66 | static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw) | ||
67 | { | ||
68 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | ||
69 | int num_parents = __clk_get_num_parents(hw->clk); | ||
70 | u32 ns, ctl; | ||
71 | int bank; | ||
72 | int i; | ||
73 | struct src_sel *s; | ||
74 | |||
75 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | ||
76 | bank = reg_to_bank(rcg, ctl); | ||
77 | s = &rcg->s[bank]; | ||
78 | |||
79 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | ||
80 | ns = ns_to_src(s, ns); | ||
81 | |||
82 | for (i = 0; i < num_parents; i++) | ||
83 | if (ns == s->parent_map[i]) | ||
84 | return i; | ||
85 | |||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | static int clk_rcg_set_parent(struct clk_hw *hw, u8 index) | ||
90 | { | ||
91 | struct clk_rcg *rcg = to_clk_rcg(hw); | ||
92 | u32 ns; | ||
93 | |||
94 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | ||
95 | ns = src_to_ns(&rcg->s, rcg->s.parent_map[index], ns); | ||
96 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static u32 md_to_m(struct mn *mn, u32 md) | ||
102 | { | ||
103 | md >>= mn->m_val_shift; | ||
104 | md &= BIT(mn->width) - 1; | ||
105 | return md; | ||
106 | } | ||
107 | |||
108 | static u32 ns_to_pre_div(struct pre_div *p, u32 ns) | ||
109 | { | ||
110 | ns >>= p->pre_div_shift; | ||
111 | ns &= BIT(p->pre_div_width) - 1; | ||
112 | return ns; | ||
113 | } | ||
114 | |||
115 | static u32 pre_div_to_ns(struct pre_div *p, u8 pre_div, u32 ns) | ||
116 | { | ||
117 | u32 mask; | ||
118 | |||
119 | mask = BIT(p->pre_div_width) - 1; | ||
120 | mask <<= p->pre_div_shift; | ||
121 | ns &= ~mask; | ||
122 | |||
123 | ns |= pre_div << p->pre_div_shift; | ||
124 | return ns; | ||
125 | } | ||
126 | |||
127 | static u32 mn_to_md(struct mn *mn, u32 m, u32 n, u32 md) | ||
128 | { | ||
129 | u32 mask, mask_w; | ||
130 | |||
131 | mask_w = BIT(mn->width) - 1; | ||
132 | mask = (mask_w << mn->m_val_shift) | mask_w; | ||
133 | md &= ~mask; | ||
134 | |||
135 | if (n) { | ||
136 | m <<= mn->m_val_shift; | ||
137 | md |= m; | ||
138 | md |= ~n & mask_w; | ||
139 | } | ||
140 | |||
141 | return md; | ||
142 | } | ||
143 | |||
144 | static u32 ns_m_to_n(struct mn *mn, u32 ns, u32 m) | ||
145 | { | ||
146 | ns = ~ns >> mn->n_val_shift; | ||
147 | ns &= BIT(mn->width) - 1; | ||
148 | return ns + m; | ||
149 | } | ||
150 | |||
151 | static u32 reg_to_mnctr_mode(struct mn *mn, u32 val) | ||
152 | { | ||
153 | val >>= mn->mnctr_mode_shift; | ||
154 | val &= MNCTR_MODE_MASK; | ||
155 | return val; | ||
156 | } | ||
157 | |||
158 | static u32 mn_to_ns(struct mn *mn, u32 m, u32 n, u32 ns) | ||
159 | { | ||
160 | u32 mask; | ||
161 | |||
162 | mask = BIT(mn->width) - 1; | ||
163 | mask <<= mn->n_val_shift; | ||
164 | ns &= ~mask; | ||
165 | |||
166 | if (n) { | ||
167 | n = n - m; | ||
168 | n = ~n; | ||
169 | n &= BIT(mn->width) - 1; | ||
170 | n <<= mn->n_val_shift; | ||
171 | ns |= n; | ||
172 | } | ||
173 | |||
174 | return ns; | ||
175 | } | ||
176 | |||
177 | static u32 mn_to_reg(struct mn *mn, u32 m, u32 n, u32 val) | ||
178 | { | ||
179 | u32 mask; | ||
180 | |||
181 | mask = MNCTR_MODE_MASK << mn->mnctr_mode_shift; | ||
182 | mask |= BIT(mn->mnctr_en_bit); | ||
183 | val &= ~mask; | ||
184 | |||
185 | if (n) { | ||
186 | val |= BIT(mn->mnctr_en_bit); | ||
187 | val |= MNCTR_MODE_DUAL << mn->mnctr_mode_shift; | ||
188 | } | ||
189 | |||
190 | return val; | ||
191 | } | ||
192 | |||
193 | static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) | ||
194 | { | ||
195 | u32 ns, md, ctl, *regp; | ||
196 | int bank, new_bank; | ||
197 | struct mn *mn; | ||
198 | struct pre_div *p; | ||
199 | struct src_sel *s; | ||
200 | bool enabled; | ||
201 | u32 md_reg; | ||
202 | u32 bank_reg; | ||
203 | bool banked_mn = !!rcg->mn[1].width; | ||
204 | struct clk_hw *hw = &rcg->clkr.hw; | ||
205 | |||
206 | enabled = __clk_is_enabled(hw->clk); | ||
207 | |||
208 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | ||
209 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | ||
210 | |||
211 | if (banked_mn) { | ||
212 | regp = &ctl; | ||
213 | bank_reg = rcg->clkr.enable_reg; | ||
214 | } else { | ||
215 | regp = &ns; | ||
216 | bank_reg = rcg->ns_reg; | ||
217 | } | ||
218 | |||
219 | bank = reg_to_bank(rcg, *regp); | ||
220 | new_bank = enabled ? !bank : bank; | ||
221 | |||
222 | if (banked_mn) { | ||
223 | mn = &rcg->mn[new_bank]; | ||
224 | md_reg = rcg->md_reg[new_bank]; | ||
225 | |||
226 | ns |= BIT(mn->mnctr_reset_bit); | ||
227 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | ||
228 | |||
229 | regmap_read(rcg->clkr.regmap, md_reg, &md); | ||
230 | md = mn_to_md(mn, f->m, f->n, md); | ||
231 | regmap_write(rcg->clkr.regmap, md_reg, md); | ||
232 | |||
233 | ns = mn_to_ns(mn, f->m, f->n, ns); | ||
234 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | ||
235 | |||
236 | ctl = mn_to_reg(mn, f->m, f->n, ctl); | ||
237 | regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl); | ||
238 | |||
239 | ns &= ~BIT(mn->mnctr_reset_bit); | ||
240 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | ||
241 | } else { | ||
242 | p = &rcg->p[new_bank]; | ||
243 | ns = pre_div_to_ns(p, f->pre_div - 1, ns); | ||
244 | } | ||
245 | |||
246 | s = &rcg->s[new_bank]; | ||
247 | ns = src_to_ns(s, s->parent_map[f->src], ns); | ||
248 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | ||
249 | |||
250 | if (enabled) { | ||
251 | *regp ^= BIT(rcg->mux_sel_bit); | ||
252 | regmap_write(rcg->clkr.regmap, bank_reg, *regp); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) | ||
257 | { | ||
258 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | ||
259 | u32 ns, ctl, md, reg; | ||
260 | int bank; | ||
261 | struct freq_tbl f = { 0 }; | ||
262 | bool banked_mn = !!rcg->mn[1].width; | ||
263 | |||
264 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | ||
265 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | ||
266 | reg = banked_mn ? ctl : ns; | ||
267 | |||
268 | bank = reg_to_bank(rcg, reg); | ||
269 | |||
270 | if (banked_mn) { | ||
271 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | ||
272 | f.m = md_to_m(&rcg->mn[bank], md); | ||
273 | f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); | ||
274 | } else { | ||
275 | f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; | ||
276 | } | ||
277 | f.src = index; | ||
278 | |||
279 | configure_bank(rcg, &f); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Calculate m/n:d rate | ||
286 | * | ||
287 | * parent_rate m | ||
288 | * rate = ----------- x --- | ||
289 | * pre_div n | ||
290 | */ | ||
291 | static unsigned long | ||
292 | calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 pre_div) | ||
293 | { | ||
294 | if (pre_div) | ||
295 | rate /= pre_div + 1; | ||
296 | |||
297 | if (mode) { | ||
298 | u64 tmp = rate; | ||
299 | tmp *= m; | ||
300 | do_div(tmp, n); | ||
301 | rate = tmp; | ||
302 | } | ||
303 | |||
304 | return rate; | ||
305 | } | ||
306 | |||
307 | static unsigned long | ||
308 | clk_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | ||
309 | { | ||
310 | struct clk_rcg *rcg = to_clk_rcg(hw); | ||
311 | u32 pre_div, m = 0, n = 0, ns, md, mode = 0; | ||
312 | struct mn *mn = &rcg->mn; | ||
313 | |||
314 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | ||
315 | pre_div = ns_to_pre_div(&rcg->p, ns); | ||
316 | |||
317 | if (rcg->mn.width) { | ||
318 | regmap_read(rcg->clkr.regmap, rcg->md_reg, &md); | ||
319 | m = md_to_m(mn, md); | ||
320 | n = ns_m_to_n(mn, ns, m); | ||
321 | /* MN counter mode is in hw.enable_reg sometimes */ | ||
322 | if (rcg->clkr.enable_reg != rcg->ns_reg) | ||
323 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &mode); | ||
324 | else | ||
325 | mode = ns; | ||
326 | mode = reg_to_mnctr_mode(mn, mode); | ||
327 | } | ||
328 | |||
329 | return calc_rate(parent_rate, m, n, mode, pre_div); | ||
330 | } | ||
331 | |||
332 | static unsigned long | ||
333 | clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | ||
334 | { | ||
335 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | ||
336 | u32 m, n, pre_div, ns, md, mode, reg; | ||
337 | int bank; | ||
338 | struct mn *mn; | ||
339 | bool banked_mn = !!rcg->mn[1].width; | ||
340 | |||
341 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | ||
342 | |||
343 | if (banked_mn) | ||
344 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, ®); | ||
345 | else | ||
346 | reg = ns; | ||
347 | |||
348 | bank = reg_to_bank(rcg, reg); | ||
349 | |||
350 | if (banked_mn) { | ||
351 | mn = &rcg->mn[bank]; | ||
352 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | ||
353 | m = md_to_m(mn, md); | ||
354 | n = ns_m_to_n(mn, ns, m); | ||
355 | mode = reg_to_mnctr_mode(mn, reg); | ||
356 | return calc_rate(parent_rate, m, n, mode, 0); | ||
357 | } else { | ||
358 | pre_div = ns_to_pre_div(&rcg->p[bank], ns); | ||
359 | return calc_rate(parent_rate, 0, 0, 0, pre_div); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | static const | ||
364 | struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate) | ||
365 | { | ||
366 | if (!f) | ||
367 | return NULL; | ||
368 | |||
369 | for (; f->freq; f++) | ||
370 | if (rate <= f->freq) | ||
371 | return f; | ||
372 | |||
373 | return NULL; | ||
374 | } | ||
375 | |||
376 | static long _freq_tbl_determine_rate(struct clk_hw *hw, | ||
377 | const struct freq_tbl *f, unsigned long rate, | ||
378 | unsigned long *p_rate, struct clk **p) | ||
379 | { | ||
380 | unsigned long clk_flags; | ||
381 | |||
382 | f = find_freq(f, rate); | ||
383 | if (!f) | ||
384 | return -EINVAL; | ||
385 | |||
386 | clk_flags = __clk_get_flags(hw->clk); | ||
387 | *p = clk_get_parent_by_index(hw->clk, f->src); | ||
388 | if (clk_flags & CLK_SET_RATE_PARENT) { | ||
389 | rate = rate * f->pre_div; | ||
390 | if (f->n) { | ||
391 | u64 tmp = rate; | ||
392 | tmp = tmp * f->n; | ||
393 | do_div(tmp, f->m); | ||
394 | rate = tmp; | ||
395 | } | ||
396 | } else { | ||
397 | rate = __clk_get_rate(*p); | ||
398 | } | ||
399 | *p_rate = rate; | ||
400 | |||
401 | return f->freq; | ||
402 | } | ||
403 | |||
404 | static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
405 | unsigned long *p_rate, struct clk **p) | ||
406 | { | ||
407 | struct clk_rcg *rcg = to_clk_rcg(hw); | ||
408 | |||
409 | return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); | ||
410 | } | ||
411 | |||
412 | static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
413 | unsigned long *p_rate, struct clk **p) | ||
414 | { | ||
415 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | ||
416 | |||
417 | return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); | ||
418 | } | ||
419 | |||
420 | static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate, | ||
421 | unsigned long parent_rate) | ||
422 | { | ||
423 | struct clk_rcg *rcg = to_clk_rcg(hw); | ||
424 | const struct freq_tbl *f; | ||
425 | u32 ns, md, ctl; | ||
426 | struct mn *mn = &rcg->mn; | ||
427 | u32 mask = 0; | ||
428 | unsigned int reset_reg; | ||
429 | |||
430 | f = find_freq(rcg->freq_tbl, rate); | ||
431 | if (!f) | ||
432 | return -EINVAL; | ||
433 | |||
434 | if (rcg->mn.reset_in_cc) | ||
435 | reset_reg = rcg->clkr.enable_reg; | ||
436 | else | ||
437 | reset_reg = rcg->ns_reg; | ||
438 | |||
439 | if (rcg->mn.width) { | ||
440 | mask = BIT(mn->mnctr_reset_bit); | ||
441 | regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, mask); | ||
442 | |||
443 | regmap_read(rcg->clkr.regmap, rcg->md_reg, &md); | ||
444 | md = mn_to_md(mn, f->m, f->n, md); | ||
445 | regmap_write(rcg->clkr.regmap, rcg->md_reg, md); | ||
446 | |||
447 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | ||
448 | /* MN counter mode is in hw.enable_reg sometimes */ | ||
449 | if (rcg->clkr.enable_reg != rcg->ns_reg) { | ||
450 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | ||
451 | ctl = mn_to_reg(mn, f->m, f->n, ctl); | ||
452 | regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl); | ||
453 | } else { | ||
454 | ns = mn_to_reg(mn, f->m, f->n, ns); | ||
455 | } | ||
456 | ns = mn_to_ns(mn, f->m, f->n, ns); | ||
457 | } else { | ||
458 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | ||
459 | } | ||
460 | |||
461 | ns = pre_div_to_ns(&rcg->p, f->pre_div - 1, ns); | ||
462 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | ||
463 | |||
464 | regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, 0); | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate) | ||
470 | { | ||
471 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | ||
472 | const struct freq_tbl *f; | ||
473 | |||
474 | f = find_freq(rcg->freq_tbl, rate); | ||
475 | if (!f) | ||
476 | return -EINVAL; | ||
477 | |||
478 | configure_bank(rcg, f); | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate, | ||
484 | unsigned long parent_rate) | ||
485 | { | ||
486 | return __clk_dyn_rcg_set_rate(hw, rate); | ||
487 | } | ||
488 | |||
489 | static int clk_dyn_rcg_set_rate_and_parent(struct clk_hw *hw, | ||
490 | unsigned long rate, unsigned long parent_rate, u8 index) | ||
491 | { | ||
492 | return __clk_dyn_rcg_set_rate(hw, rate); | ||
493 | } | ||
494 | |||
495 | const struct clk_ops clk_rcg_ops = { | ||
496 | .enable = clk_enable_regmap, | ||
497 | .disable = clk_disable_regmap, | ||
498 | .get_parent = clk_rcg_get_parent, | ||
499 | .set_parent = clk_rcg_set_parent, | ||
500 | .recalc_rate = clk_rcg_recalc_rate, | ||
501 | .determine_rate = clk_rcg_determine_rate, | ||
502 | .set_rate = clk_rcg_set_rate, | ||
503 | }; | ||
504 | EXPORT_SYMBOL_GPL(clk_rcg_ops); | ||
505 | |||
506 | const struct clk_ops clk_dyn_rcg_ops = { | ||
507 | .enable = clk_enable_regmap, | ||
508 | .is_enabled = clk_is_enabled_regmap, | ||
509 | .disable = clk_disable_regmap, | ||
510 | .get_parent = clk_dyn_rcg_get_parent, | ||
511 | .set_parent = clk_dyn_rcg_set_parent, | ||
512 | .recalc_rate = clk_dyn_rcg_recalc_rate, | ||
513 | .determine_rate = clk_dyn_rcg_determine_rate, | ||
514 | .set_rate = clk_dyn_rcg_set_rate, | ||
515 | .set_rate_and_parent = clk_dyn_rcg_set_rate_and_parent, | ||
516 | }; | ||
517 | EXPORT_SYMBOL_GPL(clk_dyn_rcg_ops); | ||
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h new file mode 100644 index 000000000000..1d6b6dece328 --- /dev/null +++ b/drivers/clk/qcom/clk-rcg.h | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #ifndef __QCOM_CLK_RCG_H__ | ||
15 | #define __QCOM_CLK_RCG_H__ | ||
16 | |||
17 | #include <linux/clk-provider.h> | ||
18 | #include "clk-regmap.h" | ||
19 | |||
20 | struct freq_tbl { | ||
21 | unsigned long freq; | ||
22 | u8 src; | ||
23 | u8 pre_div; | ||
24 | u16 m; | ||
25 | u16 n; | ||
26 | }; | ||
27 | |||
28 | /** | ||
29 | * struct mn - M/N:D counter | ||
30 | * @mnctr_en_bit: bit to enable mn counter | ||
31 | * @mnctr_reset_bit: bit to assert mn counter reset | ||
32 | * @mnctr_mode_shift: lowest bit of mn counter mode field | ||
33 | * @n_val_shift: lowest bit of n value field | ||
34 | * @m_val_shift: lowest bit of m value field | ||
35 | * @width: number of bits in m/n/d values | ||
36 | * @reset_in_cc: true if the mnctr_reset_bit is in the CC register | ||
37 | */ | ||
38 | struct mn { | ||
39 | u8 mnctr_en_bit; | ||
40 | u8 mnctr_reset_bit; | ||
41 | u8 mnctr_mode_shift; | ||
42 | #define MNCTR_MODE_DUAL 0x2 | ||
43 | #define MNCTR_MODE_MASK 0x3 | ||
44 | u8 n_val_shift; | ||
45 | u8 m_val_shift; | ||
46 | u8 width; | ||
47 | bool reset_in_cc; | ||
48 | }; | ||
49 | |||
50 | /** | ||
51 | * struct pre_div - pre-divider | ||
52 | * @pre_div_shift: lowest bit of pre divider field | ||
53 | * @pre_div_width: number of bits in predivider | ||
54 | */ | ||
55 | struct pre_div { | ||
56 | u8 pre_div_shift; | ||
57 | u8 pre_div_width; | ||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * struct src_sel - source selector | ||
62 | * @src_sel_shift: lowest bit of source selection field | ||
63 | * @parent_map: map from software's parent index to hardware's src_sel field | ||
64 | */ | ||
65 | struct src_sel { | ||
66 | u8 src_sel_shift; | ||
67 | #define SRC_SEL_MASK 0x7 | ||
68 | const u8 *parent_map; | ||
69 | }; | ||
70 | |||
71 | /** | ||
72 | * struct clk_rcg - root clock generator | ||
73 | * | ||
74 | * @ns_reg: NS register | ||
75 | * @md_reg: MD register | ||
76 | * @mn: mn counter | ||
77 | * @p: pre divider | ||
78 | * @s: source selector | ||
79 | * @freq_tbl: frequency table | ||
80 | * @clkr: regmap clock handle | ||
81 | * @lock: register lock | ||
82 | * | ||
83 | */ | ||
84 | struct clk_rcg { | ||
85 | u32 ns_reg; | ||
86 | u32 md_reg; | ||
87 | |||
88 | struct mn mn; | ||
89 | struct pre_div p; | ||
90 | struct src_sel s; | ||
91 | |||
92 | const struct freq_tbl *freq_tbl; | ||
93 | |||
94 | struct clk_regmap clkr; | ||
95 | }; | ||
96 | |||
97 | extern const struct clk_ops clk_rcg_ops; | ||
98 | |||
99 | #define to_clk_rcg(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg, clkr) | ||
100 | |||
101 | /** | ||
102 | * struct clk_dyn_rcg - root clock generator with glitch free mux | ||
103 | * | ||
104 | * @mux_sel_bit: bit to switch glitch free mux | ||
105 | * @ns_reg: NS register | ||
106 | * @md_reg: MD0 and MD1 register | ||
107 | * @mn: mn counter (banked) | ||
108 | * @s: source selector (banked) | ||
109 | * @freq_tbl: frequency table | ||
110 | * @clkr: regmap clock handle | ||
111 | * @lock: register lock | ||
112 | * | ||
113 | */ | ||
114 | struct clk_dyn_rcg { | ||
115 | u32 ns_reg; | ||
116 | u32 md_reg[2]; | ||
117 | |||
118 | u8 mux_sel_bit; | ||
119 | |||
120 | struct mn mn[2]; | ||
121 | struct pre_div p[2]; | ||
122 | struct src_sel s[2]; | ||
123 | |||
124 | const struct freq_tbl *freq_tbl; | ||
125 | |||
126 | struct clk_regmap clkr; | ||
127 | }; | ||
128 | |||
129 | extern const struct clk_ops clk_dyn_rcg_ops; | ||
130 | |||
131 | #define to_clk_dyn_rcg(_hw) \ | ||
132 | container_of(to_clk_regmap(_hw), struct clk_dyn_rcg, clkr) | ||
133 | |||
134 | /** | ||
135 | * struct clk_rcg2 - root clock generator | ||
136 | * | ||
137 | * @cmd_rcgr: corresponds to *_CMD_RCGR | ||
138 | * @mnd_width: number of bits in m/n/d values | ||
139 | * @hid_width: number of bits in half integer divider | ||
140 | * @parent_map: map from software's parent index to hardware's src_sel field | ||
141 | * @freq_tbl: frequency table | ||
142 | * @clkr: regmap clock handle | ||
143 | * @lock: register lock | ||
144 | * | ||
145 | */ | ||
146 | struct clk_rcg2 { | ||
147 | u32 cmd_rcgr; | ||
148 | u8 mnd_width; | ||
149 | u8 hid_width; | ||
150 | const u8 *parent_map; | ||
151 | const struct freq_tbl *freq_tbl; | ||
152 | struct clk_regmap clkr; | ||
153 | }; | ||
154 | |||
155 | #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) | ||
156 | |||
157 | extern const struct clk_ops clk_rcg2_ops; | ||
158 | |||
159 | #endif | ||
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c new file mode 100644 index 000000000000..00f878a04d3f --- /dev/null +++ b/drivers/clk/qcom/clk-rcg2.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/bitops.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/bug.h> | ||
18 | #include <linux/export.h> | ||
19 | #include <linux/clk-provider.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/regmap.h> | ||
22 | |||
23 | #include <asm/div64.h> | ||
24 | |||
25 | #include "clk-rcg.h" | ||
26 | |||
27 | #define CMD_REG 0x0 | ||
28 | #define CMD_UPDATE BIT(0) | ||
29 | #define CMD_ROOT_EN BIT(1) | ||
30 | #define CMD_DIRTY_CFG BIT(4) | ||
31 | #define CMD_DIRTY_N BIT(5) | ||
32 | #define CMD_DIRTY_M BIT(6) | ||
33 | #define CMD_DIRTY_D BIT(7) | ||
34 | #define CMD_ROOT_OFF BIT(31) | ||
35 | |||
36 | #define CFG_REG 0x4 | ||
37 | #define CFG_SRC_DIV_SHIFT 0 | ||
38 | #define CFG_SRC_SEL_SHIFT 8 | ||
39 | #define CFG_SRC_SEL_MASK (0x7 << CFG_SRC_SEL_SHIFT) | ||
40 | #define CFG_MODE_SHIFT 12 | ||
41 | #define CFG_MODE_MASK (0x3 << CFG_MODE_SHIFT) | ||
42 | #define CFG_MODE_DUAL_EDGE (0x2 << CFG_MODE_SHIFT) | ||
43 | |||
44 | #define M_REG 0x8 | ||
45 | #define N_REG 0xc | ||
46 | #define D_REG 0x10 | ||
47 | |||
48 | static int clk_rcg2_is_enabled(struct clk_hw *hw) | ||
49 | { | ||
50 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
51 | u32 cmd; | ||
52 | int ret; | ||
53 | |||
54 | ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd); | ||
55 | if (ret) | ||
56 | return ret; | ||
57 | |||
58 | return (cmd & CMD_ROOT_OFF) != 0; | ||
59 | } | ||
60 | |||
61 | static u8 clk_rcg2_get_parent(struct clk_hw *hw) | ||
62 | { | ||
63 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
64 | int num_parents = __clk_get_num_parents(hw->clk); | ||
65 | u32 cfg; | ||
66 | int i, ret; | ||
67 | |||
68 | ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); | ||
69 | if (ret) | ||
70 | return ret; | ||
71 | |||
72 | cfg &= CFG_SRC_SEL_MASK; | ||
73 | cfg >>= CFG_SRC_SEL_SHIFT; | ||
74 | |||
75 | for (i = 0; i < num_parents; i++) | ||
76 | if (cfg == rcg->parent_map[i]) | ||
77 | return i; | ||
78 | |||
79 | return -EINVAL; | ||
80 | } | ||
81 | |||
82 | static int update_config(struct clk_rcg2 *rcg) | ||
83 | { | ||
84 | int count, ret; | ||
85 | u32 cmd; | ||
86 | struct clk_hw *hw = &rcg->clkr.hw; | ||
87 | const char *name = __clk_get_name(hw->clk); | ||
88 | |||
89 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, | ||
90 | CMD_UPDATE, CMD_UPDATE); | ||
91 | if (ret) | ||
92 | return ret; | ||
93 | |||
94 | /* Wait for update to take effect */ | ||
95 | for (count = 500; count > 0; count--) { | ||
96 | ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd); | ||
97 | if (ret) | ||
98 | return ret; | ||
99 | if (!(cmd & CMD_UPDATE)) | ||
100 | return 0; | ||
101 | udelay(1); | ||
102 | } | ||
103 | |||
104 | WARN(1, "%s: rcg didn't update its configuration.", name); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) | ||
109 | { | ||
110 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
111 | int ret; | ||
112 | |||
113 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | ||
114 | CFG_SRC_SEL_MASK, | ||
115 | rcg->parent_map[index] << CFG_SRC_SEL_SHIFT); | ||
116 | if (ret) | ||
117 | return ret; | ||
118 | |||
119 | return update_config(rcg); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Calculate m/n:d rate | ||
124 | * | ||
125 | * parent_rate m | ||
126 | * rate = ----------- x --- | ||
127 | * hid_div n | ||
128 | */ | ||
129 | static unsigned long | ||
130 | calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div) | ||
131 | { | ||
132 | if (hid_div) { | ||
133 | rate *= 2; | ||
134 | rate /= hid_div + 1; | ||
135 | } | ||
136 | |||
137 | if (mode) { | ||
138 | u64 tmp = rate; | ||
139 | tmp *= m; | ||
140 | do_div(tmp, n); | ||
141 | rate = tmp; | ||
142 | } | ||
143 | |||
144 | return rate; | ||
145 | } | ||
146 | |||
147 | static unsigned long | ||
148 | clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | ||
149 | { | ||
150 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
151 | u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask; | ||
152 | |||
153 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); | ||
154 | |||
155 | if (rcg->mnd_width) { | ||
156 | mask = BIT(rcg->mnd_width) - 1; | ||
157 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m); | ||
158 | m &= mask; | ||
159 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n); | ||
160 | n = ~n; | ||
161 | n &= mask; | ||
162 | n += m; | ||
163 | mode = cfg & CFG_MODE_MASK; | ||
164 | mode >>= CFG_MODE_SHIFT; | ||
165 | } | ||
166 | |||
167 | mask = BIT(rcg->hid_width) - 1; | ||
168 | hid_div = cfg >> CFG_SRC_DIV_SHIFT; | ||
169 | hid_div &= mask; | ||
170 | |||
171 | return calc_rate(parent_rate, m, n, mode, hid_div); | ||
172 | } | ||
173 | |||
174 | static const | ||
175 | struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate) | ||
176 | { | ||
177 | if (!f) | ||
178 | return NULL; | ||
179 | |||
180 | for (; f->freq; f++) | ||
181 | if (rate <= f->freq) | ||
182 | return f; | ||
183 | |||
184 | return NULL; | ||
185 | } | ||
186 | |||
187 | static long _freq_tbl_determine_rate(struct clk_hw *hw, | ||
188 | const struct freq_tbl *f, unsigned long rate, | ||
189 | unsigned long *p_rate, struct clk **p) | ||
190 | { | ||
191 | unsigned long clk_flags; | ||
192 | |||
193 | f = find_freq(f, rate); | ||
194 | if (!f) | ||
195 | return -EINVAL; | ||
196 | |||
197 | clk_flags = __clk_get_flags(hw->clk); | ||
198 | *p = clk_get_parent_by_index(hw->clk, f->src); | ||
199 | if (clk_flags & CLK_SET_RATE_PARENT) { | ||
200 | if (f->pre_div) { | ||
201 | rate /= 2; | ||
202 | rate *= f->pre_div + 1; | ||
203 | } | ||
204 | |||
205 | if (f->n) { | ||
206 | u64 tmp = rate; | ||
207 | tmp = tmp * f->n; | ||
208 | do_div(tmp, f->m); | ||
209 | rate = tmp; | ||
210 | } | ||
211 | } else { | ||
212 | rate = __clk_get_rate(*p); | ||
213 | } | ||
214 | *p_rate = rate; | ||
215 | |||
216 | return f->freq; | ||
217 | } | ||
218 | |||
219 | static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
220 | unsigned long *p_rate, struct clk **p) | ||
221 | { | ||
222 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
223 | |||
224 | return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); | ||
225 | } | ||
226 | |||
227 | static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) | ||
228 | { | ||
229 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
230 | const struct freq_tbl *f; | ||
231 | u32 cfg, mask; | ||
232 | int ret; | ||
233 | |||
234 | f = find_freq(rcg->freq_tbl, rate); | ||
235 | if (!f) | ||
236 | return -EINVAL; | ||
237 | |||
238 | if (rcg->mnd_width && f->n) { | ||
239 | mask = BIT(rcg->mnd_width) - 1; | ||
240 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, | ||
241 | mask, f->m); | ||
242 | if (ret) | ||
243 | return ret; | ||
244 | |||
245 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, | ||
246 | mask, ~(f->n - f->m)); | ||
247 | if (ret) | ||
248 | return ret; | ||
249 | |||
250 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + D_REG, | ||
251 | mask, ~f->n); | ||
252 | if (ret) | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | mask = BIT(rcg->hid_width) - 1; | ||
257 | mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK; | ||
258 | cfg = f->pre_div << CFG_SRC_DIV_SHIFT; | ||
259 | cfg |= rcg->parent_map[f->src] << CFG_SRC_SEL_SHIFT; | ||
260 | if (rcg->mnd_width && f->n) | ||
261 | cfg |= CFG_MODE_DUAL_EDGE; | ||
262 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, mask, | ||
263 | cfg); | ||
264 | if (ret) | ||
265 | return ret; | ||
266 | |||
267 | return update_config(rcg); | ||
268 | } | ||
269 | |||
270 | static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, | ||
271 | unsigned long parent_rate) | ||
272 | { | ||
273 | return __clk_rcg2_set_rate(hw, rate); | ||
274 | } | ||
275 | |||
276 | static int clk_rcg2_set_rate_and_parent(struct clk_hw *hw, | ||
277 | unsigned long rate, unsigned long parent_rate, u8 index) | ||
278 | { | ||
279 | return __clk_rcg2_set_rate(hw, rate); | ||
280 | } | ||
281 | |||
282 | const struct clk_ops clk_rcg2_ops = { | ||
283 | .is_enabled = clk_rcg2_is_enabled, | ||
284 | .get_parent = clk_rcg2_get_parent, | ||
285 | .set_parent = clk_rcg2_set_parent, | ||
286 | .recalc_rate = clk_rcg2_recalc_rate, | ||
287 | .determine_rate = clk_rcg2_determine_rate, | ||
288 | .set_rate = clk_rcg2_set_rate, | ||
289 | .set_rate_and_parent = clk_rcg2_set_rate_and_parent, | ||
290 | }; | ||
291 | EXPORT_SYMBOL_GPL(clk_rcg2_ops); | ||