blob: f3e73c9fab362eddf17e93986d82436db49cfdda [file] [log] [blame]
Steve Kondik0e9f0192012-09-24 02:12:49 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 * Copyright (c) 2012 The CyanogenMod Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#include <errno.h>
18#include <string.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22
23#define LOG_TAG "CM PowerHAL"
24#include <utils/Log.h>
25
26#include <hardware/hardware.h>
27#include <hardware/power.h>
28
29#define SCALING_GOVERNOR_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
30#define BOOSTPULSE_ONDEMAND "/sys/devices/system/cpu/cpufreq/ondemand/boostpulse"
31#define BOOSTPULSE_INTERACTIVE "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
32#define SAMPLING_RATE_ONDEMAND "/sys/devices/system/cpu/cpufreq/ondemand/sampling_rate"
33#define SAMPLING_RATE_SCREEN_ON "50000"
34#define SAMPLING_RATE_SCREEN_OFF "500000"
35
36struct cm_power_module {
37 struct power_module base;
38 pthread_mutex_t lock;
39 int boostpulse_fd;
40 int boostpulse_warned;
41};
42
43static int sysfs_read(char *path, char *s, int num_bytes)
44{
45 char buf[80];
46 int count;
47 int ret = 0;
48 int fd = open(path, O_RDONLY);
49
50 if (fd < 0) {
51 strerror_r(errno, buf, sizeof(buf));
52 ALOGE("Error opening %s: %s\n", path, buf);
53
54 return -1;
55 }
56
57 if ((count = read(fd, s, num_bytes - 1)) < 0) {
58 strerror_r(errno, buf, sizeof(buf));
59 ALOGE("Error writing to %s: %s\n", path, buf);
60
61 ret = -1;
62 } else {
63 s[count] = '\0';
64 }
65
66 close(fd);
67
68 return ret;
69}
70
71static void sysfs_write(char *path, char *s)
72{
73 char buf[80];
74 int len;
75 int fd = open(path, O_WRONLY);
76
77 if (fd < 0) {
78 strerror_r(errno, buf, sizeof(buf));
79 ALOGE("Error opening %s: %s\n", path, buf);
80 return;
81 }
82
83 len = write(fd, s, strlen(s));
84 if (len < 0) {
85 strerror_r(errno, buf, sizeof(buf));
86 ALOGE("Error writing to %s: %s\n", path, buf);
87 }
88
89 close(fd);
90}
91
92static int get_scaling_governor(char governor[], int size) {
93 if (sysfs_read(SCALING_GOVERNOR_PATH, governor,
94 size) == -1) {
95 // Can't obtain the scaling governor. Return.
96 return -1;
97 } else {
98 // Strip newline at the end.
99 int len = strlen(governor);
100
101 len--;
102
103 while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r'))
104 governor[len--] = '\0';
105 }
106
107 return 0;
108}
109
110static int boostpulse_open(struct cm_power_module *cm)
111{
112 char buf[80];
113 char governor[80];
114
115 pthread_mutex_lock(&cm->lock);
116
117 if (cm->boostpulse_fd < 0) {
118 if (get_scaling_governor(governor, sizeof(governor)) < 0) {
119 ALOGE("Can't read scaling governor.");
120 cm->boostpulse_warned = 1;
121 } else {
122 if (strncmp(governor, "ondemand", 8) == 0)
123 cm->boostpulse_fd = open(BOOSTPULSE_ONDEMAND, O_WRONLY);
124 else if (strncmp(governor, "interactive", 11) == 0)
125 cm->boostpulse_fd = open(BOOSTPULSE_INTERACTIVE, O_WRONLY);
126
127 if (cm->boostpulse_fd < 0 && !cm->boostpulse_warned) {
128 strerror_r(errno, buf, sizeof(buf));
129 ALOGE("Error opening boostpulse: %s\n", buf);
130 cm->boostpulse_warned = 1;
131 } else if (cm->boostpulse_fd > 0)
132 ALOGD("Opened %s boostpulse interface", governor);
133 }
134 }
135
136 pthread_mutex_unlock(&cm->lock);
137 return cm->boostpulse_fd;
138}
139
140static void cm_power_hint(struct power_module *module, power_hint_t hint,
141 void *data)
142{
143 struct cm_power_module *cm = (struct cm_power_module *) module;
144 char buf[80];
145 int len;
146 int duration = 1;
147
148 switch (hint) {
149 case POWER_HINT_INTERACTION:
150 case POWER_HINT_CPU_BOOST:
151 if (boostpulse_open(cm) >= 0) {
152 if (data != NULL)
153 duration = (int) data;
154
155 snprintf(buf, sizeof(buf), "%d", duration);
156 len = write(cm->boostpulse_fd, buf, strlen(buf));
157
158 if (len < 0) {
159 strerror_r(errno, buf, sizeof(buf));
160 ALOGE("Error writing to boostpulse: %s\n", buf);
161
162 pthread_mutex_lock(&cm->lock);
163 close(cm->boostpulse_fd);
164 cm->boostpulse_fd = -1;
165 cm->boostpulse_warned = 0;
166 pthread_mutex_unlock(&cm->lock);
167 }
168 }
169 break;
170
171 case POWER_HINT_VSYNC:
172 break;
173
174 default:
175 break;
176 }
177}
178
179static void cm_power_set_interactive(struct power_module *module, int on)
180{
181 sysfs_write(SAMPLING_RATE_ONDEMAND,
182 on ? SAMPLING_RATE_SCREEN_ON : SAMPLING_RATE_SCREEN_OFF);
183}
184
185static void cm_power_init(struct power_module *module)
186{
187 sysfs_write(SAMPLING_RATE_ONDEMAND, SAMPLING_RATE_SCREEN_ON);
188}
189
190static struct hw_module_methods_t power_module_methods = {
191 .open = NULL,
192};
193
194struct cm_power_module HAL_MODULE_INFO_SYM = {
195 base: {
196 common: {
197 tag: HARDWARE_MODULE_TAG,
198 module_api_version: POWER_MODULE_API_VERSION_0_2,
199 hal_api_version: HARDWARE_HAL_API_VERSION,
200 id: POWER_HARDWARE_MODULE_ID,
201 name: "CM Power HAL",
202 author: "The CyanogenMod Project",
203 methods: &power_module_methods,
204 },
205 init: cm_power_init,
206 setInteractive: cm_power_set_interactive,
207 powerHint: cm_power_hint,
208 },
209
210 lock: PTHREAD_MUTEX_INITIALIZER,
211 boostpulse_fd: -1,
212 boostpulse_warned: 0,
213};