diff options
author | HongMin Son <hongmin.son@samsung.com> | 2012-09-28 14:03:31 +0900 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2014-03-19 13:09:29 -0700 |
commit | 6ccb8c7c29a067c2b29adc73ad8eb6962e90da14 (patch) | |
tree | ccc7ea1b8a90d201af14b49c8e11b58ca022da32 | |
parent | f5c0e02eb6bb4327d6fedd5d99c1f7f3cc7204a9 (diff) |
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 <hongmin.son@samsung.com>
Signed-off-by: Todd Poynor <toddpoynor@google.com>
-rw-r--r-- | drivers/power/android_battery.c | 118 | ||||
-rw-r--r-- | 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 e3b1f5e87b2..16db8cff509 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 a0749f5b9d3..f6c8298fd88 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 |