diff options
Diffstat (limited to 'drivers/cpufreq/at32ap-cpufreq.c')
-rw-r--r-- | drivers/cpufreq/at32ap-cpufreq.c | 67 |
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 | ||
23 | static struct clk *cpuclk; | 24 | static struct clk *cpuclk; |
24 | 25 | static struct cpufreq_frequency_table *freq_table; | |
25 | static 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 | ||
35 | static unsigned int at32_get_speed(unsigned int cpu) | 27 | static 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 | ||
86 | static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy) | 78 | static 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); | ||
132 | out_err_put_clk: | ||
133 | clk_put(cpuclk); | ||
134 | out_err: | ||
135 | return retval; | ||
107 | } | 136 | } |
108 | 137 | ||
109 | static struct cpufreq_driver at32_driver = { | 138 | static 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, |