diff options
author | viresh kumar <viresh.kumar@st.com> | 2011-02-16 01:40:39 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-03-09 04:49:45 -0500 |
commit | af89fd812b00a52c54a3b9b2290fae4d31c7be9a (patch) | |
tree | 3892de4165b23e98424f672c23b7a6d456ad235d /arch/arm/plat-spear | |
parent | cf285434ac0880f94bf4afdd90b06a4655f56570 (diff) |
ARM: 6703/1: SPEAr: update clk API support
- Add support for divisor per parent clock
- Add ENABLED_ON_INIT feature in clk
- Add clk_set_rate(), round_rate_index & clk_round_rate()
- Simplify clk_recalc functions
- Add/update clock definitions
Reviewed-by: Stanley Miao <stanley.miao@windriver.com>
Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
Signed-off-by: shiraz hashim <shiraz.hashim@st.com>
Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/plat-spear')
-rw-r--r-- | arch/arm/plat-spear/clock.c | 705 | ||||
-rw-r--r-- | arch/arm/plat-spear/include/plat/clock.h | 94 |
2 files changed, 649 insertions, 150 deletions
diff --git a/arch/arm/plat-spear/clock.c b/arch/arm/plat-spear/clock.c index f1cf832e4e3b..7e7ab606dc49 100644 --- a/arch/arm/plat-spear/clock.c +++ b/arch/arm/plat-spear/clock.c | |||
@@ -12,6 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/bug.h> | 14 | #include <linux/bug.h> |
15 | #include <linux/clk.h> | ||
15 | #include <linux/err.h> | 16 | #include <linux/err.h> |
16 | #include <linux/io.h> | 17 | #include <linux/io.h> |
17 | #include <linux/list.h> | 18 | #include <linux/list.h> |
@@ -22,7 +23,7 @@ | |||
22 | static DEFINE_SPINLOCK(clocks_lock); | 23 | static DEFINE_SPINLOCK(clocks_lock); |
23 | static LIST_HEAD(root_clks); | 24 | static LIST_HEAD(root_clks); |
24 | 25 | ||
25 | static void propagate_rate(struct list_head *); | 26 | static void propagate_rate(struct clk *, int on_init); |
26 | 27 | ||
27 | static int generic_clk_enable(struct clk *clk) | 28 | static int generic_clk_enable(struct clk *clk) |
28 | { | 29 | { |
@@ -64,6 +65,100 @@ static struct clkops generic_clkops = { | |||
64 | .disable = generic_clk_disable, | 65 | .disable = generic_clk_disable, |
65 | }; | 66 | }; |
66 | 67 | ||
68 | /* returns current programmed clocks clock info structure */ | ||
69 | static struct pclk_info *pclk_info_get(struct clk *clk) | ||
70 | { | ||
71 | unsigned int val, i; | ||
72 | struct pclk_info *info = NULL; | ||
73 | |||
74 | val = (readl(clk->pclk_sel->pclk_sel_reg) >> clk->pclk_sel_shift) | ||
75 | & clk->pclk_sel->pclk_sel_mask; | ||
76 | |||
77 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { | ||
78 | if (clk->pclk_sel->pclk_info[i].pclk_val == val) | ||
79 | info = &clk->pclk_sel->pclk_info[i]; | ||
80 | } | ||
81 | |||
82 | return info; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Set Update pclk, and pclk_info of clk and add clock sibling node to current | ||
87 | * parents children list | ||
88 | */ | ||
89 | static void clk_reparent(struct clk *clk, struct pclk_info *pclk_info) | ||
90 | { | ||
91 | unsigned long flags; | ||
92 | |||
93 | spin_lock_irqsave(&clocks_lock, flags); | ||
94 | list_del(&clk->sibling); | ||
95 | list_add(&clk->sibling, &pclk_info->pclk->children); | ||
96 | |||
97 | clk->pclk = pclk_info->pclk; | ||
98 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
99 | } | ||
100 | |||
101 | static void do_clk_disable(struct clk *clk) | ||
102 | { | ||
103 | if (!clk) | ||
104 | return; | ||
105 | |||
106 | if (!clk->usage_count) { | ||
107 | WARN_ON(1); | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | clk->usage_count--; | ||
112 | |||
113 | if (clk->usage_count == 0) { | ||
114 | /* | ||
115 | * Surely, there are no active childrens or direct users | ||
116 | * of this clock | ||
117 | */ | ||
118 | if (clk->pclk) | ||
119 | do_clk_disable(clk->pclk); | ||
120 | |||
121 | if (clk->ops && clk->ops->disable) | ||
122 | clk->ops->disable(clk); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static int do_clk_enable(struct clk *clk) | ||
127 | { | ||
128 | int ret = 0; | ||
129 | |||
130 | if (!clk) | ||
131 | return -EFAULT; | ||
132 | |||
133 | if (clk->usage_count == 0) { | ||
134 | if (clk->pclk) { | ||
135 | ret = do_clk_enable(clk->pclk); | ||
136 | if (ret) | ||
137 | goto err; | ||
138 | } | ||
139 | if (clk->ops && clk->ops->enable) { | ||
140 | ret = clk->ops->enable(clk); | ||
141 | if (ret) { | ||
142 | if (clk->pclk) | ||
143 | do_clk_disable(clk->pclk); | ||
144 | goto err; | ||
145 | } | ||
146 | } | ||
147 | /* | ||
148 | * Since the clock is going to be used for the first | ||
149 | * time please reclac | ||
150 | */ | ||
151 | if (clk->recalc) { | ||
152 | ret = clk->recalc(clk); | ||
153 | if (ret) | ||
154 | goto err; | ||
155 | } | ||
156 | } | ||
157 | clk->usage_count++; | ||
158 | err: | ||
159 | return ret; | ||
160 | } | ||
161 | |||
67 | /* | 162 | /* |
68 | * clk_enable - inform the system when the clock source should be running. | 163 | * clk_enable - inform the system when the clock source should be running. |
69 | * @clk: clock source | 164 | * @clk: clock source |
@@ -77,17 +172,9 @@ int clk_enable(struct clk *clk) | |||
77 | unsigned long flags; | 172 | unsigned long flags; |
78 | int ret = 0; | 173 | int ret = 0; |
79 | 174 | ||
80 | if (!clk || IS_ERR(clk)) | ||
81 | return -EFAULT; | ||
82 | |||
83 | spin_lock_irqsave(&clocks_lock, flags); | 175 | spin_lock_irqsave(&clocks_lock, flags); |
84 | if (clk->usage_count == 0) { | 176 | ret = do_clk_enable(clk); |
85 | if (clk->ops && clk->ops->enable) | ||
86 | ret = clk->ops->enable(clk); | ||
87 | } | ||
88 | clk->usage_count++; | ||
89 | spin_unlock_irqrestore(&clocks_lock, flags); | 177 | spin_unlock_irqrestore(&clocks_lock, flags); |
90 | |||
91 | return ret; | 178 | return ret; |
92 | } | 179 | } |
93 | EXPORT_SYMBOL(clk_enable); | 180 | EXPORT_SYMBOL(clk_enable); |
@@ -108,17 +195,8 @@ void clk_disable(struct clk *clk) | |||
108 | { | 195 | { |
109 | unsigned long flags; | 196 | unsigned long flags; |
110 | 197 | ||
111 | if (!clk || IS_ERR(clk)) | ||
112 | return; | ||
113 | |||
114 | WARN_ON(clk->usage_count == 0); | ||
115 | |||
116 | spin_lock_irqsave(&clocks_lock, flags); | 198 | spin_lock_irqsave(&clocks_lock, flags); |
117 | clk->usage_count--; | 199 | do_clk_disable(clk); |
118 | if (clk->usage_count == 0) { | ||
119 | if (clk->ops && clk->ops->disable) | ||
120 | clk->ops->disable(clk); | ||
121 | } | ||
122 | spin_unlock_irqrestore(&clocks_lock, flags); | 200 | spin_unlock_irqrestore(&clocks_lock, flags); |
123 | } | 201 | } |
124 | EXPORT_SYMBOL(clk_disable); | 202 | EXPORT_SYMBOL(clk_disable); |
@@ -152,15 +230,14 @@ int clk_set_parent(struct clk *clk, struct clk *parent) | |||
152 | int i, found = 0, val = 0; | 230 | int i, found = 0, val = 0; |
153 | unsigned long flags; | 231 | unsigned long flags; |
154 | 232 | ||
155 | if (!clk || IS_ERR(clk) || !parent || IS_ERR(parent)) | 233 | if (!clk || !parent) |
156 | return -EFAULT; | 234 | return -EFAULT; |
157 | if (clk->usage_count) | ||
158 | return -EBUSY; | ||
159 | if (!clk->pclk_sel) | ||
160 | return -EPERM; | ||
161 | if (clk->pclk == parent) | 235 | if (clk->pclk == parent) |
162 | return 0; | 236 | return 0; |
237 | if (!clk->pclk_sel) | ||
238 | return -EPERM; | ||
163 | 239 | ||
240 | /* check if requested parent is in clk parent list */ | ||
164 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { | 241 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { |
165 | if (clk->pclk_sel->pclk_info[i].pclk == parent) { | 242 | if (clk->pclk_sel->pclk_info[i].pclk == parent) { |
166 | found = 1; | 243 | found = 1; |
@@ -175,13 +252,14 @@ int clk_set_parent(struct clk *clk, struct clk *parent) | |||
175 | /* reflect parent change in hardware */ | 252 | /* reflect parent change in hardware */ |
176 | val = readl(clk->pclk_sel->pclk_sel_reg); | 253 | val = readl(clk->pclk_sel->pclk_sel_reg); |
177 | val &= ~(clk->pclk_sel->pclk_sel_mask << clk->pclk_sel_shift); | 254 | val &= ~(clk->pclk_sel->pclk_sel_mask << clk->pclk_sel_shift); |
178 | val |= clk->pclk_sel->pclk_info[i].pclk_mask << clk->pclk_sel_shift; | 255 | val |= clk->pclk_sel->pclk_info[i].pclk_val << clk->pclk_sel_shift; |
179 | writel(val, clk->pclk_sel->pclk_sel_reg); | 256 | writel(val, clk->pclk_sel->pclk_sel_reg); |
180 | spin_unlock_irqrestore(&clocks_lock, flags); | 257 | spin_unlock_irqrestore(&clocks_lock, flags); |
181 | 258 | ||
182 | /* reflect parent change in software */ | 259 | /* reflect parent change in software */ |
183 | clk->recalc(clk); | 260 | clk_reparent(clk, &clk->pclk_sel->pclk_info[i]); |
184 | propagate_rate(&clk->children); | 261 | |
262 | propagate_rate(clk, 0); | ||
185 | return 0; | 263 | return 0; |
186 | } | 264 | } |
187 | EXPORT_SYMBOL(clk_set_parent); | 265 | EXPORT_SYMBOL(clk_set_parent); |
@@ -195,19 +273,37 @@ EXPORT_SYMBOL(clk_set_parent); | |||
195 | */ | 273 | */ |
196 | int clk_set_rate(struct clk *clk, unsigned long rate) | 274 | int clk_set_rate(struct clk *clk, unsigned long rate) |
197 | { | 275 | { |
198 | /* TODO */ | 276 | unsigned long flags; |
199 | return -EINVAL; | 277 | int ret = -EINVAL; |
278 | |||
279 | if (!clk || !rate) | ||
280 | return -EFAULT; | ||
281 | |||
282 | if (clk->set_rate) { | ||
283 | spin_lock_irqsave(&clocks_lock, flags); | ||
284 | ret = clk->set_rate(clk, rate); | ||
285 | if (!ret) | ||
286 | /* if successful -> propagate */ | ||
287 | propagate_rate(clk, 0); | ||
288 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
289 | } else if (clk->pclk) { | ||
290 | u32 mult = clk->div_factor ? clk->div_factor : 1; | ||
291 | ret = clk_set_rate(clk->pclk, mult * rate); | ||
292 | } | ||
293 | |||
294 | return ret; | ||
200 | } | 295 | } |
201 | EXPORT_SYMBOL(clk_set_rate); | 296 | EXPORT_SYMBOL(clk_set_rate); |
202 | 297 | ||
203 | /* registers clock in platform clock framework */ | 298 | /* registers clock in platform clock framework */ |
204 | void clk_register(struct clk_lookup *cl) | 299 | void clk_register(struct clk_lookup *cl) |
205 | { | 300 | { |
206 | struct clk *clk = cl->clk; | 301 | struct clk *clk; |
207 | unsigned long flags; | 302 | unsigned long flags; |
208 | 303 | ||
209 | if (!clk || IS_ERR(clk)) | 304 | if (!cl || !cl->clk) |
210 | return; | 305 | return; |
306 | clk = cl->clk; | ||
211 | 307 | ||
212 | spin_lock_irqsave(&clocks_lock, flags); | 308 | spin_lock_irqsave(&clocks_lock, flags); |
213 | 309 | ||
@@ -220,15 +316,24 @@ void clk_register(struct clk_lookup *cl) | |||
220 | /* root clock don't have any parents */ | 316 | /* root clock don't have any parents */ |
221 | if (!clk->pclk && !clk->pclk_sel) { | 317 | if (!clk->pclk && !clk->pclk_sel) { |
222 | list_add(&clk->sibling, &root_clks); | 318 | list_add(&clk->sibling, &root_clks); |
223 | /* add clocks with only one parent to parent's children list */ | ||
224 | } else if (clk->pclk && !clk->pclk_sel) { | 319 | } else if (clk->pclk && !clk->pclk_sel) { |
320 | /* add clocks with only one parent to parent's children list */ | ||
225 | list_add(&clk->sibling, &clk->pclk->children); | 321 | list_add(&clk->sibling, &clk->pclk->children); |
226 | } else { | 322 | } else { |
227 | /* add clocks with > 1 parent to 1st parent's children list */ | 323 | /* clocks with more than one parent */ |
228 | clk->pclk = clk->pclk_sel->pclk_info[0].pclk; | 324 | struct pclk_info *pclk_info; |
229 | list_add(&clk->sibling, | 325 | |
230 | &clk->pclk_sel->pclk_info[0].pclk->children); | 326 | pclk_info = pclk_info_get(clk); |
327 | if (!pclk_info) { | ||
328 | pr_err("CLKDEV: invalid pclk info of clk with" | ||
329 | " %s dev_id and %s con_id\n", | ||
330 | cl->dev_id, cl->con_id); | ||
331 | } else { | ||
332 | clk->pclk = pclk_info->pclk; | ||
333 | list_add(&clk->sibling, &pclk_info->pclk->children); | ||
334 | } | ||
231 | } | 335 | } |
336 | |||
232 | spin_unlock_irqrestore(&clocks_lock, flags); | 337 | spin_unlock_irqrestore(&clocks_lock, flags); |
233 | 338 | ||
234 | /* add clock to arm clockdev framework */ | 339 | /* add clock to arm clockdev framework */ |
@@ -236,56 +341,142 @@ void clk_register(struct clk_lookup *cl) | |||
236 | } | 341 | } |
237 | 342 | ||
238 | /** | 343 | /** |
239 | * propagate_rate - recalculate and propagate all clocks in list head | 344 | * propagate_rate - recalculate and propagate all clocks to children |
345 | * @pclk: parent clock required to be propogated | ||
346 | * @on_init: flag for enabling clocks which are ENABLED_ON_INIT. | ||
240 | * | 347 | * |
241 | * Recalculates all root clocks in list head, which if the clock's .recalc is | 348 | * Recalculates all children clocks |
242 | * set correctly, should also propagate their rates. | ||
243 | */ | 349 | */ |
244 | static void propagate_rate(struct list_head *lhead) | 350 | void propagate_rate(struct clk *pclk, int on_init) |
245 | { | 351 | { |
246 | struct clk *clkp, *_temp; | 352 | struct clk *clk, *_temp; |
353 | int ret = 0; | ||
354 | |||
355 | list_for_each_entry_safe(clk, _temp, &pclk->children, sibling) { | ||
356 | if (clk->recalc) { | ||
357 | ret = clk->recalc(clk); | ||
358 | /* | ||
359 | * recalc will return error if clk out is not programmed | ||
360 | * In this case configure default rate. | ||
361 | */ | ||
362 | if (ret && clk->set_rate) | ||
363 | clk->set_rate(clk, 0); | ||
364 | } | ||
365 | propagate_rate(clk, on_init); | ||
366 | |||
367 | if (!on_init) | ||
368 | continue; | ||
247 | 369 | ||
248 | list_for_each_entry_safe(clkp, _temp, lhead, sibling) { | 370 | /* Enable clks enabled on init, in software view */ |
249 | if (clkp->recalc) | 371 | if (clk->flags & ENABLED_ON_INIT) |
250 | clkp->recalc(clkp); | 372 | do_clk_enable(clk); |
251 | propagate_rate(&clkp->children); | ||
252 | } | 373 | } |
253 | } | 374 | } |
254 | 375 | ||
255 | /* returns current programmed clocks clock info structure */ | 376 | /** |
256 | static struct pclk_info *pclk_info_get(struct clk *clk) | 377 | * round_rate_index - return closest programmable rate index in rate_config tbl |
378 | * @clk: ptr to clock structure | ||
379 | * @drate: desired rate | ||
380 | * @rate: final rate will be returned in this variable only. | ||
381 | * | ||
382 | * Finds index in rate_config for highest clk rate which is less than | ||
383 | * requested rate. If there is no clk rate lesser than requested rate then | ||
384 | * -EINVAL is returned. This routine assumes that rate_config is written | ||
385 | * in incrementing order of clk rates. | ||
386 | * If drate passed is zero then default rate is programmed. | ||
387 | */ | ||
388 | static int | ||
389 | round_rate_index(struct clk *clk, unsigned long drate, unsigned long *rate) | ||
257 | { | 390 | { |
258 | unsigned int mask, i; | 391 | unsigned long tmp = 0, prev_rate = 0; |
259 | unsigned long flags; | 392 | int index; |
260 | struct pclk_info *info = NULL; | ||
261 | 393 | ||
262 | spin_lock_irqsave(&clocks_lock, flags); | 394 | if (!clk->calc_rate) |
263 | mask = (readl(clk->pclk_sel->pclk_sel_reg) >> clk->pclk_sel_shift) | 395 | return -EFAULT; |
264 | & clk->pclk_sel->pclk_sel_mask; | ||
265 | 396 | ||
266 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { | 397 | if (!drate) |
267 | if (clk->pclk_sel->pclk_info[i].pclk_mask == mask) | 398 | return -EINVAL; |
268 | info = &clk->pclk_sel->pclk_info[i]; | 399 | |
400 | /* | ||
401 | * This loops ends on two conditions: | ||
402 | * - as soon as clk is found with rate greater than requested rate. | ||
403 | * - if all clks in rate_config are smaller than requested rate. | ||
404 | */ | ||
405 | for (index = 0; index < clk->rate_config.count; index++) { | ||
406 | prev_rate = tmp; | ||
407 | tmp = clk->calc_rate(clk, index); | ||
408 | if (drate < tmp) { | ||
409 | index--; | ||
410 | break; | ||
411 | } | ||
269 | } | 412 | } |
270 | spin_unlock_irqrestore(&clocks_lock, flags); | 413 | /* return if can't find suitable clock */ |
414 | if (index < 0) { | ||
415 | index = -EINVAL; | ||
416 | *rate = 0; | ||
417 | } else if (index == clk->rate_config.count) { | ||
418 | /* program with highest clk rate possible */ | ||
419 | index = clk->rate_config.count - 1; | ||
420 | *rate = tmp; | ||
421 | } else | ||
422 | *rate = prev_rate; | ||
271 | 423 | ||
272 | return info; | 424 | return index; |
273 | } | 425 | } |
274 | 426 | ||
275 | /* | 427 | /** |
276 | * Set pclk as cclk's parent and add clock sibling node to current parents | 428 | * clk_round_rate - adjust a rate to the exact rate a clock can provide |
277 | * children list | 429 | * @clk: clock source |
430 | * @rate: desired clock rate in Hz | ||
431 | * | ||
432 | * Returns rounded clock rate in Hz, or negative errno. | ||
278 | */ | 433 | */ |
279 | static void change_parent(struct clk *cclk, struct clk *pclk) | 434 | long clk_round_rate(struct clk *clk, unsigned long drate) |
280 | { | 435 | { |
281 | unsigned long flags; | 436 | long rate = 0; |
437 | int index; | ||
438 | |||
439 | /* | ||
440 | * propagate call to parent who supports calc_rate. Similar approach is | ||
441 | * used in clk_set_rate. | ||
442 | */ | ||
443 | if (!clk->calc_rate) { | ||
444 | u32 mult; | ||
445 | if (!clk->pclk) | ||
446 | return clk->rate; | ||
447 | |||
448 | mult = clk->div_factor ? clk->div_factor : 1; | ||
449 | return clk_round_rate(clk->pclk, mult * drate) / mult; | ||
450 | } | ||
282 | 451 | ||
283 | spin_lock_irqsave(&clocks_lock, flags); | 452 | index = round_rate_index(clk, drate, &rate); |
284 | list_del(&cclk->sibling); | 453 | if (index >= 0) |
285 | list_add(&cclk->sibling, &pclk->children); | 454 | return rate; |
455 | else | ||
456 | return index; | ||
457 | } | ||
458 | EXPORT_SYMBOL(clk_round_rate); | ||
286 | 459 | ||
287 | cclk->pclk = pclk; | 460 | /*All below functions are called with lock held */ |
288 | spin_unlock_irqrestore(&clocks_lock, flags); | 461 | |
462 | /* | ||
463 | * Calculates pll clk rate for specific value of mode, m, n and p | ||
464 | * | ||
465 | * In normal mode | ||
466 | * rate = (2 * M[15:8] * Fin)/(N * 2^P) | ||
467 | * | ||
468 | * In Dithered mode | ||
469 | * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) | ||
470 | */ | ||
471 | unsigned long pll_calc_rate(struct clk *clk, int index) | ||
472 | { | ||
473 | unsigned long rate = clk->pclk->rate; | ||
474 | struct pll_rate_tbl *tbls = clk->rate_config.tbls; | ||
475 | unsigned int mode; | ||
476 | |||
477 | mode = tbls[index].mode ? 256 : 1; | ||
478 | return (((2 * rate / 10000) * tbls[index].m) / | ||
479 | (mode * tbls[index].n * (1 << tbls[index].p))) * 10000; | ||
289 | } | 480 | } |
290 | 481 | ||
291 | /* | 482 | /* |
@@ -297,13 +488,11 @@ static void change_parent(struct clk *cclk, struct clk *pclk) | |||
297 | * In Dithered mode | 488 | * In Dithered mode |
298 | * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) | 489 | * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) |
299 | */ | 490 | */ |
300 | void pll_clk_recalc(struct clk *clk) | 491 | int pll_clk_recalc(struct clk *clk) |
301 | { | 492 | { |
302 | struct pll_clk_config *config = clk->private_data; | 493 | struct pll_clk_config *config = clk->private_data; |
303 | unsigned int num = 2, den = 0, val, mode = 0; | 494 | unsigned int num = 2, den = 0, val, mode = 0; |
304 | unsigned long flags; | ||
305 | 495 | ||
306 | spin_lock_irqsave(&clocks_lock, flags); | ||
307 | mode = (readl(config->mode_reg) >> config->masks->mode_shift) & | 496 | mode = (readl(config->mode_reg) >> config->masks->mode_shift) & |
308 | config->masks->mode_mask; | 497 | config->masks->mode_mask; |
309 | 498 | ||
@@ -325,22 +514,120 @@ void pll_clk_recalc(struct clk *clk) | |||
325 | den *= 256; | 514 | den *= 256; |
326 | } | 515 | } |
327 | 516 | ||
517 | if (!den) | ||
518 | return -EINVAL; | ||
519 | |||
328 | clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; | 520 | clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; |
329 | spin_unlock_irqrestore(&clocks_lock, flags); | 521 | return 0; |
522 | } | ||
523 | |||
524 | /* | ||
525 | * Configures new clock rate of pll | ||
526 | */ | ||
527 | int pll_clk_set_rate(struct clk *clk, unsigned long desired_rate) | ||
528 | { | ||
529 | struct pll_rate_tbl *tbls = clk->rate_config.tbls; | ||
530 | struct pll_clk_config *config = clk->private_data; | ||
531 | unsigned long val, rate; | ||
532 | int i; | ||
533 | |||
534 | i = round_rate_index(clk, desired_rate, &rate); | ||
535 | if (i < 0) | ||
536 | return i; | ||
537 | |||
538 | val = readl(config->mode_reg) & | ||
539 | ~(config->masks->mode_mask << config->masks->mode_shift); | ||
540 | val |= (tbls[i].mode & config->masks->mode_mask) << | ||
541 | config->masks->mode_shift; | ||
542 | writel(val, config->mode_reg); | ||
543 | |||
544 | val = readl(config->cfg_reg) & | ||
545 | ~(config->masks->div_p_mask << config->masks->div_p_shift); | ||
546 | val |= (tbls[i].p & config->masks->div_p_mask) << | ||
547 | config->masks->div_p_shift; | ||
548 | val &= ~(config->masks->div_n_mask << config->masks->div_n_shift); | ||
549 | val |= (tbls[i].n & config->masks->div_n_mask) << | ||
550 | config->masks->div_n_shift; | ||
551 | val &= ~(config->masks->dith_fdbk_m_mask << | ||
552 | config->masks->dith_fdbk_m_shift); | ||
553 | if (tbls[i].mode) | ||
554 | val |= (tbls[i].m & config->masks->dith_fdbk_m_mask) << | ||
555 | config->masks->dith_fdbk_m_shift; | ||
556 | else | ||
557 | val |= (tbls[i].m & config->masks->norm_fdbk_m_mask) << | ||
558 | config->masks->norm_fdbk_m_shift; | ||
559 | |||
560 | writel(val, config->cfg_reg); | ||
561 | |||
562 | clk->rate = rate; | ||
563 | |||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | /* | ||
568 | * Calculates ahb, apb clk rate for specific value of div | ||
569 | */ | ||
570 | unsigned long bus_calc_rate(struct clk *clk, int index) | ||
571 | { | ||
572 | unsigned long rate = clk->pclk->rate; | ||
573 | struct bus_rate_tbl *tbls = clk->rate_config.tbls; | ||
574 | |||
575 | return rate / (tbls[index].div + 1); | ||
330 | } | 576 | } |
331 | 577 | ||
332 | /* calculates current programmed rate of ahb or apb bus */ | 578 | /* calculates current programmed rate of ahb or apb bus */ |
333 | void bus_clk_recalc(struct clk *clk) | 579 | int bus_clk_recalc(struct clk *clk) |
334 | { | 580 | { |
335 | struct bus_clk_config *config = clk->private_data; | 581 | struct bus_clk_config *config = clk->private_data; |
336 | unsigned int div; | 582 | unsigned int div; |
337 | unsigned long flags; | ||
338 | 583 | ||
339 | spin_lock_irqsave(&clocks_lock, flags); | ||
340 | div = ((readl(config->reg) >> config->masks->shift) & | 584 | div = ((readl(config->reg) >> config->masks->shift) & |
341 | config->masks->mask) + 1; | 585 | config->masks->mask) + 1; |
586 | |||
587 | if (!div) | ||
588 | return -EINVAL; | ||
589 | |||
342 | clk->rate = (unsigned long)clk->pclk->rate / div; | 590 | clk->rate = (unsigned long)clk->pclk->rate / div; |
343 | spin_unlock_irqrestore(&clocks_lock, flags); | 591 | return 0; |
592 | } | ||
593 | |||
594 | /* Configures new clock rate of AHB OR APB bus */ | ||
595 | int bus_clk_set_rate(struct clk *clk, unsigned long desired_rate) | ||
596 | { | ||
597 | struct bus_rate_tbl *tbls = clk->rate_config.tbls; | ||
598 | struct bus_clk_config *config = clk->private_data; | ||
599 | unsigned long val, rate; | ||
600 | int i; | ||
601 | |||
602 | i = round_rate_index(clk, desired_rate, &rate); | ||
603 | if (i < 0) | ||
604 | return i; | ||
605 | |||
606 | val = readl(config->reg) & | ||
607 | ~(config->masks->mask << config->masks->shift); | ||
608 | val |= (tbls[i].div & config->masks->mask) << config->masks->shift; | ||
609 | writel(val, config->reg); | ||
610 | |||
611 | clk->rate = rate; | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | /* | ||
617 | * gives rate for different values of eq, x and y | ||
618 | * | ||
619 | * Fout from synthesizer can be given from two equations: | ||
620 | * Fout1 = (Fin * X/Y)/2 EQ1 | ||
621 | * Fout2 = Fin * X/Y EQ2 | ||
622 | */ | ||
623 | unsigned long aux_calc_rate(struct clk *clk, int index) | ||
624 | { | ||
625 | unsigned long rate = clk->pclk->rate; | ||
626 | struct aux_rate_tbl *tbls = clk->rate_config.tbls; | ||
627 | u8 eq = tbls[index].eq ? 1 : 2; | ||
628 | |||
629 | return (((rate/10000) * tbls[index].xscale) / | ||
630 | (tbls[index].yscale * eq)) * 10000; | ||
344 | } | 631 | } |
345 | 632 | ||
346 | /* | 633 | /* |
@@ -353,47 +640,76 @@ void bus_clk_recalc(struct clk *clk) | |||
353 | * | 640 | * |
354 | * Selection of eqn 1 or 2 is programmed in register | 641 | * Selection of eqn 1 or 2 is programmed in register |
355 | */ | 642 | */ |
356 | void aux_clk_recalc(struct clk *clk) | 643 | int aux_clk_recalc(struct clk *clk) |
357 | { | 644 | { |
358 | struct aux_clk_config *config = clk->private_data; | 645 | struct aux_clk_config *config = clk->private_data; |
359 | struct pclk_info *pclk_info = NULL; | ||
360 | unsigned int num = 1, den = 1, val, eqn; | 646 | unsigned int num = 1, den = 1, val, eqn; |
361 | unsigned long flags; | ||
362 | 647 | ||
363 | /* get current programmed parent */ | 648 | val = readl(config->synth_reg); |
364 | pclk_info = pclk_info_get(clk); | ||
365 | if (!pclk_info) { | ||
366 | spin_lock_irqsave(&clocks_lock, flags); | ||
367 | clk->pclk = NULL; | ||
368 | clk->rate = 0; | ||
369 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
370 | return; | ||
371 | } | ||
372 | 649 | ||
373 | change_parent(clk, pclk_info->pclk); | 650 | eqn = (val >> config->masks->eq_sel_shift) & |
651 | config->masks->eq_sel_mask; | ||
652 | if (eqn == config->masks->eq1_mask) | ||
653 | den *= 2; | ||
374 | 654 | ||
375 | spin_lock_irqsave(&clocks_lock, flags); | 655 | /* calculate numerator */ |
376 | if (pclk_info->scalable) { | 656 | num = (val >> config->masks->xscale_sel_shift) & |
377 | val = readl(config->synth_reg); | 657 | config->masks->xscale_sel_mask; |
378 | |||
379 | eqn = (val >> config->masks->eq_sel_shift) & | ||
380 | config->masks->eq_sel_mask; | ||
381 | if (eqn == config->masks->eq1_mask) | ||
382 | den *= 2; | ||
383 | |||
384 | /* calculate numerator */ | ||
385 | num = (val >> config->masks->xscale_sel_shift) & | ||
386 | config->masks->xscale_sel_mask; | ||
387 | |||
388 | /* calculate denominator */ | ||
389 | den *= (val >> config->masks->yscale_sel_shift) & | ||
390 | config->masks->yscale_sel_mask; | ||
391 | val = (((clk->pclk->rate/10000) * num) / den) * 10000; | ||
392 | } else | ||
393 | val = clk->pclk->rate; | ||
394 | 658 | ||
395 | clk->rate = val; | 659 | /* calculate denominator */ |
396 | spin_unlock_irqrestore(&clocks_lock, flags); | 660 | den *= (val >> config->masks->yscale_sel_shift) & |
661 | config->masks->yscale_sel_mask; | ||
662 | |||
663 | if (!den) | ||
664 | return -EINVAL; | ||
665 | |||
666 | clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | /* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ | ||
671 | int aux_clk_set_rate(struct clk *clk, unsigned long desired_rate) | ||
672 | { | ||
673 | struct aux_rate_tbl *tbls = clk->rate_config.tbls; | ||
674 | struct aux_clk_config *config = clk->private_data; | ||
675 | unsigned long val, rate; | ||
676 | int i; | ||
677 | |||
678 | i = round_rate_index(clk, desired_rate, &rate); | ||
679 | if (i < 0) | ||
680 | return i; | ||
681 | |||
682 | val = readl(config->synth_reg) & | ||
683 | ~(config->masks->eq_sel_mask << config->masks->eq_sel_shift); | ||
684 | val |= (tbls[i].eq & config->masks->eq_sel_mask) << | ||
685 | config->masks->eq_sel_shift; | ||
686 | val &= ~(config->masks->xscale_sel_mask << | ||
687 | config->masks->xscale_sel_shift); | ||
688 | val |= (tbls[i].xscale & config->masks->xscale_sel_mask) << | ||
689 | config->masks->xscale_sel_shift; | ||
690 | val &= ~(config->masks->yscale_sel_mask << | ||
691 | config->masks->yscale_sel_shift); | ||
692 | val |= (tbls[i].yscale & config->masks->yscale_sel_mask) << | ||
693 | config->masks->yscale_sel_shift; | ||
694 | writel(val, config->synth_reg); | ||
695 | |||
696 | clk->rate = rate; | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | /* | ||
702 | * Calculates gpt clk rate for different values of mscale and nscale | ||
703 | * | ||
704 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) | ||
705 | */ | ||
706 | unsigned long gpt_calc_rate(struct clk *clk, int index) | ||
707 | { | ||
708 | unsigned long rate = clk->pclk->rate; | ||
709 | struct gpt_rate_tbl *tbls = clk->rate_config.tbls; | ||
710 | |||
711 | return rate / ((1 << (tbls[index].nscale + 1)) * | ||
712 | (tbls[index].mscale + 1)); | ||
397 | } | 713 | } |
398 | 714 | ||
399 | /* | 715 | /* |
@@ -401,49 +717,142 @@ void aux_clk_recalc(struct clk *clk) | |||
401 | * Fout from synthesizer can be given from below equations: | 717 | * Fout from synthesizer can be given from below equations: |
402 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) | 718 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) |
403 | */ | 719 | */ |
404 | void gpt_clk_recalc(struct clk *clk) | 720 | int gpt_clk_recalc(struct clk *clk) |
405 | { | 721 | { |
406 | struct gpt_clk_config *config = clk->private_data; | 722 | struct gpt_clk_config *config = clk->private_data; |
407 | struct pclk_info *pclk_info = NULL; | ||
408 | unsigned int div = 1, val; | 723 | unsigned int div = 1, val; |
409 | unsigned long flags; | ||
410 | 724 | ||
411 | pclk_info = pclk_info_get(clk); | 725 | val = readl(config->synth_reg); |
412 | if (!pclk_info) { | 726 | div += (val >> config->masks->mscale_sel_shift) & |
413 | spin_lock_irqsave(&clocks_lock, flags); | 727 | config->masks->mscale_sel_mask; |
414 | clk->pclk = NULL; | 728 | div *= 1 << (((val >> config->masks->nscale_sel_shift) & |
415 | clk->rate = 0; | 729 | config->masks->nscale_sel_mask) + 1); |
416 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
417 | return; | ||
418 | } | ||
419 | 730 | ||
420 | change_parent(clk, pclk_info->pclk); | 731 | if (!div) |
421 | 732 | return -EINVAL; | |
422 | spin_lock_irqsave(&clocks_lock, flags); | ||
423 | if (pclk_info->scalable) { | ||
424 | val = readl(config->synth_reg); | ||
425 | div += (val >> config->masks->mscale_sel_shift) & | ||
426 | config->masks->mscale_sel_mask; | ||
427 | div *= 1 << (((val >> config->masks->nscale_sel_shift) & | ||
428 | config->masks->nscale_sel_mask) + 1); | ||
429 | } | ||
430 | 733 | ||
431 | clk->rate = (unsigned long)clk->pclk->rate / div; | 734 | clk->rate = (unsigned long)clk->pclk->rate / div; |
432 | spin_unlock_irqrestore(&clocks_lock, flags); | 735 | return 0; |
736 | } | ||
737 | |||
738 | /* Configures new clock rate of gptiliary synthesizers used by: UART, FIRDA*/ | ||
739 | int gpt_clk_set_rate(struct clk *clk, unsigned long desired_rate) | ||
740 | { | ||
741 | struct gpt_rate_tbl *tbls = clk->rate_config.tbls; | ||
742 | struct gpt_clk_config *config = clk->private_data; | ||
743 | unsigned long val, rate; | ||
744 | int i; | ||
745 | |||
746 | i = round_rate_index(clk, desired_rate, &rate); | ||
747 | if (i < 0) | ||
748 | return i; | ||
749 | |||
750 | val = readl(config->synth_reg) & ~(config->masks->mscale_sel_mask << | ||
751 | config->masks->mscale_sel_shift); | ||
752 | val |= (tbls[i].mscale & config->masks->mscale_sel_mask) << | ||
753 | config->masks->mscale_sel_shift; | ||
754 | val &= ~(config->masks->nscale_sel_mask << | ||
755 | config->masks->nscale_sel_shift); | ||
756 | val |= (tbls[i].nscale & config->masks->nscale_sel_mask) << | ||
757 | config->masks->nscale_sel_shift; | ||
758 | writel(val, config->synth_reg); | ||
759 | |||
760 | clk->rate = rate; | ||
761 | |||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | /* | ||
766 | * Calculates clcd clk rate for different values of div | ||
767 | * | ||
768 | * Fout from synthesizer can be given from below equation: | ||
769 | * Fout= Fin/2*div (division factor) | ||
770 | * div is 17 bits:- | ||
771 | * 0-13 (fractional part) | ||
772 | * 14-16 (integer part) | ||
773 | * To calculate Fout we left shift val by 14 bits and divide Fin by | ||
774 | * complete div (including fractional part) and then right shift the | ||
775 | * result by 14 places. | ||
776 | */ | ||
777 | unsigned long clcd_calc_rate(struct clk *clk, int index) | ||
778 | { | ||
779 | unsigned long rate = clk->pclk->rate; | ||
780 | struct clcd_rate_tbl *tbls = clk->rate_config.tbls; | ||
781 | |||
782 | rate /= 1000; | ||
783 | rate <<= 12; | ||
784 | rate /= (2 * tbls[index].div); | ||
785 | rate >>= 12; | ||
786 | rate *= 1000; | ||
787 | |||
788 | return rate; | ||
789 | } | ||
790 | |||
791 | /* | ||
792 | * calculates current programmed rate of clcd synthesizer | ||
793 | * Fout from synthesizer can be given from below equation: | ||
794 | * Fout= Fin/2*div (division factor) | ||
795 | * div is 17 bits:- | ||
796 | * 0-13 (fractional part) | ||
797 | * 14-16 (integer part) | ||
798 | * To calculate Fout we left shift val by 14 bits and divide Fin by | ||
799 | * complete div (including fractional part) and then right shift the | ||
800 | * result by 14 places. | ||
801 | */ | ||
802 | int clcd_clk_recalc(struct clk *clk) | ||
803 | { | ||
804 | struct clcd_clk_config *config = clk->private_data; | ||
805 | unsigned int div = 1; | ||
806 | unsigned long prate; | ||
807 | unsigned int val; | ||
808 | |||
809 | val = readl(config->synth_reg); | ||
810 | div = (val >> config->masks->div_factor_shift) & | ||
811 | config->masks->div_factor_mask; | ||
812 | |||
813 | if (!div) | ||
814 | return -EINVAL; | ||
815 | |||
816 | prate = clk->pclk->rate / 1000; /* first level division, make it KHz */ | ||
817 | |||
818 | clk->rate = (((unsigned long)prate << 12) / (2 * div)) >> 12; | ||
819 | clk->rate *= 1000; | ||
820 | return 0; | ||
821 | } | ||
822 | |||
823 | /* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ | ||
824 | int clcd_clk_set_rate(struct clk *clk, unsigned long desired_rate) | ||
825 | { | ||
826 | struct clcd_rate_tbl *tbls = clk->rate_config.tbls; | ||
827 | struct clcd_clk_config *config = clk->private_data; | ||
828 | unsigned long val, rate; | ||
829 | int i; | ||
830 | |||
831 | i = round_rate_index(clk, desired_rate, &rate); | ||
832 | if (i < 0) | ||
833 | return i; | ||
834 | |||
835 | val = readl(config->synth_reg) & ~(config->masks->div_factor_mask << | ||
836 | config->masks->div_factor_shift); | ||
837 | val |= (tbls[i].div & config->masks->div_factor_mask) << | ||
838 | config->masks->div_factor_shift; | ||
839 | writel(val, config->synth_reg); | ||
840 | |||
841 | clk->rate = rate; | ||
842 | |||
843 | return 0; | ||
433 | } | 844 | } |
434 | 845 | ||
435 | /* | 846 | /* |
436 | * Used for clocks that always have value as the parent clock divided by a | 847 | * Used for clocks that always have value as the parent clock divided by a |
437 | * fixed divisor | 848 | * fixed divisor |
438 | */ | 849 | */ |
439 | void follow_parent(struct clk *clk) | 850 | int follow_parent(struct clk *clk) |
440 | { | 851 | { |
441 | unsigned long flags; | ||
442 | unsigned int div_factor = (clk->div_factor < 1) ? 1 : clk->div_factor; | 852 | unsigned int div_factor = (clk->div_factor < 1) ? 1 : clk->div_factor; |
443 | 853 | ||
444 | spin_lock_irqsave(&clocks_lock, flags); | ||
445 | clk->rate = clk->pclk->rate/div_factor; | 854 | clk->rate = clk->pclk->rate/div_factor; |
446 | spin_unlock_irqrestore(&clocks_lock, flags); | 855 | return 0; |
447 | } | 856 | } |
448 | 857 | ||
449 | /** | 858 | /** |
@@ -454,5 +863,25 @@ void follow_parent(struct clk *clk) | |||
454 | */ | 863 | */ |
455 | void recalc_root_clocks(void) | 864 | void recalc_root_clocks(void) |
456 | { | 865 | { |
457 | propagate_rate(&root_clks); | 866 | struct clk *pclk; |
867 | unsigned long flags; | ||
868 | int ret = 0; | ||
869 | |||
870 | spin_lock_irqsave(&clocks_lock, flags); | ||
871 | list_for_each_entry(pclk, &root_clks, sibling) { | ||
872 | if (pclk->recalc) { | ||
873 | ret = pclk->recalc(pclk); | ||
874 | /* | ||
875 | * recalc will return error if clk out is not programmed | ||
876 | * In this case configure default clock. | ||
877 | */ | ||
878 | if (ret && pclk->set_rate) | ||
879 | pclk->set_rate(pclk, 0); | ||
880 | } | ||
881 | propagate_rate(pclk, 1); | ||
882 | /* Enable clks enabled on init, in software view */ | ||
883 | if (pclk->flags & ENABLED_ON_INIT) | ||
884 | do_clk_enable(pclk); | ||
885 | } | ||
886 | spin_unlock_irqrestore(&clocks_lock, flags); | ||
458 | } | 887 | } |
diff --git a/arch/arm/plat-spear/include/plat/clock.h b/arch/arm/plat-spear/include/plat/clock.h index 863d9e983927..5a601d830971 100644 --- a/arch/arm/plat-spear/include/plat/clock.h +++ b/arch/arm/plat-spear/include/plat/clock.h | |||
@@ -21,6 +21,7 @@ | |||
21 | /* clk structure flags */ | 21 | /* clk structure flags */ |
22 | #define ALWAYS_ENABLED (1 << 0) /* clock always enabled */ | 22 | #define ALWAYS_ENABLED (1 << 0) /* clock always enabled */ |
23 | #define RESET_TO_ENABLE (1 << 1) /* reset register bit to enable clk */ | 23 | #define RESET_TO_ENABLE (1 << 1) /* reset register bit to enable clk */ |
24 | #define ENABLED_ON_INIT (1 << 2) /* clocks enabled at init */ | ||
24 | 25 | ||
25 | /** | 26 | /** |
26 | * struct clkops - clock operations | 27 | * struct clkops - clock operations |
@@ -35,13 +36,11 @@ struct clkops { | |||
35 | /** | 36 | /** |
36 | * struct pclk_info - parents info | 37 | * struct pclk_info - parents info |
37 | * @pclk: pointer to parent clk | 38 | * @pclk: pointer to parent clk |
38 | * @pclk_mask: value to be written for selecting this parent | 39 | * @pclk_val: value to be written for selecting this parent |
39 | * @scalable: Is parent scalable (1 - YES, 0 - NO) | ||
40 | */ | 40 | */ |
41 | struct pclk_info { | 41 | struct pclk_info { |
42 | struct clk *pclk; | 42 | struct clk *pclk; |
43 | u8 pclk_mask; | 43 | u8 pclk_val; |
44 | u8 scalable; | ||
45 | }; | 44 | }; |
46 | 45 | ||
47 | /** | 46 | /** |
@@ -59,6 +58,18 @@ struct pclk_sel { | |||
59 | }; | 58 | }; |
60 | 59 | ||
61 | /** | 60 | /** |
61 | * struct rate_config - clk rate configurations | ||
62 | * @tbls: array of device specific clk rate tables, in ascending order of rates | ||
63 | * @count: size of tbls array | ||
64 | * @default_index: default setting when originally disabled | ||
65 | */ | ||
66 | struct rate_config { | ||
67 | void *tbls; | ||
68 | u8 count; | ||
69 | u8 default_index; | ||
70 | }; | ||
71 | |||
72 | /** | ||
62 | * struct clk - clock structure | 73 | * struct clk - clock structure |
63 | * @usage_count: num of users who enabled this clock | 74 | * @usage_count: num of users who enabled this clock |
64 | * @flags: flags for clock properties | 75 | * @flags: flags for clock properties |
@@ -67,7 +78,10 @@ struct pclk_sel { | |||
67 | * @en_reg_bit: clk enable/disable bit | 78 | * @en_reg_bit: clk enable/disable bit |
68 | * @ops: clk enable/disable ops - generic_clkops selected if NULL | 79 | * @ops: clk enable/disable ops - generic_clkops selected if NULL |
69 | * @recalc: pointer to clock rate recalculate function | 80 | * @recalc: pointer to clock rate recalculate function |
70 | * @div_factor: division factor to parent clock. Only for recalc = follow_parent | 81 | * @set_rate: pointer to clock set rate function |
82 | * @calc_rate: pointer to clock get rate function for index | ||
83 | * @rate_config: rate configuration information, used by set_rate | ||
84 | * @div_factor: division factor to parent clock. | ||
71 | * @pclk: current parent clk | 85 | * @pclk: current parent clk |
72 | * @pclk_sel: pointer to parent selection structure | 86 | * @pclk_sel: pointer to parent selection structure |
73 | * @pclk_sel_shift: register shift for selecting parent of this clock | 87 | * @pclk_sel_shift: register shift for selecting parent of this clock |
@@ -82,7 +96,10 @@ struct clk { | |||
82 | void __iomem *en_reg; | 96 | void __iomem *en_reg; |
83 | u8 en_reg_bit; | 97 | u8 en_reg_bit; |
84 | const struct clkops *ops; | 98 | const struct clkops *ops; |
85 | void (*recalc) (struct clk *); | 99 | int (*recalc) (struct clk *); |
100 | int (*set_rate) (struct clk *, unsigned long rate); | ||
101 | unsigned long (*calc_rate)(struct clk *, int index); | ||
102 | struct rate_config rate_config; | ||
86 | unsigned int div_factor; | 103 | unsigned int div_factor; |
87 | 104 | ||
88 | struct clk *pclk; | 105 | struct clk *pclk; |
@@ -115,6 +132,14 @@ struct pll_clk_config { | |||
115 | struct pll_clk_masks *masks; | 132 | struct pll_clk_masks *masks; |
116 | }; | 133 | }; |
117 | 134 | ||
135 | /* pll clk rate config structure */ | ||
136 | struct pll_rate_tbl { | ||
137 | u8 mode; | ||
138 | u16 m; | ||
139 | u8 n; | ||
140 | u8 p; | ||
141 | }; | ||
142 | |||
118 | /* ahb and apb bus configuration structure */ | 143 | /* ahb and apb bus configuration structure */ |
119 | struct bus_clk_masks { | 144 | struct bus_clk_masks { |
120 | u32 mask; | 145 | u32 mask; |
@@ -126,6 +151,11 @@ struct bus_clk_config { | |||
126 | struct bus_clk_masks *masks; | 151 | struct bus_clk_masks *masks; |
127 | }; | 152 | }; |
128 | 153 | ||
154 | /* ahb and apb clk bus rate config structure */ | ||
155 | struct bus_rate_tbl { | ||
156 | u8 div; | ||
157 | }; | ||
158 | |||
129 | /* Aux clk configuration structure: applicable to UART and FIRDA */ | 159 | /* Aux clk configuration structure: applicable to UART and FIRDA */ |
130 | struct aux_clk_masks { | 160 | struct aux_clk_masks { |
131 | u32 eq_sel_mask; | 161 | u32 eq_sel_mask; |
@@ -143,6 +173,13 @@ struct aux_clk_config { | |||
143 | struct aux_clk_masks *masks; | 173 | struct aux_clk_masks *masks; |
144 | }; | 174 | }; |
145 | 175 | ||
176 | /* aux clk rate config structure */ | ||
177 | struct aux_rate_tbl { | ||
178 | u16 xscale; | ||
179 | u16 yscale; | ||
180 | u8 eq; | ||
181 | }; | ||
182 | |||
146 | /* GPT clk configuration structure */ | 183 | /* GPT clk configuration structure */ |
147 | struct gpt_clk_masks { | 184 | struct gpt_clk_masks { |
148 | u32 mscale_sel_mask; | 185 | u32 mscale_sel_mask; |
@@ -156,15 +193,48 @@ struct gpt_clk_config { | |||
156 | struct gpt_clk_masks *masks; | 193 | struct gpt_clk_masks *masks; |
157 | }; | 194 | }; |
158 | 195 | ||
196 | /* gpt clk rate config structure */ | ||
197 | struct gpt_rate_tbl { | ||
198 | u16 mscale; | ||
199 | u16 nscale; | ||
200 | }; | ||
201 | |||
202 | /* clcd clk configuration structure */ | ||
203 | struct clcd_synth_masks { | ||
204 | u32 div_factor_mask; | ||
205 | u32 div_factor_shift; | ||
206 | }; | ||
207 | |||
208 | struct clcd_clk_config { | ||
209 | void __iomem *synth_reg; | ||
210 | struct clcd_synth_masks *masks; | ||
211 | }; | ||
212 | |||
213 | /* clcd clk rate config structure */ | ||
214 | struct clcd_rate_tbl { | ||
215 | u16 div; | ||
216 | }; | ||
217 | |||
159 | /* platform specific clock functions */ | 218 | /* platform specific clock functions */ |
160 | void clk_register(struct clk_lookup *cl); | 219 | void clk_register(struct clk_lookup *cl); |
161 | void recalc_root_clocks(void); | 220 | void recalc_root_clocks(void); |
162 | 221 | ||
163 | /* clock recalc functions */ | 222 | /* clock recalc & set rate functions */ |
164 | void follow_parent(struct clk *clk); | 223 | int follow_parent(struct clk *clk); |
165 | void pll_clk_recalc(struct clk *clk); | 224 | unsigned long pll_calc_rate(struct clk *clk, int index); |
166 | void bus_clk_recalc(struct clk *clk); | 225 | int pll_clk_recalc(struct clk *clk); |
167 | void gpt_clk_recalc(struct clk *clk); | 226 | int pll_clk_set_rate(struct clk *clk, unsigned long desired_rate); |
168 | void aux_clk_recalc(struct clk *clk); | 227 | unsigned long bus_calc_rate(struct clk *clk, int index); |
228 | int bus_clk_recalc(struct clk *clk); | ||
229 | int bus_clk_set_rate(struct clk *clk, unsigned long desired_rate); | ||
230 | unsigned long gpt_calc_rate(struct clk *clk, int index); | ||
231 | int gpt_clk_recalc(struct clk *clk); | ||
232 | int gpt_clk_set_rate(struct clk *clk, unsigned long desired_rate); | ||
233 | unsigned long aux_calc_rate(struct clk *clk, int index); | ||
234 | int aux_clk_recalc(struct clk *clk); | ||
235 | int aux_clk_set_rate(struct clk *clk, unsigned long desired_rate); | ||
236 | unsigned long clcd_calc_rate(struct clk *clk, int index); | ||
237 | int clcd_clk_recalc(struct clk *clk); | ||
238 | int clcd_clk_set_rate(struct clk *clk, unsigned long desired_rate); | ||
169 | 239 | ||
170 | #endif /* __PLAT_CLOCK_H */ | 240 | #endif /* __PLAT_CLOCK_H */ |