diff options
Diffstat (limited to 'arch/arm/mach-davinci/clock.c')
-rw-r--r-- | arch/arm/mach-davinci/clock.c | 75 |
1 files changed, 74 insertions, 1 deletions
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 054c303caead..01ba080433db 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c | |||
@@ -236,7 +236,7 @@ static int __init clk_disable_unused(void) | |||
236 | if (!davinci_psc_is_clk_active(ck->gpsc, ck->lpsc)) | 236 | if (!davinci_psc_is_clk_active(ck->gpsc, ck->lpsc)) |
237 | continue; | 237 | continue; |
238 | 238 | ||
239 | pr_info("Clocks: disable unused %s\n", ck->name); | 239 | pr_debug("Clocks: disable unused %s\n", ck->name); |
240 | 240 | ||
241 | davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, | 241 | davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, |
242 | (ck->flags & PSC_SWRSTDISABLE) ? | 242 | (ck->flags & PSC_SWRSTDISABLE) ? |
@@ -287,6 +287,79 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) | |||
287 | return rate; | 287 | return rate; |
288 | } | 288 | } |
289 | 289 | ||
290 | int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate) | ||
291 | { | ||
292 | unsigned v; | ||
293 | struct pll_data *pll; | ||
294 | unsigned long input; | ||
295 | unsigned ratio = 0; | ||
296 | |||
297 | /* If this is the PLL base clock, wrong function to call */ | ||
298 | if (clk->pll_data) | ||
299 | return -EINVAL; | ||
300 | |||
301 | /* There must be a parent... */ | ||
302 | if (WARN_ON(!clk->parent)) | ||
303 | return -EINVAL; | ||
304 | |||
305 | /* ... the parent must be a PLL... */ | ||
306 | if (WARN_ON(!clk->parent->pll_data)) | ||
307 | return -EINVAL; | ||
308 | |||
309 | /* ... and this clock must have a divider. */ | ||
310 | if (WARN_ON(!clk->div_reg)) | ||
311 | return -EINVAL; | ||
312 | |||
313 | pll = clk->parent->pll_data; | ||
314 | |||
315 | input = clk->parent->rate; | ||
316 | |||
317 | /* If pre-PLL, source clock is before the multiplier and divider(s) */ | ||
318 | if (clk->flags & PRE_PLL) | ||
319 | input = pll->input_rate; | ||
320 | |||
321 | if (input > rate) { | ||
322 | /* | ||
323 | * Can afford to provide an output little higher than requested | ||
324 | * only if maximum rate supported by hardware on this sysclk | ||
325 | * is known. | ||
326 | */ | ||
327 | if (clk->maxrate) { | ||
328 | ratio = DIV_ROUND_CLOSEST(input, rate); | ||
329 | if (input / ratio > clk->maxrate) | ||
330 | ratio = 0; | ||
331 | } | ||
332 | |||
333 | if (ratio == 0) | ||
334 | ratio = DIV_ROUND_UP(input, rate); | ||
335 | |||
336 | ratio--; | ||
337 | } | ||
338 | |||
339 | if (ratio > PLLDIV_RATIO_MASK) | ||
340 | return -EINVAL; | ||
341 | |||
342 | do { | ||
343 | v = __raw_readl(pll->base + PLLSTAT); | ||
344 | } while (v & PLLSTAT_GOSTAT); | ||
345 | |||
346 | v = __raw_readl(pll->base + clk->div_reg); | ||
347 | v &= ~PLLDIV_RATIO_MASK; | ||
348 | v |= ratio | PLLDIV_EN; | ||
349 | __raw_writel(v, pll->base + clk->div_reg); | ||
350 | |||
351 | v = __raw_readl(pll->base + PLLCMD); | ||
352 | v |= PLLCMD_GOSET; | ||
353 | __raw_writel(v, pll->base + PLLCMD); | ||
354 | |||
355 | do { | ||
356 | v = __raw_readl(pll->base + PLLSTAT); | ||
357 | } while (v & PLLSTAT_GOSTAT); | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | EXPORT_SYMBOL(davinci_set_sysclk_rate); | ||
362 | |||
290 | static unsigned long clk_leafclk_recalc(struct clk *clk) | 363 | static unsigned long clk_leafclk_recalc(struct clk *clk) |
291 | { | 364 | { |
292 | if (WARN_ON(!clk->parent)) | 365 | if (WARN_ON(!clk->parent)) |