diff options
Diffstat (limited to 'drivers/clk/clk-divider.c')
-rw-r--r-- | drivers/clk/clk-divider.c | 125 |
1 files changed, 109 insertions, 16 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index e548c4328f3c..02a4da98176b 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c | |||
@@ -32,30 +32,69 @@ | |||
32 | #define div_mask(d) ((1 << (d->width)) - 1) | 32 | #define div_mask(d) ((1 << (d->width)) - 1) |
33 | #define is_power_of_two(i) !(i & ~i) | 33 | #define is_power_of_two(i) !(i & ~i) |
34 | 34 | ||
35 | static unsigned int _get_table_maxdiv(const struct clk_div_table *table) | ||
36 | { | ||
37 | unsigned int maxdiv = 0; | ||
38 | const struct clk_div_table *clkt; | ||
39 | |||
40 | for (clkt = table; clkt->div; clkt++) | ||
41 | if (clkt->div > maxdiv) | ||
42 | maxdiv = clkt->div; | ||
43 | return maxdiv; | ||
44 | } | ||
45 | |||
35 | static unsigned int _get_maxdiv(struct clk_divider *divider) | 46 | static unsigned int _get_maxdiv(struct clk_divider *divider) |
36 | { | 47 | { |
37 | if (divider->flags & CLK_DIVIDER_ONE_BASED) | 48 | if (divider->flags & CLK_DIVIDER_ONE_BASED) |
38 | return div_mask(divider); | 49 | return div_mask(divider); |
39 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 50 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) |
40 | return 1 << div_mask(divider); | 51 | return 1 << div_mask(divider); |
52 | if (divider->table) | ||
53 | return _get_table_maxdiv(divider->table); | ||
41 | return div_mask(divider) + 1; | 54 | return div_mask(divider) + 1; |
42 | } | 55 | } |
43 | 56 | ||
57 | static unsigned int _get_table_div(const struct clk_div_table *table, | ||
58 | unsigned int val) | ||
59 | { | ||
60 | const struct clk_div_table *clkt; | ||
61 | |||
62 | for (clkt = table; clkt->div; clkt++) | ||
63 | if (clkt->val == val) | ||
64 | return clkt->div; | ||
65 | return 0; | ||
66 | } | ||
67 | |||
44 | static unsigned int _get_div(struct clk_divider *divider, unsigned int val) | 68 | static unsigned int _get_div(struct clk_divider *divider, unsigned int val) |
45 | { | 69 | { |
46 | if (divider->flags & CLK_DIVIDER_ONE_BASED) | 70 | if (divider->flags & CLK_DIVIDER_ONE_BASED) |
47 | return val; | 71 | return val; |
48 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 72 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) |
49 | return 1 << val; | 73 | return 1 << val; |
74 | if (divider->table) | ||
75 | return _get_table_div(divider->table, val); | ||
50 | return val + 1; | 76 | return val + 1; |
51 | } | 77 | } |
52 | 78 | ||
79 | static unsigned int _get_table_val(const struct clk_div_table *table, | ||
80 | unsigned int div) | ||
81 | { | ||
82 | const struct clk_div_table *clkt; | ||
83 | |||
84 | for (clkt = table; clkt->div; clkt++) | ||
85 | if (clkt->div == div) | ||
86 | return clkt->val; | ||
87 | return 0; | ||
88 | } | ||
89 | |||
53 | static unsigned int _get_val(struct clk_divider *divider, u8 div) | 90 | static unsigned int _get_val(struct clk_divider *divider, u8 div) |
54 | { | 91 | { |
55 | if (divider->flags & CLK_DIVIDER_ONE_BASED) | 92 | if (divider->flags & CLK_DIVIDER_ONE_BASED) |
56 | return div; | 93 | return div; |
57 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 94 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) |
58 | return __ffs(div); | 95 | return __ffs(div); |
96 | if (divider->table) | ||
97 | return _get_table_val(divider->table, div); | ||
59 | return div - 1; | 98 | return div - 1; |
60 | } | 99 | } |
61 | 100 | ||
@@ -84,6 +123,26 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, | |||
84 | */ | 123 | */ |
85 | #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) | 124 | #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) |
86 | 125 | ||
126 | static bool _is_valid_table_div(const struct clk_div_table *table, | ||
127 | unsigned int div) | ||
128 | { | ||
129 | const struct clk_div_table *clkt; | ||
130 | |||
131 | for (clkt = table; clkt->div; clkt++) | ||
132 | if (clkt->div == div) | ||
133 | return true; | ||
134 | return false; | ||
135 | } | ||
136 | |||
137 | static bool _is_valid_div(struct clk_divider *divider, unsigned int div) | ||
138 | { | ||
139 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | ||
140 | return is_power_of_two(div); | ||
141 | if (divider->table) | ||
142 | return _is_valid_table_div(divider->table, div); | ||
143 | return true; | ||
144 | } | ||
145 | |||
87 | static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | 146 | static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, |
88 | unsigned long *best_parent_rate) | 147 | unsigned long *best_parent_rate) |
89 | { | 148 | { |
@@ -111,8 +170,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | |||
111 | maxdiv = min(ULONG_MAX / rate, maxdiv); | 170 | maxdiv = min(ULONG_MAX / rate, maxdiv); |
112 | 171 | ||
113 | for (i = 1; i <= maxdiv; i++) { | 172 | for (i = 1; i <= maxdiv; i++) { |
114 | if ((divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 173 | if (!_is_valid_div(divider, i)) |
115 | && (!is_power_of_two(i))) | ||
116 | continue; | 174 | continue; |
117 | parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), | 175 | parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), |
118 | MULT_ROUND_UP(rate, i)); | 176 | MULT_ROUND_UP(rate, i)); |
@@ -176,22 +234,11 @@ const struct clk_ops clk_divider_ops = { | |||
176 | }; | 234 | }; |
177 | EXPORT_SYMBOL_GPL(clk_divider_ops); | 235 | EXPORT_SYMBOL_GPL(clk_divider_ops); |
178 | 236 | ||
179 | /** | 237 | static struct clk *_register_divider(struct device *dev, const char *name, |
180 | * clk_register_divider - register a divider clock with the clock framework | ||
181 | * @dev: device registering this clock | ||
182 | * @name: name of this clock | ||
183 | * @parent_name: name of clock's parent | ||
184 | * @flags: framework-specific flags | ||
185 | * @reg: register address to adjust divider | ||
186 | * @shift: number of bits to shift the bitfield | ||
187 | * @width: width of the bitfield | ||
188 | * @clk_divider_flags: divider-specific flags for this clock | ||
189 | * @lock: shared register lock for this clock | ||
190 | */ | ||
191 | struct clk *clk_register_divider(struct device *dev, const char *name, | ||
192 | const char *parent_name, unsigned long flags, | 238 | const char *parent_name, unsigned long flags, |
193 | void __iomem *reg, u8 shift, u8 width, | 239 | void __iomem *reg, u8 shift, u8 width, |
194 | u8 clk_divider_flags, spinlock_t *lock) | 240 | u8 clk_divider_flags, const struct clk_div_table *table, |
241 | spinlock_t *lock) | ||
195 | { | 242 | { |
196 | struct clk_divider *div; | 243 | struct clk_divider *div; |
197 | struct clk *clk; | 244 | struct clk *clk; |
@@ -217,6 +264,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name, | |||
217 | div->flags = clk_divider_flags; | 264 | div->flags = clk_divider_flags; |
218 | div->lock = lock; | 265 | div->lock = lock; |
219 | div->hw.init = &init; | 266 | div->hw.init = &init; |
267 | div->table = table; | ||
220 | 268 | ||
221 | /* register the clock */ | 269 | /* register the clock */ |
222 | clk = clk_register(dev, &div->hw); | 270 | clk = clk_register(dev, &div->hw); |
@@ -226,3 +274,48 @@ struct clk *clk_register_divider(struct device *dev, const char *name, | |||
226 | 274 | ||
227 | return clk; | 275 | return clk; |
228 | } | 276 | } |
277 | |||
278 | /** | ||
279 | * clk_register_divider - register a divider clock with the clock framework | ||
280 | * @dev: device registering this clock | ||
281 | * @name: name of this clock | ||
282 | * @parent_name: name of clock's parent | ||
283 | * @flags: framework-specific flags | ||
284 | * @reg: register address to adjust divider | ||
285 | * @shift: number of bits to shift the bitfield | ||
286 | * @width: width of the bitfield | ||
287 | * @clk_divider_flags: divider-specific flags for this clock | ||
288 | * @lock: shared register lock for this clock | ||
289 | */ | ||
290 | struct clk *clk_register_divider(struct device *dev, const char *name, | ||
291 | const char *parent_name, unsigned long flags, | ||
292 | void __iomem *reg, u8 shift, u8 width, | ||
293 | u8 clk_divider_flags, spinlock_t *lock) | ||
294 | { | ||
295 | return _register_divider(dev, name, parent_name, flags, reg, shift, | ||
296 | width, clk_divider_flags, NULL, lock); | ||
297 | } | ||
298 | |||
299 | /** | ||
300 | * clk_register_divider_table - register a table based divider clock with | ||
301 | * the clock framework | ||
302 | * @dev: device registering this clock | ||
303 | * @name: name of this clock | ||
304 | * @parent_name: name of clock's parent | ||
305 | * @flags: framework-specific flags | ||
306 | * @reg: register address to adjust divider | ||
307 | * @shift: number of bits to shift the bitfield | ||
308 | * @width: width of the bitfield | ||
309 | * @clk_divider_flags: divider-specific flags for this clock | ||
310 | * @table: array of divider/value pairs ending with a div set to 0 | ||
311 | * @lock: shared register lock for this clock | ||
312 | */ | ||
313 | struct clk *clk_register_divider_table(struct device *dev, const char *name, | ||
314 | const char *parent_name, unsigned long flags, | ||
315 | void __iomem *reg, u8 shift, u8 width, | ||
316 | u8 clk_divider_flags, const struct clk_div_table *table, | ||
317 | spinlock_t *lock) | ||
318 | { | ||
319 | return _register_divider(dev, name, parent_name, flags, reg, shift, | ||
320 | width, clk_divider_flags, table, lock); | ||
321 | } | ||