From a9bd7fd94cc9091f086f6338560426fe2125a3e3 Mon Sep 17 00:00:00 2001 From: HongMin Son Date: Fri, 28 Sep 2012 14:03:31 +0900 Subject: [PATCH] power: android-battery: add charge timeouts and recharge logic Add recharge logic when voltage threshold reached. Add charge and recharge timeouts. Change-Id: I3ef3b926ce694115dde7f8056072bef63884a5d0 Signed-off-by: HongMin Son Signed-off-by: Todd Poynor --- drivers/power/android_battery.c | 118 ++++++++++++++++-- include/linux/platform_data/android_battery.h | 5 + 2 files changed, 115 insertions(+), 8 deletions(-) diff --git a/drivers/power/android_battery.c b/drivers/power/android_battery.c index e3b1f5e87b28..16db8cff5095 100644 --- a/drivers/power/android_battery.c +++ b/drivers/power/android_battery.c @@ -60,6 +60,8 @@ struct android_bat_data { unsigned int batt_vcell; unsigned int batt_soc; unsigned int charging_status; + bool recharging; + unsigned long charging_start_time; struct workqueue_struct *monitor_wqueue; struct work_struct monitor_work; @@ -92,6 +94,8 @@ static enum power_supply_property android_power_props[] = { }; static void android_bat_update_data(struct android_bat_data *battery); +static int android_bat_enable_charging(struct android_bat_data *battery, + bool enable); static char *charge_source_str(int charge_source) { @@ -250,6 +254,21 @@ static void android_bat_update_data(struct android_bat_data *battery) android_bat_get_temp(battery); } +static void android_bat_set_charge_time(struct android_bat_data *battery, + bool enable) +{ + if (enable && !battery->charging_start_time) { + struct timespec cur_time; + + get_monotonic_boottime(&cur_time); + /* record start time for charge timeout timer */ + battery->charging_start_time = cur_time.tv_sec; + } else if (!enable) { + /* clear charge timeout timer */ + battery->charging_start_time = 0; + } +} + static int android_bat_enable_charging(struct android_bat_data *battery, bool enable) { @@ -268,12 +287,60 @@ static int android_bat_enable_charging(struct android_bat_data *battery, if (battery->pdata && battery->pdata->set_charging_enable) battery->pdata->set_charging_enable(enable); + android_bat_set_charge_time(battery, enable); pr_info("battery: enable=%d charger: %s\n", enable, charge_source_str(battery->charge_source)); - return 0; } +static bool android_bat_charge_timeout(struct android_bat_data *battery, + unsigned long timeout) +{ + struct timespec cur_time; + + if (!battery->charging_start_time) + return 0; + + get_monotonic_boottime(&cur_time); + pr_debug("%s: Start time: %ld, End time: %ld, current time: %ld\n", + __func__, battery->charging_start_time, + battery->charging_start_time + timeout, + cur_time.tv_sec); + return cur_time.tv_sec >= battery->charging_start_time + timeout; +} + +static void android_bat_charging_timer(struct android_bat_data *battery) +{ + if (!battery->charging_start_time && + battery->charging_status == POWER_SUPPLY_STATUS_CHARGING) { + android_bat_enable_charging(battery, true); + battery->recharging = true; + pr_debug("%s: charge status charging but timer is expired\n", + __func__); + } else if (battery->charging_start_time == 0) { + pr_debug("%s: charging_start_time never initialized\n", + __func__); + return; + } + + if (android_bat_charge_timeout( + battery, + battery->recharging ? battery->pdata->recharging_time : + battery->pdata->full_charging_time)) { + android_bat_enable_charging(battery, false); + if (battery->batt_vcell > + battery->pdata->recharging_voltage && + battery->batt_soc == 100) + battery->charging_status = + POWER_SUPPLY_STATUS_FULL; + battery->recharging = false; + battery->charging_start_time = 0; + pr_info("battery: charging timer expired\n"); + } + + return; +} + static void android_bat_charge_source_changed(struct android_bat_callbacks *ptr, int charge_source) { @@ -289,6 +356,18 @@ static void android_bat_charge_source_changed(struct android_bat_callbacks *ptr, queue_work(battery->monitor_wqueue, &battery->charger_work); } +static void android_bat_set_full_status(struct android_bat_callbacks *ptr) +{ + struct android_bat_data *battery = + container_of(ptr, struct android_bat_data, callbacks); + + pr_info("battery: battery full\n"); + battery->charging_status = POWER_SUPPLY_STATUS_FULL; + android_bat_enable_charging(battery, false); + battery->recharging = false; + power_supply_changed(&battery->psy_bat); +} + static void android_bat_charger_work(struct work_struct *work) { struct android_bat_data *battery = @@ -298,8 +377,9 @@ static void android_bat_charger_work(struct work_struct *work) case CHARGE_SOURCE_NONE: battery->charging_status = POWER_SUPPLY_STATUS_DISCHARGING; android_bat_enable_charging(battery, false); - if (battery->batt_health == POWER_SUPPLY_HEALTH_OVERVOLTAGE) - battery->batt_health = POWER_SUPPLY_HEALTH_GOOD; + battery->batt_health = POWER_SUPPLY_HEALTH_GOOD; + battery->recharging = false; + battery->charging_start_time = 0; break; case CHARGE_SOURCE_USB: case CHARGE_SOURCE_AC: @@ -327,14 +407,23 @@ static void android_bat_monitor_set_alarm(struct android_bat_data *battery, static void android_bat_monitor_work(struct work_struct *work) { - struct android_bat_data *battery; - battery = container_of(work, struct android_bat_data, monitor_work); + struct android_bat_data *battery = + container_of(work, struct android_bat_data, monitor_work); + struct timespec cur_time; wake_lock(&battery->monitor_wake_lock); android_bat_update_data(battery); switch (battery->charging_status) { case POWER_SUPPLY_STATUS_FULL: + if (battery->batt_vcell < battery->pdata->recharging_voltage && + !battery->recharging) { + battery->recharging = true; + android_bat_enable_charging(battery, true); + pr_info("battery: start recharging, v=%d\n", + battery->batt_vcell/1000); + } + break; case POWER_SUPPLY_STATUS_DISCHARGING: break; case POWER_SUPPLY_STATUS_CHARGING: @@ -362,9 +451,10 @@ static void android_bat_monitor_work(struct work_struct *work) android_bat_enable_charging(battery, true); battery->charging_status = POWER_SUPPLY_STATUS_CHARGING; - } else + } else { battery->charging_status = POWER_SUPPLY_STATUS_DISCHARGING; + } } break; default: @@ -373,11 +463,16 @@ static void android_bat_monitor_work(struct work_struct *work) break; } - pr_info("battery: l=%d v=%d c=%d temp=%s%ld.%ld h=%d st=%d type=%s\n", + android_bat_charging_timer(battery); + get_monotonic_boottime(&cur_time); + pr_info("battery: l=%d v=%d c=%d temp=%s%ld.%ld h=%d st=%d%s ct=%lu type=%s\n", battery->batt_soc, battery->batt_vcell/1000, battery->batt_current, battery->batt_temp < 0 ? "-" : "", abs(battery->batt_temp / 10), abs(battery->batt_temp % 10), battery->batt_health, battery->charging_status, + battery->recharging ? "r" : "", + battery->charging_start_time ? + cur_time.tv_sec - battery->charging_start_time : 0, charge_source_str(battery->charge_source)); power_supply_changed(&battery->psy_bat); battery->last_poll = ktime_get_boottime(); @@ -400,13 +495,18 @@ static enum alarmtimer_restart android_bat_monitor_alarm( static int android_power_debug_dump(struct seq_file *s, void *unused) { struct android_bat_data *battery = s->private; + struct timespec cur_time; android_bat_update_data(battery); - seq_printf(s, "l=%d v=%d c=%d temp=%s%ld.%ld h=%d st=%d type=%s\n", + get_monotonic_boottime(&cur_time); + seq_printf(s, "l=%d v=%d c=%d temp=%s%ld.%ld h=%d st=%d%s ct=%lu type=%s\n", battery->batt_soc, battery->batt_vcell/1000, battery->batt_current, battery->batt_temp < 0 ? "-" : "", abs(battery->batt_temp / 10), abs(battery->batt_temp % 10), battery->batt_health, battery->charging_status, + battery->recharging ? "r" : "", + battery->charging_start_time ? + cur_time.tv_sec - battery->charging_start_time : 0, charge_source_str(battery->charge_source)); return 0; @@ -510,6 +610,8 @@ static int android_bat_probe(struct platform_device *pdev) battery->callbacks.charge_source_changed = android_bat_charge_source_changed; + battery->callbacks.battery_set_full = + android_bat_set_full_status; if (battery->pdata && battery->pdata->register_callbacks) battery->pdata->register_callbacks(&battery->callbacks); diff --git a/include/linux/platform_data/android_battery.h b/include/linux/platform_data/android_battery.h index a0749f5b9d3b..f6c8298fd885 100644 --- a/include/linux/platform_data/android_battery.h +++ b/include/linux/platform_data/android_battery.h @@ -20,6 +20,7 @@ enum { struct android_bat_callbacks { void (*charge_source_changed) (struct android_bat_callbacks *, int); + void (*battery_set_full)(struct android_bat_callbacks *); }; struct android_bat_platform_data { @@ -37,6 +38,10 @@ struct android_bat_platform_data { int temp_high_recovery; int temp_low_recovery; int temp_low_threshold; + + unsigned long full_charging_time; + unsigned long recharging_time; + unsigned int recharging_voltage; }; #endif -- 2.34.1