2 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include "device-node.h"
22 #include "include/ss_data.h"
25 #define DEFAULT_MAX_CPU_FREQ 1200000
26 #define DEFAULT_MIN_CPU_FREQ 100000
27 #define POWER_SAVING_CPUFREQ 800000
29 static int max_cpu_freq_limit = -1;
30 static int min_cpu_freq_limit = -1;
31 static int cur_max_cpu_freq = INT_MAX;
32 static int cur_min_cpu_freq = INT_MIN;
34 static Eina_List *max_cpu_freq_list;
35 static Eina_List *min_cpu_freq_list;
37 struct cpu_freq_entry {
42 static void __set_freq_limit();
43 static int __is_entry_enble(int pid);
44 static int __remove_entry_from_max_cpu_freq_list(int pid);
45 static int __remove_entry_from_min_cpu_freq_list(int pid);
46 static int __add_entry_to_max_cpu_freq_list(int pid, int freq);
47 static int __add_entry_to_min_cpu_freq_list(int pid, int freq);
48 static int __write_max_cpu_freq(int freq);
49 static int __write_min_cpu_freq(int freq);
51 int set_max_frequency_action(int argc, char **argv)
58 r = __add_entry_to_max_cpu_freq_list(atoi(argv[0]), atoi(argv[1]));
60 PRT_TRACE_ERR("Add entry failed");
64 r = __write_max_cpu_freq(cur_max_cpu_freq);
66 PRT_TRACE_ERR("Write entry failed");
73 int set_min_frequency_action(int argc, char **argv)
80 r = __add_entry_to_min_cpu_freq_list(atoi(argv[0]), atoi(argv[1]));
82 PRT_TRACE_ERR("Add entry failed");
86 r = __write_min_cpu_freq(cur_min_cpu_freq);
88 PRT_TRACE_ERR("Write entry failed");
95 int release_max_frequency_action(int argc, char **argv)
101 r = __remove_entry_from_max_cpu_freq_list(atoi(argv[0]));
103 PRT_TRACE_ERR("Remove entry failed");
107 if (cur_max_cpu_freq == INT_MAX)
108 cur_max_cpu_freq = max_cpu_freq_limit;
110 r = __write_max_cpu_freq(cur_max_cpu_freq);
112 PRT_TRACE_ERR("Write freq failed");
119 int release_min_frequency_action(int argc, char **argv)
126 r = __remove_entry_from_min_cpu_freq_list(atoi(argv[0]));
128 PRT_TRACE_ERR("Remove entry failed");
132 if (cur_min_cpu_freq == INT_MIN)
133 cur_min_cpu_freq = min_cpu_freq_limit;
135 r = __write_min_cpu_freq(cur_min_cpu_freq);
137 PRT_TRACE_ERR("Write entry failed");
144 static int power_saving_cb(keynode_t *key_nodes, void *data)
147 int power_saving_stat = -1;
148 int power_saving_cpu_stat = -1;
150 power_saving_stat = vconf_keynode_get_bool(key_nodes);
151 if (power_saving_stat == 1) {
152 if (vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_CPU, &power_saving_cpu_stat) == 0) {
153 if (power_saving_cpu_stat == 1) {
154 ret = __add_entry_to_max_cpu_freq_list(getpid(), POWER_SAVING_CPUFREQ);
156 PRT_TRACE_ERR("Add entry failed");
161 PRT_TRACE_ERR("failed to get vconf key");
165 ret = __remove_entry_from_max_cpu_freq_list(getpid());
167 PRT_TRACE_ERR("Remove entry failed");
170 if (cur_max_cpu_freq == INT_MIN)
171 cur_max_cpu_freq = max_cpu_freq_limit;
173 ret = __write_max_cpu_freq(cur_max_cpu_freq);
175 PRT_TRACE_ERR("Write failed");
182 static int power_saving_cpu_cb(keynode_t *key_nodes, void *data)
185 int power_saving_stat = -1;
186 int power_saving_cpu_stat = -1;
188 if (vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, &power_saving_stat) == 0) {
189 if (power_saving_stat == 1) {
190 power_saving_cpu_stat = vconf_keynode_get_bool(key_nodes);
191 if (power_saving_cpu_stat == 1) {
192 ret = __add_entry_to_max_cpu_freq_list(getpid(), POWER_SAVING_CPUFREQ);
194 PRT_TRACE_ERR("Add entry failed");
198 ret = __remove_entry_from_max_cpu_freq_list(getpid());
200 PRT_TRACE_ERR("Remove entry failed");
203 if (cur_max_cpu_freq == INT_MAX)
204 cur_max_cpu_freq = max_cpu_freq_limit;
206 ret = __write_max_cpu_freq(cur_max_cpu_freq);
208 PRT_TRACE_ERR("Write failed");
213 PRT_TRACE_ERR("failed to get vconf key");
220 int ss_cpu_handler_init(void)
224 ss_action_entry_add_internal(PREDEF_SET_MAX_FREQUENCY, set_max_frequency_action, NULL, NULL);
225 ss_action_entry_add_internal(PREDEF_SET_MIN_FREQUENCY, set_min_frequency_action, NULL, NULL);
226 ss_action_entry_add_internal(PREDEF_RELEASE_MAX_FREQUENCY, release_max_frequency_action, NULL, NULL);
227 ss_action_entry_add_internal(PREDEF_RELEASE_MIN_FREQUENCY, release_min_frequency_action, NULL, NULL);
229 vconf_notify_key_changed(VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, (void *)power_saving_cb, NULL);
230 vconf_notify_key_changed(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_CPU, (void *)power_saving_cpu_cb, NULL);
235 static void __set_freq_limit()
239 ret = device_get_property(DEVICE_TYPE_CPU, PROP_CPU_CPUINFO_MAX_FREQ, &max_cpu_freq_limit);
241 PRT_TRACE_ERR("get cpufreq cpuinfo max readerror: %s", strerror(errno));
242 max_cpu_freq_limit = DEFAULT_MAX_CPU_FREQ;
245 ret = device_get_property(DEVICE_TYPE_CPU, PROP_CPU_CPUINFO_MIN_FREQ, &min_cpu_freq_limit);
247 PRT_TRACE_ERR("get cpufreq cpuinfo min readerror: %s", strerror(errno));
248 min_cpu_freq_limit = DEFAULT_MIN_CPU_FREQ;
251 /* check power saving */
252 int power_saving_stat = -1;
253 int power_saving_cpu_stat = -1;
254 if (vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, &power_saving_stat) == 0) {
255 if (power_saving_stat == 1) {
256 if (vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_CPU, &power_saving_cpu_stat) == 0) {
257 if (power_saving_cpu_stat == 1) {
258 ret = __add_entry_to_max_cpu_freq_list(getpid(), POWER_SAVING_CPUFREQ);
260 PRT_TRACE_ERR("Add entry failed");
263 ret = __write_max_cpu_freq(cur_max_cpu_freq);
265 PRT_TRACE_ERR("Write entry failed");
270 PRT_TRACE_ERR("failed to get vconf key");
274 PRT_TRACE_ERR("failed to get vconf key");
278 static int __is_entry_enable(int pid)
280 char pid_path[PATH_MAX];
282 snprintf(pid_path, PATH_MAX, "/proc/%d", pid);
283 if (access(pid_path, F_OK) < 0) {
290 static int __remove_entry_from_max_cpu_freq_list(int pid)
294 struct cpu_freq_entry *entry;
296 cur_max_cpu_freq = INT_MAX;
298 EINA_LIST_FOREACH_SAFE(max_cpu_freq_list, tmp, tmp_next, entry) {
300 if ((!__is_entry_enable(entry->pid)) || (entry->pid == pid)) {
301 max_cpu_freq_list = eina_list_remove(max_cpu_freq_list, entry);
306 if (entry->freq < cur_max_cpu_freq) {
307 cur_max_cpu_freq = entry->freq;
315 static int __remove_entry_from_min_cpu_freq_list(int pid)
319 struct cpu_freq_entry *entry;
321 cur_min_cpu_freq = INT_MIN;
323 EINA_LIST_FOREACH_SAFE(min_cpu_freq_list, tmp, tmp_next, entry) {
325 if ((!__is_entry_enable(entry->pid)) || (entry->pid == pid)) {
326 min_cpu_freq_list = eina_list_remove(min_cpu_freq_list, entry);
331 if (entry->freq > cur_min_cpu_freq) {
332 cur_min_cpu_freq = entry->freq;
341 static int __add_entry_to_max_cpu_freq_list(int pid, int freq)
344 struct cpu_freq_entry *entry;
346 r = __remove_entry_from_max_cpu_freq_list(pid);
348 PRT_TRACE_ERR("Remove duplicated entry failed");
351 if (freq < cur_max_cpu_freq) {
352 cur_max_cpu_freq = freq;
355 entry = malloc(sizeof(struct cpu_freq_entry));
357 PRT_TRACE_ERR("Malloc failed");
364 max_cpu_freq_list = eina_list_prepend(max_cpu_freq_list, entry);
365 if (!max_cpu_freq_list) {
366 PRT_TRACE_ERR("eina_list_prepend failed");
373 static int __add_entry_to_min_cpu_freq_list(int pid, int freq)
376 struct cpu_freq_entry *entry;
378 r = __remove_entry_from_min_cpu_freq_list(pid);
380 PRT_TRACE_ERR("Remove duplicated entry failed");
383 if (freq > cur_min_cpu_freq) {
384 cur_min_cpu_freq = freq;
387 entry = malloc(sizeof(struct cpu_freq_entry));
389 PRT_TRACE_ERR("Malloc failed");
396 min_cpu_freq_list = eina_list_prepend(min_cpu_freq_list, entry);
397 if (!min_cpu_freq_list) {
398 PRT_TRACE_ERR("eina_list_prepend failed");
405 static int __write_max_cpu_freq(int freq)
409 ret = device_set_property(DEVICE_TYPE_CPU, PROP_CPU_SCALING_MAX_FREQ, freq);
411 PRT_TRACE_ERR("set cpufreq max freq write error: %s", strerror(errno));
418 static int __write_min_cpu_freq(int freq)
422 ret = device_set_property(DEVICE_TYPE_CPU, PROP_CPU_SCALING_MIN_FREQ, freq);
424 PRT_TRACE_ERR("set cpufreq min freq write error: %s", strerror(errno));