[PATCH 2/3] phy: cpcap-usb: Improve host vs docked mode detection

From: Tony Lindgren
Date: Sun Dec 22 2019 - 13:17:30 EST


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@xxxxxxxxxx>
Cc: Pavel Machek <pavel@xxxxxx>
Cc: Sebastian Reichel <sre@xxxxxxxxxx>
Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx>
---
drivers/phy/motorola/phy-cpcap-usb.c | 73 ++++++++++++++++++++++------
1 file changed, 58 insertions(+), 15 deletions(-)

diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
--- a/drivers/phy/motorola/phy-cpcap-usb.c
+++ b/drivers/phy/motorola/phy-cpcap-usb.c
@@ -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,8 +235,60 @@ static void cpcap_usb_detect(struct work_struct *work)
if (error)
return;

- if (s.id_ground) {
+ 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);
+
+ 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;
+ }
+
+ 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;
+
+ cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
+
+ /*
+ * 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;
+
error = cpcap_usb_set_usb_mode(ddata);
if (error)
goto out_err;
@@ -259,21 +313,8 @@ static void cpcap_usb_detect(struct work_struct *work)

vbus = cpcap_usb_vbus_valid(ddata);

+ /* Otherwise assume we're connected to a USB host */
if (vbus) {
- /* Are we connected to a docking station with vbus? */
- if (s.id_ground) {
- dev_dbg(ddata->dev, "connected to a dock\n");
-
- /* 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);
-
- return;
- }
-
- /* Otherwise assume we're connected to a USB host */
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 */
--
2.24.1