]>
git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - drivers/clk/clk-divider.c
2 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
3 * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
4 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Adjustable divider clock implementation
13 #include <linux/clk-provider.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
17 #include <linux/err.h>
18 #include <linux/string.h>
21 * DOC: basic adjustable divider clock that cannot gate
23 * Traits of this clock:
24 * prepare - clk_prepare only ensures that parents are prepared
25 * enable - clk_enable only ensures that parents are enabled
26 * rate - rate is adjustable. clk->rate = parent->rate / divisor
27 * parent - fixed parent. No clk_set_parent support
30 #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
32 #define div_mask(d) ((1 << (d->width)) - 1)
34 static unsigned long clk_divider_recalc_rate(struct clk_hw
*hw
,
35 unsigned long parent_rate
)
37 struct clk_divider
*divider
= to_clk_divider(hw
);
40 div
= readl(divider
->reg
) >> divider
->shift
;
41 div
&= div_mask(divider
);
43 if (!(divider
->flags
& CLK_DIVIDER_ONE_BASED
))
46 return parent_rate
/ div
;
48 EXPORT_SYMBOL_GPL(clk_divider_recalc_rate
);
51 * The reverse of DIV_ROUND_UP: The maximum number which
54 #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
56 static int clk_divider_bestdiv(struct clk_hw
*hw
, unsigned long rate
,
57 unsigned long *best_parent_rate
)
59 struct clk_divider
*divider
= to_clk_divider(hw
);
61 unsigned long parent_rate
, best
= 0, now
, maxdiv
;
66 maxdiv
= (1 << divider
->width
);
68 if (divider
->flags
& CLK_DIVIDER_ONE_BASED
)
71 if (!best_parent_rate
) {
72 parent_rate
= __clk_get_rate(__clk_get_parent(hw
->clk
));
73 bestdiv
= DIV_ROUND_UP(parent_rate
, rate
);
74 bestdiv
= bestdiv
== 0 ? 1 : bestdiv
;
75 bestdiv
= bestdiv
> maxdiv
? maxdiv
: bestdiv
;
80 * The maximum divider we can use without overflowing
81 * unsigned long in rate * i below
83 maxdiv
= min(ULONG_MAX
/ rate
, maxdiv
);
85 for (i
= 1; i
<= maxdiv
; i
++) {
86 parent_rate
= __clk_round_rate(__clk_get_parent(hw
->clk
),
87 MULT_ROUND_UP(rate
, i
));
88 now
= parent_rate
/ i
;
89 if (now
<= rate
&& now
> best
) {
92 *best_parent_rate
= parent_rate
;
97 bestdiv
= (1 << divider
->width
);
98 if (divider
->flags
& CLK_DIVIDER_ONE_BASED
)
100 *best_parent_rate
= __clk_round_rate(__clk_get_parent(hw
->clk
), 1);
106 static long clk_divider_round_rate(struct clk_hw
*hw
, unsigned long rate
,
107 unsigned long *prate
)
110 div
= clk_divider_bestdiv(hw
, rate
, prate
);
116 r
= __clk_get_rate(__clk_get_parent(hw
->clk
));
120 EXPORT_SYMBOL_GPL(clk_divider_round_rate
);
122 static int clk_divider_set_rate(struct clk_hw
*hw
, unsigned long rate
)
124 struct clk_divider
*divider
= to_clk_divider(hw
);
126 unsigned long flags
= 0;
129 div
= __clk_get_rate(__clk_get_parent(hw
->clk
)) / rate
;
131 if (!(divider
->flags
& CLK_DIVIDER_ONE_BASED
))
134 if (div
> div_mask(divider
))
135 div
= div_mask(divider
);
138 spin_lock_irqsave(divider
->lock
, flags
);
140 val
= readl(divider
->reg
);
141 val
&= ~(div_mask(divider
) << divider
->shift
);
142 val
|= div
<< divider
->shift
;
143 writel(val
, divider
->reg
);
146 spin_unlock_irqrestore(divider
->lock
, flags
);
150 EXPORT_SYMBOL_GPL(clk_divider_set_rate
);
152 struct clk_ops clk_divider_ops
= {
153 .recalc_rate
= clk_divider_recalc_rate
,
154 .round_rate
= clk_divider_round_rate
,
155 .set_rate
= clk_divider_set_rate
,
157 EXPORT_SYMBOL_GPL(clk_divider_ops
);
159 struct clk
*clk_register_divider(struct device
*dev
, const char *name
,
160 const char *parent_name
, unsigned long flags
,
161 void __iomem
*reg
, u8 shift
, u8 width
,
162 u8 clk_divider_flags
, spinlock_t
*lock
)
164 struct clk_divider
*div
;
167 div
= kzalloc(sizeof(struct clk_divider
), GFP_KERNEL
);
170 pr_err("%s: could not allocate divider clk\n", __func__
);
174 /* struct clk_divider assignments */
178 div
->flags
= clk_divider_flags
;
182 div
->parent
[0] = kstrdup(parent_name
, GFP_KERNEL
);
187 clk
= clk_register(dev
, name
,
188 &clk_divider_ops
, &div
->hw
,
190 (parent_name
? 1 : 0),
196 kfree(div
->parent
[0]);