From 4ce690327a6f6ef20e28f3db14be38ec70b94e2e Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Tue, 12 Sep 2017 20:19:17 -0700 Subject: [PATCH] power: qpnp-fg-gen3: synchronize ESR extraction control configuration Currently, ESR extraction control is configured from two paths. First is invoked when Qnovo is enabled or disabled. Second is invoked when the pulse train is done and ESR measurement is requested. When the latter is run, there is a sleep time of 1.5 seconds that is essential for allowing FG to do ESR measurement. However in that time window, if Qnovo is disabled for some reason then ESR extraction control will be kept disabled unexpectedly. Fix this by protecting both the paths using a mutex lock as well as checking for qnovo enable status before disabling ESR extraction control after measuring ESR. Change-Id: Ib93539071724a1ce59d198074854a8a9c5fd3ab3 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/fg-core.h | 2 + drivers/power/supply/qcom/qpnp-fg-gen3.c | 48 ++++++++++++++++++------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 16441d6e09e4..7e393ea2208c 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -402,6 +402,7 @@ struct fg_chip { struct mutex bus_lock; struct mutex sram_rw_lock; struct mutex charge_full_lock; + struct mutex qnovo_esr_ctrl_lock; u32 batt_soc_base; u32 batt_info_base; u32 mem_if_base; @@ -435,6 +436,7 @@ struct fg_chip { bool esr_flt_cold_temp_en; bool slope_limit_en; bool use_ima_single_mode; + bool qnovo_enable; struct completion soc_update; struct completion soc_ready; struct delayed_work profile_load_work; diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 4788053115e1..d3feedf9e7b9 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -3297,20 +3297,21 @@ static int fg_force_esr_meas(struct fg_chip *chip) int rc; int esr_uohms; + mutex_lock(&chip->qnovo_esr_ctrl_lock); /* force esr extraction enable */ rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0), FG_IMA_DEFAULT); if (rc < 0) { pr_err("failed to enable esr extn rc=%d\n", rc); - return rc; + goto out; } rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip), LD_REG_CTRL_BIT, 0); if (rc < 0) { pr_err("Error in configuring qnovo_cfg rc=%d\n", rc); - return rc; + goto out; } rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip), @@ -3318,24 +3319,36 @@ static int fg_force_esr_meas(struct fg_chip *chip) ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT); if (rc < 0) { pr_err("Error in configuring force ESR rc=%d\n", rc); - return rc; + goto out; } + /* + * Release and grab the lock again after 1.5 seconds so that prepare + * callback can succeed if the request comes in between. + */ + mutex_unlock(&chip->qnovo_esr_ctrl_lock); + /* wait 1.5 seconds for hw to measure ESR */ msleep(1500); + + mutex_lock(&chip->qnovo_esr_ctrl_lock); rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip), ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT, 0); if (rc < 0) { pr_err("Error in restoring force ESR rc=%d\n", rc); - return rc; + goto out; } + /* If qnovo is disabled, then leave ESR extraction enabled */ + if (!chip->qnovo_enable) + goto done; + rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip), LD_REG_CTRL_BIT, LD_REG_CTRL_BIT); if (rc < 0) { pr_err("Error in restoring qnovo_cfg rc=%d\n", rc); - return rc; + goto out; } /* force esr extraction disable */ @@ -3344,36 +3357,46 @@ static int fg_force_esr_meas(struct fg_chip *chip) FG_IMA_DEFAULT); if (rc < 0) { pr_err("failed to disable esr extn rc=%d\n", rc); - return rc; + goto out; } +done: fg_get_battery_resistance(chip, &esr_uohms); fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms); - +out: + mutex_unlock(&chip->qnovo_esr_ctrl_lock); return rc; } static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable) { - int rc; + int rc = 0; + mutex_lock(&chip->qnovo_esr_ctrl_lock); /* force esr extraction disable when qnovo enables */ rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), qnovo_enable ? 0 : BIT(0), FG_IMA_DEFAULT); - if (rc < 0) + if (rc < 0) { pr_err("Error in configuring esr extraction rc=%d\n", rc); + goto out; + } rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip), LD_REG_CTRL_BIT, qnovo_enable ? LD_REG_CTRL_BIT : 0); if (rc < 0) { pr_err("Error in configuring qnovo_cfg rc=%d\n", rc); - return rc; + goto out; } - fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n"); - return 0; + + fg_dbg(chip, FG_STATUS, "%s for Qnovo\n", + qnovo_enable ? "Prepared" : "Unprepared"); + chip->qnovo_enable = qnovo_enable; +out: + mutex_unlock(&chip->qnovo_esr_ctrl_lock); + return rc; } static void ttf_work(struct work_struct *work) @@ -5002,6 +5025,7 @@ static int fg_gen3_probe(struct platform_device *pdev) mutex_init(&chip->cl.lock); mutex_init(&chip->ttf.lock); mutex_init(&chip->charge_full_lock); + mutex_init(&chip->qnovo_esr_ctrl_lock); init_completion(&chip->soc_update); init_completion(&chip->soc_ready); INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);