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:
Subbaraman Narayanamurthy 2017-09-13 16:38:40 -07:00
parent d475978a5f
commit a87340d406
2 changed files with 69 additions and 11 deletions

View file

@ -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;

View file

@ -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);