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.
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>
22 #include <asm/system.h>
23 #include <asm/uaccess.h>
25 #include "mach/sync_write.h"
26 #include "mach/mt_typedefs.h"
27 #include "mach/mt_cpufreq.h"
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
);
33 static int mt_cpu_ss_period_s
= 0;
34 static int mt_cpu_ss_period_ns
= 100;
36 static int mt_cpu_ss_timer_flag
= 0;
38 static bool mt_cpu_ss_debug_mode
= false;
39 static bool mt_cpu_ss_period_mode
= false;
41 enum hrtimer_restart
mt_cpu_ss_timer_func(struct hrtimer
*timer
)
43 if (mt_cpu_ss_debug_mode
)
44 printk("[%s]: enter timer function\n", __FUNCTION__
);
46 mt_cpu_ss_timer_flag
= 1; wake_up_interruptible(&mt_cpu_ss_timer_waiter
);
48 return HRTIMER_NORESTART
;
51 int mt_cpu_ss_thread_handler(void *unused
)
57 ktime_t ktime
= ktime_set(mt_cpu_ss_period_s
, mt_cpu_ss_period_ns
);
59 wait_event_interruptible(mt_cpu_ss_timer_waiter
, mt_cpu_ss_timer_flag
!= 0);
60 mt_cpu_ss_timer_flag
= 0;
64 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL
) & 0x0ff3), TOP_CKMUXSEL
);
69 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL
) | 0x0004), TOP_CKMUXSEL
);
73 if (mt_cpu_ss_debug_mode
)
74 printk("[%s]: TOP_CKMUXSEL = 0x%x\n", __FUNCTION__
, DRV_Reg32(TOP_CKMUXSEL
));
76 hrtimer_start(&mt_cpu_ss_timer
, ktime
, HRTIMER_MODE_REL
);
78 } while (!kthread_should_stop());
83 static int cpu_ss_mode_show(struct seq_file
* s
, void* v
)
85 if ((DRV_Reg32(TOP_CKMUXSEL
) & 0x000C) == 0)
86 seq_printf(s
, "CPU clock source is CLKSQ\n");
88 seq_printf(s
, "CPU clock source is ARMPLL\n");
93 static int cpu_ss_mode_open(struct inode
*inode
, struct file
*file
)
95 return single_open(file
, cpu_ss_mode_show
, NULL
);
98 static ssize_t
cpu_ss_mode_write(struct file
*file
, const char *buffer
, size_t count
, loff_t
*data
)
100 int len
= 0, mode
= 0;
103 len
= (count
< (sizeof(desc
) - 1)) ? count
: (sizeof(desc
) - 1);
104 if (copy_from_user(desc
, buffer
, len
))
110 if (sscanf(desc
, "%d", &mode
) == 1)
114 printk("[%s]: config cpu speed switch mode = ARMPLL\n", __FUNCTION__
);
115 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL
) | 0x0004), TOP_CKMUXSEL
);
119 printk("[%s]: config cpu speed switch mode = CLKSQ\n", __FUNCTION__
);
120 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL
) & 0x0ff3), TOP_CKMUXSEL
);
127 printk("[%s]: bad argument!! should be \"1\" or \"0\"\n", __FUNCTION__
);
133 static int cpu_ss_period_show(struct seq_file
* s
, void* v
)
135 seq_printf(s
, "%d (s) %d (ns)\n", mt_cpu_ss_period_s
, mt_cpu_ss_period_ns
);
140 static int cpu_ss_period_open(struct inode
*inode
, struct file
*file
)
142 return single_open(file
, cpu_ss_period_show
, NULL
);
145 static ssize_t
cpu_ss_period_write(struct file
*file
, const char *buffer
, size_t count
, loff_t
*data
)
147 int len
= 0, s
= 0, ns
= 0;
150 len
= (count
< (sizeof(desc
) - 1)) ? count
: (sizeof(desc
) - 1);
151 if (copy_from_user(desc
, buffer
, len
))
157 if (sscanf(desc
, "%d %d", &s
, &ns
) == 2)
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
;
166 printk("[%s]: bad argument!! should be \"[s]\" or \"[ns]\"\n", __FUNCTION__
);
172 static int cpu_ss_period_mode_show(struct seq_file
* s
, void* v
)
174 if (mt_cpu_ss_period_mode
)
175 seq_printf(s
, "enable");
177 seq_printf(s
, "disable");
182 static int cpu_ss_period_mode_open(struct inode
*inode
, struct file
*file
)
184 return single_open(file
, cpu_ss_period_mode_show
, NULL
);
187 static ssize_t
cpu_ss_period_mode_write(struct file
*file
, const char *buffer
, size_t count
, loff_t
*data
)
190 char mode
[20], desc
[32];
191 ktime_t ktime
= ktime_set(mt_cpu_ss_period_s
, mt_cpu_ss_period_ns
);
193 len
= (count
< (sizeof(desc
) - 1)) ? count
: (sizeof(desc
) - 1);
194 if (copy_from_user(desc
, buffer
, len
))
200 if (sscanf(desc
, "%s", mode
) == 1)
202 if (!strcmp(mode
, "enable"))
204 printk("[%s]: enable cpu speed switch period mode\n", __FUNCTION__
);
205 mt_cpu_ss_period_mode
= true;
207 mt_cpu_ss_thread
= kthread_run(mt_cpu_ss_thread_handler
, 0, "cpu speed switch");
208 if (IS_ERR(mt_cpu_ss_thread
))
210 printk("[%s]: failed to create cpu speed switch thread\n", __FUNCTION__
);
213 hrtimer_start(&mt_cpu_ss_timer
, ktime
, HRTIMER_MODE_REL
);
216 else if (!strcmp(mode
, "disable"))
218 printk("[%s]: disable cpu speed switch period mode\n", __FUNCTION__
);
219 mt_cpu_ss_period_mode
= false;
221 kthread_stop(mt_cpu_ss_thread
);
223 mt65xx_reg_sync_writel((DRV_Reg32(TOP_CKMUXSEL
) | 0x0004), TOP_CKMUXSEL
);
225 hrtimer_cancel(&mt_cpu_ss_timer
);
230 printk("[%s]: bad argument!! should be \"enable\" or \"disable\"\n", __FUNCTION__
);
235 printk("[%s]: bad argument!! should be \"enable\" or \"disable\"\n", __FUNCTION__
);
241 static int cpu_ss_debug_mode_show(struct seq_file
* s
, void* v
)
243 if (mt_cpu_ss_debug_mode
)
244 seq_printf(s
, "enable");
246 seq_printf(s
, "disable");
251 static int cpu_ss_debug_mode_open(struct inode
*inode
, struct file
*file
)
253 return single_open(file
, cpu_ss_debug_mode_show
, NULL
);
256 static ssize_t
cpu_ss_debug_mode_write(struct file
*file
, const char *buffer
, size_t count
, loff_t
*data
)
259 char mode
[20], desc
[32];
261 len
= (count
< (sizeof(desc
) - 1)) ? count
: (sizeof(desc
) - 1);
262 if (copy_from_user(desc
, buffer
, len
))
268 if (sscanf(desc
, "%s", mode
) == 1)
270 if (!strcmp(mode
, "enable"))
272 printk("[%s]: enable cpu speed switch debug mode\n", __FUNCTION__
);
273 mt_cpu_ss_debug_mode
= true;
276 else if (!strcmp(mode
, "disable"))
278 printk("[%s]: disable cpu speed switch debug mode\n", __FUNCTION__
);
279 mt_cpu_ss_debug_mode
= false;
284 printk("[%s]: bad argument!! should be \"enable\" or \"disable\"\n", __FUNCTION__
);
289 printk("[%s]: bad argument!! should be \"enable\" or \"disable\"\n", __FUNCTION__
);
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
,
302 .release
= single_release
,
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
,
311 .release
= single_release
,
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
,
320 .release
= single_release
,
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
,
329 .release
= single_release
,
333 /*********************************
334 * cpu speed stress initialization
335 **********************************/
336 static int __init
mt_cpu_ss_init(void)
338 struct proc_dir_entry
*mt_entry
= NULL
;
339 struct proc_dir_entry
*mt_cpu_ss_dir
= NULL
;
341 hrtimer_init(&mt_cpu_ss_timer
, CLOCK_MONOTONIC
, HRTIMER_MODE_REL
);
342 mt_cpu_ss_timer
.function
= mt_cpu_ss_timer_func
;
344 mt_cpu_ss_dir
= proc_mkdir("cpu_ss", NULL
);
347 pr_err("[%s]: mkdir /proc/cpu_ss failed\n", __FUNCTION__
);
351 mt_entry
= proc_create("cpu_ss_debug_mode", S_IRUGO
| S_IWUSR
| S_IWGRP
, mt_cpu_ss_dir
, &cpu_ss_debug_mode_fops
);
354 printk("[mtktscpu_init]: create /proc/cpu_ss/cpu_ss_debug_mode failed\n");
357 mt_entry
= proc_create("cpu_ss_period_mode", S_IRUGO
| S_IWUSR
| S_IWGRP
, mt_cpu_ss_dir
, &cpu_ss_period_mode_fops
);
360 printk("[mtktscpu_init]: create /proc/cpu_ss/cpu_ss_period_mode failed\n");
363 mt_entry
= proc_create("cpu_ss_period", S_IRUGO
| S_IWUSR
| S_IWGRP
, mt_cpu_ss_dir
, &cpu_ss_period_fops
);
366 printk("[mtktscpu_init]: create /proc/cpu_ss/cpu_ss_period failed\n");
369 mt_entry
= proc_create("cpu_ss_mode", S_IRUGO
| S_IWUSR
| S_IWGRP
, mt_cpu_ss_dir
, &cpu_ss_mode_fops
);
372 printk("[mtktscpu_init]: create /proc/cpu_ss/cpu_ss_mode failed\n");
379 static void __exit
mt_cpu_ss_exit(void)
384 module_init(mt_cpu_ss_init
);
385 module_exit(mt_cpu_ss_exit
);
387 MODULE_DESCRIPTION("MediaTek CPU Speed Stress driver");
388 MODULE_LICENSE("GPL");