diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-11-29 01:44:01 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-11-29 01:44:01 -0500 |
commit | ca19e77e44985b5500f5461f7d2f4ce799cb60ce (patch) | |
tree | 3ba3635ac2f212b332198b14cc3239195c153e67 /drivers/sh/clk/core.c | |
parent | 9d57883f08d3c0c111b50bf185dfee9731a12c76 (diff) | |
parent | ac70eb1305d5a81efd1e32327d7e79be15a63a5a (diff) |
Merge branch 'fix/hda' into topic/hda
Diffstat (limited to 'drivers/sh/clk/core.c')
-rw-r--r-- | drivers/sh/clk/core.c | 96 |
1 files changed, 94 insertions, 2 deletions
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index fd0d1b98901c..cb12a8e1466b 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c | |||
@@ -90,8 +90,8 @@ struct clk_rate_round_data { | |||
90 | static long clk_rate_round_helper(struct clk_rate_round_data *rounder) | 90 | static long clk_rate_round_helper(struct clk_rate_round_data *rounder) |
91 | { | 91 | { |
92 | unsigned long rate_error, rate_error_prev = ~0UL; | 92 | unsigned long rate_error, rate_error_prev = ~0UL; |
93 | unsigned long rate_best_fit = rounder->rate; | ||
94 | unsigned long highest, lowest, freq; | 93 | unsigned long highest, lowest, freq; |
94 | long rate_best_fit = -ENOENT; | ||
95 | int i; | 95 | int i; |
96 | 96 | ||
97 | highest = 0; | 97 | highest = 0; |
@@ -146,7 +146,7 @@ long clk_rate_table_round(struct clk *clk, | |||
146 | }; | 146 | }; |
147 | 147 | ||
148 | if (clk->nr_freqs < 1) | 148 | if (clk->nr_freqs < 1) |
149 | return 0; | 149 | return -ENOSYS; |
150 | 150 | ||
151 | return clk_rate_round_helper(&table_round); | 151 | return clk_rate_round_helper(&table_round); |
152 | } | 152 | } |
@@ -541,6 +541,98 @@ long clk_round_rate(struct clk *clk, unsigned long rate) | |||
541 | } | 541 | } |
542 | EXPORT_SYMBOL_GPL(clk_round_rate); | 542 | EXPORT_SYMBOL_GPL(clk_round_rate); |
543 | 543 | ||
544 | long clk_round_parent(struct clk *clk, unsigned long target, | ||
545 | unsigned long *best_freq, unsigned long *parent_freq, | ||
546 | unsigned int div_min, unsigned int div_max) | ||
547 | { | ||
548 | struct cpufreq_frequency_table *freq, *best = NULL; | ||
549 | unsigned long error = ULONG_MAX, freq_high, freq_low, div; | ||
550 | struct clk *parent = clk_get_parent(clk); | ||
551 | |||
552 | if (!parent) { | ||
553 | *parent_freq = 0; | ||
554 | *best_freq = clk_round_rate(clk, target); | ||
555 | return abs(target - *best_freq); | ||
556 | } | ||
557 | |||
558 | for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END; | ||
559 | freq++) { | ||
560 | if (freq->frequency == CPUFREQ_ENTRY_INVALID) | ||
561 | continue; | ||
562 | |||
563 | if (unlikely(freq->frequency / target <= div_min - 1)) { | ||
564 | unsigned long freq_max; | ||
565 | |||
566 | freq_max = (freq->frequency + div_min / 2) / div_min; | ||
567 | if (error > target - freq_max) { | ||
568 | error = target - freq_max; | ||
569 | best = freq; | ||
570 | if (best_freq) | ||
571 | *best_freq = freq_max; | ||
572 | } | ||
573 | |||
574 | pr_debug("too low freq %u, error %lu\n", freq->frequency, | ||
575 | target - freq_max); | ||
576 | |||
577 | if (!error) | ||
578 | break; | ||
579 | |||
580 | continue; | ||
581 | } | ||
582 | |||
583 | if (unlikely(freq->frequency / target >= div_max)) { | ||
584 | unsigned long freq_min; | ||
585 | |||
586 | freq_min = (freq->frequency + div_max / 2) / div_max; | ||
587 | if (error > freq_min - target) { | ||
588 | error = freq_min - target; | ||
589 | best = freq; | ||
590 | if (best_freq) | ||
591 | *best_freq = freq_min; | ||
592 | } | ||
593 | |||
594 | pr_debug("too high freq %u, error %lu\n", freq->frequency, | ||
595 | freq_min - target); | ||
596 | |||
597 | if (!error) | ||
598 | break; | ||
599 | |||
600 | continue; | ||
601 | } | ||
602 | |||
603 | div = freq->frequency / target; | ||
604 | freq_high = freq->frequency / div; | ||
605 | freq_low = freq->frequency / (div + 1); | ||
606 | |||
607 | if (freq_high - target < error) { | ||
608 | error = freq_high - target; | ||
609 | best = freq; | ||
610 | if (best_freq) | ||
611 | *best_freq = freq_high; | ||
612 | } | ||
613 | |||
614 | if (target - freq_low < error) { | ||
615 | error = target - freq_low; | ||
616 | best = freq; | ||
617 | if (best_freq) | ||
618 | *best_freq = freq_low; | ||
619 | } | ||
620 | |||
621 | pr_debug("%u / %lu = %lu, / %lu = %lu, best %lu, parent %u\n", | ||
622 | freq->frequency, div, freq_high, div + 1, freq_low, | ||
623 | *best_freq, best->frequency); | ||
624 | |||
625 | if (!error) | ||
626 | break; | ||
627 | } | ||
628 | |||
629 | if (parent_freq) | ||
630 | *parent_freq = best->frequency; | ||
631 | |||
632 | return error; | ||
633 | } | ||
634 | EXPORT_SYMBOL_GPL(clk_round_parent); | ||
635 | |||
544 | #ifdef CONFIG_PM | 636 | #ifdef CONFIG_PM |
545 | static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) | 637 | static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) |
546 | { | 638 | { |