3 Exports some additional hardware control to userspace.
4 Written by GraÅžvydas "notaz" Ignotas <notasas@gmail.com>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; version 2 of the License.
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/proc_fs.h>
14 #include <linux/uaccess.h>
15 #include <linux/delay.h>
16 #include <linux/clk.h>
18 #include <linux/i2c/twl4030.h>
20 #ifndef CONFIG_PROC_FS
21 #error need CONFIG_PROC_FS
24 #define PND_PROC_CPUMHZ "pandora/cpu_mhz_max"
25 #define PND_PROC_CPUOPP "pandora/cpu_opp_max"
27 static int max_allowed_opp = 3; /* 3 on ED's request */
30 static void set_opp(int nopp)
32 static const unsigned char opp2volt[5] = { 30, 38, 48, 54, 60 };
38 twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, v, 0x5E);
42 * Rationale: Slowest slew rate of the TPS65950 SMPS is 4 mV/us.
43 * Each unit is 12.5mV, resulting in 3.125us/unit.
44 * Rounded up for a safe 4us/unit.
46 udelay(abs(v - ov) * 4);
49 printk(KERN_INFO "set_opp: OPP %d set\n", opp);
52 static int mhz2opp(int mhz)
55 if (mhz<14) new_opp=3; /* Guard against -1 */
56 if (mhz>125) new_opp=2;
57 if (mhz>250) new_opp=3;
58 if (mhz>600) new_opp=4; /* Assumption: current pandoras OK with 600Mhz@OPP3 */
59 if (mhz>720) new_opp=5;
61 if (max_allowed_opp > 0 && new_opp > max_allowed_opp)
62 new_opp = max_allowed_opp;
67 static void preop_oppset(int mhz)
69 int new_opp = mhz2opp(mhz);
74 static void postop_oppset(int mhz)
76 int new_opp = mhz2opp(mhz);
83 * SYS_CLK is 26 MHz (see PRM_CLKSEL)
84 * ARM_FCLK = (SYS_CLK * M * 2) / ([N+1] * M2) / 2
85 * CM_CLKSEL1_PLL_MPU = N | (M << 8) | (M2 << 19)
87 static int get_fclk(void)
89 unsigned __iomem *base;
93 base = ioremap(0x48004000, 0x2000);
95 printk(KERN_ERR "get_fclk: can't ioremap\n");
99 ret = base[0x940 >> 2];
103 m = (ret >> 8) & 0x7ff;
104 m2 = (ret >> 19) & 7;
106 if (m2 != 1 && m2 != 2 && m2 != 4) {
107 printk(KERN_ERR "get_fclk: invalid divider %d\n", m2);
111 return 26 * m / ((n + 1) * m2);
114 static void set_fclk(int val)
116 struct clk *pllclk, *fclk;
120 printk(KERN_ERR "set_fclk: value %d out of range\n", val);
125 pllclk = clk_get(NULL, "dpll1_ck");
126 if (IS_ERR(pllclk)) {
127 printk(KERN_ERR "set_fclk: clk_get() failed: %li\n",
133 ret = clk_set_rate(pllclk, val * 1000000);
135 printk(KERN_ERR "set_fclk: clk_set_rate(dpll1_ck) "
136 "failed: %li\n", PTR_ERR(pllclk));
139 printk(KERN_INFO "dpll1_ck rate: %li\n", clk_get_rate(pllclk));
142 fclk = clk_get(NULL, "arm_fck");
143 if (!IS_ERR(pllclk)) {
144 printk(KERN_INFO "arm_fck rate: %li\n", clk_get_rate(fclk));
148 printk(KERN_INFO "PLL_MPU rate: %i\n", get_fclk() * 1000000);
152 static int proc_read_val(char *page, char **start, off_t off, int count,
158 p += sprintf(p, "%d\n", val);
160 len = (p - page) - off;
164 *eof = (len <= count) ? 1 : 0;
170 static int proc_write_val(struct file *file, const char __user *buffer,
171 unsigned long count, unsigned long *val)
176 count = strncpy_from_user(buff, buffer,
177 count < sizeof(buff) ? count : sizeof(buff) - 1);
180 ret = strict_strtoul(buff, 0, val);
182 printk(KERN_ERR "error %i parsing %s\n", ret, buff);
189 static int cpu_clk_read(char *page, char **start, off_t off, int count,
190 int *eof, void *data)
192 return proc_read_val(page, start, off, count, eof, get_fclk());
195 static int cpu_clk_write(struct file *file, const char __user *buffer,
196 unsigned long count, void *data)
201 ret = proc_write_val(file, buffer, count, &val);
209 static int cpu_maxopp_read(char *page, char **start, off_t off, int count,
210 int *eof, void *data)
212 return proc_read_val(page, start, off, count, eof, max_allowed_opp);
215 static int cpu_maxopp_write(struct file *file, const char __user *buffer,
216 unsigned long count, void *data)
221 ret = proc_write_val(file, buffer, count, &val);
225 if (val < 1 || val > 6)
228 max_allowed_opp = val;
232 static void proc_create_rw(const char *name, void *pdata,
233 read_proc_t *read_proc, write_proc_t *write_proc)
235 struct proc_dir_entry *pret;
237 pret = create_proc_entry(name, S_IWUGO | S_IRUGO, NULL);
239 proc_mkdir("pandora", NULL);
240 pret = create_proc_entry(name, S_IWUGO | S_IRUGO, NULL);
242 printk(KERN_ERR "failed to create proc file %s\n", name);
248 pret->read_proc = read_proc;
249 pret->write_proc = write_proc;
252 /* ************************************************************************* */
254 static int pndctrl_init(void)
256 opp = mhz2opp(get_fclk());
258 proc_create_rw(PND_PROC_CPUMHZ, NULL, cpu_clk_read, cpu_clk_write);
259 proc_create_rw(PND_PROC_CPUOPP, NULL, cpu_maxopp_read, cpu_maxopp_write);
261 printk(KERN_INFO "pndctrl loaded.\n");
266 static void pndctrl_cleanup(void)
268 remove_proc_entry(PND_PROC_CPUOPP, NULL);
269 remove_proc_entry(PND_PROC_CPUMHZ, NULL);
270 printk(KERN_INFO "pndctrl unloaded.\n");
274 module_init(pndctrl_init);
275 module_exit(pndctrl_cleanup);
277 MODULE_AUTHOR("Grazvydas Ignotas");
278 MODULE_LICENSE("GPL");
279 MODULE_DESCRIPTION("Pandora Additional hw control");