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

Commit f62bc5be authored by Ashish Chavan's avatar Ashish Chavan
Browse files

power: supply: smblite: Add support for concurrency mode



Add an interface to enable/disable boost concurrency. When
enabled the charger in buck-mode can act as a boost over a
separate path. The feature is supported only on PM5100 and
can be enabled using "qcom,concurrency-mode-supported" flag.

Change-Id: I3ab78af2123add2c4d5cba96500e1576b3c7deb3
Signed-off-by: default avatarAshish Chavan <ashichav@codeaurora.org>
parent bb168a0f
Loading
Loading
Loading
Loading
+55 −3
Original line number Diff line number Diff line
@@ -183,11 +183,12 @@ ATTRIBUTE_GROUPS(smblite);
static int smblite_chg_config_init(struct smblite *chip)
{
	struct smb_charger *chg = &chip->chg;
	int subtype = (u8)of_device_get_match_data(chg->dev);
	u8 val;
	int rc = 0;

	switch (subtype) {
	chg->subtype = (u8)of_device_get_match_data(chg->dev);

	switch (chg->subtype) {
	case PM2250:
		chg->wa_flags |= WEAK_ADAPTER_WA;
		chg->base = smb_base[PM2250];
@@ -209,7 +210,7 @@ static int smblite_chg_config_init(struct smblite *chip)
		chg->name = "PM5100_charger";
		break;
	default:
		pr_err("Unsupported PMIC subtype=%d\n", subtype);
		pr_err("Unsupported PMIC subtype=%d\n", chg->subtype);
		return -EINVAL;
	}

@@ -302,6 +303,9 @@ static int smblite_parse_dt_misc(struct smblite *chip, struct device_node *node)
	if (chg->chg_param.fcc_step_size_ua <= 0)
		chg->chg_param.fcc_step_size_ua = DEFAULT_FCC_STEP_SIZE_UA;

	chg->concurrent_mode_supported = of_property_read_bool(node,
					"qcom,concurrency-mode-supported");

	return 0;
}

@@ -771,6 +775,41 @@ static int smblite_init_batt_psy(struct smblite *chip)
	return rc;
}

/*******************
 * QCOM SMB Class  *
 *******************/
static ssize_t boost_concurrent_mode_store(struct class *c, struct class_attribute *attr,
						const char *buf, size_t count)
{
	struct smb_charger *chg = container_of(c, struct smb_charger, qcom_class);
	int rc;
	bool val;

	if (kstrtobool(buf, &val))
		return -EINVAL;

	rc = smblite_lib_set_concurrent_config(chg, val);
	if (rc < 0)
		return rc;

	return count;
}

static ssize_t boost_concurrent_mode_show(struct class *c, struct class_attribute *attr,
						char *buf)
{
	struct smb_charger *chg = container_of(c, struct smb_charger, qcom_class);

	return scnprintf(buf, PAGE_SIZE, "%d\n", chg->concurrent_mode_status);
}
static CLASS_ATTR_RW(boost_concurrent_mode);

static struct attribute *qcom_class_attrs[] = {
	&class_attr_boost_concurrent_mode.attr,
	NULL,
};
ATTRIBUTE_GROUPS(qcom_class);

/***************************
 * HARDWARE INITIALIZATION *
 ***************************/
@@ -1964,6 +2003,18 @@ static int smblite_probe(struct platform_device *pdev)
		goto disable_irq;
	}

	/* Register QCOM SMB class */
	if (is_concurrent_mode_supported(chg)) {
		chg->qcom_class.name = "qcom-smb";
		chg->qcom_class.owner = THIS_MODULE;
		chg->qcom_class.class_groups = qcom_class_groups;
		rc = class_register(&chg->qcom_class);
		if (rc < 0) {
			pr_err("Failed to create qcom_class rc=%d\n", rc);
			goto disable_irq;
		}
	}

	device_init_wakeup(chg->dev, true);

	rc = smblite_lib_get_prop_usb_present(chg, &pval);
@@ -1991,6 +2042,7 @@ static int smblite_remove(struct platform_device *pdev)
	struct smb_charger *chg = &chip->chg;

	smblite_disable_interrupts(chg);
	class_destroy(&chg->qcom_class);
	smblite_lib_deinit(chg);
	sysfs_remove_groups(&chg->dev->kobj, smblite_groups);
	platform_set_drvdata(pdev, NULL);
+212 −40
Original line number Diff line number Diff line
@@ -523,6 +523,40 @@ static int smblite_lib_register_notifier(struct smb_charger *chg)
	return 0;
}

bool is_concurrent_mode_supported(struct smb_charger *chg)
{
	return (chg->concurrent_mode_supported && chg->subtype == PM5100);
}

static int smblite_lib_concurrent_mode_config(struct smb_charger *chg, bool enable)
{
	int rc;

	if (!is_concurrent_mode_supported(chg))
		return 0;

	rc = smblite_lib_write(chg, CONCURRENT_MODE_CFG_REG(chg->base),
			(enable ? CONCURRENT_MODE_EN_BIT : 0));
	if (rc < 0)
		smblite_lib_err(chg, "Failed to write CONCURRENT_MODE_CFG_REG rc=%d\n",
				rc);

	if (!enable) {
		/* Remove usb_icl_vote when concurrency mode is disabled */
		rc = vote(chg->usb_icl_votable, CONCURRENT_MODE_VOTER, false,
				0);
		if (rc < 0)
			smblite_lib_err(chg, "Failed to vote on ICL rc=%d\n", rc);

		/* Remove chg_disable_vote when concurrency mode is disabled */
		rc = vote(chg->chg_disable_votable, CONCURRENT_MODE_VOTER, false, 0);
		if (rc < 0)
			smblite_lib_err(chg, "Failed to vote on ICL rc=%d\n", rc);
	}

	return rc;
}

static void smblite_lib_uusb_removal(struct smb_charger *chg)
{
	int rc;
@@ -563,6 +597,8 @@ static void smblite_lib_uusb_removal(struct smb_charger *chg)

	chg->uusb_apsd_rerun_done = false;
	chg->hvdcp3_detected = false;
	/* Disable concurrent mode on USB removal. */
	smblite_lib_concurrent_mode_config(chg, false);
}

void smblite_lib_suspend_on_debug_battery(struct smb_charger *chg)
@@ -1299,7 +1335,52 @@ static int smblite_lib_dp_pulse(struct smb_charger *chg)
	return rc;
}

int smblite_lib_force_vbus_voltage(struct smb_charger *chg, u8 val)
#define HVDCP3_QUALIFICATION_UV (PM5100_MAX_HVDCP3_PULSES * \
					(HVDCP3_STEP_SIZE_UV / 2))
static int smblite_lib_hvdcp3_force_max_vbus(struct smb_charger *chg)
{
	union power_supply_propval pval = {0, };
	int cnt = 0, rc, prev_vbus;
	bool qc3_detected = false;

	rc = smblite_lib_get_prop_usb_voltage_now(chg, &pval);
	if (rc < 0) {
		smblite_lib_err(chg, "Couldn't read voltage_now rc=%d\n",
		rc);
		return rc;
	}

	prev_vbus = pval.intval;

	/*
	 * Statically increase voltage till 6V.
	 * ( i.e : 1V / 200mV = 5 pulses ).
	 */
	while (cnt++ < PM5100_MAX_HVDCP3_PULSES) {
		smblite_lib_dp_pulse(chg);
		/* wait for 100ms for vbus to settle. */
		msleep(100);
	}

	rc = smblite_lib_get_prop_usb_voltage_now(chg, &pval);
	if (rc < 0) {
		smblite_lib_err(chg, "Couldn't read voltage_now rc=%d\n",
			rc);
		return rc;
	}

	/* Check if voltage incremented. (i.e if QC3 ) */
	if (pval.intval >= (prev_vbus + HVDCP3_QUALIFICATION_UV))
		qc3_detected = true;

	smblite_lib_dbg(chg, PR_MISC, "HVDCP3 : detected=%s, prev_vbus=%d, vbus_now=%d\n",
			(qc3_detected ? "True" : "False"), prev_vbus,
			pval.intval);

	return qc3_detected;
}

static int smblite_lib_force_vbus_voltage(struct smb_charger *chg, u8 val)
{
	int rc;

@@ -1356,6 +1437,111 @@ int smblite_lib_run_aicl(struct smb_charger *chg, int type)
	return 0;
}

#define CONCURRENCY_REDUCED_ICL_UA 300000
int smblite_lib_set_concurrent_config(struct smb_charger *chg, bool enable)
{
	int rc = 0, icl_ua = 0, settled_icl_ua = 0, usb_present = 0;
	union power_supply_propval pval = {0, };

	if (!is_concurrent_mode_supported(chg)) {
		smblite_lib_dbg(chg, PR_MISC, "Concurrent Mode supported disabled\n");
		return 0;
	}

	/* Exit if there is no change in state */
	if (chg->concurrent_mode_status == enable)
		goto out;

	rc = smblite_lib_get_prop_usb_present(chg, &pval);
	if (rc < 0) {
		smblite_lib_dbg(chg, PR_MISC,
			"Couldn't get USB preset status rc=%d\n", rc);
		goto failure;
	}
	usb_present = pval.intval;

	if (enable) {
		/* Check if USB is connected */
		if (!usb_present) {
			smblite_lib_dbg(chg, PR_MISC,
				"Failed to enable concurrent mode USB disconnected\n", rc);
			goto failure;
		}

		/* Get AICL Result */
		rc = smblite_lib_get_prop_input_current_settled(chg, &settled_icl_ua);
		if (rc) {
			smblite_lib_err(chg, "Failed read AICL Result rc=%d\n", rc);
			goto failure;
		}

		/* Return if AICL result is less than 300mA. */
		if (settled_icl_ua <= CONCURRENCY_REDUCED_ICL_UA) {
			smblite_lib_dbg(chg, PR_MISC,
				"AICL Result too less to enable concurreny mode\n");
			goto failure;
		}

		icl_ua = settled_icl_ua - CONCURRENCY_REDUCED_ICL_UA;

		rc = vote(chg->usb_icl_votable, CONCURRENT_MODE_VOTER, true,
				icl_ua);
		if (rc < 0) {
			smblite_lib_err(chg, "Failed to vote on ICL rc=%d\n", rc);
			goto failure;
		}

		if (chg->hvdcp3_detected) {
			/* Force Vbus to 5V. */
			rc = smblite_lib_force_vbus_voltage(chg, FORCE_5V_BIT);
			if (rc < 0)
				smblite_lib_err(chg, "Failed to force vbus to 5V rc=%d\n",
					rc);
		}

		/* Enable charger if already disabled */
		rc = vote(chg->chg_disable_votable, CONCURRENT_MODE_VOTER, false, 0);
		if (rc < 0) {
			smblite_lib_err(chg, "Failed to Enable charger rc=%d\n",
					rc);
			goto failure;
		}

		/* Enable concurrent mode */
		rc = smblite_lib_concurrent_mode_config(chg, true);
		if (rc < 0)
			goto failure;

		chg->concurrent_mode_status = true;
		smblite_lib_dbg(chg, PR_MISC, "Concurrent Mode enabled successfully: settled_icl_ua=%duA, icl_ua=%duA, is_hvdcp3=%d\n",
					settled_icl_ua, icl_ua,
					chg->hvdcp3_detected);
		goto out;
	} else {
		/* Disable concurrent mode */
		rc = smblite_lib_concurrent_mode_config(chg, false);
		if (rc < 0)
			goto failure;

		/* Restore vbus to MAX(6V) if QC3P5 is connected */
		if (chg->hvdcp3_detected && usb_present)
			smblite_lib_hvdcp3_force_max_vbus(chg);

		chg->concurrent_mode_status = false;
		smblite_lib_dbg(chg, PR_MISC, "Concurrent Mode disabled successfully: is_hvdcp3=%d\n",
			chg->hvdcp3_detected);
		goto out;
	}

failure:
	rc = -EINVAL;
	smblite_lib_dbg(chg, PR_MISC, "Failed to %s concurrent mode\n",
			(enable ? "Enable" : "Disable"));

out:
	return rc;
}

/*******************
 * USB PSY GETTERS *
 *******************/
@@ -2397,12 +2583,30 @@ static void smblite_lib_micro_usb_plugin(struct smb_charger *chg,
					bool vbus_rising)
{
	int rc = 0;

	u8 stat;
	if (vbus_rising) {
		rc = typec_partner_register(chg);
		if (rc < 0)
			smblite_lib_err(chg, "Couldn't register partner rc =%d\n",
					rc);

		/*
		 * For PM5100 check if concurrent mode support is enabled and
		 * charging is paused in hardware due to boost being enabled,
		 * force charging to be disabled in SW.
		 */
		if (is_concurrent_mode_supported(chg)) {
			rc = smblite_lib_read(chg, CHGR_CHG_EN_STATUS_REG(chg->base), &stat);
			if (rc < 0)
				smblite_lib_err(chg, "Couldn't read CHGR_EN_STATUS_REG rc=%d\n",
					rc);

			vote(chg->chg_disable_votable, CONCURRENT_MODE_VOTER,
				(stat & CHARGING_DISABLED_FROM_BOOST_BIT), 0);

			smblite_lib_dbg(chg, PR_MISC,
				"charger_en_status=%x, Charging disable by boost\n", stat);
		}
	} else {
		smblite_lib_notify_device_mode(chg, false);
		smblite_lib_uusb_removal(chg);
@@ -2695,54 +2899,22 @@ static void smblite_lib_handle_apsd_done(struct smb_charger *chg, bool rising)
		   apsd_result->name);
}

#define HVDCP3_QUALIFICATION_UV (PM5100_MAX_HVDCP3_PULSES * \
					(HVDCP3_STEP_SIZE_UV / 2))
static void smblite_lib_handle_hvdcp_check_timeout(struct smb_charger *chg,
					      bool rising, bool qc_charger)
{
	union power_supply_propval pval = {0, };
	int rc = 0, cnt = 0, prev_vbus;
	int rc = 0;

	if (rising) {

		if (qc_charger) {
			rc = smblite_lib_get_prop_usb_voltage_now(chg, &pval);
			if (rc < 0) {
				smblite_lib_err(chg, "Couldn't read voltage_now rc=%d\n",
					rc);
				goto failure;
			}

			prev_vbus = pval.intval;

			/*
			 * Statically increase voltage till 6V.
			 * ( i.e : 1V / 200mV = 5 pulses ).
			 */
			while (cnt++ < PM5100_MAX_HVDCP3_PULSES) {
				smblite_lib_dp_pulse(chg);
				/* wait for 100ms for vbus to settle. */
				msleep(100);
			}

			rc = smblite_lib_get_prop_usb_voltage_now(chg, &pval);
			if (rc < 0) {
				smblite_lib_err(chg, "Couldn't read voltage_now rc=%d\n",
					rc);
				goto failure;
			}

			/* Check if voltage incremented. (i.e if QC3 )*/
			if (pval.intval >= (prev_vbus + HVDCP3_QUALIFICATION_UV))
			/* Increase vbus to MAX(6V), if incremented HVDCP_3 is detected */
			rc = smblite_lib_hvdcp3_force_max_vbus(chg);
			if (rc < 0)
				smblite_lib_err(chg, "HVDCP3 detection failure\n");
			if (rc > 0)
				chg->hvdcp3_detected = true;

			smblite_lib_dbg(chg, PR_MISC, "HVDCP3 : detected=%s, prev_vbus=%d, vbus_now=%d\n",
					(chg->hvdcp3_detected ? "True" : "False"),
					prev_vbus, pval.intval);
		}
	}

failure:
	smblite_lib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__,
		   rising ? "rising" : "falling");
}
+7 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ enum print_reason {
#define ICL_CHANGE_VOTER		"ICL_CHANGE_VOTER"
#define TYPEC_SWAP_VOTER		"TYPEC_SWAP_VOTER"
#define FLASH_ACTIVE_VOTER		"FLASH_ACTIVE_VOTER"
#define CONCURRENT_MODE_VOTER		"CONCURRENT_MODE_VOTER"

#define BOOST_BACK_STORM_COUNT	3
#define WEAK_CHG_STORM_COUNT	8
@@ -264,8 +265,10 @@ struct smb_charger {
	struct iio_channel	*iio_chans;
	struct iio_channel	**iio_chan_list_qg;
	struct iio_channel	**iio_chan_list_smb_parallel;
	struct class            qcom_class;
	int			*debug_mask;
	enum smb_mode		mode;
	u8			subtype;
	int			weak_chg_icl_ua;

	/* locks */
@@ -359,6 +362,8 @@ struct smb_charger {
	bool			uusb_apsd_rerun_done;
	bool			dpdm_enabled;
	bool			hvdcp3_detected;
	bool			concurrent_mode_supported;
	bool			concurrent_mode_status;

	/* workaround flag */
	u32			wa_flags;
@@ -503,5 +508,7 @@ int smblite_iio_get_prop(struct smb_charger *chg, int channel, int *val);
int smblite_iio_set_prop(struct smb_charger *chg, int channel, int val);
int smblite_lib_get_fcc(struct smb_chg_param *param, u8 val_raw);
int smblite_lib_set_fcc(struct smb_chg_param *param, int val_u, u8 *val_raw);
int smblite_lib_set_concurrent_config(struct smb_charger *chg, bool enable);
bool is_concurrent_mode_supported(struct smb_charger *chg);

#endif /* __SMBLITE_LIB_H */
+6 −0
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ enum {
	DISABLE_CHARGE,
};

#define CHGR_CHG_EN_STATUS_REG(base)		(base.chg_base + 0x07)
#define CHARGING_DISABLED_FROM_BOOST_BIT	BIT(6)

#define CHARGER_VBAT_STATUS_REG(base)			(base.chg_base + 0x08)
#define BAT_OV_BIT				BIT(7)

@@ -103,6 +106,9 @@ enum {
#define DCDC_LDO_CFG_REG(base)			(base.dcdc_base + 0x70)
#define LDO_MODE_BIT				BIT(0)

#define CONCURRENT_MODE_CFG_REG(base)			(base.dcdc_base + 0x50)
#define CONCURRENT_MODE_EN_BIT			BIT(0)

/********************************
 *  BATIF Peripheral Registers  *
 ********************************/