summaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/at32ap-cpufreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpufreq/at32ap-cpufreq.c')
-rw-r--r--drivers/cpufreq/at32ap-cpufreq.c67
1 files changed, 48 insertions, 19 deletions
diff --git a/drivers/cpufreq/at32ap-cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c
index e0c38d938997..7439deddd5cf 100644
--- a/drivers/cpufreq/at32ap-cpufreq.c
+++ b/drivers/cpufreq/at32ap-cpufreq.c
@@ -19,18 +19,10 @@
19#include <linux/clk.h> 19#include <linux/clk.h>
20#include <linux/err.h> 20#include <linux/err.h>
21#include <linux/export.h> 21#include <linux/export.h>
22#include <linux/slab.h>
22 23
23static struct clk *cpuclk; 24static struct clk *cpuclk;
24 25static struct cpufreq_frequency_table *freq_table;
25static int at32_verify_speed(struct cpufreq_policy *policy)
26{
27 if (policy->cpu != 0)
28 return -EINVAL;
29
30 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
31 policy->cpuinfo.max_freq);
32 return 0;
33}
34 26
35static unsigned int at32_get_speed(unsigned int cpu) 27static unsigned int at32_get_speed(unsigned int cpu)
36{ 28{
@@ -85,31 +77,68 @@ static int at32_set_target(struct cpufreq_policy *policy,
85 77
86static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy) 78static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy)
87{ 79{
80 unsigned int frequency, rate, min_freq;
81 int retval, steps, i;
82
88 if (policy->cpu != 0) 83 if (policy->cpu != 0)
89 return -EINVAL; 84 return -EINVAL;
90 85
91 cpuclk = clk_get(NULL, "cpu"); 86 cpuclk = clk_get(NULL, "cpu");
92 if (IS_ERR(cpuclk)) { 87 if (IS_ERR(cpuclk)) {
93 pr_debug("cpufreq: could not get CPU clk\n"); 88 pr_debug("cpufreq: could not get CPU clk\n");
94 return PTR_ERR(cpuclk); 89 retval = PTR_ERR(cpuclk);
90 goto out_err;
95 } 91 }
96 92
97 policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000; 93 min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
98 policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; 94 frequency = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
99 policy->cpuinfo.transition_latency = 0; 95 policy->cpuinfo.transition_latency = 0;
100 policy->cur = at32_get_speed(0);
101 policy->min = policy->cpuinfo.min_freq;
102 policy->max = policy->cpuinfo.max_freq;
103 96
104 printk("cpufreq: AT32AP CPU frequency driver\n"); 97 /*
98 * AVR32 CPU frequency rate scales in power of two between maximum and
99 * minimum, also add space for the table end marker.
100 *
101 * Further validate that the frequency is usable, and append it to the
102 * frequency table.
103 */
104 steps = fls(frequency / min_freq) + 1;
105 freq_table = kzalloc(steps * sizeof(struct cpufreq_frequency_table),
106 GFP_KERNEL);
107 if (!freq_table) {
108 retval = -ENOMEM;
109 goto out_err_put_clk;
110 }
111
112 for (i = 0; i < (steps - 1); i++) {
113 rate = clk_round_rate(cpuclk, frequency * 1000) / 1000;
105 114
106 return 0; 115 if (rate != frequency)
116 freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
117 else
118 freq_table[i].frequency = frequency;
119
120 frequency /= 2;
121 }
122
123 freq_table[steps - 1].frequency = CPUFREQ_TABLE_END;
124
125 retval = cpufreq_table_validate_and_show(policy, freq_table);
126 if (!retval) {
127 printk("cpufreq: AT32AP CPU frequency driver\n");
128 return 0;
129 }
130
131 kfree(freq_table);
132out_err_put_clk:
133 clk_put(cpuclk);
134out_err:
135 return retval;
107} 136}
108 137
109static struct cpufreq_driver at32_driver = { 138static struct cpufreq_driver at32_driver = {
110 .name = "at32ap", 139 .name = "at32ap",
111 .init = at32_cpufreq_driver_init, 140 .init = at32_cpufreq_driver_init,
112 .verify = at32_verify_speed, 141 .verify = cpufreq_generic_frequency_table_verify,
113 .target = at32_set_target, 142 .target = at32_set_target,
114 .get = at32_get_speed, 143 .get = at32_get_speed,
115 .flags = CPUFREQ_STICKY, 144 .flags = CPUFREQ_STICKY,