diff options
| -rw-r--r-- | drivers/sh/clk.c | 66 | ||||
| -rw-r--r-- | include/linux/sh_clk.h | 1 |
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 | ||
| 72 | long clk_rate_table_round(struct clk *clk, | 74 | struct clk_rate_round_data; |
| 73 | struct cpufreq_frequency_table *freq_table, | 75 | |
| 74 | unsigned long rate) | 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 | 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 | ||
| 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); | ||
| 149 | } | ||
| 150 | |||
| 113 | int clk_rate_table_find(struct clk *clk, | 151 | int 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) |
