power: qpnp-bms: recalculate soc immediately upon wakeup
Under certain conditions, sleep current may be very high, and the BMS
may have counted a lot of current. However, SoC is only recalculated
once every 20 seconds of kernel time. If SoC has been recalculated just
before sleep, there may be almost 20 seconds before the SoC is updated.
The user will see SoC make a big jump a few seconds after waking up.
Fix this by recalculating SoC immediately after resume in the BMS so that
SoC is immediately refreshed upon wakeup.
Change-Id: Ie4c4260f54568d27458e9fb847c6325cd6d5d479
Signed-off-by: Xiaozhe Shi <xiaozhes@codeaurora.org>
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index d5b710d..6b09f18 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -189,6 +189,7 @@
int ocv_high_threshold_uv;
int ocv_low_threshold_uv;
+ unsigned long last_recalc_time;
};
static struct of_device_id qpnp_bms_match_table[] = {
@@ -1597,6 +1598,7 @@
chip->calculated_soc = new_calculated_soc;
pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
chip->first_time_calc_soc = 0;
+ get_current_time(&chip->last_recalc_time);
return chip->calculated_soc;
}
@@ -1640,11 +1642,8 @@
return voltage_based_soc;
}
-static void calculate_soc_work(struct work_struct *work)
+static int recalculate_soc(struct qpnp_bms_chip *chip)
{
- struct qpnp_bms_chip *chip = container_of(work,
- struct qpnp_bms_chip,
- calculate_soc_delayed_work.work);
int batt_temp, rc, soc;
struct qpnp_vadc_result result;
struct raw_soc_params raw;
@@ -1656,7 +1655,7 @@
if (rc) {
pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
LR_MUX1_BATT_THERM, rc);
- return;
+ return chip->calculated_soc;
}
pr_debug("batt_temp phy = %lld meas = 0x%llx\n",
result.physical,
@@ -1668,6 +1667,15 @@
soc = calculate_state_of_charge(chip, &raw, batt_temp);
mutex_unlock(&chip->last_ocv_uv_mutex);
}
+ return soc;
+}
+
+static void calculate_soc_work(struct work_struct *work)
+{
+ struct qpnp_bms_chip *chip = container_of(work,
+ struct qpnp_bms_chip,
+ calculate_soc_delayed_work.work);
+ int soc = recalculate_soc(chip);
if (soc < chip->low_soc_calc_threshold)
schedule_delayed_work(&chip->calculate_soc_delayed_work,
@@ -2468,6 +2476,38 @@
return 0;
}
+static int bms_resume(struct device *dev)
+{
+ int rc;
+ unsigned long soc_calc_period;
+ unsigned long time_since_last_recalc;
+ unsigned long tm_now_sec;
+ struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+ rc = get_current_time(&tm_now_sec);
+ if (rc) {
+ pr_err("Could not read current time: %d\n", rc);
+ } else if (tm_now_sec > chip->last_recalc_time) {
+ time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
+ pr_debug("Time since last recalc: %lu\n",
+ time_since_last_recalc);
+ if (chip->calculated_soc < chip->low_soc_calc_threshold)
+ soc_calc_period = chip->low_soc_calculate_soc_ms;
+ else
+ soc_calc_period = chip->calculate_soc_ms;
+
+ if (time_since_last_recalc >= soc_calc_period) {
+ chip->last_recalc_time = tm_now_sec;
+ recalculate_soc(chip);
+ }
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops qpnp_bms_pm_ops = {
+ .resume = bms_resume,
+};
+
static struct spmi_driver qpnp_bms_driver = {
.probe = qpnp_bms_probe,
.remove = __devexit_p(qpnp_bms_remove),
@@ -2475,6 +2515,7 @@
.name = QPNP_BMS_DEV_NAME,
.owner = THIS_MODULE,
.of_match_table = qpnp_bms_match_table,
+ .pm = &qpnp_bms_pm_ops,
},
};