2 * Copyright (C) STMicroelectronics 2009
3 * Copyright (C) ST-Ericsson SA 2010-2012
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>
19 static struct cpufreq_frequency_table
*freq_table
;
20 static struct clk
*armss_clk
;
22 static struct freq_attr
*dbx500_cpufreq_attr
[] = {
23 &cpufreq_freq_attr_scaling_available_freqs
,
27 static int dbx500_cpufreq_verify_speed(struct cpufreq_policy
*policy
)
29 return cpufreq_frequency_table_verify(policy
, freq_table
);
32 static int dbx500_cpufreq_target(struct cpufreq_policy
*policy
,
33 unsigned int target_freq
,
34 unsigned int relation
)
36 struct cpufreq_freqs freqs
;
40 /* Lookup the next frequency */
41 if (cpufreq_frequency_table_target(policy
, freq_table
, target_freq
,
45 freqs
.old
= policy
->cur
;
46 freqs
.new = freq_table
[idx
].frequency
;
48 if (freqs
.old
== freqs
.new)
51 /* pre-change notification */
52 cpufreq_notify_transition(policy
, &freqs
, CPUFREQ_PRECHANGE
);
54 /* update armss clk frequency */
55 ret
= clk_set_rate(armss_clk
, freqs
.new * 1000);
58 pr_err("dbx500-cpufreq: Failed to set armss_clk to %d Hz: error %d\n",
59 freqs
.new * 1000, ret
);
60 freqs
.new = freqs
.old
;
63 /* post change notification */
64 cpufreq_notify_transition(policy
, &freqs
, CPUFREQ_POSTCHANGE
);
69 static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu
)
72 unsigned long freq
= clk_get_rate(armss_clk
) / 1000;
74 /* The value is rounded to closest frequency in the defined table. */
75 while (freq_table
[i
+ 1].frequency
!= CPUFREQ_TABLE_END
) {
76 if (freq
< freq_table
[i
].frequency
+
77 (freq_table
[i
+ 1].frequency
- freq_table
[i
].frequency
) / 2)
78 return freq_table
[i
].frequency
;
82 return freq_table
[i
].frequency
;
85 static int dbx500_cpufreq_init(struct cpufreq_policy
*policy
)
89 /* get policy fields based on the table */
90 res
= cpufreq_frequency_table_cpuinfo(policy
, freq_table
);
92 cpufreq_frequency_table_get_attr(freq_table
, policy
->cpu
);
94 pr_err("dbx500-cpufreq: Failed to read policy table\n");
98 policy
->min
= policy
->cpuinfo
.min_freq
;
99 policy
->max
= policy
->cpuinfo
.max_freq
;
100 policy
->cur
= dbx500_cpufreq_getspeed(policy
->cpu
);
101 policy
->governor
= CPUFREQ_DEFAULT_GOVERNOR
;
104 * FIXME : Need to take time measurement across the target()
105 * function with no/some/all drivers in the notification
108 policy
->cpuinfo
.transition_latency
= 20 * 1000; /* in ns */
110 /* policy sharing between dual CPUs */
111 cpumask_setall(policy
->cpus
);
116 static struct cpufreq_driver dbx500_cpufreq_driver
= {
117 .flags
= CPUFREQ_STICKY
| CPUFREQ_CONST_LOOPS
,
118 .verify
= dbx500_cpufreq_verify_speed
,
119 .target
= dbx500_cpufreq_target
,
120 .get
= dbx500_cpufreq_getspeed
,
121 .init
= dbx500_cpufreq_init
,
123 .attr
= dbx500_cpufreq_attr
,
126 static int dbx500_cpufreq_probe(struct platform_device
*pdev
)
130 freq_table
= dev_get_platdata(&pdev
->dev
);
132 pr_err("dbx500-cpufreq: Failed to fetch cpufreq table\n");
136 armss_clk
= clk_get(&pdev
->dev
, "armss");
137 if (IS_ERR(armss_clk
)) {
138 pr_err("dbx500-cpufreq: Failed to get armss clk\n");
139 return PTR_ERR(armss_clk
);
142 pr_info("dbx500-cpufreq: Available frequencies:\n");
143 while (freq_table
[i
].frequency
!= CPUFREQ_TABLE_END
) {
144 pr_info(" %d Mhz\n", freq_table
[i
].frequency
/1000);
148 return cpufreq_register_driver(&dbx500_cpufreq_driver
);
151 static struct platform_driver dbx500_cpufreq_plat_driver
= {
153 .name
= "cpufreq-ux500",
154 .owner
= THIS_MODULE
,
156 .probe
= dbx500_cpufreq_probe
,
159 static int __init
dbx500_cpufreq_register(void)
161 return platform_driver_register(&dbx500_cpufreq_plat_driver
);
163 device_initcall(dbx500_cpufreq_register
);
165 MODULE_LICENSE("GPL v2");
166 MODULE_DESCRIPTION("cpufreq driver for DBX500");