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

Commit 4c1c6994 authored by Anirudh Ghayal's avatar Anirudh Ghayal Committed by Fenglin Wu
Browse files

power: qpnp-smbcharger: Add logic to run parallel AICL



Add an optional property "qcom,use-parallel-aicl" to run slave AICL
to detect the total ICL could be allotted in parallel configuration.

CRs-Fixed: 1032013
Change-Id: I6f881cf73cb4eeaf007fe9d46cbe870fbd5443cf
Signed-off-by: default avatarAnirudh Ghayal <aghayal@codeaurora.org>
Signed-off-by: default avatarFenglin Wu <fenglinw@codeaurora.org>
parent 2b69fe50
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -300,6 +300,10 @@ Optional Properties:
- qcom,max-pulse-allowed	The maximum number of pulses allowed in
				HVDCP3 mode. It can be used to restrict VBUS
				to a value.
- qcom,use-parallel-aicl	A boolean property to indicate that AICL is run on the
				parallel slave to detect adapter's ICL capacity. Ideally
				to be used if the required FCC is greater then 3A and if
				the parallel slave supports AICL.

Example:
	qcom,qpnp-smbcharger {
+218 −4
Original line number Diff line number Diff line
@@ -63,6 +63,9 @@ struct parallel_usb_cfg {
	int				initial_aicl_ma;
	ktime_t				last_disabled;
	bool				enabled_once;
	int				parallel_aicl_ma;
	bool				use_parallel_aicl;
	bool				parallel_en_in_progress;
};

struct ilim_entry {
@@ -263,6 +266,7 @@ struct smbchg_chip {
	struct completion		src_det_raised;
	struct completion		usbin_uv_lowered;
	struct completion		usbin_uv_raised;
	struct completion		hvdcp_det_done;
	int				pulse_cnt;
	struct led_classdev		led_cdev;
	bool				skip_usb_notification;
@@ -347,6 +351,7 @@ enum icl_voters {
	SW_AICL_ICL_VOTER,
	CHG_SUSPEND_WORKAROUND_ICL_VOTER,
	SHUTDOWN_WORKAROUND_ICL_VOTER,
	PARALLEL_ICL_VOTER,
	NUM_ICL_VOTER,
};

@@ -2067,6 +2072,106 @@ static int smbchg_get_aicl_level_ma(struct smbchg_chip *chip)
	return chip->tables.usb_ilim_ma_table[reg];
}

static int smbchg_run_parallel_aicl(struct smbchg_chip *chip)
{
	int rc, aicl_ma, fcc_ma, icl_ma;
	union power_supply_propval pval = {0, };
	struct power_supply *parallel_psy = get_parallel_psy(chip);

	if (!parallel_psy) {
		pr_err("parallel charger not found\n");
		return 0;
	}

	rc = power_supply_set_present(parallel_psy, true);
	if (rc) {
		pr_err("Unable to set_present for parallel_psy rc=%d\n", rc);
		return rc;
	}

	rc = power_supply_set_voltage_limit(parallel_psy, chip->vfloat_mv);
	if (rc) {
		pr_err("Unable to set vfloat for parallel_psy rc=%d\n",
								rc);
		return rc;
	}

	/* Enable slave AICL */
	pval.intval = 1;
	rc = parallel_psy->set_property(parallel_psy,
			POWER_SUPPLY_PROP_ENABLE_AICL, &pval);
	if (rc) {
		pr_err("Unable to enable AICL on parallel_psy rc=%d\n", rc);
		return rc;
	}

	/* Set max allowable FCC to slave */
	fcc_ma = get_effective_result_locked(chip->fcc_votable);
	pval.intval = fcc_ma * 1000;
	rc = parallel_psy->set_property(parallel_psy,
			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
	if (rc) {
		pr_err("Unable to set FCC for parallel_psy rc=%d\n",
								rc);
		goto restore_icl;
	}

	/* Get max allowable ICL */
	icl_ma = get_effective_result_locked(chip->usb_icl_votable);

	/*
	 * Force main charger to draw 100mA as the minimal input current
	 * but don't suspend it to keep the slave charger online.
	 * Set effective ICL value to slave charger to use it detecting
	 * adapter's real capability. The 100mA draw in main charger path
	 * will be added on slave's ICL status.
	 */
	vote(chip->usb_icl_votable, PARALLEL_ICL_VOTER, true, CURRENT_100_MA);

	rc = power_supply_set_current_limit(parallel_psy, icl_ma * 1000);
	if (rc) {
		pr_err("Unable to set ICL for parallel_psy rc=%d\n", rc);
		goto restore_icl;
	}

	rc = parallel_psy->get_property(parallel_psy,
			POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, &pval);
	if (rc) {
		pr_err("Unable to read AICL from parallel_psy rc=%d\n", rc);
		goto restore_icl;
	}

	aicl_ma = pval.intval / 1000;

	if (aicl_ma == 0) {
		pr_err("Parallel_psy ICL status is 0mA\n");
		goto restore_icl;
	}

	chip->parallel.parallel_aicl_ma = min(icl_ma, CURRENT_100_MA + aicl_ma);
	pr_smb(PR_STATUS, "parallel AICL = %d mA\n",
				chip->parallel.parallel_aicl_ma);

restore_icl:
	/* Disable slave AICL */
	pval.intval = 0;
	rc = parallel_psy->set_property(parallel_psy,
			POWER_SUPPLY_PROP_ENABLE_AICL, &pval);
	if (rc)
		pr_err("Unable to disable AICL on parallel_psy rc=%d\n", rc);

	/* Suspend slave and set back last ICL value for main charger */
	pval.intval  = 1;
	rc = parallel_psy->set_property(parallel_psy,
			POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
	if (rc)
		pr_err("Unable to suspend-input to parallel_psy rc=%d\n", rc);

	vote(chip->usb_icl_votable, PARALLEL_ICL_VOTER, false, 0);

	return rc;
}

static void smbchg_parallel_usb_disable(struct smbchg_chip *chip)
{
	struct power_supply *parallel_psy = get_parallel_psy(chip);
@@ -2078,6 +2183,7 @@ static void smbchg_parallel_usb_disable(struct smbchg_chip *chip)
	taper_irq_en(chip, false);
	chip->parallel.initial_aicl_ma = 0;
	chip->parallel.current_max_ma = 0;
	chip->parallel.parallel_aicl_ma = 0;
	power_supply_set_current_limit(parallel_psy,
				SUSPEND_CURRENT_MA * 1000);
	power_supply_set_present(parallel_psy, false);
@@ -2353,6 +2459,19 @@ static bool smbchg_is_parallel_usb_ok(struct smbchg_chip *chip,
	if (parallel_cl_ma <= SUSPEND_CURRENT_MA)
		parallel_cl_ma = 0;

	if (chip->parallel.use_parallel_aicl) {
		rc = smbchg_run_parallel_aicl(chip);
		if (rc) {
			pr_err("Failed to run parallel AICL rc=%d\n", rc);
			return false;
		}
		total_current_ma = chip->parallel.parallel_aicl_ma;
		pr_smb(PR_STATUS, "use parallel AICL result: %dmA\n",
						total_current_ma);
		*ret_total_current_ma = total_current_ma;

		return true;
	}
	/*
	 * Set the parallel charge path's input current limit (ICL)
	 * to the total current / 2
@@ -2374,6 +2493,7 @@ static bool smbchg_is_parallel_usb_ok(struct smbchg_chip *chip,
	return true;
}

#define HVDCP_DETECTION_DONE_MS		5000
#define PARALLEL_CHARGER_EN_DELAY_MS	500
static void smbchg_parallel_usb_en_work(struct work_struct *work)
{
@@ -2382,6 +2502,37 @@ static void smbchg_parallel_usb_en_work(struct work_struct *work)
				parallel_en_work.work);
	int previous_aicl_ma, total_current_ma, aicl_ma;
	bool in_progress;
	int rc, tries = 3;

	pr_smb(PR_MISC, "started\n");
	chip->parallel.parallel_en_in_progress = true;
	/*
	 * If use-parallel-aicl is enabled, we run parallel AICL to detect
	 * the total input current from the adapter which could be split and
	 * allotted to main and slave chargers. Running parallel AICL would
	 * cost ~2 seconds which is the same delay for hvdcp detection. This
	 * would cause the concurrence of parallel charging checking and
	 * hvdcp detection.
	 * The concurrence would result a mess on the parallel charger settings
	 * because both logics manipulate ICL setting as well as the parallel
	 * enabling/disabling.
	 * Wait here before parallel charging logic running, until hvdcp/
	 * hvdcp3 detection logic has finished/confirmed the charger type
	 * detection, to provide a stable ICL value for parallel charging
	 * splitting logic.
	 */
	if (chip->parallel.use_parallel_aicl) {
		while (tries--) {
			rc = wait_for_completion_interruptible_timeout(
				&chip->hvdcp_det_done,
				msecs_to_jiffies(HVDCP_DETECTION_DONE_MS));
			if (rc >= 0) {
				pr_smb(PR_STATUS, "hvdcp detection done\n");
				break;
			}
			pr_smb(PR_STATUS, "wait hvdcp_det_done interrupted\n");
		}
	}

	/* do a check to see if the aicl is stable */
	previous_aicl_ma = smbchg_get_aicl_level_ma(chip);
@@ -2408,10 +2559,14 @@ static void smbchg_parallel_usb_en_work(struct work_struct *work)
		}
	}
	mutex_unlock(&chip->parallel.lock);
	pr_smb(PR_STATUS, "Parallel check complete!\n");

	chip->parallel.parallel_en_in_progress = false;
	smbchg_relax(chip, PM_PARALLEL_CHECK);
	return;

recheck:
	chip->parallel.parallel_en_in_progress = false;
	schedule_delayed_work(&chip->parallel_en_work, 0);
}

@@ -2422,6 +2577,11 @@ static void smbchg_parallel_usb_check_ok(struct smbchg_chip *chip)
	if (!parallel_psy || !chip->parallel_charger_detected)
		return;

	if (chip->parallel.parallel_en_in_progress) {
		pr_smb(PR_MISC, "parallel logic run in progress, ignore\n");
		return;
	}

	smbchg_stay_awake(chip, PM_PARALLEL_CHECK);
	schedule_delayed_work(&chip->parallel_en_work, 0);
}
@@ -2825,14 +2985,17 @@ static int set_usb_current_limit_vote_cb(struct device *dev,
		}
	}

	/* skip the aicl rerun if hvdcp icl voter is active */
	if (effective_id == HVDCP_ICL_VOTER)
	/* skip the aicl rerun if hvdcp icl voter or parallel voter is active */
	if (effective_id == HVDCP_ICL_VOTER ||
			effective_id == PARALLEL_ICL_VOTER)
		return 0;

	aicl_ma = smbchg_get_aicl_level_ma(chip);
	if (icl_ma > aicl_ma)
		smbchg_rerun_aicl(chip);

	smbchg_parallel_usb_check_ok(chip);

	return 0;
}

@@ -4546,6 +4709,13 @@ static void smbchg_hvdcp_det_work(struct work_struct *work)
				hvdcp_det_work.work);
	int rc;

	if (chip->parallel.use_parallel_aicl) {
		if (!chip->hvdcp3_supported || !is_hvdcp_present(chip)) {
			complete_all(&chip->hvdcp_det_done);
			pr_smb(PR_MISC, "hvdcp_det_done complete\n");
		}
	}

	if (is_hvdcp_present(chip)) {
		if (!chip->hvdcp3_supported &&
			(chip->wa_flags & SMBCHG_HVDCP_9V_EN_WA)) {
@@ -4679,6 +4849,12 @@ static void handle_usb_removal(struct smbchg_chip *chip)
	/* cancel/wait for hvdcp pending work if any */
	cancel_delayed_work_sync(&chip->hvdcp_det_work);
	smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_UNKNOWN);

	if (chip->parallel.use_parallel_aicl) {
		complete_all(&chip->hvdcp_det_done);
		pr_smb(PR_MISC, "complete hvdcp_det_done\n");
	}

	if (!chip->skip_usb_notification) {
		pr_smb(PR_MISC, "setting usb psy present = %d\n",
				chip->usb_present);
@@ -4780,6 +4956,10 @@ static void handle_usb_insertion(struct smbchg_chip *chip)
		smbchg_stay_awake(chip, PM_DETECT_HVDCP);
		schedule_delayed_work(&chip->hvdcp_det_work,
					msecs_to_jiffies(HVDCP_NOTIFY_MS));
		if (chip->parallel.use_parallel_aicl) {
			reinit_completion(&chip->hvdcp_det_done);
			pr_smb(PR_MISC, "init hvdcp_det_done\n");
		}
	}

	smbchg_detect_parallel_charger(chip);
@@ -5114,9 +5294,14 @@ static void smbchg_handle_hvdcp3_disable(struct smbchg_chip *chip)
	} else if (is_usb_present(chip)) {
		read_usb_type(chip, &usb_type_name, &usb_supply_type);
		smbchg_change_usb_supply_type(chip, usb_supply_type);
		if (usb_supply_type == POWER_SUPPLY_TYPE_USB_DCP)
		if (usb_supply_type == POWER_SUPPLY_TYPE_USB_DCP) {
			schedule_delayed_work(&chip->hvdcp_det_work,
				msecs_to_jiffies(HVDCP_NOTIFY_MS));
			if (chip->parallel.use_parallel_aicl) {
				reinit_completion(&chip->hvdcp_det_done);
				pr_smb(PR_MISC, "init hvdcp_det_done\n");
			}
		}
	} else {
		smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_UNKNOWN);
	}
@@ -5338,6 +5523,11 @@ out:

	smbchg_handle_hvdcp3_disable(chip);

	if (chip->parallel.use_parallel_aicl) {
		pr_smb(PR_MISC, "complete hvdcp_det_done\n");
		complete_all(&chip->hvdcp_det_done);
	}

	return rc;
}

@@ -5542,6 +5732,11 @@ static int smbchg_unprepare_for_pulsing_lite(struct smbchg_chip *chip)
	}
	smbchg_handle_hvdcp3_disable(chip);

	if (chip->parallel.use_parallel_aicl) {
		pr_smb(PR_MISC, "complete hvdcp_det_done\n");
		complete_all(&chip->hvdcp_det_done);
	}

	return rc;
}

@@ -5591,6 +5786,11 @@ static int smbchg_hvdcp3_confirmed(struct smbchg_chip *chip)

	smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_USB_HVDCP_3);

	if (chip->parallel.use_parallel_aicl) {
		complete_all(&chip->hvdcp_det_done);
		pr_smb(PR_MISC, "hvdcp_det_done complete\n");
	}

	return rc;
}

@@ -5794,6 +5994,17 @@ static void smbchg_external_power_changed(struct power_supply *psy)
			return;
		}

		read_usb_type(chip, &usb_type_name, &usb_supply_type);
		if (usb_supply_type == POWER_SUPPLY_TYPE_USB_DCP) {
			schedule_delayed_work(&chip->hvdcp_det_work,
				msecs_to_jiffies(HVDCP_NOTIFY_MS));
			if (chip->parallel.use_parallel_aicl) {
				reinit_completion(&chip->hvdcp_det_done);
				pr_smb(PR_MISC, "init hvdcp_det_done\n");
			}
			smbchg_change_usb_supply_type(chip, usb_supply_type);
		}

		read_usb_type(chip, &usb_type_name, &usb_supply_type);
		if (usb_supply_type == POWER_SUPPLY_TYPE_USB_DCP)
			schedule_delayed_work(&chip->hvdcp_det_work,
@@ -6665,7 +6876,7 @@ static irqreturn_t aicl_done_handler(int irq, void *_chip)

	increment_aicl_count(chip);

	if (usb_present)
	if (usb_present && !chip->parallel.use_parallel_aicl)
		smbchg_parallel_usb_check_ok(chip);

	if (chip->aicl_complete)
@@ -7486,6 +7697,8 @@ static int smb_parse_dt(struct smbchg_chip *chip)

	OF_PROP_READ(chip, chip->max_pulse_allowed,
				"max-pulse-allowed", rc, 1);
	chip->parallel.use_parallel_aicl = of_property_read_bool(node,
					"qcom,use-parallel-aicl");
	/*
	 * use the dt values if they exist, otherwise do not touch the params
	 */
@@ -8216,6 +8429,7 @@ static int smbchg_probe(struct spmi_device *spmi)
	init_completion(&chip->src_det_raised);
	init_completion(&chip->usbin_uv_lowered);
	init_completion(&chip->usbin_uv_raised);
	init_completion(&chip->hvdcp_det_done);
	chip->vadc_dev = vadc_dev;
	chip->vchg_vadc_dev = vchg_vadc_dev;
	chip->spmi = spmi;