google_battery: filter abnomal battery temperature
- sample 5 data and filter abnormal part via remove max and min data
- 30 seconds for default polling and 3 seconds for fast polling
- polling rate can be adjust via debug file nodes
Bug: 262461194
Change-Id: I9d3bd956b8859ba7db6daab3d9c4516f8c0ffa0c
Signed-off-by: Jenny Ho <[email protected]>
diff --git a/google_battery.c b/google_battery.c
index 16519d8..a27d0a8 100644
--- a/google_battery.c
+++ b/google_battery.c
@@ -389,6 +389,20 @@
ktime_t last_update;
};
+#define TEMP_SAMPLE_SIZE 5
+struct batt_temp_filter {
+ struct delayed_work work;
+ struct mutex lock;
+ bool enable;
+ bool force_update;
+ bool resume_delay;
+ int sample[TEMP_SAMPLE_SIZE];
+ int default_interval;
+ int fast_interval;
+ int resume_delay_time;
+ int last_idx;
+};
+
/* battery driver state */
struct batt_drv {
struct device *device;
@@ -551,17 +565,43 @@
/* battery critical level */
int batt_critical_voltage;
+
+ /* battery temperature filter */
+ struct batt_temp_filter temp_filter;
};
-static int gbatt_get_temp(const struct batt_drv *batt_drv, int *temp);
+static int gbatt_get_temp(struct batt_drv *batt_drv, int *temp);
static int gbatt_get_capacity(struct batt_drv *batt_drv);
-static int gbatt_get_raw_temp(const struct batt_drv *batt_drv, int *temp)
+static int batt_get_filter_temp(struct batt_temp_filter *temp_filter)
{
- int err;
+ int sum = 0, max, min, i;
+
+ mutex_lock(&temp_filter->lock);
+ max = min = temp_filter->sample[0];
+ for (i = 0; i < TEMP_SAMPLE_SIZE; i++) {
+ if (temp_filter->sample[i] > max)
+ max = temp_filter->sample[i];
+ if (temp_filter->sample[i] < min)
+ min = temp_filter->sample[i];
+ sum += temp_filter->sample[i];
+ }
+ mutex_unlock(&temp_filter->lock);
+
+ return (sum - max - min) / (TEMP_SAMPLE_SIZE - 2);
+}
+
+static int gbatt_get_raw_temp(struct batt_drv *batt_drv, int *temp)
+{
+ int err = 0;
union power_supply_propval val;
+ if (batt_drv->temp_filter.enable) {
+ *temp = batt_get_filter_temp(&batt_drv->temp_filter);
+ return err;
+ }
+
if (!batt_drv->fg_psy)
return -EINVAL;
@@ -1055,7 +1095,7 @@
#define FAN_CHG_LIMIT_LOW 50
#define FAN_CHG_LIMIT_MED 70
-static int fan_bt_calculate_level(const struct batt_drv *batt_drv)
+static int fan_bt_calculate_level(struct batt_drv *batt_drv)
{
int level, temp, ret;
@@ -1088,7 +1128,7 @@
return level;
}
-static int fan_calculate_level(const struct batt_drv *batt_drv)
+static int fan_calculate_level(struct batt_drv *batt_drv)
{
int charging_rate, fan_level, chg_fan_level, cc_max;
@@ -5158,6 +5198,32 @@
DEFINE_SIMPLE_ATTRIBUTE(debug_ravg_fops, NULL, debug_ravg_fops_write, "%llu\n");
+static int debug_temp_filter_enable_read(void *data, u64 *val)
+{
+ struct batt_drv *batt_drv = (struct batt_drv *)data;
+
+ *val = batt_drv->temp_filter.enable;
+ return 0;
+}
+
+static int debug_temp_filter_enable_write(void *data, u64 val)
+{
+ struct batt_drv *batt_drv = (struct batt_drv *)data;
+ struct batt_temp_filter *temp_filter = &batt_drv->temp_filter;
+ bool enable = val != 0;
+
+ if (temp_filter->enable != enable) {
+ temp_filter->enable = enable;
+ temp_filter->force_update = true;
+ mod_delayed_work(system_wq, &temp_filter->work, 0);
+ }
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_temp_filter_enable_fops,
+ debug_temp_filter_enable_read,
+ debug_temp_filter_enable_write, "%llu\n");
#endif
@@ -7061,6 +7127,16 @@
&batt_drv->health_data.bhi_data.res_state.ravg_soc_high);
debugfs_create_file("ravg", 0400, de, batt_drv, &debug_ravg_fops);
+ /* battery temperature filter */
+ debugfs_create_u32("temp_filter_default_interval", 0644, de,
+ &batt_drv->temp_filter.default_interval);
+ debugfs_create_u32("temp_filter_fast_interval", 0644, de,
+ &batt_drv->temp_filter.fast_interval);
+ debugfs_create_u32("temp_filter_resume_delay_interval", 0644, de,
+ &batt_drv->temp_filter.resume_delay_time);
+ debugfs_create_file("temp_filter_enable", 0644, de, batt_drv,
+ &debug_temp_filter_enable_fops);
+
return 0;
}
@@ -7181,7 +7257,7 @@
return capacity_level;
}
-static int gbatt_get_temp(const struct batt_drv *batt_drv, int *temp)
+static int gbatt_get_temp(struct batt_drv *batt_drv, int *temp)
{
int err = 0;
@@ -7471,6 +7547,90 @@
return 0;
}
+#define TEMP_FILTER_DEFAULT_INTERVAL_MS 30000
+#define TEMP_FILTER_FAST_INTERVAL_MS 3000
+#define TEMP_FILTER_RESUME_DELAY_MS 1500
+static void batt_init_temp_filter(struct batt_drv *batt_drv)
+{
+ struct batt_temp_filter *temp_filter = &batt_drv->temp_filter;
+ const struct device_node *node = batt_drv->device->of_node;
+ u32 tmp;
+ int ret;
+
+ mutex_init(&batt_drv->temp_filter.lock);
+
+ ret = of_property_read_u32(node, "google,temp-filter-default-interval", &tmp);
+ if (ret == 0)
+ temp_filter->default_interval = tmp;
+ else
+ temp_filter->default_interval = TEMP_FILTER_DEFAULT_INTERVAL_MS;
+
+ ret = of_property_read_u32(node, "google,temp-filter-fast-interval", &tmp);
+ if (ret == 0)
+ temp_filter->fast_interval = tmp;
+ else
+ temp_filter->fast_interval = TEMP_FILTER_FAST_INTERVAL_MS;
+
+ ret = of_property_read_u32(node, "google,temp-filter-resume-delay", &tmp);
+ if (ret == 0)
+ temp_filter->resume_delay_time = tmp;
+ else
+ temp_filter->resume_delay_time = TEMP_FILTER_RESUME_DELAY_MS;
+
+ /* initial temperature value in first read data */
+ temp_filter->force_update = true;
+ mod_delayed_work(system_wq, &temp_filter->work, 0);
+
+ pr_info("temperture filter: default:%ds, fast:%ds, resume:%dms\n",
+ temp_filter->default_interval / 1000, temp_filter->fast_interval / 1000,
+ temp_filter->resume_delay_time);
+}
+
+static void google_battery_temp_filter_work(struct work_struct *work)
+{
+ struct batt_drv *batt_drv = container_of(work, struct batt_drv, temp_filter.work.work);
+ const union gbms_ce_adapter_details *ad = &batt_drv->ce_data.adapter_details;
+ struct batt_temp_filter *temp_filter = &batt_drv->temp_filter;
+ int interval = temp_filter->default_interval;
+ union power_supply_propval val;
+ int err = 0, i;
+
+ if (!temp_filter->enable || interval == 0)
+ return;
+
+ if (!batt_drv->fg_psy)
+ goto done;
+
+ if (temp_filter->resume_delay) {
+ interval = temp_filter->resume_delay_time; /* i2c might busy when resume */
+ temp_filter->resume_delay = false;
+ temp_filter->force_update = true;
+ goto done;
+ }
+
+ if (ad->ad_type == CHG_EV_ADAPTER_TYPE_WLC ||
+ ad->ad_type == CHG_EV_ADAPTER_TYPE_WLC_EPP ||
+ ad->ad_type == CHG_EV_ADAPTER_TYPE_WLC_SPP)
+ interval = temp_filter->fast_interval;
+
+ err = power_supply_get_property(batt_drv->fg_psy, POWER_SUPPLY_PROP_TEMP, &val);
+ if (err != 0)
+ goto done;
+
+ mutex_lock(&temp_filter->lock);
+ if (temp_filter->force_update) {
+ temp_filter->force_update = false;
+ for (i = 0; i < TEMP_SAMPLE_SIZE; i++)
+ temp_filter->sample[i] = val.intval;
+ } else {
+ temp_filter->last_idx = (temp_filter->last_idx + 1) % TEMP_SAMPLE_SIZE;
+ temp_filter->sample[temp_filter->last_idx] = val.intval;
+ }
+ mutex_unlock(&temp_filter->lock);
+
+done:
+ mod_delayed_work(system_wq, &temp_filter->work, msecs_to_jiffies(interval));
+}
/*
* poll the battery, run SOC%, dead battery, critical.
@@ -8539,6 +8699,10 @@
google_battery_dump_profile(&batt_drv->chg_profile);
}
+ batt_drv->temp_filter.enable = of_property_read_bool(node, "google,temp-filter-enable");
+ if (batt_drv->temp_filter.enable)
+ batt_init_temp_filter(batt_drv);
+
cev_stats_init(&batt_drv->ce_data, &batt_drv->chg_profile);
cev_stats_init(&batt_drv->ce_qual, &batt_drv->chg_profile);
@@ -8803,6 +8967,7 @@
INIT_DELAYED_WORK(&batt_drv->init_work, google_battery_init_work);
INIT_DELAYED_WORK(&batt_drv->batt_work, google_battery_work);
INIT_DELAYED_WORK(&batt_drv->power_metrics.work, power_metrics_data_work);
+ INIT_DELAYED_WORK(&batt_drv->temp_filter.work, google_battery_temp_filter_work);
platform_set_drvdata(pdev, batt_drv);
psy_cfg.drv_data = batt_drv;
@@ -8971,6 +9136,7 @@
pm_runtime_get_sync(batt_drv->device);
batt_drv->resume_complete = true;
+ batt_drv->temp_filter.resume_delay = true;
pm_runtime_put_sync(batt_drv->device);
mod_delayed_work(system_wq, &batt_drv->batt_work, 0);