1 /*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <dirent.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <stdbool.h>
26 //#define LOG_NDEBUG 0
27
28 #define LOG_TAG "FlounderPowerHAL"
29 #include <utils/Log.h>
30
31 #include <hardware/hardware.h>
32 #include <hardware/power.h>
33
34 #define BOOSTPULSE_PATH "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
35 #define CPU_MAX_FREQ_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
36 #define FACEDOWN_PATH "/sys/class/htc_sensorhub/sensor_hub/facedown_enabled"
37 #define TOUCH_SYNA_INTERACTIVE_PATH "/sys/devices/platform/spi-tegra114.2/spi_master/spi2/spi2.0/input/input0/interactive"
38 #define GPU_BOOST_PATH "/dev/constraint_gpu_freq"
39 #define IO_IS_BUSY_PATH "/sys/devices/system/cpu/cpufreq/interactive/io_is_busy"
40 #define LOW_POWER_MAX_FREQ "1020000"
41 #define NORMAL_MAX_FREQ "2901000"
42 #define GPU_FREQ_CONSTRAINT "852000 852000 -1 2000"
43
44 struct flounder_power_module {
45 struct power_module base;
46 pthread_mutex_t lock;
47 int boostpulse_fd;
48 int boostpulse_warned;
49 };
50
51 static bool low_power_mode = false;
52
sysfs_write(const char * path,char * s)53 static void sysfs_write(const char *path, char *s)
54 {
55 char buf[80];
56 int len;
57 int fd = open(path, O_WRONLY);
58
59 if (fd < 0) {
60 strerror_r(errno, buf, sizeof(buf));
61 ALOGE("Error opening %s: %s\n", path, buf);
62 return;
63 }
64
65 len = write(fd, s, strlen(s));
66 if (len < 0) {
67 strerror_r(errno, buf, sizeof(buf));
68 ALOGE("Error writing to %s: %s\n", path, buf);
69 }
70
71 close(fd);
72 }
73
power_init(struct power_module __unused * module)74 static void power_init(struct power_module __unused *module)
75 {
76 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate",
77 "20000");
78 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_slack",
79 "20000");
80 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time",
81 "80000");
82 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq",
83 "1530000");
84 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load",
85 "99");
86 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/target_loads",
87 "65 228000:75 624000:85");
88 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay",
89 "20000");
90 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration",
91 "1000000");
92 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/io_is_busy", "0");
93 }
94
power_set_interactive(struct power_module __unused * module,int on)95 static void power_set_interactive(struct power_module __unused *module, int on)
96 {
97 ALOGV("power_set_interactive: %d\n", on);
98
99 /*
100 * Lower maximum frequency when screen is off.
101 */
102 sysfs_write(CPU_MAX_FREQ_PATH,
103 (!on || low_power_mode) ? LOW_POWER_MAX_FREQ : NORMAL_MAX_FREQ);
104 sysfs_write(IO_IS_BUSY_PATH, on ? "1" : "0");
105 sysfs_write(FACEDOWN_PATH, on ? "0" : "1");
106 sysfs_write(TOUCH_SYNA_INTERACTIVE_PATH, on ? "1" : "0");
107 ALOGV("power_set_interactive: %d done\n", on);
108 }
109
boostpulse_open(struct flounder_power_module * flounder)110 static int boostpulse_open(struct flounder_power_module *flounder)
111 {
112 char buf[80];
113 int len;
114 static int gpu_boost_fd = -1;
115
116 pthread_mutex_lock(&flounder->lock);
117
118 if (flounder->boostpulse_fd < 0) {
119 flounder->boostpulse_fd = open(BOOSTPULSE_PATH, O_WRONLY);
120
121 if (flounder->boostpulse_fd < 0) {
122 if (!flounder->boostpulse_warned) {
123 strerror_r(errno, buf, sizeof(buf));
124 ALOGE("Error opening %s: %s\n", BOOSTPULSE_PATH, buf);
125 flounder->boostpulse_warned = 1;
126 }
127 }
128 }
129 {
130 if ( gpu_boost_fd == -1 )
131 gpu_boost_fd = open(GPU_BOOST_PATH, O_WRONLY);
132
133 if (gpu_boost_fd < 0) {
134 strerror_r(errno, buf, sizeof(buf));
135 ALOGE("Error opening %s: %s\n", GPU_BOOST_PATH, buf);
136 } else {
137 len = write(gpu_boost_fd, GPU_FREQ_CONSTRAINT,
138 strlen(GPU_FREQ_CONSTRAINT));
139 if (len < 0) {
140 strerror_r(errno, buf, sizeof(buf));
141 ALOGE("Error writing to %s: %s\n", GPU_BOOST_PATH, buf);
142 }
143 }
144 }
145
146 pthread_mutex_unlock(&flounder->lock);
147 return flounder->boostpulse_fd;
148 }
149
flounder_power_hint(struct power_module * module,power_hint_t hint,void * data)150 static void flounder_power_hint(struct power_module *module, power_hint_t hint,
151 void *data)
152 {
153 struct flounder_power_module *flounder =
154 (struct flounder_power_module *) module;
155 char buf[80];
156 int len;
157
158 switch (hint) {
159 case POWER_HINT_INTERACTION:
160 if (boostpulse_open(flounder) >= 0) {
161 len = write(flounder->boostpulse_fd, "1", 1);
162
163 if (len < 0) {
164 strerror_r(errno, buf, sizeof(buf));
165 ALOGE("Error writing to %s: %s\n", BOOSTPULSE_PATH, buf);
166 }
167 }
168
169 break;
170
171 case POWER_HINT_VSYNC:
172 break;
173
174 case POWER_HINT_LOW_POWER:
175 pthread_mutex_lock(&flounder->lock);
176 if (data) {
177 sysfs_write(CPU_MAX_FREQ_PATH, LOW_POWER_MAX_FREQ);
178 } else {
179 sysfs_write(CPU_MAX_FREQ_PATH, NORMAL_MAX_FREQ);
180 }
181 low_power_mode = data;
182 pthread_mutex_unlock(&flounder->lock);
183 break;
184
185 default:
186 break;
187 }
188 }
189
190 static struct hw_module_methods_t power_module_methods = {
191 .open = NULL,
192 };
193
194 struct flounder_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: "Flounder Power HAL",
202 author: "The Android Open Source Project",
203 methods: &power_module_methods,
204 },
205
206 init: power_init,
207 setInteractive: power_set_interactive,
208 powerHint: flounder_power_hint,
209 },
210
211 lock: PTHREAD_MUTEX_INITIALIZER,
212 boostpulse_fd: -1,
213 boostpulse_warned: 0,
214 };
215
216