2 * Rockchip pm_test Driver
4 * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
5 * Author: Finley Xiao <finley.xiao@rock-chips.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19 #include <linux/clk.h>
20 #include <linux/clk-provider.h>
21 #include <linux/cpufreq.h>
23 #include <linux/module.h>
24 #include <linux/regulator/driver.h>
25 #include <linux/regulator/machine.h>
26 #include <linux/uaccess.h>
27 #include "../../../../drivers/regulator/internal.h"
29 #define CLK_NR_CLKS 550
31 static int cpu_usage_run;
33 static DEFINE_PER_CPU(struct work_struct, work_cpu_usage);
34 static DEFINE_PER_CPU(struct workqueue_struct *, workqueue_cpu_usage);
36 static const char pi_result[] = "3141592653589793238462643383279528841971693993751058209749445923078164062862089986280348253421170679821480865132823664709384469555822317253594081284811174502841270193852115559644622948954930381964428810975665933446128475648233786783165271201991456485669234634861045432664821339360726024914127372458706606315588174881520920962829254917153643678925903611330530548820466521384146951941511609433057273657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566438602139494639522473719070217986943702770539217176293176752384674818467669451320005681271452635608277857713427577896091736371787214684409012249534301465495853710579227968925892354201995611212902196864344181598136297747713099605187072113499999983729780499510597317328160963185";
39 struct attribute attr;
40 ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
42 ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
43 const char *buf, size_t n);
46 static ssize_t clk_rate_show(struct kobject *kobj, struct kobj_attribute *attr,
51 str += sprintf(str, "get clk rate:\n");
53 " echo get [clk_name] > /sys/pm_tests/clk_rate\n");
54 str += sprintf(str, "set clk rate:\n");
56 " echo rawset [clk_name] [rate(Hz)] > /sys/pm_tests/clk_rate\n");
57 str += sprintf(str, "enable clk:\n");
59 " echo open [clk_name] > /sys/pm_tests/clk_rate\n");
60 str += sprintf(str, "disable clk:\n");
62 " echo close [clk_name] > /sys/pm_tests/clk_rate\n");
69 static struct clk *clk_get_by_name(const char *clk_name)
73 struct device_node *np;
74 struct of_phandle_args clkspec;
77 np = of_find_node_by_name(NULL, "clock-controller");
79 clkspec.args_count = 1;
80 for (i = 1; i < CLK_NR_CLKS; i++) {
82 clk = of_clk_get_from_provider(&clkspec);
83 if (IS_ERR_OR_NULL(clk))
85 name = __clk_get_name(clk);
86 if (strlen(name) != strlen(clk_name))
88 if (!strncmp(name, clk_name, strlen(clk_name)))
98 static int clk_rate_get(const char *buf)
100 char cmd[20], clk_name[20];
105 ret = sscanf(buf, "%s %s", cmd, clk_name);
109 clk = clk_get_by_name(clk_name);
110 if (IS_ERR_OR_NULL(clk)) {
111 pr_err("get clock error\n");
115 rate = clk_get_rate(clk);
117 pr_info("%s %lu Hz\n", clk_name, rate);
124 static int clk_rate_rawset(const char *buf)
126 char cmd[20], clk_name[20];
131 ret = sscanf(buf, "%s %s %lu", cmd, clk_name, &rate);
135 clk = clk_get_by_name(clk_name);
136 if (IS_ERR_OR_NULL(clk)) {
137 pr_err("get %s error\n", clk_name);
141 ret = clk_set_rate(clk, rate);
143 pr_err("set %s rate %d error\n", clk_name, ret);
147 pr_debug("%s %s %lu\n", cmd, clk_name, rate);
154 static int clk_open(const char *buf)
156 char cmd[20], clk_name[20];
160 ret = sscanf(buf, "%s %s", cmd, clk_name);
164 clk = clk_get_by_name(clk_name);
165 if (IS_ERR_OR_NULL(clk)) {
166 pr_err("get clock %s error\n", clk_name);
170 clk_prepare_enable(clk);
172 pr_debug("%s %s\n", cmd, clk_name);
179 static int clk_close(const char *buf)
181 char cmd[20], clk_name[20];
185 ret = sscanf(buf, "%s %s", cmd, clk_name);
189 clk = clk_get_by_name(clk_name);
190 if (IS_ERR_OR_NULL(clk)) {
191 pr_err("get clock %s error\n", clk_name);
195 clk_disable_unprepare(clk);
197 pr_debug("%s %s\n", cmd, clk_name);
204 static ssize_t clk_rate_store(struct kobject *kobj, struct kobj_attribute *attr,
205 const char *buf, size_t n)
210 ret = sscanf(buf, "%s", cmd);
214 if (!strncmp(cmd, "get", strlen("get"))) {
215 ret = clk_rate_get(buf);
217 pr_err("get clk err\n");
218 } else if (!strncmp(cmd, "rawset", strlen("rawset"))) {
219 ret = clk_rate_rawset(buf);
221 pr_err("rawset clk err\n");
222 } else if (!strncmp(cmd, "open", strlen("open"))) {
225 pr_err("open clk err\n");
226 } else if (!strncmp(cmd, "close", strlen("close"))) {
227 ret = clk_close(buf);
229 pr_err("close clk err\n");
231 pr_info("unsupported cmd(%s)\n", cmd);
237 static ssize_t clk_volt_show(struct kobject *kobj, struct kobj_attribute *attr,
242 str += sprintf(str, "get voltage:\n");
244 " echo get [regulaotr_name] > /sys/pm_tests/clk_volt\n");
245 str += sprintf(str, "set voltage:\n");
247 " echo set [regulaotr_name] [voltage(uV)] > /sys/pm_tests/clk_volt\n");
254 static int clk_volt_get(const char *buf)
256 char cmd[20], reg_name[20];
258 struct regulator *regulator;
260 ret = sscanf(buf, "%s %s", cmd, reg_name);
264 regulator = regulator_get(NULL, reg_name);
265 if (IS_ERR_OR_NULL(regulator)) {
266 pr_err("get regulator %s error\n", reg_name);
267 return PTR_ERR(regulator);
270 ret = regulator_get_voltage(regulator);
272 pr_info("%s %duV\n", reg_name, ret);
274 regulator_put(regulator);
279 static void break_up_regulator_limit(struct regulator_dev *rdev, int min_uV,
282 struct regulator *regulator;
284 list_for_each_entry(regulator, &rdev->consumer_list, list) {
285 if (!regulator->min_uV && !regulator->max_uV)
287 pr_debug("%s min=%d, max=%d", dev_name(regulator->dev),
288 regulator->min_uV, regulator->max_uV);
289 regulator->min_uV = min_uV;
290 regulator->max_uV = max_uV;
294 static int clk_volt_set(const char *buf)
296 char cmd[20], reg_name[20];
298 struct regulator *regulator;
300 struct regulator_dev *rdev;
303 ret = sscanf(buf, "%s %s %u", cmd, reg_name, &volt);
307 regulator = regulator_get(NULL, reg_name);
308 if (IS_ERR_OR_NULL(regulator)) {
309 pr_info("get regulator %s error\n", reg_name);
310 return PTR_ERR(regulator);
313 rdev = regulator->rdev;
314 max_uV = rdev->constraints->max_uV;
317 pr_err("invalid volt, max %d uV\n", max_uV);
321 mutex_lock(&rdev->mutex);
322 break_up_regulator_limit(rdev, volt, max_uV);
323 mutex_unlock(&rdev->mutex);
325 ret = regulator_set_voltage(regulator, volt, max_uV);
327 pr_err("set voltage %d error\n", ret);
328 regulator_put(regulator);
332 pr_debug("set %s %duV\n", reg_name, volt);
334 regulator_put(regulator);
339 static ssize_t clk_volt_store(struct kobject *kobj, struct kobj_attribute *attr,
340 const char *buf, size_t n)
345 ret = sscanf(buf, "%s", cmd);
349 if (!strncmp(cmd, "get", strlen("get"))) {
350 ret = clk_volt_get(buf);
352 pr_err("get volt err\n");
353 } else if (!strncmp(cmd, "set", strlen("set"))) {
354 ret = clk_volt_set(buf);
356 pr_err("set volt err\n");
358 pr_err("unsupported cmd(%s)\n", cmd);
364 static ssize_t cpu_usage_show(struct kobject *kobj, struct kobj_attribute *attr,
372 " cpu 0-3: echo start 0 0 > /sys/pm_tests/cpu_usage\n");
374 " cpu 4-7: echo start 0 1 > /sys/pm_tests/cpu_usage\n");
376 " cpu 0-7: echo start 0 2 > /sys/pm_tests/cpu_usage\n");
380 " cpu 0-3: echo start 1 0 > /sys/pm_tests/cpu_usage\n");
382 " cpu 4-7: echo start 1 1 > /sys/pm_tests/cpu_usage\n");
384 " cpu 0-7: echo start 1 2 > /sys/pm_tests/cpu_usage\n");
388 " cpu 0-7: echo stop -1 -1 > /sys/pm_tests/cpu_usage\n");
395 static inline int calc_pi(void)
398 long a = 10000, b = 0, c = 2800, d = 0, e = 0, g = 0;
402 char *pi_calc, *pi_temp;
403 char *pi_just = (char *)&pi_result[0];
404 size_t pi_just_size = sizeof(pi_result);
406 result = vmalloc(10000 * sizeof(int));
410 f = vmalloc(2801 * sizeof(long));
414 pi_calc = vmalloc(1000 * sizeof(char));
420 for (; d = 0, g = c * 2; c -= 14, result[bit++] = e + d / a, e = d % a)
421 for (b = c; d += f[b] * a, f[b] = d % --g, d /= g--, --b;
426 for (i = 0; i < bit; i++)
427 len += sprintf(pi_temp + len, "%d", result[i]);
429 if (strncmp(pi_just, pi_calc, pi_just_size) == 0) {
439 pr_err("calc_pi error\n");
445 static void calc_pi2(void)
451 static void calc_pi4(void)
457 static void calc_pi8(void)
463 static void calc_pi16(void)
469 /* 0xffffffc000097468 - 0xffffffc0000949c4 = 10916 byte*/
470 static void calc_pi32(void)
476 /* 0xffffffc000099ee8 - 0xffffffc0000949c4 = 21796 byte*/
477 static void calc_pi64(void)
483 /* 0xffffffc00009f3e8 - 0xffffffc0000949c4 = 43556 byte*/
484 static void calc_pi128(void)
490 /* 0xffffffc0000a9de8 - 0xffffffc0000949c4 = 87076 byte*/
491 static void calc_pi256(void)
497 /* 0xffffffc0000bf1e8 - 0xffffffc0000949c4 = 174116 byte*/
498 static void calc_pi512(void)
504 /* 0xffffffc0000ea9e8 - 0xffffffc0000949c4 = 352295 byte*/
505 static void calc_pi1024(void)
511 static void calc_pi_large(void)
516 static void handler_cpu_usage(struct work_struct *work)
518 while (cpu_usage_run == 0)
521 while (cpu_usage_run == 1)
525 static ssize_t cpu_usage_store(struct kobject *kobj,
526 struct kobj_attribute *attr,
527 const char *buf, size_t n)
529 struct workqueue_struct *workqueue;
530 struct work_struct *work;
537 ret = sscanf(buf, "%s %d %d", cmd, &usage, &cluster);
541 if (!strncmp(cmd, "start", strlen("start"))) {
543 pr_info("start while(1) test\n");
545 pr_info("start pi test\n");
549 cpu_usage_run = usage;
550 for_each_online_cpu(cpu) {
551 work = &per_cpu(work_cpu_usage, cpu);
552 workqueue = per_cpu(workqueue_cpu_usage, cpu);
553 if (!work || !workqueue) {
554 pr_err("work or workqueue NULL\n");
558 if (cluster == 0 && cpu < 4)
559 queue_work_on(cpu, workqueue, work);
560 else if (cluster == 1 && cpu >= 4)
561 queue_work_on(cpu, workqueue, work);
562 else if (cluster == 2)
563 queue_work_on(cpu, workqueue, work);
565 } else if (!strncmp(cmd, "stop", strlen("stop"))) {
566 if (cpu_usage_run == 0)
567 pr_info("stop while(1) test\n");
568 else if (cpu_usage_run == 1)
569 pr_info("stop pi test\n");
570 cpu_usage_run = usage;
576 static struct pm_attribute pm_attrs[] = {
577 __ATTR(clk_rate, 0644, clk_rate_show, clk_rate_store),
578 __ATTR(clk_volt, 0644, clk_volt_show, clk_volt_store),
579 __ATTR(cpu_usage, 0644, cpu_usage_show, cpu_usage_store),
582 static int __init pm_test_init(void)
584 struct kobject *kobject;
585 struct workqueue_struct *workqueue;
586 struct work_struct *work;
589 kobject = kobject_create_and_add("pm_tests", NULL);
593 for (i = 0; i < ARRAY_SIZE(pm_attrs); i++) {
594 ret = sysfs_create_file(kobject, &pm_attrs[i].attr);
596 pr_err("create file index %d error\n", i);
601 workqueue = create_workqueue("workqueue_cpu_usage");
603 pr_err("workqueue NULL\n");
607 for_each_online_cpu(cpu) {
608 work = &per_cpu(work_cpu_usage, cpu);
610 pr_err("work NULL\n");
613 INIT_WORK(work, handler_cpu_usage);
614 per_cpu(workqueue_cpu_usage, cpu) = workqueue;
620 late_initcall(pm_test_init);
622 MODULE_DESCRIPTION("Rockchip pm_test driver");
623 MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
624 MODULE_LICENSE("GPL v2");