Fairphone 6 wide camera experimental Linux support enables QR scanning via OV13B10 sensor

Fairphone 6 wide camera experimental Linux support enables QR scanning via OV13B10 sensor

Overview

The Fairphone 6 ultra‑wide camera (OV13B10) now produces usable images under mainline Linux, enabling QR scanning and a basic preview in GNOME Snapshot.

Background

The Fairphone 6 uses a Qualcomm SM7635 (milos) SoC. Its three cameras are a rear Sony IMX896, a front Samsung S5KKD1, and an ultra‑wide OmniVision OV13B10. Only the OV13B10 has a mainline Linux sensor driver, which originally targeted x86/ACPI laptops. The capture path on Qualcomm SoCs follows the chain: image sensor → CSI‑2 D‑PHY → CSIPHY → CSID → ISP (VFE/TFE) → memory, with supporting blocks such as the camera clock controller (camcc), CCI I2C controller, power rails, and a VCM for autofocus. Mainline Linux provides the qcom‑camss driver for the ISP, CSID, and CSIPHY blocks, while libcamera handles userspace integration and image processing.

Capturing the OV13B10 sensor

The bring‑up began by porting the existing qcom‑camss TFE530 driver to the TFE665 block present on milos. Because the register layouts are identical, the driver logic was reused; only the base offsets differed (the ISP control block moved from 0xa00 to 0x1800). The CSID665 block reused the gen‑2 CSID operations, and the CSIPHY v2.2.1 block required a new lane‑configuration table and D‑PHY tuning values taken from downstream headers. In camss.c the capture complex was described with four CSIPHYs, three CSIDs, three TFEs, their clocks, interconnects, and power domains, and a new compatible string qcom,milos‑camss was added. The device tree node camss@ac130000 was populated with registers, IRQs, clocks, interconnects, IOMMUs, GDSC, and CSI input ports.

A missing clock, CAM_CC_SOC_AHB_CLK, was identified when the TFE hardware‑version register read zero and reset timed out. Enabling this clock, which gates the AHB register bus for the whole camera complex, allowed the ISP to respond with hw_version = 0x30000000.

The OV13B10 sensor driver was modified to probe from the device tree by adding an OpenFirmware match table (ovti,ov13b10) and describing the sensor in milos‑fairphone‑fp6.dts at I2C address 0x36 on the CCI bus, with MCLK1 set to 19.2 MHz, a reset GPIO, and power rails forced on for initial bring‑up. Two details were corrected: lane numbering was changed from downstream’s one‑based <1 2 3 4> to mainline’s zero‑based <0 1 2 3>, and the ultra‑wide camera was routed to CSIPHY1 as indicated in the downstream device tree.

After these changes the sensor probed successfully, the chip ID was read over I2C, CSIPHY reported lane activity, and the ISP began producing frames.

Fixing the zero‑frame issue

Initially all frames were black, even when the sensor’s internal colour‑bar test pattern was enabled. The kernel log showed VFE0: Bad config violation, indicating a consumer/config mismatch in the ISP write engine. Comparing downstream cam_tfe_bus.c with the mainline driver revealed that the RDI write‑master’s packer format depended on the ISP bus width: the TFE530 (used in the mainline driver) has a 64‑bit RDI bus and uses packer 0xa (PLAIN64), while the TFE665 on milos has a 128‑bit RDI bus and requires packer 0x0. Changing the register value from 0xa to 0x0 eliminated the violations, allowing pixel data to be written. The resulting frames displayed the full colour‑bar pattern with a maximum pixel value of 255, confirming that the data path OV13B10 → CSIPHY → CSID → TFE665 → DDR was functional.

Integrating with libcamera

Raw Bayer frames were sufficient for a QR script, but a usable camera required libcamera. Libcamera 0.7.2 already recognised the milos qcom‑camss graph through its generic simple pipeline handler; its software ISP debayered the raw frames to RGB, with GPU acceleration on the Adreno via EGL, delivering about 30 fps. Auto‑exposure initially failed because libcamera lacked a sensor‑helper for the OV13B10. The sensor’s analogue gain is linear with gain = code / 128 (0x80 = 1×). A small helper class was added to libcamera:

class CameraSensorHelperOv13b10 : public CameraSensorHelper {
public:
    CameraSensorHelperOv13b10() { gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; }
};
REGISTER_CAMERA_SENSOR_HELPER("ov13b10", CameraSensorHelperOv13b10)

After registering the helper and adding an entry to libcamera’s sensor‑properties database (including V4L2 crop and get_selection support), the auto‑exposure loop converged. GStreamer’s libcamerasrc and PipeWire began receiving properly exposed frames. Installing the PipeWire libcamera plugin made the camera appear as a normal video source in desktop applications such as GNOME Camera and Snapshot.

Remaining challenges

  • Autofocus: the ultra‑wide camera includes a VCM (likely Awinic AW86017) that responds to the DW9714 protocol, and the mainline dw9714 driver can drive it. However, libcamera’s software ISP has no autofocus algorithm, so focus is fixed at a compromise position suitable for arm’s‑length QR scanning via a udev rule.
  • Orientation: the sensor is mounted at an angle; setting device‑tree rotation and orientation properties lets libcamera‑aware applications display the feed upright.
  • Binned modes: the OV13B10 driver advertises 2×2‑binned half‑resolution modes, but on this CAMSS path they produce garbled, sheared output. Those modes were disabled, leaving only full‑resolution and a few other clean modes. Consequently, common previews (e.g., 1080p) are a centre crop of a larger mode, slightly zoomed in rather than showing the full ultra‑wide field of view.
  • Power sequencing: regulators are forced on instead of being properly sequenced, and the VCM draws idle current while held at a fixed focus. This is acceptable for experimentation but needs proper power management for daily use.
  • ISP processing: all debayering, auto‑exposure, and auto‑white‑balance are performed in software with GPU assistance; there is no tuned hardware ISP pipeline, so image quality is not optimized.

Community reaction

Comments on the Hacker News post highlighted related work and reactions:

"Another dev has been hard at work bringing Fairphone 6 Linux support for calls, audio, microphone, NFC, GPS, and IMU: https://blorp.piefed.zip/inbox/u/https%3A%2F%2Fani.social%2F... It’s now probably the most modern well‑supported pmOS phone." – @pizzaiolo

"It’s a pity those IMX and ISOCELL sensor chips are unobtainable from Digikey. Anyone with experience buying them in smaller quantities?" – @amelius

"have fairphone looked into supporting GrapheneOS? what exactly is missing there other than “it’s not Pixel”?" – @NooneAtAll3

"The most basic device accessory and Linux. 2026. Experimental. Very on‑brand." – @1970-01-01

"I wish one day I could do cool stuff like that. Kudos!" – @BraveOPotato

"Good to see this! Love Fairphone!" – @noIdeaTheSecond

"Does the article seem AI‑written/assisted to anyone else? …" – @Throwaway698514

"Has anyone had any luck in writing drivers using LLMs? It’s one of those areas of software that is very niche and no one wants to do it. And it’s also relatively testable" – @ClumsyPilot

These remarks reflect interest in broader Linux support for the Fairphone 6, curiosity about sensor sourcing, questions about alternative OS support, and appreciation for the experimental camera work.

Sources and limitations

The patches, device‑tree changes, and libcamera modifications needed to reproduce this work are available in the repository:

https://github.com/nondescriptpointer/fairphone6-wide-camera-linux

As stated by the author, this is an experimental start, not production‑ready camera support. Only the ultra‑wide (OV13B10) camera functions; the main and front sensors lack mainline drivers. Autofocus is not available in libcamera’s software ISP, binned modes are broken on this path, power sequencing is simplified, and the ISP relies on software processing. Further work is required to fix the binned modes, implement proper power sequencing, and prepare upstream‑ready components.

Sources