aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/sh/clk.c66
-rw-r--r--include/linux/sh_clk.h1
2 files changed, 53 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)
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index 8ae37707a4a4..49f6e9b6eda2 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -53,6 +53,7 @@ struct clk {
53 struct dentry *dentry; 53 struct dentry *dentry;
54 struct clk_mapping *mapping; 54 struct clk_mapping *mapping;
55 struct cpufreq_frequency_table *freq_table; 55 struct cpufreq_frequency_table *freq_table;
56 unsigned int nr_freqs;
56}; 57};
57 58
58#define CLK_ENABLE_ON_INIT (1 << 0) 59#define CLK_ENABLE_ON_INIT (1 << 0)