Merge tag 'common-clk-api' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[~shefty/rdma-dev.git] / drivers / clk / clk-divider.c
1 /*
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>
5  *
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.
9  *
10  * Adjustable divider clock implementation
11  */
12
13 #include <linux/clk-provider.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/io.h>
17 #include <linux/err.h>
18 #include <linux/string.h>
19
20 /*
21  * DOC: basic adjustable divider clock that cannot gate
22  *
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
28  */
29
30 #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
31
32 #define div_mask(d)     ((1 << (d->width)) - 1)
33
34 static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
35                 unsigned long parent_rate)
36 {
37         struct clk_divider *divider = to_clk_divider(hw);
38         unsigned int div;
39
40         div = readl(divider->reg) >> divider->shift;
41         div &= div_mask(divider);
42
43         if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
44                 div++;
45
46         return parent_rate / div;
47 }
48 EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
49
50 /*
51  * The reverse of DIV_ROUND_UP: The maximum number which
52  * divided by m is r
53  */
54 #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
55
56 static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
57                 unsigned long *best_parent_rate)
58 {
59         struct clk_divider *divider = to_clk_divider(hw);
60         int i, bestdiv = 0;
61         unsigned long parent_rate, best = 0, now, maxdiv;
62
63         if (!rate)
64                 rate = 1;
65
66         maxdiv = (1 << divider->width);
67
68         if (divider->flags & CLK_DIVIDER_ONE_BASED)
69                 maxdiv--;
70
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;
76                 return bestdiv;
77         }
78
79         /*
80          * The maximum divider we can use without overflowing
81          * unsigned long in rate * i below
82          */
83         maxdiv = min(ULONG_MAX / rate, maxdiv);
84
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) {
90                         bestdiv = i;
91                         best = now;
92                         *best_parent_rate = parent_rate;
93                 }
94         }
95
96         if (!bestdiv) {
97                 bestdiv = (1 << divider->width);
98                 if (divider->flags & CLK_DIVIDER_ONE_BASED)
99                         bestdiv--;
100                 *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
101         }
102
103         return bestdiv;
104 }
105
106 static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
107                                 unsigned long *prate)
108 {
109         int div;
110         div = clk_divider_bestdiv(hw, rate, prate);
111
112         if (prate)
113                 return *prate / div;
114         else {
115                 unsigned long r;
116                 r = __clk_get_rate(__clk_get_parent(hw->clk));
117                 return r / div;
118         }
119 }
120 EXPORT_SYMBOL_GPL(clk_divider_round_rate);
121
122 static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate)
123 {
124         struct clk_divider *divider = to_clk_divider(hw);
125         unsigned int div;
126         unsigned long flags = 0;
127         u32 val;
128
129         div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate;
130
131         if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
132                 div--;
133
134         if (div > div_mask(divider))
135                 div = div_mask(divider);
136
137         if (divider->lock)
138                 spin_lock_irqsave(divider->lock, flags);
139
140         val = readl(divider->reg);
141         val &= ~(div_mask(divider) << divider->shift);
142         val |= div << divider->shift;
143         writel(val, divider->reg);
144
145         if (divider->lock)
146                 spin_unlock_irqrestore(divider->lock, flags);
147
148         return 0;
149 }
150 EXPORT_SYMBOL_GPL(clk_divider_set_rate);
151
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,
156 };
157 EXPORT_SYMBOL_GPL(clk_divider_ops);
158
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)
163 {
164         struct clk_divider *div;
165         struct clk *clk;
166
167         div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
168
169         if (!div) {
170                 pr_err("%s: could not allocate divider clk\n", __func__);
171                 return NULL;
172         }
173
174         /* struct clk_divider assignments */
175         div->reg = reg;
176         div->shift = shift;
177         div->width = width;
178         div->flags = clk_divider_flags;
179         div->lock = lock;
180
181         if (parent_name) {
182                 div->parent[0] = kstrdup(parent_name, GFP_KERNEL);
183                 if (!div->parent[0])
184                         goto out;
185         }
186
187         clk = clk_register(dev, name,
188                         &clk_divider_ops, &div->hw,
189                         div->parent,
190                         (parent_name ? 1 : 0),
191                         flags);
192         if (clk)
193                 return clk;
194
195 out:
196         kfree(div->parent[0]);
197         kfree(div);
198
199         return NULL;
200 }