diff options
author | Linux Build Service Account <lnxbuild@quicinc.com> | 2017-06-01 23:49:12 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-06-01 23:49:12 -0700 |
commit | 985d03300dcb647b2540e01bdb43c52e10504744 (patch) | |
tree | 18d0cb6c2f5103bef158589b0ab2eb9f7783c65c /drivers | |
parent | 99beece72f1afc37bbdaa51cf437e412962119f9 (diff) | |
parent | 6124f7574427070e5772366e3ceb53151303104f (diff) |
Merge "qpnp-fg-gen3: configure ESR timers dynamically based on charge termination"
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/supply/qcom/fg-core.h | 13 | ||||
-rw-r--r-- | drivers/power/supply/qcom/qpnp-fg-gen3.c | 236 |
2 files changed, 152 insertions, 97 deletions
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); |