Camera
This page aims to provide comprehensive information about smartphone camera sensors and their integration in Linux-based systems. Contributions and corrections are welcome – feel free to edit this page! |
Modern smartphones contain multiple camera sensors (often called "modules" or "sensors") manufactured by companies like Sony, OmniVision, Samsung, and others. These complex systems involve both hardware components and software interfaces. This guide covers technical details relevant to work on camera subsystem bringup, debugging, or optimization.
Camera Hardware Fundamentals
A typical camera module consists of:
- Image Sensor: CMOS/CCD chip that captures light (primary component)
- Lens Assembly: Optical elements focusing light onto the sensor
- VCM (Voice Coil Motor): Electromagnetic actuator for autofocus/optical stabilization
- EEPROM: Stores calibration data (lens shading, AF positions, etc.)
- Optional: IR filter, flash LED driver, OIS (Optical Image Stabilization)
Most modern sensors use MIPI CSI-2 (Camera Serial Interface 2) for data transfer, while older designs may use parallel DVP (Digital Video Port) interfaces. Many of the same concepts apply to both interfaces, though this article focuses primarily on CSI-2. |
Electrical Interface Specifications
Connection Type | Purpose | Typical Pin Count | Notes |
---|---|---|---|
Power Supplies | Sensor operation | 3-4 | AVDD (analog), DVDD (digital), DOVDD (I/O), AFVDD (autofocus) |
I²C (SCCB/CCI) | Control/configuration | 2 | SDA (data), SCL (clock). Also named SCCB (serial camera control bus), CCI (camera control interface), or 2-wire serial. |
MIPI CSI-2 | Image data transfer | 4-10 | 2 clock lanes + 1-4 data lanes (2 pins/lane). Some sensors support lane remapping. |
GPIOs | Control signals | 1-2 | Reset, powerdown, strobe |
MCLK | Master clock input | 1 | Typically 6-27MHz (named MCLK or XVCLK) |
Linux Camera Software Stack
The Linux camera stack involves multiple layers:
- V4L2 Subdev Drivers: Sensor-specific control (I²C register access)
- CSI Receiver Drivers: MIPI CSI-2 PHY handling (e.g., Qualcomm CSIPHY)
- Image Processing Pipeline: ISP, statistics collection, 3A algorithms (AE/AF/AWB)
- Userspace Interface: V4L2, libcamera, Android Camera HAL
Device Tree Configuration
The Device Tree (DT) describes hardware connections between the sensor and SoC. Correct configuration is critical for functionality.
Sensor Node Implementation
&cci_i2c0 {
ov8865: camera-sensor@10 {
compatible = "ovti,ov8865"; // Matches kernel driver
reg = <0x10>; // I²C 7-bit address
// Clock configuration
clocks = <&camcc CAMSS_MCLK0_CLK>; // Clock source
clock-names = "xvclk"; // Often 24MHz
// Power supplies
avdd-supply = <&pm8941_l17>; // Analog 2.8V
dovdd-supply = <&pm8941_lvs3>; // I/O 1.8V
dvdd-supply = <&pm8941_l3>; // Digital 1.2V
// Control GPIOs
reset-gpios = <&tlmm 90 GPIO_ACTIVE_LOW>;
powerdown-gpios = <&tlmm 89 GPIO_ACTIVE_LOW>;
// Physical properties
orientation = <1>; // 0:Front, 1:Rear
rotation = <90>; // Degrees (0,90,180,270)
// Linked components
lens-focus = <&ad5823>; // VCM driver reference
flash-leds = <&pm8941_flash>; // Flash controller (must be V4L2 subdevice)
// Pin control
pinctrl-names = "default";
pinctrl-0 = <&mclk0_pin_a>; // MCLK pin configuration
// MIPI CSI-2 Interface
port {
ov8865_ep: endpoint {
data-lanes = <1 2 3 4>; // Active data lanes
clock-lanes = <0>; // Clock lane index
bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
link-frequencies = /bits/ 64 <360000000>; // Hz
remote-endpoint = <&csiphy0_ep>; // SoC receiver node
};
};
};
};
SoC Receiver Configuration (Qualcomm)
&camss {
status = "okay";
vdda-supply = <&pm8941_l12>; // CSIPHY analog supply
ports {
port@0 {
reg = <0>; // CSIPHY0 instance
csiphy0_ep: endpoint {
clock-lanes = <0>; // Matches sensor's clock-lanes
data-lanes = <1 2 3 4>; // Matches sensor's data-lanes
bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
link-frequencies = /bits/ 64 <360000000>;
remote-endpoint = <&ov8865_ep>;
};
};
};
};
Essential Device Tree Properties
Property | Purpose | Values | Critical |
---|---|---|---|
data-lanes | Active CSI-2 data lanes | <1 2 3 4> (4-lane) <1 2> (2-lane) |
Yes |
clock-lanes | CSI-2 clock lane index | <0> | Yes |
link-frequencies | CSI-2 link speed(s) | /bits/64 <360000000> | Yes |
rotation | Sensor mounting angle | 0 , 90 , 180 , 270 | Optional (Metadata) |
orientation | Camera position | 0 (Front) 1 (Rear) |
Optional (Metadata) |
Qualcomm-Specific Implementation Details
Qualcomm SoCs use CAMSS (Camera Subsystem) with these components:
- CCI (Camera Control Interface): Dedicated I²C controller for sensors (not standard QUP/BLSP bus)
- CSIPHY: MIPI CSI-2 physical layer receiver (typically 2-4 instances)
- CSID: CSI decoder and lane demux
- ISP: Image Signal Processor
For more information, see the Qualcomm CAMSS kernel documentation.
Downstream to Upstream DT Conversion
Common downstream properties and their upstream equivalents:
Downstream Property | Upstream Equivalent | Downstream Example | Mainline Example | Notes |
---|---|---|---|---|
qcom,cci-device |
CCI controller index | qcom,cci-device = <1>
|
&cci1_i2cX {
...
};
|
Is the X on cciX_i2cY (Note: not all Devices/SoCs have multiple controllers, so the X is removed to use cci_i2cY )
|
qcom,cci-master |
CCI I²C bus index | qcom,cci-master = <0>
|
&cci1_i2c0 {
...
};
|
Is the Y on cciX_i2cY
|
qcom,csiphy-sd-index |
reg and port index in port@ node |
qcom,csiphy-sd-index = <3>
|
&camss {
ports {
port@3 {
camss_endpoint3: endpoint {
reg = <0>; // This is usually implemented on the SoC dtsi
remote-endpoint = <&camera_<ORIENTATION>_<SENSOR_NAME>_endpoint>;
...
};
}
};
};
|
CSIPHY instance number |
cam_vdig-supply |
Driver dependant | cam_vdig-supply = <&pm8009_l2>
|
vana-supply = <&vaux3>
|
Digital power rail |
cam_vana-supply |
Driver dependant | cam_vana-supply = <&pm8009l_l5>
|
vana-supply = <&vaux3>
|
Analog power rail |
cam_vio-supply |
Driver dependant | cam_vio-supply = <&pm8009l_l1>
|
vio-supply = <&vaux1>
|
I/O power rail |
cam_vaf-supply |
Driver-specific AF supply | cam_vaf-supply = <&pmi8998_bob>
|
cam_vaf-supply = <&pmi8998_bob> // (actuator/ois node)
|
Not always defined upstream; some autofocus drivers have dedicated vaf-supply
|
gpios |
Named GPIO references | gpios = <&tlmm 13 0>, <&tlmm 80 0>
|
reset-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>
|
Check schematic or downstream driver for actual functions |
clocks |
clocks or assigned-clock |
clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
|
clocks = <&camcc CAM_CC_MCLK1_CLK>;
|
Typically the MCLK input clock for the sensor |
clock-names |
clock-names |
clock-names = "cam_src_clk", "cam_clk"
|
clock-names = "xclk"
|
Usually set to xclk or mclk
|
clock-rates |
clock-rates or assigned-clock-rates |
clock-rates = <24000000>
|
clock-rates = <24000000>
|
Specifies the frequency of the sensor's master input clock (MCLK/XCLK) in Hz. Common values: 19200000, 24000000, or 26000000. Check the sensor datasheet and driver. |
sensor-position-roll , sensor-position-pitch , sensor-position-yaw |
rotation |
sensor-position-roll = <90>
sensor-position-pitch = <0>
sensor-position-yaw = <180>
|
rotation = 180
|
Upstream uses a single rotation property (0 or 180); more complex orientation handled in userspace
|
eeprom-src |
Separate EEPROM node + I²C link | eeprom-src = <&eeprom0>
|
i2c {
eeprom@50 {
compatible = "atmel,24c08";
reg = <0x50>;
};
}
|
EEPROMs modeled as separate I²C devices connected via port /endpoint
|
led-flash-src |
flash-leds |
led-flash-src = <&led_flash0>
|
flash-leds = <&led_flash0>
|
Phandle to LED flash device |
actuator-src |
lens-focus |
actuator-src = <&actuator0>
|
lens-focus = <&actuator0>
|
Phandle to lens actuator device |
Test Pattern Generation
The CSID component in CAMSS can generate test patterns for subsystem validation without sensor data:
$ v4l2-ctl -d /dev/v4l-subdev3 -L
Image Processing Controls
test_pattern 0x009f0903 (menu) : min=0 max=6 default=0 value=0 (Disabled)
0: Disabled
1: Incrementing
2: Alternating 0x55/0xAA
3: All Zeros 0x00
4: All Ones 0xFF
5: Pseudo-random Data
6: User Specified
Newer SoCs support additional patterns: "Complex pattern", "Color box", and "Color bars".
Enable test patterns using:
v4l2-ctl -d /dev/v4l-subdev3 -c test_pattern=2 # Alternating 0x55/0xAA
v4l2-ctl -d /dev/v4l-subdev3 -c test_pattern=0 # Disable pattern
Most sensors also provide test patterns for pipeline validation. CSID patterns are specific to Qualcomm's implementation. |
-
Pattern 1 (Incrementing)
-
Pattern 2 (Alternating)
-
Pattern 3 (All Zeros)
-
Pattern 4 (All Ones)
-
Pattern 5 (Pseudo-random)
Sensor Bringup Procedure
Follow this step-by-step process to enable a new camera sensor.
Establishing I²C Communication
- Enable CCI controller and I²C bus in DT
- Force power supplies and MCLK:
/ { fake-reg-mclk2 { compatible = "regulator-fixed-clock"; regulator-name = "mclk2-force-on"; pinctrl-names = "default"; pinctrl-0 = <&cam_mclk2_default>; clocks = <&camcc CAM_CC_MCLK2_CLK>; regulator-always-on; }; }; &tlmm { cam_mclk2_default: cam-mclk2-default { pins = "gpio31"; function = "cam_mclk2"; drive-strength = <2>; bias-disable; }; };
- Install
i2c-tools
- Check I2C bus numbers
i2cdetect -l
$ i2cdetect -l # TODO: Add command output
- Verify addresses with
i2cdetect -y
, the bus number will change after each reboot but the addresses output will be the same):$ i2cdetect -y 3 # Scan bus addresses # TODO: Add command output
I²C Address Conversion Description 8-bit Format
(Datasheet / Downstream Dmesg)7-bit Format
(Linux)Conversion Method Typical representation 8-bit address + R/W bit Pure 7-bit address Right-shift by 1 bit Write address example 0x20 [0 0 1 0 0 0 0 0] 0x10 [- 0 0 1 0 0 0 0] 0x20 >> 1 = 0x10
Read address example 0x21 [0 0 1 0 0 0 0 1] 0x10 [- 0 0 1 0 0 0 0] 0x21 >> 1 = 0x10
Device Tree usage Not used reg = <0x10>
N/A Common I²C Address Conversion Examples Sensor Datasheet
Write AddressLinux
7-bit AddressConversion OV8865 0x20 0x10 0x20 >> 1
IMX214 0x34 0x1a 0x34 >> 1
S5K3L6 0x5A 0x2d 0x5A >> 1
Generic formula 8-bit_addr (8-bit_addr >> 1) Right-shift operation Key points:
- The LSB (bit 0) in 8-bit addresses indicates Read/Write (0=Write, 1=Read)
- Linux tools and DT use only the upper 7 bits
- Conversion is automatic in Linux tools - just right-shift the 8-bit value
- Read sensor ID register (example for IMX582 at 0x1a):
$ i2cset -y <BUS> <ADDR> <REG> <VALUE> $ i2cset -y 3 0x1a 0x00 0x16 # Set 16-bit register address $ i2cget -y 3 0x1a # Read high byte 0x05 $ i2cget -y 3 0x1a # Read low byte 0x82
Configuring CSI-2 Interface
- Verify lane configuration in DT matches schematic
- Check clock frequency requirements (typically 19.2MHz, 24MHz, or 27MHz)
- Handle lane remapping using
data-lanes
property if needed - Ensure driver supports configured lane count
Driver Implementation
- Add compatible string to DT matching kernel driver
- Verify driver supports:
* Register configuration for desired resolution * CSI-2 lane count configuration * V4L2 controls (exposure, gain, etc.)
- Check for dependencies (e.g., clock, regulator, GPIO drivers)
Testing and Debugging Techniques
Use these tools to validate camera functionality.
V4L2 Utilities
Required packages: v4l-utils |
# List video devices
$ v4l2-ctl --list-devices
# Capture test image (YUYV format)
$ v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=YUYV \
--stream-mmap --stream-count=1 --stream-to=test.raw
# Set manual exposure
$ v4l2-ctl -d /dev/video0 -c exposure=1000
# Test flash/torch control
$ v4l2-ctl -d /dev/video0 -c flash_mode=1
Media Controller
Required packages: v4l-utils |
# Show topology and formats
$ media-ctl -p
# Example output:
# Device topology
# - entity 1: msm_csiphy0 (2 pads, 4 links)
# ...
# pad0: Sink
# [fmt:UYVY8_2X8/1920x1080 field:none colorspace:srgb]
# <- "imx355 4-001a":0 [ENABLED,IMMUTABLE]
# pad1: Source
# [fmt:UYVY8_2X8/1920x1080 field:none colorspace:srgb]
# -> "msm_csid0":0 []
# -> "msm_csid1":0 []
# -> "msm_csid2":0 []
# Enable link between entities
$ media-ctl -l '"msm_csiphy0":1->"msm_csid0":0[1]'
# Set format on pad
$ media-ctl -V '"ov8865":0[fmt:SRGGB10/3264x2448]'
# Enable test pattern generation
$ media-ctl -d /dev/media0 -V '"sensor":0[0 0 3264 2448 0]'
Libcamera Tools
Required packages: libcamera-tools qcam |
cam --list
Looks for cameras in different locations, printing useful debug output and finish with a list of cameras it found. The number at the beginning of found cameras shall be used to identify cameras in later commandscam --camera #num --list-properties
In case a camera is found, this command lists the properties of the specific camera. It is usually common to look for the Location and Rotation properties, as they are often missing from the device treescam --camera #num --info
Show supported formats/resolutions (modes). This can be useful to troubleshoot missing resolutions on formatsqcam
Opens a new window that allows selecting the right camera to test a direct video streaming from libcamera. This command needs to be run in a terminal with the whole environment setup
$ cam --list
[0:01:08.084433098] [2581] INFO Camera camera_manager.cpp:326 libcamera v0.5.1
[0:01:08.142045421] [2582] WARN CameraSensorProperties camera_sensor_properties.cpp:463 No static properties available for 'imx363'
[0:01:08.142090844] [2582] WARN CameraSensorProperties camera_sensor_properties.cpp:465 Please consider updating the camera sensor properties database
[0:01:08.142132516] [2582] WARN CameraSensor camera_sensor_legacy.cpp:501 'imx363 7-0010': No sensor delays found in static properties. Assuming unverified defaults.
[0:01:08.143837695] [2582] WARN IPASoft soft_simple.cpp:103 IPASoft: Failed to create camera sensor helper for imx363
Available cameras:
1: Internal back camera (/base/soc@0/cci@ac4b000/i2c-bus@0/camera@10)
$ cam --camera 1 --list-properties
[0:01:34.263906750] [2649] INFO Camera camera_manager.cpp:326 libcamera v0.5.1
[0:01:34.319880195] [2650] WARN CameraSensorProperties camera_sensor_properties.cpp:463 No static properties available for 'imx363'
[0:01:34.319928426] [2650] WARN CameraSensorProperties camera_sensor_properties.cpp:465 Please consider updating the camera sensor properties database
[0:01:34.319969416] [2650] WARN CameraSensor camera_sensor_legacy.cpp:501 'imx363 7-0010': No sensor delays found in static properties. Assuming unverified defaults.
[0:01:34.321667324] [2650] WARN IPASoft soft_simple.cpp:103 IPASoft: Failed to create camera sensor helper for imx363
Using camera /base/soc@0/cci@ac4b000/i2c-bus@0/camera@10 as cam0
Property: SystemDevices = [ 20736, 20737, 20738, 20739, 20740, 20741, 20742, 20743, 20744, 20745, 20746, 20747, 20748, 20749, 20750, 20751 ]
Property: ColorFilterArrangement = 0 (RGGB)
Property: PixelArrayActiveAreas = [ (8, 24)/4032x3024 ]
Property: PixelArraySize = 4032x3024
Property: Rotation = 90
Property: Location = 1 (CameraLocationBack)
Property: Model = imx363
$ cam --camera 1 --info
[0:01:55.552420774] [2694] INFO Camera camera_manager.cpp:326 libcamera v0.5.1
[0:01:55.615145558] [2695] WARN CameraSensorProperties camera_sensor_properties.cpp:463 No static properties availabl
[0:01:55.615192381] [2695] WARN CameraSensorProperties camera_sensor_properties.cpp:465 Please consider updating the
[0:01:55.615236287] [2695] WARN CameraSensor camera_sensor_legacy.cpp:501 'imx363 7-0010': No sensor delays found in
[0:01:55.616977861] [2695] WARN IPASoft soft_simple.cpp:103 IPASoft: Failed to create camera sensor helper for imx363
Using camera /base/soc@0/cci@ac4b000/i2c-bus@0/camera@10 as cam0
0: 4024x3024-ABGR8888/Unset
* Pixelformat: ABGR8888 (4x2)-(4024x3024)/(+4,+2)
- 160x120
- 240x160
- [REDACTED]
- 3840x2400
* Pixelformat: XBGR8888 (4x2)-(4024x3024)/(+4,+2)
- 160x120
- 240x160
- [REDACTED]
- 3840x2400
* Pixelformat: BGR888 (4x2)-(4024x3024)/(+4,+2)
- 160x120
- 240x160
- [REDACTED]
- 3840x2400
* Pixelformat: RGB888 (4x2)-(4024x3024)/(+4,+2)
- 160x120
- 240x160
- [REDACTED]
- 3840x2400
* Pixelformat: ARGB8888 (4x2)-(4024x3024)/(+4,+2)
- 160x120
- 240x160
- [REDACTED]
- 3840x2400
* Pixelformat: XRGB8888 (4x2)-(4024x3024)/(+4,+2)
- 160x120
- 240x160
- [REDACTED]
- 3840x2400
Sensor Support Matrix
Sensor | Resolution | Driver | Status | Device Tree Compatible | Devices Tested | Notes |
---|---|---|---|---|---|---|
Hynix HI-556 | 5MP | sr556.c | WIP | hynix,sr556 | sdm450-samsung-a6plte-r4 | |
OmniVision OV5670 | 5MP | ov5670.c | Y | ovti,ov5670 | msm8953-xiaomi-markw | |
Omnivision OV5675 | 5MP | ov5675.c | Y | ovti,ov5675 | msm8953-xiaomi-daisy msm8953-xiaomi-vince |
|
OmniVision OV8856 | 8MP | ov8856.c | N | ovti,ov8856 | sm7150-xiaomi-davinci | Untested, but probe successful |
Omnivision OV8865 | 8MP | ov8865.c | Y | ovti,ov8865 | msm8916-wingtech-wt88047 | Redmi 2 usage: [1] |
Samsung ISOCELL 3L6 | 13MP | s5k3l6xx.c | WIP | samsung,s5k3l6xx | imx8mq-librem5 sm7150-xiaomi-davinci |
sm7150-xiaomi-davinci untested Requires 19.2MHz clock support |
Samsung ISOCELL 3L8 | 13MP | s5k2xx.c | WIP | samsung,s5k3l8 | msm8953-xiaomi-markw msm8953-xiaomi-mido msm8917-motorola-nora |
|
Samsung ISOCELL 3P8 | 16MP | s5k2xx.c | WIP | samsung,s5k3p8sp | msm8953-xiaomi-ysl | |
Samsung LSI S5C73M3 | 8MP | s5c73m3 | Y | samsung,s5c73m3 | exynos4412-samsung-{m0,m3,t03g,t0lte} | TRY syscalls need implementing (see FIXME in s5c73m3-core.c) |
Sony IMX214 | 13MP | imx214.c | Y | sony,imx214 | msm8916-longcheer-l8910 msm8939-longcheer-l9100 |
Camera Software Applications
Application | Framework | Platform | Notes |
---|---|---|---|
Megapixels | V4L2 | Phosh, Plasma Mobile | PinePhone optimized |
Millipixels | libcamera | Librem 5 | Megapixels fork |
GNOME Snapshot | GStreamer | GNOME Shell | |
Pinhole | GStreamer, libaperture | GTK4 | |
harbour-pinhole | libcamera | Sailfish OS |
Troubleshooting
Common Issues and Solutions
Symptom | Possible Solution |
---|---|
I²C communication fails |
|
CSI-2 lock failures |
|
Corrupted images |
|
No devices in /dev/video* |
|
libcamera failures |
|
Pipewire Stability Workaround
libcamera together with wireplumber can be unstable, at least on sdm845 devices. Sometimes wireplumber or even pipewire crashes, causing the camera stream to freeze or the camera image to become corrupted. Restarting wireplumber or the camera app can help resolve these issues. To reduce disruptions in daily use, it is recommended to create a script and a desktop shortcut to easily restart Pipewire.
-
Create
/usr/bin/cam-refresh
:#!/usr/bin/env bash echo "Killing Snapshot" killall snapshot # It will freeze when pipewire stops sleep 0.5 # Sleep can help with stream freeze echo "Killing WirePlumber" killall wireplumber echo "Killing PipeWire" killall pipewire sleep 0.1 echo "Starting PipeWire" pipewire & sleep 1 echo "Starting WirePlumber" wireplumber &
-
Mark it as executable
sudo chmod +x /usr/bin/cam-refresh
-
Add desktop entry (
/usr/share/applications/camera-refresh.desktop
):[Desktop Entry] Type=Application Name=Camera Refresh Exec=cam-refresh Icon=camera-switch-symbolic Terminal=false Categories=Utility
- Libcamera Project
- Qualcomm CAMSS Documentation
- Camera Sensor Basics: Understanding Image Capture Technology
- DT Video Interfaces Binding
- Video Interface Devices DT Binding
- A first photo on mainline Linux A nice explanation about how to port a sensor driver from scratch.