aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2014-01-15 13:47:25 -0500
committerMike Turquette <mturquette@linaro.org>2014-01-16 15:01:00 -0500
commitbcd61c0f535a04a2aaa3f3ba27e60fae681fc88f (patch)
tree81fbb7830130ed91c207a3f088a9b5683a9f089e /drivers/clk
parent9e2631313c463c11645db046beb9bdecaf28b62f (diff)
clk: qcom: Add support for root clock generators (RCGs)
Add support for the root clock generators on Qualcomm devices. RCGs are highly customizable mux/divider/counter clocks that can be used to generate almost any rate desired given some input source that is faster than the desired rate. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/qcom/Makefile2
-rw-r--r--drivers/clk/qcom/clk-rcg.c517
-rw-r--r--drivers/clk/qcom/clk-rcg.h159
-rw-r--r--drivers/clk/qcom/clk-rcg2.c291
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
3clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-regmap.o 3clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-regmap.o
4clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-pll.o 4clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-pll.o
5clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-rcg.o
6clk-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
25static 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
32static 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
44static 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
60static int reg_to_bank(struct clk_dyn_rcg *rcg, u32 bank)
61{
62 bank &= BIT(rcg->mux_sel_bit);
63 return !!bank;
64}
65
66static 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
89static 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
101static 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
108static 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
115static 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
127static 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
144static 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
151static 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
158static 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
177static 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
193static 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
256static 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 */
291static unsigned long
292calc_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
307static unsigned long
308clk_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
332static unsigned long
333clk_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, &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
363static const
364struct 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
376static 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
404static 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
412static 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
420static 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
469static 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
483static 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
489static 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
495const 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};
504EXPORT_SYMBOL_GPL(clk_rcg_ops);
505
506const 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};
517EXPORT_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
20struct 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 */
38struct 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 */
55struct 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 */
65struct 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 */
84struct 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
97extern 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 */
114struct 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
129extern 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 */
146struct 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
157extern 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
48static 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
61static 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
82static 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
108static 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 */
129static unsigned long
130calc_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
147static unsigned long
148clk_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
174static const
175struct 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
187static 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
219static 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
227static 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
270static 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
276static 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
282const 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};
291EXPORT_SYMBOL_GPL(clk_rcg2_ops);