summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSubbaraman Narayanamurthy <subbaram@codeaurora.org>2017-01-03 15:39:08 -0800
committerSubbaraman Narayanamurthy <subbaram@codeaurora.org>2017-02-02 21:02:39 -0800
commit4fa5fdc375d8f80271aadab4022c94132580cb45 (patch)
treef8b5002a24f4c06bc4191709a79d84c0f10a1203
parent5c7833f48ba413dc71b3202d403f893a44116131 (diff)
qpnp-fg-gen3: improve SOC masking algorithm
After charge termination, charging status might not get updated until the recharge begins. This makes charge_full_update to be not called at all thereby causing SOC masking algorithm to not clear the charge_full flag. Use delta battery SOC interrupt to help with this. Keep it disabled by default and enable it after the charge termination. Disable it again when the user removes the charger. Since this needs delta battery SOC threshold to be configured, add support for it. Change-Id: Ic1a9f8a065c87efe88e315f2b2e1e1378151531b Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt8
-rw-r--r--drivers/power/supply/qcom/fg-core.h4
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c89
3 files changed, 78 insertions, 23 deletions
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index 221657780178..6ac350fee318 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -99,10 +99,10 @@ First Level Node - FG Gen3 device
- qcom,fg-delta-soc-thr
Usage: optional
Value type: <u32>
- Definition: Percentage of monotonic SOC increase upon which the delta
- SOC interrupt will be triggered. If this property is not
- specified, then the default value will be 1. Possible
- values are in the range of 0 to 12.
+ Definition: Percentage of SOC increase upon which the delta monotonic &
+ battery SOC interrupts will be triggered. If this property
+ is not specified, then the default value will be 1.
+ Possible values are in the range of 0 to 12.
- qcom,fg-recharge-soc-thr
Usage: optional
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index d71e3afd8d42..c9cc03b6c53a 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -156,7 +156,8 @@ enum fg_sram_param_id {
FG_SRAM_ESR_TIMER_CHG_INIT,
FG_SRAM_SYS_TERM_CURR,
FG_SRAM_CHG_TERM_CURR,
- FG_SRAM_DELTA_SOC_THR,
+ FG_SRAM_DELTA_MSOC_THR,
+ FG_SRAM_DELTA_BSOC_THR,
FG_SRAM_RECHARGE_SOC_THR,
FG_SRAM_RECHARGE_VBATT_THR,
FG_SRAM_KI_COEFF_MED_DISCHG,
@@ -345,6 +346,7 @@ struct fg_chip {
bool esr_fcc_ctrl_en;
bool soc_reporting_ready;
bool esr_flt_cold_temp_en;
+ bool bsoc_delta_irq_en;
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 41b4428592cb..6d77823071ca 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -48,8 +48,10 @@
#define KI_COEFF_HI_DISCHG_OFFSET 0
#define KI_COEFF_LOW_DISCHG_WORD 10
#define KI_COEFF_LOW_DISCHG_OFFSET 2
-#define DELTA_SOC_THR_WORD 12
-#define DELTA_SOC_THR_OFFSET 3
+#define DELTA_MSOC_THR_WORD 12
+#define DELTA_MSOC_THR_OFFSET 3
+#define DELTA_BSOC_THR_WORD 13
+#define DELTA_BSOC_THR_OFFSET 2
#define RECHARGE_SOC_THR_WORD 14
#define RECHARGE_SOC_THR_OFFSET 0
#define CHG_TERM_CURR_WORD 14
@@ -113,8 +115,10 @@
#define KI_COEFF_MED_DISCHG_v2_OFFSET 0
#define KI_COEFF_HI_DISCHG_v2_WORD 10
#define KI_COEFF_HI_DISCHG_v2_OFFSET 1
-#define DELTA_SOC_THR_v2_WORD 13
-#define DELTA_SOC_THR_v2_OFFSET 0
+#define DELTA_BSOC_THR_v2_WORD 12
+#define DELTA_BSOC_THR_v2_OFFSET 3
+#define DELTA_MSOC_THR_v2_WORD 13
+#define DELTA_MSOC_THR_v2_OFFSET 0
#define RECHARGE_SOC_THR_v2_WORD 14
#define RECHARGE_SOC_THR_v2_OFFSET 1
#define CHG_TERM_CURR_v2_WORD 15
@@ -143,6 +147,8 @@ static void fg_encode_current(struct fg_sram_param *sp,
static void fg_encode_default(struct fg_sram_param *sp,
enum fg_sram_param_id id, int val, u8 *buf);
+static struct fg_irq_info fg_irqs[FG_IRQ_MAX];
+
#define PARAM(_id, _addr_word, _addr_byte, _len, _num, _den, _offset, \
_enc, _dec) \
[FG_SRAM_##_id] = { \
@@ -188,8 +194,10 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = {
1000000, 122070, 0, fg_encode_current, NULL),
PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1,
100000, 390625, 0, fg_encode_current, NULL),
- PARAM(DELTA_SOC_THR, DELTA_SOC_THR_WORD, DELTA_SOC_THR_OFFSET, 1, 2048,
- 100, 0, fg_encode_default, NULL),
+ PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1,
+ 2048, 100, 0, fg_encode_default, NULL),
+ PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1,
+ 2048, 100, 0, fg_encode_default, NULL),
PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET,
1, 256, 100, 0, fg_encode_default, NULL),
PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
@@ -248,8 +256,10 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = {
1000000, 122070, 0, fg_encode_current, NULL),
PARAM(CHG_TERM_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_CURR_v2_OFFSET, 1,
100000, 390625, 0, fg_encode_current, NULL),
- PARAM(DELTA_SOC_THR, DELTA_SOC_THR_v2_WORD, DELTA_SOC_THR_v2_OFFSET, 1,
- 2048, 100, 0, fg_encode_default, NULL),
+ PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET,
+ 1, 2048, 100, 0, fg_encode_default, NULL),
+ PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET,
+ 1, 2048, 100, 0, fg_encode_default, NULL),
PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD,
RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default,
NULL),
@@ -1409,6 +1419,16 @@ static int fg_charge_full_update(struct fg_chip *chip)
if (!batt_psy_initialized(chip))
return 0;
+ if (!chip->charge_done && chip->bsoc_delta_irq_en) {
+ disable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq);
+ disable_irq_nosync(fg_irqs[BSOC_DELTA_IRQ].irq);
+ chip->bsoc_delta_irq_en = false;
+ } else if (chip->charge_done && !chip->bsoc_delta_irq_en) {
+ enable_irq(fg_irqs[BSOC_DELTA_IRQ].irq);
+ enable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq);
+ chip->bsoc_delta_irq_en = true;
+ }
+
rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
&prop);
if (rc < 0) {
@@ -1434,8 +1454,8 @@ static int fg_charge_full_update(struct fg_chip *chip)
return rc;
}
- fg_dbg(chip, FG_STATUS, "msoc: %d health: %d status: %d\n", msoc,
- chip->health, chip->charge_status);
+ fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d\n",
+ msoc, bsoc, chip->health, chip->charge_status);
if (chip->charge_done) {
if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD)
chip->charge_full = true;
@@ -2759,15 +2779,27 @@ static int fg_hw_init(struct fg_chip *chip)
}
if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) {
- fg_encode(chip->sp, FG_SRAM_DELTA_SOC_THR,
+ fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR,
chip->dt.delta_soc_thr, buf);
rc = fg_sram_write(chip,
- chip->sp[FG_SRAM_DELTA_SOC_THR].addr_word,
- chip->sp[FG_SRAM_DELTA_SOC_THR].addr_byte,
- buf, chip->sp[FG_SRAM_DELTA_SOC_THR].len,
+ chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word,
+ chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte,
+ buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len,
FG_IMA_DEFAULT);
if (rc < 0) {
- pr_err("Error in writing delta_soc_thr, rc=%d\n", rc);
+ pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc);
+ return rc;
+ }
+
+ fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR,
+ chip->dt.delta_soc_thr, buf);
+ rc = fg_sram_write(chip,
+ chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word,
+ chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte,
+ buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc);
return rc;
}
}
@@ -3058,7 +3090,20 @@ static irqreturn_t fg_soc_update_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static irqreturn_t fg_delta_soc_irq_handler(int irq, void *data)
+static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
+{
+ struct fg_chip *chip = data;
+ int rc;
+
+ fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
+ rc = fg_charge_full_update(chip);
+ if (rc < 0)
+ pr_err("Error in charge_full_update, rc=%d\n", rc);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
{
struct fg_chip *chip = data;
int rc;
@@ -3132,12 +3177,13 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
},
[MSOC_DELTA_IRQ] = {
.name = "msoc-delta",
- .handler = fg_delta_soc_irq_handler,
+ .handler = fg_delta_msoc_irq_handler,
.wakeable = true,
},
[BSOC_DELTA_IRQ] = {
.name = "bsoc-delta",
- .handler = fg_dummy_irq_handler,
+ .handler = fg_delta_bsoc_irq_handler,
+ .wakeable = true,
},
[SOC_READY_IRQ] = {
.name = "soc-ready",
@@ -3752,6 +3798,13 @@ static int fg_gen3_probe(struct platform_device *pdev)
if (fg_irqs[SOC_UPDATE_IRQ].irq)
disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
+ /* Keep BSOC_DELTA_IRQ irq disabled until we require it */
+ if (fg_irqs[BSOC_DELTA_IRQ].irq) {
+ disable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq);
+ disable_irq_nosync(fg_irqs[BSOC_DELTA_IRQ].irq);
+ chip->bsoc_delta_irq_en = false;
+ }
+
rc = fg_debugfs_create(chip);
if (rc < 0) {
dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",