diff options
Diffstat (limited to 'drivers/battery/samsung_battery.c')
-rw-r--r-- | drivers/battery/samsung_battery.c | 868 |
1 files changed, 691 insertions, 177 deletions
diff --git a/drivers/battery/samsung_battery.c b/drivers/battery/samsung_battery.c index d1cee8f..c63430b 100644 --- a/drivers/battery/samsung_battery.c +++ b/drivers/battery/samsung_battery.c @@ -31,9 +31,13 @@ #include <linux/workqueue.h> #include <linux/proc_fs.h> #include <linux/android_alarm.h> +#include <linux/regulator/machine.h> #include <linux/battery/samsung_battery.h> #include <mach/regs-pmu.h> #include "battery-factory.h" +#ifdef CONFIG_BATTERY_MAX77693_CHARGER +#include <linux/mfd/max77693-private.h> +#endif #if defined(CONFIG_S3C_ADC) #include <plat/adc.h> #endif @@ -45,8 +49,8 @@ static char *supply_list[] = { "battery", }; + #if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) -static bool battery_terminal_check_support(struct battery_info *info); static void battery_error_control(struct battery_info *info); #endif @@ -69,7 +73,9 @@ static int battery_get_cable(struct battery_info *info) { union power_supply_propval value; int cable_type = 0; - +#if defined(EXTENDED_ONLINE_TYPE) + int online_val; +#endif pr_debug("%s\n", __func__); mutex_lock(&info->ops_lock); @@ -78,7 +84,25 @@ static int battery_get_cable(struct battery_info *info) case CABLE_DET_CHARGER: info->psy_charger->get_property(info->psy_charger, POWER_SUPPLY_PROP_ONLINE, &value); + +#if defined(EXTENDED_ONLINE_TYPE) + /* | 31-24: RSVD | 23-16: MAIN TYPE | + 15-8: SUB TYPE | 7-0: POWER TYPE | */ + online_val = value.intval; + online_val &= ~(ONLINE_TYPE_RSVD_MASK); + cable_type = ((online_val & ONLINE_TYPE_MAIN_MASK) >> + ONLINE_TYPE_MAIN_SHIFT); + info->cable_sub_type = ((online_val & ONLINE_TYPE_SUB_MASK) >> + ONLINE_TYPE_SUB_SHIFT); + info->cable_pwr_type = ((online_val & ONLINE_TYPE_PWR_MASK) >> + ONLINE_TYPE_PWR_SHIFT); + pr_info("%s: main(%d), sub(%d), pwr(%d)\n", __func__, + cable_type, + info->cable_sub_type, + info->cable_pwr_type); +#else cable_type = value.intval; +#endif break; default: pr_err("%s: not support src(%d)\n", __func__, @@ -172,6 +196,117 @@ static int battery_get_temper(struct battery_info *info) return temper; } +#define ADC_REG_NAME "vcc_adc_1.8v" +static int battery_set_adc_power(struct battery_info *info, bool en) +{ + struct regulator *regulator; + int is_en; + int ret = 0; + pr_debug("%s\n", __func__); + + regulator = regulator_get(NULL, ADC_REG_NAME); + if (IS_ERR(regulator)) + return -ENODEV; + + is_en = regulator_is_enabled(regulator); + + if (is_en != en) + pr_info("%s: %s: is_en(%d), en(%d)\n", __func__, + ADC_REG_NAME, is_en, en); + + if (!is_en && en) + ret = regulator_enable(regulator); + else if (is_en && !en) + ret = regulator_force_disable(regulator); + + info->adc_pwr_st = en; + + regulator_put(regulator); + + return ret; +} + +static int battery_get_vf(struct battery_info *info) +{ + union power_supply_propval value; + int present = 0; + int adc; + pr_debug("%s\n", __func__); + + if (info->factory_mode) { + pr_debug("%s: No need to check battery in factory mode\n", + __func__); + return 1; + } + + mutex_lock(&info->ops_lock); + + switch (info->pdata->vf_det_src) { + case VF_DET_ADC: +#if defined(CONFIG_S3C_ADC) + if (info->pdata->vf_det_src == VF_DET_ADC) + battery_set_adc_power(info, 1); + adc = s3c_adc_read(info->adc_client, info->pdata->vf_det_ch); + if (info->pdata->vf_det_src == VF_DET_ADC) + battery_set_adc_power(info, 0); +#else + adc = 350; /* temporary value */ +#endif + info->battery_vf_adc = adc; + present = INRANGE(adc, info->pdata->vf_det_th_l, + info->pdata->vf_det_th_h); + if (!present) + pr_info("%s: adc(%d), out of range(%d ~ %d)\n", + __func__, adc, + info->pdata->vf_det_th_l, + info->pdata->vf_det_th_h); + break; + case VF_DET_CHARGER: + info->psy_charger->get_property(info->psy_charger, + POWER_SUPPLY_PROP_PRESENT, &value); + present = value.intval; + break; + case VF_DET_GPIO: + present = !gpio_get_value(info->batdet_gpio); + break; + default: + pr_err("%s: not support src(%d)\n", __func__, + info->pdata->vf_det_src); + present = 1; /* always detected */ + break; + } + + pr_debug("%s: present(%d)\n", __func__, present); + + mutex_unlock(&info->ops_lock); + return present; +} + +/* judge power off or not by current_avg */ +static int battery_get_curr_avg(struct battery_info *info) +{ + int curr_avg; + pr_debug("%s\n", __func__); + + /* if 0% && under min voltage && low power charging, power off */ + if ((info->battery_soc <= PWROFF_SOC) && + (info->battery_vcell < info->pdata->voltage_min) && + (info->battery_v_diff < 0) && + (info->input_current < info->pdata->chg_curr_ta)) { + pr_info("%s: soc(%d), vol(%d < %d), diff(%d), in_curr(%d)\n", + __func__, info->battery_soc, + (info->battery_vcell / 1000), + (info->pdata->voltage_min / 1000), + info->battery_v_diff, + info->input_current); + curr_avg = -1; + } else { + curr_avg = info->input_current; + } + + return curr_avg; +} + /* Get info from power supply at realtime */ int battery_get_info(struct battery_info *info, enum power_supply_property property) @@ -194,15 +329,15 @@ int battery_get_info(struct battery_info *info, case POWER_SUPPLY_PROP_STATUS: case POWER_SUPPLY_PROP_CHARGE_TYPE: case POWER_SUPPLY_PROP_HEALTH: - case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_CURRENT_MAX: case POWER_SUPPLY_PROP_CURRENT_NOW: -#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) case POWER_SUPPLY_PROP_CHARGE_FULL: -#endif info->psy_charger->get_property(info->psy_charger, property, &value); break; + case POWER_SUPPLY_PROP_PRESENT: + value.intval = battery_get_vf(info); + break; case POWER_SUPPLY_PROP_ONLINE: value.intval = battery_get_cable(info); break; @@ -212,6 +347,10 @@ int battery_get_info(struct battery_info *info, info->psy_fuelgauge->get_property(info->psy_fuelgauge, property, &value); break; + /* Update current_avg */ + case POWER_SUPPLY_PROP_CURRENT_AVG: + value.intval = battery_get_curr_avg(info); + break; /* Update from fuelgauge or adc */ case POWER_SUPPLY_PROP_TEMP: value.intval = battery_get_temper(info); @@ -230,7 +369,10 @@ void battery_update_info(struct battery_info *info) int temper; /* Update from Charger */ - info->cable_type = battery_get_cable(info); + if (info->slate_mode) + info->cable_type = POWER_SUPPLY_TYPE_BATTERY; + else + info->cable_type = battery_get_cable(info); info->psy_charger->get_property(info->psy_charger, POWER_SUPPLY_PROP_STATUS, &value); @@ -254,9 +396,7 @@ void battery_update_info(struct battery_info *info) info->battery_health = value.intval; #endif - info->psy_charger->get_property(info->psy_charger, - POWER_SUPPLY_PROP_PRESENT, &value); - info->battery_present = value.intval; + info->battery_present = battery_get_vf(info); info->psy_charger->get_property(info->psy_charger, POWER_SUPPLY_PROP_CURRENT_NOW, &value); @@ -275,7 +415,7 @@ void battery_update_info(struct battery_info *info) /* Fuelgauge power off state */ if ((info->cable_type != POWER_SUPPLY_TYPE_BATTERY) && - (info->battery_present == 0)) { + (info->battery_present == 0) && (info->monitor_count)) { pr_info("%s: abnormal fuelgauge power state\n", __func__); goto update_finish; } @@ -321,10 +461,16 @@ void battery_update_info(struct battery_info *info) info->battery_t_delta = temper - info->battery_temper; info->battery_temper = temper; + /* update current_avg later */ + info->charge_current_avg = battery_get_curr_avg(info); + update_finish: switch (info->battery_error_test) { case 0: pr_debug("%s: error test: not test modde\n", __func__); +#if defined(CONFIG_TARGET_LOCALE_KOR) + info->errortest_stopcharging = false; +#endif break; case 1: pr_info("%s: error test: full charged\n", __func__); @@ -346,12 +492,17 @@ update_finish: pr_info("%s: error test: vf error\n", __func__); info->battery_present = 0; break; +#if defined(CONFIG_TARGET_LOCALE_KOR) + case 6: + info->errortest_stopcharging = true; + break; +#endif default: pr_info("%s: error test: unknown state\n", __func__); break; } - pr_info("%s: state(%d), type(%d), " + pr_debug("%s: state(%d), type(%d), " "health(%d), present(%d), " "cable(%d), curr(%d), " "soc(%d), raw(%d), " @@ -396,22 +547,99 @@ void battery_control_info(struct battery_info *info, } } -static void samsung_battery_alarm_start(struct alarm *alarm) +static void battery_event_alarm(struct alarm *alarm) { struct battery_info *info = container_of(alarm, struct battery_info, - alarm); - pr_debug("%s\n", __func__); + event_alarm); + pr_info("%s: exit event state, %ds gone\n", __func__, + info->pdata->event_time); + + /* clear event state */ + info->event_state = EVENT_STATE_CLEAR; wake_lock(&info->monitor_wake_lock); schedule_work(&info->monitor_work); } +void battery_event_control(struct battery_info *info) +{ + int event_num; + ktime_t interval, next, slack; + /* sync with event_type in samsung_battery.h */ + char *event_type_name[] = { "WCDMA CALL", "GSM CALL", "CALL", + "VIDEO", "MUSIC", "BROWSER", + "HOTSPOT", "CAMERA", "DATA CALL", + "GPS", "LTE", "WIFI", + "USE", "UNKNOWN" + }; + + pr_debug("%s\n", __func__); + + if (info->event_type) { + pr_info("%s: in event state(%d), type(0x%04x)\n", __func__, + info->event_state, info->event_type); + + for (event_num = 0; event_num < EVENT_TYPE_MAX; event_num++) { + if (info->event_type & (1 << event_num)) + pr_info("%s: %d: %s\n", __func__, event_num, + event_type_name[event_num]); + } + + if (info->event_state == EVENT_STATE_SET) { + pr_info("%s: event already set, event(%d, 0x%04x)\n", + __func__, info->event_state, info->event_type); + } else if (info->event_state == EVENT_STATE_IN_TIMER) { + pr_info("%s: cancel event timer\n", __func__); + + alarm_cancel(&info->event_alarm); + + info->event_state = EVENT_STATE_SET; + + wake_lock(&info->monitor_wake_lock); + schedule_work(&info->monitor_work); + } else { + pr_info("%s: enter event state(%d, 0x%04x)\n", + __func__, info->event_state, info->event_type); + + info->event_state = EVENT_STATE_SET; + + wake_lock(&info->monitor_wake_lock); + schedule_work(&info->monitor_work); + } + } else { + pr_info("%s: clear event type(0x%04x), wait %ds\n", __func__, + info->event_type, info->pdata->event_time); + + if (info->event_state == EVENT_STATE_SET) { + pr_info("%s: start event timer\n", __func__); + info->last_poll = alarm_get_elapsed_realtime(); + + interval = ktime_set(info->pdata->event_time, 0); + next = ktime_add(info->last_poll, interval); + slack = ktime_set(20, 0); + + alarm_start_range(&info->event_alarm, next, + ktime_add(next, slack)); + + info->event_state = EVENT_STATE_IN_TIMER; + } else { + pr_info("%s: event already clear, event(%d, 0x%04x)\n", + __func__, info->event_state, info->event_type); + } + } +} + static void battery_notify_full_state(struct battery_info *info) { union power_supply_propval value; + pr_debug("%s: r(%d), f(%d), rs(%d), fs(%d), s(%d)\n", __func__, + info->recharge_phase, info->full_charged_state, + info->battery_raw_soc, info->battery_full_soc, + info->battery_soc); if ((info->recharge_phase && info->full_charged_state) || - ((info->battery_raw_soc > info->battery_full_soc) && + ((info->charge_real_state != POWER_SUPPLY_STATUS_DISCHARGING) && + (info->battery_raw_soc > info->battery_full_soc) && (info->battery_soc == 100))) { /* notify full state to fuel guage */ value.intval = POWER_SUPPLY_STATUS_FULL; @@ -420,6 +648,16 @@ static void battery_notify_full_state(struct battery_info *info) } } +static void battery_monitor_alarm(struct alarm *alarm) +{ + struct battery_info *info = container_of(alarm, struct battery_info, + monitor_alarm); + pr_debug("%s\n", __func__); + + wake_lock(&info->monitor_wake_lock); + schedule_work(&info->monitor_work); +} + static void battery_monitor_interval(struct battery_info *info) { ktime_t interval, next, slack; @@ -454,6 +692,10 @@ static void battery_monitor_interval(struct battery_info *info) break; } + /* 5 times after boot, apply no interval (1 sec) */ + if (info->monitor_count < 5) + info->monitor_interval = 1; + /* apply monitor interval weight */ if (info->monitor_weight != 100) { pr_info("%s: apply weight(%d), %d -> %d\n", __func__, @@ -470,7 +712,7 @@ static void battery_monitor_interval(struct battery_info *info) next = ktime_add(info->last_poll, interval); slack = ktime_set(20, 0); - alarm_start_range(&info->alarm, next, ktime_add(next, slack)); + alarm_start_range(&info->monitor_alarm, next, ktime_add(next, slack)); local_irq_restore(flags); } @@ -503,8 +745,12 @@ static bool battery_abstimer_cond(struct battery_info *info) struct timespec current_time; pr_debug("%s\n", __func__); + /* always update time for info data */ + ktime = alarm_get_elapsed_realtime(); + info->current_time = current_time = ktime_to_timespec(ktime); + if ((info->cable_type == POWER_SUPPLY_TYPE_USB) || - (info->full_charged_state == true) || + (info->full_charged_state != STATUS_NOT_FULL) || (info->charge_start_time == 0)) { pr_debug("%s: not abstimer state, cb(%d), f(%d), t(%d)\n", __func__, info->cable_type, @@ -514,9 +760,6 @@ static bool battery_abstimer_cond(struct battery_info *info) return false; } - ktime = alarm_get_elapsed_realtime(); - current_time = ktime_to_timespec(ktime); - if (info->recharge_phase) { abstimer_duration = info->pdata->abstimer_recharge_duration; } else { @@ -534,6 +777,7 @@ static bool battery_abstimer_cond(struct battery_info *info) (int)current_time.tv_sec, info->charge_start_time, abstimer_duration); info->abstimer_state = true; + info->abstimer_active = (int)current_time.tv_sec; } else { pr_debug("%s: not abstimer state, t(%d - %d ?? %d)\n", __func__, (int)current_time.tv_sec, info->charge_start_time, @@ -548,10 +792,11 @@ static bool battery_fullcharged_cond(struct battery_info *info) { int f_cond_soc; int f_cond_vcell; + int full_state; pr_debug("%s\n", __func__); - /* max voltage - 50mV */ - f_cond_vcell = info->pdata->voltage_max - 50000; + /* max voltage - RECHG_DROP_VALUE: recharge voltage */ + f_cond_vcell = info->pdata->voltage_max - RECHG_DROP_VALUE; /* max soc - 5% */ f_cond_soc = 95; @@ -566,10 +811,32 @@ static bool battery_fullcharged_cond(struct battery_info *info) pr_info("%s: real full charged, v(%d), s(%d)\n", __func__, info->battery_vcell, info->battery_soc); - info->full_charged_state = true; +#if defined(USE_2STEP_TERM) + full_state = battery_get_info(info, + POWER_SUPPLY_PROP_CHARGE_FULL); + if (!full_state) { + if (info->full_charged_state != STATUS_1ST_FULL) + pr_info("%s: 1st full by current\n", + __func__); + + info->full_charged_state = STATUS_1ST_FULL; + + return false; + } else { + if (info->full_charged_state != STATUS_2ND_FULL) + pr_info("%s: 2nd full by timer\n", + __func__); + + info->full_charged_state = STATUS_2ND_FULL; + + return true; + } +#else + info->full_charged_state = STATUS_1ST_FULL; return true; +#endif } else { - pr_info("%s: charger full charged, v(%d), s(%d)\n", + pr_info("%s: not real full charged, v(%d), s(%d)\n", __func__, info->battery_vcell, info->battery_soc); @@ -587,13 +854,13 @@ static bool battery_fullcharged_cond(struct battery_info *info) POWER_SUPPLY_PROP_STATUS); return false; } - } else if (info->full_charged_state == true) { + } else if (info->full_charged_state != STATUS_NOT_FULL) { pr_debug("%s: already full charged, v(%d), s(%d)\n", __func__, info->battery_vcell, info->battery_soc); } else { pr_debug("%s: not full charged, v(%d), s(%d)\n", __func__, info->battery_vcell, info->battery_soc); - info->full_charged_state = false; + info->full_charged_state = STATUS_NOT_FULL; } return false; @@ -645,7 +912,6 @@ static bool battery_health_cond(struct battery_info *info) #if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) if (info->cable_type == POWER_SUPPLY_TYPE_BATTERY) { info->health_state = false; - info->is_unspec_phase = false; return false; } #endif @@ -681,10 +947,6 @@ static bool battery_health_cond(struct battery_info *info) info->battery_health); info->health_state = false; -#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) - if (battery_terminal_check_support(info)) - pr_err("%s: health support, error state!\n", __func__); -#endif } return info->health_state; @@ -692,8 +954,41 @@ static bool battery_health_cond(struct battery_info *info) static bool battery_temper_cond(struct battery_info *info) { + int ovh_stop, ovh_recover; + int frz_stop, frz_recover; pr_debug("%s\n", __func__); + /* update overheat temperature threshold */ + if ((info->pdata->ctia_spec == true) && (info->lpm_state)) { + ovh_stop = info->pdata->lpm_overheat_stop_temp; + ovh_recover = info->pdata->lpm_overheat_recovery_temp; + frz_stop = info->pdata->lpm_freeze_stop_temp; + frz_recover = info->pdata->lpm_freeze_recovery_temp; + } else if ((info->pdata->ctia_spec == true) && + (info->event_state != EVENT_STATE_CLEAR)) { + ovh_stop = info->pdata->event_overheat_stop_temp; + ovh_recover = info->pdata->event_overheat_recovery_temp; + frz_stop = info->pdata->event_freeze_stop_temp; + frz_recover = info->pdata->event_freeze_recovery_temp; + pr_info("%s: ovh(%d/%d), frz(%d/%d), lpm(%d), " + "event(%d, 0x%04x)\n", __func__, + ovh_stop, ovh_recover, frz_stop, frz_recover, + info->lpm_state, info->event_state, info->event_type); + } else { + ovh_stop = info->pdata->overheat_stop_temp; + ovh_recover = info->pdata->overheat_recovery_temp; + frz_stop = info->pdata->freeze_stop_temp; + frz_recover = info->pdata->freeze_recovery_temp; + } + +#if defined(CONFIG_MACH_T0_USA_SPR) + /* unver rev0.7, do not stop charging by tempereture */ + if (system_rev < 7) { + ovh_stop = info->battery_temper + 1; + frz_stop = info->battery_temper - 1; + } +#endif + if (info->temper_state == false) { if (info->charge_real_state != POWER_SUPPLY_STATUS_CHARGING) { pr_debug("%s: r_state !charging, cs(%d)\n", @@ -703,21 +998,15 @@ static bool battery_temper_cond(struct battery_info *info) pr_debug("%s: check charging stop temper " "cond: %d ?? %d ~ %d\n", __func__, - info->battery_temper, - info->pdata->freeze_stop_temp, - info->pdata->overheat_stop_temp); + info->battery_temper, frz_stop, ovh_stop); - if (info->battery_temper >= - info->pdata->overheat_stop_temp) { + if (info->battery_temper >= ovh_stop) { pr_info("%s: stop by overheated, t(%d ? %d)\n", - __func__, info->battery_temper, - info->pdata->overheat_stop_temp); + __func__, info->battery_temper, ovh_stop); info->overheated_state = true; - } else if (info->battery_temper <= - info->pdata->freeze_stop_temp) { - pr_info("%s: stop by overheated, t(%d ? %d)\n", - __func__, info->battery_temper, - info->pdata->freeze_stop_temp); + } else if (info->battery_temper <= frz_stop) { + pr_info("%s: stop by freezed, t(%d ? %d)\n", + __func__, info->battery_temper, frz_stop); info->freezed_state = true; } else pr_debug("%s: normal charging, t(%d)\n", __func__, @@ -725,23 +1014,17 @@ static bool battery_temper_cond(struct battery_info *info) } else { pr_debug("%s: check charging recovery temper " "cond: %d ?? %d ~ %d\n", __func__, - info->battery_temper, - info->pdata->freeze_recovery_temp, - info->pdata->overheat_recovery_temp); + info->battery_temper, frz_recover, ovh_recover); if ((info->overheated_state == true) && - (info->battery_temper <= - info->pdata->overheat_recovery_temp)) { + (info->battery_temper <= ovh_recover)) { pr_info("%s: recovery from overheated, t(%d ? %d)\n", - __func__, info->battery_temper, - info->pdata->overheat_recovery_temp); + __func__, info->battery_temper, ovh_recover); info->overheated_state = false; } else if ((info->freezed_state == true) && - (info->battery_temper >= - info->pdata->freeze_recovery_temp)) { + (info->battery_temper >= frz_recover)) { pr_info("%s: recovery from freezed, t(%d ? %d)\n", - __func__, info->battery_temper, - info->pdata->freeze_recovery_temp); + __func__, info->battery_temper, frz_recover); info->freezed_state = false; } else pr_info("%s: charge stopped, t(%d)\n", __func__, @@ -781,17 +1064,38 @@ static void battery_charge_control(struct battery_info *info, ktime = alarm_get_elapsed_realtime(); current_time = ktime_to_timespec(ktime); - if ((chg_curr != 0) && (info->siop_state == true)) { - pr_info("%s: siop state, charge current is %dmA\n", __func__, - info->siop_charge_current); - chg_curr = info->siop_charge_current; + if ((info->cable_type != POWER_SUPPLY_TYPE_BATTERY) && + (chg_curr > 0) && (info->siop_state == true)) { + + switch (info->siop_lv) { + case SIOP_LV1: + info->siop_charge_current = + info->pdata->chg_curr_siop_lv1; + break; + case SIOP_LV2: + info->siop_charge_current = + info->pdata->chg_curr_siop_lv2; + break; + case SIOP_LV3: + info->siop_charge_current = + info->pdata->chg_curr_siop_lv3; + break; + default: + info->siop_charge_current = + info->pdata->chg_curr_usb; + break; + } + + chg_curr = MIN(chg_curr, info->siop_charge_current); + pr_info("%s: siop state, level(%d), cc(%d)\n", + __func__, info->siop_lv, chg_curr); } if (in_curr == KEEP_CURR) goto charge_current_con; /* input current limit */ - in_curr = min(in_curr, info->pdata->in_curr_limit); + in_curr = MIN(in_curr, info->pdata->in_curr_limit); /* check charge input before and after */ if (info->input_current == ((in_curr / 20) * 20)) { @@ -843,7 +1147,7 @@ charge_state_con: battery_control_info(info, POWER_SUPPLY_PROP_STATUS, ENABLE); info->charge_start_time = current_time.tv_sec; - pr_err("%s: charge enabled, current as %d/%dmA @%d\n", + pr_info("%s: charge enabled, current as %d/%dmA @%d\n", __func__, info->charge_current, info->input_current, info->charge_start_time); @@ -863,7 +1167,7 @@ charge_state_con: } else if ((chg_curr == 0) && (info->charge_start_time != 0)) { battery_control_info(info, POWER_SUPPLY_PROP_STATUS, DISABLE); - pr_err("%s: charge disabled, current as %d/%dmA @%d\n", + pr_info("%s: charge disabled, current as %d/%dmA @%d\n", __func__, info->charge_current, info->input_current, (int)current_time.tv_sec); @@ -905,13 +1209,17 @@ charge_state_con: static void battery_indicator_icon(struct battery_info *info) { if (info->cable_type != POWER_SUPPLY_TYPE_BATTERY) { - if (info->full_charged_state == true) { + if (info->full_charged_state != STATUS_NOT_FULL) { info->charge_virt_state = POWER_SUPPLY_STATUS_FULL; info->battery_soc = 100; - } else if (info->abstimer_state == true) { - info->charge_virt_state = - POWER_SUPPLY_STATUS_CHARGING; + } else if (info->abstimer_active) { + if (info->battery_soc == 100) + info->charge_virt_state = + POWER_SUPPLY_STATUS_FULL; + else + info->charge_virt_state = + POWER_SUPPLY_STATUS_CHARGING; } else if (info->recharge_phase == true) { info->charge_virt_state = POWER_SUPPLY_STATUS_CHARGING; @@ -1005,7 +1313,8 @@ static void battery_interval_calulation(struct battery_info *info) } /* prevent critical low voltage factor */ - if ((info->battery_vcell < (info->pdata->voltage_min - 100000)) || + if ((info->battery_vcell < + (info->pdata->voltage_min - PWROFF_MARGIN)) || (info->battery_vfocv < info->pdata->voltage_min)) { pr_info("%s: voltage(%d) too low state\n", __func__, info->battery_vcell); @@ -1053,16 +1362,16 @@ static void battery_interval_calulation(struct battery_info *info) if (info->lpm_state == true) info->monitor_weight *= 2; - /* 2 times after boot(about 1min), apply charging interval(30sec) */ - if (info->monitor_count < 2) { - pr_info("%s: now in booting, set 30s\n", __func__); - info->monitor_mode = MONITOR_EMER_LV1; + /* 5 times after boot, apply no interval (1 sec) */ + if (info->monitor_count < 5) { + pr_info("%s: now in booting, set 1s\n", __func__); + info->monitor_mode = MONITOR_EMER_LV1; /* dummy value */ return; } /* * prevent low voltage phase - * default, vcell is lower than min_voltage + 50mV, -20% + * default, vcell is lower than min_voltage + 50mV, -30% */ if (info->battery_vcell < (info->pdata->voltage_min + 50000)) { info->monitor_mode = MONITOR_EMER_LV1; @@ -1147,10 +1456,16 @@ static void battery_monitor_work(struct work_struct *work) { struct battery_info *info = container_of(work, struct battery_info, monitor_work); + int muic_cb_typ; pr_debug("%s\n", __func__); mutex_lock(&info->mon_lock); + if (info->battery_test_mode) { + pr_info("%s: now in test mode, not updated\n", __func__); + goto monitor_finish; + } + #if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) /* first, check cable-type */ info->cable_type = battery_get_cable(info); @@ -1163,8 +1478,9 @@ static void battery_monitor_work(struct work_struct *work) info->overheated_state = false; info->freezed_state = false; info->temper_state = false; - info->full_charged_state = false; + info->full_charged_state = STATUS_NOT_FULL; info->abstimer_state = false; + info->abstimer_active = false; info->recharge_phase = false; #if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) @@ -1184,28 +1500,25 @@ static void battery_monitor_work(struct work_struct *work) /* Check battery state from charger and fuelgauge */ battery_update_info(info); -#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) - /* check unspec recovery */ - if (info->is_unspec_phase) { - if ((info->battery_health != - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) && - (battery_terminal_check_support(info) == false)) { - pr_info("%s: recover from unspec phase!\n", __func__); - info->is_unspec_recovery = true; + /* adc ldo , vf irq control */ + if (info->pdata->vf_det_src == VF_DET_GPIO) { + if (info->cable_type == POWER_SUPPLY_TYPE_BATTERY) { + if (info->batdet_irq_st) { + disable_irq(info->batdet_irq); + info->batdet_irq_st = false; + } + if (info->adc_pwr_st) + battery_set_adc_power(info, 0); + } else { + if (!info->adc_pwr_st) + battery_set_adc_power(info, 1); + if (!info->batdet_irq_st) { + enable_irq(info->batdet_irq); + info->batdet_irq_st = true; + } } } - /* If it's recovery phase from unspec state, go to charge_ok */ - if (info->is_unspec_recovery) { - pr_info("%s: recovered from unspec phase" - ": re-setting charge current!\n", __func__); - battery_charge_control(info, OFF_CURR, OFF_CURR); - info->is_unspec_recovery = false; - info->is_unspec_phase = false; - goto charge_ok; - } -#endif - /* if battery is missed state, do not check charge scenario */ if (info->battery_present == 0) goto monitor_finish; @@ -1215,6 +1528,14 @@ static void battery_monitor_work(struct work_struct *work) goto charge_ok; /* Below is charger is connected state */ +#if defined(CONFIG_TARGET_LOCALE_KOR) + if (info->errortest_stopcharging) { + pr_info("%s: charge stopped by error_test mode\n", __func__); + battery_charge_control(info, OFF_CURR, OFF_CURR); + goto monitor_finish; + } +#endif + if (battery_temper_cond(info) == true) { pr_info("%s: charge stopped by temperature\n", __func__); battery_charge_control(info, OFF_CURR, OFF_CURR); @@ -1246,7 +1567,9 @@ static void battery_monitor_work(struct work_struct *work) } charge_ok: +#if defined(CONFIG_MACH_GC1) pr_err("%s: Updated Cable State(%d)\n", __func__, info->cable_type); +#endif switch (info->cable_type) { case POWER_SUPPLY_TYPE_BATTERY: if (!info->pdata->suspend_chging) @@ -1257,15 +1580,16 @@ charge_ok: info->overheated_state = false; info->freezed_state = false; info->temper_state = false; - info->full_charged_state = false; + info->full_charged_state = STATUS_NOT_FULL; info->abstimer_state = false; + info->abstimer_active = false; info->recharge_phase = false; break; case POWER_SUPPLY_TYPE_MAINS: if (!info->pdata->suspend_chging) wake_lock(&info->charge_wake_lock); battery_charge_control(info, info->pdata->chg_curr_ta, - info->pdata->chg_curr_ta); + info->pdata->in_curr_limit); break; case POWER_SUPPLY_TYPE_USB: if (!info->pdata->suspend_chging) @@ -1282,8 +1606,45 @@ charge_ok: case POWER_SUPPLY_TYPE_DOCK: if (!info->pdata->suspend_chging) wake_lock(&info->charge_wake_lock); - battery_charge_control(info, info->pdata->chg_curr_dock, - info->pdata->chg_curr_dock); + muic_cb_typ = max77693_muic_get_charging_type(); + switch (muic_cb_typ) { + case CABLE_TYPE_AUDIODOCK_MUIC: + pr_info("%s: audio dock, %d\n", + __func__, DOCK_TYPE_AUDIO_CURR); + battery_charge_control(info, + DOCK_TYPE_AUDIO_CURR, + DOCK_TYPE_AUDIO_CURR); + break; + case CABLE_TYPE_SMARTDOCK_TA_MUIC: + if (info->cable_sub_type == ONLINE_SUB_TYPE_SMART_OTG) { + pr_info("%s: smart dock ta & host, %d\n", + __func__, DOCK_TYPE_SMART_OTG_CURR); + battery_charge_control(info, + DOCK_TYPE_SMART_OTG_CURR, + DOCK_TYPE_SMART_OTG_CURR); + } else { + pr_info("%s: smart dock ta & no host, %d\n", + __func__, DOCK_TYPE_SMART_NOTG_CURR); + battery_charge_control(info, + DOCK_TYPE_SMART_NOTG_CURR, + DOCK_TYPE_SMART_NOTG_CURR); + } + break; + case CABLE_TYPE_SMARTDOCK_USB_MUIC: + pr_info("%s: smart dock usb(low), %d\n", + __func__, DOCK_TYPE_LOW_CURR); + battery_charge_control(info, + DOCK_TYPE_LOW_CURR, + DOCK_TYPE_LOW_CURR); + break; + default: + pr_info("%s: general dock, %d\n", + __func__, info->pdata->chg_curr_dock); + battery_charge_control(info, + info->pdata->chg_curr_dock, + info->pdata->chg_curr_dock); + break; + } break; case POWER_SUPPLY_TYPE_WIRELESS: if (!info->pdata->suspend_chging) @@ -1299,6 +1660,7 @@ monitor_finish: /* icon indicator */ battery_indicator_icon(info); + /* nofify full state to fuelgauge */ battery_notify_full_state(info); /* dynamic battery polling interval */ @@ -1311,29 +1673,48 @@ monitor_finish: if (info->pdata->led_indicator == true) battery_indicator_led(info); - pr_info("[%d] bat: s(%d, %d), v(%d, %d), b(%d), " - "t(%d.%d), h(%d), " - "cs(%d, %d), cb(%d), cr(%d, %d), " - "a(%d), f(%d), r(%d), t(%d)\n", + power_supply_changed(&info->psy_bat); + + pr_info("[%d] bat: s(%d, %d), v(%d, %d), " + "t(%d.%d), " + "cs(%d, %d), cb(%d), cr(%d, %d)", ++info->monitor_count, info->battery_soc, info->battery_r_s_delta, info->battery_vcell / 1000, info->battery_v_diff / 1000, - info->battery_present, info->battery_temper / 10, info->battery_temper % 10, - info->battery_health, info->charge_real_state, info->charge_virt_state, info->cable_type, info->charge_current, - info->input_current, - info->abstimer_state, - info->full_charged_state, - info->recharge_phase, - info->charge_start_time); + info->input_current); - power_supply_changed(&info->psy_bat); + if (info->battery_present == 0) + pr_cont(", b(%d)", info->battery_present); + if (info->battery_health != POWER_SUPPLY_HEALTH_GOOD) + pr_cont(", h(%d)", info->battery_health); + if (info->abstimer_state == 1) + pr_cont(", a(%d)", info->abstimer_state); + if (info->abstimer_active) + pr_cont(", aa(%d)", info->abstimer_active); + if (info->full_charged_state != STATUS_NOT_FULL) + pr_cont(", f(%d)", info->full_charged_state); + if (info->recharge_phase == 1) + pr_cont(", r(%d)", info->recharge_phase); + if (info->charge_start_time != 0) + pr_cont(", t(%d)", ((int)info->current_time.tv_sec - + info->charge_start_time)); + if (info->event_state != EVENT_STATE_CLEAR) + pr_cont(", e(%d, 0x%04x)", info->event_state, info->event_type); + if (info->siop_state) + pr_cont(", op(%d, %d)", info->siop_state, info->siop_lv); + + pr_cont("\n"); + + /* check current_avg */ + if (info->charge_current_avg < 0) + pr_info("%s: charging but discharging, power off\n", __func__); #if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) /* prevent suspend for ui-update */ @@ -1429,35 +1810,6 @@ static void battery_error_work(struct work_struct *work) } #if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) -static bool battery_terminal_check_support(struct battery_info *info) -{ - int full_mode; - int vcell; - bool ret = false; - pr_debug("%s\n", __func__); - - full_mode = battery_get_info(info, POWER_SUPPLY_PROP_CHARGE_FULL); - vcell = battery_get_info(info, POWER_SUPPLY_PROP_VOLTAGE_NOW); - pr_debug("%s: chg_status = %d, vcell = %d\n", - __func__, full_mode, vcell); - - if (full_mode && (vcell <= 3800000)) { - pr_info("%s: top-off or done mode, but low voltage(%d)\n", - __func__, vcell / 1000); - /* check again */ - vcell = battery_get_info(info, POWER_SUPPLY_PROP_VOLTAGE_NOW); - if (vcell <= 3800000) { - pr_info("%s: top-off or done mode, but low voltage(%d), " - "set health error!\n", - __func__, vcell / 1000); - info->health_state = true; - ret = true; - } - } - - return ret; -} - static void battery_error_control(struct battery_info *info) { pr_info("%s\n", __func__); @@ -1478,21 +1830,12 @@ static void battery_error_control(struct battery_info *info) POWER_SUPPLY_STATUS_NOT_CHARGING; } } else if (info->health_state == true) { - if ((info->battery_health == - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) || - battery_terminal_check_support(info)) { - pr_info("%s: battery unspec, " - "disable charging and off the " - "system path!\n", __func__); - - /* invalid top-off state, - assume terminals(+/-) open */ - battery_charge_control(info, OFF_CURR, OFF_CURR); - pr_info("%s: set unspec phase!\n", __func__); - info->is_unspec_phase = true; - } else if (info->battery_health == + if (info->battery_health == POWER_SUPPLY_HEALTH_OVERVOLTAGE) pr_info("%s: vbus ovp state!", __func__); + else if (info->battery_health == + POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) + pr_info("%s: uspec state from charger", __func__); } return; @@ -1512,7 +1855,15 @@ static enum power_supply_property samsung_battery_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_AVG, +#ifdef CONFIG_SLP + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, +#endif POWER_SUPPLY_PROP_CAPACITY, +#ifdef CONFIG_SLP + POWER_SUPPLY_PROP_CAPACITY_RAW, +#endif POWER_SUPPLY_PROP_TEMP, }; @@ -1556,9 +1907,29 @@ static int samsung_battery_get_property(struct power_supply *ps, case POWER_SUPPLY_PROP_CURRENT_NOW: val->intval = info->charge_current; break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = info->charge_current_avg; + break; case POWER_SUPPLY_PROP_CAPACITY: val->intval = info->battery_soc; break; +#ifdef CONFIG_SLP + case POWER_SUPPLY_PROP_CAPACITY_RAW: + val->intval = info->battery_raw_soc; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + if (info->full_charged_state) + val->intval = true; + else + val->intval = false; + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + if (info->charge_real_state == POWER_SUPPLY_STATUS_CHARGING) + val->intval = true; + else + val->intval = false; + break; +#endif case POWER_SUPPLY_PROP_TEMP: val->intval = info->battery_temper; break; @@ -1590,21 +1961,59 @@ static int samsung_battery_set_property(struct power_supply *ps, return 0; } - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - case POWER_SUPPLY_PROP_CHARGE_TYPE: - case POWER_SUPPLY_PROP_HEALTH: - case POWER_SUPPLY_PROP_PRESENT: - case POWER_SUPPLY_PROP_ONLINE: - case POWER_SUPPLY_PROP_TECHNOLOGY: - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - case POWER_SUPPLY_PROP_CURRENT_MAX: - case POWER_SUPPLY_PROP_CURRENT_NOW: - case POWER_SUPPLY_PROP_CAPACITY: - case POWER_SUPPLY_PROP_TEMP: - break; - default: - return -EINVAL; + if (info->battery_test_mode) { + pr_info("%s: set test value: psp(%d), val(%d)\n", + __func__, psp, val->intval); + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + info->charge_virt_state = val->intval; + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + info->charge_type = val->intval; + break; + case POWER_SUPPLY_PROP_HEALTH: + info->battery_health = val->intval; + break; + case POWER_SUPPLY_PROP_PRESENT: + info->battery_present = val->intval; + break; + case POWER_SUPPLY_PROP_ONLINE: + info->cable_type = val->intval; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + info->battery_vcell = val->intval; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + info->input_current = val->intval; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + info->charge_current = val->intval; + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + info->charge_current_avg = val->intval; + break; + case POWER_SUPPLY_PROP_CAPACITY: + info->battery_soc = val->intval; + break; + case POWER_SUPPLY_PROP_TEMP: + info->battery_temper = val->intval; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + info->pdata->voltage_max = val->intval; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + info->pdata->voltage_min = val->intval; + break; + default: + return -EINVAL; + } + } else { + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + break; + default: + return -EINVAL; + } } cancel_work_sync(&info->monitor_work); @@ -1625,8 +2034,10 @@ static int samsung_usb_get_property(struct power_supply *ps, return -EINVAL; /* Set enable=1 only if the USB charger is connected */ - val->intval = (info->cable_type == POWER_SUPPLY_TYPE_USB) || - (info->cable_type == POWER_SUPPLY_TYPE_USB_CDP); + val->intval = ((info->charge_virt_state != + POWER_SUPPLY_STATUS_DISCHARGING) && + ((info->cable_type == POWER_SUPPLY_TYPE_USB) || + (info->cable_type == POWER_SUPPLY_TYPE_USB_CDP))); return 0; } @@ -1642,22 +2053,48 @@ static int samsung_ac_get_property(struct power_supply *ps, return -EINVAL; /* Set enable=1 only if the AC charger is connected */ - val->intval = (info->cable_type == POWER_SUPPLY_TYPE_MAINS) || - (info->cable_type == POWER_SUPPLY_TYPE_MISC) || - (info->cable_type == POWER_SUPPLY_TYPE_DOCK) || - (info->cable_type == POWER_SUPPLY_TYPE_WIRELESS); + val->intval = ((info->charge_virt_state != + POWER_SUPPLY_STATUS_DISCHARGING) && + ((info->cable_type == POWER_SUPPLY_TYPE_MAINS) || + (info->cable_type == POWER_SUPPLY_TYPE_MISC) || + (info->cable_type == POWER_SUPPLY_TYPE_DOCK) || + (info->cable_type == POWER_SUPPLY_TYPE_WIRELESS))); return 0; } +static irqreturn_t battery_isr(int irq, void *data) +{ + struct battery_info *info = data; + int bat_gpio; + pr_info("%s: irq(%d)\n", __func__, irq); + + bat_gpio = gpio_get_value(info->batdet_gpio); + pr_info("%s: battery present gpio(%d)\n", __func__, bat_gpio); + + cancel_work_sync(&info->monitor_work); + wake_lock(&info->monitor_wake_lock); + schedule_work(&info->monitor_work); + + return IRQ_HANDLED; +} + static __devinit int samsung_battery_probe(struct platform_device *pdev) { struct battery_info *info; - int ret = 0; + struct samsung_battery_platform_data *pdata = pdev->dev.platform_data; + int ret = -ENODEV; char *temper_src_name[] = { "fuelgauge", "ap adc", "ext adc", "unknown" }; - pr_info("%s: SAMSUNG Battery Driver Loading\n", __func__); + char *vf_src_name[] = { "adc", "charger irq", "gpio", "unknown" + }; + pr_info("%s: battery init\n", __func__); + + if (!pdata) { + pr_err("%s: no platform data\n", __func__); + return -ENODEV; + } info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) @@ -1666,7 +2103,7 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev) platform_set_drvdata(pdev, info); info->dev = &pdev->dev; - info->pdata = pdev->dev.platform_data; + info->pdata = pdata; /* Check charger name and fuelgauge name. */ if (!info->pdata->charger_name || !info->pdata->fuelgauge_name) { @@ -1699,19 +2136,37 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev) goto err_psy_get; } +#if defined(CONFIG_MACH_M0) /* WORKAROUND: set battery pdata in driver */ if (system_rev == 3) { info->pdata->temper_src = TEMPER_EXT_ADC; info->pdata->temper_ch = 7; } +#endif pr_info("%s: Temperature source: %s\n", __func__, temper_src_name[info->pdata->temper_src]); + + /* not supported H/W rev for VF ADC */ +#if defined(CONFIG_MACH_T0) && defined(CONFIG_TARGET_LOCALE_USA) + if (system_rev < 7) + info->pdata->vf_det_src = VF_DET_CHARGER; +#endif + pr_info("%s: VF detect source: %s\n", __func__, + vf_src_name[info->pdata->vf_det_src]); + /* recalculate recharge voltage, it depends on max voltage value */ info->pdata->recharge_voltage = info->pdata->voltage_max - RECHG_DROP_VALUE; pr_info("%s: Recharge voltage: %d\n", __func__, info->pdata->recharge_voltage); + + if (info->pdata->ctia_spec == true) { + pr_info("%s: applied CTIA spec, event time(%ds)\n", + __func__, info->pdata->event_time); + } else + pr_info("%s: not applied CTIA spec\n", __func__); + #if defined(CONFIG_S3C_ADC) /* adc register */ info->adc_client = s3c_adc_register(pdev, NULL, NULL, 0); @@ -1730,18 +2185,21 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev) pr_info("%s: boot with charging, s(%d)\n", __func__, info->charge_real_state); info->charge_start_time = 1; + battery_set_adc_power(info, 1); } else { pr_info("%s: boot without charging, s(%d)\n", __func__, info->charge_real_state); info->charge_start_time = 0; } - info->full_charged_state = false; + info->full_charged_state = STATUS_NOT_FULL; info->abstimer_state = false; + info->abstimer_active = false; info->recharge_phase = false; info->siop_charge_current = info->pdata->chg_curr_usb; info->monitor_mode = MONITOR_NORM; info->led_state = BATT_LED_DISCHARGING; info->monitor_count = 0; + info->slate_mode = 0; /* LPM charging state */ info->lpm_state = lpcharge; @@ -1808,10 +2266,54 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev) goto err_psy_reg_ac; } + /* battery present irq */ + if (!info->pdata->batt_present_gpio) { + pr_info("%s: do not support battery gpio detect\n", __func__); + goto gpio_bat_det_finish; + } else + pr_info("%s: support battery gpio detection\n", __func__); + + info->batdet_gpio = info->pdata->batt_present_gpio; + info->batdet_irq = gpio_to_irq(info->batdet_gpio); + ret = gpio_request(info->batdet_gpio, "battery_present_n"); + if (ret) { + pr_err("%s: failed requesting gpio %d\n", __func__, + info->batdet_gpio); + goto err_irq; + } + gpio_direction_input(info->batdet_gpio); + gpio_free(info->batdet_gpio); + + ret = request_threaded_irq(info->batdet_irq, NULL, + battery_isr, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "batdet-irq", info); + if (ret) { + pr_err("%s: fail to request batdet irq: %d: %d\n", + __func__, info->batdet_irq, ret); + goto err_irq; + } + + ret = enable_irq_wake(info->batdet_irq); + if (ret) { + pr_err("%s: failed enable irq wake %d\n", __func__, + info->batdet_irq); + goto err_enable_irq; + } + + info->batdet_irq_st = true; +gpio_bat_det_finish: + /* Using android alarm for gauging instead of workqueue */ info->last_poll = alarm_get_elapsed_realtime(); - alarm_init(&info->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, - samsung_battery_alarm_start); + alarm_init(&info->monitor_alarm, + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + battery_monitor_alarm); + + if (info->pdata->ctia_spec == true) + alarm_init(&info->event_alarm, + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + battery_event_alarm); /* update battery init status */ schedule_work(&info->monitor_work); @@ -1829,14 +2331,20 @@ static __devinit int samsung_battery_probe(struct platform_device *pdev) } #endif - pr_info("%s: SAMSUNG Battery Driver Loaded\n", __func__); + pr_info("%s: probe complete\n", __func__); + return 0; +err_enable_irq: + free_irq(info->batdet_irq, info); +err_irq: + power_supply_unregister(&info->psy_ac); err_psy_reg_ac: power_supply_unregister(&info->psy_usb); err_psy_reg_usb: power_supply_unregister(&info->psy_bat); err_psy_reg_bat: + s3c_adc_release(info->adc_client); wake_lock_destroy(&info->monitor_wake_lock); wake_lock_destroy(&info->emer_wake_lock); #if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC) @@ -1861,6 +2369,10 @@ static int __devexit samsung_battery_remove(struct platform_device *pdev) remove_proc_entry("battery_info_proc", NULL); + alarm_cancel(&info->monitor_alarm); + if (info->pdata->ctia_spec == true) + alarm_cancel(&info->event_alarm); + cancel_work_sync(&info->error_work); cancel_work_sync(&info->monitor_work); @@ -1913,6 +2425,8 @@ static void samsung_battery_complete(struct device *dev) pr_info("%s\n", __func__); info->monitor_mode = MONITOR_NORM; + + battery_monitor_interval(info); } static int samsung_battery_suspend(struct device *dev) |