Fairphone 6 广角摄像头实验性 Linux 支持
摘要
已为 Fairphone 6 的超广角摄像头开发了实验性 Linux 驱动,通过 qcom-camss 驱动和 libcamera 在主线 Linux 上实现了二维码扫描功能。
暂无内容
查看缓存全文
缓存时间: 2026/07/22 23:24
# Fairphone 6 超广角摄像头的实验性 Linux 支持 · nondescriptpointer
来源:https://nondescriptpointer.com/articles/fairphone-6-wide-camera-linux/
发布日期:2026年7月21日
Fairphone 6 超广角摄像头在GNOME Snapshot中工作。
## 背景
**Fairphone 6** 是主线Linux和postmarketOS的一个有趣目标,原因如下:
- 与大多数其他受支持的postmarketOS设备相比,它拥有相对现代的硬件。
- Fairphone投资于主线Linux支持,由Luca Weiss推动大部分开发工作。
- 这些努力已经为硬件提供了有希望的初始支持。
- Fairphone有意允许替代操作系统。
- Fairphone旨在长期支持其设备,因此这款手机可以为未来的工作提供稳定的基础。
目前仍有两个主要障碍阻止该设备普遍可用:**板载音频和摄像头支持**。我正在做一个需要二维码扫描的项目,因此我以此为契机,看看能否让至少一个摄像头工作起来。免责声明:我严重依赖LLM的帮助来完成这项工作。
## Fairphone 6 摄像头
Fairphone 6 有三个摄像头:
- 后置:Sony IMX896
- 前置:Samsung S5KKD1
- 超广角:OmniVision OV13B10
Sony和Samsung传感器没有主线Linux驱动,但OmniVision OV13B10有一个主线驱动。超广角摄像头足以用于二维码扫描。
手机摄像头并非单一设备。在Qualcomm SoC上,捕获路径是一个链条:
``
图像传感器 → CSI-2 D-PHY → CSIPHY → CSID → ISP (VFE/TFE) → 内存
(I2C) (MIPI lane) (解码) (解复用) (写入引擎) (DMA)
``
还有几个支持组件,包括摄像头时钟控制器(camcc)、CCI(Qualcomm专用的摄像头I2C控制器)、电源轨和用于自动对焦的VCM(音圈马达)。
下游厂商的Android内核使用Qualcomm庞大且专有的CAMX/cam-kernel栈来驱动所有这些。在主线上,等效的是更小的**qcom-camss**驱动,而**libcamera**提供用户空间集成和图像处理。
为了让OmniVision摄像头工作,我必须让qcom-camss了解SoC的特定模块、在设备树中描述硬件、启用传感器驱动,并配置libcamera将原始Bayer帧转换为应用程序可以使用的图像。
## 初步探索
在开始实现之前,我想弄清楚有多少工作是新的,有多少可以从主线已经支持的硬件中移植。这将表明该项目在没有制造商支持的情况下是否可行。
初步研究令人鼓舞:
- FP6的SoC是Qualcomm**milos** (SM7635)。下游主板代号为volcano,postmarketOS已经使用基于主线的内核分支启动它。
- 摄像头硬件模块是**TFE665**(一个薄前端ISP)、**CSID665**和**CSIPHY v2.2.1**。
- **camcc时钟控制器**和**CCI**已经存在于内核分支中。
- 三个摄像头分别是:- **主摄:**Sony IMX896,没有主线驱动。 - **超广角:**OmniVision**OV13B10**,有一个主线驱动,但只支持ACPI/x86。 - **前置:**Samsung S5KKD1,没有主线驱动。
这使得目标很明确:**OV13B10超广角**。它是一个13 MP传感器,有现有的主线驱动,其宽视野适合二维码扫描。
当我比较下游寄存器头文件(`cam_tfe665.h`、`cam_csiphy_2_2_1_hwreg.h`和`cam_tfe_bus.c`)与主线`qcom-camss`时,我发现TFE665本质上与主线已经支持的TFE530是相同的IP。寄存器布局相同。只有内部模块的基地址偏移不同,因为写入总线位于不同的地址。类似地,CSID665 RDI寄存器与受支持的CSID匹配,而CSIPHY v2.2.1属于同一个三相PHY系列。
这意味着我可以**移植现有的驱动,而不是从头编写所有内容**。
## 步骤1:将捕获子系统移植到内核中
`qcom-camss`尚未在milos上可用,因此我必须连接现有的部分。
### TFE665 ISP驱动
我添加了一个新的`camss-vfe-665.c`,直接以主线TFE530驱动(`camss-vfe-340.c`)为模型。由于寄存器内容相同,驱动逻辑也相同。主要区别在于,milos将ISP控制模块和写入总线模块放置在不同的偏移量上。总线寄存器基地址从`0xa00`移至`0x1800`,封装这个偏移量变化占据了大部分工作。
### CSID665 和 CSIPHY v2.2.1
- **CSID665**重用了现有的gen-2 CSID操作,因为其RDI寄存器偏移量相同。
- **CSIPHY v2.2.1**需要为此版本配置新的lane配置表和D-PHY调谐值。我从下游的`cam_csiphy_2_2_1_hwreg.h`中转录了通道寄存器序列以及大约1.1 Gbps/lane ("500 Msps")的数据速率和AFE设置。PHY的寄存器窗口偏移量为`0x1000`。
### 资源、兼容性和设备树
在`camss.c`中,我描述了milos的捕获复合体:四个CSIPHY、三个CSID、三个TFE、它们的时钟、互连和电源域。我还注册了一个新的`qcom,milos-camss`兼容字符串。在设备树中,我添加了`camss@ac13000`节点,包含其寄存器、IRQ、时钟、互连、IOMMU、GDSC和CSI输入端口,以及MCLK和复位引脚控制状态。
### 缺少寄存器总线时钟
这时我遇到了一个问题。驱动绑定成功,但读取TFE硬件版本寄存器返回`0x0`,并且复位超时,就像模块未上电一样。修复方法是一个看似并非ISP时钟的时钟:**`CAM_CC_SOC_AHB_CLK`**。它门控了整个摄像头复合体(包括CCI)使用的AHB寄存器总线。没有它,寄存器访问静默返回零。我添加了该时钟和CAMNOC AXI时钟,然后设置了CAMNOC数据路径时钟速率。ISP以`hw_version = 0x30000000`复活了。
这表明,在Qualcomm硬件上,如果一个模块读回零值,可能是其访问路径上缺少时钟或电源域。
## 步骤2:启动OV13B10传感器
主线`ov13b10`驱动存在,但它是为x86/ACPI笔记本电脑编写的,仅通过ACPI匹配。我在两个地方进行了修改。
### 使驱动在ARM和设备树上可用
- 我添加了一个**OpenFirmware匹配表**(`ovti,ov13b10`),以便驱动可以从设备树探测。
- 我在`milos-fairphone-fp6.dts`中描述了传感器。它位于CCI I2C总线上,地址为`0x36`,需要**MCLK1 19.2 MHz**、一个复位GPIO和电源轨。对于这个实验性的启动,我简单地强制打开了稳压器,而不是完全排序。
### 2个小细节
1. **lane编号。**下游设备树使用`data-lanes = <1 2 3 4>`,而主线的约定是**从0开始索引**:`<0 1 2 3>`。使用错误的编号,CSIPHY编程了一个缺少lane 0的lane掩码,PHY从未锁定。
2. **哪个CSIPHY?**FP6的布线将超广角摄像头路由到**CSIPHY1**。从下游设备树中获取此信息而不是猜测,节省了大量试错。
此时,传感器成功探测,芯片ID通过I2C正确读取,CSIPHY报告了通道活动,ISP产生了**完全黑色**的帧。
## 步骤3:全零帧之谜
这是主要的缺陷。帧以正确的速率和大小到达,`buf_done`被触发,但每个像素都是零。即使我启用了传感器内部的彩色条测试模式(该模式在传感器内部生成,无论场景如何都应出现),情况也是如此。数据路径传递了帧定时,但没有传递像素数据。
内核日志提供了一个线索:`VFE0: Bad config violation`。ISP的写入引擎报告了每个帧一次的**消费者/配置违规**,因为写入主机的配置与传入数据不匹配。
当我深入研究下游的`cam_tfe_bus.c`时,差异变得清晰。RDI写入主机的**打包器格式**取决于ISP总线宽度:
- TFE530 (qcm2290,主线驱动的目标) 有**64位**RDI总线,因此它使用打包器`0xa`。
- **TFE665 (milos) 有128位RDI总线,因此它需要打包器`0x0`。**
主线驱动硬编码了64位值。在milos上,这是错误的,写入引擎拒绝写入像素。将寄存器值从`PLAIN64 (0xa)`更改为`0x0`将全零帧变成了**真实图像**:最大像素值为255,完整的彩色条模式出现,违规也停止了。
这就是摄像头物理工作的时刻:**OV13B10 → CSIPHY → CSID → TFE665 → DDR**,传递真实的Bayer帧。
## 步骤4:原始Bayer到libcamera
原始帧足以用于二维码脚本,但一个可用的摄像头需要**libcamera**,这是现代Linux摄像头应用程序使用的用户空间框架。libcamera 0.7.2已经通过其通用的**简单**管道处理程序识别了milos`qcom-camss`图。其**软件ISP**将原始Bayer帧去马赛克为RGB,通过EGL在Adreno上使用GPU加速,开箱即用约30 fps。`cam`和GStreamer的`libcamerasrc`立即生成了干净的图像。
**自动曝光**是未工作的部分。图像偏暗或过亮,日志报告`Failed to create camera sensor helper for ov13b10`。libcamera的软件自动曝光和增益循环需要一个小的逐传感器辅助程序来将传感器的增益寄存器值映射到实际增益倍数。libcamera包含几个传感器的辅助程序,但不包括这个。
修复很小。OV13B10的模拟增益是线性的,`0x80 = 1×`,或`gain = code / 128`,这与其它几个OmniVision传感器的行为相同。我在libcamera的传感器辅助程序数据库中添加了一个类:
``
class CameraSensorHelperOv13b10 : public CameraSensorHelper {
public:
CameraSensorHelperOv13b10() { gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; }
};
REGISTER_CAMERA_SENSOR_HELPER("ov13b10", CameraSensorHelperOv13b10)
``
自动曝光循环立即开始收敛。我还向libcamera的传感器属性数据库添加了一个条目,并反向移植了传感器驱动的V4L2裁剪和`get_selection`支持,libcamera使用这些来获取像素阵列几何信息。之后,GStreamer和PipeWire接收到了正确曝光的视频流。安装PipeWire libcamera插件后,摄像头在桌面应用程序中作为一个普通视频源出现。
在某些情况下图像仍然有些过曝,因此辅助程序可能需要进一步工作。
## 步骤5:对焦、方向和分辨率问题
我仍然有几个需要微调的问题。
### 自动对焦
超广角摄像头有一个**音圈马达(VCM)**用于对焦。下游设备树表明它是**Awinic AW86017**。在给自动对焦电源轨(由一个GPIO驱动的稳压器控制)上电后,探测CCI I2C总线,我在地址`0x0c`处发现了一个设备,它使用事实上的标准DW9714 10位DAC协议。主线**`dw9714`**驱动直接驱动它。
一次对焦扫描确认镜头物理移动,并且在中间设置处清晰度明显达到峰值。libcamera通过设备树中的`lens-focus`链接将镜头与传感器关联起来。
不幸的是,libcamera的**软件ISP没有自动对焦算法**。为了避免将镜头停在无限远处并产生模糊的近距离图像,我设置了一个合理的固定对焦,针对臂长距离的二维码扫描和文档进行了调整,使用了一个小的udev规则。可以根据需要调整设置,或者从软件控制对焦。
### 方向
传感器安装的角度相对于手机的竖向方向是倾斜的,因此预览最初显示为横向。设置设备树旋转和方向属性后,支持libcamera的应用程序可以正确显示预览。
### Binning模式
OV13B10驱动提供了多个分辨率,包括2×2 binning的半分辨率模式。在此CAMSS路径上,**binning模式产生了混乱、扭曲的输出**。它们的读出几何与声明的帧大小不匹配,而全分辨率和其他几个模式是清晰的。
为了避免发布损坏的预览,我**禁用了这两个损坏的模式**,以便libcamera只选择工作模式。代价是,由于软件ISP是裁剪而不是缩放,1080p预览是更大模式的中心裁剪。它有一点放大,而不是显示完整的超广角视野。
结果是,在GNOME Camera/Snapshot中获得了**实时、方向正确、自动曝光、对焦良好的预览**,并且二维码扫描可以工作。
## 来源
重现这些结果所需的补丁和相关文件可在此仓库中找到:
github.com/nondescriptpointer/fairphone6-wide-camera-linux (https://github.com/nondescriptpointer/fairphone6-wide-camera-linux)
## 限制
这是一个实验性的开始,而不是生产级摄像头支持。
- **只有超广角(OV13B10)工作。**主摄(IMX896)和前置(S5KKD1)传感器没有主线驱动。
- **没有自动对焦。**libcamera的软件ISP没有对比度AF循环,因此对焦是一个固定的折中位置。真正的自动对焦需要软件ISP中的AF算法或应用程序端的循环来驱动VCM。
- **常见分辨率的预览视野被裁剪**,因为2×2 binning的传感器模式在此路径上损坏,而软件ISP是裁剪而不是缩放。修复binning模式的寄存器序列或添加缩放器将恢复完整的超广角视野。
- **电源排序被简化。**稳压器被强制开启而不是排序,并且VCM在保持固定对焦位置时消耗少量空闲电流。这对于实验很好,但日常使用需要适当的电源管理。
- **ISP是纯软件的。**所有去马赛克、自动曝光和自动白平衡处理在软件中完成,有GPU辅助。它对于二维码扫描和随意使用效果很好,但不能提供经过调谐的硬件ISP管道的图像质量。
- 我没有花时间**优化图像质量**。可能需要进一步优化才能从传感器获得更好的照片。
## 后续步骤
- 修复binning模式以恢复完整视野。
- 编写正确的电源排序。
- 准备已经准备好向上游提交的部分。
相似文章
Fairphone 6 与 PostmarketOS 主摄像头正常工作
开发者宣布,在 Fairphone 6 上运行 PostmarketOS 的主摄像头驱动开发取得进展,实现正常工作,包括色彩校正改进以及紧急呼叫验证和未来设备支持的计划。
postmarketOS 2026年7月:libcamera 0.7.2
postmarketOS 2026年7月月度更新,涵盖 libcamera 0.7.2 升级(包含上游化补丁)、改进的视频通话支持、组织变更以及即将到来的会议亮相。
Fairphone Gen 6+
Fairphone 推出了 Gen 6+,这是一款模块化智能手机,设计使用至2033年,强调可持续性和长久耐用性。
Fairphone 现已在美国正式上市
Fairphone 发布了 Gen. 6+ 智能手机,升级硬件包括 Snapdragon 7s Gen 4 处理器和 12GB RAM,同时强调可持续性、可维修性和延长支持。
Fairphone 6 Plus 正是我们急需的中端手机
Fairphone 6 Plus 是一款可维修、材料来源符合伦理标准的中端 Android 手机,现已在美国上市,提供 12 个用户可自行更换的部件和接近原生的系统体验。它在不牺牲可持续性的前提下实现了典型的中端机性能,是该品牌的一个重要里程碑。