Home | History | Annotate | Download | only in power
      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 #include <errno.h>
     17 #include <string.h>
     18 #include <sys/types.h>
     19 #include <sys/stat.h>
     20 #include <fcntl.h>
     21 
     22 #define LOG_TAG "Tuna PowerHAL"
     23 #include <utils/Log.h>
     24 
     25 #include <hardware/hardware.h>
     26 #include <hardware/power.h>
     27 
     28 #define BOOSTPULSE_PATH "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
     29 
     30 struct tuna_power_module {
     31     struct power_module base;
     32     pthread_mutex_t lock;
     33     int boostpulse_fd;
     34     int boostpulse_warned;
     35 };
     36 
     37 static void sysfs_write(char *path, char *s)
     38 {
     39     char buf[80];
     40     int len;
     41     int fd = open(path, O_WRONLY);
     42 
     43     if (fd < 0) {
     44         strerror_r(errno, buf, sizeof(buf));
     45         ALOGE("Error opening %s: %s\n", path, buf);
     46         return;
     47     }
     48 
     49     len = write(fd, s, strlen(s));
     50     if (len < 0) {
     51         strerror_r(errno, buf, sizeof(buf));
     52         ALOGE("Error writing to %s: %s\n", path, buf);
     53     }
     54 
     55     close(fd);
     56 }
     57 
     58 static void tuna_power_init(struct power_module *module)
     59 {
     60     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate",
     61                 "20000");
     62     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time",
     63                 "60000");
     64     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq",
     65                 "700000");
     66     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/target_loads",
     67                 "70 920000:80 1200000:99");
     68     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load",
     69                 "99");
     70     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay",
     71                 "80000");
     72 }
     73 
     74 static int boostpulse_open(struct tuna_power_module *tuna)
     75 {
     76     char buf[80];
     77 
     78     pthread_mutex_lock(&tuna->lock);
     79 
     80     if (tuna->boostpulse_fd < 0) {
     81         tuna->boostpulse_fd = open(BOOSTPULSE_PATH, O_WRONLY);
     82 
     83         if (tuna->boostpulse_fd < 0) {
     84             if (!tuna->boostpulse_warned) {
     85                 strerror_r(errno, buf, sizeof(buf));
     86                 ALOGE("Error opening %s: %s\n", BOOSTPULSE_PATH, buf);
     87                 tuna->boostpulse_warned = 1;
     88             }
     89         }
     90     }
     91 
     92     pthread_mutex_unlock(&tuna->lock);
     93     return tuna->boostpulse_fd;
     94 }
     95 
     96 static void tuna_power_set_interactive(struct power_module *module, int on)
     97 {
     98     /*
     99      * Lower maximum frequency when screen is off.  CPU 0 and 1 share a
    100      * cpufreq policy.
    101      */
    102 
    103     sysfs_write("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq",
    104                 on ? "1200000" : "700000");
    105 }
    106 
    107 static void tuna_power_hint(struct power_module *module, power_hint_t hint,
    108                             void *data)
    109 {
    110     struct tuna_power_module *tuna = (struct tuna_power_module *) module;
    111     char buf[80];
    112     int len;
    113 
    114     switch (hint) {
    115     case POWER_HINT_INTERACTION:
    116         if (boostpulse_open(tuna) >= 0) {
    117 	    len = write(tuna->boostpulse_fd, "1", 1);
    118 
    119 	    if (len < 0) {
    120 	        strerror_r(errno, buf, sizeof(buf));
    121 		ALOGE("Error writing to %s: %s\n", BOOSTPULSE_PATH, buf);
    122 	    }
    123 	}
    124         break;
    125 
    126     case POWER_HINT_VSYNC:
    127         break;
    128 
    129     default:
    130         break;
    131     }
    132 }
    133 
    134 static struct hw_module_methods_t power_module_methods = {
    135     .open = NULL,
    136 };
    137 
    138 struct tuna_power_module HAL_MODULE_INFO_SYM = {
    139     base: {
    140         common: {
    141             tag: HARDWARE_MODULE_TAG,
    142             module_api_version: POWER_MODULE_API_VERSION_0_2,
    143             hal_api_version: HARDWARE_HAL_API_VERSION,
    144             id: POWER_HARDWARE_MODULE_ID,
    145             name: "Tuna Power HAL",
    146             author: "The Android Open Source Project",
    147             methods: &power_module_methods,
    148         },
    149 
    150        init: tuna_power_init,
    151        setInteractive: tuna_power_set_interactive,
    152        powerHint: tuna_power_hint,
    153     },
    154 
    155     lock: PTHREAD_MUTEX_INITIALIZER,
    156     boostpulse_fd: -1,
    157     boostpulse_warned: 0,
    158 };
    159