From d37bc1fb6359f080ea05f2fa3ffff9f73c13e4a4 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Thu, 4 Apr 2013 12:18:18 +0530 Subject: [PATCH] power: pm8921-charger: BTC override fixes - Monitor battery health when charger is not connected - Add configurable temperature hysteresis and enable the same for BTC override - Avoid releasing wakelock when charging is not in progress and BTC override is enabled - check temperature thresholds when fully charged, to handle temperature restrictions while restarting charging CRs-Fixed: 466525 Change-Id: I8cad3f8bcf65844fc1048625d9b387ede132d3e0 Signed-off-by: Anirudh Ghayal --- drivers/power/pm8921-charger.c | 52 ++++++++++++++++++++--- include/linux/mfd/pm8xxx/pm8921-charger.h | 1 + 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c index 459ab1d23d3..e00e1c37bd2 100644 --- a/drivers/power/pm8921-charger.c +++ b/drivers/power/pm8921-charger.c @@ -213,6 +213,8 @@ struct bms_notify { * @alarm_high_mv: the battery alarm voltage high * @cool_temp_dc: the cool temp threshold in deciCelcius * @warm_temp_dc: the warm temp threshold in deciCelcius + * @hysteresis_temp_dc: the hysteresis between temp thresholds in + * deciCelcius * @resume_voltage_delta: the voltage delta from vdd max at which the * battery should resume charging * @term_current: The charging based term current @@ -235,6 +237,7 @@ struct pm8921_chg_chip { unsigned int alarm_high_mv; int cool_temp_dc; int warm_temp_dc; + int hysteresis_temp_dc; unsigned int temp_check_period; unsigned int cool_bat_chg_current; unsigned int warm_bat_chg_current; @@ -308,6 +311,7 @@ static int charging_disabled; static int thermal_mitigation; static struct pm8921_chg_chip *the_chip; +static void check_temp_thresholds(struct pm8921_chg_chip *chip); #define LPM_ENABLE_BIT BIT(2) static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable) @@ -3162,6 +3166,22 @@ static void update_heartbeat(struct work_struct *work) struct delayed_work *dwork = to_delayed_work(work); struct pm8921_chg_chip *chip = container_of(dwork, struct pm8921_chg_chip, update_heartbeat_work); + bool chg_present = chip->usb_present || chip->dc_present; + + /* for battery health when charger is not connected */ + if (chip->btc_override && !chg_present) + schedule_delayed_work(&chip->btc_override_work, + round_jiffies_relative(msecs_to_jiffies + (chip->btc_delay_ms))); + + /* + * check temp thresholds when charger is present and + * and battery is FULL. The temperature here can impact + * the charging restart conditions. + */ + if (chip->btc_override && chg_present && + !wake_lock_active(&chip->eoc_wake_lock)) + check_temp_thresholds(chip); power_supply_changed(&chip->batt_psy); if (chip->recent_reported_soc <= 20) @@ -3317,7 +3337,7 @@ static void check_temp_thresholds(struct pm8921_chg_chip *chip) if (chip->warm_temp_dc != INT_MIN) { if (chip->is_bat_warm - && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC) + && temp < chip->warm_temp_dc - chip->hysteresis_temp_dc) battery_warm(false); else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc) battery_warm(true); @@ -3325,7 +3345,7 @@ static void check_temp_thresholds(struct pm8921_chg_chip *chip) if (chip->cool_temp_dc != INT_MIN) { if (chip->is_bat_cool - && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC) + && temp > chip->cool_temp_dc + chip->hysteresis_temp_dc) battery_cool(false); else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc) battery_cool(true); @@ -3543,7 +3563,8 @@ static void btc_override_worker(struct work_struct *work) temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ); if (temp) { - if (decidegc < chip->btc_override_hot_decidegc) + if (decidegc < chip->btc_override_hot_decidegc - + chip->hysteresis_temp_dc) /* stop forcing batt hot */ rc = pm_chg_override_hot(chip, 0); if (rc) @@ -3558,7 +3579,8 @@ static void btc_override_worker(struct work_struct *work) temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ); if (temp) { - if (decidegc > chip->btc_override_cold_decidegc) + if (decidegc > chip->btc_override_cold_decidegc + + chip->hysteresis_temp_dc) /* stop forcing batt cold */ rc = pm_chg_override_cold(chip, 0); if (rc) @@ -3622,7 +3644,8 @@ static void eoc_worker(struct work_struct *work) end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma); - if (end == CHG_NOT_IN_PROGRESS) { + if (end == CHG_NOT_IN_PROGRESS && (!chip->btc_override || + !(chip->usb_present || chip->dc_present))) { count = 0; goto eoc_worker_stop; } @@ -3650,7 +3673,8 @@ static void eoc_worker(struct work_struct *work) chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip); } else { check_temp_thresholds(chip); - adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv); + if (end != CHG_NOT_IN_PROGRESS) + adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv); pr_debug("EOC count = %d\n", count); schedule_delayed_work(&chip->eoc_work, round_jiffies_relative(msecs_to_jiffies @@ -3659,9 +3683,9 @@ static void eoc_worker(struct work_struct *work) } eoc_worker_stop: - wake_unlock(&chip->eoc_wake_lock); /* set the vbatdet back, in case it was changed to trigger charging */ set_appropriate_vbatdet(chip); + wake_unlock(&chip->eoc_wake_lock); } /** @@ -3795,6 +3819,11 @@ static void __devinit determine_initial_state(struct pm8921_chg_chip *chip) schedule_delayed_work(&chip->unplug_check_work, msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS)); pm8921_chg_enable_irq(chip, CHG_GONE_IRQ); + + if (chip->btc_override) + schedule_delayed_work(&chip->btc_override_work, + round_jiffies_relative(msecs_to_jiffies + (chip->btc_delay_ms))); } pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ); @@ -4600,6 +4629,8 @@ static int pm8921_charger_resume(struct device *dev) is_usb_chg_plugged_in(the_chip))) schedule_delayed_work(&chip->btc_override_work, 0); + schedule_delayed_work(&chip->update_heartbeat_work, 0); + return 0; } @@ -4607,6 +4638,8 @@ static int pm8921_charger_suspend(struct device *dev) { struct pm8921_chg_chip *chip = dev_get_drvdata(dev); + cancel_delayed_work_sync(&chip->update_heartbeat_work); + if (chip->btc_override) cancel_delayed_work_sync(&chip->btc_override_work); @@ -4663,6 +4696,11 @@ static int __devinit pm8921_charger_probe(struct platform_device *pdev) else chip->warm_temp_dc = INT_MIN; + if (pdata->hysteresis_temp) + chip->hysteresis_temp_dc = pdata->hysteresis_temp * 10; + else + chip->hysteresis_temp_dc = TEMP_HYSTERISIS_DECIDEGC; + chip->temp_check_period = pdata->temp_check_period; chip->max_bat_chg_current = pdata->max_bat_chg_current; /* Assign to corresponding module parameter */ diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h index 1c67b1eeb3b..5439fd1e62a 100644 --- a/include/linux/mfd/pm8xxx/pm8921-charger.h +++ b/include/linux/mfd/pm8xxx/pm8921-charger.h @@ -165,6 +165,7 @@ struct pm8921_charger_platform_data { unsigned int warm_bat_chg_current; unsigned int cool_bat_voltage; unsigned int warm_bat_voltage; + int hysteresis_temp; unsigned int (*get_batt_capacity_percent) (void); int64_t batt_id_min; int64_t batt_id_max;