Merge tag 'v3.10.55' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / mach-mt8127 / mt_cpu_ss.c
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 */
7
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/sched.h>
11 #include <linux/init.h>
12 #include <linux/delay.h>
13 #include <linux/proc_fs.h>
14 #include <linux/spinlock.h>
15 #include <linux/kthread.h>
16 #include <linux/hrtimer.h>
17 #include <linux/ktime.h>
18 #include <linux/xlog.h>
19 #include <linux/jiffies.h>
20 #include <linux/seq_file.h>
21
22 #include <asm/system.h>
23 #include <asm/uaccess.h>
24
25 #include "mach/sync_write.h"
26 #include "mach/mt_typedefs.h"
27 #include "mach/mt_cpufreq.h"
28
29 static struct hrtimer mt_cpu_ss_timer;
30 struct task_struct *mt_cpu_ss_thread = NULL;
31 static DECLARE_WAIT_QUEUE_HEAD(mt_cpu_ss_timer_waiter);
32
33 static int mt_cpu_ss_period_s = 0;
34 static int mt_cpu_ss_period_ns = 100;
35
36 static int mt_cpu_ss_timer_flag = 0;
37
38 static bool mt_cpu_ss_debug_mode = false;
39 static bool mt_cpu_ss_period_mode = false;
40
41 enum hrtimer_restart mt_cpu_ss_timer_func(struct hrtimer *timer)
42 {
43 if (mt_cpu_ss_debug_mode)
44 printk("[%s]: enter timer function\n", __FUNCTION__);
45
46 mt_cpu_ss_timer_flag = 1; wake_up_interruptible(&mt_cpu_ss_timer_waiter);
47
48 return HRTIMER_NORESTART;
49 }
50
51 int mt_cpu_ss_thread_handler(void *unused)
52 {
53 kal_uint32 flag = 0;
54
55 do
56 {
57 ktime_t ktime = ktime_set(mt_cpu_ss_period_s, mt_cpu_ss_period_ns);
58
59 wait_event_interruptible(mt_cpu_ss_timer_waiter, mt_cpu_ss_timer_flag != 0);
60 mt_cpu_ss_timer_flag = 0;
61
62 if (!flag)
63 {
64 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL) & 0x0ff3), TOP_CKMUXSEL);
65 flag = 1;
66 }
67 else
68 {
69 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL) | 0x0004), TOP_CKMUXSEL);
70 flag = 0;
71 }
72
73 if (mt_cpu_ss_debug_mode)
74 printk("[%s]: TOP_CKMUXSEL = 0x%x\n", __FUNCTION__, DRV_Reg32(TOP_CKMUXSEL));
75
76 hrtimer_start(&mt_cpu_ss_timer, ktime, HRTIMER_MODE_REL);
77
78 } while (!kthread_should_stop());
79
80 return 0;
81 }
82
83 static int cpu_ss_mode_show(struct seq_file* s, void* v)
84 {
85 if ((DRV_Reg32(TOP_CKMUXSEL) & 0x000C) == 0)
86 seq_printf(s, "CPU clock source is CLKSQ\n");
87 else
88 seq_printf(s, "CPU clock source is ARMPLL\n");
89
90 return 0;
91 }
92
93 static int cpu_ss_mode_open(struct inode *inode, struct file *file)
94 {
95 return single_open(file, cpu_ss_mode_show, NULL);
96 }
97
98 static ssize_t cpu_ss_mode_write(struct file *file, const char *buffer, size_t count, loff_t *data)
99 {
100 int len = 0, mode = 0;
101 char desc[32];
102
103 len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
104 if (copy_from_user(desc, buffer, len))
105 {
106 return 0;
107 }
108 desc[len] = '\0';
109
110 if (sscanf(desc, "%d", &mode) == 1)
111 {
112 if (mode)
113 {
114 printk("[%s]: config cpu speed switch mode = ARMPLL\n", __FUNCTION__);
115 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL) | 0x0004), TOP_CKMUXSEL);
116 }
117 else
118 {
119 printk("[%s]: config cpu speed switch mode = CLKSQ\n", __FUNCTION__);
120 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL) & 0x0ff3), TOP_CKMUXSEL);
121 }
122
123 return count;
124 }
125 else
126 {
127 printk("[%s]: bad argument!! should be \"1\" or \"0\"\n", __FUNCTION__);
128 }
129
130 return -EINVAL;
131 }
132
133 static int cpu_ss_period_show(struct seq_file* s, void* v)
134 {
135 seq_printf(s, "%d (s) %d (ns)\n", mt_cpu_ss_period_s, mt_cpu_ss_period_ns);
136
137 return 0;
138 }
139
140 static int cpu_ss_period_open(struct inode *inode, struct file *file)
141 {
142 return single_open(file, cpu_ss_period_show, NULL);
143 }
144
145 static ssize_t cpu_ss_period_write(struct file *file, const char *buffer, size_t count, loff_t *data)
146 {
147 int len = 0, s = 0, ns = 0;
148 char desc[32];
149
150 len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
151 if (copy_from_user(desc, buffer, len))
152 {
153 return 0;
154 }
155 desc[len] = '\0';
156
157 if (sscanf(desc, "%d %d", &s, &ns) == 2)
158 {
159 printk("[%s]: set cpu speed switch period = %d (s), %d (ns)\n", __FUNCTION__, s, ns);
160 mt_cpu_ss_period_s = s;
161 mt_cpu_ss_period_ns = ns;
162 return count;
163 }
164 else
165 {
166 printk("[%s]: bad argument!! should be \"[s]\" or \"[ns]\"\n", __FUNCTION__);
167 }
168
169 return -EINVAL;
170 }
171
172 static int cpu_ss_period_mode_show(struct seq_file* s, void* v)
173 {
174 if (mt_cpu_ss_period_mode)
175 seq_printf(s, "enable");
176 else
177 seq_printf(s, "disable");
178
179 return 0;
180 }
181
182 static int cpu_ss_period_mode_open(struct inode *inode, struct file *file)
183 {
184 return single_open(file, cpu_ss_period_mode_show, NULL);
185 }
186
187 static ssize_t cpu_ss_period_mode_write(struct file *file, const char *buffer, size_t count, loff_t *data)
188 {
189 int len = 0;
190 char mode[20], desc[32];
191 ktime_t ktime = ktime_set(mt_cpu_ss_period_s, mt_cpu_ss_period_ns);
192
193 len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
194 if (copy_from_user(desc, buffer, len))
195 {
196 return 0;
197 }
198 desc[len] = '\0';
199
200 if (sscanf(desc, "%s", mode) == 1)
201 {
202 if (!strcmp(mode, "enable"))
203 {
204 printk("[%s]: enable cpu speed switch period mode\n", __FUNCTION__);
205 mt_cpu_ss_period_mode = true;
206
207 mt_cpu_ss_thread = kthread_run(mt_cpu_ss_thread_handler, 0, "cpu speed switch");
208 if (IS_ERR(mt_cpu_ss_thread))
209 {
210 printk("[%s]: failed to create cpu speed switch thread\n", __FUNCTION__);
211 }
212
213 hrtimer_start(&mt_cpu_ss_timer, ktime, HRTIMER_MODE_REL);
214 return count;
215 }
216 else if (!strcmp(mode, "disable"))
217 {
218 printk("[%s]: disable cpu speed switch period mode\n", __FUNCTION__);
219 mt_cpu_ss_period_mode = false;
220
221 kthread_stop(mt_cpu_ss_thread);
222
223 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL) | 0x0004), TOP_CKMUXSEL);
224
225 hrtimer_cancel(&mt_cpu_ss_timer);
226 return count;
227 }
228 else
229 {
230 printk("[%s]: bad argument!! should be \"enable\" or \"disable\"\n", __FUNCTION__);
231 }
232 }
233 else
234 {
235 printk("[%s]: bad argument!! should be \"enable\" or \"disable\"\n", __FUNCTION__);
236 }
237
238 return -EINVAL;
239 }
240
241 static int cpu_ss_debug_mode_show(struct seq_file* s, void* v)
242 {
243 if (mt_cpu_ss_debug_mode)
244 seq_printf(s, "enable");
245 else
246 seq_printf(s, "disable");
247
248 return 0;
249 }
250
251 static int cpu_ss_debug_mode_open(struct inode *inode, struct file *file)
252 {
253 return single_open(file, cpu_ss_debug_mode_show, NULL);
254 }
255
256 static ssize_t cpu_ss_debug_mode_write(struct file *file, const char *buffer, size_t count, loff_t *data)
257 {
258 int len = 0;
259 char mode[20], desc[32];
260
261 len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
262 if (copy_from_user(desc, buffer, len))
263 {
264 return 0;
265 }
266 desc[len] = '\0';
267
268 if (sscanf(desc, "%s", mode) == 1)
269 {
270 if (!strcmp(mode, "enable"))
271 {
272 printk("[%s]: enable cpu speed switch debug mode\n", __FUNCTION__);
273 mt_cpu_ss_debug_mode = true;
274 return count;
275 }
276 else if (!strcmp(mode, "disable"))
277 {
278 printk("[%s]: disable cpu speed switch debug mode\n", __FUNCTION__);
279 mt_cpu_ss_debug_mode = false;
280 return count;
281 }
282 else
283 {
284 printk("[%s]: bad argument!! should be \"enable\" or \"disable\"\n", __FUNCTION__);
285 }
286 }
287 else
288 {
289 printk("[%s]: bad argument!! should be \"enable\" or \"disable\"\n", __FUNCTION__);
290 }
291
292 return -EINVAL;
293 }
294
295
296 static const struct file_operations cpu_ss_debug_mode_fops = {
297 .owner = THIS_MODULE,
298 .write = cpu_ss_debug_mode_write,
299 .open = cpu_ss_debug_mode_open,
300 .read = seq_read,
301 .llseek = seq_lseek,
302 .release = single_release,
303 };
304
305 static const struct file_operations cpu_ss_period_mode_fops = {
306 .owner = THIS_MODULE,
307 .write = cpu_ss_period_mode_write,
308 .open = cpu_ss_period_mode_open,
309 .read = seq_read,
310 .llseek = seq_lseek,
311 .release = single_release,
312 };
313
314 static const struct file_operations cpu_ss_period_fops = {
315 .owner = THIS_MODULE,
316 .write = cpu_ss_period_write,
317 .open = cpu_ss_period_open,
318 .read = seq_read,
319 .llseek = seq_lseek,
320 .release = single_release,
321 };
322
323 static const struct file_operations cpu_ss_mode_fops = {
324 .owner = THIS_MODULE,
325 .write = cpu_ss_mode_write,
326 .open = cpu_ss_mode_open,
327 .read = seq_read,
328 .llseek = seq_lseek,
329 .release = single_release,
330 };
331
332
333 /*********************************
334 * cpu speed stress initialization
335 **********************************/
336 static int __init mt_cpu_ss_init(void)
337 {
338 struct proc_dir_entry *mt_entry = NULL;
339 struct proc_dir_entry *mt_cpu_ss_dir = NULL;
340
341 hrtimer_init(&mt_cpu_ss_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
342 mt_cpu_ss_timer.function = mt_cpu_ss_timer_func;
343
344 mt_cpu_ss_dir = proc_mkdir("cpu_ss", NULL);
345 if (!mt_cpu_ss_dir)
346 {
347 pr_err("[%s]: mkdir /proc/cpu_ss failed\n", __FUNCTION__);
348 }
349 else
350 {
351 mt_entry = proc_create("cpu_ss_debug_mode", S_IRUGO | S_IWUSR | S_IWGRP, mt_cpu_ss_dir, &cpu_ss_debug_mode_fops);
352 if (!mt_entry)
353 {
354 printk("[mtktscpu_init]: create /proc/cpu_ss/cpu_ss_debug_mode failed\n");
355 }
356
357 mt_entry = proc_create("cpu_ss_period_mode", S_IRUGO | S_IWUSR | S_IWGRP, mt_cpu_ss_dir, &cpu_ss_period_mode_fops);
358 if (!mt_entry)
359 {
360 printk("[mtktscpu_init]: create /proc/cpu_ss/cpu_ss_period_mode failed\n");
361 }
362
363 mt_entry = proc_create("cpu_ss_period", S_IRUGO | S_IWUSR | S_IWGRP, mt_cpu_ss_dir, &cpu_ss_period_fops);
364 if (!mt_entry)
365 {
366 printk("[mtktscpu_init]: create /proc/cpu_ss/cpu_ss_period failed\n");
367 }
368
369 mt_entry = proc_create("cpu_ss_mode", S_IRUGO | S_IWUSR | S_IWGRP, mt_cpu_ss_dir, &cpu_ss_mode_fops);
370 if (!mt_entry)
371 {
372 printk("[mtktscpu_init]: create /proc/cpu_ss/cpu_ss_mode failed\n");
373 }
374 }
375
376 return 0;
377 }
378
379 static void __exit mt_cpu_ss_exit(void)
380 {
381
382 }
383
384 module_init(mt_cpu_ss_init);
385 module_exit(mt_cpu_ss_exit);
386
387 MODULE_DESCRIPTION("MediaTek CPU Speed Stress driver");
388 MODULE_LICENSE("GPL");