summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@quicinc.com>2017-06-01 23:49:12 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-06-01 23:49:12 -0700
commit985d03300dcb647b2540e01bdb43c52e10504744 (patch)
tree18d0cb6c2f5103bef158589b0ab2eb9f7783c65c /drivers
parent99beece72f1afc37bbdaa51cf437e412962119f9 (diff)
parent6124f7574427070e5772366e3ceb53151303104f (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.h13
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c236
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);