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/devices.h"
31 #include "core/device-handler.h"
32 #include "core/device-notifier.h"
33 #include "core/common.h"
34 #include "core/list.h"
35 #include "device-node.h"
36 #include "display/setting.h"
37 #include "display/poll.h"
38 #include "core/edbus-handler.h"
39 #include "core/power-supply.h"
40 #include "power/power-handler.h"
42 #define CHARGE_POWERSAVE_FREQ_ACT "charge_powersave_freq_act"
43 #define CHARGE_RELEASE_FREQ_ACT "charge_release_freq_act"
46 #define BATTERY_CHARGING 65535
47 #define BATTERY_UNKNOWN -1
49 #define WARNING_LOW_BAT_ACT "warning_low_bat_act"
50 #define CRITICAL_LOW_BAT_ACT "critical_low_bat_act"
51 #define POWER_OFF_BAT_ACT "power_off_bat_act"
52 #define CHARGE_BAT_ACT "charge_bat_act"
53 #define CHARGE_CHECK_ACT "charge_check_act"
54 #define CHARGE_ERROR_ACT "charge_error_act"
55 #define CHARGE_ERROR_LOW_ACT "charge_error_low_act"
56 #define CHARGE_ERROR_HIGH_ACT "charge_error_high_act"
57 #define CHARGE_ERROR_OVP_ACT "charge_error_ovp_act"
58 #define WAITING_INTERVAL 10
60 #define LOWBAT_CPU_CTRL_ID "id6"
61 #define LOWBAT_CPU_FREQ_RATE (0.7)
63 #define LOWBAT_POPUP_NAME "lowbat-syspopup"
64 #define LOWBAT_EXEC_PATH PREFIX"/bin/lowbatt-popup"
72 struct lowbat_process_entry {
75 int (*func) (void *data);
78 static int cur_bat_state = BATTERY_UNKNOWN;
79 static int cur_bat_capacity = -1;
81 static int lowbat_popup_option = 0;
82 static int lowbat_freq = -1;
83 static struct battery_config_info battery_info = {
84 .normal = BATTERY_NORMAL,
85 .warning = BATTERY_WARNING,
86 .critical = BATTERY_CRITICAL,
87 .poweroff = BATTERY_POWEROFF,
88 .realoff = BATTERY_REALOFF,
91 static dd_list *lpe = NULL;
92 static int scenario_count = 0;
94 static int lowbat_initialized(void *data)
101 status = *(int *)data;
105 static 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 static 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 static int power_execute(void)
160 static const struct device_ops *ops = NULL;
162 FIND_DEVICE_INT(ops, POWER_OPS_NAME);
164 return ops->execute(INTERNAL_PWROFF);
167 static int booting_done(void *data)
181 static int lowbat_popup(char *option)
183 static int launched_poweroff = 0;
184 static const struct device_ops *apps = NULL;
185 struct popup_data *params;
187 int r_disturb, s_disturb, r_block, s_block;
194 if (strcmp(option, POWER_OFF_BAT_ACT))
195 launched_poweroff = 0;
197 if (!strcmp(option, CRITICAL_LOW_BAT_ACT)) {
199 value = "lowbattery_critical";
203 lowbat_popup_option = LOWBAT_OPT_CHECK;
204 } else if (!strcmp(option, WARNING_LOW_BAT_ACT)) {
205 if (is_factory_mode() == 1)
208 value = "lowbattery_warning";
212 lowbat_popup_option = LOWBAT_OPT_WARNING;
213 } else if (!strcmp(option, POWER_OFF_BAT_ACT)) {
215 lowbat_popup_option = LOWBAT_OPT_POWEROFF;
216 } else if (!strcmp(option, CHARGE_ERROR_ACT)) {
218 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
219 } else if (!strcmp(option, CHARGE_ERROR_LOW_ACT)) {
220 value = "chargeerrlow";
221 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
222 } else if (!strcmp(option, CHARGE_ERROR_HIGH_ACT)) {
223 value = "chargeerrhigh";
224 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
225 } else if (!strcmp(option, CHARGE_ERROR_OVP_ACT)) {
226 value = "chargeerrovp";
227 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
228 } else if (!strcmp(option, CHARGE_CHECK_ACT)) {
229 launched_poweroff = 0;
234 ret = vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &state);
235 if (state == 1 || ret != 0 || booting_done(NULL)) {
237 if (launched_poweroff == 1) {
238 _I("will be foreced power off");
243 if (lowbat_popup_option == LOWBAT_OPT_POWEROFF)
244 launched_poweroff = 1;
246 pid = get_exec_pid(LOWBAT_EXEC_PATH);
248 _I("pre launched %s destroy", LOWBAT_EXEC_PATH);
252 FIND_DEVICE_INT(apps, "apps");
254 params = malloc(sizeof(struct popup_data));
255 if (params == NULL) {
259 r_disturb = vconf_get_int("memory/shealth/sleep/do_not_disturb", &s_disturb);
260 r_block = vconf_get_bool("db/setting/blockmode_wearable", &s_block);
261 if ((r_disturb != 0 && r_block != 0) ||
262 (s_disturb == 0 && s_block == 0) ||
263 lowbat_popup_option == LOWBAT_OPT_CHARGEERR)
264 pm_change_internal(getpid(), LCD_NORMAL);
267 params->name = LOWBAT_POPUP_NAME;
268 params->key = POPUP_KEY_CONTENT;
269 params->value = strdup(value);
270 apps->init((void *)params);
274 _D("boot-animation running yet");
280 static int battery_check_act(void *data)
282 lowbat_popup(CHARGE_CHECK_ACT);
286 static int battery_warning_low_act(void *data)
288 lowbat_popup(WARNING_LOW_BAT_ACT);
292 static int battery_critical_low_act(void *data)
294 lowbat_popup(CRITICAL_LOW_BAT_ACT);
298 int battery_power_off_act(void *data)
300 vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, VCONFKEY_SYSMAN_POWER_OFF_DIRECT);
304 int battery_charge_err_act(void *data)
306 lowbat_popup(CHARGE_ERROR_ACT);
310 int battery_charge_err_low_act(void *data)
312 lowbat_popup(CHARGE_ERROR_LOW_ACT);
316 int battery_charge_err_high_act(void *data)
318 lowbat_popup(CHARGE_ERROR_HIGH_ACT);
322 int battery_charge_err_ovp_act(void *data)
324 lowbat_popup(CHARGE_ERROR_OVP_ACT);
328 static int battery_charge_act(void *data)
334 /* instead of adding action to the queue, execute it right here */
335 if (device_get_property(DEVTYPE_JACK, JACK_PROP_TA_ONLINE, &val) == 0
337 snprintf(argstr, 128, "-t 4");
338 launch_after_kill_if_exist(LOWBAT_EXEC_PATH, argstr);
344 static void lowbat_scenario_init(void)
346 lowbat_add_scenario(battery_info.normal, battery_info.warning, battery_warning_low_act);
347 lowbat_add_scenario(battery_info.warning, battery_info.critical, battery_critical_low_act);
348 lowbat_add_scenario(battery_info.poweroff, battery_info.realoff, battery_power_off_act);
349 lowbat_add_scenario(battery_info.normal, battery_info.critical, battery_critical_low_act);
350 lowbat_add_scenario(battery_info.warning, battery_info.poweroff, battery_critical_low_act);
351 lowbat_add_scenario(battery_info.critical, battery_info.realoff, battery_power_off_act);
352 lowbat_add_scenario(battery_info.normal, battery_info.poweroff, battery_critical_low_act);
353 lowbat_add_scenario(battery_info.warning, battery_info.realoff, battery_power_off_act);
354 lowbat_add_scenario(battery_info.normal, battery_info.realoff, battery_power_off_act);
355 lowbat_add_scenario(battery_info.realoff, battery_info.realoff, battery_power_off_act);
356 lowbat_add_scenario(battery_info.realoff, battery_info.normal, battery_check_act);
357 lowbat_add_scenario(battery_info.realoff, battery_info.warning, battery_check_act);
358 lowbat_add_scenario(battery_info.realoff, battery_info.critical, battery_check_act);
359 lowbat_add_scenario(battery_info.realoff, battery_info.poweroff, battery_check_act);
362 static void change_lowbat_level(int bat_percent)
366 if (cur_bat_capacity == bat_percent)
369 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, &prev) < 0) {
370 _E("vconf_get_int() failed");
375 if (bat_percent > BATTERY_LEVEL_CHECK_FULL) {
376 now = VCONFKEY_SYSMAN_BAT_LEVEL_FULL;
377 } else if (bat_percent > BATTERY_LEVEL_CHECK_HIGH) {
378 now = VCONFKEY_SYSMAN_BAT_LEVEL_HIGH;
379 } else if (bat_percent > BATTERY_LEVEL_CHECK_LOW) {
380 now = VCONFKEY_SYSMAN_BAT_LEVEL_LOW;
381 } else if (bat_percent > BATTERY_LEVEL_CHECK_CRITICAL) {
382 now = VCONFKEY_SYSMAN_BAT_LEVEL_CRITICAL;
384 now = VCONFKEY_SYSMAN_BAT_LEVEL_EMPTY;
388 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, now);
391 static int lowbat_process(int bat_percent, void *ad)
393 int new_bat_capacity;
395 int vconf_state = -1;
398 bool low_bat = false;
399 bool full_bat = false;
406 new_bat_capacity = bat_percent;
407 if (new_bat_capacity < 0)
409 change_lowbat_level(new_bat_capacity);
411 if (new_bat_capacity != cur_bat_capacity) {
412 _D("[BAT_MON] cur = %d new = %d", cur_bat_capacity, new_bat_capacity);
413 if (vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, new_bat_capacity) == 0)
414 cur_bat_capacity = new_bat_capacity;
417 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &vconf_state) < 0) {
418 _E("vconf_get_int() failed");
423 if (new_bat_capacity <= battery_info.realoff) {
424 if (battery.charge_now) {
425 new_bat_state = battery_info.poweroff;
426 if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
427 status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
429 new_bat_state = battery_info.realoff;
430 if (vconf_state != VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
431 status = VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF;
433 } else if (new_bat_capacity <= battery_info.poweroff) {
434 new_bat_state = battery_info.poweroff;
435 if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
436 status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
437 } else if (new_bat_capacity <= battery_info.critical) {
438 new_bat_state = battery_info.critical;
439 if (vconf_state != VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
440 status = VCONFKEY_SYSMAN_BAT_CRITICAL_LOW;
441 } else if (new_bat_capacity <= battery_info.warning) {
442 new_bat_state = battery_info.warning;
443 if (vconf_state != VCONFKEY_SYSMAN_BAT_WARNING_LOW)
444 status = VCONFKEY_SYSMAN_BAT_WARNING_LOW;
446 new_bat_state = battery_info.normal;
447 if (new_bat_capacity == BATTERY_FULL) {
448 if (battery.charge_full) {
449 if (vconf_state != VCONFKEY_SYSMAN_BAT_FULL)
450 status = VCONFKEY_SYSMAN_BAT_FULL;
453 if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
454 status = VCONFKEY_SYSMAN_BAT_NORMAL;
457 if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
458 status = VCONFKEY_SYSMAN_BAT_NORMAL;
464 lock = pm_lock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, STAY_CUR_STATE, 0);
465 ret = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, status);
466 power_supply_broadcast(CHARGE_LEVEL_SIGNAL, status);
467 if (update_pm_setting)
468 update_pm_setting(SETTING_LOW_BATT, status);
476 if (vconf_get_int(VCONFKEY_PM_KEY_IGNORE, &extreme) == 0 && extreme == TRUE &&
477 (status > VCONFKEY_SYSMAN_BAT_POWER_OFF && status <= VCONFKEY_SYSMAN_BAT_FULL))
478 if (vconf_set_int(VCONFKEY_PM_KEY_IGNORE, FALSE) == 0)
479 _I("release key ignore");
481 if (new_bat_capacity <= battery_info.warning)
484 device_notify(DEVICE_NOTIFIER_LOWBAT, (void*)low_bat);
486 if (cur_bat_state == new_bat_state && new_bat_state > battery_info.realoff)
489 if (cur_bat_state == BATTERY_UNKNOWN)
490 cur_bat_state = battery_info.normal;
491 result = lowbat_scenario(cur_bat_state, new_bat_state, NULL);
493 _I("cur %d, new %d(capacity %d)",
494 cur_bat_state, new_bat_state, bat_percent);
495 cur_bat_state = new_bat_state;
498 pm_unlock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
503 static int lowbat_read(void)
507 r = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CAPACITY, &bat_percent);
514 static int change_freq(char *option)
521 if (!strcmp(option, CHARGE_POWERSAVE_FREQ_ACT))
523 device_notify(DEVICE_NOTIFIER_PMQOS_LOWBAT, (void*)val);
527 static void change_lowbat_cpu_freq(int bat_percent)
529 static int init_cpu_freq = 0;
530 static int power_save = 0;
531 if (cur_bat_capacity == bat_percent)
534 if (bat_percent > battery_info.poweroff && init_cpu_freq == 0) {
536 change_freq(CHARGE_RELEASE_FREQ_ACT);
540 if (bat_percent <= battery_info.poweroff && power_save == 0) {
542 change_freq(CHARGE_POWERSAVE_FREQ_ACT);
543 } else if (power_save == 1) {
545 change_freq(CHARGE_RELEASE_FREQ_ACT);
549 static int check_lowbat_percent(int *pct)
553 bat_percent = lowbat_read();
554 if (bat_percent < 0) {
555 _E("[BATMON] Cannot read battery gage. stop read fuel gage");
558 if (bat_percent > 100)
560 change_lowbat_level(bat_percent);
561 change_lowbat_cpu_freq(bat_percent);
566 void lowbat_monitor(void *data)
570 r = lowbat_initialized(NULL);
575 r = check_lowbat_percent(&bat_percent);
579 bat_percent = *(int *)data;
580 print_lowbat_state(bat_percent);
581 lowbat_process(bat_percent, NULL);
584 /* for debugging (request by kernel) */
585 static int check_battery()
590 if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_PRESENT, &ret) < 0) {
591 _E("FAIL: device_get_property(): [BATMON] battery check : %d", ret);
593 _D("[BATMON] battery check : %d", ret);
598 static int check_power_save_mode(void)
601 int power_saving_cpu_stat = -1;
603 ret = vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_CPU,
604 &power_saving_cpu_stat);
606 _E("failed to get vconf key");
610 if (power_saving_cpu_stat == 1)
615 static int lowbat_monitor_init(void *data)
619 lowbat_initialized(&status);
620 unregister_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
621 battery_config_load(&battery_info);
622 _I("%d %d %d %d %d", battery_info.normal, battery_info.warning,
623 battery_info.critical, battery_info.poweroff, battery_info.realoff);
624 lowbat_scenario_init();
625 check_lowbat_percent(&battery.capacity);
626 lowbat_process(battery.capacity, NULL);
630 static void lowbat_init(void *data)
632 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
633 register_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
636 static void lowbat_exit(void *data)
640 lowbat_initialized(&status);
641 unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
644 static const struct device_ops lowbat_device_ops = {
645 .priority = DEVICE_PRIORITY_NORMAL,
651 DEVICE_OPS_REGISTER(&lowbat_device_ops)