diff options
| author | Subbaraman Narayanamurthy <subbaram@codeaurora.org> | 2017-05-17 17:43:22 -0700 |
|---|---|---|
| committer | Subbaraman Narayanamurthy <subbaram@codeaurora.org> | 2017-05-31 19:01:05 -0700 |
| commit | 6124f7574427070e5772366e3ceb53151303104f (patch) | |
| tree | 7bd0c1953d7ddf05765b020c718227f0b747bb17 | |
| parent | 3d1963e351de96cc19d692427d54652fe44bdaf0 (diff) | |
qpnp-fg-gen3: configure ESR timers dynamically based on charge termination
With ESR discharge timer retry, max having same value, ESR pulse
can fire frequently when battery FET is open past charge
termination. This frequent ESR pulses increase power consumption
when the device is idle.
Upon charge termination, change the ESR discharging timer retry
to 0 so that ESR pulse can fire less frequently saving power.
Add support for this through fg_esr_timer_config() based on end
of charge and sleep conditions.
Currently, retry/max for ESR charging and discharging timers are
configured with the same value specified through device tree.
Extend the device tree property to take in different retry/max
values for those timers.
Change-Id: Ib30b8ae7d893b5cab00ed83dd7318b53e3b63ac1
Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
| -rw-r--r-- | Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt | 20 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msm-pm660.dtsi | 6 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msm-pmi8998.dtsi | 5 | ||||
| -rw-r--r-- | drivers/power/supply/qcom/fg-core.h | 13 | ||||
| -rw-r--r-- | drivers/power/supply/qcom/qpnp-fg-gen3.c | 236 |
5 files changed, 172 insertions, 108 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 12d32ec74369..012368275db3 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt @@ -145,22 +145,30 @@ First Level Node - FG Gen3 device - qcom,fg-esr-timer-charging Usage: optional - Value type: <u32> + Value type: <prop-encoded-array> Definition: Number of cycles between ESR pulses while the battery is - charging. + charging. Array of 2 elements if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer - qcom,fg-esr-timer-awake Usage: optional - Value type: <u32> + Value type: <prop-encoded-array> Definition: Number of cycles between ESR pulses while the system is - awake and the battery is discharging. + awake and the battery is discharging. Array of 2 elements + if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer - qcom,fg-esr-timer-asleep Usage: optional - Value type: <u32> + Value type: <prop-encoded-array> Definition: Number of cycles between ESR pulses while the system is asleep and the battery is discharging. This option requires - qcom,fg-esr-timer-awake to be defined. + qcom,fg-esr-timer-awake to be defined. Array of 2 elements + if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer - qcom,fg-esr-pulse-thresh-ma Usage: optional diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi index 7fde74f3d570..f33baaa13142 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi @@ -545,9 +545,9 @@ io-channel-names = "rradc_batt_id", "rradc_die_temp"; qcom,rradc-base = <0x4500>; - qcom,fg-esr-timer-awake = <96>; - qcom,fg-esr-timer-asleep = <256>; - qcom,fg-esr-timer-charging = <96>; + qcom,fg-esr-timer-awake = <96 96>; + qcom,fg-esr-timer-asleep = <256 256>; + qcom,fg-esr-timer-charging = <0 96>; qcom,cycle-counter-en; status = "okay"; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index ad32ab01c5fb..89f6532b4999 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -337,8 +337,9 @@ io-channels = <&pmi8998_rradc 0>; io-channel-names = "rradc_batt_id"; qcom,rradc-base = <0x4500>; - qcom,fg-esr-timer-awake = <96>; - qcom,fg-esr-timer-asleep = <256>; + qcom,fg-esr-timer-awake = <96 96>; + qcom,fg-esr-timer-asleep = <256 256>; + qcom,fg-esr-timer-charging = <0 96>; qcom,cycle-counter-en; status = "okay"; diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 25c9d0251cf1..c5346babf310 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -219,6 +219,12 @@ enum slope_limit_status { SLOPE_LIMIT_NUM_COEFFS, }; +enum esr_timer_config { + TIMER_RETRY = 0, + TIMER_MAX, + NUM_ESR_TIMERS, +}; + /* DT parameters for FG device */ struct fg_dt_props { bool force_load_profile; @@ -234,9 +240,9 @@ struct fg_dt_props { int recharge_soc_thr; int recharge_volt_thr_mv; int rsense_sel; - int esr_timer_charging; - int esr_timer_awake; - int esr_timer_asleep; + int esr_timer_charging[NUM_ESR_TIMERS]; + int esr_timer_awake[NUM_ESR_TIMERS]; + int esr_timer_asleep[NUM_ESR_TIMERS]; int rconn_mohms; int esr_clamp_mohms; int cl_start_soc; @@ -385,6 +391,7 @@ struct fg_chip { int maint_soc; int delta_soc; int last_msoc; + int esr_timer_charging_default[NUM_ESR_TIMERS]; enum slope_limit_status slope_limit_sts; bool profile_available; bool profile_loaded; diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 26648595c55c..36ac1960a176 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -1025,12 +1025,15 @@ static inline void get_esr_meas_current(int curr_ma, u8 *val) *val <<= ESR_PULL_DOWN_IVAL_SHIFT; } -static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging, - int flags) +static int fg_set_esr_timer(struct fg_chip *chip, int cycles_init, + int cycles_max, bool charging, int flags) { u8 buf[2]; int rc, timer_max, timer_init; + if (cycles_init < 0 || cycles_max < 0) + return 0; + if (charging) { timer_max = FG_SRAM_ESR_TIMER_CHG_MAX; timer_init = FG_SRAM_ESR_TIMER_CHG_INIT; @@ -1039,7 +1042,7 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging, timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT; } - fg_encode(chip->sp, timer_max, cycles, buf); + fg_encode(chip->sp, timer_max, cycles_max, buf); rc = fg_sram_write(chip, chip->sp[timer_max].addr_word, chip->sp[timer_max].addr_byte, buf, @@ -1050,7 +1053,7 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging, return rc; } - fg_encode(chip->sp, timer_init, cycles, buf); + fg_encode(chip->sp, timer_init, cycles_init, buf); rc = fg_sram_write(chip, chip->sp[timer_init].addr_word, chip->sp[timer_init].addr_byte, buf, @@ -1061,6 +1064,8 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging, return rc; } + fg_dbg(chip, FG_STATUS, "esr_%s_timer set to %d/%d\n", + charging ? "charging" : "discharging", cycles_init, cycles_max); return 0; } @@ -2039,6 +2044,50 @@ static int fg_esr_fcc_config(struct fg_chip *chip) return 0; } +static int fg_esr_timer_config(struct fg_chip *chip, bool sleep) +{ + int rc, cycles_init, cycles_max; + bool end_of_charge = false; + + end_of_charge = is_input_present(chip) && chip->charge_done; + fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge); + + /* ESR discharging timer configuration */ + cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] : + chip->dt.esr_timer_awake[TIMER_RETRY]; + if (end_of_charge) + cycles_init = 0; + + cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] : + chip->dt.esr_timer_awake[TIMER_MAX]; + + rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false, + sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in setting ESR timer, rc=%d\n", rc); + return rc; + } + + /* ESR charging timer configuration */ + cycles_init = cycles_max = -EINVAL; + if (end_of_charge || sleep) { + cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY]; + cycles_max = chip->dt.esr_timer_charging[TIMER_MAX]; + } else if (is_input_present(chip)) { + cycles_init = chip->esr_timer_charging_default[TIMER_RETRY]; + cycles_max = chip->esr_timer_charging_default[TIMER_MAX]; + } + + rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true, + sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in setting ESR timer, rc=%d\n", rc); + return rc; + } + + return 0; +} + static void fg_batt_avg_update(struct fg_chip *chip) { if (chip->charge_status == chip->prev_charge_status) @@ -2112,6 +2161,10 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); + rc = fg_esr_timer_config(chip, false); + if (rc < 0) + pr_err("Error in configuring ESR timer, rc=%d\n", rc); + rc = fg_get_battery_temp(chip, &batt_temp); if (!rc) { rc = fg_slope_limit_config(chip, batt_temp); @@ -3115,6 +3168,8 @@ static const struct power_supply_desc fg_psy_desc = { /* INIT FUNCTIONS STAY HERE */ +#define DEFAULT_ESR_CHG_TIMER_RETRY 8 +#define DEFAULT_ESR_CHG_TIMER_MAX 16 static int fg_hw_init(struct fg_chip *chip) { int rc; @@ -3283,22 +3338,29 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } - if (chip->dt.esr_timer_charging > 0) { - rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging, true, - FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in setting ESR timer, rc=%d\n", rc); - return rc; - } + if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) { + chip->esr_timer_charging_default[TIMER_RETRY] = + DEFAULT_ESR_CHG_TIMER_RETRY; + chip->esr_timer_charging_default[TIMER_MAX] = + DEFAULT_ESR_CHG_TIMER_MAX; + } else { + /* We don't need this for pm660 at present */ + chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL; + chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL; } - if (chip->dt.esr_timer_awake > 0) { - rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false, - FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in setting ESR timer, rc=%d\n", rc); - return rc; - } + rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY], + chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in setting ESR timer, rc=%d\n", rc); + return rc; + } + + rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY], + chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in setting ESR timer, rc=%d\n", rc); + return rc; } if (chip->cyc_ctr.en) @@ -3778,6 +3840,32 @@ static int fg_register_interrupts(struct fg_chip *chip) return 0; } +static int fg_parse_dt_property_u32_array(struct device_node *node, + const char *prop_name, int *buf, int len) +{ + int rc; + + rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32)); + if (rc < 0) { + if (rc == -EINVAL) + return 0; + else + return rc; + } else if (rc != len) { + pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name, + rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(node, prop_name, buf, len); + if (rc < 0) { + pr_err("Error in reading %s, rc=%d\n", prop_name, rc); + return rc; + } + + return 0; +} + static int fg_parse_slope_limit_coefficients(struct fg_chip *chip) { struct device_node *node = chip->dev->of_node; @@ -3788,17 +3876,10 @@ static int fg_parse_slope_limit_coefficients(struct fg_chip *chip) if (rc < 0) return 0; - rc = of_property_count_elems_of_size(node, "qcom,slope-limit-coeffs", - sizeof(u32)); - if (rc != SLOPE_LIMIT_NUM_COEFFS) - return -EINVAL; - - rc = of_property_read_u32_array(node, "qcom,slope-limit-coeffs", - chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS); - if (rc < 0) { - pr_err("Error in reading qcom,slope-limit-coeffs, rc=%d\n", rc); + rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs", + chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS); + if (rc < 0) return rc; - } for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) { if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX || @@ -3817,44 +3898,20 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip) struct device_node *node = chip->dev->of_node; int rc, i; - rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-soc-dischg", - sizeof(u32)); - if (rc != KI_COEFF_SOC_LEVELS) - return 0; - - rc = of_property_read_u32_array(node, "qcom,ki-coeff-soc-dischg", - chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS); - if (rc < 0) { - pr_err("Error in reading ki-coeff-soc-dischg, rc=%d\n", - rc); + rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg", + chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS); + if (rc < 0) return rc; - } - - rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-med-dischg", - sizeof(u32)); - if (rc != KI_COEFF_SOC_LEVELS) - return 0; - rc = of_property_read_u32_array(node, "qcom,ki-coeff-med-dischg", - chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS); - if (rc < 0) { - pr_err("Error in reading ki-coeff-med-dischg, rc=%d\n", - rc); + rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg", + chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS); + if (rc < 0) return rc; - } - - rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-hi-dischg", - sizeof(u32)); - if (rc != KI_COEFF_SOC_LEVELS) - return 0; - rc = of_property_read_u32_array(node, "qcom,ki-coeff-hi-dischg", - chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS); - if (rc < 0) { - pr_err("Error in reading ki-coeff-hi-dischg, rc=%d\n", - rc); + rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg", + chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS); + if (rc < 0) return rc; - } for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) { if (chip->dt.ki_coeff_soc[i] < 0 || @@ -4099,23 +4156,26 @@ static int fg_parse_dt(struct fg_chip *chip) rc); } - rc = of_property_read_u32(node, "qcom,fg-esr-timer-charging", &temp); - if (rc < 0) - chip->dt.esr_timer_charging = -EINVAL; - else - chip->dt.esr_timer_charging = temp; + rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging", + chip->dt.esr_timer_charging, NUM_ESR_TIMERS); + if (rc < 0) { + chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL; + } - rc = of_property_read_u32(node, "qcom,fg-esr-timer-awake", &temp); - if (rc < 0) - chip->dt.esr_timer_awake = -EINVAL; - else - chip->dt.esr_timer_awake = temp; + rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake", + chip->dt.esr_timer_awake, NUM_ESR_TIMERS); + if (rc < 0) { + chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL; + } - rc = of_property_read_u32(node, "qcom,fg-esr-timer-asleep", &temp); - if (rc < 0) - chip->dt.esr_timer_asleep = -EINVAL; - else - chip->dt.esr_timer_asleep = temp; + rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep", + chip->dt.esr_timer_asleep, NUM_ESR_TIMERS); + if (rc < 0) { + chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL; + } chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en"); if (chip->cyc_ctr.en) @@ -4453,15 +4513,9 @@ static int fg_gen3_suspend(struct device *dev) struct fg_chip *chip = dev_get_drvdata(dev); int rc; - if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) { - rc = fg_set_esr_timer(chip, chip->dt.esr_timer_asleep, false, - FG_IMA_NO_WLOCK); - if (rc < 0) { - pr_err("Error in setting ESR timer during suspend, rc=%d\n", - rc); - return rc; - } - } + rc = fg_esr_timer_config(chip, true); + if (rc < 0) + pr_err("Error in configuring ESR timer, rc=%d\n", rc); cancel_delayed_work_sync(&chip->batt_avg_work); if (fg_sram_dump) @@ -4474,15 +4528,9 @@ static int fg_gen3_resume(struct device *dev) struct fg_chip *chip = dev_get_drvdata(dev); int rc; - if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) { - rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false, - FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in setting ESR timer during resume, rc=%d\n", - rc); - return rc; - } - } + rc = fg_esr_timer_config(chip, false); + if (rc < 0) + pr_err("Error in configuring ESR timer, rc=%d\n", rc); fg_circ_buf_clr(&chip->ibatt_circ_buf); fg_circ_buf_clr(&chip->vbatt_circ_buf); |
