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-cachyosonce
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/xdgand
~/.config). It is not overwritten bypipewire/wireplumberpackage
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.nameand the ALSA paths are untouched, so nothing that routes by name
breaks. - Because the card is stuck on the
pro-audioprofile, 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 statusorpactl 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.