power: qpnp-fg-gen3: improve cycle counter algorithm

Currently, when the charging status transitions to a state other
than charging, cycle counter algorithm stores the cycle count for
all the buckets for which the counting had started. This is fine
with respect to the algorithm.

However with qnovo enabled charging, this can cause issues when
charging status can go to not charging intermittently causing the
cycle count to be stored multiple times for a bucket. Modify the
logic to check for the charge termination or the presence of
input to go through all the buckets for storing the count. Also,
increment and store the counter only if battery SOC had increased
more than 2 LSBs for that SOC bucket.

While at it, run cycle_counter algorithm as a function instead
of a work. Also, keep the usage of cycle counter feature enable
flag inside the cycle counter APIs.

Change-Id: I62a92964ccbc6b965af09696deddc6fa8366a841
Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
This commit is contained in:
Subbaraman Narayanamurthy 2017-06-09 15:09:11 -07:00 committed by Nicholas Troast
parent 96168e19d4
commit 183bc63f12
2 changed files with 103 additions and 121 deletions

View file

@ -49,7 +49,6 @@
#define SRAM_READ "fg_sram_read"
#define SRAM_WRITE "fg_sram_write"
#define PROFILE_LOAD "fg_profile_load"
#define DELTA_SOC "fg_delta_soc"
#define TTF_PRIMING "fg_ttf_priming"
/* Delta BSOC irq votable reasons */
@ -438,7 +437,6 @@ struct fg_chip {
struct completion soc_ready;
struct delayed_work profile_load_work;
struct work_struct status_change_work;
struct work_struct cycle_count_work;
struct delayed_work ttf_work;
struct delayed_work sram_dump_work;
};

View file

@ -2231,94 +2231,14 @@ static void fg_ttf_update(struct fg_chip *chip)
schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
}
static void status_change_work(struct work_struct *work)
{
struct fg_chip *chip = container_of(work,
struct fg_chip, status_change_work);
union power_supply_propval prop = {0, };
int rc, batt_temp;
if (!batt_psy_initialized(chip)) {
fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
goto out;
}
rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
&prop);
if (rc < 0) {
pr_err("Error in getting charging status, rc=%d\n", rc);
goto out;
}
chip->prev_charge_status = chip->charge_status;
chip->charge_status = prop.intval;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
if (rc < 0) {
pr_err("Error in getting charge type, rc=%d\n", rc);
goto out;
}
chip->charge_type = prop.intval;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
if (rc < 0) {
pr_err("Error in getting charge_done, rc=%d\n", rc);
goto out;
}
chip->charge_done = prop.intval;
if (chip->cyc_ctr.en)
schedule_work(&chip->cycle_count_work);
fg_cap_learning_update(chip);
rc = fg_charge_full_update(chip);
if (rc < 0)
pr_err("Error in charge_full_update, rc=%d\n", rc);
rc = fg_adjust_recharge_soc(chip);
if (rc < 0)
pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
rc = fg_adjust_ki_coeff_dischg(chip);
if (rc < 0)
pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
rc = fg_esr_fcc_config(chip);
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);
if (rc < 0)
pr_err("Error in configuring slope limiter rc:%d\n",
rc);
rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
if (rc < 0)
pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
rc);
}
fg_ttf_update(chip);
out:
fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
chip->charge_status, chip->charge_type, chip->charge_done);
pm_relax(chip->dev);
}
static void restore_cycle_counter(struct fg_chip *chip)
{
int rc = 0, i;
u8 data[2];
if (!chip->cyc_ctr.en)
return;
mutex_lock(&chip->cyc_ctr.lock);
for (i = 0; i < BUCKET_COUNT; i++) {
rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
@ -2372,20 +2292,25 @@ static int fg_inc_store_cycle_ctr(struct fg_chip *chip, int bucket)
rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
FG_IMA_DEFAULT);
if (rc < 0)
if (rc < 0) {
pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
bucket, rc);
else
chip->cyc_ctr.count[bucket] = cyc_count;
return rc;
}
chip->cyc_ctr.count[bucket] = cyc_count;
fg_dbg(chip, FG_STATUS, "Stored count %d in bucket %d\n", cyc_count,
bucket);
return rc;
}
static void cycle_count_work(struct work_struct *work)
static void fg_cycle_counter_update(struct fg_chip *chip)
{
int rc = 0, bucket, i, batt_soc;
struct fg_chip *chip = container_of(work,
struct fg_chip,
cycle_count_work);
if (!chip->cyc_ctr.en)
return;
mutex_lock(&chip->cyc_ctr.lock);
rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
@ -2397,45 +2322,30 @@ static void cycle_count_work(struct work_struct *work)
/* We need only the most significant byte here */
batt_soc = (u32)batt_soc >> 24;
if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
/* Find out which bucket the SOC falls in */
bucket = batt_soc / BUCKET_SOC_PCT;
pr_debug("batt_soc: %d bucket: %d\n", batt_soc, bucket);
/* Find out which bucket the SOC falls in */
bucket = batt_soc / BUCKET_SOC_PCT;
/*
* If we've started counting for the previous bucket,
* then store the counter for that bucket if the
* counter for current bucket is getting started.
*/
if (bucket > 0 && chip->cyc_ctr.started[bucket - 1] &&
!chip->cyc_ctr.started[bucket]) {
rc = fg_inc_store_cycle_ctr(chip, bucket - 1);
if (rc < 0) {
pr_err("Error in storing cycle_ctr rc: %d\n",
rc);
goto out;
} else {
chip->cyc_ctr.started[bucket - 1] = false;
chip->cyc_ctr.last_soc[bucket - 1] = 0;
}
}
if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
if (!chip->cyc_ctr.started[bucket]) {
chip->cyc_ctr.started[bucket] = true;
chip->cyc_ctr.last_soc[bucket] = batt_soc;
}
} else {
} else if (chip->charge_done || !is_input_present(chip)) {
for (i = 0; i < BUCKET_COUNT; i++) {
if (chip->cyc_ctr.started[i] &&
batt_soc > chip->cyc_ctr.last_soc[i]) {
batt_soc > chip->cyc_ctr.last_soc[i] + 2) {
rc = fg_inc_store_cycle_ctr(chip, i);
if (rc < 0)
pr_err("Error in storing cycle_ctr rc: %d\n",
rc);
chip->cyc_ctr.last_soc[i] = 0;
chip->cyc_ctr.started[i] = false;
}
chip->cyc_ctr.started[i] = false;
}
}
fg_dbg(chip, FG_STATUS, "batt_soc: %d bucket: %d chg_status: %d\n",
batt_soc, bucket, chip->charge_status);
out:
mutex_unlock(&chip->cyc_ctr.lock);
}
@ -2456,6 +2366,83 @@ static int fg_get_cycle_count(struct fg_chip *chip)
return count;
}
static void status_change_work(struct work_struct *work)
{
struct fg_chip *chip = container_of(work,
struct fg_chip, status_change_work);
union power_supply_propval prop = {0, };
int rc, batt_temp;
if (!batt_psy_initialized(chip)) {
fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
goto out;
}
rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
&prop);
if (rc < 0) {
pr_err("Error in getting charging status, rc=%d\n", rc);
goto out;
}
chip->prev_charge_status = chip->charge_status;
chip->charge_status = prop.intval;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
if (rc < 0) {
pr_err("Error in getting charge type, rc=%d\n", rc);
goto out;
}
chip->charge_type = prop.intval;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
if (rc < 0) {
pr_err("Error in getting charge_done, rc=%d\n", rc);
goto out;
}
chip->charge_done = prop.intval;
fg_cycle_counter_update(chip);
fg_cap_learning_update(chip);
rc = fg_charge_full_update(chip);
if (rc < 0)
pr_err("Error in charge_full_update, rc=%d\n", rc);
rc = fg_adjust_recharge_soc(chip);
if (rc < 0)
pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
rc = fg_adjust_ki_coeff_dischg(chip);
if (rc < 0)
pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
rc = fg_esr_fcc_config(chip);
if (rc < 0)
pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
rc = fg_get_battery_temp(chip, &batt_temp);
if (!rc) {
rc = fg_slope_limit_config(chip, batt_temp);
if (rc < 0)
pr_err("Error in configuring slope limiter rc:%d\n",
rc);
rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
if (rc < 0)
pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
rc);
}
fg_ttf_update(chip);
out:
fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
chip->charge_status, chip->charge_type, chip->charge_done);
pm_relax(chip->dev);
}
static int fg_bp_params_config(struct fg_chip *chip)
{
int rc = 0;
@ -3755,8 +3742,7 @@ static int fg_hw_init(struct fg_chip *chip)
return rc;
}
if (chip->cyc_ctr.en)
restore_cycle_counter(chip);
restore_cycle_counter(chip);
if (chip->dt.jeita_hyst_temp >= 0) {
val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
@ -4030,8 +4016,7 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
int rc;
fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
if (chip->cyc_ctr.en)
schedule_work(&chip->cycle_count_work);
fg_cycle_counter_update(chip);
if (chip->cl.active)
fg_cap_learning_update(chip);
@ -4801,7 +4786,6 @@ static int fg_gen3_probe(struct platform_device *pdev)
init_completion(&chip->soc_ready);
INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
INIT_WORK(&chip->status_change_work, status_change_work);
INIT_WORK(&chip->cycle_count_work, cycle_count_work);
INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);