blob: 887faf6f3b2132c330a95212d78dd505e0de7f10 [file] [log] [blame]
Christopher N. Hessede5e3c62015-12-21 21:28:23 +01001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 * Copyright (C) 2014 The CyanogenMod Project
4 * Copyright (C) 2014-2015 Andreas Schneider <asn@cryptomilk.org>
Christopher N. Hessef05f9022017-01-16 22:49:06 +01005 * Copyright (C) 2014-2017 Christopher N. Hesse <raymanfx@gmail.com>
Christopher N. Hessede5e3c62015-12-21 21:28:23 +01006 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
Christopher N. Hesse3360b092016-07-11 15:48:35 +020020#include <ctype.h>
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010021#include <dirent.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <malloc.h>
25#include <stdbool.h>
Christopher N. Hessee1434192016-11-18 18:56:17 +010026#include <stdlib.h>
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010027#include <string.h>
28#include <unistd.h>
29
30#include <sys/types.h>
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010031
32#define LOG_TAG "SamsungPowerHAL"
33/* #define LOG_NDEBUG 0 */
34#include <utils/Log.h>
35
36#include <hardware/hardware.h>
37#include <hardware/power.h>
Christopher N. Hesse12263502016-12-07 12:18:20 +010038#include <liblights/samsung_lights_helper.h>
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010039
Christopher N. Hesse4139d852016-12-07 12:21:44 +010040#include "samsung_power.h"
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010041
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +020042#define BOOST_PATH "/boost"
43#define BOOSTPULSE_PATH "/boostpulse"
Christopher N. Hesse81f714d2017-03-12 17:11:04 +010044
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +020045#define IO_IS_BUSY_PATH "/io_is_busy"
46#define HISPEED_FREQ_PATH "/hispeed_freq"
Christopher N. Hesse81f714d2017-03-12 17:11:04 +010047
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +020048#define MAX_FREQ_PATH "/cpufreq/scaling_max_freq"
49
50#define CLUSTER_COUNT ARRAY_SIZE(CPU_SYSFS_PATHS)
51#define PARAM_MAXLEN 10
52
53#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])
Christopher N. Hessed9106e92017-03-04 01:05:14 +010054
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010055struct samsung_power_module {
56 struct power_module base;
57 pthread_mutex_t lock;
Christopher N. Hessefb5669e2017-07-08 12:44:39 +020058 int boost_fd;
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010059 int boostpulse_fd;
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +020060 char hispeed_freqs[CLUSTER_COUNT][PARAM_MAXLEN];
61 char max_freqs[CLUSTER_COUNT][PARAM_MAXLEN];
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010062 char* touchscreen_power_path;
63 char* touchkey_power_path;
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010064};
65
Andreas Schneiderf15d7f42016-02-03 10:43:47 +010066enum power_profile_e {
67 PROFILE_POWER_SAVE = 0,
68 PROFILE_BALANCED,
Christopher N. Hesse58f2ca02017-01-17 00:01:15 +010069 PROFILE_HIGH_PERFORMANCE,
70 PROFILE_MAX
Andreas Schneiderf15d7f42016-02-03 10:43:47 +010071};
Christopher N. Hesseccd970d2017-01-25 22:41:05 +010072
Andreas Schneiderf15d7f42016-02-03 10:43:47 +010073static enum power_profile_e current_power_profile = PROFILE_BALANCED;
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010074
75/**********************************************************
76 *** HELPER FUNCTIONS
77 **********************************************************/
78
79static int sysfs_read(char *path, char *s, int num_bytes)
80{
81 char errno_str[64];
82 int len;
83 int ret = 0;
84 int fd;
85
86 fd = open(path, O_RDONLY);
87 if (fd < 0) {
88 strerror_r(errno, errno_str, sizeof(errno_str));
Christopher N. Hesse354f7132017-03-04 01:06:22 +010089 ALOGE("Error opening %s: %s", path, errno_str);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010090
91 return -1;
92 }
93
94 len = read(fd, s, num_bytes - 1);
95 if (len < 0) {
96 strerror_r(errno, errno_str, sizeof(errno_str));
Christopher N. Hesse354f7132017-03-04 01:06:22 +010097 ALOGE("Error reading from %s: %s", path, errno_str);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +010098
99 ret = -1;
100 } else {
Christopher N. Hesse0da5fbf2017-07-08 13:56:25 +0200101 // do not store newlines, but terminate the string instead
102 if (s[len-1] == '\n') {
103 s[len-1] = '\0';
104 } else {
105 s[len] = '\0';
106 }
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100107 }
108
109 close(fd);
110
111 return ret;
112}
113
114static void sysfs_write(const char *path, char *s)
115{
116 char errno_str[64];
117 int len;
118 int fd;
119
120 fd = open(path, O_WRONLY);
121 if (fd < 0) {
122 strerror_r(errno, errno_str, sizeof(errno_str));
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100123 ALOGE("Error opening %s: %s", path, errno_str);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100124 return;
125 }
126
127 len = write(fd, s, strlen(s));
128 if (len < 0) {
129 strerror_r(errno, errno_str, sizeof(errno_str));
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100130 ALOGE("Error writing to %s: %s", path, errno_str);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100131 }
132
133 close(fd);
134}
135
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +0200136static void cpu_sysfs_read(const char *param, char s[CLUSTER_COUNT][PARAM_MAXLEN])
137{
138 char path[PATH_MAX];
139
140 for (unsigned int i = 0; i < ARRAY_SIZE(CPU_SYSFS_PATHS); i++) {
141 sprintf(path, "%s%s", CPU_SYSFS_PATHS[i], param);
142 sysfs_read(path, s[i], PARAM_MAXLEN);
143 }
144}
145
146static void cpu_sysfs_write(const char *param, char s[CLUSTER_COUNT][PARAM_MAXLEN])
147{
148 char path[PATH_MAX];
149
150 for (unsigned int i = 0; i < ARRAY_SIZE(CPU_SYSFS_PATHS); i++) {
151 sprintf(path, "%s%s", CPU_SYSFS_PATHS[i], param);
152 sysfs_write(path, s[i]);
153 }
154}
155
156static void cpu_interactive_read(const char *param, char s[CLUSTER_COUNT][PARAM_MAXLEN])
157{
158 char path[PATH_MAX];
159
160 for (unsigned int i = 0; i < ARRAY_SIZE(CPU_INTERACTIVE_PATHS); i++) {
161 sprintf(path, "%s%s", CPU_INTERACTIVE_PATHS[i], param);
162 sysfs_read(path, s[i], PARAM_MAXLEN);
163 }
164}
165
166static void cpu_interactive_write(const char *param, char s[CLUSTER_COUNT][PARAM_MAXLEN])
167{
168 char path[PATH_MAX];
169
170 for (unsigned int i = 0; i < ARRAY_SIZE(CPU_INTERACTIVE_PATHS); i++) {
171 sprintf(path, "%s%s", CPU_INTERACTIVE_PATHS[i], param);
172 sysfs_write(path, s[i]);
173 }
174}
175
Christopher N. Hessefb5669e2017-07-08 12:44:39 +0200176static void send_boost(int boost_fd, int32_t duration_us)
Christopher N. Hesse5fada9b2017-01-16 23:39:48 +0100177{
Christopher N. Hessefb5669e2017-07-08 12:44:39 +0200178 int len;
Christopher N. Hesse5fada9b2017-01-16 23:39:48 +0100179
Christopher N. Hessefb5669e2017-07-08 12:44:39 +0200180 if (boost_fd < 0) {
Christopher N. Hesse5fada9b2017-01-16 23:39:48 +0100181 return;
182 }
183
Christopher N. Hessefb5669e2017-07-08 12:44:39 +0200184 len = write(boost_fd, "1", 1);
185 if (len < 0) {
186 ALOGE("Error writing to %s%s: %s", CPU_INTERACTIVE_PATHS[0], BOOST_PATH, strerror(errno));
187 return;
188 }
189
Christopher N. Hesse5fada9b2017-01-16 23:39:48 +0100190 usleep(duration_us);
Christopher N. Hessefb5669e2017-07-08 12:44:39 +0200191 len = write(boost_fd, "0", 1);
Christopher N. Hessef21fbdb2017-03-04 01:41:58 +0100192}
193
194static void send_boostpulse(int boostpulse_fd)
195{
196 int len;
197
198 if (boostpulse_fd < 0) {
199 return;
200 }
201
202 len = write(boostpulse_fd, "1", 1);
203 if (len < 0) {
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +0200204 ALOGE("Error writing to %s%s: %s", CPU_INTERACTIVE_PATHS[0], BOOSTPULSE_PATH,
205 strerror(errno));
Christopher N. Hessef21fbdb2017-03-04 01:41:58 +0100206 }
207}
208
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100209/**********************************************************
210 *** POWER FUNCTIONS
211 **********************************************************/
212
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100213static void set_power_profile(struct samsung_power_module *samsung_pwr,
Christopher N. Hesse58f2ca02017-01-17 00:01:15 +0100214 int profile)
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100215{
Christopher N. Hesse58f2ca02017-01-17 00:01:15 +0100216 if (profile < 0 || profile >= PROFILE_MAX) {
217 return;
218 }
219
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100220 if (current_power_profile == profile) {
221 return;
222 }
223
224 ALOGV("%s: profile=%d", __func__, profile);
225
226 switch (profile) {
227 case PROFILE_POWER_SAVE:
Martin Bouchet4bf8a792017-03-28 04:00:04 -0300228 // Grab value set by init.*.rc
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +0200229 cpu_interactive_read(HISPEED_FREQ_PATH, samsung_pwr->hispeed_freqs);
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100230 // Limit to hispeed freq
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +0200231 cpu_sysfs_write(MAX_FREQ_PATH, samsung_pwr->hispeed_freqs);
Christopher N. Hessef05f9022017-01-16 22:49:06 +0100232 ALOGV("%s: set powersave mode", __func__);
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100233 break;
234 case PROFILE_BALANCED:
235 // Restore normal max freq
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +0200236 cpu_sysfs_write(MAX_FREQ_PATH, samsung_pwr->max_freqs);
Christopher N. Hessef05f9022017-01-16 22:49:06 +0100237 ALOGV("%s: set balanced mode", __func__);
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100238 break;
239 case PROFILE_HIGH_PERFORMANCE:
240 // Restore normal max freq
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +0200241 cpu_sysfs_write(MAX_FREQ_PATH, samsung_pwr->max_freqs);
Christopher N. Hessef05f9022017-01-16 22:49:06 +0100242 ALOGV("%s: set performance mode", __func__);
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100243 break;
Christopher N. Hesse2981f792017-03-12 17:08:47 +0100244 default:
245 ALOGW("%s: Unknown power profile: %d", __func__, profile);
246 return;
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100247 }
248
249 current_power_profile = profile;
250}
251
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100252static void find_input_nodes(struct samsung_power_module *samsung_pwr, char *dir)
253{
254 const char filename[] = "name";
255 char errno_str[64];
256 struct dirent *de;
257 char file_content[20];
258 char *path = NULL;
259 char *node_path = NULL;
260 size_t pathsize;
261 size_t node_pathsize;
262 DIR *d;
263
264 d = opendir(dir);
265 if (d == NULL) {
266 return;
267 }
268
269 while ((de = readdir(d)) != NULL) {
270 if (strncmp(filename, de->d_name, sizeof(filename)) == 0) {
271 pathsize = strlen(dir) + strlen(de->d_name) + 2;
272 node_pathsize = strlen(dir) + strlen("enabled") + 2;
273
274 path = malloc(pathsize);
275 node_path = malloc(node_pathsize);
276 if (path == NULL || node_path == NULL) {
277 strerror_r(errno, errno_str, sizeof(errno_str));
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100278 ALOGE("Out of memory: %s", errno_str);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100279 return;
280 }
281
282 snprintf(path, pathsize, "%s/%s", dir, filename);
283 sysfs_read(path, file_content, sizeof(file_content));
284
285 snprintf(node_path, node_pathsize, "%s/%s", dir, "enabled");
286
287 if (strncmp(file_content, "sec_touchkey", 12) == 0) {
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100288 ALOGV("%s: found touchkey path: %s", __func__, node_path);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100289 samsung_pwr->touchkey_power_path = malloc(node_pathsize);
290 if (samsung_pwr->touchkey_power_path == NULL) {
291 strerror_r(errno, errno_str, sizeof(errno_str));
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100292 ALOGE("Out of memory: %s", errno_str);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100293 return;
294 }
Christopher N. Hesse22da3132016-02-01 12:36:54 +0100295 snprintf(samsung_pwr->touchkey_power_path, node_pathsize,
296 "%s", node_path);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100297 }
298
299 if (strncmp(file_content, "sec_touchscreen", 15) == 0) {
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100300 ALOGV("%s: found touchscreen path: %s", __func__, node_path);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100301 samsung_pwr->touchscreen_power_path = malloc(node_pathsize);
302 if (samsung_pwr->touchscreen_power_path == NULL) {
303 strerror_r(errno, errno_str, sizeof(errno_str));
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100304 ALOGE("Out of memory: %s", errno_str);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100305 return;
306 }
Christopher N. Hesse22da3132016-02-01 12:36:54 +0100307 snprintf(samsung_pwr->touchscreen_power_path, node_pathsize,
308 "%s", node_path);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100309 }
310 }
311 }
312
313 if (path)
314 free(path);
315 if (node_path)
316 free(node_path);
317 closedir(d);
318}
319
320/**********************************************************
321 *** INIT FUNCTIONS
322 **********************************************************/
323
324static void init_cpufreqs(struct samsung_power_module *samsung_pwr)
325{
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +0200326 cpu_interactive_read(HISPEED_FREQ_PATH, samsung_pwr->hispeed_freqs);
327 cpu_sysfs_read(MAX_FREQ_PATH, samsung_pwr->max_freqs);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100328}
329
330static void init_touch_input_power_path(struct samsung_power_module *samsung_pwr)
331{
332 char dir[1024];
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100333 uint32_t i;
334
335 for (i = 0; i < 20; i++) {
336 snprintf(dir, sizeof(dir), "/sys/class/input/input%d", i);
337 find_input_nodes(samsung_pwr, dir);
338 }
339}
340
Christopher N. Hessefb5669e2017-07-08 12:44:39 +0200341static void boost_open(struct samsung_power_module *samsung_pwr)
342{
343 char path[PATH_MAX];
344
345 // the boost node is only valid for the LITTLE cluster
346 sprintf(path, "%s%s", CPU_INTERACTIVE_PATHS[0], BOOST_PATH);
347
348 samsung_pwr->boost_fd = open(path, O_WRONLY);
349 if (samsung_pwr->boost_fd < 0) {
350 ALOGE("Error opening %s: %s\n", path, strerror(errno));
351 }
352}
353
354static void boostpulse_open(struct samsung_power_module *samsung_pwr)
355{
356 char path[PATH_MAX];
357
358 // the boostpulse node is only valid for the LITTLE cluster
359 sprintf(path, "%s%s", CPU_INTERACTIVE_PATHS[0], BOOSTPULSE_PATH);
360
361 samsung_pwr->boostpulse_fd = open(path, O_WRONLY);
362 if (samsung_pwr->boostpulse_fd < 0) {
363 ALOGE("Error opening %s: %s\n", path, strerror(errno));
364 }
365}
366
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100367static void samsung_power_init(struct power_module *module)
368{
369 struct samsung_power_module *samsung_pwr = (struct samsung_power_module *) module;
370
371 init_cpufreqs(samsung_pwr);
Christopher N. Hessed9106e92017-03-04 01:05:14 +0100372
Christopher N. Hessefb5669e2017-07-08 12:44:39 +0200373 // keep interactive boost fds opened
374 boost_open(samsung_pwr);
Christopher N. Hessed9106e92017-03-04 01:05:14 +0100375 boostpulse_open(samsung_pwr);
376
Christopher N. Hesse65c65bd2017-03-07 23:01:12 +0100377 samsung_pwr->touchscreen_power_path = NULL;
378 samsung_pwr->touchkey_power_path = NULL;
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100379 init_touch_input_power_path(samsung_pwr);
Christopher N. Hesse775bce82017-07-08 13:46:35 +0200380
381 ALOGI("Initialized settings:");
Christopher N. Hesse1146f1a2017-07-13 21:14:57 +0200382 char max_freqs[PATH_MAX];
383 sprintf(max_freqs, "max_freqs: cluster[0]: %s", samsung_pwr->max_freqs[0]);
384 for (unsigned int i = 1; i < CLUSTER_COUNT; i++) {
385 sprintf(max_freqs, "%s, %s[%d]: %s", max_freqs, "cluster", i, samsung_pwr->max_freqs[i]);
386 }
387 ALOGI("%s", max_freqs);
388 char hispeed_freqs[PATH_MAX];
389 sprintf(hispeed_freqs, "hispeed_freqs: cluster[0]: %s", samsung_pwr->hispeed_freqs[0]);
390 for (unsigned int i = 1; i < CLUSTER_COUNT; i++) {
391 sprintf(hispeed_freqs, "%s, %s[%d]: %s", hispeed_freqs, "cluster", i,
392 samsung_pwr->hispeed_freqs[i]);
393 }
394 ALOGI("%s", hispeed_freqs);
Christopher N. Hesseff868462017-07-09 23:07:09 +0200395 ALOGI("boostpulse_fd: %d", samsung_pwr->boostpulse_fd);
Christopher N. Hesse775bce82017-07-08 13:46:35 +0200396 ALOGI("touchscreen_power_path: %s",
397 samsung_pwr->touchscreen_power_path ? samsung_pwr->touchscreen_power_path : "NULL");
398 ALOGI("touchkey_power_path: %s",
399 samsung_pwr->touchkey_power_path ? samsung_pwr->touchkey_power_path : "NULL");
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100400}
401
Christopher N. Hessef6296722017-01-16 22:47:11 +0100402/**********************************************************
403 *** API FUNCTIONS
404 ***
405 *** Refer to power.h for documentation.
406 **********************************************************/
407
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100408static void samsung_power_set_interactive(struct power_module *module, int on)
409{
410 struct samsung_power_module *samsung_pwr = (struct samsung_power_module *) module;
Christopher N. Hessed9106e92017-03-04 01:05:14 +0100411 int panel_brightness;
412 char button_state[2];
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100413 int rc;
Christopher N. Hessed9106e92017-03-04 01:05:14 +0100414 static bool touchkeys_blocked = false;
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +0200415 char ON[CLUSTER_COUNT][PARAM_MAXLEN] = {"1", "1"};
416 char OFF[CLUSTER_COUNT][PARAM_MAXLEN] = {"0", "0"};
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100417
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100418 ALOGV("power_set_interactive: %d", on);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100419
Christopher N. Hessed9106e92017-03-04 01:05:14 +0100420 /*
421 * Do not disable any input devices if the screen is on but we are in a non-interactive
422 * state.
423 */
Christopher N. Hesse3360b092016-07-11 15:48:35 +0200424 if (!on) {
Christopher N. Hessed9106e92017-03-04 01:05:14 +0100425 panel_brightness = get_cur_panel_brightness();
426 if (panel_brightness < 0) {
427 ALOGE("%s: Failed to read panel brightness", __func__);
428 } else if (panel_brightness > 0) {
Christopher N. Hesse3360b092016-07-11 15:48:35 +0200429 ALOGV("%s: Moving to non-interactive state, but screen is still on,"
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100430 " not disabling input devices", __func__);
Christopher N. Hesse3360b092016-07-11 15:48:35 +0200431 goto out;
432 }
433 }
434
Paul Keith5e4fbe02017-04-21 21:34:17 -0500435 /* Sanity check the touchscreen path */
436 if (samsung_pwr->touchscreen_power_path) {
437 sysfs_write(samsung_pwr->touchscreen_power_path, on ? "1" : "0");
438 }
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100439
Christopher N. Hessed9106e92017-03-04 01:05:14 +0100440 /* Bail out if the device does not have touchkeys */
441 if (samsung_pwr->touchkey_power_path == NULL) {
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100442 goto out;
443 }
444
445 if (!on) {
Christopher N. Hessed9106e92017-03-04 01:05:14 +0100446 rc = sysfs_read(samsung_pwr->touchkey_power_path, button_state, ARRAY_SIZE(button_state));
447 if (rc < 0) {
448 ALOGE("%s: Failed to read touchkey state", __func__);
449 goto out;
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100450 }
Christopher N. Hessed9106e92017-03-04 01:05:14 +0100451 /*
452 * If button_state is 0, the keys have been disabled by another component
453 * (for example cmhw), which means we don't want them to be enabled when resuming
454 * from suspend.
455 */
456 if (button_state[0] == '0') {
457 touchkeys_blocked = true;
458 } else {
459 touchkeys_blocked = false;
460 }
461 }
462
463 if (!touchkeys_blocked) {
464 sysfs_write(samsung_pwr->touchkey_power_path, on ? "1" : "0");
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100465 }
466
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100467out:
Christopher N. Hesse7ad73bc2017-06-28 22:53:03 +0200468 cpu_interactive_write(IO_IS_BUSY_PATH, on ? ON : OFF);
Christopher N. Hesse63b5bd72017-05-29 20:45:14 +0200469
Christopher N. Hesse354f7132017-03-04 01:06:22 +0100470 ALOGV("power_set_interactive: %d done", on);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100471}
472
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100473static void samsung_power_hint(struct power_module *module,
474 power_hint_t hint,
475 void *data)
476{
477 struct samsung_power_module *samsung_pwr = (struct samsung_power_module *) module;
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100478
Christopher N. Hesse15b63092017-03-12 17:04:53 +0100479 /* Bail out if low-power mode is active */
Christopher N. Hesse5eca5aa2017-04-26 21:42:10 +0200480 if (current_power_profile == PROFILE_POWER_SAVE && hint != POWER_HINT_LOW_POWER
Christopher N. Hesse62b70f82018-02-19 23:20:14 +0100481 && hint != POWER_HINT_SET_PROFILE && hint != POWER_HINT_DISABLE_TOUCH) {
Christopher N. Hesse4f7dc6f2018-02-19 23:17:09 +0100482 ALOGV("%s: PROFILE_POWER_SAVE active, ignoring hint %d", __func__, hint);
Christopher N. Hesse15b63092017-03-12 17:04:53 +0100483 return;
484 }
485
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100486 switch (hint) {
Christopher N. Hesse2981f792017-03-12 17:08:47 +0100487 case POWER_HINT_VSYNC:
488 ALOGV("%s: POWER_HINT_VSYNC", __func__);
489 break;
490 case POWER_HINT_INTERACTION:
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100491 ALOGV("%s: POWER_HINT_INTERACTION", __func__);
Christopher N. Hessef21fbdb2017-03-04 01:41:58 +0100492 send_boostpulse(samsung_pwr->boostpulse_fd);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100493 break;
Christopher N. Hesse2981f792017-03-12 17:08:47 +0100494 case POWER_HINT_LOW_POWER:
495 ALOGV("%s: POWER_HINT_LOW_POWER", __func__);
Christopher N. Hesse3fa2b692017-04-05 18:52:48 +0200496 set_power_profile(samsung_pwr, data ? PROFILE_POWER_SAVE : PROFILE_BALANCED);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100497 break;
Christopher N. Hesse2981f792017-03-12 17:08:47 +0100498 case POWER_HINT_LAUNCH:
Christopher N. Hesse3fa2b692017-04-05 18:52:48 +0200499 ALOGV("%s: POWER_HINT_LAUNCH", __func__);
500 send_boostpulse(samsung_pwr->boostpulse_fd);
501 break;
Christopher N. Hesse5fada9b2017-01-16 23:39:48 +0100502 case POWER_HINT_CPU_BOOST:
Christopher N. Hesse3fa2b692017-04-05 18:52:48 +0200503 ALOGV("%s: POWER_HINT_CPU_BOOST", __func__);
Christopher N. Hessefb5669e2017-07-08 12:44:39 +0200504 int32_t duration_us = *((int32_t *)data);
505 send_boost(samsung_pwr->boost_fd, duration_us);
Christopher N. Hesse5fada9b2017-01-16 23:39:48 +0100506 break;
Christopher N. Hesse2981f792017-03-12 17:08:47 +0100507 case POWER_HINT_SET_PROFILE:
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100508 ALOGV("%s: POWER_HINT_SET_PROFILE", __func__);
Christopher N. Hesse2981f792017-03-12 17:08:47 +0100509 int profile = *((intptr_t *)data);
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100510 set_power_profile(samsung_pwr, profile);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100511 break;
Christopher N. Hessef9b8e832017-01-17 00:04:45 +0100512 case POWER_HINT_DISABLE_TOUCH:
513 ALOGV("%s: POWER_HINT_DISABLE_TOUCH", __func__);
Christopher N. Hesse3fa2b692017-04-05 18:52:48 +0200514 sysfs_write(samsung_pwr->touchscreen_power_path, data ? "0" : "1");
Christopher N. Hessef9b8e832017-01-17 00:04:45 +0100515 break;
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100516 default:
Christopher N. Hesse2981f792017-03-12 17:08:47 +0100517 ALOGW("%s: Unknown power hint: %d", __func__, hint);
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100518 break;
519 }
520}
521
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100522static int samsung_get_feature(struct power_module *module __unused,
523 feature_t feature)
524{
525 if (feature == POWER_FEATURE_SUPPORTED_PROFILES) {
Christopher N. Hesse58f2ca02017-01-17 00:01:15 +0100526 return PROFILE_MAX;
Andreas Schneiderf15d7f42016-02-03 10:43:47 +0100527 }
528
529 return -1;
530}
531
Stricted1a871752018-08-28 07:30:40 +0200532static void samsung_set_feature(struct power_module *module __unused, feature_t feature, int state __unused)
Christopher N. Hessee480d892016-06-22 23:04:39 +0200533{
Christopher N. Hessee480d892016-06-22 23:04:39 +0200534 switch (feature) {
ishantvivek987dcca2016-11-21 06:05:47 +0000535#ifdef TARGET_TAP_TO_WAKE_NODE
Christopher N. Hessee480d892016-06-22 23:04:39 +0200536 case POWER_FEATURE_DOUBLE_TAP_TO_WAKE:
537 ALOGV("%s: %s double tap to wake", __func__, state ? "enabling" : "disabling");
ishantvivek987dcca2016-11-21 06:05:47 +0000538 sysfs_write(TARGET_TAP_TO_WAKE_NODE, state > 0 ? "1" : "0");
Christopher N. Hessee480d892016-06-22 23:04:39 +0200539 break;
540#endif
541 default:
542 break;
543 }
544}
545
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100546static struct hw_module_methods_t power_module_methods = {
547 .open = NULL,
548};
549
550struct samsung_power_module HAL_MODULE_INFO_SYM = {
551 .base = {
552 .common = {
553 .tag = HARDWARE_MODULE_TAG,
554 .module_api_version = POWER_MODULE_API_VERSION_0_2,
555 .hal_api_version = HARDWARE_HAL_API_VERSION,
556 .id = POWER_HARDWARE_MODULE_ID,
557 .name = "Samsung Power HAL",
Christopher N. Hesseaa75be42017-01-16 22:47:59 +0100558 .author = "The LineageOS Project",
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100559 .methods = &power_module_methods,
560 },
561
562 .init = samsung_power_init,
563 .setInteractive = samsung_power_set_interactive,
564 .powerHint = samsung_power_hint,
Christopher N. Hessee480d892016-06-22 23:04:39 +0200565 .getFeature = samsung_get_feature,
566 .setFeature = samsung_set_feature
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100567 },
568
569 .lock = PTHREAD_MUTEX_INITIALIZER,
570 .boostpulse_fd = -1,
Christopher N. Hessede5e3c62015-12-21 21:28:23 +0100571};