Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

phy: rockchip: inno-usb2: fix disconnection in gadget mode

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>

authored by

Louis Chauvet and committed by
Vinod Koul
028e8ca7 4914d67d

+4 -2
+4 -2
drivers/phy/rockchip/phy-rockchip-inno-usb2.c
··· 821 821 container_of(work, struct rockchip_usb2phy_port, chg_work.work); 822 822 struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); 823 823 struct regmap *base = get_reg_base(rphy); 824 - bool is_dcd, tmout, vout; 824 + bool is_dcd, tmout, vout, vbus_attach; 825 825 unsigned long delay; 826 + 827 + vbus_attach = property_enabled(rphy->grf, &rport->port_cfg->utmi_bvalid); 826 828 827 829 dev_dbg(&rport->phy->dev, "chg detection work state = %d\n", 828 830 rphy->chg_state); 829 831 switch (rphy->chg_state) { 830 832 case USB_CHG_STATE_UNDEFINED: 831 - if (!rport->suspended) 833 + if (!rport->suspended && !vbus_attach) 832 834 rockchip_usb2phy_power_off(rport->phy); 833 835 /* put the controller in non-driving mode */ 834 836 property_enable(base, &rphy->phy_cfg->chg_det.opmode, false);