google_battery: implement bhi algo by impedance

Bug: 224784618
Signed-off-by: Jack Wu <[email protected]>
Change-Id: Iebcae07fb3fcc15cc94174c3e92f00ea8345e5ce
diff --git a/max1720x_battery.c b/max1720x_battery.c
index 704126e..e1763e5 100644
--- a/max1720x_battery.c
+++ b/max1720x_battery.c
@@ -60,6 +60,13 @@
 
 #define FILTERCFG_TEMP_HYSTERESIS	30
 
+#define BHI_IMPEDANCE_SOC_LO		50
+#define BHI_IMPEDANCE_SOC_HI		55
+#define BHI_IMPEDANCE_TEMP_LO		250
+#define BHI_IMPEDANCE_TEMP_HI		300
+#define BHI_IMPEDANCE_CYCLE_CNT_DELTA	2
+#define BHI_IMPEDANCE_TIMERH		50 /* 7*24 / 3.2hr */
+
 #include "max1720x.h"
 #include "max1730x.h"
 #include "max_m5.h"
@@ -234,6 +241,9 @@
 	u16 pre_repsoc;
 
 	struct power_supply_desc max1720x_psy_desc;
+
+	int bhi_cycle_count;
+	int bhi_last_timerh;
 };
 
 #define MAX1720_EMPTY_VOLTAGE(profile, temp, cycle) \
@@ -1885,6 +1895,80 @@
 	return err;
 }
 
+/* call holding chip->model_lock */
+static int max1720x_check_impedance(struct max1720x_chip *chip)
+{
+	struct max17x0x_regmap *map = &chip->regmap;
+	int soc, temp, cycle_count, delta, ret;
+	u16 data, timerh;
+
+	if (!chip->model_state_valid)
+		return -EAGAIN;
+
+	soc = max1720x_get_battery_soc(chip);
+	if (soc < BHI_IMPEDANCE_SOC_LO || soc > BHI_IMPEDANCE_SOC_HI)
+		return -ENODATA;
+
+	ret = max17x0x_reg_read(map, MAX17X0X_TAG_temp, &data);
+	if (ret < 0)
+		return -EINVAL;
+
+	temp = reg_to_deci_deg_cel(data);
+	if (temp < BHI_IMPEDANCE_TEMP_LO || temp > BHI_IMPEDANCE_TEMP_HI)
+		return -ENODATA;
+
+	ret = REGMAP_READ(&chip->regmap, MAX1720X_TIMERH, &timerh);
+	if (ret < 0 || timerh == chip->bhi_last_timerh)
+		return ret < 0 ? -EINVAL : -ENODATA;
+
+	cycle_count = max1720x_get_cycle_count(chip);
+	if (cycle_count < 0)
+		return -EINVAL;
+
+	/* POR reset */
+	if (!timerh || !chip->bhi_cycle_count)
+		chip->bhi_cycle_count = cycle_count;
+
+	delta = cycle_count - chip->bhi_cycle_count;
+
+	if (delta < BHI_IMPEDANCE_CYCLE_CNT_DELTA && timerh < BHI_IMPEDANCE_TIMERH)
+		return -ENODATA;
+
+	chip->bhi_last_timerh = timerh;
+
+	return 0;
+}
+
+/* will return error if the value is not qualified */
+static int max1720x_get_health_impedance(struct max1720x_chip *chip)
+{
+	u16 data, act_impedance;
+	int ret;
+
+	ret = max1720x_check_impedance(chip);
+	if (ret < 0)
+		return ret;
+
+	ret = gbms_storage_read(GBMS_TAG_ACIM, &data, sizeof(data));
+	if (ret < 0)
+		return -EINVAL;
+
+	act_impedance = data;
+	if (act_impedance == 0xffff) {
+		u16 resistance;
+
+		ret = REGMAP_READ(&chip->regmap, MAX1720X_RCELL, &data);
+		if (ret < 0)
+			return -EINVAL;
+
+		resistance = reg_to_resistance_micro_ohms(data, chip->RSense);
+		ret = gbms_storage_write(GBMS_TAG_ACIM, &resistance, sizeof(resistance));
+		return (ret < 0) ? -EINVAL : resistance;
+	}
+
+	return act_impedance;
+}
+
 static int max1720x_get_property(struct power_supply *psy,
 				 enum power_supply_property psp,
 				 union power_supply_propval *val)
@@ -2078,6 +2162,10 @@
 	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
 		val->strval = chip->serial_number;
 		break;
+	case GBMS_PROP_HEALTH_ACT_IMPEDANCE:
+		/* get activation impedance (and only if qualified) */
+		val->intval = max1720x_get_health_impedance(chip);
+		break;
 	default:
 		err = -EINVAL;
 		break;
@@ -5033,6 +5121,8 @@
 	chip->fake_capacity = -EINVAL;
 	chip->resume_complete = true;
 	chip->init_complete = true;
+	chip->bhi_cycle_count = 0;
+	chip->bhi_last_timerh = 0;
 	max17x0x_init_debugfs(chip);
 
 	/*