aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-10-15 05:17:35 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-10-15 05:17:35 -0400
commitf586903d27e2503a3e7d427b3d665bbaf1b7f4d4 (patch)
tree4f0cdaac4f18025f46fc35418a54747d6b294205 /drivers/sh
parent28085bc5de19cad365bcff98e9c8785c397c7c36 (diff)
sh: clkfwk: Abstract rate rounding helper.
Presently the only assisted rate rounding is frequency table backed, but there are cases where it's impractical to use a frequency table for certain clocks (such as the FSIDIV case, which supports 65535 divisors), and we wish to reuse the same rate rounding algorithm. This breaks out the core of the rate rounding logic in to its own helper routine and shuffles the frequency table logic around, switching to using an iterator for the generic helper routine. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/sh')
-rw-r--r--drivers/sh/clk.c66
1 files changed, 52 insertions, 14 deletions
diff --git a/drivers/sh/clk.c b/drivers/sh/clk.c
index 813d97cdad49..3ac6fa0005b9 100644
--- a/drivers/sh/clk.c
+++ b/drivers/sh/clk.c
@@ -45,6 +45,8 @@ void clk_rate_table_build(struct clk *clk,
45 unsigned long freq; 45 unsigned long freq;
46 int i; 46 int i;
47 47
48 clk->nr_freqs = nr_freqs;
49
48 for (i = 0; i < nr_freqs; i++) { 50 for (i = 0; i < nr_freqs; i++) {
49 div = 1; 51 div = 1;
50 mult = 1; 52 mult = 1;
@@ -69,30 +71,39 @@ void clk_rate_table_build(struct clk *clk,
69 freq_table[i].frequency = CPUFREQ_TABLE_END; 71 freq_table[i].frequency = CPUFREQ_TABLE_END;
70} 72}
71 73
72long clk_rate_table_round(struct clk *clk, 74struct clk_rate_round_data;
73 struct cpufreq_frequency_table *freq_table, 75
74 unsigned long rate) 76struct clk_rate_round_data {
77 unsigned long rate;
78 unsigned int min, max;
79 long (*func)(unsigned int pos, struct clk_rate_round_data *arg);
80 void *arg;
81};
82
83#define for_each_frequency(pos, r, freq) \
84 for (pos = r->min, freq = r->func(pos, r->arg); \
85 pos < r->max; pos++, freq = r->func(pos, r)) \
86 if (unlikely(freq == 0)) \
87 ; \
88 else
89
90static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
75{ 91{
76 unsigned long rate_error, rate_error_prev = ~0UL; 92 unsigned long rate_error, rate_error_prev = ~0UL;
77 unsigned long rate_best_fit = rate; 93 unsigned long rate_best_fit = rounder->rate;
78 unsigned long highest, lowest; 94 unsigned long highest, lowest, freq;
79 int i; 95 int i;
80 96
81 highest = 0; 97 highest = 0;
82 lowest = ~0UL; 98 lowest = ~0UL;
83 99
84 for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { 100 for_each_frequency(i, rounder, freq) {
85 unsigned long freq = freq_table[i].frequency;
86
87 if (freq == CPUFREQ_ENTRY_INVALID)
88 continue;
89
90 if (freq > highest) 101 if (freq > highest)
91 highest = freq; 102 highest = freq;
92 if (freq < lowest) 103 if (freq < lowest)
93 lowest = freq; 104 lowest = freq;
94 105
95 rate_error = abs(freq - rate); 106 rate_error = abs(freq - rounder->rate);
96 if (rate_error < rate_error_prev) { 107 if (rate_error < rate_error_prev) {
97 rate_best_fit = freq; 108 rate_best_fit = freq;
98 rate_error_prev = rate_error; 109 rate_error_prev = rate_error;
@@ -102,14 +113,41 @@ long clk_rate_table_round(struct clk *clk,
102 break; 113 break;
103 } 114 }
104 115
105 if (rate >= highest) 116 if (rounder->rate >= highest)
106 rate_best_fit = highest; 117 rate_best_fit = highest;
107 if (rate <= lowest) 118 if (rounder->rate <= lowest)
108 rate_best_fit = lowest; 119 rate_best_fit = lowest;
109 120
110 return rate_best_fit; 121 return rate_best_fit;
111} 122}
112 123
124static long clk_rate_table_iter(unsigned int pos,
125 struct clk_rate_round_data *rounder)
126{
127 struct cpufreq_frequency_table *freq_table = rounder->arg;
128 unsigned long freq = freq_table[pos].frequency;
129
130 if (freq == CPUFREQ_ENTRY_INVALID)
131 freq = 0;
132
133 return freq;
134}
135
136long clk_rate_table_round(struct clk *clk,
137 struct cpufreq_frequency_table *freq_table,
138 unsigned long rate)
139{
140 struct clk_rate_round_data table_round = {
141 .min = 0,
142 .max = clk->nr_freqs,
143 .func = clk_rate_table_iter,
144 .arg = freq_table,
145 .rate = rate,
146 };
147
148 return clk_rate_round_helper(&table_round);
149}
150
113int clk_rate_table_find(struct clk *clk, 151int clk_rate_table_find(struct clk *clk,
114 struct cpufreq_frequency_table *freq_table, 152 struct cpufreq_frequency_table *freq_table,
115 unsigned long rate) 153 unsigned long rate)