diff options
Diffstat (limited to 'drivers/sh')
-rw-r--r-- | drivers/sh/clk/core.c | 96 | ||||
-rw-r--r-- | drivers/sh/intc/core.c | 2 | ||||
-rw-r--r-- | drivers/sh/intc/dynamic.c | 2 |
3 files changed, 96 insertions, 4 deletions
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index fd0d1b98901c..09615b51d591 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 %lu, 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 %lu, 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 | { |
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 873a99ff8f64..e5e9e6735f7d 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c | |||
@@ -79,7 +79,7 @@ static void __init intc_register_irq(struct intc_desc *desc, | |||
79 | * Register the IRQ position with the global IRQ map, then insert | 79 | * Register the IRQ position with the global IRQ map, then insert |
80 | * it in to the radix tree. | 80 | * it in to the radix tree. |
81 | */ | 81 | */ |
82 | irq_reserve_irqs(irq, 1); | 82 | irq_reserve_irq(irq); |
83 | 83 | ||
84 | raw_spin_lock_irqsave(&intc_big_lock, flags); | 84 | raw_spin_lock_irqsave(&intc_big_lock, flags); |
85 | radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq)); | 85 | radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq)); |
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c index 4187cce20ffd..a3677c9dfe36 100644 --- a/drivers/sh/intc/dynamic.c +++ b/drivers/sh/intc/dynamic.c | |||
@@ -60,5 +60,5 @@ void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs) | |||
60 | int i; | 60 | int i; |
61 | 61 | ||
62 | for (i = 0; i < nr_vecs; i++) | 62 | for (i = 0; i < nr_vecs; i++) |
63 | irq_reserve_irqs(evt2irq(vectors[i].vect), 1); | 63 | irq_reserve_irq(evt2irq(vectors[i].vect)); |
64 | } | 64 | } |