aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-01-27 06:18:24 -0500
committerPaul Mundt <lethal@linux-sh.org>2012-01-27 06:18:24 -0500
commit1bcfc723c8688a257df920999a43bcc2e59d5908 (patch)
treeed9684aed2267f06f05217c4f96978644a82ea6f /arch/sh
parentecbef17adbbbe89eb6b3e4d4e5b756d63041319c (diff)
sh: cpufreq: Support CPU clock frequency table.
This adds support for the frequency table provided by the clock framework under the struct clk definition (if available). In cases where no table is generated or otherwise supported, we fall back on coarse grained scaling via clock framework rounding, as before. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/kernel/cpufreq.c74
1 files changed, 46 insertions, 28 deletions
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c
index 66dbb74546c3..e0accdc5438a 100644
--- a/arch/sh/kernel/cpufreq.c
+++ b/arch/sh/kernel/cpufreq.c
@@ -84,10 +84,32 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy,
84 return 0; 84 return 0;
85} 85}
86 86
87static int sh_cpufreq_verify(struct cpufreq_policy *policy)
88{
89 struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu);
90 struct cpufreq_frequency_table *freq_table;
91
92 freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
93 if (freq_table)
94 return cpufreq_frequency_table_verify(policy, freq_table);
95
96 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
97 policy->cpuinfo.max_freq);
98
99 policy->min = (clk_round_rate(cpuclk, 1) + 500) / 1000;
100 policy->max = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
101
102 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
103 policy->cpuinfo.max_freq);
104
105 return 0;
106}
107
87static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) 108static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
88{ 109{
89 unsigned int cpu = policy->cpu; 110 unsigned int cpu = policy->cpu;
90 struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); 111 struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
112 struct cpufreq_frequency_table *freq_table;
91 struct device *dev; 113 struct device *dev;
92 114
93 if (!cpu_online(cpu)) 115 if (!cpu_online(cpu))
@@ -101,25 +123,24 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
101 return PTR_ERR(cpuclk); 123 return PTR_ERR(cpuclk);
102 } 124 }
103 125
104 /* cpuinfo and default policy values */ 126 policy->cur = policy->min = policy->max = sh_cpufreq_get(cpu);
105 policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
106 policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
107 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
108 127
109 policy->cur = sh_cpufreq_get(cpu); 128 freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
110 policy->min = policy->cpuinfo.min_freq; 129 if (freq_table) {
111 policy->max = policy->cpuinfo.max_freq; 130 int result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
112 131
113 /* 132 if (!result)
114 * Catch the cases where the clock framework hasn't been wired up 133 cpufreq_frequency_table_get_attr(freq_table, cpu);
115 * properly to support scaling. 134 } else {
116 */ 135 policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
117 if (unlikely(policy->min == policy->max)) { 136 policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
118 dev_err(dev, "rate rounding not supported on this CPU.\n");
119 clk_put(cpuclk);
120 return -EINVAL;
121 } 137 }
122 138
139 policy->min = policy->cpuinfo.min_freq;
140 policy->max = policy->cpuinfo.max_freq;
141
142 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
143
123 dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, " 144 dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, "
124 "Maximum %u.%03u MHz.\n", 145 "Maximum %u.%03u MHz.\n",
125 policy->min / 1000, policy->min % 1000, 146 policy->min / 1000, policy->min % 1000,
@@ -128,28 +149,25 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
128 return 0; 149 return 0;
129} 150}
130 151
131static int sh_cpufreq_verify(struct cpufreq_policy *policy) 152static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
132{ 153{
133 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 154 unsigned int cpu = policy->cpu;
134 policy->cpuinfo.max_freq); 155 struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
135 return 0;
136}
137 156
138static int sh_cpufreq_exit(struct cpufreq_policy *policy) 157 cpufreq_frequency_table_put_attr(cpu);
139{
140 struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu);
141 clk_put(cpuclk); 158 clk_put(cpuclk);
159
142 return 0; 160 return 0;
143} 161}
144 162
145static struct cpufreq_driver sh_cpufreq_driver = { 163static struct cpufreq_driver sh_cpufreq_driver = {
146 .owner = THIS_MODULE, 164 .owner = THIS_MODULE,
147 .name = "sh", 165 .name = "sh",
148 .init = sh_cpufreq_cpu_init,
149 .verify = sh_cpufreq_verify,
150 .target = sh_cpufreq_target,
151 .get = sh_cpufreq_get, 166 .get = sh_cpufreq_get,
152 .exit = sh_cpufreq_exit, 167 .target = sh_cpufreq_target,
168 .verify = sh_cpufreq_verify,
169 .init = sh_cpufreq_cpu_init,
170 .exit = sh_cpufreq_cpu_exit,
153}; 171};
154 172
155static int __init sh_cpufreq_module_init(void) 173static int __init sh_cpufreq_module_init(void)