Enable the integrated camera on Intel Meteor Lake (14th Gen) laptops running Ubuntu/Debian.
This fixes the camera on devices where the sensor is connected via the Lattice USB-IO bridge (USB 2ac1:20c9) and the Intel IPU6 image processing unit — a combination that requires multiple out-of-tree drivers and the Intel Camera HAL userspace stack.
- OS: Ubuntu 24.04 LTS or Debian 12+ (other apt-based distros may work with adjustments)
- Kernel: 6.10+ recommended (IPU6 ISYS and sensor drivers are in mainline). Older kernels need additional out-of-tree modules.
- Hardware: Intel IPU6 (see Supported IPU6 Variants) with Lattice USB-IO bridge
- Packages:
build-essential,cmake,dkms,git, GStreamer dev libraries (installed automatically bysetup.sh)
| Laptop | Sensor | IPU6 PCI | USB-IO Bridge |
|---|---|---|---|
| Lenovo ThinkPad X1 Carbon Gen 12 | OmniVision OV08F40 | 8086:7d19 |
2ac1:20c9 |
| Other Meteor Lake laptops | Various | 8086:7d19 |
2ac1:20c9 |
Check if your laptop is affected:
# Should show Intel IPU6
lspci | grep -i "Multimedia"
# Should show Lattice device (2ac1:xxxx)
lsusb | grep 2ac1
# Should show OVTI08F4 or similar sensor in ACPI
grep -r . /sys/bus/acpi/devices/OVTI*/ 2>/dev/null | head -5
# Should show INT3472 deferring on GPIO chip
dmesg | grep -i "int3472"On mainline Linux kernels (6.10+), the IPU6 ISYS driver and camera sensor drivers are included, but:
-
Missing USBIO driver: The Lattice USB-IO bridge (
2ac1:20c9) provides GPIO/I2C access to the camera sensor. Without theusbiodriver, theINT3472discrete power controller cannot find the GPIO chip (INTC1007:00) and the sensor never powers on. -
Missing PSYS module: The IPU6 Processing System (PSYS) kernel module is not in mainline. The Camera HAL requires it.
-
No direct V4L2 streaming: Unlike typical USB cameras, IPU6 cameras cannot stream via V4L2 directly. They require the Intel Camera HAL (userspace image processing) and the
icamerasrcGStreamer plugin. -
App compatibility: Since the camera only works via
icamerasrc(not V4L2), a v4l2loopback virtual device is needed so that browsers and apps can access it.
┌─────────────────────────────────────────────────────────┐
│ Firefox (PipeWire camera portal) │
│ Chromium-based browsers (direct V4L2) │
├─────────────────────────────────────────────────────────┤
│ PipeWire V4L2 SPA node ←──── ipu6-pipewire-fixup │
│ (for Firefox / portal-based apps) │
├─────────────────────────────────────────────────────────┤
│ /dev/video99 — v4l2loopback (virtual V4L2 device) │
├─────────────────────────────────────────────────────────┤
│ GStreamer pipeline: icamerasrc → videoconvert → v4l2sink│
├─────────────────────────────────────────────────────────┤
│ Intel Camera HAL (libcamhal) — userspace ISP │
├─────────────────────────────────────────────────────────┤
│ IPU6 PSYS kernel module (out-of-tree) │
│ IPU6 ISYS kernel module (mainline ≥6.10) │
├─────────────────────────────────────────────────────────┤
│ Camera sensor driver (ov08x40, mainline) │
├─────────────────────────────────────────────────────────┤
│ INT3472 power controller ← GPIO from INTC1007 │
├─────────────────────────────────────────────────────────┤
│ USBIO drivers (out-of-tree) — usbio, gpio-usbio, │
│ i2c-usbio → Lattice USB bridge (2ac1:20c9) │
└─────────────────────────────────────────────────────────┘
git clone https://github.com/achrafsoltani/ipu6-camera.git
cd ipu6-camera
sudo ./setup.sh
sudo rebootAfter reboot, the camera appears as "Integrated Camera" on /dev/video99.
Test it at webcamtests.com in any browser — Firefox, Chrome, Brave, or Edge.
| Step | Description |
|---|---|
| 1 | Installs build dependencies (build-essential, cmake, dkms, GStreamer dev libs, python3-gi, etc.) |
| 2 | Clones and builds Intel USBIO drivers via DKMS |
| 3 | Clones and builds IPU6 PSYS module via DKMS (fetches kernel headers from kernel.org) |
| 4 | Installs Camera HAL binaries (firmware + proprietary ISP libraries) |
| 5 | Builds Intel Camera HAL (libcamhal) |
| 6 | Builds icamerasrc GStreamer plugin (branch: icamerasrc_slim_api) |
| 7 | Configures kernel module auto-loading and udev rules |
| 8 | Configures Firefox PipeWire camera support (media.webrtc.camera.allow-pipewire) |
| 9 | Installs systemd service (ipu6-camera-loopback) with PipeWire fixup |
| 10 | Installs system tray toggle utility (ipu6-camera-tray) with desktop autostart |
If you prefer to build each component yourself, follow these steps:
sudo apt install build-essential cmake dkms git pkg-config \
linux-headers-$(uname -r) v4l2loopback-dkms libexpat1-dev \
automake autoconf libtool libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good gstreamer1.0-tools \
gir1.2-ayatanaappindicator3-0.1 python3-gigit clone https://github.com/intel/usbio-drivers.git
cd usbio-drivers
make -C . KERNELDIR=/lib/modules/$(uname -r)/build
sudo make -C . KERNELDIR=/lib/modules/$(uname -r)/build install
sudo modprobe usbio gpio-usbio i2c-usbioVerify: dmesg | grep usbio should show the bridge binding, and dmesg | grep int3472 should no longer show "deferring".
git clone https://github.com/intel/ipu6-drivers.git
cd ipu6-drivers
# Fetch headers missing from kernel headers package (kernel ≥6.10)
KVER=$(echo $(uname -r) | grep -oP '^\d+\.\d+')
for h in ipu6.h ipu6-bus.h ipu6-buttress.h ipu6-cpd.h ipu6-dma.h \
ipu6-fw-com.h ipu6-mmu.h ipu6-platform-buttress-regs.h \
ipu6-platform-regs.h; do
curl -sfL "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/drivers/media/pci/intel/ipu6/${h}?h=v${KVER}" \
-o drivers/media/pci/intel/ipu6/${h}
done
make KERNELRELEASE=$(uname -r)
sudo make KERNELRELEASE=$(uname -r) install
sudo modprobe intel-ipu6-psysgit clone https://github.com/intel/ipu6-camera-bins.git
cd ipu6-camera-bins
sudo cp -r lib/firmware/* /lib/firmware/
sudo cp -P lib/*.so lib/*.so.* /usr/lib/
sudo cp -P lib/*.a /usr/lib/
sudo cp -r include/* /usr/include/
sudo mkdir -p /usr/lib/pkgconfig
sudo cp lib/pkgconfig/* /usr/lib/pkgconfig/
sudo ldconfiggit clone https://github.com/intel/ipu6-camera-hal.git
cd ipu6-camera-hal
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr \
-DIPU_VER=ipu6epmtl -DPRODUCTION_NAME=ipu6epmtl
make -j$(nproc)
sudo make install
sudo ldconfigReplace
ipu6epmtlwithipu6epfor Alder/Raptor Lake, oripu6for Tiger Lake.
git clone -b icamerasrc_slim_api https://github.com/intel/icamerasrc.git
cd icamerasrc
export CHROME_SLIM_CAMHAL=ON
export STRIP_VIRTUAL_CHANNEL_CAMHAL=ON
./autogen.sh
./configure --prefix=/usr
make -j$(nproc)
sudo make installsudo modprobe v4l2loopback video_nr=99 card_label="Integrated Camera" exclusive_caps=1
export GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0
sudo -E gst-launch-1.0 -e \
icamerasrc buffer-count=7 \
! video/x-raw,format=NV12,width=1280,height=720 \
! videoconvert \
! video/x-raw,format=YUY2,width=1280,height=720,framerate=30/1 \
! identity drop-allocation=true \
! v4l2sink device=/dev/video99 sync=falseThe camera should now be visible in browsers as "Integrated Camera".
| File | Description |
|---|---|
setup.sh |
Automated setup script (run with sudo) |
start-camera.sh |
Manual camera start script (run with sudo) |
ipu6-camera-loopback.service |
systemd service for automatic startup |
ipu6-pipewire-fixup |
PipeWire V4L2 node + portal permissions (runs after service starts) |
firefox-pipewire-camera.js |
Firefox autoconfig pref to enable PipeWire camera |
99-hide-ipu6-raw.rules |
udev rule to hide raw IPU6 nodes from apps |
ipu6-camera-tray |
System tray toggle utility (Python, AppIndicator) |
ipu6-camera-tray.desktop |
Desktop file for app launcher + autostart |
A system tray applet (ipu6-camera-tray) for managing the camera without the terminal. Built with Python 3 and AyatanaAppIndicator3 for native GNOME/Wayland support.
- Left-click: Toggle camera on/off (prompts for password via polkit)
- Right-click menu: Toggle, Settings, Status, Quit
- Dynamic icon:
camera-videowhen active,camera-video-symbolic(grey) when inactive - Auto-start: Starts automatically on login via
~/.config/autostart/ - Single instance: File lock prevents duplicate processes
- Polling: Icon updates every 5 seconds to reflect service state
Right-click → Settings opens a GTK dialog to:
- Resolution: Switch between 720p (1280×720) and 1080p (1920×1080). Updates the systemd service file via
pkexecand restarts the camera if active. - Auto-start: Enable or disable the camera service starting on boot (
systemctl enable/disable).
Right-click → Status shows a read-only text view with:
- Service state (active/inactive)
- Auto-start state (enabled/disabled)
- Current resolution
- PipeWire video node listing (
wpctl status) - Camera portal availability (
IsCameraPresent)
ipu6-camera-tray &| Package | Purpose |
|---|---|
gir1.2-ayatanaappindicator3-0.1 |
AppIndicator tray icon support |
python3-gi |
GTK/GLib Python bindings |
pkexec |
Graphical privilege escalation (pre-installed) |
All dependencies are installed automatically by setup.sh.
# Check modules are loaded
lsmod | grep -E 'usbio|ipu6|v4l2loopback'
# Check service status
sudo systemctl status ipu6-camera-loopback
# Check kernel logs
dmesg | grep -iE 'ipu6|int3472|ov08|usbio'
# INT3472 still deferring? USBIO modules not loaded
sudo modprobe usbio gpio-usbio i2c-usbioThe udev rule should hide raw IPU6 nodes. If they still appear:
# Reload udev rules
sudo udevadm control --reload-rules
sudo udevadm trigger
# Strip leftover ACLs (one-time, does not persist)
sudo setfacl -b /dev/video{0..47}Firefox Snap requires PipeWire for camera access (it cannot use V4L2 directly from the sandbox). The setup script configures this automatically, but if the camera still doesn't appear:
-
Check the Firefox about:config pref:
- Open
about:configin Firefox - Search for
media.webrtc.camera.allow-pipewire - Set it to
trueif it isn't already - Restart Firefox
- Open
-
Check the PipeWire V4L2 node exists:
wpctl status | grep -A5 "Video" # Should show "Integrated-Camera" under Sources
-
Check portal camera permission:
busctl --user get-property org.freedesktop.portal.Desktop \ /org/freedesktop/portal/desktop \ org.freedesktop.portal.Camera IsCameraPresent # Should return: b true -
Re-run the PipeWire fixup manually:
sudo /usr/local/bin/ipu6-pipewire-fixup
-
Restart Firefox completely (close all windows, reopen).
How it works: The ipu6-pipewire-fixup script creates a PipeWire V4L2 SPA node (via pw-cli create-node spa-node-factory) that points at /dev/video99. This node has port.physical=true and port.terminal=true, which are properties the XDG desktop portal requires to expose a camera device. The script also grants camera permission in the portal's permission store and restarts the portal daemon.
# Check detailed logs
sudo journalctl -u ipu6-camera-loopback -n 50
# Verify GStreamer can find icamerasrc
GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0 gst-inspect-1.0 icamerasrc
# Try manual pipeline
sudo GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0 gst-launch-1.0 -e \
icamerasrc buffer-count=7 ! video/x-raw,format=NV12,width=1280,height=720 ! fakesinkThe Camera HAL only supports specific resolutions. Known working:
- 1280×720 (recommended, lower CPU usage)
- 1920×1080
Other resolutions (e.g. native 3856×2416) may fail or produce corrupt output.
To switch resolution, use the tray utility (Settings dialog) or edit the service file manually:
sudo systemctl restart ipu6-camera-loopbackIf a kernel update breaks the DKMS modules:
# Rebuild both modules for the new kernel
sudo dkms autoinstall
# Or rebuild individually
sudo dkms build usbio/0.3
sudo dkms install usbio/0.3
sudo dkms build ipu6-drivers/0.0.0
sudo dkms install ipu6-drivers/0.0.0If the IPU6 PSYS build fails because of missing kernel headers, re-run setup.sh — it fetches the correct headers for the running kernel.
The tray utility requires AppIndicator support in your desktop environment:
- GNOME: Install and enable the AppIndicator extension (pre-installed on Ubuntu as
ubuntu-appindicators) - KDE/XFCE: AppIndicator support is built-in
- Verify:
gnome-extensions show ubuntu-appindicators@ubuntu.comshould showState: ACTIVE
| Platform | Generation | PCI ID | HAL variant |
|---|---|---|---|
| Tiger Lake (TGL) | 11th Gen | 8086:9a19 |
ipu6 |
| Jasper Lake (JSL) | Pentium/Celeron | 8086:4e19 |
ipu6 |
| Alder Lake (ADL) | 12th Gen | 8086:462e |
ipu6ep |
| Raptor Lake (RPL) | 13th Gen | 8086:462e |
ipu6ep |
| Meteor Lake (MTL) | 14th Gen (Core Ultra) | 8086:7d19 |
ipu6epmtl |
The setup script auto-detects the variant from the PCI ID.
Both USBIO and IPU6 PSYS modules are installed via DKMS, so they automatically rebuild when you update your kernel.
dkms status
# usbio/0.3, 6.17.0-14-generic, x86_64: installed
# ipu6-drivers/0.0.0, 6.17.0-14-generic, x86_64: installedThe GStreamer pipeline (icamerasrc → videoconvert → v4l2sink) runs continuously while the camera is active. Typical resource usage:
- 720p (1280×720): ~3-5% CPU on a Core Ultra 7 165U
- 1080p (1920×1080): ~5-8% CPU
Use the tray utility to switch resolutions without editing config files.
To fully reverse the setup:
# 1. Stop and disable the service
sudo systemctl stop ipu6-camera-loopback
sudo systemctl disable ipu6-camera-loopback
sudo rm /etc/systemd/system/ipu6-camera-loopback.service
sudo systemctl daemon-reload
# 2. Remove DKMS modules
sudo dkms remove ipu6-drivers/0.0.0 --all
sudo dkms remove usbio/0.3 --all
sudo rm -rf /usr/src/ipu6-drivers-0.0.0 /usr/src/usbio-0.3
# 3. Remove Camera HAL and icamerasrc
sudo rm -f /usr/lib/libcamhal.so*
sudo rm -f /usr/lib/gstreamer-1.0/libgsticamerasrc.so
# 4. Remove configuration
sudo rm -f /etc/modules-load.d/ipu6-camera.conf
sudo rm -f /etc/udev/rules.d/99-hide-ipu6-raw.rules
sudo rm -f /usr/local/bin/ipu6-pipewire-fixup
sudo rm -f /etc/firefox/syspref.js
sudo rm -f /usr/lib/firefox/defaults/pref/firefox-pipewire-camera.js
sudo udevadm control --reload-rules
# 5. Remove tray utility
sudo rm -f /usr/local/bin/ipu6-camera-tray
rm -f ~/.local/share/applications/ipu6-camera-tray.desktop
rm -f ~/.config/autostart/ipu6-camera-tray.desktop
# 6. Reboot
sudo rebootNote: This does not remove the Camera HAL binaries (firmware, headers, static libraries) installed to
/lib/firmware/,/usr/lib/, and/usr/include/. These are harmless to leave in place, but can be removed manually if desired.
| Laptop | CPU | Sensor | Kernel | OS | Status |
|---|---|---|---|---|---|
| Lenovo ThinkPad X1 Carbon Gen 12 | Core Ultra 7 165U | OV08F40 | 6.17.0-14-generic (HWE) | Ubuntu 24.04 LTS | Working |
If you've tested this on other hardware, please open an issue or PR to add your configuration.
- intel/usbio-drivers — Lattice USB-IO bridge drivers
- intel/ipu6-drivers — IPU6 out-of-tree drivers (PSYS, sensor drivers)
- intel/ipu6-camera-bins — Proprietary firmware and ISP libraries
- intel/ipu6-camera-hal — Camera HAL (userspace image processing)
- intel/icamerasrc — GStreamer source plugin
- Kernel ≥6.10: IPU6 ISYS and sensor drivers are in mainline. Only PSYS and USBIO need out-of-tree builds.
- Kernel <6.10: More out-of-tree modules needed (full IPU6, IVSC, etc.). The
ipu6-driversDKMS handles this automatically.
If you've tested this on additional hardware, please open an issue or PR with your laptop model, sensor, and kernel version.
MIT — Copyright (c) 2026 Achraf SOLTANI
This project orchestrates components from Intel's open-source repositories, each with their own licences (GPL-2.0 for kernel modules, Apache-2.0 for Camera HAL, proprietary for camera-bins).