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 34struct 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 42static 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 63static 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); 94done: 95 closedir(d); 96} 97 98static 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 * cpufreq interactive governor: timer 20ms, min sample 40ms, 105 * hispeed 1G at load 90%, 140ms load burst needed to move above hispeed. 106 */ 107 108 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate", 109 "20000"); 110 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time", 111 "40000"); 112 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq", 113 "1000000"); 114 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load", 115 "90"); 116 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay", 117 "140000"); 118 119 init_touchscreen_power_path(manta); 120} 121 122static void power_set_interactive(struct power_module *module, int on) 123{ 124 struct manta_power_module *manta = (struct manta_power_module *) module; 125 char buf[80]; 126 int ret; 127 128 ALOGV("power_set_interactive: %d\n", on); 129 130 /* 131 * Lower maximum frequency when screen is off. CPU 0 and 1 share a 132 * cpufreq policy. 133 */ 134 sysfs_write("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", 135 on ? "1700000" : "800000"); 136 137 sysfs_write(manta->touchscreen_power_path, on ? "Y" : "N"); 138 139 ALOGV("power_set_interactive: %d done\n", on); 140} 141 142static int boostpulse_open(struct manta_power_module *manta) 143{ 144 char buf[80]; 145 146 pthread_mutex_lock(&manta->lock); 147 148 if (manta->boostpulse_fd < 0) { 149 manta->boostpulse_fd = open(BOOSTPULSE_PATH, O_WRONLY); 150 151 if (manta->boostpulse_fd < 0) { 152 if (!manta->boostpulse_warned) { 153 strerror_r(errno, buf, sizeof(buf)); 154 ALOGE("Error opening %s: %s\n", BOOSTPULSE_PATH, buf); 155 manta->boostpulse_warned = 1; 156 } 157 } 158 } 159 160 pthread_mutex_unlock(&manta->lock); 161 return manta->boostpulse_fd; 162} 163 164static void manta_power_hint(struct power_module *module, power_hint_t hint, 165 void *data) 166{ 167 struct manta_power_module *manta = (struct manta_power_module *) module; 168 char buf[80]; 169 int len; 170 171 switch (hint) { 172 case POWER_HINT_INTERACTION: 173 if (boostpulse_open(manta) >= 0) { 174 len = write(manta->boostpulse_fd, "1", 1); 175 176 if (len < 0) { 177 strerror_r(errno, buf, sizeof(buf)); 178 ALOGE("Error writing to %s: %s\n", BOOSTPULSE_PATH, buf); 179 } 180 } 181 182 break; 183 184 case POWER_HINT_VSYNC: 185 break; 186 187 default: 188 break; 189 } 190} 191 192static struct hw_module_methods_t power_module_methods = { 193 .open = NULL, 194}; 195 196struct manta_power_module HAL_MODULE_INFO_SYM = { 197 base: { 198 common: { 199 tag: HARDWARE_MODULE_TAG, 200 module_api_version: POWER_MODULE_API_VERSION_0_2, 201 hal_api_version: HARDWARE_HAL_API_VERSION, 202 id: POWER_HARDWARE_MODULE_ID, 203 name: "Manta Power HAL", 204 author: "The Android Open Source Project", 205 methods: &power_module_methods, 206 }, 207 208 init: power_init, 209 setInteractive: power_set_interactive, 210 powerHint: manta_power_hint, 211 }, 212 213 lock: PTHREAD_MUTEX_INITIALIZER, 214 boostpulse_fd: -1, 215 boostpulse_warned: 0, 216}; 217 218