Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d13a1a55 authored by Ashay Jaiswal's avatar Ashay Jaiswal
Browse files

power: battery: cleanup FCC stepper flow to handle override votes



Update following in the FCC stepper logic:
- Skip stepping in case if override vote is applied on main's or
  parallel's FCC.
- In case of CP calculate the target FCC/ILIM based on maximum
  allowed ICL and FCC.

Also cache the userspace daemon's vote on main charger's FCC and
use it for all subsequent ILIM calculations, this is to ensure
across disable/re-enable of CP(due to hw faults/FCC) CP_ILIM is
always calculated based on override vote.

Change-Id: I548b4a99c11de9cd89b6a25f8c23180363db7a69
Signed-off-by: default avatarAshay Jaiswal <ashayj@codeaurora.org>
parent eb45ec3a
Loading
Loading
Loading
Loading
+125 −68
Original line number Original line Diff line number Diff line
@@ -189,6 +189,34 @@ static int cp_get_parallel_mode(struct pl_data *chip, int mode)
	return pval.intval;
	return pval.intval;
}
}


static int get_hvdcp3_icl_limit(struct pl_data *chip)
{
	int rc, main_icl, target_icl = -EINVAL;
	union power_supply_propval pval = {0, };

	rc = power_supply_get_property(chip->usb_psy,
				POWER_SUPPLY_PROP_REAL_TYPE, &pval);
	if ((rc < 0) || (pval.intval != POWER_SUPPLY_TYPE_USB_HVDCP_3))
		return target_icl;

	/*
	 * For HVDCP3 adapters, limit max. ILIM as follows:
	 * HVDCP3_ICL: Maximum ICL of HVDCP3 adapter(from DT configuration)
	 * For Parallel input configurations:
	 * VBUS: target_icl = HVDCP3_ICL - main_ICL
	 * VMID: target_icl = HVDCP3_ICL
	 */
	target_icl = chip->chg_param->hvdcp3_max_icl_ua;
	if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE)
					== POWER_SUPPLY_PL_USBIN_USBIN) {
		main_icl = get_effective_result_locked(chip->usb_icl_votable);
		if ((main_icl >= 0) && (main_icl < target_icl))
			target_icl -= main_icl;
	}

	return target_icl;
}

/*
/*
 * Adapter CC Mode: ILIM over-ridden explicitly, below takes no effect.
 * Adapter CC Mode: ILIM over-ridden explicitly, below takes no effect.
 *
 *
@@ -204,7 +232,7 @@ static int cp_get_parallel_mode(struct pl_data *chip, int mode)
 */
 */
static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim)
static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim)
{
{
	int rc, fcc, main_icl, target_icl = chip->chg_param->hvdcp3_max_icl_ua;
	int rc, fcc, target_icl;
	union power_supply_propval pval = {0, };
	union power_supply_propval pval = {0, };


	if (!is_usb_available(chip))
	if (!is_usb_available(chip))
@@ -217,30 +245,8 @@ static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim)
					== POWER_SUPPLY_PL_OUTPUT_VPH)
					== POWER_SUPPLY_PL_OUTPUT_VPH)
		return;
		return;


	rc = power_supply_get_property(chip->usb_psy,
	target_icl = get_hvdcp3_icl_limit(chip);
				POWER_SUPPLY_PROP_REAL_TYPE, &pval);
	ilim = (target_icl > 0) ? min(ilim, target_icl) : ilim;
	if (rc < 0)
		return;

	/*
	 * For HVDCP3 adapters limit max. ILIM based on DT configuration
	 * of HVDCP3 ICL value.
	 * Input VBUS:
	 * target_icl = HVDCP3_ICL - main_ICL
	 * Input VMID
	 * target_icl = HVDCP3_ICL
	 */
	if (pval.intval == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
		if (((cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE))
					== POWER_SUPPLY_PL_USBIN_USBIN)) {
			main_icl = get_effective_result_locked(
							chip->usb_icl_votable);
			if ((main_icl >= 0) && (main_icl < target_icl))
				target_icl -= main_icl;
		}

		ilim = min(target_icl, ilim);
	}


	rc = power_supply_get_property(chip->cp_master_psy,
	rc = power_supply_get_property(chip->cp_master_psy,
				POWER_SUPPLY_PROP_MIN_ICL, &pval);
				POWER_SUPPLY_PROP_MIN_ICL, &pval);
@@ -663,14 +669,17 @@ static void get_main_fcc_config(struct pl_data *chip, int *total_fcc)
static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua,
static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua,
			int parallel_fcc_ua)
			int parallel_fcc_ua)
{
{
	int main_set_fcc_ua, total_fcc_ua;
	int main_set_fcc_ua, total_fcc_ua, target_icl;
	bool override;


	if (!chip->chg_param->fcc_step_size_ua) {
	if (!chip->chg_param->fcc_step_size_ua) {
		pr_err("Invalid fcc stepper step size, value 0\n");
		pr_err("Invalid fcc stepper step size, value 0\n");
		return;
		return;
	}
	}


	if (is_override_vote_enabled_locked(chip->fcc_main_votable)) {
	total_fcc_ua = main_fcc_ua + parallel_fcc_ua;
	override = is_override_vote_enabled_locked(chip->fcc_main_votable);
	if (override) {
		/*
		/*
		 * FCC stepper params need re-calculation in override mode
		 * FCC stepper params need re-calculation in override mode
		 * only if there is change in Main or total FCC
		 * only if there is change in Main or total FCC
@@ -678,48 +687,99 @@ static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua,


		main_set_fcc_ua = get_effective_result_locked(
		main_set_fcc_ua = get_effective_result_locked(
							chip->fcc_main_votable);
							chip->fcc_main_votable);
		total_fcc_ua = main_fcc_ua + parallel_fcc_ua;

		if ((main_set_fcc_ua != chip->override_main_fcc_ua)
		if ((main_set_fcc_ua != chip->override_main_fcc_ua)
				|| (total_fcc_ua != chip->total_fcc_ua)) {
				|| (total_fcc_ua != chip->total_fcc_ua)) {
			chip->override_main_fcc_ua = main_set_fcc_ua;
			chip->override_main_fcc_ua = main_set_fcc_ua;
			chip->total_fcc_ua = total_fcc_ua;
			chip->total_fcc_ua = total_fcc_ua;
			parallel_fcc_ua = (total_fcc_ua
						- chip->override_main_fcc_ua);
		} else {
		} else {
			goto skip_fcc_step_update;
			goto skip_fcc_step_update;
		}
		}
	}
	}


	/* Read current FCC of main charger */
	/*
	chip->main_fcc_ua = get_effective_result(chip->fcc_main_votable);
	 * If override vote is removed then start main FCC from the
	chip->main_step_fcc_dir = (main_fcc_ua > chip->main_fcc_ua) ?
	 * last overridden value.
				STEP_UP : STEP_DOWN;
	 * Clear slave_fcc if requested parallel current is 0 i.e.
	chip->main_step_fcc_count = abs((main_fcc_ua - chip->main_fcc_ua) /
	 * parallel is disabled.
				chip->chg_param->fcc_step_size_ua);
	 */
	chip->main_step_fcc_residual = abs((main_fcc_ua - chip->main_fcc_ua) %
	if (chip->override_main_fcc_ua && !override) {
				chip->chg_param->fcc_step_size_ua);
		chip->main_fcc_ua = chip->override_main_fcc_ua;
		chip->override_main_fcc_ua = 0;
		if (!parallel_fcc_ua)
			chip->slave_fcc_ua = 0;
	} else {
		chip->main_fcc_ua = get_effective_result_locked(
						chip->fcc_main_votable);
	}


	chip->parallel_step_fcc_dir = (parallel_fcc_ua > chip->slave_fcc_ua) ?
	/* Skip stepping if override vote is applied on main */
	if (override) {
		chip->main_step_fcc_count = 0;
		chip->main_step_fcc_residual = 0;
	} else {
		chip->main_step_fcc_dir =
				(main_fcc_ua > chip->main_fcc_ua) ?
					STEP_UP : STEP_DOWN;
					STEP_UP : STEP_DOWN;
	chip->parallel_step_fcc_count
		chip->main_step_fcc_count =
				= abs((parallel_fcc_ua - chip->slave_fcc_ua) /
				abs(main_fcc_ua - chip->main_fcc_ua) /
					chip->chg_param->fcc_step_size_ua);
					chip->chg_param->fcc_step_size_ua;
	chip->parallel_step_fcc_residual
		chip->main_step_fcc_residual =
				= abs((parallel_fcc_ua - chip->slave_fcc_ua) %
				abs(main_fcc_ua - chip->main_fcc_ua) %
					chip->chg_param->fcc_step_size_ua);
					chip->chg_param->fcc_step_size_ua;
	}

	 /* Calculate CP_ILIM based on adapter limit and max. FCC */
	if (!parallel_fcc_ua && is_cp_available(chip) && override) {
		if (!chip->cp_ilim_votable)
			chip->cp_ilim_votable = find_votable("CP_ILIM");

		target_icl = get_hvdcp3_icl_limit(chip) * 2;
		total_fcc_ua -= chip->main_fcc_ua;

		/*
		 * CP_ILIM = parallel_fcc_ua / 2.
		 * Calculate parallel_fcc_ua as follows:
		 * parallel_fcc_ua is based minimum of total FCC
		 * or adapter's maximum allowed ICL limitation(if adapter
		 * has max. ICL limitations).
		 */
		parallel_fcc_ua = (target_icl > 0) ?
				min(target_icl, total_fcc_ua) : total_fcc_ua;
	}


	/* Skip stepping if override vote is applied on CP */
	if (chip->cp_ilim_votable
		&& is_override_vote_enabled(chip->cp_ilim_votable)) {
		chip->parallel_step_fcc_count = 0;
		chip->parallel_step_fcc_residual = 0;
	} else {
		chip->parallel_step_fcc_dir =
				(parallel_fcc_ua > chip->slave_fcc_ua) ?
					STEP_UP : STEP_DOWN;
		chip->parallel_step_fcc_count =
				abs(parallel_fcc_ua - chip->slave_fcc_ua) /
					chip->chg_param->fcc_step_size_ua;
		chip->parallel_step_fcc_residual =
				abs(parallel_fcc_ua - chip->slave_fcc_ua) %
					chip->chg_param->fcc_step_size_ua;
	}
skip_fcc_step_update:
skip_fcc_step_update:
	if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual
	if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual
		|| chip->main_step_fcc_count || chip->main_step_fcc_residual)
		|| chip->main_step_fcc_count || chip->main_step_fcc_residual)
		chip->step_fcc = 1;
		chip->step_fcc = 1;


	pr_debug("Main FCC Stepper parameters: main_step_direction: %d, main_step_count: %d, main_residual_fcc: %d\n",
	pl_dbg(chip, PR_PARALLEL,
		chip->main_step_fcc_dir, chip->main_step_fcc_count,
		"Main FCC Stepper parameters: target_main_fcc: %d, current_main_fcc: %d main_step_direction: %d, main_step_count: %d, main_residual_fcc: %d override_main_fcc_ua: %d override: %d\n",
		chip->main_step_fcc_residual);
		main_fcc_ua, chip->main_fcc_ua, chip->main_step_fcc_dir,
	pr_debug("Parallel FCC Stepper parameters: parallel_step_direction: %d, parallel_step_count: %d, parallel_residual_fcc: %d\n",
		chip->main_step_fcc_count, chip->main_step_fcc_residual,
		chip->override_main_fcc_ua, override);
	pl_dbg(chip, PR_PARALLEL,
		"Parallel FCC Stepper parameters: target_pl_fcc: %d current_pl_fcc: %d parallel_step_direction: %d, parallel_step_count: %d, parallel_residual_fcc: %d\n",
		parallel_fcc_ua, chip->slave_fcc_ua,
		chip->parallel_step_fcc_dir, chip->parallel_step_fcc_count,
		chip->parallel_step_fcc_dir, chip->parallel_step_fcc_count,
		chip->parallel_step_fcc_residual);
		chip->parallel_step_fcc_residual);
	pl_dbg(chip, PR_PARALLEL, "FCC Stepper parameters: step_fcc=%d\n",
		chip->step_fcc);
}
}


#define MINIMUM_PARALLEL_FCC_UA		500000
#define MINIMUM_PARALLEL_FCC_UA		500000
@@ -845,7 +905,7 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
{
{
	struct pl_data *chip = data;
	struct pl_data *chip = data;
	int master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0;
	int master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0;
	int main_fcc_ua = 0, cp_fcc_ua = 0, fcc_thr_ua = 0, rc;
	int cp_fcc_ua = 0, fcc_thr_ua = 0, rc;
	union power_supply_propval pval = {0, };
	union power_supply_propval pval = {0, };
	bool is_cc_mode = false;
	bool is_cc_mode = false;


@@ -892,14 +952,14 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
							(4 * pval.intval);
							(4 * pval.intval);
	}
	}


	if (chip->fcc_main_votable)
	/*
		main_fcc_ua =
	 * CP charger current = Total FCC - Main charger's FCC.
			get_effective_result_locked(chip->fcc_main_votable);
	 * Main charger FCC is userspace's override vote on main.

	 */
	if (main_fcc_ua < 0)
	cp_fcc_ua = total_fcc_ua - chip->chg_param->forced_main_fcc;
		main_fcc_ua = 0;
	pl_dbg(chip, PR_PARALLEL,

		"cp_fcc_ua=%d total_fcc_ua=%d forced_main_fcc=%d\n",
	cp_fcc_ua = total_fcc_ua - main_fcc_ua;
		cp_fcc_ua, total_fcc_ua, chip->chg_param->forced_main_fcc);
	if (cp_fcc_ua > 0) {
	if (cp_fcc_ua > 0) {
		if (chip->cp_slave_psy && chip->cp_slave_disable_votable) {
		if (chip->cp_slave_psy && chip->cp_slave_disable_votable) {
			/*
			/*
@@ -1487,13 +1547,6 @@ static int pl_disable_vote_callback(struct votable *votable,
			if (chip->step_fcc) {
			if (chip->step_fcc) {
				vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
				vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
					true, 0);
					true, 0);
				/*
				 * Configure ILIM above min ILIM of CP to
				 * ensure CP is not disabled due to ILIM vote.
				 * Later FCC stepper will take to ILIM to
				 * target value.
				 */
				cp_configure_ilim(chip, FCC_VOTER, 0);
				schedule_delayed_work(&chip->fcc_stepper_work,
				schedule_delayed_work(&chip->fcc_stepper_work,
					0);
					0);
			}
			}
@@ -1786,6 +1839,10 @@ static void handle_usb_change(struct pl_data *chip)
		vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER,
		vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER,
				false, 0);
				false, 0);
		vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0);
		vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0);
		chip->override_main_fcc_ua = 0;
		chip->total_fcc_ua = 0;
		chip->slave_fcc_ua = 0;
		chip->main_fcc_ua = 0;
	}
	}
}
}


+1 −0
Original line number Original line Diff line number Diff line
@@ -11,6 +11,7 @@ struct charger_param {
	u32 fcc_step_size_ua;
	u32 fcc_step_size_ua;
	u32 smb_version;
	u32 smb_version;
	u32 hvdcp3_max_icl_ua;
	u32 hvdcp3_max_icl_ua;
	u32 forced_main_fcc;
};
};


int qcom_batt_init(struct charger_param *param);
int qcom_batt_init(struct charger_param *param);
+3 −0
Original line number Original line Diff line number Diff line
@@ -1364,6 +1364,9 @@ static int smb5_usb_main_set_prop(struct power_supply *psy,
	case POWER_SUPPLY_PROP_FORCE_MAIN_FCC:
	case POWER_SUPPLY_PROP_FORCE_MAIN_FCC:
		vote_override(chg->fcc_main_votable, CC_MODE_VOTER,
		vote_override(chg->fcc_main_votable, CC_MODE_VOTER,
				(val->intval < 0) ? false : true, val->intval);
				(val->intval < 0) ? false : true, val->intval);
		if (val->intval >= 0)
			chg->chg_param.forced_main_fcc = val->intval;

		/* Main FCC updated re-calculate FCC */
		/* Main FCC updated re-calculate FCC */
		rerun_election(chg->fcc_votable);
		rerun_election(chg->fcc_votable);
		break;
		break;
+2 −0
Original line number Original line Diff line number Diff line
@@ -1199,6 +1199,7 @@ static void smblib_uusb_removal(struct smb_charger *chg)
	chg->usb_icl_delta_ua = 0;
	chg->usb_icl_delta_ua = 0;
	chg->pulse_cnt = 0;
	chg->pulse_cnt = 0;
	chg->uusb_apsd_rerun_done = false;
	chg->uusb_apsd_rerun_done = false;
	chg->chg_param.forced_main_fcc = 0;


	/* write back the default FLOAT charger configuration */
	/* write back the default FLOAT charger configuration */
	rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
	rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
@@ -5854,6 +5855,7 @@ static void typec_src_removal(struct smb_charger *chg)
	chg->voltage_min_uv = MICRO_5V;
	chg->voltage_min_uv = MICRO_5V;
	chg->voltage_max_uv = MICRO_5V;
	chg->voltage_max_uv = MICRO_5V;
	chg->usbin_forced_max_uv = 0;
	chg->usbin_forced_max_uv = 0;
	chg->chg_param.forced_main_fcc = 0;


	/* Reset all CC mode votes */
	/* Reset all CC mode votes */
	vote(chg->fcc_main_votable, MAIN_FCC_VOTER, false, 0);
	vote(chg->fcc_main_votable, MAIN_FCC_VOTER, false, 0);