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

Commit 11330d9f authored by Abhijeet Dharmapurikar's avatar Abhijeet Dharmapurikar Committed by Harry Yang
Browse files

power: qcom: lock USB removal



During USB removal a lot of cleanup happens; votables are reset, flags
are cleared, etc. After the cleanup is finished there is a chance that
USB power supply consumers may set properties before getting the USB
removal notification. This can lead to many problems where ICL limits
are set based on the previous insertion, or APSD is disabled due to a
late setting of PD_ACTIVE.

Introduce a lock which prevents USB power supply consumers from setting
properties when USB has been removed. This lock will ensure that the
next insertion starts with a clean slate.

CRs-Fixed: 2020132
Change-Id: I05a4145289b6097e41afc30aa09782722fa03fb6
Signed-off-by: default avatarNicholas Troast <ntroast@codeaurora.org>
Signed-off-by: default avatarAbhijeet Dharmapurikar <adharmap@codeaurora.org>
parent 8c28e0fa
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -540,6 +540,12 @@ static int smb2_usb_set_prop(struct power_supply *psy,
	struct smb_charger *chg = &chip->chg;
	int rc = 0;

	mutex_lock(&chg->lock);
	if (!chg->typec_present) {
		rc = -EINVAL;
		goto unlock;
	}

	switch (psp) {
	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
		rc = smblib_set_prop_usb_voltage_min(chg, val);
@@ -578,6 +584,8 @@ static int smb2_usb_set_prop(struct power_supply *psy,
		break;
	}

unlock:
	mutex_unlock(&chg->lock);
	return rc;
}

+48 −28
Original line number Diff line number Diff line
@@ -3103,7 +3103,11 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data)

static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
{
	if (!vbus_rising) {
	if (vbus_rising) {
		/* use the typec flag even though its not typec */
		chg->typec_present = 1;
	} else {
		chg->typec_present = 0;
		smblib_update_usb_type(chg);
		extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
		smblib_uusb_removal(chg);
@@ -3119,18 +3123,16 @@ static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising)
}

#define PL_DELAY_MS			30000
irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
void smblib_usb_plugin_locked(struct smb_charger *chg)
{
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;
	int rc;
	u8 stat;
	bool vbus_rising;

	rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
	if (rc < 0) {
		dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
		return IRQ_HANDLED;
		smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
		return;
	}

	vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
@@ -3180,8 +3182,18 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
		smblib_typec_usb_plugin(chg, vbus_rising);

	power_supply_changed(chg->usb_psy);
	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
		irq_data->name, vbus_rising ? "attached" : "detached");
	smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
					vbus_rising ? "attached" : "detached");
}

irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
{
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;

	mutex_lock(&chg->lock);
	smblib_usb_plugin_locked(chg);
	mutex_unlock(&chg->lock);
	return IRQ_HANDLED;
}

@@ -3720,46 +3732,33 @@ irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg)
	return IRQ_HANDLED;
}

irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
static void smblib_usb_typec_change(struct smb_charger *chg)
{
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;
	int rc;
	u8 stat4, stat5;
	bool debounce_done, sink_attached, legacy_cable;

	if (chg->micro_usb_mode)
		return smblib_handle_usb_typec_change_for_uusb(chg);

	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
		return IRQ_HANDLED;
		return;
	}

	rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
		return IRQ_HANDLED;
		return;
	}

	debounce_done = (bool)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
	sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT);
	legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT);

	if (chg->cc2_detach_wa_active) {
		smblib_dbg(chg, PR_INTERRUPT, "Ignoring cc2_wrkarnd=%d dd=%d\n",
				chg->cc2_detach_wa_active,
				debounce_done);
		return IRQ_HANDLED;
	}

	smblib_handle_typec_debounce_done(chg,
			debounce_done, sink_attached, legacy_cable);

	if (stat4 & TYPEC_VBUS_ERROR_STATUS_BIT)
		smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n",
			irq_data->name);
		smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");

	if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT)
		schedule_work(&chg->vconn_oc_work);
@@ -3767,6 +3766,26 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
	power_supply_changed(chg->usb_psy);
	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4);
	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat5);
}

irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
{
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;

	if (chg->micro_usb_mode) {
		smblib_handle_usb_typec_change_for_uusb(chg);
		return IRQ_HANDLED;
	}

	if (chg->cc2_detach_wa_active) {
		smblib_dbg(chg, PR_INTERRUPT, "Ignoring cc2_wa_active\n");
		return IRQ_HANDLED;
	}

	mutex_lock(&chg->lock);
	smblib_usb_typec_change(chg);
	mutex_unlock(&chg->lock);
	return IRQ_HANDLED;
}

@@ -3892,7 +3911,6 @@ static void rdstd_cc2_detach_work(struct work_struct *work)
{
	int rc;
	u8 stat4, stat5;
	struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"};
	struct smb_charger *chg = container_of(work, struct smb_charger,
						rdstd_cc2_detach_work);

@@ -3955,8 +3973,9 @@ static void rdstd_cc2_detach_work(struct work_struct *work)
	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
						EXIT_SNK_BASED_ON_CC_BIT, 0);
	smblib_reg_block_restore(chg, cc2_detach_settings);
	irq_data.parent_data = chg;
	smblib_handle_usb_typec_change(0, &irq_data);
	mutex_lock(&chg->lock);
	smblib_usb_typec_change(chg);
	mutex_unlock(&chg->lock);
	return;

rerun:
@@ -4356,6 +4375,7 @@ int smblib_init(struct smb_charger *chg)
{
	int rc = 0;

	mutex_init(&chg->lock);
	mutex_init(&chg->write_lock);
	mutex_init(&chg->otg_oc_lock);
	INIT_WORK(&chg->bms_update_work, bms_update_work);
+1 −0
Original line number Diff line number Diff line
@@ -229,6 +229,7 @@ struct smb_charger {
	int			smb_version;

	/* locks */
	struct mutex		lock;
	struct mutex		write_lock;
	struct mutex		ps_change_lock;
	struct mutex		otg_oc_lock;