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:
parent
96168e19d4
commit
183bc63f12
2 changed files with 103 additions and 121 deletions
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue