Home | History | Annotate | Download | only in power
      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 #include <cutils/properties.h>
     27 //#define LOG_NDEBUG 0
     28 
     29 #define LOG_TAG "FlounderPowerHAL"
     30 #include <utils/Log.h>
     31 
     32 #include <hardware/hardware.h>
     33 #include <hardware/power.h>
     34 
     35 #define BOOSTPULSE_PATH "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
     36 #define CPU_MAX_FREQ_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
     37 #define FACEDOWN_PATH "/sys/class/htc_sensorhub/sensor_hub/facedown_enabled"
     38 #define TOUCH_SYNA_INTERACTIVE_PATH "/sys/devices/platform/spi-tegra114.2/spi_master/spi2/spi2.0/input/input0/interactive"
     39 #define WAKE_GESTURE_PATH "/sys/devices/platform/spi-tegra114.2/spi_master/spi2/spi2.0/input/input0/wake_gesture"
     40 #define GPU_BOOST_PATH "/dev/constraint_gpu_freq"
     41 #define IO_IS_BUSY_PATH "/sys/devices/system/cpu/cpufreq/interactive/io_is_busy"
     42 #define LOW_POWER_MAX_FREQ "1020000"
     43 #define NORMAL_MAX_FREQ "2901000"
     44 #define GPU_FREQ_CONSTRAINT "852000 852000 -1 2000"
     45 #define SVELTE_PROP "ro.boot.svelte"
     46 #define SVELTE_MAX_FREQ_PROP "ro.config.svelte.max_cpu_freq"
     47 #define SVELTE_LOW_POWER_MAX_FREQ_PROP "ro.config.svelte.low_power_max_cpu_freq"
     48 
     49 struct flounder_power_module {
     50     struct power_module base;
     51     pthread_mutex_t lock;
     52     int boostpulse_fd;
     53     int boostpulse_warned;
     54 };
     55 
     56 static bool low_power_mode = false;
     57 
     58 static char *max_cpu_freq = NORMAL_MAX_FREQ;
     59 static char *low_power_max_cpu_freq = LOW_POWER_MAX_FREQ;
     60 
     61 static void sysfs_write(const char *path, char *s)
     62 {
     63     char buf[80];
     64     int len;
     65     int fd = open(path, O_WRONLY);
     66 
     67     if (fd < 0) {
     68         strerror_r(errno, buf, sizeof(buf));
     69         ALOGE("Error opening %s: %s\n", path, buf);
     70         return;
     71     }
     72 
     73     len = write(fd, s, strlen(s));
     74     if (len < 0) {
     75         strerror_r(errno, buf, sizeof(buf));
     76         ALOGE("Error writing to %s: %s\n", path, buf);
     77     }
     78 
     79     close(fd);
     80 }
     81 
     82 static void calculate_max_cpu_freq() {
     83     int32_t is_svelte = property_get_int32(SVELTE_PROP, 0);
     84 
     85     if (is_svelte) {
     86         char prop_buffer[PROPERTY_VALUE_MAX];
     87         int len = property_get(SVELTE_MAX_FREQ_PROP, prop_buffer, LOW_POWER_MAX_FREQ);
     88         max_cpu_freq = strndup(prop_buffer, len);
     89         len = property_get(SVELTE_LOW_POWER_MAX_FREQ_PROP, prop_buffer, LOW_POWER_MAX_FREQ);
     90         low_power_max_cpu_freq = strndup(prop_buffer, len);
     91     }
     92 }
     93 
     94 static void power_init(struct power_module __unused *module)
     95 {
     96     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate",
     97                 "20000");
     98     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_slack",
     99                 "20000");
    100     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time",
    101                 "80000");
    102     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq",
    103                 "1530000");
    104     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load",
    105                 "99");
    106     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/target_loads",
    107                 "65 228000:75 624000:85");
    108     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay",
    109                 "20000");
    110     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration",
    111                 "1000000");
    112     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/io_is_busy", "0");
    113 
    114     calculate_max_cpu_freq();
    115 }
    116 
    117 static void power_set_interactive(struct power_module __unused *module, int on)
    118 {
    119     ALOGV("power_set_interactive: %d\n", on);
    120 
    121     /*
    122      * Lower maximum frequency when screen is off.
    123      */
    124     sysfs_write(CPU_MAX_FREQ_PATH,
    125                 (!on || low_power_mode) ? low_power_max_cpu_freq : max_cpu_freq);
    126     sysfs_write(IO_IS_BUSY_PATH, on ? "1" : "0");
    127     sysfs_write(FACEDOWN_PATH, on ? "0" : "1");
    128     sysfs_write(TOUCH_SYNA_INTERACTIVE_PATH, on ? "1" : "0");
    129     ALOGV("power_set_interactive: %d done\n", on);
    130 }
    131 
    132 static int boostpulse_open(struct flounder_power_module *flounder)
    133 {
    134     char buf[80];
    135     int len;
    136     static int gpu_boost_fd = -1;
    137 
    138     pthread_mutex_lock(&flounder->lock);
    139 
    140     if (flounder->boostpulse_fd < 0) {
    141         flounder->boostpulse_fd = open(BOOSTPULSE_PATH, O_WRONLY);
    142 
    143         if (flounder->boostpulse_fd < 0) {
    144             if (!flounder->boostpulse_warned) {
    145                 strerror_r(errno, buf, sizeof(buf));
    146                 ALOGE("Error opening %s: %s\n", BOOSTPULSE_PATH, buf);
    147                 flounder->boostpulse_warned = 1;
    148             }
    149         }
    150     }
    151     {
    152         if ( gpu_boost_fd == -1 )
    153             gpu_boost_fd = open(GPU_BOOST_PATH, O_WRONLY);
    154 
    155         if (gpu_boost_fd < 0) {
    156             strerror_r(errno, buf, sizeof(buf));
    157             ALOGE("Error opening %s: %s\n", GPU_BOOST_PATH, buf);
    158         } else {
    159             len = write(gpu_boost_fd, GPU_FREQ_CONSTRAINT,
    160                         strlen(GPU_FREQ_CONSTRAINT));
    161             if (len < 0) {
    162                 strerror_r(errno, buf, sizeof(buf));
    163                 ALOGE("Error writing to %s: %s\n", GPU_BOOST_PATH, buf);
    164             }
    165         }
    166     }
    167 
    168     pthread_mutex_unlock(&flounder->lock);
    169     return flounder->boostpulse_fd;
    170 }
    171 
    172 static void set_feature(struct power_module *module, feature_t feature, int state)
    173 {
    174     struct flounder_power_module *flounder =
    175             (struct flounder_power_module *) module;
    176     switch (feature) {
    177     case POWER_FEATURE_DOUBLE_TAP_TO_WAKE:
    178         pthread_mutex_lock(&flounder->lock);
    179         sysfs_write(WAKE_GESTURE_PATH, state ? "1" : "0");
    180         pthread_mutex_unlock(&flounder->lock);
    181         break;
    182     default:
    183         ALOGW("Error setting the feature, it doesn't exist %d\n", feature);
    184         break;
    185     }
    186 }
    187 
    188 static void flounder_power_hint(struct power_module *module, power_hint_t hint,
    189                                 void *data)
    190 {
    191     struct flounder_power_module *flounder =
    192             (struct flounder_power_module *) module;
    193     char buf[80];
    194     int len;
    195 
    196     switch (hint) {
    197      case POWER_HINT_INTERACTION:
    198         if (boostpulse_open(flounder) >= 0) {
    199             len = write(flounder->boostpulse_fd, "1", 1);
    200 
    201             if (len < 0) {
    202                 strerror_r(errno, buf, sizeof(buf));
    203                 ALOGE("Error writing to %s: %s\n", BOOSTPULSE_PATH, buf);
    204             }
    205         }
    206 
    207         break;
    208 
    209    case POWER_HINT_VSYNC:
    210         break;
    211 
    212     case POWER_HINT_LOW_POWER:
    213         pthread_mutex_lock(&flounder->lock);
    214         if (data) {
    215             sysfs_write(CPU_MAX_FREQ_PATH, low_power_max_cpu_freq);
    216         } else {
    217             sysfs_write(CPU_MAX_FREQ_PATH, max_cpu_freq);
    218         }
    219         low_power_mode = data;
    220         pthread_mutex_unlock(&flounder->lock);
    221         break;
    222 
    223     default:
    224             break;
    225     }
    226 }
    227 
    228 static struct hw_module_methods_t power_module_methods = {
    229     .open = NULL,
    230 };
    231 
    232 struct flounder_power_module HAL_MODULE_INFO_SYM = {
    233     base: {
    234         common: {
    235             tag: HARDWARE_MODULE_TAG,
    236             module_api_version: POWER_MODULE_API_VERSION_0_2,
    237             hal_api_version: HARDWARE_HAL_API_VERSION,
    238             id: POWER_HARDWARE_MODULE_ID,
    239             name: "Flounder Power HAL",
    240             author: "The Android Open Source Project",
    241             methods: &power_module_methods,
    242         },
    243 
    244         init: power_init,
    245         setInteractive: power_set_interactive,
    246         powerHint: flounder_power_hint,
    247         setFeature: set_feature,
    248     },
    249 
    250     lock: PTHREAD_MUTEX_INITIALIZER,
    251     boostpulse_fd: -1,
    252     boostpulse_warned: 0,
    253 };
    254 
    255