Repository navigation
Patch enabling speakers, mic, camera, suspend and hibernate, and touchpad configuration for surface pro 11 intel. - #1990
AndreGilerson wants to merge 21 commits into
Conversation
|
Tested on Surface Pro for Business 11th Edition with Intel (SKU Working: Speakers, microphone detected and functional. I did not test HDMI audio outputs. Note on topology: The patch sets Might be worth noting in the PR description that the monolithic topology file isn't needed. First boot probe failure: On the very first boot, the SOF probe failed with Mixer switches default to off: After the driver loads, the RT1320 codec's output and capture switches are off. Speakers and mic show up in desktop audio settings but produce no sound until enabled: # Speaker output
amixer -c 0 cset name='rt1320-1 OT23 L Switch' on
amixer -c 0 cset name='rt1320-1 OT23 R Switch' on
# Microphone capture
amixer -c 0 cset name='rt1320-1 FU Capture Switch' on,on,on,onThese persist with |
|
@diwakar-s-maurya Thanks for the feedback, I have integrated this into the new contrib scripts in my newest commits which should auto configure the audio devices. |
|
@AndreGilerson Thanks! Would you mind opening a separate PR for the kernel changes at https://github.com/linux-surface/kernel/? (It's just a bit easier to review and I've pretty much automated generating patches from the kernel repo by now). |
|
Are there any news on this pr? Does it get merged in near future? I would love to use my integrated speakers. |
|
Is there anything we could do (without deep knowledge of the linux kernel, ...) in helping to get this pull request merged or to at least adapt the patches for a newer kernel version than 6.17? |
|
Sorry life and work happened during the last few weeks, so I was not able to focus on this anymore. But the changes are open on my branch, so maybe someone else could forward this. I am however happy to say that I am using my kernel patches on my surface 11 with nixos the whole time and it is so stable that is has become my daily driver. I am actually flirting with applying the patches to the 7.0 kernel, because I have read somewhere that the entire sleep system, for which i have patches too, works way more cleanly with that kernel version. But I will probably only get to it in 2 weeks. |
Fixed soundwire matching the wrong ids, because the amplifiers on the surface use class ids instead of uinique ids. Furthermore the added a second DAI entry to the RT1320 coder info, that enables the mic. Added endpoints to the surface machine table entry.
To use the cameras, one does need a more up to date version of libcamera than e.g. the ubuntu apt sources provide. Libcamera can be found in: https://github.com/libcamera-org/libcamera. This has been developed with commit b18132713165210d45d66d54e7ae6086a021a47e. When installed, using cam -l should show both cameras, and qcam should be able to view a video stream of both. Please note, that the image quality will be terrible, as the driver contains no optimization yet.
…es the surface immediately goes back to sleep
…1876. Map mic component name from "rt1320-1" to "rt1320-dmic" in the card components string. The old name didn't match the upstream UCM regex which only accepts -dmic/-sdca suffixes. This follows the existing convention used by rt712-dmic and rt713-dmic. Requires rt1320-dmic.conf in alsa-ucm-conf (not yet upstream). A bit hacky to change an existing patch, but should be fine atm.
Enable safe validation of contrib package installation without modifying the system. Adds --dry-run to cameras, audio, and hibernate-setup scripts. Creates new install.sh scripts (with --dry-run, --install, --remove) for suspend and touchpad packages that previously required manual file copies.
Userspace audio configs for Surface Pro 11 (Intel Lunar Lake): RT1320 DMIC UCM config, PipeWire speaker EQ, mic noise suppression, and install script with mixer switch initialization. Install script created with assitance from claude code.
…tarting logind terminates all login sessions, which kills GNOME and leaves you on a broken TTY. The logind drop-in config (LidSwitchIgnoreInhibited=no) will take effect on the next reboot instead, which is safe.
Add udev rule and libinput quirk for the Type Cover touchpad: - Group keyboard (045E:0C8E) and touchpad (045E:0C8D) into the same libinput device group to enable disable-while-typing (DWT) - Tune edge palm detection threshold as fallback to firmware palm rejection - Include install/uninstall script with dry-run support Install script created with the assistance of claude code.
Automated setup for the full IPU7 camera pipeline: builds ipu7-drivers, installs Intel firmware/libs, patches and builds the camera HAL with Surface Pro 11 sensor configs (IMX681 front, OV13858 rear), and builds the GStreamer icamerasrc plugin. Includes v4l2loopback virtual camera bridge so standard apps (Firefox, Zoom, Chrome) can use the cameras, with udev/WirePlumber rules to hide the 32 raw ISYS nodes. Extracts AIQB tuning files from Microsoft firmware for optimal image quality, with upstream fallback when firmware is unavailable. Install script created with the assistance of claude code.
|
Opened a separate PR for the kernel changes in linux-surface/kernel#164. Removed the kernel patches from this PR, just keeping the contrib packages. Furthermore I tested them on a clean ubuntu 26.04 install and applied some fixes. |
Beyond the known display-pipeline hang, two more Lunar Lake issues drove second-cycle suspend hangs: - GPE 0xAB: spurious TRP3 (00:07.3) hot-plug interrupt on a port that doesn't exist on this SKU. Firmware's _LAB handler calls undefined SLAB, flooding dmesg with AE_NOT_FOUND and causing printk contention during dpm_suspend. Mitigated by acpi_mask_gpe=0xAB plus new surface-disable-gpe-ab.service (boot-time chipset disable) and 52-gpe-ab-disable sleep hook (re-applied every resume; the disable state isn't fully persistent across s2idle). - pcie_aspm.policy=powersupersave drove the TB4 root ports into L1.2 across s2idle, wedging the xhci/NHI controllers. Switched to policy=default; pcie_aspm=force is retained so ASPM stays enabled. Also: acpi_osi -> "Windows 2022", install.sh switches to install(1) and warns if powersupersave is still on the cmdline, README updated with measured drain (~200 mW avg, ~10 day standby) replacing the prior ~351 mW estimate. README.md and install.sh script adjusted using claude code.
|
@AndreGilerson Thanks for your work again! After switching from the 6.17 kernel with your patches to the 6.18 one, sound still worked, and also the cameras showed in However the mic stopped working; I managed to get it working again as in #1876 (comment) Additionally I've tried your contrib scripts for the audio and the cameras: The audio script worked well; it now sounds better with the EQ. I did have to enable the systemd filter-chain service such that it would start automatically after rebooting. Maybe this would be worth noting in the readme. And if the denoise filter is active, the mic-icon in gnome is always shown; should it be like that? The camera script didn't work that well; it couldn't find the By replacing the name here I could get the script to continue, but somehow I then wasn't able to get v4l2loopback installed running on a non-rpm kernel; maybe I would have to compile it from source. And another issue: the script wasn't able to extract the AIQB files from the .msi, it didn't find them; maybe the .msi changed somehow? On the Microsoft website it is dated to yesterday. One issue that I've found with the lid sensor (which also works now for me, although a bit inconsistent): When suspending via power-button and then closing the lid, the surface unsuspends. Do you know if this is normal? However, thank you a lot for your effort and its already really cool to be able to use the (now well-sounding) speakers and suspend, ... working a lot better! |
|
@Timeo04 Thanks for the input! Since i only have this one device that I am using for development and testing (and even daily use, but i am using two separate SSDs for that now...) it is always difficult to discern whether an old change, or some other artifact is interacting with issue i am currently working on. As a first step because @qzed also mentioned that they are going to auto generate the patches later anyway, can you instead of using the patches from this repo, please just use my kernel with all the changes applied: https://github.com/AndreGilerson/linux-surface-kernel/tree/v6.18-surface-devel ? Can you also please check the following list of problems so that i have not missed anything? I will be opening up separate issues for all the subsystems in my forks later, because I am starting to lose track of everything. Cameras (kernel side)
Audio contrib:
Camera Contrib:
Lid / suspend:
|
|
@AndreGilerson Thank you for your response, that sounds good. I wasn't sure if it was the idea to directly compile the kernel from your kernel repository, but thank you for your hint, then I will do so the next time I compile the kernel. Your list seems right and so far complete. For the 2. point in Camera Contrib, I think the issue is it won't install from rpm fusion when having a kernel-devel installed from a kernel not installed from rpm. |
|
I got the pro 12 intel, and issues seem to be pretty much the same as with pro 11 intel: #2144 Will these patches, when merged also apply to this device? If not, I would be happy to contribute to similar patches for the pro 12! |
|
Some notes from testing this on a Surface Pro 11 for Business (Intel / Lunar Lake) with Fedora 43. Fair warning first: I'm not a kernel or camera developer, and I worked most of this out with the help of an AI assistant. So please read the below as observations from one device, not as a diagnosis. Some of it may be wrong. I'm posting it because a few of the findings would have saved me a lot of time if I had known them earlier. Kernel is your AudioSpeakers and microphone work. There is one thing that stopped the card from working at all here, at least with alsa-ucm 1.2.16. The card reports: No With no valid UCM profile, PipeWire only offers Defining After that the HiFi profile shows up and speakers and mic work normally. I don't know whether that belongs in the machine driver (setting Build notes for FedoraNone of these are bugs, but they cost time on a non-Debian distro.
If an existing distro kernel config is used as a starting point,
ipu7-camera-hal includes A symlink The RPM Fusion v4l2loopback akmod won't build against a self-built kernel: The binrpm-pkg devel package doesn't provide that. Building v4l2loopback from upstream git against Out-of-tree modules need a manual Cameras with the HAL and the bridgeThis works, with a few things I noticed. Only one camera can stream per boot. When the second bridge instance starts, it gets: and the first camera doesn't recover until a reboot. HAL init is not reliable either. I regularly get: even when the sensor probed fine and is in the media graph ( Because the bridge streams into v4l2loopback continuously from session start, the privacy LED stays on all the time and roughly 30-50% of a core is used even when nothing is reading the camera. As a user that's a bit unfortunate, since the LED no longer tells you whether the camera is actually in use. AE oscillates, which shows up as visible brightness pulsing. so it doesn't seem to be a calibration issue. Qt applications (kamoso in my case) crash reliably on the v4l2loopback devices. The Cameras through libcamera directlyOnce the kernel has the imx681 and vd55g0 drivers, libcamera's simple pipeline handler with the software ISP picks up all three sensors: Start and stop happen on demand there, and the LED matches actual use, so I ended up switching to this and disabling the bridge. A few gaps I ran into: imx681 has no sensor helper in libcamera, so AGC runs without a gain model: Adding a helper with the Sony model ov13858 has no hflip/vflip and no rotation control, The sensor is mounted upside down in this device, and as far as I understand libcamera can only compensate for that if the driver reports it. I took the ov13b10 implementation as a template (register 0x3820, mirror on bit 3, flip on bits 4+5, together with the ±1 window offset shift on 0x3811/0x3813 that keeps the Bayer order intact) and added There also seems to be a mismatch between array and lens on ov13858: the full array is larger than the illuminated circle, so the corners of the full resolution mode are black. Cropping that mode to 3840x2880 centred got rid of them. On imx681 the field of view is very wide, and a centred crop to 3496x2400 made it more usable here, though that's more a matter of taste. Both values were found by trial and error on a single device, so I wouldn't trust them too far. imx681 only has one full resolution mode, so a 1080p request gets cropped out of the full array, which is about a quarter of the area and looks like a strong zoom in video calls. A binned mode (something around 1748x1200) would presumably give applications the full field of view. ov13858 doesn't have that problem because of its binned modes, but 1080p taken from those is fairly soft, since the software ISP does no sharpening. Neither sensor has tuning files, so the IPA falls back to uncalibrated defaults: and the image looks flat. A hand-adjusted CCM works as a stopgap. One limitation that doesn't seem to be the HAL's fault: only one camera at a time works on this path as well. libcamera's simple pipeline handler appears to treat cameras that share a media device as mutually exclusive, so a second client either gets: or doesn't see any cameras at all. Overall the image quality on this path is fine for video calls but clearly below Windows, mostly because of the missing tuning and the lack of sharpening or denoise in the software ISP. One more thingThe patch directories here target 6.17/6.18 while current linux-surface kernels are at 6.19.x, which is why I ended up on the v7.0 branch for all of the above. If any of this is useful and you want more detail, exact register values, full logs, or a test of some specific change on this hardware, just say so. |
|
Some data from a Surface Pro 11 for Business (Intel, Core Ultra 7 266V) on Arch Linux, in case it's useful. I'm running a kernel built straight from the HEAD of your Speakers work. The internal speakers come up as the default sink and have been working through two months of daily use. Worth mentioning because #1852 still lists internal speakers as not working on this device, so people reading that issue may not realise it is already solved on your branch. The internal mic does not, and I think it is exactly what your v7.0 commit Card components here: versus what @Ringbaer reported on so the mic DAI link is never created on 6.18. The hardware side looks fine, both SDCA functions are discovered: but then only the amp and HDMI topologies get loaded:
That lines up with the comment in Would you consider backporting that part to One more data point on @Ringbaer's UCM finding: on alsa-ucm-conf 1.2.15.3 the card works fine, because |
|
Another Surface Pro 11 for Business (Intel, Core Ultra 7 268V), Ubuntu 26.04, I think our two data points together explain the microphone question, so here The mic works here, on stock userspaceTwo things there speak directly to posts above:
Why, and I think this is the interesting partThis machine has no machine match entry at all. That is the same behaviour So the generic path appears to give the right answer for free, provided it is What I did instead, for comparisonThe firmware declares one physical RT1320 twice — Plus one codec fix that I think is needed either way, and is not in your branch: Both are in review on linux-sound: Caveats, because one machine is one machineThis is a 268V with the November 2025 firmware, and the mic working may depend If it would help, I am happy to run anything on this device — including your |
|
@AndreGilerson — the infrared illuminator works on the Surface Pro 11 with the
|
| strobe on | strobe off | difference | |
|---|---|---|---|
| GPIO 0 | 19.74 | 19.76 | −0.02 |
| GPIO 1 | 51.93 | 40.97 | +10.96 |
| GPIO 2 | 19.51 | 19.51 | 0.00 |
| GPIO 3 | 22.53 | 24.87 | −2.34 |
Confirmed with three cycles of GPIO 1 alone, the other three held disabled:
117.95 / 115.60 / 117.71 lit against 21.51 / 22.06 / 24.43 dark — better than
five times brighter, and the room visibly lit in the difference image.
Worth knowing if you try this yourself: the strobe fires only inside the
exposure window, so at the minimum exposure of 4 lines it is 48 µs out of 21 ms
and invisible both to a phone camera and to a brightness measurement. An earlier
sweep of all four GPIOs at minimum exposure found nothing and looked like a
negative result. Use a realistic exposure.
Windows, for reference, writes strobe mode to all four GPIOs in one burst
(0x0467 <- 02 02 02 02) — it does not need to know which pin it is. That works,
but it is one machine's wiring rather than generic behaviour.
The patch
Verified after a reboot: the driver logs GPIO 1 drives the IR illuminator, and
led_mode now does what it says —
led_mode=0 -> 0x0467..0x046a = 01 01 01 01
led_mode=1 -> 0x0467..0x046a = 01 02 01 01
led_mode=0 -> 0x0467..0x046a = 01 01 01 01
--- a/drivers/media/i2c/vd55g0.c
+++ b/drivers/media/i2c/vd55g0.c
@@ -12,6 +12,7 @@
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dmi.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
@@ -170,6 +171,42 @@
* INT3472 on Surface Pro 11 registers: GPIO type 0x0B → "avdd",
* type 0x10 → "dovdd". Only 2 supplies provided via INT3472.
*/
+/*
+ * Which of the sensor's four GPIOs drives the infrared illuminator is described
+ * by the "st,leds" device-tree property. ACPI platforms have no equivalent and
+ * say nothing about the pin, so the mapping has to come from a DMI match.
+ *
+ * strobe_gpio overrides the table, and is how an unlisted machine's pin gets
+ * found: load with each value in turn and watch the bezel through a phone
+ * camera, which sees near infrared. Use a realistic exposure - the strobe fires
+ * only inside the exposure window, so at the minimum 4 lines it is 48 us in 21
+ * ms and invisible.
+ */
+static int strobe_gpio = -1;
+module_param(strobe_gpio, int, 0644);
+MODULE_PARM_DESC(strobe_gpio, "sensor GPIO driving the IR illuminator (0-3, -1 = use DMI table)");
+
+struct vd55g0_dmi_data {
+ unsigned int led_gpio;
+};
+
+static const struct vd55g0_dmi_data vd55g0_surface_pro_11 = {
+ .led_gpio = 1,
+};
+
+static const struct dmi_system_id vd55g0_dmi_ids[] = {
+ {
+ /* Microsoft Surface Pro 11 for Business (Intel) */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_SKU,
+ "Surface_Pro_11th_Edition_With_Intel_For_Business_2103"),
+ },
+ .driver_data = (void *)&vd55g0_surface_pro_11,
+ },
+ { }
+};
+
static const char * const vd55g0_supply_name[] = {
"avdd",
"dovdd",
@@ -2013,10 +2050,27 @@
return ret;
}
} else {
- /* ACPI: initialize GPIO arrays to disabled defaults */
+ const struct dmi_system_id *id;
+ int gpio = strobe_gpio;
+
+ /* ACPI: no st,* properties exist; start from all disabled */
memset(sensor->gpios.leds, ~0, sizeof(sensor->gpios.leds));
memset(sensor->gpios.out_sync, ~0, sizeof(sensor->gpios.out_sync));
sensor->gpios.in_sync = ~0;
+
+ /*
+ * ACPI does not describe which GPIO drives the infrared
+ * illuminator, so it has to come from a DMI match or from the
+ * module parameter.
+ */
+ id = dmi_first_match(vd55g0_dmi_ids);
+ if (gpio < 0 && id)
+ gpio = ((const struct vd55g0_dmi_data *)id->driver_data)->led_gpio;
+
+ if (gpio >= 0 && gpio < VD55G0_NB_GPIOS) {
+ sensor->gpios.leds[0] = gpio;
+ dev_info(dev, "GPIO %d drives the IR illuminator\n", gpio);
+ }
}
ret = vd55g0_tx_from_ep(sensor, handle);The module parameter is there so an unlisted machine can find its own pin the
same way: load with each value in turn and watch through a phone camera.
Happy to test anything on this unit — Surface Pro for Business 11th Edition with
Intel, Core Ultra 7 268V, Ubuntu 26.04.
|
Written up the parts of the SP11 Intel cameras this PR does not cover, as a It leads by pointing here for the colour cameras — the HAL patch with What is in there instead:
One open question in there I cannot answer and would value your view on: our |
|
@AndreGilerson — I've just emailed you at the address in the driver's It asks two things about your
No need to answer here, and no rush at all — I'm only flagging it in case a cold mail from Proton to Gmail lands in spam. |
|
Surface Pro 11 268v, SKU Until today I only had sound with a self-built kernel from AndreGilerson's In my DSDT the amp really is there twice, the two entries differ only in the So instead of building a whole kernel I just rebuilt soundwire-intel.ko for the One correction to what I posted back in August: the Mics "1" workaround in Two things still show up in dmesg and I have no idea whether they matter: Audio works anyway. Thanks for ur hard work and for taking this upstream - this thread and #2260 look |
|
Thank you for testing it, and for writing it up. The module you built is the same fix as ours: "soundwire: dmi-quirks: drop Your result also confirms, on stock 7.2.8, that the quirk alone is enough: On the three messages: on Ubuntu's 7.0.0-34 here, with the quirk and the |
|
I redid it on two clean boots this time, without touching pipeWire, marking the No bus clashes and no MAX_RETRY at any point, so please disregard that part of my |
|
Thank you for re-running it, and so carefully. Then the two machines agree: One thing to keep in mind until the fix reaches Fedora's kernel: the module in |
@eidos-case I've tested your patch on Fedora with a 7.2.8 upstream kernel and for me sound and the mic work using your patch. |
Fixed soundwire matching the wrong ids, because the amplifiers on the surface use class ids instead of uinique ids. Furthermore the added a second DAI entry to the RT1320 coder info, that enables the mic. Added endpoints to the surface machine table entry.
Tested on ubuntu 25.10 with 6.17. Further testing required for other kernels.
The quality of the Mic is at the moment a bit low, some optimization is required.