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

Commit daeb5ac7 authored by Vijayavardhan Vennapusa's avatar Vijayavardhan Vennapusa
Browse files

USB: pd: Always set selfpowered bit after explicit contract



USB PD spec says after PD explicit contract, device needs to
advertise as selfpowered and needs to mark bMaxPower as zero.
Otherwise USB PD compliance test 4.10.2 is failing. Fix the
failure by advertising as self powered after explicit contract
through new extcon property.

Change-Id: If3acdc06b4ac8567bb101ecfc23076af4894e776
Signed-off-by: default avatarVijayavardhan Vennapusa <vvreddy@codeaurora.org>
parent e4fab30e
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -255,6 +255,7 @@ struct dwc3_msm {
	struct notifier_block	id_nb;
	struct notifier_block	eud_event_nb;
	struct notifier_block	host_restart_nb;
	struct notifier_block	self_power_nb;

	struct notifier_block	host_nb;
	bool			xhci_ss_compliance_enable;
@@ -296,6 +297,8 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
						unsigned int value);
static int dwc3_restart_usb_host_mode(struct notifier_block *nb,
					unsigned long event, void *ptr);
static int dwc3_notify_pd_status(struct notifier_block *nb,
				unsigned long event, void *ptr);

/**
 *
@@ -3041,12 +3044,19 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc, int start_idx)
	if (!IS_ERR(edev)) {
		mdwc->extcon_vbus = edev;
		mdwc->vbus_nb.notifier_call = dwc3_msm_vbus_notifier;
		mdwc->self_power_nb.notifier_call = dwc3_notify_pd_status;
		ret = extcon_register_notifier(edev, EXTCON_USB,
				&mdwc->vbus_nb);
		if (ret < 0) {
			dev_err(mdwc->dev, "failed to register notifier for USB\n");
			return ret;
		}
		ret = extcon_register_blocking_notifier(edev, EXTCON_USB,
							&mdwc->self_power_nb);
		if (ret < 0) {
			dev_err(mdwc->dev, "failed to register blocking notifier\n");
			goto err1;
		}
	}

	/*
@@ -4149,6 +4159,28 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on)
	return 0;
}

static int dwc3_notify_pd_status(struct notifier_block *nb,
				unsigned long event, void *ptr)
{
	struct dwc3_msm *mdwc;
	struct dwc3 *dwc;
	int ret = 0;
	union extcon_property_value val;

	mdwc = container_of(nb, struct dwc3_msm, self_power_nb);
	dwc = platform_get_drvdata(mdwc->dwc3);

	ret = extcon_get_property(mdwc->extcon_vbus, EXTCON_USB,
					EXTCON_PROP_USB_PD_CONTRACT, &val);

	if (!ret)
		dwc->gadget.self_powered = val.intval;
	else
		dwc->gadget.self_powered = 0;

	return ret;
}

/* speed: 0 - USB_SPEED_HIGH, 1 - USB_SPEED_SUPER */
static int dwc3_restart_usb_host_mode(struct notifier_block *nb,
				unsigned long event, void *ptr)
+4 −0
Original line number Diff line number Diff line
@@ -583,6 +583,10 @@ static int config_buf(struct usb_configuration *config,
	c->iConfiguration = config->iConfiguration;
	c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
	c->bMaxPower = encode_bMaxPower(speed, config);
	if (config->cdev->gadget->self_powered) {
		c->bmAttributes |= USB_CONFIG_ATT_SELFPOWER;
		c->bMaxPower = 0;
	}

	/* There may be e.g. OTG descriptors */
	if (config->descriptors) {
+26 −0
Original line number Diff line number Diff line
@@ -533,6 +533,22 @@ static inline void start_usb_peripheral(struct usbpd *pd)
	extcon_set_state_sync(pd->extcon, EXTCON_USB, 1);
}

static void notify_pd_contract_status(struct usbpd *pd)
{
	int ret = 0;
	union extcon_property_value val;

	if (!pd)
		return;

	val.intval = pd->in_explicit_contract;
	extcon_set_property(pd->extcon, EXTCON_USB,
			EXTCON_PROP_USB_PD_CONTRACT, val);
	ret = extcon_blocking_sync(pd->extcon, EXTCON_USB, 0);
	if (ret)
		usbpd_err(&pd->dev, "err(%d) while notifying pd status", ret);
}

/**
 * This API allows client driver to request for releasing SS lanes. It should
 * not be called from atomic context.
@@ -1252,6 +1268,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)

	case PE_SRC_READY:
		pd->in_explicit_contract = true;
		notify_pd_contract_status(pd);

		if (pd->vdm_tx)
			kick_sm(pd, 0);
@@ -1398,6 +1415,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)

	case PE_SNK_READY:
		pd->in_explicit_contract = true;
		notify_pd_contract_status(pd);

		if (pd->vdm_tx)
			kick_sm(pd, 0);
@@ -1433,6 +1451,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
				POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val);

		pd->in_explicit_contract = false;
		notify_pd_contract_status(pd);

		/*
		 * need to update PR bit in message header so that
@@ -1996,6 +2015,7 @@ static void usbpd_sm(struct work_struct *w)
		pd->in_pr_swap = false;
		pd->pd_connected = false;
		pd->in_explicit_contract = false;
		notify_pd_contract_status(pd);
		pd->hard_reset_recvd = false;
		pd->caps_count = 0;
		pd->hard_reset_count = 0;
@@ -2079,6 +2099,7 @@ static void usbpd_sm(struct work_struct *w)
				POWER_SUPPLY_PROP_PR_SWAP, &val);

		pd->in_explicit_contract = false;
		notify_pd_contract_status(pd);
		pd->selected_pdo = pd->requested_pdo = 0;
		pd->rdo = 0;
		rx_msg_cleanup(pd);
@@ -2302,6 +2323,7 @@ static void usbpd_sm(struct work_struct *w)

		pd_send_hard_reset(pd);
		pd->in_explicit_contract = false;
		notify_pd_contract_status(pd);
		pd->rdo = 0;
		rx_msg_cleanup(pd);
		reset_vdm_state(pd);
@@ -2747,6 +2769,7 @@ static void usbpd_sm(struct work_struct *w)

		pd_send_hard_reset(pd);
		pd->in_explicit_contract = false;
		notify_pd_contract_status(pd);
		pd->selected_pdo = pd->requested_pdo = 0;
		pd->rdo = 0;
		reset_vdm_state(pd);
@@ -2778,6 +2801,7 @@ static void usbpd_sm(struct work_struct *w)
		power_supply_set_property(pd->usb_psy,
				POWER_SUPPLY_PROP_PR_SWAP, &val);
		pd->in_explicit_contract = false;
		notify_pd_contract_status(pd);

		if (pd->vbus_enabled) {
			regulator_disable(pd->vbus);
@@ -3963,6 +3987,8 @@ struct usbpd *usbpd_create(struct device *parent)
	/* Support reporting polarity and speed via properties */
	extcon_set_property_capability(pd->extcon, EXTCON_USB,
			EXTCON_PROP_USB_TYPEC_POLARITY);
	extcon_set_property_capability(pd->extcon, EXTCON_USB,
			EXTCON_PROP_USB_PD_CONTRACT);
	extcon_set_property_capability(pd->extcon, EXTCON_USB,
			EXTCON_PROP_USB_SS);
	extcon_set_property_capability(pd->extcon, EXTCON_USB_HOST,
+6 −1
Original line number Diff line number Diff line
@@ -113,14 +113,19 @@
 * @type:       integer (intval)
 * @value:      0 (USB/USB2) or 1 (USB3)
 * @default:    0 (USB/USB2)
 * -EXTCON_PROP_USB_PD_CONTRACT
 * @type:	integer (intval)
 * @value:	0 (bus powered) or 1 (self powered)
 * @default:	0 (bus powered)
 *
 */
#define EXTCON_PROP_USB_VBUS		0
#define EXTCON_PROP_USB_TYPEC_POLARITY	1
#define EXTCON_PROP_USB_SS		2
#define EXTCON_PROP_USB_PD_CONTRACT	3

#define EXTCON_PROP_USB_MIN		0
#define EXTCON_PROP_USB_MAX		2
#define EXTCON_PROP_USB_MAX		3
#define EXTCON_PROP_USB_CNT	(EXTCON_PROP_USB_MAX - EXTCON_PROP_USB_MIN + 1)

/* Properties of EXTCON_TYPE_CHG. */
+1 −0
Original line number Diff line number Diff line
@@ -539,6 +539,7 @@ struct usb_gadget {
	u32				extra_buf_alloc;
	bool				l1_supported;
	bool				is_chipidea;
	bool				self_powered;
};
#define work_to_gadget(w)	(container_of((w), struct usb_gadget, work))