DWC2 Driver: Unable to power cycle vbus regulator enabled USB port more than once.
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 45/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Quiet
- Tech stack
- c, linux
- Domain
- embedded-iot, operating-systems
Research direction
Start by tracing the DWC2 entry points named in the report: _dwc2_hcd_resume, dwc2_core_host_init, and dwc2_vbus_supply_init, alongside ClearPortFeature(PORT_POWER). Reproduce with uhubctl on the CM5 and compare behavior with root-hub autosuspend disabled. Done means repeated off/on cycles reliably disable the regulator and its usage count does not remain above zero.
Written by the indexing model from the issue text.
Description
Describe the bug
I have a CM5 where I need to switch off USB 5v VBUS to the USB2 (OTG) USB Port, this is implemented on our PCB.
While implementing my voltage regulator driver I noticed that I can only power cycle the USB port once, further power cycle requests (i.e. via uhubctl) fail to disable the regulator. And the regulator usage count stays >0.
I've asked claude for possible reasons, this is what it responded with:
● Found the definitive mechanism. dwc2_core_host_init only re-asserts HPRT0_PWR if it was cleared — and it's called from dwc2_hcd_reinit during _dwc2_hcd_resume. Now let me confirm the call
chain and the final write at line 4548:
The root cause is now fully identified:
_dwc2_hcd_resume is registered as the bus_resume hook (line 5052-5053). When the USB bus resumes from a suspended state (lx_state == DWC2_L2), it does three things that fight
ClearPortFeature(PORT_POWER):
1. Line 4508: dwc2_hcd_reinit → dwc2_core_host_init (line 2262-2270): if op_state == OTG_STATE_A_HOST (which is always set for dr_mode = "host") and HPRT0_PWR is currently 0 — it writes it
back to 1.
2. Line 4538: dwc2_vbus_supply_init — unconditional regulator_enable, incrementing use_count.
3. Line 4548: explicitly writes HPRT0_PWR | HPRT0_CONNDET | HPRT0_ENACHG to HPRT0 — forcing HPRT0_PWR = 1 regardless.
The trigger sequence:
1. ClearPortFeature(PORT_POWER) clears HPRT0_PWR = 0, calls dwc2_vbus_supply_exit
2. If the bus was in lx_state = DWC2_L2 (auto-suspended), OR the device disconnect event causes the USB core to call bus_resume to process the port status change...
3. _dwc2_hcd_resume runs: lx_state == L2 check passes, CONNSTS == 0 check passes (device just disconnected), falls through to the full resume path
4. HPRT0_PWR is re-written to 1, use_count is incremented again
Why the bus is in L2: USB autosuspend. When the connected device goes idle (default: 2 seconds), the USB stack auto-suspends it, then auto-suspends the root hub, calling bus_suspend →
_dwc2_hcd_suspend → sets lx_state = L2.
---
Fix: disable root hub autosuspend
echo -1 > /sys/bus/usb/devices/usb1/power/autosuspend_delay
With autosuspend disabled, _dwc2_hcd_suspend (bus_suspend) is never called, lx_state stays at DWC2_L0, and _dwc2_hcd_resume exits immediately at line 4455:
if (hsotg->lx_state != DWC2_L2)
goto unlock; // ← exits here, no HPRT0_PWR re-assertion
To make this permanent, add a udev rule:
# /etc/udev/rules.d/99-usb-no-autosuspend.rules
ACTION=="add", SUBSYSTEM=="usb", DRIVER=="usb", ATTR{idVendor}=="0000", \
ATTR{power/autosuspend_delay}="-1"
Or target the root hub specifically:
ACTION=="add", SUBSYSTEM=="usb", KERNELS=="usb1", ATTR{power/autosuspend_delay}="-1"
The deeper issue: DWC2's bus_resume is designed to unconditionally restore port power (it has no awareness that ClearPortFeature(PORT_POWER) was intentional). ClearPortFeature(PORT_POWER)
and bus autosuspend/resume are fighting each other. Disabling autosuspend removes bus_suspend/resume from the equation entirely, leaving use_count managed only by _dwc2_hcd_start (initial
enable) and ClearPortFeature/SetPortFeature (user's uhubctl calls).
Disabling autosuspend does indeed work around the issue.
Steps to reproduce the behaviour
Couple a regulator to the USB port via a dtoverlay (untested example!):
/dts-v1/;
/plugin/;
/{
compatible = "brcm,bcm2708";
fragment@0 {
target-path = "/";
__overlay__ {
usb_power_regulator: fixedregulator@0 {
compatible = "regulator-fixed";
regulator-name = "fixed-supply";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&gpios 14 0>;
enable-active-high;
};
};
};
fragment@1 {
target = <&usb>;
dwc2_usb: __overlay__ {
power-domains = <0 0>;
compatible = "brcm,bcm2835-usb";
dr_mode = "host";
g-np-tx-fifo-size = <32>;
g-rx-fifo-size = <558>;
g-tx-fifo-size = <512 512 512 512 512 256 256>;
status = "okay";
vbus-supply = <&usb_power_regulator>;
};
};
};
And use uhubctrl to disable the USB port (CM5):
uhubctl -l 5 -p 1 -a off
verify the regulator switched to disabled via sysfs then re-enable it:
uhubctl -l 5 -p 1 -a on
Observe the regulator is back on, then repeat and observe the regulator doesn't get disabled anymore
Device (s)
Raspberry Pi CM5
System
CM5, custom receiver PCB, Custom Yocto based OS, RPI-Linux 6.12.75
Logs
No response
Additional context
If this is by design, feel free to close, the work-around also works for me.
- Dominant language
- C
- Stars
- 13.2k
- Forks
- 5.5k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 21
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from raspberrypi/linux
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
raspberrypi/linux#7415 · 2 comments · 1 reaction ·
-
rp1-cfe doesn't forward V4L2_EVENT_SOURCE_CHANGE event from csi-2 sensor driver to userspace app Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
raspberrypi/linux#7399 · 1 comment ·
-
Difficulty 1/5 Under an hour Newbie friendliness 82/100
raspberrypi/linux#7357 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
raspberrypi/linux#7054 · 2 comments ·
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
raspberrypi/linux#7634 · 8 comments · 1 reaction ·
All issues in raspberrypi/linux
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
zephyrproject-rtos/zephyr#119726 ·
-
[Bounty proposal] fix(web): memory insights count an evening memory on the next day ($25 proposed) Open
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
BasedHardware/omi#15320 ·
-
[adam] AdamNet network read doesn't cap to MAX_ADAM_PACKET_LEN, overflows client receive buffers Open
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
FujiNetWIFI/fujinet-firmware#1649 · 2 comments ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
HarbourMasters/Shipwright#7229 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
riscv-software-src/riscv-isa-sim#2435 · 1 comment ·