Commit 9492535e authored by Tony Lindgren's avatar Tony Lindgren Committed by Kishon Vijay Abraham I
Browse files

phy: cpcap-usb: Improve host vs docked mode detection



When docked to a Motorola lapdock or media dock, we're in USB A-host mode
with VBUS provided by the dock. When in regular USB A-host mode, we're
providing the VBUS. And in regular USB A-host mode we must also keep
kicking the VBUS to keep it active.

Let's wait a bit before configuring the USB PHY to allow some time between
the ID and VBUS changes. And let's add vbus_provider flag so we can detect
docked mode and regularo USB A-host mode better.

With better USB A-host mode detection, we can now also just kick the
VBUS to keep it enabled and leave out the unnecessary line muxing.

We only need to set and clear vbus_provider in the delayed work so no
locking is needed for it currently.

Cc: Merlijn Wajer <merlijn@wizzup.org>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Sebastian Reichel <sre@kernel.org>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent 63078b6b
Loading
Loading
Loading
Loading
+58 −15
Original line number Diff line number Diff line
@@ -134,6 +134,8 @@ struct cpcap_phy_ddata {
	struct iio_channel *id;
	struct regulator *vusb;
	atomic_t active;
	unsigned int vbus_provider:1;
	unsigned int docked:1;
};

static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata)
@@ -233,11 +235,11 @@ static void cpcap_usb_detect(struct work_struct *work)
	if (error)
		return;

	if (s.id_ground) {
		dev_dbg(ddata->dev, "id ground, USB host mode\n");
		error = cpcap_usb_set_usb_mode(ddata);
		if (error)
			goto out_err;
	vbus = cpcap_usb_vbus_valid(ddata);

	/* We need to kick the VBUS as USB A-host */
	if (s.id_ground && ddata->vbus_provider) {
		dev_dbg(ddata->dev, "still in USB A-host mode, kicking VBUS\n");

		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);

@@ -251,29 +253,68 @@ static void cpcap_usb_detect(struct work_struct *work)
		return;
	}

	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
				   CPCAP_BIT_VBUSSTBY_EN |
				   CPCAP_BIT_VBUSEN_SPI, 0);
	if (vbus && s.id_ground && ddata->docked) {
		dev_dbg(ddata->dev, "still docked as A-host, signal ID down\n");

		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);

		return;
	}

	/* No VBUS needed with docks */
	if (vbus && s.id_ground && !ddata->vbus_provider) {
		dev_dbg(ddata->dev, "connected to a dock\n");

		ddata->docked = true;

		error = cpcap_usb_set_usb_mode(ddata);
		if (error)
			goto out_err;

	vbus = cpcap_usb_vbus_valid(ddata);
		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);

	if (vbus) {
		/* Are we connected to a docking station with vbus? */
		if (s.id_ground) {
			dev_dbg(ddata->dev, "connected to a dock\n");
		/*
		 * Force check state again after musb has reoriented,
		 * otherwise devices won't enumerate after loading PHY
		 * driver.
		 */
		schedule_delayed_work(&ddata->detect_work,
				      msecs_to_jiffies(1000));

		return;
	}

	if (s.id_ground && !ddata->docked) {
		dev_dbg(ddata->dev, "id ground, USB host mode\n");

		ddata->vbus_provider = true;

			/* No VBUS needed with docks */
		error = cpcap_usb_set_usb_mode(ddata);
		if (error)
			goto out_err;

		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);

		error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
					   CPCAP_BIT_VBUSSTBY_EN |
					   CPCAP_BIT_VBUSEN_SPI,
					   CPCAP_BIT_VBUSEN_SPI);
		if (error)
			goto out_err;

		return;
	}

	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
				   CPCAP_BIT_VBUSSTBY_EN |
				   CPCAP_BIT_VBUSEN_SPI, 0);
	if (error)
		goto out_err;

	vbus = cpcap_usb_vbus_valid(ddata);

	/* Otherwise assume we're connected to a USB host */
	if (vbus) {
		dev_dbg(ddata->dev, "connected to USB host\n");
		error = cpcap_usb_set_usb_mode(ddata);
		if (error)
@@ -283,6 +324,8 @@ static void cpcap_usb_detect(struct work_struct *work)
		return;
	}

	ddata->vbus_provider = false;
	ddata->docked = false;
	cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);

	/* Default to debug UART mode */