omap_overclocking: don't reject higher opp values
[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 > opp_max_avail)
276                 val = opp_max_avail;
277
278         if (val < 1)
279                 return -EINVAL;
280
281         ret = set_opp_max(val);
282         if (ret != 0)
283                 return ret;
284
285         return retval;
286 }
287
288 static int sys_clk_read(char *page, char **start, off_t off, int count,
289                 int *eof, void *data)
290 {
291         return proc_read_val(page, start, off, count, eof, get_sys_mhz_max());
292 }
293
294 static int sys_clk_write(struct file *file, const char __user *buffer,
295                 unsigned long count, void *data)
296 {
297         unsigned long val;
298         int ret, retval;
299
300         retval = proc_write_val(file, buffer, count, &val);
301         if (retval < 0)
302                 return retval;
303
304         ret = set_sys_mhz_max(val);
305         if (ret < 0)
306                 return ret;
307
308         return retval;
309 }
310
311 static void proc_create_rw(const char *name, void *pdata,
312                            read_proc_t *read_proc, write_proc_t *write_proc)
313 {
314         struct proc_dir_entry *pret;
315
316         pret = create_proc_entry(name, S_IWUSR | S_IRUGO, NULL);
317         if (pret == NULL) {
318                 proc_mkdir(PROC_DIR, NULL);
319                 pret = create_proc_entry(name, S_IWUSR | S_IRUGO, NULL);
320                 if (pret == NULL) {
321                         pr_err("%s: failed to create proc file %s\n",
322                                 __func__, name);
323                         return;
324                 }
325         }
326
327         pret->data = pdata;
328         pret->read_proc = read_proc;
329         pret->write_proc = write_proc;
330 }
331
332 static int pndctrl_init(void)
333 {
334         int ret;
335
336         ret = init_opp_hacks();
337         if (ret != 0) {
338                 pr_err("init_opp_hacks failed: %d\n", ret);
339                 return -EFAULT;
340         }
341
342         proc_create_rw(PROC_CPUMHZ, NULL, cpu_clk_read, cpu_clk_write);
343         proc_create_rw(PROC_CPUOPP, NULL, cpu_maxopp_read, cpu_maxopp_write);
344         proc_create_rw(PROC_SYSMHZ, NULL, sys_clk_read, sys_clk_write);
345
346         pr_info("OMAP overclocker loaded.\n");
347         return 0;
348 }
349
350
351 static void pndctrl_cleanup(void)
352 {
353         remove_proc_entry(PROC_CPUOPP, NULL);
354         remove_proc_entry(PROC_CPUMHZ, NULL);
355         remove_proc_entry(PROC_SYSMHZ, NULL);
356 }
357
358 module_init(pndctrl_init);
359 module_exit(pndctrl_cleanup);
360
361 MODULE_AUTHOR("GraÅžvydas Ignotas");
362 MODULE_LICENSE("GPL");
363 MODULE_DESCRIPTION("OMAP overclocking support");