From 62e801f1f8018d14f2fcf00fee3ee2ecd277a025 Mon Sep 17 00:00:00 2001
From: chenxing <chenxing@rock-chips.com>
Date: Wed, 20 Mar 2013 14:29:15 +0800
Subject: [PATCH] rk: add /sys/pm_tests/tools support

---
 arch/arm/plat-rk/Kconfig                   |   2 +
 arch/arm/plat-rk/Makefile                  |   1 +
 arch/arm/plat-rk/rk_pm_tests/Kconfig       |  29 ++++
 arch/arm/plat-rk/rk_pm_tests/Makefile      |   8 ++
 arch/arm/plat-rk/rk_pm_tests/clk_rate.c    | 155 +++++++++++++++++++++
 arch/arm/plat-rk/rk_pm_tests/clk_rate.h    |   8 ++
 arch/arm/plat-rk/rk_pm_tests/clk_volt.c    |  60 ++++++++
 arch/arm/plat-rk/rk_pm_tests/clk_volt.h    |   8 ++
 arch/arm/plat-rk/rk_pm_tests/cpu_usage.c   | 129 +++++++++++++++++
 arch/arm/plat-rk/rk_pm_tests/cpu_usage.h   |   8 ++
 arch/arm/plat-rk/rk_pm_tests/freq_limit.c  |  65 +++++++++
 arch/arm/plat-rk/rk_pm_tests/freq_limit.h  |   8 ++
 arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.c | 121 ++++++++++++++++
 arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.h |   5 +
 14 files changed, 607 insertions(+)
 create mode 100755 arch/arm/plat-rk/rk_pm_tests/Kconfig
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/Makefile
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/clk_rate.c
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/clk_rate.h
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/clk_volt.c
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/clk_volt.h
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/cpu_usage.c
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/cpu_usage.h
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/freq_limit.c
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/freq_limit.h
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.c
 create mode 100644 arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.h

diff --git a/arch/arm/plat-rk/Kconfig b/arch/arm/plat-rk/Kconfig
index 8d7aba6a812c..88f3964b6136 100755
--- a/arch/arm/plat-rk/Kconfig
+++ b/arch/arm/plat-rk/Kconfig
@@ -113,6 +113,8 @@ config RK_CLOCK_PROC
 	bool "/proc/clocks support"
 	depends on PROC_FS
 
+source arch/arm/plat-rk/rk_pm_tests/Kconfig
+
 if !ARCH_RK29
 menu "Support for RK power manage"
 
diff --git a/arch/arm/plat-rk/Makefile b/arch/arm/plat-rk/Makefile
index 2544a3253553..0dc74c95bc74 100755
--- a/arch/arm/plat-rk/Makefile
+++ b/arch/arm/plat-rk/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_DDR_FREQ) += ddr_freq.o
 obj-$(CONFIG_DVFS) += dvfs.o
 obj-y += pwm.o
 obj-$(CONFIG_RK_TIMER) += rk_timer.o
+obj-$(CONFIG_RK_PM_TESTS) += rk_pm_tests/
diff --git a/arch/arm/plat-rk/rk_pm_tests/Kconfig b/arch/arm/plat-rk/rk_pm_tests/Kconfig
new file mode 100755
index 000000000000..a9ad24fc655d
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/Kconfig
@@ -0,0 +1,29 @@
+menuconfig RK_PM_TESTS
+	bool "/sys/pm_tests/ support"
+	help
+	  PM tests tools
+
+if RK_PM_TESTS
+
+config PM_TEST_CLK_RATE
+	bool "Scale clock rate"
+	default y
+	help
+	  Use to set clock rate
+
+config PM_TEST_CLK_VOLT
+	bool "Scale voltage"
+	default y
+	help
+	  Use to set voltage domain's voltage
+
+config PM_TEST_FREQ_LIMIT
+	bool "Limit clocks' frequency"
+	help
+	  Use to limit clocks' frequency
+
+config PM_TEST_CPU_USAGE
+	bool "Set cpu running at a fixed frequency"
+	help
+	  Use to Set cpu running at a fixed frequency
+endif
diff --git a/arch/arm/plat-rk/rk_pm_tests/Makefile b/arch/arm/plat-rk/rk_pm_tests/Makefile
new file mode 100644
index 000000000000..1f742c866a94
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_RK_PM_TESTS) += rk_pm_tests.o
+
+# Optional functions
+obj-$(CONFIG_PM_TEST_CLK_RATE) += clk_rate.o
+obj-$(CONFIG_PM_TEST_CLK_VOLT) += clk_volt.o
+obj-$(CONFIG_PM_TEST_FREQ_LIMIT) += freq_limit.o
+obj-$(CONFIG_PM_TEST_CPU_USAGE) += cpu_usage.o
+
diff --git a/arch/arm/plat-rk/rk_pm_tests/clk_rate.c b/arch/arm/plat-rk/rk_pm_tests/clk_rate.c
new file mode 100644
index 000000000000..3d102b21130a
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/clk_rate.c
@@ -0,0 +1,155 @@
+#include <linux/clk.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/resume-trace.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/regulator/machine.h>
+#include <plat/dma-pl330.h>
+#include <linux/mfd/wm831x/core.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+#include <mach/ddr.h>
+#include <mach/dvfs.h>
+
+#include <linux/fs.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include "rk_pm_tests.h"
+#include "clk_rate.h"
+/***************************************************************************/
+#define FILE_GOV_MODE "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+#define FILE_SETSPEED "/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"
+#define FILE_CUR_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
+
+static int file_read(char *file_path, char *buf)
+{
+	struct file *file = NULL;
+	mm_segment_t old_fs;
+	loff_t offset = 0;
+
+	PM_DBG("read %s\n", file_path);
+	file = filp_open(file_path, O_RDONLY, 0);
+
+	if (IS_ERR(file)) {
+		PM_ERR("%s error open file  %s\n", __func__, file_path);
+		return -1;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	file->f_op->read(file, (char *)buf, 32, &offset);
+	sscanf(buf, "%s", buf);
+
+	set_fs(old_fs);
+	filp_close(file, NULL);  
+
+	file = NULL;
+
+	return 0;
+
+}
+
+static int file_write(char *file_path, char *buf)
+{
+	struct file *file = NULL;
+	mm_segment_t old_fs;
+	loff_t offset = 0;
+
+	PM_DBG("write %s %s size = %d\n", file_path, buf, strlen(buf));
+	file = filp_open(file_path, O_RDWR, 0);
+
+	if (IS_ERR(file)) {
+		PM_ERR("%s error open file  %s\n", __func__, file_path);
+		return -1;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	file->f_op->write(file, (char *)buf, strlen(buf), &offset);
+
+	set_fs(old_fs);
+	filp_close(file, NULL);  
+
+	file = NULL;
+
+	return 0;
+
+}
+
+ssize_t clk_rate_show(struct kobject *kobj, struct kobj_attribute *attr,
+		char *buf)
+{
+	char *str = buf;
+	str += sprintf(str, "set	[clk_name]	[rate(Hz)]\n"
+			"reset	[clk_name]	[rate(Hz) = 0]\n");
+	if (str != buf)
+		*(str - 1) = '\n';
+	return (str - buf);
+
+}
+
+ssize_t clk_rate_store(struct kobject *kobj, struct kobj_attribute *attr,
+		const char *buf, size_t n)
+{
+	char cmd[20], clk_name[20], msg[50];
+	int rate;
+	struct clk *clk;
+	sscanf(buf, "%s %s %d", cmd, clk_name, &rate);
+
+
+	clk = clk_get(NULL, clk_name);
+	if (IS_ERR(clk)) {
+		PM_ERR("%s get clk %s error\n", __func__, clk_name);
+		return n;
+	}
+
+	if (0 == strncmp(cmd, "set", strlen("set"))) {
+		PM_DBG("Get command set %s %dHz\n", clk_name, rate);
+		if (file_read(FILE_GOV_MODE, msg) != 0) {
+			PM_ERR("read current governor error\n");
+			return n;
+		} else {
+			PM_DBG("current governor = %s\n", msg);
+		}
+
+		strcpy(msg, "userspace");
+		if (file_write(FILE_GOV_MODE, msg) != 0) {
+			PM_ERR("set current governor error\n");
+			return n;
+		}
+
+		dvfs_clk_enable_limit(clk, rate, rate);
+		clk_set_rate(clk, rate);
+
+	} else if (0 == strncmp(cmd, "reset", strlen("reset"))) {	
+		PM_DBG("Get command reset %s\n", clk_name);
+		if (file_read(FILE_GOV_MODE, msg) != 0) {
+			PM_ERR("read current governor error\n");
+			return n;
+		} else {
+			PM_DBG("current governor = %s\n", msg);
+		}
+
+		strcpy(msg, "interactive");
+		if (file_write(FILE_GOV_MODE, msg) != 0) {
+			PM_ERR("set current governor error\n");
+			return n;
+		}
+
+		dvfs_clk_disable_limit(clk);
+	}
+	
+	return n;
+}
+
diff --git a/arch/arm/plat-rk/rk_pm_tests/clk_rate.h b/arch/arm/plat-rk/rk_pm_tests/clk_rate.h
new file mode 100644
index 000000000000..bfb649d09a36
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/clk_rate.h
@@ -0,0 +1,8 @@
+#ifndef _CLK_RATE_H_
+#define _CLK_RATE_H_
+ssize_t clk_rate_show(struct kobject *kobj, struct kobj_attribute *attr,
+		char *buf);
+ssize_t clk_rate_store(struct kobject *kobj, struct kobj_attribute *attr,
+		const char *buf, size_t n);
+
+#endif
diff --git a/arch/arm/plat-rk/rk_pm_tests/clk_volt.c b/arch/arm/plat-rk/rk_pm_tests/clk_volt.c
new file mode 100644
index 000000000000..ef4e7a4a10f8
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/clk_volt.c
@@ -0,0 +1,60 @@
+#include <linux/clk.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/resume-trace.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/regulator/machine.h>
+#include <plat/dma-pl330.h>
+#include <linux/mfd/wm831x/core.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+#include <mach/ddr.h>
+#include <mach/dvfs.h>
+
+#include "rk_pm_tests.h"
+#include "clk_volt.h"
+/***************************************************************************/
+ssize_t clk_volt_show(struct kobject *kobj, struct kobj_attribute *attr,
+		char *buf)
+{
+	char *str = buf;
+	str += sprintf(str, "[regulaotr_name]	[voltage(uV)]\n");
+	if (str != buf)
+		*(str - 1) = '\n';
+	return (str - buf);
+
+}
+
+ssize_t clk_volt_store(struct kobject *kobj, struct kobj_attribute *attr,
+		const char *buf, size_t n)
+{
+	char regulator_name[20];
+	unsigned int volt;
+	int ret = 0;
+	struct regulator *regulator;
+	
+	sscanf(buf, "%s %u", regulator_name, &volt);
+	
+	regulator = dvfs_get_regulator(regulator_name);
+	if (IS_ERR(regulator)) {
+		PM_ERR("%s get dvfs_regulator %s error\n", __func__, regulator_name);
+		return n;
+	}
+
+	ret = regulator_set_voltage(regulator, volt, volt); 
+	PM_DBG("ret = %d\n", ret);
+
+
+//	if (0 == strncmp(cmd, "enable", strlen("enable"))) {
+	return n;
+}
+
diff --git a/arch/arm/plat-rk/rk_pm_tests/clk_volt.h b/arch/arm/plat-rk/rk_pm_tests/clk_volt.h
new file mode 100644
index 000000000000..346bd20bfea2
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/clk_volt.h
@@ -0,0 +1,8 @@
+#ifndef _CLK_VOLT_H_
+#define _CLK_VOLT_H_
+ssize_t clk_volt_show(struct kobject *kobj, struct kobj_attribute *attr,
+		char *buf);
+ssize_t clk_volt_store(struct kobject *kobj, struct kobj_attribute *attr,
+		const char *buf, size_t n);
+
+#endif
diff --git a/arch/arm/plat-rk/rk_pm_tests/cpu_usage.c b/arch/arm/plat-rk/rk_pm_tests/cpu_usage.c
new file mode 100644
index 000000000000..192484e8b4f1
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/cpu_usage.c
@@ -0,0 +1,129 @@
+#include <linux/clk.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/resume-trace.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/regulator/machine.h>
+#include <plat/dma-pl330.h>
+#include <linux/mfd/wm831x/core.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+#include <mach/cru.h>
+#include <mach/dvfs.h>
+#include <mach/sram.h>
+#include <linux/random.h>
+
+#include <linux/fs.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include "rk_pm_tests.h"
+#include "cpu_usage.h"
+/***************************************************************************/
+#define cru_readl(offset)	readl_relaxed(RK2928_CRU_BASE + offset)
+#define cru_writel(v, offset)	do { writel_relaxed(v, RK2928_CRU_BASE + offset); dsb(); } while (0)
+
+struct workqueue_struct	*workqueue_cpu_usage0;
+struct work_struct 	work_cpu_usage0;
+struct workqueue_struct	*workqueue_cpu_usage1;
+struct work_struct 	work_cpu_usage1;
+
+
+int cpu_usage_run = 0;
+int cpu_usage_percent = 0;
+
+struct timer_list arm_mode_timer;
+#define ARM_MODE_TIMER_MSEC	100
+static void arm_mode_timer_handler(unsigned long data)
+{
+	int i;
+	PM_DBG("enter %s\n", __func__);
+	if (cpu_usage_run == 0) {
+		PM_DBG("STOP\n");
+		return ;
+	}
+
+	arm_mode_timer.expires  = jiffies + msecs_to_jiffies(ARM_MODE_TIMER_MSEC);
+	add_timer(&arm_mode_timer);
+	for(i = 0; i < cpu_usage_percent; i++) {
+		mdelay(1);
+	}
+}
+
+static void handler_cpu_usage(struct work_struct *work)
+{	
+#if 1
+	while(cpu_usage_run) {
+		barrier();
+	}
+#else
+	del_timer(&arm_mode_timer);
+	arm_mode_timer.expires	= jiffies + msecs_to_jiffies(ARM_MODE_TIMER_MSEC);
+	add_timer(&arm_mode_timer);
+#endif
+}
+ssize_t cpu_usage_show(struct kobject *kobj, struct kobj_attribute *attr,
+		char *buf)
+{
+	char *str = buf;
+	str += sprintf(str, "HELLO\n");
+	if (str != buf)
+		*(str - 1) = '\n';
+	return (str - buf);
+
+}
+ssize_t cpu_usage_store(struct kobject *kobj, struct kobj_attribute *attr,
+		const char *buf, size_t n)
+{
+	char cmd[20];
+	int usage = 0;
+	sscanf(buf, "%s %d", cmd, &usage);
+
+	if((strncmp(cmd, "start", strlen("start")) == 0)) {
+		PM_DBG("get cmd start\n");
+		cpu_usage_run = 1;
+		
+		cpu_usage_percent = (ARM_MODE_TIMER_MSEC * usage) / 100;
+		if (workqueue_cpu_usage0 == NULL) {
+			PM_ERR("workqueue NULL\n");
+			return n;
+		}
+		if (workqueue_cpu_usage1 == NULL) {
+			PM_ERR("workqueue NULL\n");
+			return n;
+		}
+
+		queue_work_on(0, workqueue_cpu_usage0, &work_cpu_usage0);
+		queue_work_on(1, workqueue_cpu_usage1, &work_cpu_usage1);
+#if 0
+		del_timer(&arm_mode_timer);
+		arm_mode_timer.expires	= jiffies + msecs_to_jiffies(ARM_MODE_TIMER_MSEC);
+		add_timer(&arm_mode_timer);
+#endif
+	
+	} else if (strncmp(cmd, "stop", strlen("stop")) == 0) {
+		PM_DBG("get cmd stop\n");
+		cpu_usage_run = 0;
+	}
+
+	return n;
+}
+
+static int __init cpu_usage_init(void)
+{
+	workqueue_cpu_usage0 = create_singlethread_workqueue("workqueue_cpu_usage0");
+	INIT_WORK(&work_cpu_usage0, handler_cpu_usage);
+	workqueue_cpu_usage1 = create_singlethread_workqueue("workqueue_cpu_usage1");
+	INIT_WORK(&work_cpu_usage1, handler_cpu_usage);
+	setup_timer(&arm_mode_timer, arm_mode_timer_handler, (unsigned int)NULL);
+	return 0;
+}
+late_initcall(cpu_usage_init);
diff --git a/arch/arm/plat-rk/rk_pm_tests/cpu_usage.h b/arch/arm/plat-rk/rk_pm_tests/cpu_usage.h
new file mode 100644
index 000000000000..0c45ad4f4846
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/cpu_usage.h
@@ -0,0 +1,8 @@
+#ifndef _CPU_USAGE_H_
+#define _CPU_USAGE_H_
+ssize_t cpu_usage_show(struct kobject *kobj, struct kobj_attribute *attr,
+		char *buf);
+ssize_t cpu_usage_store(struct kobject *kobj, struct kobj_attribute *attr,
+		const char *buf, size_t n);
+
+#endif
diff --git a/arch/arm/plat-rk/rk_pm_tests/freq_limit.c b/arch/arm/plat-rk/rk_pm_tests/freq_limit.c
new file mode 100644
index 000000000000..02582adde316
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/freq_limit.c
@@ -0,0 +1,65 @@
+#include <linux/clk.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/resume-trace.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/regulator/machine.h>
+#include <plat/dma-pl330.h>
+#include <linux/mfd/wm831x/core.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+#include <mach/ddr.h>
+#include <mach/dvfs.h>
+
+#include "rk_pm_tests.h"
+#include "freq_limit.h"
+/***************************************************************************/
+ssize_t freq_limit_show(struct kobject *kobj, struct kobj_attribute *attr,
+		char *buf)
+{
+	char *str = buf;
+	str += sprintf(str, "command(enable/disable) clk_name	min_rate	max_rate\n");
+	if (str != buf)
+		*(str - 1) = '\n';
+	return (str - buf);
+
+}
+
+ssize_t freq_limit_store(struct kobject *kobj, struct kobj_attribute *attr,
+		const char *buf, size_t n)
+{
+	char cmd[20], clk_name[20];
+	unsigned int min_rate, max_rate;
+	struct clk *clk;
+	sscanf(buf, "%s %s %u %u", cmd, clk_name, &min_rate, &max_rate);
+	
+	clk = clk_get(NULL, clk_name);
+	if (IS_ERR(clk)) {
+		PM_ERR("get clk %s error\n", __func__);
+		return n;
+	}
+
+	if (0 == strncmp(cmd, "enable", strlen("enable"))) {
+		PM_DBG("limit enable clk(%s) min(%d) max(%d)\n", clk_name, min_rate, max_rate);
+		dvfs_clk_enable_limit(clk, min_rate, max_rate);
+		clk_set_rate(clk, min_rate);
+	
+	} else if (0 == strncmp(cmd, "disable", strlen("disable"))) {
+		PM_DBG("limit disable clk(%s)\n", clk_name);
+		dvfs_clk_disable_limit(clk);
+	
+	} else {
+		PM_ERR("unknown command\n");
+	}
+	return n;
+}
+
diff --git a/arch/arm/plat-rk/rk_pm_tests/freq_limit.h b/arch/arm/plat-rk/rk_pm_tests/freq_limit.h
new file mode 100644
index 000000000000..44c7c14ac2cd
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/freq_limit.h
@@ -0,0 +1,8 @@
+#ifndef _FREQ_LIMIT_H_
+#define _FREQ_LIMIT_H_
+ssize_t freq_limit_show(struct kobject *kobj, struct kobj_attribute *attr,
+		char *buf);
+ssize_t freq_limit_store(struct kobject *kobj, struct kobj_attribute *attr,
+		const char *buf, size_t n);
+
+#endif
diff --git a/arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.c b/arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.c
new file mode 100644
index 000000000000..9330c450c0e1
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.c
@@ -0,0 +1,121 @@
+/* arch/arm/mach-rk30/rk_pm_tests.c
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+/*************************************************************************/
+/*	  COPYRIGHT (C)  ROCK-CHIPS FUZHOU . ALL RIGHTS RESERVED.*/
+/*************************************************************************
+FILE		:	  rk_pm_tests.c
+DESC		:	  Power management in dynning state
+AUTHOR		:	  chenxing
+DATE		:	  2012-7-2
+NOTES		:
+$LOG: GPIO.C,V $
+REVISION 0.01
+#include <linux/clk.h>
+#include <linux/kobject.h>
+ ***************************************************************************/
+#include <linux/string.h>
+#include <linux/resume-trace.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/regulator/machine.h>
+#include <plat/dma-pl330.h>
+#include <linux/mfd/wm831x/core.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+//#include <mach/ddr.h>
+
+#include "rk_pm_tests.h"
+
+#include "clk_rate.h"
+#include "clk_volt.h"
+#include "freq_limit.h"
+#include "cpu_usage.h"
+//#include "rk2928_freq.h"
+//#include "rk2928_max_freq.h"
+//#include "cpu_calc.h"
+//#include "ddr_scale_freq.h"
+//#include "pmic_delay.h"
+//#include "rk30_volt_diff.h"
+
+static struct kobject *pm_tests_kobj;
+struct pm_attribute {
+	struct attribute	attr;
+	ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
+			char *buf);
+	ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
+			const char *buf, size_t n);
+};
+
+static struct pm_attribute pm_attrs[] = {
+	/* node_name	permision	show_func	store_func*/
+#ifdef CONFIG_PM_TEST_CLK_RATE
+	__ATTR(clk_rate, S_IRUGO | S_IWUSR, clk_rate_show, clk_rate_store),
+#endif
+#ifdef CONFIG_PM_TEST_CLK_VOLT
+	__ATTR(clk_volt, S_IRUGO | S_IWUSR, clk_volt_show, clk_volt_store),
+#endif
+#ifdef CONFIG_PM_TEST_FREQ_LIMIT
+	__ATTR(freq_limit, S_IRUGO | S_IWUSR, freq_limit_show, freq_limit_store),
+#endif
+#ifdef CONFIG_PM_TEST_CPU_USAGE
+	__ATTR(cpu_usage, S_IRUGO | S_IWUSR, cpu_usage_show, cpu_usage_store),
+#endif
+		
+#if 0
+	__ATTR(ddr_scale_freq, S_IRUGO | S_IWUSR, ddr_scale_freq_show, ddr_scale_freq_store),
+	__ATTR(pmic_delay, S_IRUGO | S_IWUSR, pmic_delay_show, pmic_delay_store),
+#endif
+//	__ATTR(rk2928_freq, S_IRUGO | S_IWUSR, rk2928_freq_show, rk2928_freq_store),
+//	__ATTR(rk2928_max_freq, S_IRUGO | S_IWUSR, rk2928_max_freq_show, rk2928_max_freq_store),
+//	__ATTR(cpu_calc, S_IRUGO | S_IWUSR, cpu_calc_show, cpu_calc_store),
+//	__ATTR(rk30_volt_diff, S_IRUGO | S_IWUSR, rk30_volt_diff_show, rk30_volt_diff_store),
+};
+
+static void __exit rk_pm_tests_exit(void)
+{
+	kobject_put(pm_tests_kobj);
+}
+
+static int __init rk_pm_tests_init(void)
+{
+	int i, ret = 0;
+	pm_tests_kobj = kobject_create_and_add("pm_tests", NULL);
+
+	if (!pm_tests_kobj)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(pm_attrs); i++) {
+		ret = sysfs_create_file(pm_tests_kobj, &pm_attrs[i].attr);
+		if (ret != 0) {
+			PM_ERR("create index %d error\n", i);
+			return ret;
+		}
+	}
+	
+	return ret;
+}
+
+late_initcall(rk_pm_tests_init);
+module_exit(rk_pm_tests_exit);
diff --git a/arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.h b/arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.h
new file mode 100644
index 000000000000..d0d7a8d2aa65
--- /dev/null
+++ b/arch/arm/plat-rk/rk_pm_tests/rk_pm_tests.h
@@ -0,0 +1,5 @@
+#ifndef _RK_PM_TESTS_H_
+#define _RK_PM_TESTS_H_
+#define PM_DBG(fmt, args...) printk(KERN_DEBUG "PM_TESTS_DBG:\t"fmt, ##args)
+#define PM_ERR(fmt, args...) printk(KERN_ERR "PM_TESTS_ERR:\t"fmt, ##args)
+#endif
-- 
2.34.1