]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
phy: rockchip: inno-usb2: fix disconnection in gadget mode
authorLouis Chauvet <louis.chauvet@bootlin.com>
Thu, 27 Nov 2025 10:26:16 +0000 (11:26 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Jan 2026 10:21:26 +0000 (11:21 +0100)
commit 028e8ca7b20fb7324f3e5db34ba8bd366d9d3acc upstream.

When the OTG USB port is used to power the SoC, configured as peripheral
and used in gadget mode, there is a disconnection about 6 seconds after the
gadget is configured and enumerated.

The problem was observed on a Radxa Rock Pi S board, which can only be
powered by the only USB-C connector. That connector is the only one usable
in gadget mode. This implies the USB cable is connected from before boot
and never disconnects while the kernel runs.

The problem happens because of the PHY driver code flow, summarized as:

 * UDC start code (triggered via configfs at any time after boot)
   -> phy_init
       -> rockchip_usb2phy_init
           -> schedule_delayed_work(otg_sm_work [A], 6 sec)
   -> phy_power_on
       -> rockchip_usb2phy_power_on
           -> enable clock
           -> rockchip_usb2phy_reset

 * Now the gadget interface is up and running.

 * 6 seconds later otg_sm_work starts [A]
   -> rockchip_usb2phy_otg_sm_work():
       if (B_IDLE state && VBUS present && ...):
           schedule_delayed_work(&rport->chg_work [B], 0);

 * immediately the chg_detect_work starts [B]
   -> rockchip_chg_detect_work():
       if chg_state is UNDEFINED:
           if (!rport->suspended):
               rockchip_usb2phy_power_off() <--- [X]

At [X], the PHY is powered off, causing a disconnection. This quickly
triggers a new connection and following re-enumeration, but any connection
that had been established during the 6 seconds is broken.

The code already checks for !rport->suspended (which, somewhat
counter-intuitively, means the PHY is powered on), so add a guard for VBUS
as well to avoid a disconnection when a cable is connected.

Fixes: 98898f3bc83c ("phy: rockchip-inno-usb2: support otg-port for rk3399")
Cc: stable@vger.kernel.org
Closes: https://lore.kernel.org/lkml/20250414185458.7767aabc@booty/
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
Co-developed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Reviewed-by: Théo Lebrun <theo.lebrun@bootlin.com>
Link: https://patch.msgid.link/20251127-rk3308-fix-usb-gadget-phy-disconnect-v2-1-dac8a02cd2ca@bootlin.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/phy/rockchip/phy-rockchip-inno-usb2.c

index a53cc9c86b7c924e361b3a9cfc12a61798afccbf..8f4c08e599aa2284b59ef55fefe33a597f57e129 100644 (file)
@@ -821,14 +821,16 @@ static void rockchip_chg_detect_work(struct work_struct *work)
                container_of(work, struct rockchip_usb2phy_port, chg_work.work);
        struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
        struct regmap *base = get_reg_base(rphy);
-       bool is_dcd, tmout, vout;
+       bool is_dcd, tmout, vout, vbus_attach;
        unsigned long delay;
 
+       vbus_attach = property_enabled(rphy->grf, &rport->port_cfg->utmi_bvalid);
+
        dev_dbg(&rport->phy->dev, "chg detection work state = %d\n",
                rphy->chg_state);
        switch (rphy->chg_state) {
        case USB_CHG_STATE_UNDEFINED:
-               if (!rport->suspended)
+               if (!rport->suspended && !vbus_attach)
                        rockchip_usb2phy_power_off(rport->phy);
                /* put the controller in non-driving mode */
                if (!vbus_attach)