4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
29 #include "core/launch.h"
30 #include "core/noti.h"
31 #include "core/queue.h"
32 #include "core/data.h"
33 #include "core/devices.h"
34 #include "core/device-handler.h"
35 #include "core/device-notifier.h"
36 #include "core/common.h"
37 #include "core/list.h"
38 #include "device-node.h"
39 #include "display/setting.h"
40 #include "display/poll.h"
41 #include "core/edbus-handler.h"
42 #include "core/power-supply.h"
44 #define PREDEF_LOWBAT "lowbat"
45 #define PREDEF_LOWBAT_CHANGE_FREQ "lowbat_change_freq"
47 #define CHARGE_POWERSAVE_FREQ_ACT "charge_powersave_freq_act"
48 #define CHARGE_RELEASE_FREQ_ACT "charge_release_freq_act"
51 #define BATTERY_CHARGING 65535
52 #define BATTERY_UNKNOWN -1
53 #define BATTERY_FULL 100
55 #define WARNING_LOW_BAT_ACT "warning_low_bat_act"
56 #define CRITICAL_LOW_BAT_ACT "critical_low_bat_act"
57 #define POWER_OFF_BAT_ACT "power_off_bat_act"
58 #define CHARGE_BAT_ACT "charge_bat_act"
59 #define CHARGE_CHECK_ACT "charge_check_act"
60 #define CHARGE_ERROR_ACT "charge_error_act"
61 #define CHARGE_ERROR_LOW_ACT "charge_error_low_act"
62 #define CHARGE_ERROR_HIGH_ACT "charge_error_high_act"
63 #define CHARGE_ERROR_OVP_ACT "charge_error_ovp_act"
64 #define WAITING_INTERVAL 10
66 #define LOWBAT_CPU_CTRL_ID "id6"
67 #define LOWBAT_CPU_FREQ_RATE (0.7)
69 #define LOWBAT_POPUP_NAME "lowbat-syspopup"
70 #define LOWBAT_EXEC_PATH PREFIX"/bin/lowbatt-popup"
78 struct lowbat_process_entry {
81 int (*func) (void *data);
84 static int cur_bat_state = BATTERY_UNKNOWN;
85 static int cur_bat_capacity = -1;
87 static int lowbat_popup_option = 0;
88 static int lowbat_freq = -1;
89 static struct battery_config_info battery_info;
91 static dd_list *lpe = NULL;
92 static int scenario_count = 0;
94 static int lowbat_initialized(void *data)
101 status = *(int *)data;
105 int lowbat_scenario(int old, int now, void *data)
108 struct lowbat_process_entry *scenario;
111 DD_LIST_FOREACH(lpe, n, scenario) {
112 if (old != scenario->old || now != scenario->now)
116 scenario->func(data);
123 int lowbat_add_scenario(int old, int now, int (*func)(void *data))
125 struct lowbat_process_entry *scenario;
127 _I("%d %d, %x", old, now, func);
130 _E("invalid func address!");
134 scenario = malloc(sizeof(struct lowbat_process_entry));
136 _E("Fail to malloc for notifier!");
142 scenario->func = func;
144 DD_LIST_APPEND(lpe, scenario);
149 static void print_lowbat_state(unsigned int bat_percent)
153 for (i = 0; i < BAT_MON_SAMPLES; i++)
154 _D("\t%d", recent_bat_percent[i]);
158 int battery_check_act(void *data)
160 notify_action(PREDEF_LOWBAT, 1, CHARGE_CHECK_ACT);
164 int battery_warning_low_act(void *data)
166 notify_action(PREDEF_LOWBAT, 1, WARNING_LOW_BAT_ACT);
170 int battery_critical_low_act(void *data)
172 notify_action(PREDEF_LOWBAT, 1, CRITICAL_LOW_BAT_ACT);
176 int battery_power_off_act(void *data)
178 vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, VCONFKEY_SYSMAN_POWER_OFF_DIRECT);
182 int battery_charge_err_act(void *data)
184 notify_action(PREDEF_LOWBAT, 1, CHARGE_ERROR_ACT);
188 int battery_charge_err_low_act(void *data)
190 notify_action(PREDEF_LOWBAT, 1, CHARGE_ERROR_LOW_ACT);
194 int battery_charge_err_high_act(void *data)
196 notify_action(PREDEF_LOWBAT, 1, CHARGE_ERROR_HIGH_ACT);
200 int battery_charge_err_ovp_act(void *data)
202 notify_action(PREDEF_LOWBAT, 1, CHARGE_ERROR_OVP_ACT);
206 static int battery_charge_act(void *data)
212 /* instead of adding action to the queue, execute it right here */
213 if (device_get_property(DEVTYPE_JACK, JACK_PROP_TA_ONLINE, &val) == 0
215 snprintf(argstr, 128, "-t 4");
216 launch_after_kill_if_exist(LOWBAT_EXEC_PATH, argstr);
222 static void lowbat_scenario_init(void)
224 lowbat_add_scenario(battery_info.normal, battery_info.warning, battery_warning_low_act);
225 lowbat_add_scenario(battery_info.warning, battery_info.critical, battery_warning_low_act);
226 lowbat_add_scenario(battery_info.critical, battery_info.poweroff, battery_critical_low_act);
227 lowbat_add_scenario(battery_info.poweroff, battery_info.realoff, battery_power_off_act);
228 lowbat_add_scenario(battery_info.normal, battery_info.critical, battery_warning_low_act);
229 lowbat_add_scenario(battery_info.warning, battery_info.poweroff, battery_critical_low_act);
230 lowbat_add_scenario(battery_info.critical, battery_info.realoff, battery_power_off_act);
231 lowbat_add_scenario(battery_info.normal, battery_info.poweroff, battery_critical_low_act);
232 lowbat_add_scenario(battery_info.warning, battery_info.realoff, battery_power_off_act);
233 lowbat_add_scenario(battery_info.normal, battery_info.realoff, battery_power_off_act);
234 lowbat_add_scenario(battery_info.realoff, battery_info.realoff, battery_power_off_act);
235 lowbat_add_scenario(battery_info.realoff, battery_info.normal, battery_check_act);
236 lowbat_add_scenario(battery_info.realoff, battery_info.warning, battery_check_act);
237 lowbat_add_scenario(battery_info.realoff, battery_info.critical, battery_check_act);
238 lowbat_add_scenario(battery_info.realoff, battery_info.poweroff, battery_check_act);
241 static void change_lowbat_level(int bat_percent)
245 if (cur_bat_capacity == bat_percent)
248 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, &prev) < 0) {
249 _E("vconf_get_int() failed");
254 if (bat_percent > BATTERY_LEVEL_CHECK_FULL) {
255 now = VCONFKEY_SYSMAN_BAT_LEVEL_FULL;
256 } else if (bat_percent > BATTERY_LEVEL_CHECK_HIGH) {
257 now = VCONFKEY_SYSMAN_BAT_LEVEL_HIGH;
258 } else if (bat_percent > BATTERY_LEVEL_CHECK_LOW) {
259 now = VCONFKEY_SYSMAN_BAT_LEVEL_LOW;
260 } else if (bat_percent > BATTERY_LEVEL_CHECK_CRITICAL) {
261 now = VCONFKEY_SYSMAN_BAT_LEVEL_CRITICAL;
263 now = VCONFKEY_SYSMAN_BAT_LEVEL_EMPTY;
267 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, now);
270 static int lowbat_process(int bat_percent, void *ad)
272 int new_bat_capacity;
274 int vconf_state = -1;
277 bool low_bat = false;
278 bool full_bat = false;
282 new_bat_capacity = bat_percent;
283 if (new_bat_capacity < 0)
285 change_lowbat_level(new_bat_capacity);
286 pm_lock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, STAY_CUR_STATE, 0);
288 if (new_bat_capacity != cur_bat_capacity) {
289 _D("[BAT_MON] cur = %d new = %d", cur_bat_capacity, new_bat_capacity);
290 if (vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, new_bat_capacity) == 0)
291 cur_bat_capacity = new_bat_capacity;
294 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &vconf_state) < 0) {
295 _E("vconf_get_int() failed");
300 if (new_bat_capacity <= battery_info.realoff) {
301 if (battery.charge_now) {
302 new_bat_state = battery_info.poweroff;
303 if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
304 status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
306 new_bat_state = battery_info.realoff;
307 if (vconf_state != VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
308 status = VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF;
310 } else if (new_bat_capacity <= battery_info.poweroff) {
311 new_bat_state = battery_info.poweroff;
312 if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
313 status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
314 } else if (new_bat_capacity <= battery_info.critical) {
315 new_bat_state = battery_info.critical;
316 if (vconf_state != VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
317 status = VCONFKEY_SYSMAN_BAT_CRITICAL_LOW;
318 } else if (new_bat_capacity <= battery_info.warning) {
319 new_bat_state = battery_info.warning;
320 if (vconf_state != VCONFKEY_SYSMAN_BAT_WARNING_LOW)
321 status = VCONFKEY_SYSMAN_BAT_WARNING_LOW;
323 new_bat_state = battery_info.normal;
324 if (new_bat_capacity == BATTERY_FULL) {
325 if (battery.charge_full) {
326 if (vconf_state != VCONFKEY_SYSMAN_BAT_FULL)
327 status = VCONFKEY_SYSMAN_BAT_FULL;
330 if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
331 status = VCONFKEY_SYSMAN_BAT_NORMAL;
334 if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
335 status = VCONFKEY_SYSMAN_BAT_NORMAL;
341 ret = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, status);
342 power_supply_broadcast(CHARGE_LEVEL_SIGNAL, status);
343 if (update_pm_setting)
344 update_pm_setting(SETTING_LOW_BATT, status);
352 if (vconf_get_int(VCONFKEY_PM_KEY_IGNORE, &extreme) == 0 && extreme == TRUE &&
353 (status > VCONFKEY_SYSMAN_BAT_POWER_OFF && status <= VCONFKEY_SYSMAN_BAT_FULL))
354 if (vconf_set_int(VCONFKEY_PM_KEY_IGNORE, FALSE) == 0)
355 _I("release key ignore");
357 if (new_bat_capacity <= battery_info.warning)
360 device_notify(DEVICE_NOTIFIER_LOWBAT, (void*)low_bat);
362 if (cur_bat_state == new_bat_state && new_bat_state > battery_info.realoff)
365 if (cur_bat_state == BATTERY_UNKNOWN)
366 cur_bat_state = battery_info.normal;
367 result = lowbat_scenario(cur_bat_state, new_bat_state, NULL);
369 _I("cur_bat_state %d, new_bat_state %d", cur_bat_state, new_bat_state);
370 cur_bat_state = new_bat_state;
372 pm_unlock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
377 static int lowbat_read()
381 r = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CAPACITY, &bat_percent);
388 static void change_lowbat_cpu_freq(int bat_percent)
390 static int init_cpu_freq = 0;
391 static int power_save = 0;
392 if (cur_bat_capacity == bat_percent)
395 if (bat_percent > battery_info.poweroff && init_cpu_freq == 0) {
397 notify_action(PREDEF_LOWBAT_CHANGE_FREQ, 1, CHARGE_RELEASE_FREQ_ACT);
401 if (bat_percent <= battery_info.poweroff && power_save == 0) {
403 notify_action(PREDEF_LOWBAT_CHANGE_FREQ, 1, CHARGE_POWERSAVE_FREQ_ACT);
404 } else if (power_save == 1) {
406 notify_action(PREDEF_LOWBAT_CHANGE_FREQ, 1, CHARGE_RELEASE_FREQ_ACT);
410 static int check_lowbat_percent(int *pct)
414 bat_percent = lowbat_read();
415 if (bat_percent < 0) {
416 _E("[BATMON] Cannot read battery gage. stop read fuel gage");
419 if (bat_percent > 100)
421 change_lowbat_level(bat_percent);
422 change_lowbat_cpu_freq(bat_percent);
427 void lowbat_monitor(void *data)
431 r = lowbat_initialized(NULL);
436 r = check_lowbat_percent(&bat_percent);
440 bat_percent = *(int *)data;
441 print_lowbat_state(bat_percent);
442 lowbat_process(bat_percent, NULL);
445 /* for debugging (request by kernel) */
446 static int check_battery()
451 if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_PRESENT, &ret) < 0) {
452 _E("FAIL: device_get_property(): [BATMON] battery check : %d", ret);
454 _D("[BATMON] battery check : %d", ret);
459 static int booting_done(void *data)
473 int lowbat_action(int argc, char **argv)
479 static int launched_poweroff = 0;
481 struct popup_data *params;
482 static const struct device_ops *apps = NULL;
487 if (strcmp(argv[0], POWER_OFF_BAT_ACT))
488 launched_poweroff = 0;
490 if (!strcmp(argv[0], CRITICAL_LOW_BAT_ACT)) {
492 lowbat_popup_option = LOWBAT_OPT_CHECK;
493 } else if (!strcmp(argv[0], WARNING_LOW_BAT_ACT)) {
494 if (is_factory_mode() == 1)
497 lowbat_popup_option = LOWBAT_OPT_WARNING;
498 } else if (!strcmp(argv[0], POWER_OFF_BAT_ACT)) {
500 lowbat_popup_option = LOWBAT_OPT_POWEROFF;
501 } else if (!strcmp(argv[0], CHARGE_ERROR_ACT)) {
503 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
504 } else if (!strcmp(argv[0], CHARGE_ERROR_LOW_ACT)) {
505 value = "chargeerrlow";
506 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
507 } else if (!strcmp(argv[0], CHARGE_ERROR_HIGH_ACT)) {
508 value = "chargeerrhigh";
509 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
510 } else if (!strcmp(argv[0], CHARGE_ERROR_OVP_ACT)) {
511 value = "chargeerrovp";
512 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
513 } else if (!strcmp(argv[0], CHARGE_CHECK_ACT)) {
514 launched_poweroff = 0;
519 ret = vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &state);
520 if (state == 1 || ret != 0 || booting_done(NULL)) {
522 if (launched_poweroff == 1) {
523 _I("will be foreced power off");
524 do_poweroff(0, NULL);
528 if (lowbat_popup_option == LOWBAT_OPT_POWEROFF)
529 launched_poweroff = 1;
531 pid = predefine_get_pid(LOWBAT_EXEC_PATH);
533 _I("pre launched %s destroy", LOWBAT_EXEC_PATH);
537 apps = find_device("apps");
541 params = malloc(sizeof(struct popup_data));
542 if (params == NULL) {
546 pm_change_internal(getpid(), LCD_NORMAL);
547 params->name = LOWBAT_POPUP_NAME;
548 params->key = POPUP_KEY_CONTENT;
549 params->value = strdup(value);
550 apps->init((void *)params);
554 _D("boot-animation running yet");
560 static int check_power_save_mode(void)
563 int power_saving_cpu_stat = -1;
565 ret = vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_CPU,
566 &power_saving_cpu_stat);
568 _E("failed to get vconf key");
572 if (power_saving_cpu_stat == 1)
577 int change_freq_action(int argc, char **argv)
584 if (!strcmp(argv[0], CHARGE_POWERSAVE_FREQ_ACT))
586 device_notify(DEVICE_NOTIFIER_PMQOS_LOWBAT, (void*)val);
590 static int lowbat_monitor_init(void *data)
594 lowbat_initialized(&status);
595 unregister_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
596 battery_config_load(&battery_info);
597 _I("%d %d %d %d %d", battery_info.normal, battery_info.warning,
598 battery_info.critical, battery_info.poweroff, battery_info.realoff);
599 lowbat_scenario_init();
600 register_action(PREDEF_LOWBAT, lowbat_action, NULL, NULL);
601 register_action(PREDEF_LOWBAT_CHANGE_FREQ, change_freq_action, NULL, NULL);
602 lowbat_process(battery.capacity, NULL);
606 static void lowbat_init(void *data)
608 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
609 register_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
612 static void lowbat_exit(void *data)
616 lowbat_initialized(&status);
617 unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
620 static const struct device_ops lowbat_device_ops = {
621 .priority = DEVICE_PRIORITY_NORMAL,
627 DEVICE_OPS_REGISTER(&lowbat_device_ops)