google_cpm: handle thermal transition during negotiation

Handle themal level transitions for MDIS and for legacy thermal
cooling devices. Turn off and turn on charging (including setting
the wireless charger online) after critical level.

Bug: 231656227
Test: rapid toggle of thermal levels, sweep for MDIS and legagy
Signed-off-by: AleX Pelosi <[email protected]>
Change-Id: I49dd2c2a4cf9e886b9a67f60fc650b80f6e6b8d9
diff --git a/google_cpm.c b/google_cpm.c
index 8fa0fc2..d3b1725 100644
--- a/google_cpm.c
+++ b/google_cpm.c
@@ -141,6 +141,7 @@
 	/* MDIS: wired and wireless via main charger */
 	struct gvotable_election *fcc_votable;
 	struct gvotable_election *dc_icl_votable;
+	struct gvotable_election *tx_icl_votable;
 	/* MDIS: wired and wireless via DC charger */
 	struct gvotable_election *cp_votable;
 	/* MDIS: configuration */
@@ -616,8 +617,8 @@
 		ret = limit >= 0;
 
 error_exit:
-	pr_debug("%s: CPM_THERM_DC_FCC pps_index=%d value=%d limit=%d applied=%d\n",
-		 __func__, gcpm->pps_index, value, limit, ret);
+	dev_dbg(gcpm->device, "%s: DC_FCC->MSC_FCC pps_index=%d value=%d limit=%d applied=%d\n",
+		__func__, gcpm->pps_index, value, limit, ret);
 
 	return ret;
 }
@@ -764,27 +765,36 @@
 	return -EINVAL;
 }
 
+static int gcpm_mdis_in_is_wireless(struct gcpm_drv *gcpm, int index)
+{
+	return index == 1; /* TODO: query at startup using type==WIRELESS */
+}
+
 /* return the PPS_CP or the WLC_CP limit */
 static int gcpm_chg_select_check_cp_limit(struct gcpm_drv *gcpm)
 {
-	int cp_min = -1;
+	int online, cp_min = -1, in_idx;
 
-	/* wlc might use a different CP limit than wired */
-	if (gcpm->wlc_pps_data.pd_online && gcpm->dc_limit_cc_min_wlc >= 0)
-		cp_min = gcpm->dc_limit_cc_min_wlc;
-	else if (gcpm->tcpm_pps_data.pd_online && gcpm->dc_limit_cc_min >= 0)
+	in_idx = gcpm_mdis_match_cp_source(gcpm, &online);
+	if (in_idx < 0 || gcpm_mdis_in_is_wireless(gcpm, in_idx)) {
+		if (gcpm->dc_limit_cc_min_wlc >= 0)
+			cp_min = gcpm->dc_limit_cc_min_wlc;
+	} else if (gcpm->dc_limit_cc_min >= 0) {
 		cp_min = gcpm->dc_limit_cc_min;
+	}
 
+	/* wlc might use a different (higher) CP limit than wired */
+	dev_dbg(gcpm->device, "%s: in_idx=%d cp_min=%d\n", __func__, in_idx, cp_min);
 	return cp_min;
 }
 
 /* call holding mutex_lock(&gcpm->chg_psy_lock) */
 static int gcpm_chg_select_by_demand(struct gcpm_drv *gcpm)
 {
-	const int cp_min = gcpm_chg_select_check_cp_limit(gcpm);
 	int cc_max = gcpm->cc_max; /* from google_charger */
 	int index = GCPM_DEFAULT_CHARGER;
 	int batt_demand = -1;
+	int cp_min;
 
 	/*
 	 * ->cc_max is lowered from the main-charger thermal limit and might
@@ -796,7 +806,6 @@
 	 * same as gcpm->cp_fcc_hold_limit on exit).
 	 */
 	if (gcpm->cp_fcc_hold && gcpm->cp_fcc_hold_limit >= 0) {
-
 		/*
 		 * ->cp_fcc_hold is set when a thermal limit caused the switch
 		 * from CP to main-charger. In this case ->cp_fcc_hold_limit
@@ -808,9 +817,8 @@
 		 * CP will restart on PD wired only when the actual charging
 		 * current exceeds the cp_min limit.
 		 */
-		pr_debug("%s: raise due to hold cc_max=%d->%d cp_min=%d\n",
-			 __func__, cc_max, gcpm->cp_fcc_hold_limit, cp_min);
-
+		dev_dbg(gcpm->device, "%s: change due to hold cc_max=%d->%d\n",
+			__func__, cc_max, gcpm->cp_fcc_hold_limit);
 		cc_max = gcpm->cp_fcc_hold_limit;
 	}
 
@@ -827,33 +835,45 @@
 	if (batt_demand > gcpm->dc_limit_demand)
 		index = GCPM_INDEX_DC_ENABLE;
 
-	pr_debug("%s: index=%d cc_max=%d gcpm->fv_uv=%d demand=%d, dc_limit=%d\n", __func__,
-		 index, cc_max / 1000, gcpm->fv_uv / 1000,
-		 batt_demand, gcpm->dc_limit_demand);
+	dev_dbg(gcpm->device, "%s: index=%d cc_max=%d gcpm->fv_uv=%d demand=%d, dc_limit=%d\n",
+		__func__, index, cc_max / 1000, gcpm->fv_uv / 1000,
+		batt_demand, gcpm->dc_limit_demand);
 
-	/* current demand less than min demand for CP */
-	if (cp_min != -1 && cc_max <= cp_min) {
+	/*
+	 * the limit for DC depends on the source that is active with the
+	 * complication that using the DC_ICL disables the THERMAL limit
+	 * on MSC_FCC and will cause an immediate reselection of CP.
+	 * The code settig ->hold and ->cp_fcc_hold_limit needs to make sure
+	 * that the limit is appropriate.
+	 */
+	cp_min = gcpm_chg_select_check_cp_limit(gcpm);
+	if (cp_min == -1 || cc_max <= cp_min) {
 		const bool cp_active = gcpm_chg_is_cp_active(gcpm);
 
-		pr_debug("%s: cc_max=%d under cp_min=%d, ->hold=%d:%d index:%d->%d\n",
-			 __func__, cc_max, cp_min, gcpm->cp_fcc_hold, cp_active,
-			 index, GCPM_DEFAULT_CHARGER);
+		/* current demand less than min demand for CP */
+		dev_dbg(gcpm->device,
+			"%s: cc_max=%d under cp_min=%d, ->hold=%d->%d index:%d->%d\n",
+			__func__, cc_max, cp_min, gcpm->cp_fcc_hold,
+			gcpm->cp_fcc_hold ? gcpm->cp_fcc_hold : cp_active,
+			index, GCPM_DEFAULT_CHARGER);
 
 		/*
 		 * Switch to the default charger and hold it.
 		 * NOTE: ->cp_fcc_hold is reset in gcpm_dc_fcc_callback()
-		 * when the thermal limit changes.
+		 * and when the MDIS thermal limit changes. This piece is
+		 * only for legacy dc_fcc since the mdis code handle this.
 		 */
 		if (!gcpm->cp_fcc_hold)
 			gcpm->cp_fcc_hold = cp_active;
+
 		index = GCPM_DEFAULT_CHARGER;
 	}
 
 exit_done:
-	if (index != gcpm->dc_index)
-		pr_debug("by_d: index:%d->%d demand=%d,limit=%d cc_max=%d,cp_min=%d, hold=%d",
-			 gcpm->dc_index, index, batt_demand, gcpm->dc_limit_demand,
-			 cc_max, cp_min, gcpm->cp_fcc_hold);
+	dev_dbg(gcpm->device,
+		"by_d: index:%d->%d demand=%d,limit=%d cc_max=%d,cp_min=%d, hold=%d",
+		gcpm->dc_index, index, batt_demand, gcpm->dc_limit_demand,
+		cc_max, cp_min, gcpm->cp_fcc_hold);
 	return index;
 }
 
@@ -1278,7 +1298,7 @@
 	int index, schedule_pps_interval = -1;
 	bool dc_done = false, dc_ena;
 
-	pr_debug("%s: on=%d dc_state=%d dc_index=%d\n", __func__,
+	dev_dbg(gcpm->device, "%s: init_ok=%d dc_state=%d dc_index=%d\n", __func__,
 		 gcpm->dc_init_complete, gcpm->dc_state, gcpm->dc_index);
 
 	if (!gcpm->dc_init_complete)
@@ -1891,7 +1911,6 @@
 
 			/* reset to the default charger, and clear taper */
 			gcpm->dc_index = GCPM_DEFAULT_CHARGER;
-			gcpm->cp_fcc_hold = false;
 			gcpm_taper_ctl(gcpm, 0);
 
 			/*
@@ -2333,52 +2352,126 @@
 	return ret;
 }
 
-/* needs mutex_unlock(&gcpm->chg_psy_lock); */
+static int mdis_set_wlc_online(struct gcpm_drv *gcpm)
+{
+	struct power_supply *wlc_psy = gcpm->wlc_pps_data.pps_psy;
+	union power_supply_propval pval;
+	int ret;
+
+	if (!wlc_psy)
+		return PPS_PSY_OFFLINE;
+
+	ret = power_supply_get_property(wlc_psy, POWER_SUPPLY_PROP_ONLINE, &pval);
+	if (ret < 0 || pval.intval == PPS_PSY_OFFLINE) {
+
+		pval.intval = PPS_PSY_FIXED_ONLINE;
+		ret = power_supply_set_property(wlc_psy, POWER_SUPPLY_PROP_ONLINE,
+						&pval);
+		if (ret < 0)
+			return ret;
+	}
+
+	return pval.intval;
+}
+
+/*
+ * A negative msc_fcc, dc_icl or cp_fcc disables the MDIS vote on the
+ * corresponding source.
+ * cp_fcc=0 re-enable the MDIS votes on MSC_FCC and DC_ICL and forces the
+ * transition to MW charging when/if using the charge pump (in this case
+ * charging will stop if MSC_FCC/DC_ICL are zero).
+ *
+ * needs mutex_unlock(&gcpm->chg_psy_lock);
+ */
 static int gcpm_mdis_update_limits(struct gcpm_drv *gcpm, int msc_fcc,
 				   int dc_icl, int cp_fcc)
 {
-	const bool cp_enabled = cp_fcc > 0;
-	struct gvotable_election *el;
+	struct gvotable_election *dc_icl_votable;
+	struct gvotable_election *fcc_votable;
+	struct gvotable_election *cp_votable;
 	int ret;
 
-	/* votes on MSC_FCC applied only when CP is not enabled */
-	el = gcpm_get_fcc_votable(gcpm);
-	if (el) {
-		ret = mdis_cast_vote(el, msc_fcc, msc_fcc >= 0 && !cp_enabled);
+	pr_info("MSC_MDIS msc_fcc=%d dc_icl=%d cp_fcc=%d\n",
+		msc_fcc, dc_icl, cp_fcc);
+
+	cp_votable = gcpm_get_cp_votable(gcpm);
+	dc_icl_votable = gcpm_get_dc_icl_votable(gcpm);
+
+	/*
+	 * set (or reset) the MDIS limit for CP.
+	 * The callback for GCPM_FCC needs to be locked.
+	 */
+	if (cp_fcc != 0 && cp_votable) {
+		ret = mdis_cast_vote(cp_votable, cp_fcc, cp_fcc > 0);
 		if (ret < 0)
-			dev_err(gcpm->device, "vote %d on MSC_FCC failed (%d)\n",
+			dev_err(gcpm->device, "MDIS: vote %d on CP failed (%d)\n",
+				cp_fcc, ret);
+	}
+
+	/*
+	 * set (or reset) the  MDIS limit for MSC_FCC.
+	 * Turns off the main-charger from the charging loop in google_charger
+	 * but will not be able to restart charging if/when the charging loop
+	 * is not running (MSC_FCC might not have a callback that cause a
+	 * respin of the usecase state machine)
+	 * NOTE: this limit is enabled only when CP is not enabled
+	 */
+	fcc_votable = gcpm_get_fcc_votable(gcpm);
+	if (fcc_votable) {
+		ret = mdis_cast_vote(fcc_votable, msc_fcc, msc_fcc >= 0 && cp_fcc == 0);
+		if (ret < 0)
+			dev_err(gcpm->device, "MDIS: vote %d on MSC_FCC failed (%d)\n",
 				msc_fcc, ret);
 	}
 
-	/* votes on DC_ICL applied only when CP is not enabled */
-	el = gcpm_get_dc_icl_votable(gcpm);
-	if (el) {
-		ret = mdis_cast_vote(el, dc_icl, dc_icl >= 0 && !cp_enabled);
+	/*
+	 * set (or reset) the  MDIS limit for DC_ICL.
+	 * NOTE: Can vote on DC_ICL even when using CP.
+	 */
+	if (dc_icl != 0 && dc_icl_votable) {
+		int wlc_state;
+
+		/* need to set online WLC if not onlne */
+		wlc_state = mdis_set_wlc_online(gcpm);
+		if (wlc_state == PPS_PSY_OFFLINE)
+			dev_err(gcpm->device, "MDIS: WLC offine\n");
+
+		/* turning ON after critical level for WLC is complicated */
+		ret = mdis_cast_vote(dc_icl_votable, dc_icl, dc_icl > 0);
+		if (ret < 0)
+			dev_err(gcpm->device, "MDIS: vote %d on DC_ICL failed (%d)\n",
+				dc_icl, ret);
+	}
+
+	/* adjust limit for RTX */
+	if (!gcpm->tx_icl_votable)
+		gcpm->tx_icl_votable = gvotable_election_get_handle("TX_ICL");
+	if (gcpm->tx_icl_votable)
+		gvotable_cast_int_vote(gcpm->tx_icl_votable, "MDIS", 0, dc_icl == 0);
+
+	/*
+	 * turns off the CP and will revert to main.
+	 * NOTE: The limit for main charger MSC_FCC is updated above.
+	 */
+	if (cp_fcc == 0 && cp_votable) {
+		ret = mdis_cast_vote(cp_votable, 0, true);
+		if (ret < 0)
+			dev_err(gcpm->device, "MDIS: vote %d on CP failed (%d)\n",
+				cp_fcc, ret);
+	}
+
+	/* turning off wireless charging equires disabling the wireless IC */
+	if (dc_icl == 0 && dc_icl_votable) {
+		ret = mdis_cast_vote(dc_icl_votable, 0, true);
 		if (ret < 0)
 			dev_err(gcpm->device, "vote %d on DC_ICL failed (%d)\n",
 				dc_icl, ret);
 	}
 
-	/* votes on GCPM_FCC */
-	el = gcpm_get_cp_votable(gcpm);
-	if (el) {
-		ret = mdis_cast_vote(el, cp_fcc, cp_fcc >= 0);
-		if (ret < 0)
-			dev_err(gcpm->device, "vote %d on CP failed (%d)\n",
-				cp_fcc, ret);
-	}
-
-	pr_info("MSC_THERM_MDIS msc_fcc=%d dc_icl=%d cp_fcc=%d ret=%d\n",
-		msc_fcc, dc_icl, cp_fcc, ret);
-
 	/* one or more might fail, consider retries */
 	return 0;
 }
 
-static int gcpm_mdis_in_is_wireless(struct gcpm_drv *gcpm, int index)
-{
-	return index == 1; /* TODO: query at startup using type==WIRELESS */
-}
 
  /* max dissipation themal level: apply the limit  */
 static int gcpm_set_mdis_charge_cntl_limit(struct thermal_cooling_device *tcd,
@@ -2386,23 +2479,28 @@
 {
 	struct mdis_thermal_device *tdev = tcd->devdata;
 	struct gcpm_drv *gcpm = tdev->gcpm;
+	int online = 0, budget = -1, in_idx = -1;
 	int msc_fcc, dc_icl, cp_fcc, ret;
-	int online = 0, budget = -1;
-	int in_idx = -1;
 
 	if (tdev->thermal_levels <= 0 || lvl < 0 || lvl > tdev->thermal_levels)
 		return -EINVAL;
 
 	mutex_lock(&gcpm->chg_psy_lock);
 
+	dev_dbg(gcpm->device, "MSC_THERM_MDIS lvl=%d->%d\n", tdev->current_level, (int)lvl);
+
 	tdev->current_level = lvl;
 	if (lvl == tdev->thermal_levels || tdev->thermal_mitigation[lvl] == 0) {
 		budget = msc_fcc = dc_icl = cp_fcc = 0;
+		gcpm->cp_fcc_hold_limit = gcpm_chg_select_check_cp_limit(gcpm);
+		gcpm->cp_fcc_hold = true;
 	} else if (tdev->current_level == 0) {
 		budget = tdev->thermal_mitigation[0];
 		msc_fcc = dc_icl = cp_fcc = -1;
+		/* mdis callback will clear hold and re-evaluate PPS */
+		gcpm->cp_fcc_hold_limit = -1;
 	} else {
-		int cp_min;
+		int cp_min = -1;
 
 		budget = tdev->thermal_mitigation[lvl];
 
@@ -2412,68 +2510,95 @@
 
 		/*
 		 * cp_fcc limit is routed to DC when DC is selected or ignored.
-		 * the code in gcpm_psy_set_property() uses cp_fcc and cc_max to
-		 * determine when to swich source.
+		 * the code in gcpm_psy_set_property() uses cp_fcc and cc_max
+		 * to determine when to swich source.
 		 */
 		in_idx = gcpm_mdis_match_cp_source(gcpm, &online);
 		if (in_idx < 0) {
-			/* source not online */
-			cp_fcc = -1;
-		} else if (gcpm_mdis_in_is_wireless(gcpm, in_idx)) {
-			/* WLC_CP? use the charge pump with wireless charging */
-			cp_fcc = gcpm->mdis_out_limits[1][lvl + tdev->thermal_levels];
 			/*
-			 * forces wlc-overrides-fcc when wireless charging
-			 * Reset only in PROG_ONLINE to allow transitioning
-			 * OUT of WLC_DC when the charging current falls
-			 * under the DC limit.
+			 * this happens when none of the sources are online.
+			 * and CAN happen when we resume after the thermal
+			 * engine has shut this down. Forces cp_fcc to 0
+			 * to apply dc_icl and msc_fcc.
 			 */
-			if (online != PPS_PSY_PROG_ONLINE)
-				msc_fcc = -1;
+			cp_fcc = 0;
+		} else if (gcpm_mdis_in_is_wireless(gcpm, in_idx)) {
+			/* WLC_CP use the charge pump with wireless charging */
+			cp_fcc = gcpm->mdis_out_limits[1][lvl + tdev->thermal_levels];
+			if (gcpm->dc_limit_cc_min_wlc >= 0)
+				cp_min = gcpm->dc_limit_cc_min_wlc;
+			else if (gcpm->dc_limit_cc_min >= 0)
+				cp_min = gcpm->dc_limit_cc_min;
+
+			/*
+			* forces wlc-overrides-fcc when wireless charging
+			* Reset only in PROG_ONLINE to allow transitioning
+			* OUT of WLC_DC when the charging current falls
+			* under the DC limit.
+			*/
+			msc_fcc = -1;
 		} else {
-			/* PPS_CP? use the charge pump with TCPM */
+			/* PPS_CP use the charge pump with TCPM */
 			cp_fcc = gcpm->mdis_out_limits[1][lvl];
+			if (gcpm->dc_limit_cc_min >= 0)
+				cp_min = gcpm->dc_limit_cc_min;
 		}
 
 		/*
-		 * validate the new cp limit against cp_min and disable CP
-		 * if the new limit is under it. Disabling CP will enable
-		 * the votes on MSC_FCC and DC_ICL which will cause a respin
-		 * of the roundtrip.
+		 * validate the cp limit against cp_min and disable CP
+		 * with hold if the new limit is under it.
 		 * NOTE: there might be a corner case when the MSC_FCC or the
 		 * DC_ICL limit doesn't change after re-enabling the vote.
 		 */
-		cp_min = gcpm_chg_select_check_cp_limit(gcpm);
-		if (cp_min != -1 && cp_fcc <= cp_min) {
-			pr_debug("MSC_MDIS cp_fcc:%d->0 cp_min=%d\n",
-				 cp_fcc, cp_min);
+		if (cp_min == -1) {
+			pr_debug("MSC_MDIS cp_fcc_hold_limit:%d->-1 cp_fcc=%d cp_min=%d\n",
+				gcpm->cp_fcc_hold_limit, cp_fcc, cp_min);
+		} else if (cp_fcc > cp_min) {
+			/* mdis callback will clear hold and re-evaluate PPS */
+			gcpm->cp_fcc_hold_limit = -1;
+			pr_debug("MSC_MDIS cp_fcc_hold_limit:%d->-1 cp_fcc=%d cp_min=%d\n",
+				gcpm->cp_fcc_hold_limit, cp_fcc, cp_min);
+		} else if (cp_fcc <= cp_min) {
+			/*
+			 * setting ->cp_fcc_hold_limit to 0 select the
+			  main-charger in gcpm_chg_select_by_demand().
+			 */
+			gcpm->cp_fcc_hold_limit = gcpm_mdis_in_is_wireless(gcpm, in_idx) ?
+						0 : cp_min;
+			gcpm->cp_fcc_hold = true;
+
+			pr_debug("MSC_MDIS cp_fcc:%d->0 hold_limit=%d cp_min=%d\n",
+				cp_fcc, gcpm->cp_fcc_hold_limit, cp_min);
 			cp_fcc = 0;
 		}
 	}
 
-	pr_info("MSC_MDIS in_idx=%d online=%d cp_fcc=%d hold=%d, hold_limit=%d->%d\n",
-		in_idx, online, cp_fcc, gcpm->cp_fcc_hold,
-		gcpm->cp_fcc_hold_limit, cp_fcc);
+	dev_info(gcpm->device,
+		"MSC_THERM_MDIS lvl=%lu in_idx=%d online=%d cp_fcc=%d hold=%d, hold_limit=%d\n",
+		lvl, in_idx, online, cp_fcc, gcpm->cp_fcc_hold,
+		gcpm->cp_fcc_hold_limit);
 
 	/*
-	 * . cp_fcc <= 0 must cause the transition to MW (use msc_fcc or dc_icl)
+	 * this might be in the callback for mdis_votable
+	 * . cp_fcc == 0 will apply msc_fcc, dc_icl and must cause the
+	*    transition from CP to MW
+	 * . cp_fcc < 0 it only removes the MDIS limit on CP charging
 	 * . msc_fcc = -1 when charging from dc_icl (wlc-overrides-fcc)
 	 */
-	ret = gcpm_mdis_update_limits(gcpm, msc_fcc, dc_icl,
-				      online == PPS_PSY_PROG_ONLINE ? cp_fcc : -1);
-	/*
-	 * ->cp_fcc_hold is set when select forced the default charger
-	 * because CP current fell UNDER the dc_limit_cc_mim_* limit.
-	 */
-	if (ret == 0 && gcpm->cp_fcc_hold)
-		gcpm->cp_fcc_hold_limit = cp_fcc;
-
-	mutex_unlock(&gcpm->chg_psy_lock);
+	ret = gcpm_mdis_update_limits(gcpm, msc_fcc, dc_icl, cp_fcc);
+	if (ret < 0)
+		pr_err("%s: cannot update limits (%d)", __func__, ret);
 
 	/*  fix the disable, run another charging loop */
-	if (gcpm->mdis_votable)
+	if (gcpm->mdis_votable) {
 		ret = gvotable_cast_int_vote(gcpm->mdis_votable, "MDIS",
 					     budget, budget >= 0);
+		if (ret < 0)
+			pr_err("%s: cannot update budget (%d)", __func__, ret);
+
+	}
+
+	mutex_unlock(&gcpm->chg_psy_lock);
 
 	return 0;
 }
@@ -2750,30 +2875,35 @@
 	struct gcpm_drv *gcpm = gvotable_get_data(el);
 	struct mdis_thermal_device *tdev = &gcpm->thermal_device;
 	const int budget = (long)value;
+	bool trigger_select = budget != 0 && gcpm->cp_fcc_hold;
 
-	pr_info("MSC_MDIS lvl=%d budget=%d hold=%d\n", tdev->current_level,
-		budget, gcpm->cp_fcc_hold);
+	pr_debug("MSC_MDIS callback lvl=%d budget=%d hold=%d cp_fcc_hold_limit=%d\n",
+		 tdev->current_level, budget, gcpm->cp_fcc_hold,
+		 gcpm->cp_fcc_hold_limit);
+
+	/*
+	 * the limit is cleared when charging current is greater that the limit.
+	 * NOTE: Clearing the hold allows re-enabling PPS again.
+	 */
+	if (gcpm->cp_fcc_hold_limit == -1)
+		gcpm->cp_fcc_hold = false;
 
 	/*
 	 * gcpm->cp_fcc_hold is set when charging switched to main from DC
-	 * due to the charging current falling under cc_min limit.
+	 * due to the charging current falling under cc_mi      n limit: clear the
+	 * hold and give PPS a change if the limit is cleared.
+	 * NOTE: need to
 	 */
-	if (budget != 0 && gcpm->cp_fcc_hold) {
+	if (trigger_select) {
 		int ret;
 
-		/*
-		 * Clear ->cp_fcc_hold and restart PPS Detection when the
-		 * budget is changed. This is similar to the behavior for
-		 * DC_FCC.
-		 */
-		gcpm->cp_fcc_hold = false;
 		ret = gcpm_chg_select_logic(gcpm);
 		if (ret == -EAGAIN) {
 			const int interval = 5; /* seconds */
 
 			/* let the setting go through but */
 			mod_delayed_work(system_wq, &gcpm->select_work,
-					msecs_to_jiffies(interval * 1000));
+					 msecs_to_jiffies(interval * 1000));
 		}
 	}
 
@@ -2809,19 +2939,23 @@
 	struct power_supply *cp_psy;
 	int cp_min, ret;
 
-	/* apply the vote to the DC charger */
-	cp_psy = gcpm_chg_get_active_cp(gcpm);
-	if (!cp_psy) {
-		pr_debug("MSC_GCPM_FCC: has_psy=%d limit=%d\n", !!cp_psy, limit);
+	/*
+	 * the current limit is changed, validate it against the min
+	 * NOTE: this is also used to trigger select_work when restarting
+	 * charging when coming off thermal mitigation.
+	 */
+	cp_min = gcpm_chg_select_check_cp_limit(gcpm);
+	if (cp_min != -1 && limit <= cp_min) {
+		pr_debug("MSC_GCPM_FCC: limit=%d reason=%s cpmin=%d trigger select\n",
+			 limit, reason, cp_min);
+		mod_delayed_work(system_wq, &gcpm->select_work, 0);
 		return 0;
 	}
 
-	/* the current limit is changed, validate it against the min */
-	cp_min = gcpm_chg_select_check_cp_limit(gcpm);
-	if (cp_min != -1 && limit <= cp_min) {
-		pr_debug("MSC_GCPM_FCC: limit=%d reason=%s under cpmin=%d\n",
-			 limit, reason, cp_min);
-		mod_delayed_work(system_wq, &gcpm->select_work, 0);
+	/* route the vote to the CP when active */
+	cp_psy = gcpm_chg_get_active_cp(gcpm);
+	if (!cp_psy) {
+		pr_debug("MSC_GCPM_FCC: not active limit=%d\n", limit);
 		return 0;
 	}