• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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