diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/arm/mach-davinci/clock.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
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..e4e3af179f02 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 > pll->div_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 &= ~pll->div_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)) |