2 * OMAP CPU overclocking hacks
4 * Licensed under the GPL-2 or later.
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/proc_fs.h>
10 #include <linux/uaccess.h>
12 #include <plat/omap_device.h>
14 #define PROC_DIR "pandora"
15 #define PROC_CPUMHZ "pandora/cpu_mhz_max"
16 #define PROC_CPUOPP "pandora/cpu_opp_max"
18 /* FIXME: could use opp3xxx_data.c, but that's initdata.. */
19 static const unsigned long nominal_freqs_35xx[] = {
20 125000000, 250000000, 500000000, 550000000, 600000000,
23 static const unsigned long nominal_freqs_36xx[] = {
24 300000000, 600000000, 800000000, 1000000000,
27 static const unsigned long *nominal_freqs;
29 static int opp_max_avail, opp_max;
31 static int set_opp_max(int new_opp_max)
33 struct device *mpu_dev;
36 if (new_opp_max == opp_max)
39 mpu_dev = omap_device_get_by_hwmod_name("mpu");
40 if (IS_ERR(mpu_dev)) {
41 pr_err("%s: mpu device not available (%ld)\n",
42 __func__, PTR_ERR(mpu_dev));
46 for (i = 1; i < new_opp_max; i++) {
47 ret = opp_enable_i(mpu_dev, i);
49 dev_err(mpu_dev, "%s: opp_enable returned %d\n",
53 for (i = new_opp_max; i < opp_max_avail; i++) {
54 ret = opp_disable_i(mpu_dev, i);
56 dev_err(mpu_dev, "%s: opp_disable returned %d\n",
60 opp_max = new_opp_max;
61 dev_info(mpu_dev, "max OPP set to %d\n", opp_max);
66 static int set_mhz_max(unsigned long new_mhz_max)
68 unsigned long cur_mhz_max = 0;
69 struct device *mpu_dev;
72 new_mhz_max *= 1000000;
74 if (opp_max < 1 || opp_max > opp_max_avail) {
75 pr_err("%s: corrupt opp_max: %d\n", __func__, opp_max);
80 /* going below nominal makes no sense, it will save us nothing,
81 * user should reduce max OPP instead */
82 if (new_mhz_max < nominal_freqs[index])
83 new_mhz_max = nominal_freqs[index];
85 mpu_dev = omap_device_get_by_hwmod_name("mpu");
86 if (IS_ERR(mpu_dev)) {
87 pr_err("%s: mpu device not available (%ld)\n",
88 __func__, PTR_ERR(mpu_dev));
92 opp_hack_get_freq(mpu_dev, index, &cur_mhz_max);
93 if (cur_mhz_max == new_mhz_max)
96 ret = opp_hack_set_freq(mpu_dev, index, new_mhz_max);
98 dev_err(mpu_dev, "%s: opp_hack_set_freq returned %d\n",
106 static int get_mhz_max(void)
108 unsigned long cur_mhz_max = 0;
109 struct device *mpu_dev;
111 if (opp_max < 1 || opp_max > opp_max_avail) {
112 pr_err("%s: corrupt opp_max: %d\n", __func__, opp_max);
116 mpu_dev = omap_device_get_by_hwmod_name("mpu");
117 if (IS_ERR(mpu_dev)) {
118 pr_err("%s: mpu device not available (%ld)\n",
119 __func__, PTR_ERR(mpu_dev));
123 opp_hack_get_freq(mpu_dev, opp_max - 1, &cur_mhz_max);
125 return cur_mhz_max / 1000000;
128 static int init_opp_hacks(void)
130 struct device *mpu_dev;
132 mpu_dev = omap_device_get_by_hwmod_name("mpu");
133 if (IS_ERR(mpu_dev)) {
134 pr_err("%s: mpu device not available (%ld)\n",
135 __func__, PTR_ERR(mpu_dev));
139 if (cpu_is_omap3630()) {
140 nominal_freqs = nominal_freqs_36xx;
141 opp_max_avail = sizeof(nominal_freqs_36xx) / sizeof(nominal_freqs_36xx[0]);
143 } else if (cpu_is_omap34xx()) {
144 nominal_freqs = nominal_freqs_35xx;
145 opp_max_avail = sizeof(nominal_freqs_35xx) / sizeof(nominal_freqs_35xx[0]);
146 opp_max = opp_max_avail;
148 dev_err(mpu_dev, "%s: unsupported CPU\n", __func__);
155 static int proc_read_val(char *page, char **start, off_t off, int count,
161 p += sprintf(p, "%d\n", val);
163 len = (p - page) - off;
167 *eof = (len <= count) ? 1 : 0;
173 static int proc_write_val(struct file *file, const char __user *buffer,
174 unsigned long count, unsigned long *val)
179 count = strncpy_from_user(buff, buffer,
180 count < sizeof(buff) ? count : sizeof(buff) - 1);
183 ret = strict_strtoul(buff, 0, val);
185 pr_err("error %i parsing %s\n", ret, buff);
192 static int cpu_clk_read(char *page, char **start, off_t off, int count,
193 int *eof, void *data)
195 return proc_read_val(page, start, off, count, eof, get_mhz_max());
198 static int cpu_clk_write(struct file *file, const char __user *buffer,
199 unsigned long count, void *data)
204 retval = proc_write_val(file, buffer, count, &val);
208 ret = set_mhz_max(val);
215 static int cpu_maxopp_read(char *page, char **start, off_t off, int count,
216 int *eof, void *data)
218 return proc_read_val(page, start, off, count, eof, opp_max);
221 static int cpu_maxopp_write(struct file *file, const char __user *buffer,
222 unsigned long count, void *data)
227 retval = proc_write_val(file, buffer, count, &val);
231 if (val < 1 || val > opp_max_avail)
234 ret = set_opp_max(val);
241 static void proc_create_rw(const char *name, void *pdata,
242 read_proc_t *read_proc, write_proc_t *write_proc)
244 struct proc_dir_entry *pret;
246 pret = create_proc_entry(name, S_IWUGO | S_IRUGO, NULL);
248 proc_mkdir(PROC_DIR, NULL);
249 pret = create_proc_entry(name, S_IWUGO | S_IRUGO, NULL);
251 pr_err("%s: failed to create proc file %s\n",
258 pret->read_proc = read_proc;
259 pret->write_proc = write_proc;
262 static int pndctrl_init(void)
266 ret = init_opp_hacks();
268 pr_err("init_opp_hacks failed: %d\n", ret);
272 proc_create_rw(PROC_CPUMHZ, NULL, cpu_clk_read, cpu_clk_write);
273 proc_create_rw(PROC_CPUOPP, NULL, cpu_maxopp_read, cpu_maxopp_write);
275 pr_info("OMAP overclocker loaded.\n");
280 static void pndctrl_cleanup(void)
282 remove_proc_entry(PROC_CPUOPP, NULL);
283 remove_proc_entry(PROC_CPUMHZ, NULL);
286 module_init(pndctrl_init);
287 module_exit(pndctrl_cleanup);
289 MODULE_AUTHOR("GraÅžvydas Ignotas");
290 MODULE_LICENSE("GPL");
291 MODULE_DESCRIPTION("OMAP overclocking support");