2 * Copyright (C) STMicroelectronics 2009
3 * Copyright (C) ST-Ericsson SA 2010
5 * License Terms: GNU General Public License v2
6 * Author: Sundar Iyer <sundar.iyer@stericsson.com>
7 * Author: Martin Persson <martin.persson@stericsson.com>
8 * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
11 #include <linux/kernel.h>
12 #include <linux/cpufreq.h>
13 #include <linux/delay.h>
14 #include <linux/slab.h>
15 #include <linux/mfd/db8500-prcmu.h>
18 static struct cpufreq_frequency_table freq_table
[] = {
28 /* Used for MAX_OPP, if available */
30 .frequency
= CPUFREQ_TABLE_END
,
34 .frequency
= CPUFREQ_TABLE_END
,
38 static enum arm_opp idx2opp
[] = {
44 static struct freq_attr
*db8500_cpufreq_attr
[] = {
45 &cpufreq_freq_attr_scaling_available_freqs
,
49 static int db8500_cpufreq_verify_speed(struct cpufreq_policy
*policy
)
51 return cpufreq_frequency_table_verify(policy
, freq_table
);
54 static int db8500_cpufreq_target(struct cpufreq_policy
*policy
,
55 unsigned int target_freq
,
56 unsigned int relation
)
58 struct cpufreq_freqs freqs
;
61 /* scale the target frequency to one of the extremes supported */
62 if (target_freq
< policy
->cpuinfo
.min_freq
)
63 target_freq
= policy
->cpuinfo
.min_freq
;
64 if (target_freq
> policy
->cpuinfo
.max_freq
)
65 target_freq
= policy
->cpuinfo
.max_freq
;
67 /* Lookup the next frequency */
68 if (cpufreq_frequency_table_target
69 (policy
, freq_table
, target_freq
, relation
, &idx
)) {
73 freqs
.old
= policy
->cur
;
74 freqs
.new = freq_table
[idx
].frequency
;
75 freqs
.cpu
= policy
->cpu
;
77 if (freqs
.old
== freqs
.new)
80 /* pre-change notification */
81 cpufreq_notify_transition(&freqs
, CPUFREQ_PRECHANGE
);
83 /* request the PRCM unit for opp change */
84 if (prcmu_set_arm_opp(idx2opp
[idx
])) {
85 pr_err("db8500-cpufreq: Failed to set OPP level\n");
89 /* post change notification */
90 cpufreq_notify_transition(&freqs
, CPUFREQ_POSTCHANGE
);
95 static unsigned int db8500_cpufreq_getspeed(unsigned int cpu
)
98 /* request the prcm to get the current ARM opp */
99 for (i
= 0; prcmu_get_arm_opp() != idx2opp
[i
]; i
++)
101 return freq_table
[i
].frequency
;
104 static int __cpuinit
db8500_cpufreq_init(struct cpufreq_policy
*policy
)
109 BUILD_BUG_ON(ARRAY_SIZE(idx2opp
) + 1 != ARRAY_SIZE(freq_table
));
111 if (cpu_is_u8500v2() && !prcmu_is_u8400()) {
112 freq_table
[0].frequency
= 400000;
113 freq_table
[1].frequency
= 800000;
114 if (prcmu_has_arm_maxopp())
115 freq_table
[2].frequency
= 1000000;
118 /* get policy fields based on the table */
119 res
= cpufreq_frequency_table_cpuinfo(policy
, freq_table
);
121 cpufreq_frequency_table_get_attr(freq_table
, policy
->cpu
);
123 pr_err("db8500-cpufreq : Failed to read policy table\n");
127 policy
->min
= policy
->cpuinfo
.min_freq
;
128 policy
->max
= policy
->cpuinfo
.max_freq
;
129 policy
->cur
= db8500_cpufreq_getspeed(policy
->cpu
);
131 for (i
= 0; freq_table
[i
].frequency
!= policy
->cur
; i
++)
134 policy
->governor
= CPUFREQ_DEFAULT_GOVERNOR
;
137 * FIXME : Need to take time measurement across the target()
138 * function with no/some/all drivers in the notification
141 policy
->cpuinfo
.transition_latency
= 20 * 1000; /* in ns */
143 /* policy sharing between dual CPUs */
144 cpumask_copy(policy
->cpus
, &cpu_present_map
);
146 policy
->shared_type
= CPUFREQ_SHARED_TYPE_ALL
;
151 static struct cpufreq_driver db8500_cpufreq_driver
= {
152 .flags
= CPUFREQ_STICKY
,
153 .verify
= db8500_cpufreq_verify_speed
,
154 .target
= db8500_cpufreq_target
,
155 .get
= db8500_cpufreq_getspeed
,
156 .init
= db8500_cpufreq_init
,
158 .attr
= db8500_cpufreq_attr
,
161 static int __init
db8500_cpufreq_register(void)
163 if (!cpu_is_u8500v20_or_later())
166 pr_info("cpufreq for DB8500 started\n");
167 return cpufreq_register_driver(&db8500_cpufreq_driver
);
169 device_initcall(db8500_cpufreq_register
);