summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorSubbaraman Narayanamurthy <subbaram@codeaurora.org>2017-12-01 10:54:40 -0800
committerSubbaraman Narayanamurthy <subbaram@codeaurora.org>2017-12-20 15:42:23 -0800
commitb5ef1a816809fedccd27ff135582c152d19988fe (patch)
tree607de9451cae9ae7ff07c1ac76a25482f84b431f /drivers/power
parente1fe906b59110ddb0847f30085db84434637f045 (diff)
power: qpnp-fg-gen3: Improve ESR accuracy at cold temperature with Qnovo
When the battery is in cold temperature for a certain amount of time and device is charged with Qnovo enabled charging, ESR pulse will fire less frequently. This along with ESR pulses not getting qualified can cause the ESR to be less accurate. To improve ESR accuracy, add change to apply relaxed filter coefficients once the battery temperature starts ramping up after hitting a lower threshold of say 6 C after charging begins. CRs-Fixed: 2151708 Change-Id: Iff6c2ffbab1f327dfefcf1550213c37df4a8ad42 Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/supply/qcom/fg-core.h15
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c230
2 files changed, 209 insertions, 36 deletions
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 1935704fcf09..20191ffa5e68 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -13,6 +13,7 @@
#ifndef __FG_CORE_H__
#define __FG_CORE_H__
+#include <linux/alarmtimer.h>
#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
@@ -224,6 +225,12 @@ enum slope_limit_status {
SLOPE_LIMIT_NUM_COEFFS,
};
+enum esr_filter_status {
+ ROOM_TEMP = 1,
+ LOW_TEMP,
+ RELAX_TEMP,
+};
+
enum esr_timer_config {
TIMER_RETRY = 0,
TIMER_MAX,
@@ -270,6 +277,9 @@ struct fg_dt_props {
int esr_broad_flt_upct;
int esr_tight_lt_flt_upct;
int esr_broad_lt_flt_upct;
+ int esr_flt_rt_switch_temp;
+ int esr_tight_rt_flt_upct;
+ int esr_broad_rt_flt_upct;
int slope_limit_temp;
int esr_pulse_thresh_ma;
int esr_meas_curr_ma;
@@ -424,8 +434,10 @@ struct fg_chip {
int delta_soc;
int last_msoc;
int last_recharge_volt_mv;
+ int delta_temp_irq_count;
int esr_timer_charging_default[NUM_ESR_TIMERS];
enum slope_limit_status slope_limit_sts;
+ enum esr_filter_status esr_flt_sts;
bool profile_available;
bool profile_loaded;
bool battery_missing;
@@ -446,6 +458,9 @@ struct fg_chip {
struct work_struct status_change_work;
struct delayed_work ttf_work;
struct delayed_work sram_dump_work;
+ struct work_struct esr_filter_work;
+ struct alarm esr_filter_alarm;
+ ktime_t last_delta_temp_time;
};
/* Debugfs data structures are below */
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index f33673732d62..2f958a3438ee 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -2182,67 +2182,197 @@ static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
return 0;
}
-static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp)
+static int __fg_esr_filter_config(struct fg_chip *chip,
+ enum esr_filter_status esr_flt_sts)
{
- u8 esr_tight_lt_flt, esr_broad_lt_flt;
- bool cold_temp = false;
+ u8 esr_tight_flt, esr_broad_flt;
+ int esr_tight_flt_upct, esr_broad_flt_upct;
int rc;
- /*
- * If the battery temperature is lower than -20 C, then skip modifying
- * ESR filter.
- */
- if (batt_temp < -210)
+ if (esr_flt_sts == chip->esr_flt_sts)
return 0;
- /*
- * If battery temperature is lesser than 10 C (default), then apply the
- * ESR low temperature tight and broad filter values to ESR room
- * temperature tight and broad filters. If battery temperature is higher
- * than 10 C, then apply back the room temperature ESR filter
- * coefficients to ESR room temperature tight and broad filters.
- */
- if (batt_temp > chip->dt.esr_flt_switch_temp
- && chip->esr_flt_cold_temp_en) {
- fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
- chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt);
- fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
- chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt);
- } else if (batt_temp <= chip->dt.esr_flt_switch_temp
- && !chip->esr_flt_cold_temp_en) {
- fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
- chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt);
- fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
- chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt);
- cold_temp = true;
+ if (esr_flt_sts == ROOM_TEMP) {
+ esr_tight_flt_upct = chip->dt.esr_tight_flt_upct;
+ esr_broad_flt_upct = chip->dt.esr_broad_flt_upct;
+ } else if (esr_flt_sts == LOW_TEMP) {
+ esr_tight_flt_upct = chip->dt.esr_tight_lt_flt_upct;
+ esr_broad_flt_upct = chip->dt.esr_broad_lt_flt_upct;
+ } else if (esr_flt_sts == RELAX_TEMP) {
+ esr_tight_flt_upct = chip->dt.esr_tight_rt_flt_upct;
+ esr_broad_flt_upct = chip->dt.esr_broad_rt_flt_upct;
} else {
+ pr_err("Unknown esr filter config\n");
return 0;
}
+ fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER, esr_tight_flt_upct,
+ &esr_tight_flt);
rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte,
- &esr_tight_lt_flt,
+ &esr_tight_flt,
chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
if (rc < 0) {
pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc);
return rc;
}
+ fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER, esr_broad_flt_upct,
+ &esr_broad_flt);
rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte,
- &esr_broad_lt_flt,
+ &esr_broad_flt,
chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
if (rc < 0) {
pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc);
return rc;
}
- chip->esr_flt_cold_temp_en = cold_temp;
- fg_dbg(chip, FG_STATUS, "applied %s ESR filter values\n",
- cold_temp ? "cold" : "normal");
+ chip->esr_flt_sts = esr_flt_sts;
+ fg_dbg(chip, FG_STATUS, "applied ESR filter %d values\n", esr_flt_sts);
+ return 0;
+}
+
+#define DT_IRQ_COUNT 3
+#define DELTA_TEMP_IRQ_TIME_MS 300000
+#define ESR_FILTER_ALARM_TIME_MS 900000
+static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp,
+ bool override)
+{
+ enum esr_filter_status esr_flt_sts = ROOM_TEMP;
+ bool qnovo_en, input_present, count_temp_irq = false;
+ s64 time_ms;
+ int rc;
+
+ /*
+ * If the battery temperature is lower than -20 C, then skip modifying
+ * ESR filter.
+ */
+ if (batt_temp < -210)
+ return 0;
+
+ qnovo_en = is_qnovo_en(chip);
+ input_present = is_input_present(chip);
+
+ /*
+ * If Qnovo is enabled, after hitting a lower battery temperature of
+ * say 6 C, count the delta battery temperature interrupts for a
+ * certain period of time when the battery temperature increases.
+ * Switch to relaxed filter coefficients once the temperature increase
+ * is qualified so that ESR accuracy can be improved.
+ */
+ if (qnovo_en && !override) {
+ if (input_present) {
+ if (chip->esr_flt_sts == RELAX_TEMP) {
+ /* do nothing */
+ return 0;
+ }
+
+ count_temp_irq = true;
+ if (chip->delta_temp_irq_count) {
+ /* Don't count when temperature is dropping. */
+ if (batt_temp <= chip->last_batt_temp)
+ count_temp_irq = false;
+ } else {
+ /*
+ * Starting point for counting. Check if the
+ * temperature is qualified.
+ */
+ if (batt_temp > chip->dt.esr_flt_rt_switch_temp)
+ count_temp_irq = false;
+ else
+ chip->last_delta_temp_time =
+ ktime_get();
+ }
+ } else {
+ chip->delta_temp_irq_count = 0;
+ rc = alarm_try_to_cancel(&chip->esr_filter_alarm);
+ if (rc < 0)
+ pr_err("Couldn't cancel esr_filter_alarm\n");
+ }
+ }
+
+ /*
+ * If battery temperature is lesser than 10 C (default), then apply the
+ * ESR low temperature tight and broad filter values to ESR room
+ * temperature tight and broad filters. If battery temperature is higher
+ * than 10 C, then apply back the room temperature ESR filter
+ * coefficients to ESR room temperature tight and broad filters.
+ */
+ if (batt_temp > chip->dt.esr_flt_switch_temp)
+ esr_flt_sts = ROOM_TEMP;
+ else
+ esr_flt_sts = LOW_TEMP;
+
+ if (count_temp_irq) {
+ time_ms = ktime_ms_delta(ktime_get(),
+ chip->last_delta_temp_time);
+ chip->delta_temp_irq_count++;
+ fg_dbg(chip, FG_STATUS, "dt_irq_count: %d\n",
+ chip->delta_temp_irq_count);
+
+ if (chip->delta_temp_irq_count >= DT_IRQ_COUNT
+ && time_ms <= DELTA_TEMP_IRQ_TIME_MS) {
+ fg_dbg(chip, FG_STATUS, "%d interrupts in %lld ms\n",
+ chip->delta_temp_irq_count, time_ms);
+ esr_flt_sts = RELAX_TEMP;
+ }
+ }
+
+ rc = __fg_esr_filter_config(chip, esr_flt_sts);
+ if (rc < 0)
+ return rc;
+
+ if (esr_flt_sts == RELAX_TEMP)
+ alarm_start_relative(&chip->esr_filter_alarm,
+ ms_to_ktime(ESR_FILTER_ALARM_TIME_MS));
+
return 0;
}
+#define FG_ESR_FILTER_RESTART_MS 60000
+static void esr_filter_work(struct work_struct *work)
+{
+ struct fg_chip *chip = container_of(work,
+ struct fg_chip, esr_filter_work);
+ int rc, batt_temp;
+
+ rc = fg_get_battery_temp(chip, &batt_temp);
+ if (rc < 0) {
+ pr_err("Error in getting batt_temp\n");
+ alarm_start_relative(&chip->esr_filter_alarm,
+ ms_to_ktime(FG_ESR_FILTER_RESTART_MS));
+ }
+
+ rc = fg_esr_filter_config(chip, batt_temp, true);
+ if (rc < 0) {
+ pr_err("Error in configuring ESR filter rc:%d\n", rc);
+ alarm_start_relative(&chip->esr_filter_alarm,
+ ms_to_ktime(FG_ESR_FILTER_RESTART_MS));
+ }
+
+ chip->delta_temp_irq_count = 0;
+ pm_relax(chip->dev);
+}
+
+static enum alarmtimer_restart fg_esr_filter_alarm_cb(struct alarm *alarm,
+ ktime_t now)
+{
+ struct fg_chip *chip = container_of(alarm, struct fg_chip,
+ esr_filter_alarm);
+
+ fg_dbg(chip, FG_STATUS, "ESR filter alarm triggered %lld\n",
+ ktime_to_ms(now));
+ /*
+ * We cannot vote for awake votable here as that takes a mutex lock
+ * and this is executed in an atomic context.
+ */
+ pm_stay_awake(chip->dev);
+ schedule_work(&chip->esr_filter_work);
+
+ return ALARMTIMER_NORESTART;
+}
+
static int fg_esr_fcc_config(struct fg_chip *chip)
{
union power_supply_propval prop = {0, };
@@ -4293,14 +4423,14 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
union power_supply_propval prop = {0, };
int rc, batt_temp;
- fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
rc = fg_get_battery_temp(chip, &batt_temp);
if (rc < 0) {
pr_err("Error in getting batt_temp\n");
return IRQ_HANDLED;
}
+ fg_dbg(chip, FG_IRQ, "irq %d triggered bat_temp: %d\n", irq, batt_temp);
- rc = fg_esr_filter_config(chip, batt_temp);
+ rc = fg_esr_filter_config(chip, batt_temp, false);
if (rc < 0)
pr_err("Error in configuring ESR filter rc:%d\n", rc);
@@ -4691,6 +4821,9 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip)
#define DEFAULT_ESR_BROAD_FLT_UPCT 99610
#define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 30000
#define DEFAULT_ESR_BROAD_LT_FLT_UPCT 30000
+#define DEFAULT_ESR_FLT_RT_DECIDEGC 60
+#define DEFAULT_ESR_TIGHT_RT_FLT_UPCT 5860
+#define DEFAULT_ESR_BROAD_RT_FLT_UPCT 156250
#define DEFAULT_ESR_CLAMP_MOHMS 20
#define DEFAULT_ESR_PULSE_THRESH_MA 110
#define DEFAULT_ESR_MEAS_CURR_MA 120
@@ -5016,6 +5149,27 @@ static int fg_parse_dt(struct fg_chip *chip)
else
chip->dt.esr_broad_lt_flt_upct = temp;
+ rc = of_property_read_u32(node, "qcom,fg-esr-rt-filter-switch-temp",
+ &temp);
+ if (rc < 0)
+ chip->dt.esr_flt_rt_switch_temp = DEFAULT_ESR_FLT_RT_DECIDEGC;
+ else
+ chip->dt.esr_flt_rt_switch_temp = temp;
+
+ rc = of_property_read_u32(node, "qcom,fg-esr-tight-rt-filter-micro-pct",
+ &temp);
+ if (rc < 0)
+ chip->dt.esr_tight_rt_flt_upct = DEFAULT_ESR_TIGHT_RT_FLT_UPCT;
+ else
+ chip->dt.esr_tight_rt_flt_upct = temp;
+
+ rc = of_property_read_u32(node, "qcom,fg-esr-broad-rt-filter-micro-pct",
+ &temp);
+ if (rc < 0)
+ chip->dt.esr_broad_rt_flt_upct = DEFAULT_ESR_BROAD_RT_FLT_UPCT;
+ else
+ chip->dt.esr_broad_rt_flt_upct = temp;
+
rc = fg_parse_slope_limit_coefficients(chip);
if (rc < 0)
pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
@@ -5047,6 +5201,7 @@ static int fg_parse_dt(struct fg_chip *chip)
static void fg_cleanup(struct fg_chip *chip)
{
+ alarm_try_to_cancel(&chip->esr_filter_alarm);
power_supply_unreg_notifier(&chip->nb);
debugfs_remove_recursive(chip->dfs_root);
if (chip->awake_votable)
@@ -5159,6 +5314,9 @@ static int fg_gen3_probe(struct platform_device *pdev)
INIT_WORK(&chip->status_change_work, status_change_work);
INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
+ INIT_WORK(&chip->esr_filter_work, esr_filter_work);
+ alarm_init(&chip->esr_filter_alarm, ALARM_BOOTTIME,
+ fg_esr_filter_alarm_cb);
rc = fg_memif_init(chip);
if (rc < 0) {
@@ -5230,7 +5388,7 @@ static int fg_gen3_probe(struct platform_device *pdev)
if (!rc) {
pr_info("battery SOC:%d voltage: %duV temp: %d id: %dKOhms\n",
msoc, volt_uv, batt_temp, chip->batt_id_ohms / 1000);
- rc = fg_esr_filter_config(chip, batt_temp);
+ rc = fg_esr_filter_config(chip, batt_temp, false);
if (rc < 0)
pr_err("Error in configuring ESR filter rc:%d\n", rc);
}