power: qpnp-fg: add support for ESR pulse tuning feature

Currently, ESR is being under-estimated when the battery state of
charge (SOC) is less than 2%. Add a change which can do tuning to
use default ESR values when SOC is less than 2% and switch back
to ESR extraction when SOC goes above 2%. When the SOC is greater
than 2% and less than 5%, apply slow settings for ESR pulse. When
the SOC crosses 5%, apply the default settings.

This will allow the SOC to increase more accurately when the FG
starts with a better ESR value. This feature is supported via
device tree property "qcom,esr-pulse-tuning-en".

CRs-Fixed: 953448
Change-Id: I37da8d2a9d795dc3d4daffeaf80a72d188243bfd
Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
This commit is contained in:
Subbaraman Narayanamurthy 2015-12-16 18:48:53 -08:00 committed by David Keitel
parent 3ad8f9a878
commit 467ced45c8
2 changed files with 217 additions and 0 deletions

View file

@ -168,6 +168,16 @@ Parent node optional properties:
coulomb count.
- qcom,fg-therm-delay-us: The time in microseconds to delay battery
thermistor biasing.
- qcom,esr-pulse-tuning-en: A boolean property to enable ESR pulse
tuning feature. If this is enabled,
ESR pulse extraction will be disabled
when state of charge (SOC) is less than
2%. It will be enabled back when SOC
gets above 2%. In addition, for SOC
between 2% and 5%, ESR pulse timing
settings will be different from default.
Once SOC crosses 5%, ESR pulse timings
will be restored back to default.
qcom,fg-soc node required properties:
- reg : offset and length of the PMIC peripheral register map.

View file

@ -506,11 +506,18 @@ struct fg_chip {
u16 *offset;
bool ima_supported;
bool init_done;
/* jeita hysteresis */
bool jeita_hysteresis_support;
bool batt_hot;
bool batt_cold;
int cold_hysteresis;
int hot_hysteresis;
/* ESR pulse tuning */
struct fg_wakeup_source esr_extract_wakeup_source;
struct work_struct esr_extract_config_work;
bool esr_extract_disabled;
bool imptr_pulse_slow_en;
bool esr_pulse_tune_en;
};
/* FG_MEMIF DEBUGFS structures */
@ -3318,6 +3325,11 @@ static void status_change_work(struct work_struct *work)
unsigned long current_time = 0;
int cc_soc, rc, capacity = get_prop_capacity(chip);
if (chip->esr_pulse_tune_en) {
fg_stay_awake(&chip->esr_extract_wakeup_source);
schedule_work(&chip->esr_extract_config_work);
}
if (chip->status == POWER_SUPPLY_STATUS_FULL) {
if (capacity >= 99 && chip->hold_soc_while_full
&& chip->health == POWER_SUPPLY_HEALTH_GOOD) {
@ -3970,6 +3982,11 @@ static irqreturn_t fg_soc_irq_handler(int irq, void *_chip)
schedule_work(&chip->fg_cap_learning_work);
}
if (chip->esr_pulse_tune_en) {
fg_stay_awake(&chip->esr_extract_wakeup_source);
schedule_work(&chip->esr_extract_config_work);
}
return IRQ_HANDLED;
}
@ -4351,6 +4368,150 @@ static void update_cc_cv_setpoint(struct fg_chip *chip)
tmp[0], tmp[1], CC_CV_SETPOINT_REG);
}
#define CBITS_INPUT_FILTER_REG 0x4B4
#define CBITS_RMEAS1_OFFSET 1
#define CBITS_RMEAS2_OFFSET 2
#define CBITS_RMEAS1_DEFAULT_VAL 0x65
#define CBITS_RMEAS2_DEFAULT_VAL 0x65
#define IMPTR_FAST_TIME_SHIFT 1
#define IMPTR_LONG_TIME_SHIFT (1 << 4)
#define IMPTR_PULSE_CTR_CHG 1
#define IMPTR_PULSE_CTR_DISCHG (1 << 4)
static int fg_config_imptr_pulse(struct fg_chip *chip, bool slow)
{
int rc;
u8 cntr[2] = {0, 0};
u8 val;
if (slow == chip->imptr_pulse_slow_en) {
if (fg_debug_mask & FG_STATUS)
pr_info("imptr_pulse_slow is %sabled already\n",
slow ? "en" : "dis");
return 0;
}
fg_mem_lock(chip);
val = slow ? (IMPTR_FAST_TIME_SHIFT | IMPTR_LONG_TIME_SHIFT) :
CBITS_RMEAS1_DEFAULT_VAL;
rc = fg_mem_write(chip, &val, CBITS_INPUT_FILTER_REG, 1,
CBITS_RMEAS1_OFFSET, 0);
if (rc) {
pr_err("unable to write cbits_rmeas1_offset rc=%d\n", rc);
goto done;
}
val = slow ? (IMPTR_PULSE_CTR_CHG | IMPTR_PULSE_CTR_DISCHG) :
CBITS_RMEAS2_DEFAULT_VAL;
rc = fg_mem_write(chip, &val, CBITS_INPUT_FILTER_REG, 1,
CBITS_RMEAS2_OFFSET, 0);
if (rc) {
pr_err("unable to write cbits_rmeas2_offset rc=%d\n", rc);
goto done;
}
if (slow) {
rc = fg_mem_write(chip, cntr, COUNTER_IMPTR_REG, 4,
COUNTER_IMPTR_OFFSET, 0);
if (rc) {
pr_err("failed to write COUNTER_IMPTR rc=%d\n", rc);
goto done;
}
rc = fg_mem_write(chip, cntr, COUNTER_PULSE_REG, 2,
COUNTER_PULSE_OFFSET, 0);
if (rc) {
pr_err("failed to write COUNTER_IMPTR rc=%d\n", rc);
goto done;
}
}
chip->imptr_pulse_slow_en = slow;
if (fg_debug_mask & FG_STATUS)
pr_info("imptr_pulse_slow is %sabled\n", slow ? "en" : "dis");
done:
fg_mem_release(chip);
return rc;
}
#define CURRENT_DELTA_MIN_REG 0x42C
#define CURRENT_DELTA_MIN_OFFSET 1
#define SYS_CFG_1_REG 0x4AC
#define SYS_CFG_1_OFFSET 0
#define CURRENT_DELTA_MIN_DEFAULT 0x16
#define CURRENT_DELTA_MIN_500MA 0xCD
#define RSLOW_CFG_USE_FIX_RSER_VAL BIT(7)
#define ENABLE_ESR_PULSE_VAL BIT(3)
static int fg_config_esr_extract(struct fg_chip *chip, bool disable)
{
int rc;
u8 val;
if (disable == chip->esr_extract_disabled) {
if (fg_debug_mask & FG_STATUS)
pr_info("ESR extract already %sabled\n",
disable ? "dis" : "en");
return 0;
}
fg_mem_lock(chip);
val = disable ? CURRENT_DELTA_MIN_500MA :
CURRENT_DELTA_MIN_DEFAULT;
rc = fg_mem_write(chip, &val, CURRENT_DELTA_MIN_REG, 1,
CURRENT_DELTA_MIN_OFFSET, 0);
if (rc) {
pr_err("unable to write curr_delta_min rc=%d\n", rc);
goto done;
}
val = disable ? RSLOW_CFG_USE_FIX_RSER_VAL : 0;
rc = fg_mem_masked_write(chip, RSLOW_CFG_REG,
RSLOW_CFG_USE_FIX_RSER_VAL, val, RSLOW_CFG_OFFSET);
if (rc) {
pr_err("unable to write rslow cfg rc= %d\n", rc);
goto done;
}
val = disable ? 0 : ENABLE_ESR_PULSE_VAL;
rc = fg_mem_masked_write(chip, SYS_CFG_1_REG,
ENABLE_ESR_PULSE_VAL, val, SYS_CFG_1_OFFSET);
if (rc) {
pr_err("unable to write sys_cfg_1 rc= %d\n", rc);
goto done;
}
chip->esr_extract_disabled = disable;
if (fg_debug_mask & FG_STATUS)
pr_info("ESR extract is %sabled\n", disable ? "dis" : "en");
done:
fg_mem_release(chip);
return rc;
}
#define ESR_EXTRACT_STOP_SOC 2
#define IMPTR_PULSE_CONFIG_SOC 5
static void esr_extract_config_work(struct work_struct *work)
{
struct fg_chip *chip = container_of(work, struct fg_chip,
esr_extract_config_work);
bool input_present = is_input_present(chip);
int capacity = get_prop_capacity(chip);
if (input_present && capacity <= ESR_EXTRACT_STOP_SOC) {
fg_config_esr_extract(chip, true);
} else if (capacity > ESR_EXTRACT_STOP_SOC) {
fg_config_esr_extract(chip, false);
if (capacity <= IMPTR_PULSE_CONFIG_SOC)
fg_config_imptr_pulse(chip, true);
else
fg_config_imptr_pulse(chip, false);
}
fg_relax(&chip->esr_extract_wakeup_source);
}
#define LOW_LATENCY BIT(6)
#define BATT_PROFILE_OFFSET 0x4C0
#define PROFILE_INTEGRITY_REG 0x53C
@ -4507,6 +4668,11 @@ try_again:
*/
reinit_completion(&chip->first_soc_done);
if (chip->esr_pulse_tune_en) {
fg_stay_awake(&chip->esr_extract_wakeup_source);
schedule_work(&chip->esr_extract_config_work);
}
/*
* set the restart bits so that the next fg cycle will not reload
* the profile
@ -5287,6 +5453,9 @@ static int fg_of_init(struct fg_chip *chip)
if (chip->cyc_ctr.en)
chip->cyc_ctr.id = 1;
chip->esr_pulse_tune_en = of_property_read_bool(node,
"qcom,esr-pulse-tuning-en");
return rc;
}
@ -5498,6 +5667,7 @@ static void fg_cleanup(struct fg_chip *chip)
wakeup_source_trash(&chip->update_sram_wakeup_source.source);
wakeup_source_trash(&chip->gain_comp_wakeup_source.source);
wakeup_source_trash(&chip->capacity_learning_wakeup_source.source);
wakeup_source_trash(&chip->esr_extract_wakeup_source.source);
}
static int fg_remove(struct platform_device *pdev)
@ -5976,6 +6146,7 @@ static int fg_common_hw_init(struct fg_chip *chip)
{
int rc;
int resume_soc_raw;
u8 val;
update_iterm(chip);
update_cutoff_voltage(chip);
@ -6048,6 +6219,37 @@ static int fg_common_hw_init(struct fg_chip *chip)
if (chip->cyc_ctr.en)
restore_cycle_counter(chip);
if (chip->esr_pulse_tune_en) {
rc = fg_mem_read(chip, &val, SYS_CFG_1_REG, 1, SYS_CFG_1_OFFSET,
0);
if (rc) {
pr_err("unable to read sys_cfg_1: %d\n", rc);
return rc;
}
if (!(val & ENABLE_ESR_PULSE_VAL))
chip->esr_extract_disabled = true;
if (fg_debug_mask & FG_STATUS)
pr_info("ESR extract is %sabled\n",
chip->esr_extract_disabled ? "dis" : "en");
rc = fg_mem_read(chip, &val, CBITS_INPUT_FILTER_REG, 1,
CBITS_RMEAS1_OFFSET, 0);
if (rc) {
pr_err("unable to read cbits_input_filter_reg: %d\n",
rc);
return rc;
}
if (val & (IMPTR_FAST_TIME_SHIFT | IMPTR_LONG_TIME_SHIFT))
chip->imptr_pulse_slow_en = true;
if (fg_debug_mask & FG_STATUS)
pr_info("imptr_pulse_slow is %sabled\n",
chip->imptr_pulse_slow_en ? "en" : "dis");
}
return 0;
}
@ -6432,6 +6634,8 @@ static int fg_probe(struct platform_device *pdev)
"qpnp_fg_gain_comp");
wakeup_source_init(&chip->capacity_learning_wakeup_source.source,
"qpnp_fg_cap_learning");
wakeup_source_init(&chip->esr_extract_wakeup_source.source,
"qpnp_fg_esr_extract");
mutex_init(&chip->rw_lock);
mutex_init(&chip->cyc_ctr.lock);
mutex_init(&chip->learning_data.learning_lock);
@ -6455,6 +6659,7 @@ static int fg_probe(struct platform_device *pdev)
INIT_WORK(&chip->charge_full_work, charge_full_work);
INIT_WORK(&chip->gain_comp_work, iadc_gain_comp_work);
INIT_WORK(&chip->bcl_hi_power_work, bcl_hi_power_work);
INIT_WORK(&chip->esr_extract_config_work, esr_extract_config_work);
alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME,
fg_cap_learning_alarm_cb);
init_completion(&chip->sram_access_granted);
@ -6622,6 +6827,7 @@ cancel_work:
cancel_work_sync(&chip->init_work);
cancel_work_sync(&chip->charge_full_work);
cancel_work_sync(&chip->bcl_hi_power_work);
cancel_work_sync(&chip->esr_extract_config_work);
of_init_fail:
mutex_destroy(&chip->rslow_comp.lock);
mutex_destroy(&chip->rw_lock);
@ -6636,6 +6842,7 @@ of_init_fail:
wakeup_source_trash(&chip->update_sram_wakeup_source.source);
wakeup_source_trash(&chip->gain_comp_wakeup_source.source);
wakeup_source_trash(&chip->capacity_learning_wakeup_source.source);
wakeup_source_trash(&chip->esr_extract_wakeup_source.source);
return rc;
}