Skip to content

# 3.5mm headphone jack never auto-detects on KONKR Pocket FIT (SM8650) #426

Description

@JaseRuss

Hardware Device

KONKR Pocket FIT (G3 Gen 3)

OS Version

20260907.78958ee

Description

Hello as you will probably immediately be able to tell I used Claude Code to work through this issue. Apologies if you don't accept help from these tools I had a look around but couldn't see anything forbidding it. I appriciated that this will probably make you treat the below with suspicion but I promise that this is from a place of wanting to help my fellow handheld gamers

We were able to get sound out the device, and I've tested the parts I am able to so as not to waste anyones time.

3.5mm headphone jack never auto-detects on KONKR Pocket FIT (SM8650)

Summary

On the KONKR Pocket FIT (SM8650 / G3 Gen 3), inserting a 3.5mm plug is never detected,
so audio never moves to the headphones. Speakers work normally.

The analog headphone path is fully functional, and the Headphones output is
present and usable — it just has to be selected by hand, because nothing ever reports
the plug. Two independent bugs each break automatic switching:

  1. Kernel: WCD939x MBHC mechanical insertion detection fires correctly, but
    electrical plug-type detection never runs, so the jack control never reports
    present.
  2. Userspace (Armada's UCM2 profile): the Headphones device declares
    JackControl "Headset Jack", which is not a control that exists on this card, so
    the port's availability can never be evaluated at all.

Either one alone is sufficient to prevent auto-switching. Neither prevents manual
selection.

Workaround for users, no file changes needed:

pactl set-card-profile alsa_card.platform-sound "HiFi (Headphones, Speaker)"
wpctl set-default <headphones-node-id>

(wpctl set-default rather than pactl set-default-sink — only the former persists the
choice to ~/.local/state/wireplumber/default-nodes. The profile itself persists via
default-profile either way.) Once the Headphones profile is active, Speaker is also
present in it, so switching between the two outputs afterwards needs no further profile
change. You must switch manually every time; there is no auto-switch.

No Steam restart is required for this workaround — verified on a live
gamescope/gamepadui session (see "Behaviour on a Steam session" below).

Since the switch has to be made by hand every time, it is far more usable wired up as
two non-Steam library shortcuts — see "Practical stopgap" below for the script and the
shortcuts.vdf gotchas.

Affected system

Device KONKR Pocket FIT
DT compatible konkr,pocket-fit, qcom,sm8650
SoC SM8650 (Snapdragon G3 Gen 3)
ALSA card SM8650-APS2 (AYANEO Pocket S2 profile)
Machine driver snd_soc_sc8280xp
Image ghcr.io/armada-os/armada:beta
Image version 20260907.78958ee (sha256:0045126954a1…)
Kernel 7.2.3 aarch64
Fedora base 44
PipeWire 1.6.8
WirePlumber 0.5.14
alsa-lib 1.2.16.1-1.fc44

Note: the board matches the AYANEO Pocket S2 UCM profile and reports itself as
"AYANEO Controller" / "AYANEO DEVICE" in /proc/bus/input/devices. There is no KONKR
profile for sm8650, although conf.d/sm8750/SM8750-KONKR.conf exists for the 8 Elite
variant.

Symptom

  • Inserting or removing a 3.5mm plug produces no reaction of any kind: no UI change,
    no port switch, no log line, no input event.
  • Audio keeps going to the speakers.
  • Selecting the Headphones profile by hand works and produces correct stereo audio.
  • Separately, no capture devices are exposed at all (see "Additional issue").

Default card state on boot:

Active Profile: HiFi (HDMI0, Speaker)

$ pactl list sinks short
51  alsa_output.platform-sound.HiFi__HDMI0__sink    PipeWire  s16le 2ch 48000Hz  SUSPENDED
52  alsa_output.platform-sound.HiFi__Speaker__sink  PipeWire  s16le 2ch 48000Hz  SUSPENDED

Headphones conflicts with HDMI0 (both are hw:0,0, and HDMI0 declares
ConflictingDevice ["Headphones"]), so they appear as two mutually exclusive card
profiles rather than two ports of one profile. The card boots into
HiFi (HDMI0, Speaker) and, because jack detection never fires, nothing ever moves it
to HiFi (Headphones, Speaker).


Bug 1 — WCD939x MBHC: mechanical detect fires, electrical detect never runs

Evidence

The MBHC mechanical-detect interrupt works perfectly. Across four physical plug
transitions (unplug, replug, unplug, replug) the counter incremented exactly four
times, one per transition:

# before
246:  6  ...  wcd939x  4  Edge  mbhc sw intr
# after 4 transitions
246: 10  ...  wcd939x  4  Edge  mbhc sw intr

But the electrical-detection interrupts never fire at all, at any point:

$ grep -E "Elect Insert|Elect Remove|Button Press" /proc/interrupts
249:  0  ...  wcd939x  3  Edge  Elect Insert
250:  0  ...  wcd939x  2  Edge  Elect Remove
247:  0  ...  wcd939x  0  Edge  Button Press detect

Consequently the plug is never reported. With headphones physically inserted:

$ amixer -c 0 cget numid=139        # 'Headphone Jack'
  : values=off
$ amixer -c 0 cget numid=138        # 'Mic Jack'
  : values=off
$ evtest --query /dev/input/event8 EV_SW SW_HEADPHONE_INSERT ; echo $?
0                                   # 0 = not inserted

evtest on the jack input device recorded zero events across two full
unplug/replug cycles, and dmesg gained no audio-related lines. Plug type is never
determined:

HPH Type        = 0
HPHL Impedance  = 0
HPHR Impedance  = 0

What is correctly configured

This is not a missing-DT-node problem. Everything expected is present:

  • /proc/device-tree/audio-codec is qcom,wcd9395-codec / qcom,wcd9390-codec with
    full MBHC configuration:
    • qcom,mbhc-headphone-vthreshold-microvolt = 50000
    • qcom,mbhc-headset-vthreshold-microvolt = 1700000
    • qcom,mbhc-buttons-vthreshold-microvolt = <75000 150000 237000 500000 …>
    • qcom,micbias1-microvolt … qcom,micbias4-microvolt = 1800000
  • snd_soc_wcd_mbhc is loaded and referenced by snd_soc_wcd939x
  • wcd939x_usbss is loaded and bound at i2c 1-000e
  • Both WCD939x SoundWire devices bound cleanly, and the jack registered:
    [12.943194] wcd939x_codec audio-codec: bound sdw:2:0:0217:010e:00:4 …
    [12.943206] wcd939x_codec audio-codec: bound sdw:3:0:0217:010e:00:3 …
    [12.977916] input: SM8650-APS2 Headset Jack as /devices/platform/sound/sound/card0/input8
    
  • The jack input device declares the right capabilities
    (/sys/class/input/event8/device/capabilities/sw = d4 →
    SW_HEADPHONE_INSERT | SW_MICROPHONE_INSERT | SW_LINEOUT_INSERT | SW_JACK_PHYSICAL_INSERT)

There are no MBHC-related errors in dmesg at all. The only codec warning is benign:

[7.169097] wcd939x_codec audio-codec: supply vdd-px not found, using dummy regulator

Leading hypothesis (unconfirmed)

qcom,hphl-jack-type-normally-closed and qcom,ground-jack-type-normally-closed are
absent from the audio-codec node. If this board wires its jack detect switches
normally-closed, their absence would cause the driver to interpret every mechanical
interrupt as a removal rather than an insertion — never advancing to electrical
detection, and matching the observed evidence exactly (mechanical IRQs counted,
Elect Insert permanently 0).

This is a hypothesis, not a confirmed diagnosis. Someone with the board schematic or
the vendor DT should confirm the jack detect polarity before patching.


Bug 2 — UCM2 JackControl names a control that does not exist

Location

/usr/share/alsa/ucm2/Qualcomm/sm8650/APS2/HiFi.conf, line 52:

SectionDevice."Headphones" {
        ...
        Value {
                PlaybackPriority 200
                PlaybackPCM "hw:${CardId},0"
                PlaybackMixer "default:${CardId}"
                PlaybackMixerElem "HP"
                JackControl "Headset Jack"       # <-- no such kcontrol
                JackHWMute "Speaker"
        }
}

Evidence

The card exposes exactly three iface=CARD jack controls, and Headset Jack is not
among them:

$ amixer -c 0 controls | grep "iface=CARD"
numid=140,iface=CARD,name='DP0 Jack'
numid=139,iface=CARD,name='Headphone Jack'
numid=138,iface=CARD,name='Mic Jack'

Headset Jack is the name of the ASoC jack (hence the input device
SM8650-APS2 Headset Jack), but the kcontrols are named after the jack pins —
Headphone Jack and Mic Jack. JackControl requires a kcontrol name.

Every other Qualcomm UCM profile in the tree uses the correct name, including the
sibling profile for the same SoC and the one for the next SoC generation:

$ grep -rn "JackControl" /usr/share/alsa/ucm2/Qualcomm/ | grep -i "headphone\|headset"
.../sm8650/QRD/HiFi.conf:45:        JackControl "Headphone Jack"      # correct
.../sm8750/MTP/HiFi.conf:47:        JackControl "Headphone Jack"      # correct
.../sm8550/HDK/HiFi.conf:43:        JackControl "Headphone Jack"      # correct
.../sc8280xp/HiFi.conf:48:          JackControl "Headphone Jack"      # correct
.../x1e80100/HiFi.conf:52:          JackControl "Headphone Jack"      # correct
.../sm8650/APS2/HiFi.conf:52:       JackControl "Headset Jack"        # WRONG

Only sm8650/APS2 — the profile this board matches — is wrong.

Observed effect

The port's availability is never evaluated. It stays permanently unknown rather than
flipping between available and unavailable:

[Out] Headphones: Headphones playback (type: Headphones, priority: 200,
      availability group: Headset, availability unknown)

Compare HDMI0, whose JackControl "DP0 Jack" resolves correctly and therefore
reports real state:

[Out] HDMI0: DisplayPort 0 playback (type: HDMI, priority: 200,
      availability group: DP0, not available)

Verified by A/B test: replacing only this one line and restarting PipeWire changes the
port from availability group: Headset, availability unknown to plain
availability unknown, confirming the string is being looked up and silently failing.

Important scoping note: this bug does not hide the Headphones sink. The profile
and sink are present and fully usable either way — confirmed by testing the stock,
unpatched file. It only breaks availability tracking, which is one of the two reasons
auto-switching never happens. Fixing this line alone will not restore
auto-switching, because Bug 1 means the correctly-named control would read off
forever anyway. Both bugs need fixing.

Fix

--- a/ucm2/Qualcomm/sm8650/APS2/HiFi.conf
+++ b/ucm2/Qualcomm/sm8650/APS2/HiFi.conf
@@
-		JackControl "Headset Jack"
+		JackControl "Headphone Jack"

The same wrong string appears again, already commented out, at line 74 in the disabled
Headset capture section — worth correcting at the same time.

The rest of the profile is correct

The Headphones device section is otherwise complete and valid. All 17 mixer controls
referenced by its EnableSequence exist on this card (verified individually):
CLSH Switch, HPHL_RDAC Switch, HPHR_RDAC Switch, HPHL_COMP Switch,
HPHR_COMP Switch, HPHL Switch, HPHR Switch, RX HPH Mode, RX_HPH PWR Mode,
RX_MACRO RX0 MUX, RX_MACRO RX1 MUX, RX INT0_1 MIX1 INP0, RX INT1_1 MIX1 INP0,
RX INT0 DEM MUX, RX INT1 DEM MUX, RX_CODEC_DMA_RX_0 Audio Mixer MultiMedia1,
HP Volume. Selecting the profile runs the sequence correctly and produces working
stereo audio.


Proof the analog path is healthy

Selecting the Headphones profile on the stock, unmodified configuration causes
UCM to apply the EnableSequence and produces clean stereo audio in the headphones:

$ pactl set-card-profile alsa_card.platform-sound "HiFi (Headphones, Speaker)"
$ amixer -D hw:0 cget "name=HPHL Switch"      # -> on
$ amixer -D hw:0 cget "name=HPHR Switch"      # -> on
$ amixer -D hw:0 cget "name=CLSH Switch"      # -> on
$ amixer -D hw:0 cget "name=RX HPH Mode"      # -> 4  (CLS_H_LOHIFI)
$ paplay --device=alsa_output.platform-sound.HiFi__Headphones__sink tone.wav

Each channel was additionally verified in isolation, driving the codec directly:

$ speaker-test -D hw:0,0 -c 2 -t sine -f 440 -s 1   # left  -> audible, left earcup
$ speaker-test -D hw:0,0 -c 2 -t sine -f 440 -s 2   # right -> audible, right earcup

Both channels work and are correctly panned. (Note for anyone reproducing:
speaker-test -c 2 -t sine alternates channels, so a listener can easily mistake it
for a single working channel. Use -s 1 / -s 2 to isolate.)

DAPM confirmed symmetric power-up during playback:

HPHL PGA: On  in 1 out 1 - R12297(0x3009) mask 0x80
HPHR PGA: On  in 1 out 1 - R12297(0x3009) mask 0x40
HPHL_RDAC: On   HPHR_RDAC: On   RDAC1: On   RDAC2: On
IN1_HPHL: On    IN2_HPHR: On    CLS_H_PORT: On   VDD_BUCK: On

No OCP or PDM watchdog interrupts fired during playback
(HPH_L OCP detect, HPH_R OCP detect, HPHL/HPHR PDM WD INT all 0).

So the codec, class-H amplifier, rx-macro routing, SBU mux and physical jack wiring are
all fine. Only detection is broken.


Additional issue — no capture devices at all

The same UCM profile has both input sections commented out, so the device exposes no
microphone whatsoever (wpctl status shows zero sources) despite pcm2c/pcm3c
existing and MultiMedia3/4 Capture being present in aplay -l:

  • SectionDevice."Headset" (headset mic, hw:0,2, ADC2) — commented out
  • SectionDevice."Mic" (bottom mic, hw:0,3, SMIC8) — commented out

Probably worth its own issue.


Behaviour on a Steam session (tested)

All of the following was checked on a live gamescope-session-plus@steam session with
gamepadui running, confirming by ear that Steam's own UI navigation sounds followed the
output.

The workaround needs no Steam restart. Steam follows both:

  • a plain default-sink change within one profile (Headphones ↔ Speaker) — Steam UI
    audio moved to the new output immediately; and
  • a full profile change (HiFi (HDMI0, Speaker) → HiFi (Headphones, Speaker)),
    which destroys and recreates the sink nodes. Steam UI audio still followed, and all
    four PipeWire clients (Steam, Steam Voice Settings, gamescope,
    Chromium input) stayed connected throughout.

What does break Steam: restarting PipeWire or WirePlumber. This is only relevant
to anyone testing a UCM change via ALSA_CONFIG_UCM2, not to the workaround above.
After systemctl --user restart pipewire wireplumber pipewire-pulse:

  • gamescope and Chromium input disappear from the PipeWire client list and do not
    reconnect; Steam stays listed but produces no streams
  • Steam goes completely silent even though the sinks are healthy (verified working via
    paplay at the same time)
  • Steam's output-device menu shows stale ghost entries — e.g. a DisplayPort 0
    device that no longer exists in the active profile, so three "Built-in Audio" entries
    appear where there are only two sinks

Recovery requires restarting the session, which closes and reopens the Steam UI:

systemctl --user restart gamescope-session-plus@steam.service

Afterwards all four clients reconnect with fresh PIDs and audio works normally. Worth
mentioning in any docs that tell users to restart PipeWire on this platform.

Practical stopgap: expose the switch as two non-Steam shortcuts

Because switching has to be done by hand every time, and gamepadui's output-device menu
is several levels deep in the Quick Access Menu, it is much more usable as two library
entries. This is what I ended up doing on the affected device, and it works well enough
to live with until the kernel fix lands.

~/.local/bin/armada-audio-switch:

#!/bin/bash
# Switch audio output between speakers and the 3.5mm jack.
# Needed because WCD939x MBHC electrical jack detection never fires on this board,
# so PipeWire never switches outputs by itself.
set -uo pipefail

CARD="alsa_card.platform-sound"
HP_SINK="alsa_output.platform-sound.HiFi__Headphones__sink"
SPK_SINK="alsa_output.platform-sound.HiFi__Speaker__sink"
HP_PROFILE="HiFi (Headphones, Speaker)"

note() {
  printf '%s\n' "$1"
  command -v notify-send >/dev/null 2>&1 && notify-send -t 2500 "Audio output" "$1" 2>/dev/null
  return 0
}
die() { note "$1"; exit 1; }

active_profile() {
  pactl list cards 2>/dev/null | awk '/Active Profile:/{sub(/^\tActive Profile: /,""); print; exit}'
}
have_sink() { pactl list sinks short 2>/dev/null | grep -qF "$1"; }

# set-default-sink only affects NEW streams, so move the live ones too
move_streams() {
  local target="$1" id
  for id in $(pactl list sink-inputs short 2>/dev/null | cut -f1); do
    pactl move-sink-input "$id" "$target" 2>/dev/null || true
  done
}

set_default() {
  local sink="$1" id
  pactl set-default-sink "$sink" 2>/dev/null || die "failed to set default sink"
  id=$(pactl list sinks short 2>/dev/null | grep -F "$sink" | cut -f1 | head -1)
  # wpctl (not pactl) persists the choice to ~/.local/state/wireplumber/default-nodes
  [ -n "${id:-}" ] && wpctl set-default "$id" 2>/dev/null || true
  pactl set-sink-mute "$sink" 0 2>/dev/null || true
  move_streams "$sink"
}

case "${1:-}" in
  headphones|hp|jack)
      # Headphones conflicts with HDMI0, so it exists only in the Headphones profile
      if [ "$(active_profile)" != "$HP_PROFILE" ]; then
        pactl set-card-profile "$CARD" "$HP_PROFILE" || die "could not select $HP_PROFILE"
        for _ in $(seq 10); do have_sink "$HP_SINK" && break; sleep 0.3; done
      fi
      have_sink "$HP_SINK" || die "Headphones sink did not appear"
      set_default "$HP_SINK"; note "Headphones (3.5mm)" ;;
  speakers|speaker|spk)
      # Speaker is in every HiFi profile, so no profile change needed
      have_sink "$SPK_SINK" || die "Speaker sink not found"
      set_default "$SPK_SINK"; note "Built-in speakers" ;;
  *)  echo "usage: ${0##*/} headphones|speakers" >&2; exit 2 ;;
esac

Then two one-line launchers, since a Steam shortcut needs its own target per entry:

# ~/.local/share/armada-audio/Headphones.sh
#!/bin/bash
exec "$HOME/.local/bin/armada-audio-switch" headphones
# ~/.local/share/armada-audio/Speakers.sh
#!/bin/bash
exec "$HOME/.local/bin/armada-audio-switch" speakers

Add both via Desktop Mode → Steam → Add a Non-Steam Game, which is the supported
route. Two details caught me out doing it headlessly:

  • Non-Steam shortcuts live in
    ~/.local/share/Steam/userdata/<steamID3>/config/shortcuts.vdf, which is binary
    VDF
    (0x00 nested map, 0x01 string, 0x02 little-endian int32, 0x08
    terminator; root is \x00shortcuts\x00, file ends \x08\x08). Non-Steam appids
    follow crc32(Exe + AppName) | 0x80000000, read back as a signed int32.
  • Steam rewrites that file when it exits, so it must be edited with Steam stopped
    (systemctl --user stop gamescope-session-plus@steam.service) or the edit is silently
    discarded.

Two caveats on the result: the shortcut flashes as "Running" for a moment because the
script exits immediately, and a future Steam client change to the shortcuts format could
drop the entries. The underlying script is unaffected either way.

Notes for packaging the fix

These UCM files are not owned by any RPM (rpm -qf → "not owned by any package")
and alsa-ucm-conf is not installed, so they ship directly in the Armada image rather
than coming from Fedora. The UCM fix therefore belongs in the Armada repo (and ideally
upstream alsa-ucm-conf), not in a Fedora package.

Armada is Fedora bootc and / is a read-only composefs overlay:

composefs / overlay ro,relatime,lowerdir+=/run/ostree/.private/cfsroot-lower,…
/dev/sda14 /etc btrfs rw,…

so /usr/share/alsa/ucm2 cannot be edited in place on a deployed system. For local
testing, alsa-lib 1.2.16.1 honours ALSA_CONFIG_UCM2 (confirmed present in
libasound.so.2.0.0), so a patched tree in a writable location plus a systemd user
drop-in setting Environment="ALSA_CONFIG_UCM2=…" on pipewire.service,
wireplumber.service and pipewire-pulse.service works without touching /usr or
requiring bootc usr-overlay. That is only needed for testing the UCM change, though —
the user-facing workaround is just the pactl set-card-profile above.

Anyone testing that way should note the Steam caveat above: applying the drop-in means
restarting PipeWire, which silently kills Steam's audio until the gamescope session is
restarted. Restart the session as part of the test, or the UCM change will look broken
when it is not.

Steps to reproduce

plug in 3.5mm headphones

Expected behavior

plugging in headphones should swap to that output

Actual behavior

continued playing via speakers

Additional comments

No response

Confirmations

  • I have read the project's README and documentation.
  • I searched existing issues and confirm this is not a duplicate.
  • I can reproduce this issue on the latest Armada release (or I noted the exact release above).
  • I attached relevant logs, screenshots, or a minimal reproduction if applicable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Fields

    Priority

    None yet

    Projects

    • Status
      In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions