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

Commit 4e9dff7f authored by Jack Pham's avatar Jack Pham
Browse files

usb: extcon: Move to updated API



The extcon_get* APIs now acquire a spinlock, so they cannot be called
in the notifier context as that causes a recursive lock issue. Move
the calls in the dwc3-msm VBUS & ID notifiers to resume_work() so
that speed & orientation can be queried in a worker thread instead.

While at it replace the calls to extcon_get_cable_state_(), which is
now deprecated, with extcon_get_state() and extcon_set_cable_state_()
with extcon_set_state_sync(). Also, as Type-C orientation and speed
indicators can now be supported with per-cable properties, switch to
using those instead of defining custom EXTCON cable types.

Change-Id: I78a487a96cd75fdafdda3debf6bfa8382f96d04b
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent fd8f40e6
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -144,10 +144,10 @@ static void eud_event_notifier(struct work_struct *eud_work)
					eud_work);

	if (chip->int_status == EUD_INT_VBUS)
		extcon_set_cable_state_(chip->extcon, chip->extcon_id,
		extcon_set_state_sync(chip->extcon, chip->extcon_id,
					chip->usb_attach);
	else if (chip->int_status == EUD_INT_CHGR)
		extcon_set_cable_state_(chip->extcon, chip->extcon_id,
		extcon_set_state_sync(chip->extcon, chip->extcon_id,
					chip->chgr_enable);
}

+43 −63
Original line number Diff line number Diff line
@@ -2371,9 +2371,47 @@ static void dwc3_resume_work(struct work_struct *w)
{
	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, resume_work);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	union extcon_property_value val;
	unsigned int extcon_id;
	struct extcon_dev *edev = NULL;
	int ret = 0;

	dev_dbg(mdwc->dev, "%s: dwc3 resume work\n", __func__);

	if (mdwc->vbus_active) {
		edev = mdwc->extcon_vbus;
		extcon_id = EXTCON_USB;
	} else if (mdwc->id_state == DWC3_ID_GROUND) {
		edev = mdwc->extcon_id;
		extcon_id = EXTCON_USB_HOST;
	}

	/* Check speed and Type-C polarity values in order to configure PHY */
	if (edev && extcon_get_state(edev, extcon_id)) {
		ret = extcon_get_property(edev, extcon_id,
					EXTCON_PROP_USB_SS, &val);

		/* Use default dwc->maximum_speed if speed isn't reported */
		if (!ret)
			dwc->maximum_speed = (val.intval == 0) ?
					USB_SPEED_HIGH : USB_SPEED_SUPER;

		if (dwc->maximum_speed > dwc->max_hw_supp_speed)
			dwc->maximum_speed = dwc->max_hw_supp_speed;

		dbg_event(0xFF, "speed", dwc->maximum_speed);

		ret = extcon_get_property(edev, extcon_id,
				EXTCON_PROP_USB_TYPEC_POLARITY, &val);
		if (ret)
			mdwc->typec_orientation = ORIENTATION_NONE;
		else
			mdwc->typec_orientation = val.intval ?
					ORIENTATION_CC2 : ORIENTATION_CC1;

		dbg_event(0xFF, "cc_state", mdwc->typec_orientation);
	}

	/*
	 * exit LPM first to meet resume timeline from device side.
	 * resume_pending flag would prevent calling
@@ -2617,45 +2655,18 @@ static int dwc3_msm_id_notifier(struct notifier_block *nb,
{
	struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, id_nb);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	struct extcon_dev *edev = ptr;
	enum dwc3_id_state id;
	int cc_state;
	int speed;

	if (!edev) {
		dev_err(mdwc->dev, "%s: edev null\n", __func__);
		goto done;
	}

	id = event ? DWC3_ID_GROUND : DWC3_ID_FLOAT;

	dev_dbg(mdwc->dev, "host:%ld (id:%d) event received\n", event, id);

	cc_state = extcon_get_cable_state_(edev, EXTCON_USB_CC);
	if (cc_state < 0)
		mdwc->typec_orientation = ORIENTATION_NONE;
	else
		mdwc->typec_orientation =
			cc_state ? ORIENTATION_CC2 : ORIENTATION_CC1;

	dbg_event(0xFF, "cc_state", mdwc->typec_orientation);

	speed = extcon_get_cable_state_(edev, EXTCON_USB_SPEED);
	/* Use default dwc->maximum_speed if extcon doesn't report speed. */
	if (speed >= 0)
		dwc->maximum_speed =
			(speed == 0) ? USB_SPEED_HIGH : USB_SPEED_SUPER;

	if (dwc->maximum_speed > dwc->max_hw_supp_speed)
		dwc->maximum_speed = dwc->max_hw_supp_speed;

	if (mdwc->id_state != id) {
		mdwc->id_state = id;
		dbg_event(0xFF, "id_state", mdwc->id_state);
		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
	}

done:
	return NOTIFY_DONE;
}

@@ -2664,44 +2675,19 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
{
	struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, vbus_nb);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	struct extcon_dev *edev = ptr;
	int cc_state;
	int speed;

	if (!edev) {
		dev_err(mdwc->dev, "%s: edev null\n", __func__);
		goto done;
	}

	dev_dbg(mdwc->dev, "vbus:%ld event received\n", event);

	if (mdwc->vbus_active == event)
		return NOTIFY_DONE;

	cc_state = extcon_get_cable_state_(edev, EXTCON_USB_CC);
	if (cc_state < 0)
		mdwc->typec_orientation = ORIENTATION_NONE;
	else
		mdwc->typec_orientation =
			cc_state ? ORIENTATION_CC2 : ORIENTATION_CC1;

	dbg_event(0xFF, "cc_state", mdwc->typec_orientation);

	speed = extcon_get_cable_state_(edev, EXTCON_USB_SPEED);
	/* Use default dwc->maximum_speed if extcon doesn't report speed. */
	if (speed >= 0)
		dwc->maximum_speed =
			(speed == 0) ? USB_SPEED_HIGH : USB_SPEED_SUPER;

	if (dwc->maximum_speed > dwc->max_hw_supp_speed)
		dwc->maximum_speed = dwc->max_hw_supp_speed;

	mdwc->vbus_active = event;
	if (dwc->is_drd && !mdwc->in_restart)
		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
done:

	return NOTIFY_DONE;
}

/*
 * Handle EUD based soft detach/attach event, and force USB high speed mode
 * functionality on receiving soft attach event.
@@ -2717,12 +2703,6 @@ static int dwc3_msm_eud_notifier(struct notifier_block *nb,
{
	struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, eud_event_nb);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	struct extcon_dev *edev = ptr;

	if (!edev) {
		dev_err(mdwc->dev, "%s: edev null\n", __func__);
		goto done;
	}

	dbg_event(0xFF, "EUD_NB", event);
	dev_dbg(mdwc->dev, "eud:%ld event received\n", event);
@@ -2735,7 +2715,7 @@ static int dwc3_msm_eud_notifier(struct notifier_block *nb,
	mdwc->vbus_active = event;
	if (dwc->is_drd && !mdwc->in_restart)
		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
done:

	return NOTIFY_DONE;
}

@@ -3276,10 +3256,10 @@ static int dwc3_msm_probe(struct platform_device *pdev)
	}

	/* Update initial VBUS/ID state from extcon */
	if (mdwc->extcon_vbus && extcon_get_cable_state_(mdwc->extcon_vbus,
	if (mdwc->extcon_vbus && extcon_get_state(mdwc->extcon_vbus,
							EXTCON_USB))
		dwc3_msm_vbus_notifier(&mdwc->vbus_nb, true, mdwc->extcon_vbus);
	else if (mdwc->extcon_id && extcon_get_cable_state_(mdwc->extcon_id,
	else if (mdwc->extcon_id && extcon_get_state(mdwc->extcon_id,
							EXTCON_USB_HOST))
		dwc3_msm_id_notifier(&mdwc->id_nb, true, mdwc->extcon_id);
	else if (!pval.intval) {
+32 −13
Original line number Diff line number Diff line
@@ -373,8 +373,6 @@ static LIST_HEAD(_usbpd); /* useful for debugging */
static const unsigned int usbpd_extcon_cable[] = {
	EXTCON_USB,
	EXTCON_USB_HOST,
	EXTCON_USB_CC,
	EXTCON_USB_SPEED,
	EXTCON_NONE,
};

@@ -397,32 +395,43 @@ EXPORT_SYMBOL(usbpd_get_plug_orientation);

static inline void stop_usb_host(struct usbpd *pd)
{
	extcon_set_cable_state_(pd->extcon, EXTCON_USB_HOST, 0);
	extcon_set_state_sync(pd->extcon, EXTCON_USB_HOST, 0);
}

static inline void start_usb_host(struct usbpd *pd, bool ss)
{
	enum plug_orientation cc = usbpd_get_plug_orientation(pd);
	union extcon_property_value val;

	extcon_set_cable_state_(pd->extcon, EXTCON_USB_CC,
			cc == ORIENTATION_CC2);
	extcon_set_cable_state_(pd->extcon, EXTCON_USB_SPEED, ss);
	extcon_set_cable_state_(pd->extcon, EXTCON_USB_HOST, 1);
	val.intval = (cc == ORIENTATION_CC2);
	extcon_set_property(pd->extcon, EXTCON_USB_HOST,
			EXTCON_PROP_USB_TYPEC_POLARITY, val);

	val.intval = ss;
	extcon_set_property(pd->extcon, EXTCON_USB_HOST,
			EXTCON_PROP_USB_SS, val);

	extcon_set_state_sync(pd->extcon, EXTCON_USB_HOST, 1);
}

static inline void stop_usb_peripheral(struct usbpd *pd)
{
	extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0);
	extcon_set_state_sync(pd->extcon, EXTCON_USB, 0);
}

static inline void start_usb_peripheral(struct usbpd *pd)
{
	enum plug_orientation cc = usbpd_get_plug_orientation(pd);
	union extcon_property_value val;

	val.intval = (cc == ORIENTATION_CC2);
	extcon_set_property(pd->extcon, EXTCON_USB,
			EXTCON_PROP_USB_TYPEC_POLARITY, val);

	extcon_set_cable_state_(pd->extcon, EXTCON_USB_CC,
			cc == ORIENTATION_CC2);
	extcon_set_cable_state_(pd->extcon, EXTCON_USB_SPEED, 1);
	extcon_set_cable_state_(pd->extcon, EXTCON_USB, 1);
	val.intval = 1;
	extcon_set_property(pd->extcon, EXTCON_USB, EXTCON_PROP_USB_SS, val);

	extcon_set_state_sync(pd->extcon, EXTCON_USB, 1);
}

static int set_power_role(struct usbpd *pd, enum power_role pr)
@@ -1817,7 +1826,7 @@ static void usbpd_sm(struct work_struct *w)
			regulator_disable(pd->vbus);

		if (pd->current_dr != DR_DFP) {
			extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0);
			extcon_set_state_sync(pd->extcon, EXTCON_USB, 0);
			pd->current_dr = DR_DFP;
			pd_phy_update_roles(pd->current_dr, pd->current_pr);
		}
@@ -3207,6 +3216,16 @@ struct usbpd *usbpd_create(struct device *parent)
		goto put_psy;
	}

	/* 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_SS);
	extcon_set_property_capability(pd->extcon, EXTCON_USB_HOST,
			EXTCON_PROP_USB_TYPEC_POLARITY);
	extcon_set_property_capability(pd->extcon, EXTCON_USB_HOST,
			EXTCON_PROP_USB_SS);

	pd->vbus = devm_regulator_get(parent, "vbus");
	if (IS_ERR(pd->vbus)) {
		ret = PTR_ERR(pd->vbus);
+0 −6
Original line number Diff line number Diff line
@@ -65,12 +65,6 @@
#define EXTCON_JACK_SPDIF_IN	26	/* Sony Philips Digital InterFace */
#define EXTCON_JACK_SPDIF_OUT	27

/* connector orientation 0 - CC1, 1 - CC2 */
#define EXTCON_USB_CC		28

/* connector speed 0 - High Speed, 1 - super speed */
#define EXTCON_USB_SPEED	29

/* Display external connector */
#define EXTCON_DISP_HDMI	40	/* High-Definition Multimedia Interface */
#define EXTCON_DISP_MHL		41	/* Mobile High-Definition Link */