Snap for 12263504 from 64498b23ff04d2e104c4a64cb439cb57c4ab94a1 to android13-gs-pixel-5.10-24Q4-release

Change-Id: Ie134cb7c49cbcba42e5b7ba46193122418017ccb
Signed-off-by: Coastguard Worker <[email protected]>
diff --git a/google_battery.c b/google_battery.c
index 8ec9bce..619ec7a 100644
--- a/google_battery.c
+++ b/google_battery.c
@@ -547,7 +547,6 @@
 
 	/* FAN level */
 	struct gvotable_election *fan_level_votable;
-	int fan_last_level;
 
 	/* stats */
 	int msc_state;
@@ -595,7 +594,6 @@
 	struct gbms_storage_device *history;
 
 	/* Fan control */
-	int fan_level;
 	int fan_bt_limits[NB_FAN_BT_LIMITS];
 
 	/* AACR: Aged Adjusted Charging Rate */
@@ -1262,48 +1260,30 @@
 	return fan_level;
 }
 
-static void fan_level_reset(const struct batt_drv *batt_drv)
+static bool vote_fan_level(struct gvotable_election *fan_level_votable, int level, bool enable)
 {
+	int ret;
 
-	if (batt_drv->fan_level_votable)
-		gvotable_cast_int_vote(batt_drv->fan_level_votable,
-				       "MSC_BATT", 0, false);
-}
+	if (!fan_level_votable)
+		fan_level_votable = gvotable_election_get_handle(VOTABLE_FAN_LEVEL);
 
-static int fan_level_cb(struct gvotable_election *el,
-			const char *reason, void *vote)
-{
-	struct batt_drv *batt_drv = gvotable_get_data(el);
-	const int last_lvl = batt_drv->fan_last_level;
-	int lvl = GVOTABLE_PTR_TO_INT(vote);
+	if (!fan_level_votable)
+		return false;
 
-	if (!batt_drv)
-		return 0;
-
-	if (batt_drv->fan_last_level == lvl)
-		return 0;
-
-	pr_debug("FAN_LEVEL %d->%d reason=%s\n",
-		batt_drv->fan_last_level, lvl, reason ? reason : "<>");
-
-	batt_drv->fan_last_level = lvl;
-
-	if (!chg_state_is_disconnected(&batt_drv->chg_state)) {
-
-		logbuffer_log(batt_drv->ttf_stats.ttf_log,
-			"FAN_LEVEL %d->%d reason=%s",
-			last_lvl, lvl,
-			reason ? reason : "<>");
-
-		/*
-		 * Send the uevent by kobject API to distinguish the uevent sent by
-                 * power_supply_changed() since fan_level is not a standard power_supply_property
-		 */
-		kobject_uevent(&batt_drv->device->kobj, KOBJ_CHANGE);
+	ret = gvotable_cast_int_vote(fan_level_votable, "MSC_BATT", level, enable);
+	if (ret < 0) {
+		pr_err("MSC_FAN_LVL: enable:%d, level=%d ret=%d\n", enable, level, ret);
+		return false;
 	}
 
-	return 0;
+	return true;
 }
+
+static void fan_level_reset(struct batt_drv *batt_drv)
+{
+	vote_fan_level(batt_drv->fan_level_votable, 0, false);
+}
+
 /* ------------------------------------------------------------------------- */
 
 /*
@@ -4979,7 +4959,7 @@
 /* call holding mutex_lock(&batt_drv->chg_lock); */
 static int batt_chg_logic(struct batt_drv *batt_drv)
 {
-	int rc, err = 0;
+	int rc, level, err = 0;
 	bool jeita_stop;
 	bool changed = false;
 	const bool disable_votes = batt_drv->disable_votes;
@@ -5251,13 +5231,9 @@
 	}
 
 	/* Fan level can be updated only during power transfer */
-	if (batt_drv->fan_level_votable) {
-		int level = fan_calculate_level(batt_drv);
-
-		gvotable_cast_int_vote(batt_drv->fan_level_votable,
-				       "MSC_BATT", level, true);
-		pr_debug("MSC_FAN_LVL: level=%d\n", level);
-	}
+	level = fan_calculate_level(batt_drv);
+	vote_fan_level(batt_drv->fan_level_votable, level, true);
+	pr_debug("MSC_FAN_LVL: level=%d\n", level);
 
 	if (!batt_drv->msc_interval_votable)
 		batt_drv->msc_interval_votable =
@@ -7066,48 +7042,6 @@
 static const DEVICE_ATTR(constant_charge_voltage, 0444,
 			 batt_show_constant_charge_voltage, NULL);
 
-static ssize_t fan_level_store(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf, size_t count) {
-	struct power_supply *psy = container_of(dev, struct power_supply, dev);
-	struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
-	int ret = 0;
-	int level;
-
-	ret = kstrtoint(buf, 0, &level);
-	if (ret < 0)
-		return ret;
-
-	if ((level < FAN_LVL_UNKNOWN) || (level > FAN_LVL_ALARM))
-		return -ERANGE;
-
-	batt_drv->fan_level = level;
-
-	/* always send a power supply event when forcing the value */
-	if (batt_drv->psy)
-		power_supply_changed(batt_drv->psy);
-
-	return count;
-}
-
-static ssize_t fan_level_show(struct device *dev,
-			      struct device_attribute *attr, char *buf)
-{
-	struct power_supply *psy = container_of(dev, struct power_supply, dev);
-	struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
-	int result = 0;
-
-	if (batt_drv->fan_level == -1 && batt_drv->fan_level_votable)
-		result = gvotable_get_current_int_vote(
-				batt_drv->fan_level_votable);
-	else
-		result = batt_drv->fan_level;
-
-	return scnprintf(buf, PAGE_SIZE, "%d\n", result);
-}
-
-static const DEVICE_ATTR_RW(fan_level);
-
 static ssize_t show_health_safety_margin(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -8421,9 +8355,6 @@
 	ret = device_create_file(&batt_drv->psy->dev, &dev_attr_constant_charge_voltage);
 	if (ret)
 		dev_err(&batt_drv->psy->dev, "Failed to create constant charge voltage\n");
-	ret = device_create_file(&batt_drv->psy->dev, &dev_attr_fan_level);
-	if (ret)
-		dev_err(&batt_drv->psy->dev, "Failed to create fan level\n");
 	ret = device_create_file(&batt_drv->psy->dev, &dev_attr_health_safety_margin);
 	if (ret)
 		dev_err(&batt_drv->psy->dev, "Failed to create health safety margin\n");
@@ -8975,7 +8906,9 @@
 	/* TODO: google_battery caches cycle count, should use that */
 	cycle_cnt = GPSY_GET_PROP(batt_drv->fg_psy,
 				  POWER_SUPPLY_PROP_CYCLE_COUNT);
-	if (cycle_cnt < 0)
+
+	/* not update history if cycle count is not ready */
+	if (cycle_cnt <= 0)
 		return -EIO;
 
 	if (batt_drv->blf_collect_now) {
@@ -10749,23 +10682,6 @@
 
 	/* Fan levels limits from battery temperature */
 	batt_fan_bt_init(batt_drv);
-	batt_drv->fan_level = -1;
-	batt_drv->fan_last_level = -1;
-	batt_drv->fan_level_votable =
-		gvotable_create_int_election(NULL, gvotable_comparator_int_max,
-					     fan_level_cb, batt_drv);
-	if (IS_ERR_OR_NULL(batt_drv->fan_level_votable)) {
-		ret = PTR_ERR(batt_drv->fan_level_votable);
-		dev_err(batt_drv->device, "Fail to create fan_level_votable\n");
-		batt_drv->fan_level_votable = NULL;
-	} else {
-		gvotable_set_vote2str(batt_drv->fan_level_votable,
-				      gvotable_v2s_int);
-		gvotable_election_set_name(batt_drv->fan_level_votable,
-					   VOTABLE_FAN_LEVEL);
-		gvotable_cast_long_vote(batt_drv->fan_level_votable,
-					"DEFAULT", FAN_LVL_UNKNOWN, true);
-	}
 
 	/* charge speed interface: status and type */
 	batt_drv->csi_status_votable =
diff --git a/max1720x_battery.c b/max1720x_battery.c
index 5a0ca41..aae381e 100644
--- a/max1720x_battery.c
+++ b/max1720x_battery.c
@@ -941,10 +941,6 @@
 
 	version_now = max_m5_model_read_version(chip->model_data);
 	version_load = max_m5_fg_model_version(chip->model_data);
-
-	if (!force && version_now == version_load)
-		return -EEXIST;
-
 	gbms_logbuffer_devlog(chip->ce_log, chip->dev,  LOGLEVEL_INFO, 0, LOGLEVEL_INFO,
 			      "Schedule Load FG Model, ID=%d, ver:%d->%d cap_lsb:%d->%d",
 			      chip->batt_id, version_now, version_load,
@@ -2390,6 +2386,49 @@
 	return 0;
 }
 
+/* call holding chip->model_lock */
+static int max1720x_clear_por(struct max1720x_chip *chip)
+{
+	u16 data;
+	int ret;
+
+	ret = REGMAP_READ(&chip->regmap, MAX1720X_STATUS, &data);
+	if (ret < 0 || (data & MAX1720X_STATUS_POR) == 0)
+		return ret;
+
+	return regmap_update_bits(chip->regmap.regmap,
+				  MAX1720X_STATUS,
+				  MAX1720X_STATUS_POR,
+				  0x0);
+}
+
+/* call holding chip->model_lock */
+static void max1720x_check_por(struct max1720x_chip *chip)
+{
+	u16 data;
+	int ret;
+
+	ret = REGMAP_READ(&chip->regmap, MAX1720X_STATUS, &data);
+	if (ret < 0 || (data & MAX1720X_STATUS_POR) == 0)
+		return;
+
+	chip->por = true;
+	chip->cycle_reg_ok = false;
+	if (chip->fake_battery == 0) { /* no battery */
+		max1720x_clear_por(chip);
+	} else {
+		gbms_logbuffer_devlog(chip->ce_log, chip->dev, LOGLEVEL_INFO, 0, LOGLEVEL_INFO,
+				      "POR is set(%04x), model reload:%d",
+				      data, chip->model_reload);
+		/*
+		 * trigger model load if not on-going, clear POR only when
+		 * model loading done successfully
+		 */
+		if (chip->model_reload != MAX_M5_LOAD_MODEL_REQUEST)
+			max1720x_model_reload(chip, false);
+	}
+}
+
 static int max1720x_get_property(struct power_supply *psy,
 				 enum power_supply_property psp,
 				 union power_supply_propval *val)
@@ -2493,6 +2532,7 @@
 		val->intval = rc;
 		break;
 	case POWER_SUPPLY_PROP_PRESENT:
+		/* gauge has no POR interrupt, keep polling here to catch POR */
 		if (chip->fake_battery != -1) {
 			val->intval = chip->fake_battery;
 		} else if (chip->gauge_type == -1) {
@@ -2507,16 +2547,11 @@
 			if (!val->intval)
 				break;
 
-			/* chip->por prevent garbage in cycle count */
-			chip->por = (data & MAX1720X_STATUS_POR) != 0;
-			if (chip->por && chip->model_ok &&
-			    chip->model_reload != MAX_M5_LOAD_MODEL_REQUEST) {
-				/* trigger reload model and clear of POR */
-				mutex_unlock(&chip->model_lock);
-				__pm_relax(chip->get_prop_ws);
-				max1720x_fg_irq_thread_fn(-1, chip);
-				return err;
-			}
+			if (!chip->por)
+				max1720x_check_por(chip);
+			mutex_unlock(&chip->model_lock);
+			__pm_relax(chip->get_prop_ws);
+			return err;
 		}
 		break;
 	case POWER_SUPPLY_PROP_TEMP:
@@ -3127,29 +3162,6 @@
 	 */
 	fg_status_clr = fg_status;
 
-	if (fg_status & MAX1720X_STATUS_POR) {
-		const bool no_battery = chip->fake_battery == 0;
-
-		mutex_lock(&chip->model_lock);
-		chip->por = true;
-		chip->cycle_reg_ok = false;
-		if (no_battery) {
-			fg_status_clr &= ~MAX1720X_STATUS_POR;
-		} else {
-			gbms_logbuffer_devlog(chip->ce_log, chip->dev,
-					      LOGLEVEL_INFO, 0, LOGLEVEL_INFO,
-					      "POR is set(%04x), model reload:%d",
-					      fg_status, chip->model_reload);
-			/*
-			 * trigger model load if not on-going, clear POR only when
-			 * model loading done successfully
-			 */
-			if (chip->model_reload != MAX_M5_LOAD_MODEL_REQUEST)
-				max1720x_model_reload(chip, false);
-		}
-		mutex_unlock(&chip->model_lock);
-	}
-
 	if (fg_status & MAX1720X_STATUS_IMN)
 		pr_debug("IMN is set\n");
 
@@ -4624,24 +4636,6 @@
 	return 0;
 }
 
-static int max1720x_clear_por(struct max1720x_chip *chip)
-{
-	u16 data;
-	int ret;
-
-	ret = REGMAP_READ(&chip->regmap, MAX1720X_STATUS, &data);
-	if (ret < 0)
-		return ret;
-
-	if ((data & MAX1720X_STATUS_POR) == 0)
-		return 0;
-
-	return regmap_update_bits(chip->regmap.regmap,
-				  MAX1720X_STATUS,
-				  MAX1720X_STATUS_POR,
-				  0x0);
-}
-
 /* read state from fg (if needed) and set the next update field */
 static int max1720x_set_next_update(struct max1720x_chip *chip)
 {
@@ -4760,6 +4754,7 @@
 			if (rc == 0) {
 				chip->model_reload = MAX_M5_LOAD_MODEL_IDLE;
 				chip->model_ok = true;
+				chip->por = false;
 				new_model = true;
 				/* saved new value in max1720x_set_next_update */
 				chip->model_next_update = reg_cycle > 0 ? reg_cycle - 1 : 0;
@@ -4767,8 +4762,6 @@
 		} else if (rc != -EAGAIN) {
 			chip->model_reload = MAX_M5_LOAD_MODEL_DISABLED;
 			chip->model_ok = false;
-		} else if (chip->model_reload > MAX_M5_LOAD_MODEL_IDLE) {
-			chip->model_reload += 1;
 		}
 	}
 
@@ -4779,6 +4772,7 @@
 	if (chip->model_reload >= MAX_M5_LOAD_MODEL_REQUEST) {
 		const unsigned long delay = msecs_to_jiffies(60 * 1000);
 
+		chip->model_reload += 1;
 		mod_delayed_work(system_wq, &chip->model_work, delay);
 	}
 
@@ -6085,10 +6079,12 @@
 	chip->init_complete = true;
 	chip->bhi_acim = 0;
 
-	/*
-	 * Handle any IRQ that might have been set before init
-	 * NOTE: will clear the POR bit and trigger model load if needed
-	 */
+	/* Handle POR interrupt */
+	mutex_lock(&chip->model_lock);
+	max1720x_check_por(chip);
+	mutex_unlock(&chip->model_lock);
+
+	/* Handle other IRQs that might have been set before init */
 	max1720x_fg_irq_thread_fn(-1, chip);
 
 	max1720x_update_timer_base(chip);
diff --git a/max_m5.c b/max_m5.c
index 1345f76..4ad9afd 100644
--- a/max_m5.c
+++ b/max_m5.c
@@ -471,7 +471,7 @@
 static int max_m5_update_gauge_custom_parameters(struct max_m5_data *m5_data)
 {
 	struct max17x0x_regmap *regmap = m5_data->regmap;
-	int ret, retries;
+	int ret, retries, temp;
 	u16 data;
 
 	/* write parameters (which include state) */
@@ -503,16 +503,6 @@
 
 	m5_data->cap_lsb = max_m5_period2caplsb(m5_data->parameters.taskperiod);
 
-	/*
-	 * version could be in the DT: this will overwrite it if set.
-	 * Invalid version is not written out.
-	 */
-	ret = max_m5_model_write_version(m5_data, m5_data->model_version);
-	if (ret < 0) {
-		dev_err(m5_data->dev, "cannot update version (%d)\n", ret);
-		return ret;
-	}
-
 	/* trigger load model */
 	ret = REGMAP_READ(regmap, MAX_M5_CONFIG2, &data);
 	if (ret == 0)
@@ -531,25 +521,37 @@
 		ret = REGMAP_READ(regmap, MAX_M5_CONFIG2, &data);
 		if (ret == 0 && !(data & MAX_M5_CONFIG2_LDMDL)) {
 			ret = REGMAP_READ(regmap, MAX_M5_REPCAP, &data);
-			if (ret == 0 && data != 0) {
-				int temp;
-
-				temp = max_m5_model_read_version(m5_data);
-				if (m5_data->model_version == MAX_M5_INVALID_VERSION) {
-					dev_info(m5_data->dev, "No Model Version, Current %x\n",
-						 temp);
-				} else if (temp != m5_data->model_version) {
-					dev_info(m5_data->dev, "Model Version %x, Mismatch %x\n",
-						 m5_data->model_version, temp);
-					return -EINVAL;
-				}
-
-				return 0;
-			}
+			if (ret == 0 && data != 0)
+				break;
 		}
 	}
 
-	return -ETIMEDOUT;
+	if (retries == 0)
+		return -ETIMEDOUT;
+
+	/*
+	 * version could be in the DT: this will overwrite it if set.
+	 * Invalid version is not written out.
+	 */
+	ret = max_m5_model_write_version(m5_data, m5_data->model_version);
+	if (ret < 0) {
+		dev_err(m5_data->dev, "cannot update version (%d)\n", ret);
+		return ret;
+	}
+
+	temp = max_m5_model_read_version(m5_data);
+	if (m5_data->model_version == MAX_M5_INVALID_VERSION) {
+		dev_info(m5_data->dev, "No Model Version, Current %x\n", temp);
+		return -EINVAL;
+	}
+
+	if (temp != m5_data->model_version) {
+		dev_info(m5_data->dev, "Model Version %x, Mismatch %x\n",
+			 m5_data->model_version, temp);
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
 /* protected from mutex_lock(&chip->model_lock) */
diff --git a/p9221_charger.c b/p9221_charger.c
index 1a208f6..cfd687c 100644
--- a/p9221_charger.c
+++ b/p9221_charger.c
@@ -4808,6 +4808,47 @@
 
 static DEVICE_ATTR_RO(fw_rev);
 
+static ssize_t fan_level_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct p9221_charger_data *charger = i2c_get_clientdata(client);
+	int result = 0;
+
+	if (charger->fan_level_votable)
+		result = gvotable_get_current_int_vote(charger->fan_level_votable);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", result);
+}
+
+static ssize_t fan_level_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct p9221_charger_data *charger = i2c_get_clientdata(client);
+	int ret = 0;
+	int level;
+
+	ret = kstrtoint(buf, 0, &level);
+	if (ret < 0)
+		return ret;
+
+	if ((level < FAN_LVL_UNKNOWN) || (level > FAN_LVL_ALARM))
+		return -ERANGE;
+
+	if (charger->fan_level_votable) {
+		ret = gvotable_cast_int_vote(charger->fan_level_votable, "MSC_USR", level, true);
+		if (ret < 0)
+			pr_err("MSC_FAN_LVL: fail to set level=%d(ret=%d)\n", level, ret);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(fan_level);
+
 static ssize_t p9382_show_rtx_boost(struct device *dev,
 				    struct device_attribute *attr,
 				    char *buf)
@@ -5347,6 +5388,7 @@
 	&dev_attr_mitigate_threshold.attr,
 	&dev_attr_wpc_ready.attr,
 	&dev_attr_qien.attr,
+	&dev_attr_fan_level.attr,
 	NULL
 };
 
@@ -6799,6 +6841,31 @@
 	return 0;
 }
 
+static int fan_level_cb(struct gvotable_election *el,
+			const char *reason, void *vote)
+{
+	struct p9221_charger_data *charger = gvotable_get_data(el);
+	int lvl = GVOTABLE_PTR_TO_INT(vote);
+
+	if (!charger)
+		return 0;
+
+	if (charger->fan_last_level == lvl)
+		return 0;
+
+	if (!charger->online)
+		return 0;
+
+	logbuffer_log(charger->log, "FAN_LEVEL %d->%d reason=%s",
+		      charger->fan_last_level, lvl, reason ? reason : "<>");
+
+	charger->fan_last_level = lvl;
+
+	kobject_uevent(&charger->dev->kobj, KOBJ_CHANGE);
+
+	return 0;
+}
+
 /*
  *  If able to read the chip_id register then we know we are online
  *
@@ -7075,6 +7142,24 @@
 	if (!charger->chg_mode_votable)
 		dev_warn(&charger->client->dev, "Could not find %s votable\n", GBMS_MODE_VOTABLE);
 
+	charger->fan_level_votable =
+		gvotable_create_int_election(NULL, gvotable_comparator_int_max,
+					     fan_level_cb, charger);
+	if (IS_ERR_OR_NULL(charger->fan_level_votable)) {
+		ret = PTR_ERR(charger->fan_level_votable);
+		dev_err(&client->dev, "Fail to create fan_level_votable\n");
+		charger->fan_level_votable = NULL;
+	} else {
+		gvotable_set_vote2str(charger->fan_level_votable,
+				      gvotable_v2s_int);
+		gvotable_election_set_name(charger->fan_level_votable,
+					   VOTABLE_FAN_LEVEL);
+		gvotable_cast_long_vote(charger->fan_level_votable,
+					"DEFAULT", FAN_LVL_UNKNOWN, true);
+	}
+
+	charger->fan_last_level = -1;
+
 	/* Ramping on BPP is optional */
 	if (charger->pdata->icl_ramp_delay_ms != -1) {
 		charger->icl_ramp_ua = P9221_DC_ICL_BPP_RAMP_DEFAULT_UA;
diff --git a/p9221_charger.h b/p9221_charger.h
index 3b72a69..d891d3f 100644
--- a/p9221_charger.h
+++ b/p9221_charger.h
@@ -719,6 +719,7 @@
 	struct gvotable_election	*csi_status_votable;
 	struct gvotable_election	*csi_type_votable;
 	struct gvotable_election	*point_full_ui_soc_votable;
+	struct gvotable_election	*fan_level_votable;
 	struct notifier_block		nb;
 	struct mutex			io_lock;
 	struct mutex			cmd_lock;
@@ -844,6 +845,7 @@
 	bool				hpp_hv;
 	int				fod_mode;
 	enum p9xxx_chk_rp		check_rp;
+	int				fan_last_level;
 
 #if IS_ENABLED(CONFIG_GPIOLIB)
 	struct gpio_chip gpio;