power: qpnp-fg-gen3: Improve the accuracy of charge_counter
Currently, charge_counter is based off CC_SOC_SW which is based off coulomb counter. However, there could be some accumulation of error due to inaccuracy in ADC over time. This can potentially affect the accuracy of charge_counter. To overcome this, prime CC_SOC_SW during discharging based off battery SOC and to a full value during charge termination. While at it, expose the charge_counter_shadow property based off battery SOC for comparison. CRs-Fixed: 2109421 Change-Id: I50de44afbdbd747db95946416a09062df205fd6c Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
This commit is contained in:
parent
d475978a5f
commit
a87340d406
2 changed files with 69 additions and 11 deletions
|
@ -412,6 +412,7 @@ struct fg_chip {
|
|||
int batt_id_ohms;
|
||||
int ki_coeff_full_soc;
|
||||
int charge_status;
|
||||
int prev_charge_status;
|
||||
int charge_done;
|
||||
int charge_type;
|
||||
int online_status;
|
||||
|
|
|
@ -562,6 +562,21 @@ static int fg_get_charge_raw(struct fg_chip *chip, int *val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define BATT_SOC_32BIT GENMASK(31, 0)
|
||||
static int fg_get_charge_counter_shadow(struct fg_chip *chip, int *val)
|
||||
{
|
||||
int rc, batt_soc;
|
||||
|
||||
rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
|
||||
if (rc < 0) {
|
||||
pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
*val = div_u64((u32)batt_soc * chip->cl.learned_cc_uah, BATT_SOC_32BIT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fg_get_charge_counter(struct fg_chip *chip, int *val)
|
||||
{
|
||||
int rc, cc_soc;
|
||||
|
@ -1249,6 +1264,21 @@ static bool is_parallel_charger_available(struct fg_chip *chip)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int fg_prime_cc_soc_sw(struct fg_chip *chip, int cc_soc_sw)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
|
||||
chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
|
||||
chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
|
||||
if (rc < 0)
|
||||
pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
|
||||
else
|
||||
fg_dbg(chip, FG_STATUS, "cc_soc_sw: %x\n", cc_soc_sw);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fg_save_learned_cap_to_sram(struct fg_chip *chip)
|
||||
{
|
||||
int16_t cc_mah;
|
||||
|
@ -1434,7 +1464,6 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define BATT_SOC_32BIT GENMASK(31, 0)
|
||||
static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
|
||||
{
|
||||
int rc, cc_soc_sw, batt_soc_msb;
|
||||
|
@ -1453,16 +1482,13 @@ static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
|
|||
/* Prime cc_soc_sw with battery SOC when capacity learning begins */
|
||||
cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
|
||||
BATT_SOC_32BIT);
|
||||
rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
|
||||
chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
|
||||
chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
|
||||
rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
|
||||
if (rc < 0) {
|
||||
pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
chip->cl.init_cc_soc_sw = cc_soc_sw;
|
||||
chip->cl.active = true;
|
||||
fg_dbg(chip, FG_CAP_LEARN, "Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n",
|
||||
batt_soc_msb, chip->cl.init_cc_soc_sw);
|
||||
out:
|
||||
|
@ -1482,9 +1508,7 @@ static int fg_cap_learning_done(struct fg_chip *chip)
|
|||
|
||||
/* Write a FULL value to cc_soc_sw */
|
||||
cc_soc_sw = CC_SOC_30BIT;
|
||||
rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
|
||||
chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
|
||||
chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
|
||||
rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
|
||||
if (rc < 0) {
|
||||
pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
|
||||
goto out;
|
||||
|
@ -1497,8 +1521,9 @@ out:
|
|||
|
||||
static void fg_cap_learning_update(struct fg_chip *chip)
|
||||
{
|
||||
int rc, batt_soc, batt_soc_msb;
|
||||
int rc, batt_soc, batt_soc_msb, cc_soc_sw;
|
||||
bool input_present = is_input_present(chip);
|
||||
bool prime_cc = false;
|
||||
|
||||
mutex_lock(&chip->cl.lock);
|
||||
|
||||
|
@ -1511,6 +1536,9 @@ static void fg_cap_learning_update(struct fg_chip *chip)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (chip->charge_status == chip->prev_charge_status)
|
||||
goto out;
|
||||
|
||||
rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
|
||||
if (rc < 0) {
|
||||
pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
|
||||
|
@ -1526,8 +1554,12 @@ static void fg_cap_learning_update(struct fg_chip *chip)
|
|||
if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
|
||||
rc = fg_cap_learning_begin(chip, batt_soc);
|
||||
chip->cl.active = (rc == 0);
|
||||
} else {
|
||||
if ((chip->charge_status ==
|
||||
POWER_SUPPLY_STATUS_DISCHARGING) ||
|
||||
chip->charge_done)
|
||||
prime_cc = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (chip->charge_done) {
|
||||
rc = fg_cap_learning_done(chip);
|
||||
|
@ -1545,6 +1577,7 @@ static void fg_cap_learning_update(struct fg_chip *chip)
|
|||
batt_soc_msb);
|
||||
chip->cl.active = false;
|
||||
chip->cl.init_cc_uah = 0;
|
||||
prime_cc = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1561,10 +1594,29 @@ static void fg_cap_learning_update(struct fg_chip *chip)
|
|||
batt_soc_msb);
|
||||
chip->cl.active = false;
|
||||
chip->cl.init_cc_uah = 0;
|
||||
prime_cc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prime CC_SOC_SW when the device is not charging or during charge
|
||||
* termination when the capacity learning is not active.
|
||||
*/
|
||||
|
||||
if (prime_cc) {
|
||||
if (chip->charge_done)
|
||||
cc_soc_sw = CC_SOC_30BIT;
|
||||
else
|
||||
cc_soc_sw = div_u64((u32)batt_soc *
|
||||
CC_SOC_30BIT, BATT_SOC_32BIT);
|
||||
|
||||
rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
|
||||
if (rc < 0)
|
||||
pr_err("Error in writing cc_soc_sw, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&chip->cl.lock);
|
||||
}
|
||||
|
@ -2564,7 +2616,7 @@ static void status_change_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
fg_ttf_update(chip);
|
||||
|
||||
chip->prev_charge_status = chip->charge_status;
|
||||
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);
|
||||
|
@ -3553,6 +3605,9 @@ static int fg_psy_get_property(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
|
||||
rc = fg_get_charge_counter(chip, &pval->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
|
||||
rc = fg_get_charge_counter_shadow(chip, &pval->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
|
||||
rc = fg_get_time_to_full(chip, &pval->intval);
|
||||
break;
|
||||
|
@ -3762,6 +3817,7 @@ static enum power_supply_property fg_psy_props[] = {
|
|||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
||||
POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
|
||||
POWER_SUPPLY_PROP_SOC_REPORTING_READY,
|
||||
|
@ -4958,6 +5014,7 @@ static int fg_gen3_probe(struct platform_device *pdev)
|
|||
chip->debug_mask = &fg_gen3_debug_mask;
|
||||
chip->irqs = fg_irqs;
|
||||
chip->charge_status = -EINVAL;
|
||||
chip->prev_charge_status = -EINVAL;
|
||||
chip->ki_coeff_full_soc = -EINVAL;
|
||||
chip->online_status = -EINVAL;
|
||||
chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
|
||||
|
|
Loading…
Add table
Reference in a new issue