blob: ff4210655f31f343e0ee64d6d743bf0d8cab47e6 [file] [log] [blame]
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 * Copyright (C) 2012 The CyanogenMod Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#include <errno.h>
18#include <string.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22
jt113488fda932012-10-19 23:17:48 -050023#define LOG_TAG "S5PC110 PowerHAL"
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +070024#include <utils/Log.h>
25
26#include <hardware/hardware.h>
27#include <hardware/power.h>
28
jt113488fda932012-10-19 23:17:48 -050029#define SCALING_GOVERNOR_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
30#define BOOSTPULSE_ONDEMAND "/sys/devices/system/cpu/cpufreq/ondemand/boostpulse"
31#define BOOSTPULSE_INTERACTIVE "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
Steve Kondikde4b10b2013-02-08 21:47:56 -060032#define TIMER_RATE_SCREEN_ON "30000"
33#define TIMER_RATE_SCREEN_OFF "150000"
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +070034
35struct s5pc110_power_module {
36 struct power_module base;
37 pthread_mutex_t lock;
38 int boostpulse_fd;
39 int boostpulse_warned;
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +070040};
41
Steve Kondikde4b10b2013-02-08 21:47:56 -060042static char governor[20];
43
jt113488fda932012-10-19 23:17:48 -050044static int sysfs_read(char *path, char *s, int num_bytes)
45{
46 char buf[80];
47 int count;
48 int ret = 0;
49 int fd = open(path, O_RDONLY);
50
51 if (fd < 0) {
52 strerror_r(errno, buf, sizeof(buf));
53 ALOGE("Error opening %s: %s\n", path, buf);
54
55 return -1;
56 }
57
58 if ((count = read(fd, s, num_bytes - 1)) < 0) {
59 strerror_r(errno, buf, sizeof(buf));
60 ALOGE("Error writing to %s: %s\n", path, buf);
61
62 ret = -1;
63 } else {
64 s[count] = '\0';
65 }
66
67 close(fd);
68
69 return ret;
70}
71
Steve Kondikde4b10b2013-02-08 21:47:56 -060072static void sysfs_write(char *path, char *s)
73{
74 char buf[80];
75 int len;
76 int fd = open(path, O_WRONLY);
77
78 if (fd < 0) {
79 strerror_r(errno, buf, sizeof(buf));
80 ALOGE("Error opening %s: %s\n", path, buf);
81 return;
82 }
83
84 len = write(fd, s, strlen(s));
85 if (len < 0) {
86 strerror_r(errno, buf, sizeof(buf));
87 ALOGE("Error writing to %s: %s\n", path, buf);
88 }
89
90 close(fd);
91}
92
93static int get_scaling_governor() {
jt113488fda932012-10-19 23:17:48 -050094 if (sysfs_read(SCALING_GOVERNOR_PATH, governor,
Steve Kondikde4b10b2013-02-08 21:47:56 -060095 sizeof(governor)) == -1) {
jt113488fda932012-10-19 23:17:48 -050096 // Can't obtain the scaling governor. Return.
97 return -1;
98 } else {
99 // Strip newline at the end.
100 int len = strlen(governor);
101
102 len--;
103
104 while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r'))
105 governor[len--] = '\0';
106 }
107
108 return 0;
109}
110
Steve Kondikde4b10b2013-02-08 21:47:56 -0600111static void s5pc110_power_set_interactive(struct power_module *module, int on)
112{
113 if (strncmp(governor, "interactive", 11) == 0)
114 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate",
115 on ? TIMER_RATE_SCREEN_ON : TIMER_RATE_SCREEN_OFF);
116}
117
118static void configure_governor()
119{
120 s5pc110_power_set_interactive(NULL, 1);
121
122 if (strncmp(governor, "ondemand", 8) == 0) {
123 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/up_threshold", "95");
124 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/io_is_busy", "1");
125 sysfs_write("/sys/devices/system/cpu/cpufreq/ondemand/sampling_down_factor", "4");
126 } else if (strncmp(governor, "interactive", 11) == 0) {
127 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time", "90000");
128 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay", "30000");
129 }
130}
131
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +0700132static int boostpulse_open(struct s5pc110_power_module *s5pc110)
133{
134 char buf[80];
135
136 pthread_mutex_lock(&s5pc110->lock);
137
138 if (s5pc110->boostpulse_fd < 0) {
Steve Kondikde4b10b2013-02-08 21:47:56 -0600139 if (get_scaling_governor() < 0) {
jt113488fda932012-10-19 23:17:48 -0500140 ALOGE("Can't read scaling governor.");
141 s5pc110->boostpulse_warned = 1;
142 } else {
143 if (strncmp(governor, "ondemand", 8) == 0)
144 s5pc110->boostpulse_fd = open(BOOSTPULSE_ONDEMAND, O_WRONLY);
145 else if (strncmp(governor, "interactive", 11) == 0)
146 s5pc110->boostpulse_fd = open(BOOSTPULSE_INTERACTIVE, O_WRONLY);
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +0700147
jt113488fda932012-10-19 23:17:48 -0500148 if (s5pc110->boostpulse_fd < 0 && !s5pc110->boostpulse_warned) {
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +0700149 strerror_r(errno, buf, sizeof(buf));
jt113488fda932012-10-19 23:17:48 -0500150 ALOGE("Error opening %s boostpulse interface: %s\n", governor, buf);
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +0700151 s5pc110->boostpulse_warned = 1;
Steve Kondikde4b10b2013-02-08 21:47:56 -0600152 } else if (s5pc110->boostpulse_fd > 0) {
153 configure_governor();
jt113488fda932012-10-19 23:17:48 -0500154 ALOGD("Opened %s boostpulse interface", governor);
Steve Kondikde4b10b2013-02-08 21:47:56 -0600155 }
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +0700156 }
157 }
158
159 pthread_mutex_unlock(&s5pc110->lock);
160 return s5pc110->boostpulse_fd;
161}
162
163static void s5pc110_power_hint(struct power_module *module, power_hint_t hint,
164 void *data)
165{
166 struct s5pc110_power_module *s5pc110 = (struct s5pc110_power_module *) module;
167 char buf[80];
168 int len;
169 int duration = 1;
170
171 switch (hint) {
172 case POWER_HINT_INTERACTION:
173 case POWER_HINT_CPU_BOOST:
174 if (boostpulse_open(s5pc110) >= 0) {
175 if (data != NULL)
176 duration = (int) data;
177
178 snprintf(buf, sizeof(buf), "%d", duration);
179 len = write(s5pc110->boostpulse_fd, buf, strlen(buf));
180
181 if (len < 0) {
182 strerror_r(errno, buf, sizeof(buf));
jt113488fda932012-10-19 23:17:48 -0500183 ALOGE("Error writing to boostpulse: %s\n", buf);
184
185 pthread_mutex_lock(&s5pc110->lock);
186 close(s5pc110->boostpulse_fd);
187 s5pc110->boostpulse_fd = -1;
188 s5pc110->boostpulse_warned = 0;
189 pthread_mutex_unlock(&s5pc110->lock);
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +0700190 }
191 }
192 break;
193
194 case POWER_HINT_VSYNC:
195 break;
196
197 default:
198 break;
199 }
200}
201
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +0700202static void s5pc110_power_init(struct power_module *module)
203{
Steve Kondikde4b10b2013-02-08 21:47:56 -0600204 get_scaling_governor();
205 configure_governor();
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +0700206}
207
208static struct hw_module_methods_t power_module_methods = {
209 .open = NULL,
210};
211
212struct s5pc110_power_module HAL_MODULE_INFO_SYM = {
213 base: {
214 common: {
215 tag: HARDWARE_MODULE_TAG,
216 module_api_version: POWER_MODULE_API_VERSION_0_2,
217 hal_api_version: HARDWARE_HAL_API_VERSION,
218 id: POWER_HARDWARE_MODULE_ID,
219 name: "S5PC110 Power HAL",
Steve Kondikde4b10b2013-02-08 21:47:56 -0600220 author: "The CyanogenMod Project",
Pawit Pornkitprasan5bff9ac2012-09-25 21:17:58 +0700221 methods: &power_module_methods,
222 },
223 init: s5pc110_power_init,
224 setInteractive: s5pc110_power_set_interactive,
225 powerHint: s5pc110_power_hint,
226 },
227
228 lock: PTHREAD_MUTEX_INITIALIZER,
229 boostpulse_fd: -1,
230 boostpulse_warned: 0,
231};