forked from rubenslte/android_kernel_samsung_msm8226
power: bms: Report zero SOC if voltage is below cutoff
If the battery voltage remains below the cutoff threshold for a specific period (determined by a platform data - vbatt_cutoff_retries) report the SOC as 0. This allows the userspace to perform a graceful shutdown. Also, provide a platform data entry (low_voltage_detect) to enable this functionality. Enable 'low_voltage_detect' and set 'vbatt_cutoff_retries' as required to enable the full functionality. CRs-Fixed: 450387 Change-Id: I668d391cab3d0424fe5f370df0c1169124c34f5e Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
This commit is contained in:
committed by
Gerrit - the friendly Code Review server
parent
8e9aa3235d
commit
0c7c2bcff1
+59
-10
@@ -59,6 +59,8 @@
|
||||
#define PON_CNTRL_6 0x018
|
||||
#define WD_BIT BIT(7)
|
||||
|
||||
#define BATT_ALARM_ACCURACY 50 /* 50mV */
|
||||
|
||||
enum pmic_bms_interrupts {
|
||||
PM8921_BMS_SBI_WRITE_OK,
|
||||
PM8921_BMS_CC_THR,
|
||||
@@ -159,7 +161,6 @@ struct pm8921_bms_chip {
|
||||
int soc_at_cv;
|
||||
int prev_chg_soc;
|
||||
struct power_supply *batt_psy;
|
||||
bool low_voltage_wake_lock_held;
|
||||
struct wake_lock low_voltage_wake_lock;
|
||||
int soc_calc_period;
|
||||
int normal_voltage_calc_ms;
|
||||
@@ -170,6 +171,9 @@ struct pm8921_bms_chip {
|
||||
int ocv_dis_high_soc;
|
||||
int ocv_dis_low_soc;
|
||||
int prev_vbat_batt_terminal_uv;
|
||||
int vbatt_cutoff_count;
|
||||
int low_voltage_detect;
|
||||
int vbatt_cutoff_retries;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -391,6 +395,20 @@ static int usb_chg_plugged_in(struct pm8921_bms_chip *chip)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pm8921_bms_low_voltage_config(struct pm8921_bms_chip *chip,
|
||||
int time_ms)
|
||||
{
|
||||
int ms = 0;
|
||||
|
||||
/* if work was pending and was cancelled, calculate SOC immediately */
|
||||
if (!cancel_delayed_work_sync(&chip->calculate_soc_delayed_work))
|
||||
ms = time_ms;
|
||||
|
||||
chip->soc_calc_period = time_ms;
|
||||
schedule_delayed_work(&chip->calculate_soc_delayed_work,
|
||||
msecs_to_jiffies(ms));
|
||||
}
|
||||
|
||||
static int pm8921_bms_enable_batt_alarm(struct pm8921_bms_chip *chip)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -479,8 +497,12 @@ static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
|
||||
* hold the low voltage wakelock until the soc
|
||||
* work finds it appropriate to release it.
|
||||
*/
|
||||
wake_lock(&the_chip->low_voltage_wake_lock);
|
||||
the_chip->low_voltage_wake_lock_held = 1;
|
||||
if (!wake_lock_active(&the_chip->low_voltage_wake_lock)) {
|
||||
pr_debug("Holding low voltage wakelock\n");
|
||||
wake_lock(&the_chip->low_voltage_wake_lock);
|
||||
pm8921_bms_low_voltage_config(the_chip,
|
||||
the_chip->low_voltage_calc_ms);
|
||||
}
|
||||
|
||||
rc = pm8xxx_batt_alarm_disable(
|
||||
PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
|
||||
@@ -1788,26 +1810,42 @@ static void very_low_voltage_check(struct pm8921_bms_chip *chip,
|
||||
* if battery is very low (v_cutoff voltage + 20mv) hold
|
||||
* a wakelock untill soc = 0%
|
||||
*/
|
||||
if (vbat_uv <= (chip->v_cutoff + 20) * 1000
|
||||
&& !chip->low_voltage_wake_lock_held) {
|
||||
if (vbat_uv <= (chip->alarm_low_mv + 20) * 1000 &&
|
||||
!wake_lock_active(&the_chip->low_voltage_wake_lock)) {
|
||||
pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
|
||||
wake_lock(&chip->low_voltage_wake_lock);
|
||||
chip->low_voltage_wake_lock_held = 1;
|
||||
chip->soc_calc_period = chip->low_voltage_calc_ms;
|
||||
}
|
||||
|
||||
if (vbat_uv > (chip->v_cutoff + 20) * 1000
|
||||
&& chip->low_voltage_wake_lock_held) {
|
||||
if (vbat_uv > (chip->alarm_low_mv + 20 + BATT_ALARM_ACCURACY) * 1000
|
||||
&& wake_lock_active(&the_chip->low_voltage_wake_lock)) {
|
||||
pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
|
||||
chip->low_voltage_wake_lock_held = 0;
|
||||
wake_unlock(&chip->low_voltage_wake_lock);
|
||||
chip->vbatt_cutoff_count = 0;
|
||||
chip->soc_calc_period = chip->normal_voltage_calc_ms;
|
||||
rc = pm8921_bms_enable_batt_alarm(chip);
|
||||
if (rc)
|
||||
pr_err("Unable to enable batt alarm\n");
|
||||
wake_unlock(&chip->low_voltage_wake_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_voltage_below_cutoff_window(struct pm8921_bms_chip *chip,
|
||||
int ibat_ua, int vbat_uv)
|
||||
{
|
||||
if (vbat_uv < (chip->v_cutoff * 1000) && ibat_ua > 0) {
|
||||
chip->vbatt_cutoff_count++;
|
||||
if (chip->vbatt_cutoff_count >= chip->vbatt_cutoff_retries) {
|
||||
pr_debug("cutoff_count >= %d\n",
|
||||
chip->vbatt_cutoff_retries);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
chip->vbatt_cutoff_count = 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int last_soc_est = -EINVAL;
|
||||
static int adjust_soc(struct pm8921_bms_chip *chip, int soc,
|
||||
int batt_temp, int chargecycles,
|
||||
@@ -1834,6 +1872,15 @@ static int adjust_soc(struct pm8921_bms_chip *chip, int soc,
|
||||
|
||||
very_low_voltage_check(chip, ibat_ua, vbat_uv);
|
||||
|
||||
if (chip->low_voltage_detect &&
|
||||
wake_lock_active(&chip->low_voltage_wake_lock)) {
|
||||
if (is_voltage_below_cutoff_window(chip, ibat_ua, vbat_uv)) {
|
||||
soc = 0;
|
||||
pr_info("Voltage below cutoff, setting soc to 0\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
|
||||
|
||||
ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
|
||||
@@ -3327,6 +3374,8 @@ static int __devinit pm8921_bms_probe(struct platform_device *pdev)
|
||||
|
||||
chip->alarm_low_mv = pdata->alarm_low_mv;
|
||||
chip->alarm_high_mv = pdata->alarm_high_mv;
|
||||
chip->low_voltage_detect = pdata->low_voltage_detect;
|
||||
chip->vbatt_cutoff_retries = pdata->vbatt_cutoff_retries;
|
||||
|
||||
mutex_init(&chip->calib_mutex);
|
||||
INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
|
||||
|
||||
@@ -44,6 +44,8 @@ struct pm8xxx_bms_core_data {
|
||||
* @disable_flat_portion_ocv: feature to disable ocv updates while in sleep
|
||||
* @ocv_dis_high_soc: the high soc percent when ocv should be disabled
|
||||
* @ocv_dis_low_soc: the low soc percent when ocv should be enabled
|
||||
* @low_voltage_detect: feature to enable 0 SOC reporting on low volatge
|
||||
* @vbatt_cutoff_retries: number of tries before we report a 0 SOC
|
||||
*/
|
||||
struct pm8921_bms_platform_data {
|
||||
struct pm8xxx_bms_core_data bms_cdata;
|
||||
@@ -65,6 +67,8 @@ struct pm8921_bms_platform_data {
|
||||
int disable_flat_portion_ocv;
|
||||
int ocv_dis_high_soc;
|
||||
int ocv_dis_low_soc;
|
||||
int low_voltage_detect;
|
||||
int vbatt_cutoff_retries;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
|
||||
|
||||
Reference in New Issue
Block a user