blob: ec3335b9d66e9ff0824627fc58c39e589c9ec52d [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
Anurag Singhb2adeec2012-12-14 10:23:03 -080029#define ONDEMAND_GOVERNOR "ondemand"
30#define INTERACTIVE_GOVERNOR "interactive"
Steve Kondik0e9f0192012-09-24 02:12:49 -070031#define SCALING_GOVERNOR_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
32#define BOOSTPULSE_ONDEMAND "/sys/devices/system/cpu/cpufreq/ondemand/boostpulse"
33#define BOOSTPULSE_INTERACTIVE "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
Steve Kondik0e9f0192012-09-24 02:12:49 -070034#define SAMPLING_RATE_SCREEN_ON "50000"
35#define SAMPLING_RATE_SCREEN_OFF "500000"
Steve Kondike29bcbf2013-02-07 21:21:52 -080036#define TIMER_RATE_SCREEN_ON "30000"
37#define TIMER_RATE_SCREEN_OFF "500000"
Steve Kondik0e9f0192012-09-24 02:12:49 -070038
39struct cm_power_module {
40 struct power_module base;
41 pthread_mutex_t lock;
42 int boostpulse_fd;
43 int boostpulse_warned;
44};
45
Steve Kondike29bcbf2013-02-07 21:21:52 -080046static char governor[20];
47
Steve Kondik0e9f0192012-09-24 02:12:49 -070048static int sysfs_read(char *path, char *s, int num_bytes)
49{
50 char buf[80];
51 int count;
52 int ret = 0;
53 int fd = open(path, O_RDONLY);
54
55 if (fd < 0) {
56 strerror_r(errno, buf, sizeof(buf));
57 ALOGE("Error opening %s: %s\n", path, buf);
58
59 return -1;
60 }
61
62 if ((count = read(fd, s, num_bytes - 1)) < 0) {
63 strerror_r(errno, buf, sizeof(buf));
64 ALOGE("Error writing to %s: %s\n", path, buf);
65
66 ret = -1;
67 } else {
68 s[count] = '\0';
69 }
70
71 close(fd);
72
73 return ret;
74}
75
76static void sysfs_write(char *path, char *s)
77{
78 char buf[80];
79 int len;
80 int fd = open(path, O_WRONLY);
81
82 if (fd < 0) {
83 strerror_r(errno, buf, sizeof(buf));
84 ALOGE("Error opening %s: %s\n", path, buf);
85 return;
86 }
87
88 len = write(fd, s, strlen(s));
89 if (len < 0) {
90 strerror_r(errno, buf, sizeof(buf));
91 ALOGE("Error writing to %s: %s\n", path, buf);
92 }
93
94 close(fd);
95}
96
Steve Kondike29bcbf2013-02-07 21:21:52 -080097static int get_scaling_governor() {
Steve Kondik0e9f0192012-09-24 02:12:49 -070098 if (sysfs_read(SCALING_GOVERNOR_PATH, governor,
Steve Kondike29bcbf2013-02-07 21:21:52 -080099 sizeof(governor)) == -1) {
Steve Kondik0e9f0192012-09-24 02:12:49 -0700100 return -1;
101 } else {
102 // Strip newline at the end.
103 int len = strlen(governor);
104
105 len--;
106
107 while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r'))
108 governor[len--] = '\0';
109 }
110
111 return 0;
112}
113
Steve Kondike29bcbf2013-02-07 21:21:52 -0800114static void cm_power_set_interactive(struct power_module *module, int on)
115{
116 if (strncmp(governor, ONDEMAND_GOVERNOR, 8) == 0)
117 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/sampling_rate",
118 on ? SAMPLING_RATE_SCREEN_ON : SAMPLING_RATE_SCREEN_OFF);
119 else if (strncmp(governor, INTERACTIVE_GOVERNOR, 11) == 0)
120 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate",
121 on ? TIMER_RATE_SCREEN_ON : TIMER_RATE_SCREEN_OFF);
122}
123
124
125static void configure_governor()
126{
127 cm_power_set_interactive(NULL, 1);
128
129 if (strncmp(governor, ONDEMAND_GOVERNOR, 8) == 0) {
130 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/up_threshold", "90");
131 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/io_is_busy", "1");
132 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/sampling_down_factor", "4");
133 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/down_differential", "10");
Steve Kondik3977ff12013-06-29 15:02:24 -0400134 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/up_threshold_multi_core", "70");
135 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/down_differential_multi_core", "3");
136 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/optimal_freq", "918000");
137 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/sync_freq", "960000");
138 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/up_threshold_any_cpu_load", "80");
Steve Kondike29bcbf2013-02-07 21:21:52 -0800139
140 } else if (strncmp(governor, INTERACTIVE_GOVERNOR, 11) == 0) {
141 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time", "90000");
Steve Kondik25ddb282013-03-22 06:26:38 -0700142 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/io_is_busy", "1");
Steve Kondike29bcbf2013-02-07 21:21:52 -0800143 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq", "1134000");
144 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay", "30000");
145 }
146}
147
Steve Kondik0e9f0192012-09-24 02:12:49 -0700148static int boostpulse_open(struct cm_power_module *cm)
149{
150 char buf[80];
Steve Kondik0e9f0192012-09-24 02:12:49 -0700151
152 pthread_mutex_lock(&cm->lock);
153
154 if (cm->boostpulse_fd < 0) {
Steve Kondike29bcbf2013-02-07 21:21:52 -0800155 if (get_scaling_governor() < 0) {
Steve Kondik0e9f0192012-09-24 02:12:49 -0700156 ALOGE("Can't read scaling governor.");
157 cm->boostpulse_warned = 1;
158 } else {
Anurag Singhb2adeec2012-12-14 10:23:03 -0800159 if (strncmp(governor, ONDEMAND_GOVERNOR, 8) == 0)
Steve Kondik0e9f0192012-09-24 02:12:49 -0700160 cm->boostpulse_fd = open(BOOSTPULSE_ONDEMAND, O_WRONLY);
Anurag Singhb2adeec2012-12-14 10:23:03 -0800161 else if (strncmp(governor, INTERACTIVE_GOVERNOR, 11) == 0)
Steve Kondik0e9f0192012-09-24 02:12:49 -0700162 cm->boostpulse_fd = open(BOOSTPULSE_INTERACTIVE, O_WRONLY);
163
164 if (cm->boostpulse_fd < 0 && !cm->boostpulse_warned) {
165 strerror_r(errno, buf, sizeof(buf));
Steve Kondike29bcbf2013-02-07 21:21:52 -0800166 ALOGV("Error opening boostpulse: %s\n", buf);
Steve Kondik0e9f0192012-09-24 02:12:49 -0700167 cm->boostpulse_warned = 1;
Steve Kondike29bcbf2013-02-07 21:21:52 -0800168 } else if (cm->boostpulse_fd > 0) {
169 configure_governor();
Steve Kondik0e9f0192012-09-24 02:12:49 -0700170 ALOGD("Opened %s boostpulse interface", governor);
Steve Kondike29bcbf2013-02-07 21:21:52 -0800171 }
Steve Kondik0e9f0192012-09-24 02:12:49 -0700172 }
173 }
174
175 pthread_mutex_unlock(&cm->lock);
176 return cm->boostpulse_fd;
177}
178
179static void cm_power_hint(struct power_module *module, power_hint_t hint,
180 void *data)
181{
182 struct cm_power_module *cm = (struct cm_power_module *) module;
183 char buf[80];
184 int len;
185 int duration = 1;
186
187 switch (hint) {
188 case POWER_HINT_INTERACTION:
189 case POWER_HINT_CPU_BOOST:
190 if (boostpulse_open(cm) >= 0) {
191 if (data != NULL)
192 duration = (int) data;
193
194 snprintf(buf, sizeof(buf), "%d", duration);
195 len = write(cm->boostpulse_fd, buf, strlen(buf));
196
197 if (len < 0) {
198 strerror_r(errno, buf, sizeof(buf));
199 ALOGE("Error writing to boostpulse: %s\n", buf);
200
201 pthread_mutex_lock(&cm->lock);
202 close(cm->boostpulse_fd);
203 cm->boostpulse_fd = -1;
204 cm->boostpulse_warned = 0;
205 pthread_mutex_unlock(&cm->lock);
206 }
207 }
208 break;
209
210 case POWER_HINT_VSYNC:
211 break;
212
213 default:
214 break;
215 }
216}
217
Steve Kondik0e9f0192012-09-24 02:12:49 -0700218static void cm_power_init(struct power_module *module)
219{
Steve Kondike29bcbf2013-02-07 21:21:52 -0800220 get_scaling_governor();
221 configure_governor();
Steve Kondik0e9f0192012-09-24 02:12:49 -0700222}
223
224static struct hw_module_methods_t power_module_methods = {
225 .open = NULL,
226};
227
228struct cm_power_module HAL_MODULE_INFO_SYM = {
229 base: {
230 common: {
231 tag: HARDWARE_MODULE_TAG,
232 module_api_version: POWER_MODULE_API_VERSION_0_2,
233 hal_api_version: HARDWARE_HAL_API_VERSION,
234 id: POWER_HARDWARE_MODULE_ID,
235 name: "CM Power HAL",
236 author: "The CyanogenMod Project",
237 methods: &power_module_methods,
238 },
239 init: cm_power_init,
240 setInteractive: cm_power_set_interactive,
241 powerHint: cm_power_hint,
242 },
243
244 lock: PTHREAD_MUTEX_INITIALIZER,
245 boostpulse_fd: -1,
246 boostpulse_warned: 0,
247};