Skip to content

issue #5936

Description

@kibo1no1shirei-kan

Headphone jack non-functional on Huawei MateBook D15 (sof-essx8336 / ES8336) — jack detection dead, amp-enable GPIO not driven by mixer controls

Summary

On this Huawei MateBook D15 (Comet Lake, sof-essx8336 driver), the 3.5mm headphone jack does not produce audio under any configuration. Investigation shows two distinct, compounding driver-level bugs:

  1. Jack detection is completely non-functional — the SW_HEADPHONE_INSERT switch never fires regardless of quirk value tested, despite the ACPI DSDT declaring a valid GpioInt jack-detect line.
  2. The Headphone Switch / Speaker Switch ALSA mixer controls are disconnected from the actual amp-enable GPIO lines — toggling these controls in software has no effect on the physical GPIO state that gates the headphone/speaker amplifiers.

Headphones are confirmed fully functional under Windows on the same hardware, and USB-C audio output works correctly under Linux, isolating the fault entirely to this driver's handling of the onboard ES8336 codec's 3.5mm analog path.

Hardware

  • Model: Huawei MateBook D15 (10th Gen Intel, Comet Lake)
  • Board: HUAWEI-BOHB_WAX9-M1240-BOHB_WAX9_PCB_B2 (per alsa.long_card_name)
  • Codec: ES8336 (sof-essx8336)
  • Kernel driver: snd_soc_sof_es8336
  • Platform GPIO controller: INT34BB:00 (Intel Comet Lake PCH GPIO community), exposed as gpiochip0, 312 lines
  • Distro: CachyOS (Arch-based)

Board has multiple hardware sub-variants

The DSDT's _SUB (Subsystem ID) method under the ESSX device returns one of four IDs depending on an EC register read, meaning this single BIOS/board name actually covers multiple hardware revisions:

Method (_SUB, 0, NotSerialized)
{
    If ((^^^LPCB.EC0.MRBD == 0x38))
    {
        If (((RDCM (0xB6) & 0xF0) == 0x10))
        {
            Return ("152D125E")
        }
        Else
        {
            Return ("152D125F")
        }
    }
    ElseIf (((RDCM (0xB6) & 0xF0) == 0x10))
    {
        Return ("152D1261")
    }
    Else
    {
        Return ("152D1262")
    }
}

Any quirk table entry keyed only on a generic board/DMI string may not account for this variance.

ACPI GPIO resource declaration (DSDT, Device (ESSX))

Device (ESSX)
{
    Name (_HID, "ESSX8336")
    Name (SBUF, ResourceTemplate ()
    {
        I2cSerialBusV2 (0x0010, ...)
        I2cSerialBusV2 (0x0011, ...)
        GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
            "\\_SB.PCI0.GPI0", ...) { Pin: 0x0000 }   // resolved via PIN1
        GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
            "\\_SB.PCI0.GPI0", ...) { Pin: 0x0000 }   // resolved via PIN2
        GpioInt (Edge, ActiveHigh, ExclusiveAndWake, PullDefault, 0x0000,
            "\\_SB.PCI0.GPI0", ...) { Pin: 0x0000 }   // resolved via INT1
    })
    CreateWordField (SBUF, 0x59, PIN1)
    CreateWordField (SBUF, 0x81, PIN2)
    CreateWordField (SBUF, 0xA9, INT1)
    Method (_INI, 0, NotSerialized)
    {
        PIN1 = GNUM (0x04010010)
        PIN2 = GNUM (0x0401000F)
        INT1 = GNUM (0x04020016)
    }
}

Decoding via the board's own GNUM/GGRP helper methods (group = (Arg0 & 0x00FF0000) >> 16, pin = Arg0 & 0xFF):

Signal Raw value Group Pin Declared type
PIN1 (GPIO output) 0x04010010 1 16 Output
PIN2 (GPIO output) 0x0401000F 1 15 Output
INT1 (jack-detect IRQ) 0x04020016 2 22 GpioInt, Edge, ActiveHigh

Runtime GPIO state (/sys/kernel/debug/gpio)

The kernel has already correctly bound and named two of these lines:

gpiochip0: 312 GPIOs, parent: platform/INT34BB:00, INT34BB:00:
 gpio-35  (                    |TPDE GpioInt(0)     ) in  hi IRQ ACTIVE LOW
 gpio-47  (                    |headphone-enable    ) out hi ACTIVE LOW
 gpio-48  (                    |speakers-enable     ) out lo ACTIVE LOW
 gpio-278 (                    |ESSX GpioInt(0)     ) in  hi IRQ

Both headphone-enable and speakers-enable are ACTIVE LOW (asserted/enabled = logic lo).

Observed state on the HiFi (..., Headphones, Headset, Mic) PipeWire/ALSA profile:

  • headphone-enable: hidisabled
  • speakers-enable: loenabled

i.e. even while the "Headphones" ALSA/PipeWire profile is active and the corresponding sink is selected, the physical amp-enable GPIO for the headphone path is never asserted. The speaker amp remains enabled regardless of profile selection.

Mixer controls do not affect the GPIO state

Two raw mixer controls exist that appear intended to drive these lines:

numid=30,iface=MIXER,name='Headphone Switch'
numid=29,iface=MIXER,name='Speaker Switch'

Observed prior to any change:

numid=30 'Headphone Switch': values=on
numid=29 'Speaker Switch':   values=off

Despite Headphone Switch already reading on and Speaker Switch already reading off, the GPIO debug output still shows headphone-enable = hi (disabled) and speakers-enable = lo (enabled) — the opposite of what the mixer control names claim. Explicitly re-setting both controls to their already-reported values via amixer -c 0 cset numid=30 on / cset numid=29 off produced no change in the GPIO state.

This indicates the Headphone Switch / Speaker Switch ALSA controls are not correctly wired to the headphone-enable (gpio-47) / speakers-enable (gpio-48) lines in the current driver, or are shadowed by another control/quirk path that overrides them.

Jack detection is dead regardless of quirk value

Confirmed via evtest against /dev/input/eventN (sof-essx8336 Headset device), monitoring SW_HEADPHONE_INSERT directly:

  • Default DMI-detected quirk (0x1a0 — SSP0 + DMIC + headphone GPIO + headset mic1): jack always reads on, never toggles on physical plug/unplug.
  • 0x1a0 | SOF_ES8336_JD_INVERTED (0x40) = 0x1e0: jack always reads off, never toggles.
  • 0x1a0 | SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK (0x10) = 0x1b0: no change, never toggles.
  • 0x1a0 | 0x40 | 0x10 = 0x1f0 (both bits combined): switch initializes at state 0 but still never toggles on physical insert/removal.

sudo dmesg | grep -i quirk confirms each value is actually loaded by the module (cat /sys/module/snd_soc_sof_es8336/parameters/quirk matches the decimal equivalent of each hex value tested).

Confirmation the hardware itself is functional

  • Windows on the same physical machine: headphone jack works correctly, including automatic switching between speaker and headphone output.
  • USB-C headphones on this Linux install: work correctly (bypasses the ES8336 codec entirely, confirming the fault is isolated to this codec's driver path, not a general audio subsystem issue).

Reproduction steps

  1. Boot CachyOS on the affected D15 board.
  2. Confirm active quirk: cat /sys/module/snd_soc_sof_es8336/parameters/quirk
  3. Monitor jack-detect: sudo evtest /dev/input/eventN (device named sof-essx8336 Headset), then physically plug/unplug 3.5mm headphones. No SW_HEADPHONE_INSERT event fires at any tested quirk value.
  4. Manually switch to the Headphones profile: pactl set-card-profile alsa_card.pci-0000_00_1f.3-platform-sof-essx8336 "HiFi (HDMI1, HDMI2, HDMI3, Headphones, Headset, Mic)"
  5. Check GPIO state: sudo cat /sys/kernel/debug/gpio | grep -i -A2 -B2 "headphone\|speaker"headphone-enable remains hi (disabled).
  6. No audio is audible through the 3.5mm jack under any tested mixer/quirk/profile combination.

Requested from maintainers

  • Confirmation of the correct quirk value (or driver fix) for this board's _SUB variant(s) (152D125E / 152D125F / 152D1261 / 152D1262).
  • Investigation into why Headphone Switch (numid 30) / Speaker Switch (numid 29) do not affect the headphone-enable (gpio-47) / speakers-enable (gpio-48) GPIO lines despite apparently being intended to.
  • Investigation into why the jack-detect interrupt (ACPI GpioInt, Group 2 Pin 22 — likely corresponding to gpio-278 "ESSX GpioInt(0)" in the runtime GPIO dump) never fires a SW_HEADPHONE_INSERT event under any tested quirk combination.

Environment

  • Kernel/module: snd_soc_sof_es8336
  • Audio server: PipeWire 1.6.8 + WirePlumber
  • Distro: CachyOS

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions