summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt26
-rw-r--r--drivers/power/supply/qcom/fg-core.h15
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c230
3 files changed, 235 insertions, 36 deletions
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index 0c2e365cd099..dc967edb6192 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -370,6 +370,32 @@ First Level Node - FG Gen3 device
30000 (3 %) will be used. Lowest possible value is
1954 (0.19 %).
+- qcom,fg-esr-rt-filter-switch-temp
+ Usage: optional
+ Value type: <u32>
+ Definition: Battery temperature threshold below which ESR relax
+ filter coefficients will be applied after a certain
+ number of delta battery temperature interrupts firing in
+ an interval of time. This will be applied only when Qnovo
+ is enabled. If this is not specified, then the default
+ value used will be -100. Unit is in decidegC.
+
+- qcom,fg-esr-tight-rt-filter-micro-pct
+ Usage: optional
+ Value type: <u32>
+ Definition: Value in micro percentage for relax temperature ESR tight
+ filter. If this is not specified, then a default value of
+ 5860 will be used. Lowest possible value is 1954 (0.19 %).
+ This will be applied only if Qnovo is enabled.
+
+- qcom,fg-esr-broad-rt-filter-micro-pct
+ Usage: optional
+ Value type: <u32>
+ Definition: Value in micro percentage for relax temperature ESR broad
+ filter. If this is not specified, then a default value of
+ 156250 will be used. Lowest possible value is 1954 (0.19 %).
+ This will be applied only if Qnovo is enabled.
+
- qcom,fg-auto-recharge-soc
Usage: optional
Value type: <empty>
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);
}