Commit f586903d27e2503a3e7d427b3d665bbaf1b7f4d4
1 parent
28085bc5de
Exists in
master
and in
4 other branches
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>
Showing 2 changed files with 53 additions and 14 deletions Side-by-side Diff
drivers/sh/clk.c
... | ... | @@ -45,6 +45,8 @@ |
45 | 45 | unsigned long freq; |
46 | 46 | int i; |
47 | 47 | |
48 | + clk->nr_freqs = nr_freqs; | |
49 | + | |
48 | 50 | for (i = 0; i < nr_freqs; i++) { |
49 | 51 | div = 1; |
50 | 52 | mult = 1; |
51 | 53 | |
52 | 54 | |
53 | 55 | |
... | ... | @@ -69,30 +71,39 @@ |
69 | 71 | freq_table[i].frequency = CPUFREQ_TABLE_END; |
70 | 72 | } |
71 | 73 | |
72 | -long clk_rate_table_round(struct clk *clk, | |
73 | - struct cpufreq_frequency_table *freq_table, | |
74 | - unsigned long rate) | |
74 | +struct clk_rate_round_data; | |
75 | + | |
76 | +struct 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 | + | |
90 | +static long clk_rate_round_helper(struct clk_rate_round_data *rounder) | |
75 | 91 | { |
76 | 92 | unsigned long rate_error, rate_error_prev = ~0UL; |
77 | - unsigned long rate_best_fit = rate; | |
78 | - unsigned long highest, lowest; | |
93 | + unsigned long rate_best_fit = rounder->rate; | |
94 | + unsigned long highest, lowest, freq; | |
79 | 95 | int i; |
80 | 96 | |
81 | 97 | highest = 0; |
82 | 98 | lowest = ~0UL; |
83 | 99 | |
84 | - for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { | |
85 | - unsigned long freq = freq_table[i].frequency; | |
86 | - | |
87 | - if (freq == CPUFREQ_ENTRY_INVALID) | |
88 | - continue; | |
89 | - | |
100 | + for_each_frequency(i, rounder, freq) { | |
90 | 101 | if (freq > highest) |
91 | 102 | highest = freq; |
92 | 103 | if (freq < lowest) |
93 | 104 | lowest = freq; |
94 | 105 | |
95 | - rate_error = abs(freq - rate); | |
106 | + rate_error = abs(freq - rounder->rate); | |
96 | 107 | if (rate_error < rate_error_prev) { |
97 | 108 | rate_best_fit = freq; |
98 | 109 | rate_error_prev = rate_error; |
99 | 110 | |
100 | 111 | |
... | ... | @@ -102,12 +113,39 @@ |
102 | 113 | break; |
103 | 114 | } |
104 | 115 | |
105 | - if (rate >= highest) | |
116 | + if (rounder->rate >= highest) | |
106 | 117 | rate_best_fit = highest; |
107 | - if (rate <= lowest) | |
118 | + if (rounder->rate <= lowest) | |
108 | 119 | rate_best_fit = lowest; |
109 | 120 | |
110 | 121 | return rate_best_fit; |
122 | +} | |
123 | + | |
124 | +static 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 | + | |
136 | +long 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); | |
111 | 149 | } |
112 | 150 | |
113 | 151 | int clk_rate_table_find(struct clk *clk, |