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/module.h>
12 #include <linux/kernel.h>
13 #include <linux/cpufreq.h>
14 #include <linux/delay.h>
15 #include <linux/slab.h>
16 #include <linux/platform_device.h>
17 #include <linux/clk.h>
20 static struct cpufreq_frequency_table
*freq_table
;
21 static struct clk
*armss_clk
;
23 static struct freq_attr
*dbx500_cpufreq_attr
[] = {
24 &cpufreq_freq_attr_scaling_available_freqs
,
28 static int dbx500_cpufreq_verify_speed(struct cpufreq_policy
*policy
)
30 return cpufreq_frequency_table_verify(policy
, freq_table
);
33 static int dbx500_cpufreq_target(struct cpufreq_policy
*policy
,
34 unsigned int target_freq
,
35 unsigned int relation
)
37 struct cpufreq_freqs freqs
;
41 /* scale the target frequency to one of the extremes supported */
42 if (target_freq
< policy
->cpuinfo
.min_freq
)
43 target_freq
= policy
->cpuinfo
.min_freq
;
44 if (target_freq
> policy
->cpuinfo
.max_freq
)
45 target_freq
= policy
->cpuinfo
.max_freq
;
47 /* Lookup the next frequency */
48 if (cpufreq_frequency_table_target(policy
, freq_table
, target_freq
,
52 freqs
.old
= policy
->cur
;
53 freqs
.new = freq_table
[idx
].frequency
;
55 if (freqs
.old
== freqs
.new)
58 /* pre-change notification */
59 for_each_cpu(freqs
.cpu
, policy
->cpus
)
60 cpufreq_notify_transition(&freqs
, CPUFREQ_PRECHANGE
);
62 /* update armss clk frequency */
63 ret
= clk_set_rate(armss_clk
, freqs
.new * 1000);
66 pr_err("dbx500-cpufreq: Failed to set armss_clk to %d Hz: error %d\n",
67 freqs
.new * 1000, ret
);
71 /* post change notification */
72 for_each_cpu(freqs
.cpu
, policy
->cpus
)
73 cpufreq_notify_transition(&freqs
, CPUFREQ_POSTCHANGE
);
78 static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu
)
81 unsigned long freq
= clk_get_rate(armss_clk
) / 1000;
83 while (freq_table
[i
].frequency
!= CPUFREQ_TABLE_END
) {
84 if (freq
<= freq_table
[i
].frequency
)
85 return freq_table
[i
].frequency
;
89 /* We could not find a corresponding frequency. */
90 pr_err("dbx500-cpufreq: Failed to find cpufreq speed\n");
94 static int __cpuinit
dbx500_cpufreq_init(struct cpufreq_policy
*policy
)
98 /* get policy fields based on the table */
99 res
= cpufreq_frequency_table_cpuinfo(policy
, freq_table
);
101 cpufreq_frequency_table_get_attr(freq_table
, policy
->cpu
);
103 pr_err("dbx500-cpufreq: Failed to read policy table\n");
107 policy
->min
= policy
->cpuinfo
.min_freq
;
108 policy
->max
= policy
->cpuinfo
.max_freq
;
109 policy
->cur
= dbx500_cpufreq_getspeed(policy
->cpu
);
110 policy
->governor
= CPUFREQ_DEFAULT_GOVERNOR
;
113 * FIXME : Need to take time measurement across the target()
114 * function with no/some/all drivers in the notification
117 policy
->cpuinfo
.transition_latency
= 20 * 1000; /* in ns */
119 /* policy sharing between dual CPUs */
120 cpumask_copy(policy
->cpus
, cpu_present_mask
);
122 policy
->shared_type
= CPUFREQ_SHARED_TYPE_ALL
;
127 static struct cpufreq_driver dbx500_cpufreq_driver
= {
128 .flags
= CPUFREQ_STICKY
,
129 .verify
= dbx500_cpufreq_verify_speed
,
130 .target
= dbx500_cpufreq_target
,
131 .get
= dbx500_cpufreq_getspeed
,
132 .init
= dbx500_cpufreq_init
,
134 .attr
= dbx500_cpufreq_attr
,
137 static int dbx500_cpufreq_probe(struct platform_device
*pdev
)
141 freq_table
= dev_get_platdata(&pdev
->dev
);
143 pr_err("dbx500-cpufreq: Failed to fetch cpufreq table\n");
147 armss_clk
= clk_get(&pdev
->dev
, "armss");
148 if (IS_ERR(armss_clk
)) {
149 pr_err("dbx500-cpufreq: Failed to get armss clk\n");
150 return PTR_ERR(armss_clk
);
153 pr_info("dbx500-cpufreq: Available frequencies:\n");
154 while (freq_table
[i
].frequency
!= CPUFREQ_TABLE_END
) {
155 pr_info(" %d Mhz\n", freq_table
[i
].frequency
/1000);
159 return cpufreq_register_driver(&dbx500_cpufreq_driver
);
162 static struct platform_driver dbx500_cpufreq_plat_driver
= {
164 .name
= "cpufreq-ux500",
165 .owner
= THIS_MODULE
,
167 .probe
= dbx500_cpufreq_probe
,
170 static int __init
dbx500_cpufreq_register(void)
172 if (!cpu_is_u8500_family())
175 return platform_driver_register(&dbx500_cpufreq_plat_driver
);
177 device_initcall(dbx500_cpufreq_register
);
179 MODULE_LICENSE("GPL v2");
180 MODULE_DESCRIPTION("cpufreq driver for DBX500");