Steam Deck OLED: QCA2066 Bluetooth times out after S4 hibernation on SteamOS 3.9.1
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 52/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- linux
- Domain
- operating-systems
Research direction
Start by reproducing explicit S4 hibernation in Desktop Mode on the Steam Deck OLED and compare the hci_uart_qca/serial0-0 logs with and without the tested systemd-hibernate.service workaround. Investigate the QCA2066 controller recovery path across hibernate and verify that Bluetooth returns powered with existing paired headphones still usable. Done means a native recovery works reliably without the local unbind/bind hook.
Written by the indexing model from the issue text.
Description
System information
- Device: Steam Deck OLED / Valve Galileo
- BIOS: F7G0114
- SteamOS: 3.9.1, build 20260914.100
- Kernel: 7.2.4-valve1-1-neptune-72-g5ab4af5e2eb9 (linux-neptune-72 7.2.4.valve1-1)
- BlueZ: 5.87-2.4
- KDE PowerDevil: 6.7.3-2.1
- Configured atomupd branch: beta (the installed OS reports 3.9.1)
- Bluetooth device: QCOM2066 / QCA2066, UART driver hci_uart_qca, serdev device serial0-0
Expected behavior
After an explicit suspend-to-disk (S4 / hibernate) in Desktop Mode, the Bluetooth adapter should return to its previous powered state and existing paired headphones should remain usable.
Actual behavior
The system resumes successfully, but the Bluetooth controller repeatedly times out and cannot be powered on normally. bluetooth.service remains active and rfkill reports neither a soft nor a hard block. bluetoothctl reports Powered: no while PowerState is on. The paired headphones cannot be used.
This is hibernate, not ordinary suspend-to-RAM: logind records a hibernate request from PowerDevil, Valve's hibernate-prepare.service successfully creates its temporary swap file, and systemd-sleep reports returning from hibernate. No manual swap/GRUB/initramfs changes were made to enable hibernation. The Desktop Mode power button was configured to Hibernate.
Related report: #2201. That report was closed because its author could no longer reproduce it. This report supplies a reproducible case on 3.9.1 triggered by explicit hibernation, rather than a low-battery event.
Steps to reproduce
- Boot the OLED Deck, enter Desktop Mode, and enable Bluetooth. Use an already paired Bluetooth headset.
- Select Hibernate in KDE (or configure the Desktop Mode power button to Hibernate and press it).
- Wait for the Deck to finish hibernating, then press the power button to resume.
- Try to use the headset or enable the Bluetooth adapter. The controller is unresponsive and HCI commands time out.
Game Mode power-button behavior was not modified or tested. This report concerns explicit S4 in Desktop Mode.
Relevant logs before the workaround
These excerpts use Asia/Shanghai time (UTC+08:00), 2026-09-28:
02:03:33 systemd-logind: hibernate requested from client PID 5116 ('org_kde_powerde')
02:03:33 hibernate-swap-helper.sh: Creating swap file: 16204716 KB (15824 MB)
02:03:33 hibernate-swap-helper.sh: Hibernation configured successfully
02:03:34 systemd-sleep: Performing sleep operation 'hibernate'...
02:04:22 kernel: ACPI: PM: Waking up from system sleep state S4
02:04:24 kernel: Bluetooth: hci0: command 0x0c01 tx timeout
02:04:24 kernel: Bluetooth: hci0: Opcode 0x0c01 failed: -110
02:04:24 kernel: Bluetooth: hci0: crash the soc to collect controller dump
02:04:26 kernel: Bluetooth: hci0: Opcode 0x0c1a failed: -110
02:04:29 systemd-sleep: System returned from sleep operation 'hibernate'.
02:04:35 kernel: Bluetooth: hci0: Injecting HCI hardware error event
02:04:37 kernel: Bluetooth: hci0: clearing allocated memory due to memdump timeout
02:04:39 kernel: Bluetooth: hci0: Opcode 0x0c03 failed: -110
02:05:24 kernel: Bluetooth: hci0: Opcode 0x0c03 failed: -110
Workaround tested on this device
A local systemd-hibernate.service drop-in runs a script before and after the hibernate operation:
- Before hibernating: save the BlueZ Powered state, then unbind only serial0-0 from /sys/bus/serial/drivers/hci_uart_qca/unbind.
- After resuming: bind serial0-0 back through the same driver's bind attribute, wait for the BlueZ adapter to become available, and restore its Powered state.
- The script does not touch Wi-Fi, pairing data, or the ordinary suspend service.
One complete real hibernate/resume test with this workaround succeeded. QCA firmware setup completed, Powered returned to yes about two seconds after binding, and the original paired headphones worked without re-pairing. This is one successful cycle, not a claim of long-term reliability.
Simply unbinding/rebinding after the failure recovered the controller once, but repeating that on a healthy controller caused firmware-download/version-query timeouts and the adapter disappeared. Therefore the final workaround detaches the device before S4 and binds it after resume; it does not blindly reset a healthy controller after every wake.
The successful cycle logs were:
02:17:21 helper: saved power state: on
02:17:21 helper: detaching QCA UART controller before hibernation
02:17:21 systemd-sleep: Performing sleep operation 'hibernate'...
02:18:22 systemd-sleep: System returned from sleep operation 'hibernate'.
02:18:23 helper: binding QCA UART controller after hibernation
02:18:24 kernel: Bluetooth: hci0: QCA setup on UART is completed
02:18:25 helper: controller restored successfully: powered=true
Both systemd-hibernate.service and its pre/post actions completed successfully; temporary hibernation swap and the helper's saved state were cleaned up. The two existing paired-device records were retained. A transient Frame reassembly failed (-84) also appeared during reinitialization, followed by successful firmware setup; the earlier persistent HCI timeouts did not recur after setup in this observation window.
Investigation direction
The workaround suggests that the controller/transport state needs to be reconstructed across S4, but the kernel or firmware root cause has not been established. A native QCA2066 hibernate recovery fix would be preferable to maintaining a local unbind/bind hook, particularly because SteamOS updates can remove the local drop-in.
- Dominant language
- No language data
- Stars
- 2.6k
- Forks
- 83
- PR merge metrics
- No merged PRs in 30d
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
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 ValveSoftware/SteamOS
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
ValveSoftware/SteamOS#2856 ·
-
steam-short-session-tracker: incorrect registry backup path resets settings during automatic repairOpen
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
ValveSoftware/SteamOS#2829 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 68/100
ValveSoftware/SteamOS#1743 · 1 comment · 2 reactions ·
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
ValveSoftware/SteamOS#2855 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
ValveSoftware/SteamOS#2853 ·
All issues in ValveSoftware/SteamOS
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
compiler/runtime
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
golang/go#81836 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
ComplianceAsCode/content#15152 ·
Maintainers usually reply within 2 days
-
Area: Browsers bug report needs triage OS: Windows
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
actions/runner-images#14810 ·
Maintainers usually reply within 3 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day