1 /* 2 * Copyright (C) 2012 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 //#define LOG_NDEBUG 0 25 26 #define LOG_TAG "MantaPowerHAL" 27 #include <utils/Log.h> 28 29 #include <hardware/hardware.h> 30 #include <hardware/power.h> 31 32 #define BOOSTPULSE_PATH "/sys/devices/system/cpu/cpufreq/interactive/boostpulse" 33 34 struct manta_power_module { 35 struct power_module base; 36 pthread_mutex_t lock; 37 int boostpulse_fd; 38 int boostpulse_warned; 39 const char *touchscreen_power_path; 40 }; 41 42 static void sysfs_write(const char *path, char *s) 43 { 44 char buf[80]; 45 int len; 46 int fd = open(path, O_WRONLY); 47 48 if (fd < 0) { 49 strerror_r(errno, buf, sizeof(buf)); 50 ALOGE("Error opening %s: %s\n", path, buf); 51 return; 52 } 53 54 len = write(fd, s, strlen(s)); 55 if (len < 0) { 56 strerror_r(errno, buf, sizeof(buf)); 57 ALOGE("Error writing to %s: %s\n", path, buf); 58 } 59 60 close(fd); 61 } 62 63 static void init_touchscreen_power_path(struct manta_power_module *manta) 64 { 65 char buf[80]; 66 const char dir[] = "/sys/devices/platform/s3c2440-i2c.3/i2c-3/3-004a/input"; 67 const char filename[] = "enabled"; 68 DIR *d; 69 struct dirent *de; 70 char *path; 71 int pathsize; 72 73 d = opendir(dir); 74 if (d == NULL) { 75 strerror_r(errno, buf, sizeof(buf)); 76 ALOGE("Error opening directory %s: %s\n", dir, buf); 77 return; 78 } 79 while ((de = readdir(d)) != NULL) { 80 if (strncmp("input", de->d_name, 5) == 0) { 81 pathsize = strlen(dir) + strlen(de->d_name) + sizeof(filename) + 2; 82 path = malloc(pathsize); 83 if (path == NULL) { 84 strerror_r(errno, buf, sizeof(buf)); 85 ALOGE("Out of memory: %s\n", buf); 86 return; 87 } 88 snprintf(path, pathsize, "%s/%s/%s", dir, de->d_name, filename); 89 manta->touchscreen_power_path = path; 90 goto done; 91 } 92 } 93 ALOGE("Error failed to find input dir in %s\n", dir); 94 done: 95 closedir(d); 96 } 97 98 static void power_init(struct power_module *module) 99 { 100 struct manta_power_module *manta = (struct manta_power_module *) module; 101 struct dirent **namelist; 102 int n; 103 104 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate", 105 "20000"); 106 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_slack", 107 "20000"); 108 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time", 109 "40000"); 110 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq", 111 "1000000"); 112 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load", 113 "99"); 114 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/target_loads", "70 1200000:70 1300000:75 1400000:80 1500000:99"); 115 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay", 116 "80000"); 117 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration", 118 "500000"); 119 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/io_is_busy", "1"); 120 121 init_touchscreen_power_path(manta); 122 } 123 124 static void power_set_interactive(struct power_module *module, int on) 125 { 126 struct manta_power_module *manta = (struct manta_power_module *) module; 127 char buf[80]; 128 int ret; 129 130 ALOGV("power_set_interactive: %d\n", on); 131 132 /* 133 * Lower maximum frequency when screen is off. CPU 0 and 1 share a 134 * cpufreq policy. 135 */ 136 sysfs_write("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", 137 on ? "1700000" : "800000"); 138 139 sysfs_write(manta->touchscreen_power_path, on ? "Y" : "N"); 140 141 ALOGV("power_set_interactive: %d done\n", on); 142 } 143 144 static int boostpulse_open(struct manta_power_module *manta) 145 { 146 char buf[80]; 147 148 pthread_mutex_lock(&manta->lock); 149 150 if (manta->boostpulse_fd < 0) { 151 manta->boostpulse_fd = open(BOOSTPULSE_PATH, O_WRONLY); 152 153 if (manta->boostpulse_fd < 0) { 154 if (!manta->boostpulse_warned) { 155 strerror_r(errno, buf, sizeof(buf)); 156 ALOGE("Error opening %s: %s\n", BOOSTPULSE_PATH, buf); 157 manta->boostpulse_warned = 1; 158 } 159 } 160 } 161 162 pthread_mutex_unlock(&manta->lock); 163 return manta->boostpulse_fd; 164 } 165 166 static void manta_power_hint(struct power_module *module, power_hint_t hint, 167 void *data) 168 { 169 struct manta_power_module *manta = (struct manta_power_module *) module; 170 char buf[80]; 171 int len; 172 173 switch (hint) { 174 case POWER_HINT_INTERACTION: 175 if (boostpulse_open(manta) >= 0) { 176 len = write(manta->boostpulse_fd, "1", 1); 177 178 if (len < 0) { 179 strerror_r(errno, buf, sizeof(buf)); 180 ALOGE("Error writing to %s: %s\n", BOOSTPULSE_PATH, buf); 181 } 182 } 183 184 break; 185 186 case POWER_HINT_VSYNC: 187 break; 188 189 default: 190 break; 191 } 192 } 193 194 static struct hw_module_methods_t power_module_methods = { 195 .open = NULL, 196 }; 197 198 struct manta_power_module HAL_MODULE_INFO_SYM = { 199 base: { 200 common: { 201 tag: HARDWARE_MODULE_TAG, 202 module_api_version: POWER_MODULE_API_VERSION_0_2, 203 hal_api_version: HARDWARE_HAL_API_VERSION, 204 id: POWER_HARDWARE_MODULE_ID, 205 name: "Manta Power HAL", 206 author: "The Android Open Source Project", 207 methods: &power_module_methods, 208 }, 209 210 init: power_init, 211 setInteractive: power_set_interactive, 212 powerHint: manta_power_hint, 213 }, 214 215 lock: PTHREAD_MUTEX_INITIALIZER, 216 boostpulse_fd: -1, 217 boostpulse_warned: 0, 218 }; 219 220