ux500: dynamic SOC detection
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / arm / mach-ux500 / cpufreq.c
blob5c5b747f134dcf6dc2c3293d798fbca44bf2344f
1 /*
2 * CPU frequency scaling for u8500
3 * Inspired by linux/arch/arm/mach-davinci/cpufreq.c
5 * Copyright (C) STMicroelectronics 2009
6 * Copyright (C) ST-Ericsson SA 2010
8 * License Terms: GNU General Public License v2
10 * Author: Sundar Iyer <sundar.iyer@stericsson.com>
11 * Author: Martin Persson <martin.persson@stericsson.com>
12 * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
16 #include <linux/platform_device.h>
17 #include <linux/kernel.h>
18 #include <linux/cpufreq.h>
19 #include <linux/delay.h>
21 #include <mach/hardware.h>
22 #include <mach/prcmu.h>
23 #include <mach/prcmu-defs.h>
25 #define DRIVER_NAME "cpufreq-u8500"
26 #define CPUFREQ_NAME "u8500"
28 static struct device *dev;
30 static struct cpufreq_frequency_table freq_table[] = {
31 [0] = {
32 .index = 0,
33 .frequency = 200000,
35 [1] = {
36 .index = 1,
37 .frequency = 300000,
39 [2] = {
40 .index = 2,
41 .frequency = 600000,
43 [3] = {
44 /* Used for CPU_OPP_MAX, if available */
45 .index = 3,
46 .frequency = CPUFREQ_TABLE_END,
48 [4] = {
49 .index = 4,
50 .frequency = CPUFREQ_TABLE_END,
54 static enum prcmu_cpu_opp index2opp[] = {
55 CPU_OPP_EXT_CLK,
56 CPU_OPP_50,
57 CPU_OPP_100,
58 CPU_OPP_MAX
61 static int u8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
63 return cpufreq_frequency_table_verify(policy, freq_table);
66 static int u8500_cpufreq_target(struct cpufreq_policy *policy,
67 unsigned int target_freq,
68 unsigned int relation)
70 struct cpufreq_freqs freqs;
71 unsigned int index;
72 int ret = 0;
75 * Ensure desired rate is within allowed range. Some govenors
76 * (ondemand) will just pass target_freq=0 to get the minimum.
78 if (target_freq < policy->cpuinfo.min_freq)
79 target_freq = policy->cpuinfo.min_freq;
80 if (target_freq > policy->cpuinfo.max_freq)
81 target_freq = policy->cpuinfo.max_freq;
83 ret = cpufreq_frequency_table_target(policy, freq_table,
84 target_freq, relation, &index);
85 if (ret < 0) {
86 dev_err(dev, "Could not look up next frequency\n");
87 return ret;
90 freqs.old = policy->cur;
91 freqs.new = freq_table[index].frequency;
92 freqs.cpu = policy->cpu;
94 if (freqs.old == freqs.new) {
95 dev_dbg(dev, "Current and target frequencies are equal\n");
96 return 0;
99 dev_dbg(dev, "transition: %u --> %u\n", freqs.old, freqs.new);
100 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
102 ret = prcmu_set_cpu_opp(index2opp[index]);
103 if (ret < 0) {
104 dev_err(dev, "Failed to set OPP level\n");
105 return ret;
108 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
110 return ret;
113 static unsigned int u8500_cpufreq_getspeed(unsigned int cpu)
115 int i;
117 for (i = 0; prcmu_get_cpu_opp() != index2opp[i]; i++)
119 return freq_table[i].frequency;
122 static int __cpuinit u8500_cpu_init(struct cpufreq_policy *policy)
124 int res;
126 BUILD_BUG_ON(ARRAY_SIZE(index2opp) + 1 != ARRAY_SIZE(freq_table));
128 if (cpu_is_u8500v2()) {
129 freq_table[1].frequency = 400000;
130 freq_table[2].frequency = 800000;
131 if (prcmu_has_arm_maxopp())
132 freq_table[3].frequency = 1000000;
135 /* get policy fields based on the table */
136 res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
137 if (!res)
138 cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
139 else {
140 dev_err(dev, "u8500-cpufreq : Failed to read policy table\n");
141 return res;
144 policy->min = policy->cpuinfo.min_freq;
145 policy->max = policy->cpuinfo.max_freq;
146 policy->cur = u8500_cpufreq_getspeed(policy->cpu);
147 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
150 * FIXME : Need to take time measurement across the target()
151 * function with no/some/all drivers in the notification
152 * list.
154 policy->cpuinfo.transition_latency = 200 * 1000; /* in ns */
156 /* policy sharing between dual CPUs */
157 cpumask_copy(policy->cpus, &cpu_present_map);
159 policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
161 return res;
164 static struct freq_attr *u8500_cpufreq_attr[] = {
165 &cpufreq_freq_attr_scaling_available_freqs,
166 NULL,
168 static int u8500_cpu_exit(struct cpufreq_policy *policy)
170 cpufreq_frequency_table_put_attr(policy->cpu);
171 return 0;
174 static struct cpufreq_driver u8500_driver = {
175 .owner = THIS_MODULE,
176 .flags = CPUFREQ_STICKY,
177 .verify = u8500_cpufreq_verify_speed,
178 .target = u8500_cpufreq_target,
179 .get = u8500_cpufreq_getspeed,
180 .init = u8500_cpu_init,
181 .exit = u8500_cpu_exit,
182 .name = CPUFREQ_NAME,
183 .attr = u8500_cpufreq_attr,
186 static int __init u8500_cpufreq_probe(struct platform_device *pdev)
188 dev = &pdev->dev;
189 return cpufreq_register_driver(&u8500_driver);
192 static int __exit u8500_cpufreq_remove(struct platform_device *pdev)
194 return cpufreq_unregister_driver(&u8500_driver);
197 static struct platform_driver u8500_cpufreq_driver = {
198 .driver = {
199 .name = DRIVER_NAME,
200 .owner = THIS_MODULE,
202 .remove = __exit_p(u8500_cpufreq_remove),
205 static int __init u8500_cpufreq_init(void)
207 return platform_driver_probe(&u8500_cpufreq_driver,
208 &u8500_cpufreq_probe);
211 device_initcall(u8500_cpufreq_init);