Chuwi UniBook Linux Audio fix for es9356

I just got the UniBook ($599) from CHUWI. It’s intel’s Wildcat Lake – a Core 3 304 which has 1 singular P core and 4 Low-Power e-cores. 8gb ram and 256gb ssd.

Why!? Linux! Obviously. This thing is so bleeding edge the sound is a bit iffy. So here’s my notes on the fix. I’m working on a DKMS backport for older kernels, but for now, you need the 7.2-rc package if you’re on arch AND this additional configuration.

More details soon ™ and full review soon ™. If you have any questions or wonder anything about this laptop – chime in below.

Fix: No audio on Intel Wildcat Lake (PTL) laptop ES9356 SoundWire codec

Symptom

Built-in speakers + mic not enumerated (aplay -l / arecord -l empty or
HDMI-only). dmesg shows:
part id 0x9356 is not supported
using HDA machine driver skl_hda_dsp_generic now

Cause

The ES9356 SDCA SoundWire codec driver (snd-soc-es9356) landed in mainline
kernel v7.2-rc. Kernels older than that have no machine driver for the codec.

Fix install a kernel >= v7.2-rc (CachyOS is what I used but should work with any Arch-based distro)

sudo pacman -S linux-cachyos-rc linux-cachyos-rc-headers
# 7.2.rc5-1 from the cachyos-v3 repo. Pacman hooks auto-build the
# initramfs and regenerate /boot/limine.conf  do NOT hand-edit the ESP.

sudo systemctl reboot
# default_entry:2 = linux-cachyos-rc (default overrides remember-last in Limine)

There are maybe some bios settings relevant here – intel non-UAA mode is the Chuwi default and that’s what worked for me.

The main problem is that the “default” devices are not “wired” internally. Device 2 is speakers, device 4 is the mic (that works). Thanks es9356! Ulgh.

Verify

uname -r                                   # -> 7.2.0-rc5-1-cachyos-rc
aplay -l                                   # -> Speaker (device 2) present
arecord -l                                 # -> Microphone (device 4) present

Optional: boost mic gain (defaults are near-zero → near-silent mic)

sudo amixer -c 0 cset numid=10 3           # es9356 FU11 Capture Volume -> max
sudo amixer -c 0 cset numid=5 10           # es9356 FU33 Capture Volume -> max

Expose to userspace (pro-audio profile)

pactl set-card-profile <card> pro-audio
# -> "sof-soundwire pro 2" = speaker, "sof-soundwire pro 4" = mic

Functional tests

speaker-test -D plughw:0,2 -c 2 -t wav -l 1
pw-record --target "alsa_input.pci-0000_00_1f.3-platform-sof_sdw.pro-input-4" \
          --rate 44100 /tmp/test.wav

Notes

  • No firmware/topology update needed: sof-firmware >= 2025.12 ships the SDCA
    topologies (sof-sdca-jack-id0.tplg, sof-sdca-1amp-id2.tplg, sof-sdca-mic-id4.tplg).
  • The RC kernel is a release candidate; switch to stable linux-cachyos once
    CachyOS ships >= 7.2.

Friendly device labels in KDE (plasma-pa / system tray)

Problem. The sof-soundwire card exposes only the pro-audio profile (all
HDMI profiles report available: no), so PipeWire creates one raw pro-audio
node per PCM. KDE/plasma-pa shows those raw names – sof-soundwire Pro 2,
Pro 4, etc. – instead of friendly device names.

Fix. A WirePlumber monitor.alsa.rules fragment that sets
node.nick/node.description per node, matching on node.name (regex) +
device.profile.name. This is purely a userspace display-label change: no
kernel/DKMS/ESP changes, no reboot.

Create /etc/wireplumber/wireplumber.conf.d/10-es9356-labels.conf
(system-wide, applies to all users, survives restarts and reboots):

# WirePlumber ALSA node relabeling for CHUWI UniBook (sof-soundwire / ES9356)
#
# The sof-soundwire card exposes only the pro-audio profile, so PipeWire creates
# separate pro-audio nodes with raw names like "sof-soundwire Pro 2". This file
# gives each node a friendly, human-readable node.nick / node.description so that
# KDE (plasma-pa / system tray / audio settings) shows e.g. "Speakers",
# "Built-in Microphone", "Headphones" instead of "sof-soundwire Pro 2".
#
# Mechanism: monitor.alsa.rules (JSON array) in a wireplumber.conf.d fragment.
# Applied by the ALSA monitor (scripts/monitors/alsa.lua) at node creation via
# JsonUtils.match_rules_update_properties(). Array sections MERGE across fragment
# files, so this coexists with the packaged alsa-vm.conf.
#
# Match keys: node.name (exact, incl. dedup suffix) + device.profile.name
# (available at match time). Only display properties are changed - node.name and
# the working ALSA paths are untouched, so pw-play/pw-record targets stay valid.
#
# Hardware mapping (UCM es9356*.conf):
#   pro-output-0  = Headphones (Jack Out)
#   pro-output-2  = Speaker
#   pro-output-5  = HDMI 1
#   pro-output-6  = HDMI 2
#   pro-output-7  = HDMI 3
#   pro-output-31 = Deepbuffer Jack Out (duplicate of Jack Out)
#   pro-input-1   = Headset Mic (Jack In)
#   pro-input-4   = Built-in Mic (DMIC)

monitor.alsa.rules = [
  {
    matches = [
      {
        node.name = "~alsa_output.pci-0000_00_1f.3-platform-sof_sdw.pro-output-0.*"
        device.profile.name = "pro-output-0"
      }
    ]
    actions = {
      update-props = {
        node.nick        = "Headphones"
        node.description = "Headphones (Jack Out)"
      }
    }
  },
  {
    matches = [
      {
        node.name = "~alsa_output.pci-0000_00_1f.3-platform-sof_sdw.pro-output-2.*"
        device.profile.name = "pro-output-2"
      }
    ]
    actions = {
      update-props = {
        node.nick        = "Speakers"
        node.description = "Speakers"
      }
    }
  },
  {
    matches = [
      {
        node.name = "~alsa_output.pci-0000_00_1f.3-platform-sof_sdw.pro-output-5.*"
        device.profile.name = "pro-output-5"
      }
    ]
    actions = {
      update-props = {
        node.nick        = "HDMI 1"
        node.description = "HDMI 1"
      }
    }
  },
  {
    matches = [
      {
        node.name = "~alsa_output.pci-0000_00_1f.3-platform-sof_sdw.pro-output-6.*"
        device.profile.name = "pro-output-6"
      }
    ]
    actions = {
      update-props = {
        node.nick        = "HDMI 2"
        node.description = "HDMI 2"
      }
    }
  },
  {
    matches = [
      {
        node.name = "~alsa_output.pci-0000_00_1f.3-platform-sof_sdw.pro-output-7.*"
        device.profile.name = "pro-output-7"
      }
    ]
    actions = {
      update-props = {
        node.nick        = "HDMI 3"
        node.description = "HDMI 3"
      }
    }
  },
  {
    matches = [
      {
        node.name = "~alsa_output.pci-0000_00_1f.3-platform-sof_sdw.pro-output-31.*"
        device.profile.name = "pro-output-31"
      }
    ]
    actions = {
      update-props = {
        node.nick        = "Headphones (Deepbuffer)"
        node.description = "Headphones (Deepbuffer)"
      }
    }
  },
  {
    matches = [
      {
        node.name = "~alsa_input.pci-0000_00_1f.3-platform-sof_sdw.pro-input-1.*"
        device.profile.name = "pro-input-1"
      }
    ]
    actions = {
      update-props = {
        node.nick        = "Headset Microphone"
        node.description = "Headset Microphone (Jack In)"
      }
    }
  },
  {
    matches = [
      {
        node.name = "~alsa_input.pci-0000_00_1f.3-platform-sof_sdw.pro-input-4.*"
        device.profile.name = "pro-input-4"
      }
    ]
    actions = {
      update-props = {
        node.nick        = "Built-in Microphone"
        node.description = "Built-in Microphone"
      }
    }
  }
]

Apply (briefly cuts audio for ~2s while WirePlumber restarts):

systemctl --user restart wireplumber

Before → after (the node.name values are unchanged, so pw-play /
pw-record targets and the default sink/source keep routing correctly):

PipeWire node Before (description / nick) After (description / nick)
pro-output-2 sof-soundwire Pro 2 / Pro 2 Speakers / Speakers (default sink)
pro-output-0 sof-soundwire Pro / Pro Headphones (Jack Out) / Headphones
pro-output-31 sof-soundwire Pro 31 / Pro 31 Headphones (Deepbuffer)
pro-output-5 sof-soundwire Pro 5 / HDMI 1 HDMI 1
pro-output-6 sof-soundwire Pro 6 / HDMI 2 HDMI 2
pro-output-7 sof-soundwire Pro 7 / HDMI 3 HDMI 3
pro-input-4 sof-soundwire Pro 4 / Pro 4 Built-in Microphone (default source)
pro-input-1 sof-soundwire Pro 1 / Pro 1 Headset Microphone (Jack In) / Headset Microphone

Notes / caveats

  • The fragment lives in /etc/wireplumber/wireplumber.conf.d/ the
    compile-time sysconfdir that is always searched (before /etc/xdg and
    ~/.config). It is not overwritten by pipewire/wireplumber package
    updates, and it re-applies on every WirePlumber start, so it survives
    restarts and reboots.
  • Only display properties (node.nick / node.description) are changed;
    node.name and the ALSA paths are untouched, so nothing that routes by name
    breaks.
  • Because the card is stuck on the pro-audio profile, KDE still lists each
    node as a separate device (no Output/Input grouping) that is inherent
    to pro-audio, not a regression from this config.
  • Verify with wpctl status or pactl list sinks sources. If the system tray
    caches labels, restart the tray widget or re-log in.

Backports?

The LTS kernel (6.18.40) does not have the FUNC_NUM_* function-number macros or SDCA_SINGLE_Q78_TLV that the es9356 driver depends on. These are 7.x-era additions to the SDCA headers. So the es9356 driver cannot compile against LTS headers without backporting the SDCA header macros too

I can do a working dkms for 7.x kernels. How about that?

Even then, the LTS sdw-utils has a different struct layout and no runtime machine-selection path… that’s not good. TODO more later.

1 Like

The available Linux support is better than I expected (with some tweaking).
Looking forward to the review and battery life on Linux.

Can you please provide a lstopo output?

lstopo --whole-io --no-collapse -p

I’m kinda interested how they allocated the limited pcie lanes and if anything in general stands out.
Probably not as it’s a relative small/simple chip.

 lspci -tv
-[0000:00]-+-00.0  Intel Corporation Device fd03
           +-02.0  Intel Corporation Wildcat Lake [Intel Graphics]
           +-04.0  Intel Corporation Device fd1d
           +-06.0-[01]----00.0  Realtek Semiconductor Co., Ltd. RTL8852BE PCIe 802.11ax Wireless Network Controller
           +-06.1-[02]----00.0  Realtek Semiconductor Co., Ltd. RTL8111/8168/8211/8411 PCI Express Gigabit Ethernet Controller
           +-0a.0  Intel Corporation Device fd7d
           +-0b.0  Intel Corporation Device fd3e
           +-0d.0  Intel Corporation Device 4d31
           +-12.0  Intel Corporation Device 4d45
           +-14.0  Intel Corporation Device 4d7d
           +-14.2  Intel Corporation Device 4d7f
           +-16.0  Intel Corporation Device 4d70
           +-18.0  Intel Corporation Device 4d5d
           +-19.0  Intel Corporation Device 4d50
           +-1c.0-[03]----00.0  MAXIO Technology (Hangzhou) Ltd. NVMe SSD Controller MAP1202 (DRAM-less)
           +-1f.0  Intel Corporation Device 4d01
           +-1f.3  Intel Corporation Device 4d28
           +-1f.4  Intel Corporation Device 4d22
           \-1f.5  Intel Corporation Device 4d23

lstopo --whole-io --no-collapse -p
Machine (7525MB total)
  Package P#0
    NUMANode P#0 (7525MB)
    L3 P#0 (6144KB) + L2 P#1 (3072KB) + L1d P#4 (48KB) + L1i P#4 (64KB) + Core P#4 + PU P#0
    L2 P#8 (4096KB)
      L1d P#64 (32KB) + L1i P#64 (64KB) + Core P#32 + PU P#1
      L1d P#66 (32KB) + L1i P#66 (64KB) + Core P#33 + PU P#2
      L1d P#68 (32KB) + L1i P#68 (64KB) + Core P#34 + PU P#3
      L1d P#70 (32KB) + L1i P#70 (64KB) + Core P#35 + PU P#4
  HostBridge
    PCI 00:00.0 (HostBridge)
    PCI 00:02.0 (VGA)
      GPU "renderD128"
      GPU "card0"
    PCI 00:04.0 (SignalProcessing)
    PCIBridge
      PCI 01:00.0 (Network)
        Net "wlan0"
    PCIBridge
      PCI 02:00.0 (Ethernet)
        Net "enp2s0"
    PCI 00:0a.0 (SignalProcessing)
    PCI 00:0b.0 (ProcessingAccelerator)
    PCI 00:0d.0 (USB)
    PCI 00:12.0 (Serial)
    PCI 00:14.0 (USB)
    PCI 00:14.2 (RAM)
    PCI 00:16.0 (Communication)
    PCI 00:18.0 (Communication)
    PCI 00:19.0 (SerialBus)
    PCIBridge
      PCI 03:00.0 (NVMExp)
        Block(Disk) "nvme0n1"
    PCI 00:1f.0 (ISABridge)
    PCI 00:1f.3 (MultimediaAudio)
    PCI 00:1f.4 (SMBus)
    PCI 00:1f.5 (SerialBus)


1 Like

@wendell Thanks a bunch.

As expected nothing new Intel had not already published prior.
The more noticeable parts is the Chuwi addition.

It’s apparently easier and/or maybe cheaper to use a dedicated Realtek wifi and gbe ethernet controller than to use the in chip repackaged solution and just adding some supporting components.

I figure this cpu will also make some killer SBC devices.

YES. The 1t performance just totally destroys everything because its one real P core. And the bom cost is cheap.

2 Likes

so im curious about something. i thought intel used a standardized codec so it didnt need a new driver. what changed here?