1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
/*++
linux/arch/arm/mach-wmt/wmt_cpuidle.c
Copyright (c) 2008 WonderMedia Technologies, Inc.
This program is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software Foundation,
either version 2 of the License, or (at your option) any later version.
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.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
WonderMedia Technologies, Inc.
10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
--*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/cpuidle.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/export.h>
#include <asm/proc-fns.h>
#include <asm/cpuidle.h>
//#define DEBUG
#ifdef DEBUG
static int dbg_mask = 0;
module_param(dbg_mask, int, S_IRUGO | S_IWUSR);
#define id_dbg(fmt, args...) \
do {\
if (dbg_mask) \
printk(KERN_ERR "[%s]_%d: " fmt, __func__ , __LINE__, ## args);\
} while(0)
#define id_trace() \
do {\
if (dbg_mask) \
printk(KERN_ERR "trace in %s %d\n", __func__, __LINE__);\
} while(0)
#else
#define id_dbg(fmt, args...)
#define id_trace()
#endif
#define WMT_CPU_IDLE_MAX_STATES 2
extern int wmt_setsyspara(char *varname, unsigned char *varval);
extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlenex);
/* Actual code that puts the SoC in different idle states */
static int wmt_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
cpu_do_idle();
return index;
}
static struct cpuidle_driver wmt_cpuidle_driver = {
.name = "wmt_cpuidle",
.owner = THIS_MODULE,
.en_core_tk_irqen = 1,
/* ARM Wait for interrupt state */
.states[0] = ARM_CPUIDLE_WFI_STATE,
/* Wait for interrupt and DDR self refresh state */
.states[1] = {
.enter = wmt_enter_idle,
.exit_latency = 10,
.target_residency = 100000,
.flags = CPUIDLE_FLAG_TIME_VALID,
.name = "ZAC_OFF",
.desc = "WFI and disable ZAC clock",
},
.state_count = WMT_CPU_IDLE_MAX_STATES,
};
static int __init wmt_cpuidle_check_env(void)
{
int ret = 0;
int varlen = 128;
unsigned int drv_en = 0;
unsigned char buf[128] = {0};
/* uboot env name is: wmt.cpuidle.param/wmt.dvfs.param */
ret = wmt_getsyspara("wmt.cpuidle.param", buf, &varlen);
if (ret) {
printk(KERN_INFO "Can not find uboot env wmt.cpuidle.param\n");
ret = -ENODATA;
goto out;
}
id_dbg("wmt.cpuidle.param:%s\n", buf);
sscanf(buf, "%d", &drv_en);
if (!drv_en) {
printk(KERN_INFO "wmt cpuidle driver disaled\n");
ret = -ENODEV;
goto out;
}
out:
return ret;
}
static DEFINE_PER_CPU(struct cpuidle_device, wmt_cpuidle_device);
static int __init wmt_cpuidle_driver_init(void)
{
struct cpuidle_device *device = NULL;
if (wmt_cpuidle_check_env()) {
printk(KERN_WARNING "wmt_cpuidle check env failed!\n");
return -EINVAL;
}
device = &per_cpu(wmt_cpuidle_device, smp_processor_id());
device->state_count = WMT_CPU_IDLE_MAX_STATES;
cpuidle_register_driver(&wmt_cpuidle_driver);
if (cpuidle_register_device(device)) {
printk(KERN_ERR "wmt_cpuidle_driver_init: Failed registering\n");
return -EIO;
}
printk(KERN_INFO "WMT cpuidle driver register\n");
return 0;
}
module_init(wmt_cpuidle_driver_init);
MODULE_AUTHOR("WonderMedia Technologies, Inc");
MODULE_DESCRIPTION("WMT CPU idle driver");
MODULE_LICENSE("Dual BSD/GPL");
|