129241dfe05476aa9ccdb6a845ef39071b2d4063
[pandora-kernel.git] / drivers / misc / omap_overclocking.c
1 /*
2  * OMAP CPU overclocking hacks
3  *
4  * Licensed under the GPL-2 or later.
5  */
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/proc_fs.h>
9 #include <linux/opp.h>
10 #include <linux/clk.h>
11 #include <linux/uaccess.h>
12
13 #include <plat/omap_device.h>
14
15 #define PROC_DIR        "pandora"
16 #define PROC_CPUMHZ     "pandora/cpu_mhz_max"
17 #define PROC_CPUOPP     "pandora/cpu_opp_max"
18 #define PROC_SYSMHZ     "pandora/sys_mhz_max"
19
20 /* FIXME: could use opp3xxx_data.c, but that's initdata.. */
21 static const unsigned long nominal_freqs_35xx[] = {
22         125000000, 250000000, 500000000, 550000000, 600000000,
23 };
24
25 static const unsigned long nominal_freqs_36xx[] = {
26         300000000, 600000000, 800000000, 1000000000,
27 };
28
29 static const unsigned long *nominal_freqs;
30
31 static int opp_max_avail, opp_max;
32
33 static int set_opp_max(int new_opp_max)
34 {
35         struct device *mpu_dev;
36         int i, ret;
37
38         if (new_opp_max == opp_max)
39                 return 0;
40
41         mpu_dev = omap_device_get_by_hwmod_name("mpu");
42         if (IS_ERR(mpu_dev)) {
43                 pr_err("%s: mpu device not available (%ld)\n",
44                         __func__, PTR_ERR(mpu_dev));
45                 return -ENODEV;
46         }
47
48         for (i = 1; i < new_opp_max; i++) {
49                 ret = opp_enable_i(mpu_dev, i);
50                 if (ret != 0)
51                         dev_err(mpu_dev, "%s: opp_enable returned %d\n",
52                                 __func__, ret);
53         }
54
55         for (i = new_opp_max; i < opp_max_avail; i++) {
56                 ret = opp_disable_i(mpu_dev, i);
57                 if (ret != 0)
58                         dev_err(mpu_dev, "%s: opp_disable returned %d\n",
59                                 __func__, ret);
60         }
61
62         opp_max = new_opp_max;
63         dev_info(mpu_dev, "max OPP set to %d\n", opp_max);
64
65         return 0;
66 }
67
68 static int set_cpu_mhz_max(unsigned long new_mhz_max)
69 {
70         unsigned long cur_mhz_max = 0;
71         struct device *mpu_dev;
72         int index, ret;
73
74         new_mhz_max *= 1000000;
75
76         if (opp_max < 1 || opp_max > opp_max_avail) {
77                 pr_err("%s: corrupt opp_max: %d\n", __func__, opp_max);
78                 return -EINVAL;
79         }
80         index = opp_max - 1;
81
82         /* going below nominal makes no sense, it will save us nothing,
83          * user should reduce max OPP instead */
84         if (new_mhz_max < nominal_freqs[index])
85                 new_mhz_max = nominal_freqs[index];
86
87         mpu_dev = omap_device_get_by_hwmod_name("mpu");
88         if (IS_ERR(mpu_dev)) {
89                 pr_err("%s: mpu device not available (%ld)\n",
90                         __func__, PTR_ERR(mpu_dev));
91                 return -ENODEV;
92         }
93
94         opp_hack_get_freq(mpu_dev, index, &cur_mhz_max);
95         if (cur_mhz_max == new_mhz_max)
96                 return 0;
97
98         ret = opp_hack_set_freq(mpu_dev, index, new_mhz_max);
99         if (ret != 0) {
100                 dev_err(mpu_dev, "%s: opp_hack_set_freq returned %d\n",
101                         __func__, ret);
102                 return ret;
103         }
104
105         return 0;
106 }
107
108 static int get_cpu_mhz_max(void)
109 {
110         unsigned long cur_mhz_max = 0;
111         struct device *mpu_dev;
112
113         if (opp_max < 1 || opp_max > opp_max_avail) {
114                 pr_err("%s: corrupt opp_max: %d\n", __func__, opp_max);
115                 return -EINVAL;
116         }
117
118         mpu_dev = omap_device_get_by_hwmod_name("mpu");
119         if (IS_ERR(mpu_dev)) {
120                 pr_err("%s: mpu device not available (%ld)\n",
121                         __func__, PTR_ERR(mpu_dev));
122                 return -ENODEV;
123         }
124
125         opp_hack_get_freq(mpu_dev, opp_max - 1, &cur_mhz_max);
126
127         return cur_mhz_max / 1000000;
128 }
129
130 static int init_opp_hacks(void)
131 {
132         struct device *mpu_dev;
133
134         mpu_dev = omap_device_get_by_hwmod_name("mpu");
135         if (IS_ERR(mpu_dev)) {
136                 pr_err("%s: mpu device not available (%ld)\n",
137                         __func__, PTR_ERR(mpu_dev));
138                 return -ENODEV;
139         }
140
141         if (cpu_is_omap3630()) {
142                 nominal_freqs = nominal_freqs_36xx;
143                 opp_max_avail = sizeof(nominal_freqs_36xx) / sizeof(nominal_freqs_36xx[0]);
144                 opp_max = 2;
145         } else if (cpu_is_omap34xx()) {
146                 nominal_freqs = nominal_freqs_35xx;
147                 opp_max_avail = sizeof(nominal_freqs_35xx) / sizeof(nominal_freqs_35xx[0]);
148                 opp_max = opp_max_avail;
149         } else {
150                 dev_err(mpu_dev, "%s: unsupported CPU\n", __func__);
151                 return -ENODEV;
152         }
153
154         return 0;
155 }
156
157 static int set_sys_mhz_max(unsigned long rate)
158 {
159         struct clk *dpll3_m2_ck;
160         int ret;
161
162         rate *= 1000000;
163
164         dpll3_m2_ck = clk_get(NULL, "dpll3_m2_ck");
165         if (IS_ERR(dpll3_m2_ck)) {
166                 pr_err("%s: dpll3_m2_clk not available: %ld\n",
167                         __func__, PTR_ERR(dpll3_m2_ck));
168                 return -ENODEV;
169         }
170
171         pr_info("Reprogramming CORE clock to %luHz\n", rate);
172         ret = clk_set_rate(dpll3_m2_ck, rate);
173         if (ret)
174                 pr_err("dpll3_m2_clk rate change failed: %d\n", ret);
175
176         clk_put(dpll3_m2_ck);
177
178         return ret;
179 }
180
181 static int get_sys_mhz_max(void)
182 {
183         struct clk *dpll3_m2_ck;
184         int ret;
185
186         dpll3_m2_ck = clk_get(NULL, "dpll3_m2_ck");
187         if (IS_ERR(dpll3_m2_ck)) {
188                 pr_err("%s: dpll3_m2_clk not available: %ld\n",
189                         __func__, PTR_ERR(dpll3_m2_ck));
190                 return -ENODEV;
191         }
192
193         ret = clk_get_rate(dpll3_m2_ck);
194         clk_put(dpll3_m2_ck);
195
196         return ret / 1000000;
197 }
198
199 static int proc_read_val(char *page, char **start, off_t off, int count,
200                 int *eof, int val)
201 {
202         char *p = page;
203         int len;
204
205         p += sprintf(p, "%d\n", val);
206
207         len = (p - page) - off;
208         if (len < 0)
209                 len = 0;
210
211         *eof = (len <= count) ? 1 : 0;
212         *start = page + off;
213
214         return len;
215 }
216
217 static int proc_write_val(struct file *file, const char __user *buffer,
218                 unsigned long count, unsigned long *val)
219 {
220         char buff[32];
221         int ret;
222
223         count = strncpy_from_user(buff, buffer,
224                         count < sizeof(buff) ? count : sizeof(buff) - 1);
225         buff[count] = 0;
226
227         ret = strict_strtoul(buff, 0, val);
228         if (ret < 0) {
229                 pr_err("error %i parsing %s\n", ret, buff);
230                 return ret;
231         }
232
233         return count;
234 }
235
236 static int cpu_clk_read(char *page, char **start, off_t off, int count,
237                 int *eof, void *data)
238 {
239         return proc_read_val(page, start, off, count, eof, get_cpu_mhz_max());
240 }
241
242 static int cpu_clk_write(struct file *file, const char __user *buffer,
243                 unsigned long count, void *data)
244 {
245         unsigned long val;
246         int ret, retval;
247
248         retval = proc_write_val(file, buffer, count, &val);
249         if (retval < 0)
250                 return retval;
251
252         ret = set_cpu_mhz_max(val);
253         if (ret < 0)
254                 return ret;
255
256         return retval;
257 }
258
259 static int cpu_maxopp_read(char *page, char **start, off_t off, int count,
260                 int *eof, void *data)
261 {
262         return proc_read_val(page, start, off, count, eof, opp_max);
263 }
264
265 static int cpu_maxopp_write(struct file *file, const char __user *buffer,
266                 unsigned long count, void *data)
267 {
268         unsigned long val;
269         int ret, retval;
270
271         retval = proc_write_val(file, buffer, count, &val);
272         if (retval < 0)
273                 return retval;
274
275         if (val < 1 || val > opp_max_avail)
276                 return -EINVAL;
277
278         ret = set_opp_max(val);
279         if (ret != 0)
280                 return ret;
281
282         return retval;
283 }
284
285 static int sys_clk_read(char *page, char **start, off_t off, int count,
286                 int *eof, void *data)
287 {
288         return proc_read_val(page, start, off, count, eof, get_sys_mhz_max());
289 }
290
291 static int sys_clk_write(struct file *file, const char __user *buffer,
292                 unsigned long count, void *data)
293 {
294         unsigned long val;
295         int ret, retval;
296
297         retval = proc_write_val(file, buffer, count, &val);
298         if (retval < 0)
299                 return retval;
300
301         ret = set_sys_mhz_max(val);
302         if (ret < 0)
303                 return ret;
304
305         return retval;
306 }
307
308 static void proc_create_rw(const char *name, void *pdata,
309                            read_proc_t *read_proc, write_proc_t *write_proc)
310 {
311         struct proc_dir_entry *pret;
312
313         pret = create_proc_entry(name, S_IWUSR | S_IRUGO, NULL);
314         if (pret == NULL) {
315                 proc_mkdir(PROC_DIR, NULL);
316                 pret = create_proc_entry(name, S_IWUSR | S_IRUGO, NULL);
317                 if (pret == NULL) {
318                         pr_err("%s: failed to create proc file %s\n",
319                                 __func__, name);
320                         return;
321                 }
322         }
323
324         pret->data = pdata;
325         pret->read_proc = read_proc;
326         pret->write_proc = write_proc;
327 }
328
329 static int pndctrl_init(void)
330 {
331         int ret;
332
333         ret = init_opp_hacks();
334         if (ret != 0) {
335                 pr_err("init_opp_hacks failed: %d\n", ret);
336                 return -EFAULT;
337         }
338
339         proc_create_rw(PROC_CPUMHZ, NULL, cpu_clk_read, cpu_clk_write);
340         proc_create_rw(PROC_CPUOPP, NULL, cpu_maxopp_read, cpu_maxopp_write);
341         proc_create_rw(PROC_SYSMHZ, NULL, sys_clk_read, sys_clk_write);
342
343         pr_info("OMAP overclocker loaded.\n");
344         return 0;
345 }
346
347
348 static void pndctrl_cleanup(void)
349 {
350         remove_proc_entry(PROC_CPUOPP, NULL);
351         remove_proc_entry(PROC_CPUMHZ, NULL);
352         remove_proc_entry(PROC_SYSMHZ, NULL);
353 }
354
355 module_init(pndctrl_init);
356 module_exit(pndctrl_cleanup);
357
358 MODULE_AUTHOR("GraÅžvydas Ignotas");
359 MODULE_LICENSE("GPL");
360 MODULE_DESCRIPTION("OMAP overclocking support");