Jump to content

Camera

From postmarketOS Wiki
Note 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)
Note 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
Note Most sensors also provide test patterns for pipeline validation. CSID patterns are specific to Qualcomm's implementation.

Sensor Bringup Procedure

Follow this step-by-step process to enable a new camera sensor.

Establishing I²C Communication

  1. Enable CCI controller and I²C bus in DT
  2. 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;
        };
    };
    
  3. Install i2c-tools
  4. Check I2C bus numbers i2cdetect -l
    $ i2cdetect -l
    # TODO: Add command output
    
  5. 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 Address
    Linux
    7-bit Address
    Conversion
    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
  6. 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

  1. Verify lane configuration in DT matches schematic
  2. Check clock frequency requirements (typically 19.2MHz, 24MHz, or 27MHz)
  3. Handle lane remapping using data-lanes property if needed
  4. Ensure driver supports configured lane count

Driver Implementation

  1. Add compatible string to DT matching kernel driver
  2. Verify driver supports:
  * Register configuration for desired resolution
  * CSI-2 lane count configuration
  * V4L2 controls (exposure, gain, etc.)
  1. Check for dependencies (e.g., clock, regulator, GPIO drivers)

Testing and Debugging Techniques

Use these tools to validate camera functionality.

V4L2 Utilities

Note 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

Note 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

Note Required packages: libcamera-tools qcam
  1. 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 commands
  2. cam --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 trees
  3. cam --camera #num --info Show supported formats/resolutions (modes). This can be useful to troubleshoot missing resolutions on formats
  4. qcam 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
  • Check pull-up resistors
  • Verify power supplies, setting regulator-always-on on camera-related regulators may help to debug)
  • Confirm MCLK is running
CSI-2 lock failures
  • Validate lane mappings
  • Check clock frequency
  • Verify DT link-frequencies
Corrupted images
  • Increase CMA size (cma=256M kernel parameter or setting CONFIG_CMA_SIZE_MBYTES=256 in kernel config)
  • Check buffer sizes in DT
No devices in /dev/video*
  • Verify media controller links
  • Check V4L2 subdev registration
libcamera failures
  • Ensure sufficient CMA memory (cat /proc/meminfo | grep -i cma)

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.

  1. 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 &
    
  2. Mark it as executable
    sudo chmod +x /usr/bin/cam-refresh
    
  3. 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
    
  4. References and Further Reading