P22: Enable dynamic IR drop

Enable dynamic irdrop on P22 and merge other logging changes from P23.
Check bug for testing details on C10.

Bug: 261736557
Change-Id: I63feedc0917d78471e3eebc431fbe14cb35ee60d
Signed-off-by: Ken Yang <[email protected]>
diff --git a/google_battery.c b/google_battery.c
index f116e78..bd852a5 100644
--- a/google_battery.c
+++ b/google_battery.c
@@ -620,6 +620,10 @@
 	/* charging policy */
 	struct gvotable_election *charging_policy_votable;
 	int charging_policy;
+
+	/* irdrop for DC */
+	bool dc_irdrop;
+
 };
 
 static int gbatt_get_temp(struct batt_drv *batt_drv, int *temp);
@@ -2962,9 +2966,14 @@
 	int vchg = batt_drv->chg_state.f.vchrg;
 	int msc_state = MSC_NONE;
 	bool match_enable;
+	bool no_back_down = false;
 
-	if (batt_drv->chg_state.f.flags & GBMS_CS_FLAG_NOCOMP)
-		vchg = 0;
+	if (batt_drv->chg_state.f.flags & GBMS_CS_FLAG_DIRECT_CHG) {
+		if (batt_drv->dc_irdrop)
+			no_back_down = true;
+		else
+			vchg = 0;
+	}
 	match_enable = vchg != 0;
 
 	if ((vbatt - vtier) > otv_margin) {
@@ -2978,9 +2987,12 @@
 		 * switching voltage tiers if the current is right).
 		 * NOTE: lowering voltage might cause a small drop in
 		 * current (we should remain  under next tier)
+		 * TODO: the fv_uv_resolution might be different in
+		 * main charger and CP (should separate them)
 		 */
 		*fv_uv = gbms_msc_round_fv_uv(profile, vtier,
-			*fv_uv - profile->fv_uv_resolution);
+					      *fv_uv - profile->fv_uv_resolution,
+					      no_back_down ? cc_max : 0);
 		if (*fv_uv < vtier)
 			*fv_uv = vtier;
 
@@ -3008,10 +3020,12 @@
 		} else {
 			/* simple pullback */
 			msc_state = MSC_PULLBACK;
+			if (no_back_down)
+				*fv_uv = batt_drv->fv_uv;
 			batt_prlog(BATT_PRLOG_ALWAYS,
-				  "MSC_PULLBACK vt=%d vb=%d ibatt=%d fv_uv=%d->%d\n",
+				  "MSC_PULLBACK vt=%d vb=%d ibatt=%d fv_uv=%d->%d no_back=%d\n",
 				  vtier, vbatt, ibatt,
-				  batt_drv->fv_uv, *fv_uv);
+				  batt_drv->fv_uv, *fv_uv, no_back_down);
 		}
 
 		/*
@@ -3028,28 +3042,35 @@
 		 * data might not be consistent (b/110318684)
 		 * NOTE: could add PID loop for management of thermals
 		 */
-		const int vchrg_ua = vchg * 1000;
+		const int vchrg_uv = vchg * 1000;
+		const int pre_fv = *fv_uv;
 
 		msc_state = MSC_FAST;
 
 		/* invalid or 0 vchg disable IDROP compensation */
-		if (vchrg_ua <= 0) {
+		if (vchrg_uv <= 0) {
 			/* could keep it steady instead */
 			*fv_uv = vtier;
-		} else if (vchrg_ua > vbatt) {
-			*fv_uv = gbms_msc_round_fv_uv(profile, vtier,
-				vtier + (vchrg_ua - vbatt));
+		} else if (vchrg_uv > vbatt) {
+			const int cc_max = GBMS_CCCM_LIMITS(profile, temp_idx, *vbatt_idx);
+
+			*fv_uv = gbms_msc_round_fv_uv(profile, vtier, vtier + (vchrg_uv - vbatt),
+						      no_back_down ? cc_max : 0);
 		}
 
+		/* not allow to reduce fv in DC to avoid the VSWITCH */
+		if (no_back_down && (pre_fv > *fv_uv))
+			*fv_uv = pre_fv;
+
 		/* no tier switch in fast charge (TODO unless close to tier) */
 		if (batt_drv->checked_cv_cnt == 0)
 			batt_drv->checked_cv_cnt = 1;
 
 		batt_prlog(BATT_PRLOG_ALWAYS,
-			   "MSC_FAST vt=%d vb=%d ib=%d fv_uv=%d->%d vchrg=%d cv_cnt=%d\n",
+			   "MSC_FAST vt=%d vb=%d ib=%d fv_uv=%d->%d vchrg=%d cv_cnt=%d no_back=%d\n",
 			   vtier, vbatt, ibatt, batt_drv->fv_uv, *fv_uv,
 			   batt_drv->chg_state.f.vchrg,
-			   batt_drv->checked_cv_cnt);
+			   batt_drv->checked_cv_cnt, no_back_down);
 
 	} else if (chg_type == POWER_SUPPLY_CHARGE_TYPE_TRICKLE) {
 		/*
@@ -3135,9 +3156,12 @@
 		 * TAPER_RAISE: under tier vlim, raise one click &
 		 * debounce taper (see above handling of STEADY)
 		 */
+		const int cc_max = GBMS_CCCM_LIMITS(profile, temp_idx, *vbatt_idx);
+
 		msc_state = MSC_RAISE;
 		*fv_uv = gbms_msc_round_fv_uv(profile, vtier,
-			*fv_uv + profile->fv_uv_resolution);
+					      *fv_uv + profile->fv_uv_resolution,
+					      no_back_down ? cc_max : 0);
 		*update_interval = profile->cv_update_interval;
 
 		/* debounce next taper voltage adjustment */
@@ -4385,7 +4409,7 @@
 		  batt_drv->vbatt_idx != vbatt_idx ||
 		  batt_drv->fv_uv != fv_uv;
 	batt_prlog(batt_prlog_level(changed),
-		   "MSC_LOGIC temp_idx:%d->%d, vbatt_idx:%d->%d, fv=%d->%d, ui=%d->%d cv_cnt=%d ov_cnt=%d\n",
+		   "MSC_LOGIC temp_idx:%d->%d, vbatt_idx:%d->%d, fv=%d->%d, cc_max=%d, ui=%d cv_cnt=%d ov_cnt=%d\n",
 		   batt_drv->temp_idx, temp_idx, batt_drv->vbatt_idx, vbatt_idx,
 		   batt_drv->fv_uv, fv_uv, batt_drv->cc_max, update_interval,
 		   batt_drv->checked_cv_cnt, batt_drv->checked_ov_cnt);
@@ -9831,6 +9855,10 @@
 	if (ret < 0)
 		batt_drv->health_data.bhi_data.first_usage_date = 0;
 
+	batt_drv->dc_irdrop = of_property_read_bool(node, "google,dc-irdrop");
+	if (batt_drv->dc_irdrop)
+		pr_info("dc irdrop is enabled\n");
+
 	/* single battery disconnect */
 	(void)batt_bpst_init_debugfs(batt_drv);
 
diff --git a/google_bms.c b/google_bms.c
index 9f87c54..11b1332 100644
--- a/google_bms.c
+++ b/google_bms.c
@@ -38,6 +38,7 @@
 
 #define GBMS_DEFAULT_FV_UV_RESOLUTION   25000
 #define GBMS_DEFAULT_FV_UV_MARGIN_DPCT  1020
+#define GBMS_DEFAULT_FV_DC_RATIO        20
 #define GBMS_DEFAULT_CV_DEBOUNCE_CNT    3
 #define GBMS_DEFAULT_CV_UPDATE_INTERVAL 2000
 #define GBMS_DEFAULT_CV_TIER_OV_CNT     10
@@ -341,6 +342,11 @@
 	if (ret < 0)
 		profile->fv_uv_margin_dpct = GBMS_DEFAULT_FV_UV_MARGIN_DPCT;
 
+	ret = of_property_read_u32(node, "google,fv-dc-ratio",
+				   &profile->fv_dc_ratio);
+	if (ret < 0)
+		profile->fv_dc_ratio = GBMS_DEFAULT_FV_DC_RATIO;
+
 	/* debounce tier switch */
 	ret = of_property_read_u32(node, "google,cv-debounce-cnt",
 				   &profile->cv_debounce_cnt);
@@ -415,21 +421,37 @@
 }
 EXPORT_SYMBOL_GPL(gbms_dump_raw_profile);
 
+/*
+ * When charging in DC, the fv_max will be (FV + cc_max * fv_dc_ratio).
+ * DC can be detected by cc_ua non-zero.
+ * The gap between Vchg and Vbat is caused by the ibat and the impedance.
+ * The fv_dc_ratio is used to simulate the impedance to get the proper fv, so
+ * the vbat will not over the otv threshold.
+ */
 int gbms_msc_round_fv_uv(const struct gbms_chg_profile *profile,
-			   int vtier, int fv_uv)
+			   int vtier, int fv_uv, int cc_ua)
 {
 	int result;
-	const unsigned int fv_uv_max = (vtier / 1000)
-					* profile->fv_uv_margin_dpct;
+	const unsigned int fv_uv_max = (vtier / 1000) * profile->fv_uv_margin_dpct;
+	const unsigned int dc_fv_uv_max = vtier + (cc_ua / 1000) * profile->fv_dc_ratio;
+	const unsigned int last_fv = profile->volt_limits[profile->volt_nb_limits - 1];
+	unsigned int fv_max;
 
-	if (fv_uv_max != 0 && fv_uv > fv_uv_max)
-		fv_uv = fv_uv_max;
+	if (cc_ua == 0)
+		fv_max = fv_uv_max;
+	else if (dc_fv_uv_max >= last_fv)
+		fv_max = last_fv - profile->fv_uv_resolution;
+	else
+		fv_max = dc_fv_uv_max;
+
+	if (fv_max != 0 && fv_uv > fv_max)
+		fv_uv = fv_max;
 
 	result = fv_uv - (fv_uv % profile->fv_uv_resolution);
 
-	if (fv_uv_max != 0)
+	if (fv_max != 0)
 		gbms_info(profile, "MSC_ROUND: fv_uv=%d vtier=%d fv_uv_max=%d -> %d\n",
-			fv_uv, vtier, fv_uv_max, result);
+			  fv_uv, vtier, fv_max, result);
 
 	return result;
 }
diff --git a/google_bms.h b/google_bms.h
index 91a4410..2a943ba 100644
--- a/google_bms.h
+++ b/google_bms.h
@@ -49,6 +49,7 @@
 
 	/* behavior */
 	u32 fv_uv_margin_dpct;
+	u32 fv_dc_ratio;
 	u32 cv_range_accuracy;
 	u32 cv_debounce_cnt;
 	u32 cv_update_interval;
@@ -402,7 +403,7 @@
 #define GBMS_CS_FLAG_CV		BIT(3)
 #define GBMS_CS_FLAG_ILIM	BIT(4)
 #define GBMS_CS_FLAG_CCLVL	BIT(5)
-#define GBMS_CS_FLAG_NOCOMP     BIT(6)
+#define GBMS_CS_FLAG_DIRECT_CHG	BIT(6)
 
 union gbms_charger_state {
 	uint64_t v;
@@ -433,7 +434,7 @@
 int gbms_msc_temp_idx(const struct gbms_chg_profile *profile, int temp);
 int gbms_msc_voltage_idx(const struct gbms_chg_profile *profile, int vbatt);
 int gbms_msc_round_fv_uv(const struct gbms_chg_profile *profile,
-			   int vtier, int fv_uv);
+			   int vtier, int fv_uv, int cc_ua);
 
 /* newgen charging: charger flags  */
 uint8_t gbms_gen_chg_flags(int chg_status, int chg_type);
diff --git a/pca9468_charger.c b/pca9468_charger.c
index b225398..183ddb9 100644
--- a/pca9468_charger.c
+++ b/pca9468_charger.c
@@ -128,6 +128,8 @@
 #define PCA9468_SC_CLK_DITHER_RATE_DEF	0	/* 25kHz */
 #define PCA9468_SC_CLK_DITHER_LIMIT_DEF	0xF	/* 10% */
 
+#define PCA9468_TIER_SWITCH_DELTA	25000	/* uV */
+
 /* INT1 Register Buffer */
 enum {
 	REG_INT1,
@@ -1040,11 +1042,11 @@
 static int pca9468_apply_irdrop(struct pca9468_charger *pca9468, int fv_uv)
 {
 	const int delta_limit = pca9468_irdrop_limit(pca9468, fv_uv);
-	int ret, vbat, pca_vbat = 0, delta = 0;
+	int ret = -1, vbat, pca_vbat = 0, delta = 0;
 	const bool adaptive = false;
 
 	/* use classic irdrop */
-	if (pca9468->irdrop_comp_ok)
+	if (!pca9468->pdata->pca_irdrop)
 		goto error_done;
 
 	ret = pca9468_get_batt_info(pca9468, BATT_VOLTAGE, &vbat);
@@ -1613,7 +1615,7 @@
 {
 	const int iin_high = pca9468->iin_cc + pca9468->pdata->iin_cc_comp_offset;
 	const int iin_low = pca9468->iin_cc - pca9468->pdata->iin_cc_comp_offset;
-	const ibat_limit = (pca9468->cc_max * FCC_POWER_INCREASE_THRESHOLD) / 100;
+	const int ibat_limit = (pca9468->cc_max * FCC_POWER_INCREASE_THRESHOLD) / 100;
 	int rc, ibat, icn = -EINVAL, iin = -EINVAL;
 	bool ovc_flag;
 
@@ -2385,24 +2387,31 @@
 	if (fv_uv < 0)
 		return fv_uv;
 
+	if (pca9468->fv_uv == fv_uv)
+		goto error_done;
+
 	/* actually change the hardware */
 	ret = pca9468_set_vfloat(pca9468, fv_uv);
 	if (ret < 0)
 		goto error_done;
 
-	/* Restart the process (TODO: optimize this) */
-	ret = pca9468_reset_dcmode(pca9468);
-	if (ret < 0) {
-		pr_err("%s: cannot reset dcmode (%d)\n", __func__, ret);
-	} else {
-		dev_info(pca9468->dev, "%s: charging_state=%u->%u\n", __func__,
-			 pca9468->charging_state, DC_STATE_ADJUST_CC);
+	/* Restart the process if tier switch happened (either direction) */
+	if (abs(fv_uv - pca9468->fv_uv) > PCA9468_TIER_SWITCH_DELTA) {
+		ret = pca9468_reset_dcmode(pca9468);
+		if (ret < 0) {
+			pr_err("%s: cannot reset dcmode (%d)\n", __func__, ret);
+		} else {
+			dev_info(pca9468->dev, "%s: charging_state=%u->%u\n", __func__,
+				pca9468->charging_state, DC_STATE_ADJUST_CC);
 
-		pca9468->charging_state = DC_STATE_ADJUST_CC;
-		pca9468->timer_id = TIMER_PDMSG_SEND;
-		pca9468->timer_period = 0;
+			pca9468->charging_state = DC_STATE_ADJUST_CC;
+			pca9468->timer_id = TIMER_PDMSG_SEND;
+			pca9468->timer_period = 0;
+		}
 	}
 
+	pca9468->fv_uv = fv_uv;
+
 error_done:
 	logbuffer_prlog(pca9468, LOGLEVEL_INFO,
 			"%s: new_vfloat=%d, fv_uv=%d ret=%d", __func__,
@@ -2424,19 +2433,17 @@
 	}
 
 	mutex_lock(&pca9468->lock);
-	if (pca9468->fv_uv == vfloat)
+	if (pca9468->new_vfloat == vfloat)
 		goto done;
 
-	/* this is what is requested */
-	pca9468->fv_uv = vfloat;
-
 	/* use fv_uv at start in pca9468_preset_config() */
 	if (pca9468->charging_state == DC_STATE_NO_CHARGING ||
 	    pca9468->charging_state == DC_STATE_CHECK_VBAT) {
-		// pca9468->pdata->v_float = vfloat;
+		pca9468->fv_uv = vfloat;
 	} else {
 		/* applied in pca9468_apply_new_vfloat() from CC or in CV loop */
 		pca9468->new_vfloat = vfloat;
+		pr_debug("%s: new_vfloat=%d\n", __func__, pca9468->new_vfloat);
 
 		/* might want to tickle the cycle */
 	}
@@ -2670,6 +2677,7 @@
 
 	switch(ccmode) {
 	case STS_MODE_IIN_LOOP:
+		pca9468->chg_data.iin_loop_count++;
 	case STS_MODE_CHG_LOOP:	/* CHG_LOOP does't exist */
 		apply_ircomp = true;
 
@@ -2757,7 +2765,7 @@
 		goto error;
 	}
 
-	if (!pca9468->irdrop_comp_ok && apply_ircomp) {
+	if (pca9468->pdata->pca_irdrop && apply_ircomp) {
 		int rc;
 
 		rc = pca9468_comp_irdrop(pca9468);
@@ -2801,7 +2809,7 @@
 /* 2:1 Direct Charging CC MODE control */
 static int pca9468_charge_ccmode(struct pca9468_charger *pca9468)
 {
-	int ccmode, vin_vol, iin, ret = 0;
+	int ccmode = -1, vin_vol, iin, ret = 0;
 	bool apply_ircomp = false;
 
 	pr_debug("%s: ======START======= \n", __func__);
@@ -2886,6 +2894,7 @@
 		break;
 
 	case STS_MODE_IIN_LOOP:
+		pca9468->chg_data.iin_loop_count++;
 	case STS_MODE_CHG_LOOP:
 		iin = pca9468_read_adc(pca9468, ADCCH_IIN);
 		if (iin < 0)
@@ -2933,7 +2942,7 @@
 		break;
 	}
 
-	if (!pca9468->irdrop_comp_ok && apply_ircomp) {
+	if (pca9468->pdata->pca_irdrop && apply_ircomp) {
 		int rc;
 
 		rc = pca9468_comp_irdrop(pca9468);
@@ -2985,8 +2994,9 @@
 	}
 
 	switch(cvmode) {
-	case STS_MODE_CHG_LOOP:
 	case STS_MODE_IIN_LOOP:
+		pca9468->chg_data.iin_loop_count++;
+	case STS_MODE_CHG_LOOP:
 
 		if (pca9468->ta_type == TA_TYPE_WIRELESS) {
 			/* Decrease RX voltage (100mV) */
@@ -3180,8 +3190,9 @@
 		pca9468->timer_period = PCA9468_CVMODE_CHECK_T;
 	} break;
 
-	case STS_MODE_CHG_LOOP:
 	case STS_MODE_IIN_LOOP:
+		pca9468->chg_data.iin_loop_count++;
+	case STS_MODE_CHG_LOOP:
 		/* Check the TA type */
 		if (pca9468->ta_type == TA_TYPE_WIRELESS) {
 			/* Decrease RX Voltage (100mV) */
@@ -4288,7 +4299,6 @@
 		/* Start Direct Charging on Index */
 		pca9468->dc_start_time = get_boot_sec();
 		p9468_chg_stats_init(&pca9468->chg_data);
-		pca9468->irdrop_comp_ok = false;
 		pca9468->pps_index = index;
 
 		dev_info(pca9468->dev, "%s: charging_state=%u->%u\n", __func__,
@@ -4465,8 +4475,6 @@
 		ret = pca9468_get_chg_chgr_state(pca9468, &chg_state);
 		if (ret < 0)
 			return ret;
-		if (pca9468->irdrop_comp_ok)
-			chg_state.f.flags &= ~GBMS_CS_FLAG_NOCOMP;
 		gbms_propval_int64val(val) = chg_state.v;
 		break;
 
@@ -4696,6 +4704,9 @@
 		pdata->irdrop_limits[1] = PCA9468_IRDROP_LIMIT_TIER2;
 		pdata->irdrop_limits[2] = PCA9468_IRDROP_LIMIT_TIER3;
 	}
+	pdata->pca_irdrop = of_property_read_bool(np_pca9468, "google,pca-irdrop");
+	if (pdata->pca_irdrop)
+		pr_info("%s: google,pca-irdrop is set, run irdrop in pca\n", __func__);
 
 	/* Spread Spectrum settings */
 	ret = of_property_read_u32(np_pca9468, "pca9468,sc-clk-dither-rate",
@@ -4905,10 +4916,11 @@
 			chg_data->receiver_state[3],
 			chg_data->receiver_state[4]);
 	len += scnprintf(&buff[len], max_size - len,
-			"N: ovc=%d,ovc_ibatt=%d,ovc_delta=%d rcp=%d,stby=%d\n",
+			"N: ovc=%d,ovc_ibatt=%d,ovc_delta=%d rcp=%d,stby=%d, iin_loop=%d\n",
 			chg_data->ovc_count, chg_data->ovc_max_ibatt, chg_data->ovc_max_delta,
 			chg_data->rcp_count,
-			chg_data->stby_count);
+			chg_data->stby_count,
+			chg_data->iin_loop_count);
 	len += scnprintf(&buff[len], max_size - len,
 			"C: nc=%d,pre=%d,ca=%d,cc=%d,cv=%d,adj=%d\n",
 			chg_data->nc_count,
@@ -5003,8 +5015,6 @@
 			    &debug_adc_chan_ops);
 	debugfs_create_file("pps_index", 0644, chip->debug_root, chip,
 			    &debug_pps_index_ops);
-	debugfs_create_bool("irdrop_comp", 0644, chip->debug_root,
-			    &chip->irdrop_comp_ok);
 
 	return 0;
 }
diff --git a/pca9468_charger.h b/pca9468_charger.h
index 21dbcd3..d72d2fd 100644
--- a/pca9468_charger.h
+++ b/pca9468_charger.h
@@ -43,6 +43,7 @@
 	/* irdrop */
 	unsigned int	irdrop_limits[3];
 	int		irdrop_limit_cnt;
+	bool		pca_irdrop;
 
 	/* Spread Spectrum settings */
 	unsigned int	sc_clk_dither_rate;
@@ -104,6 +105,7 @@
 	unsigned int cv_count;
 	unsigned int adj_count;
 	unsigned int stby_count;
+	unsigned int iin_loop_count;
 };
 
 #define p9468_chg_stats_valid(chg_data) ((chg_data)->valid)
@@ -179,7 +181,6 @@
  * @debug_adc_channel: ADC channel to read
  * @init_done: true when initialization is complete
  * @dc_start_time: start time (sec since boot) of the DC session
- * @irdrop_comp_ok: when true clear GBMS_CS_FLAG_NOCOMP in flags
  */
 struct pca9468_charger {
 	struct wakeup_source	*monitor_wake_lock;
diff --git a/pca9468_gbms_pps.c b/pca9468_gbms_pps.c
index 98c0bab..0145ea0 100644
--- a/pca9468_gbms_pps.c
+++ b/pca9468_gbms_pps.c
@@ -600,7 +600,7 @@
 	chg_state->f.chg_type = pca9468_get_charge_type(pca9468);
 	chg_state->f.flags = gbms_gen_chg_flags(chg_state->f.chg_status,
 						chg_state->f.chg_type);
-	chg_state->f.flags |= GBMS_CS_FLAG_NOCOMP;
+	chg_state->f.flags |= GBMS_CS_FLAG_DIRECT_CHG;
 
 	vchrg = pca9468_read_adc(pca9468, ADCCH_VBAT);
 	if (vchrg > 0)