Camera driver analysis

Linux version:4.19

Sensor: OV13850

(1) Load and unload functions

//DTS match table
static const struct of_device_id ov13850_of_match[] = {
{.compatible = “omnivision,ov13850-v4l2-i2c-subdev”},

MODULE_DEVICE_TABLE(i2c, ov13850_id);

static struct i2c_driver ov13850_i2c_driver = {
.driver = {
.name = ov13850_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = ov13850_of_match
.probe = ov13850_probe,
.remove = ov13850_remove,
.id_table = ov13850_id,

OV13850 is controlled by I2C interface, so use i2c_driver for registration.


static int ov13850_probe(struct i2c_client *client,
const struct i2c_device_id *id)
dev_info(&client->dev, “probing…\n”);

ov13850_filltimings(&ov13850_custom_config); //fill timing information
v4l2_i2c_subdev_init(&, client, &ov13850_camera_module_ops); //initialize v4l2_subdev |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ov13850.custom = ov13850_custom_config;

dev_info(&client->dev, “probing successful\n”);
return 0;
The above mainly fills the timing information according to the information in the global variable ov13850_custom_config. Then initialize v4l2_subdev, ov13850 is an I2C interface, so use v4l2_i2c_subdev_init for initialization. v4l2_i2c_subdev_init is the encapsulation of v4l2_subdev_init.

static struct v4l2_subdev_ops ov13850_camera_module_ops = {
.core = &ov13850_camera_module_core_ops, //Core operations
.video = &ov13850_camera_module_video_ops, //video操作
.pad = &ov13850_camera_module_pad_ops

static struct ov_camera_module_custom_config ov13850_custom_config = {
.start_streaming = ov13850_start_streaming, //sensor starts to output data stream
.stop_streaming = ov13850_stop_streaming, //sensor stops output data stream
.s_ctrl = ov13850_s_ctrl,
.s_ext_ctrls = ov13850_s_ext_ctrls, //sensor control (set automatic exposure control)
.g_ctrl = ov13850_g_ctrl,
.g_timings = ov13850_g_timings, //Get sensor timing
.check_camera_id = ov13850_check_camera_id, //读取Sensor ID
.s_vts = ov13850_auto_adjust_fps, //Automatically adjust the refresh rate
.set_flip = ov13850_set_flip, //Set sensor image
#ifdef OV13850_ONE_LANE
.configs = ov13850_onelane_configs, //Configuration information of single lane (resolution, refresh rate, etc.)
.num_configs = ARRAY_SIZE(ov13850_onelane_configs),

.configs = ov13850_configs, //Multi-lane configuration information
.num_configs = ARRAY_SIZE(ov13850_configs),
.power_up_delays_ms = {5, 20, 0},
*0: Exposure time valid fileds; exposure time
*1: Exposure gain valid fileds; Exposure gain
*(2 fileds == 1 frames)
.exposure_valid_frame = {4, 4}
The callbacks set above are basically to set registers.

(3) Open the data stream

static int ov13850_start_streaming(struct ov_camera_module *cam_mod)
int ret = 0;

“active config=%s\n”, cam_mod->active_config->name);

ret = ov13850_g_VTS(cam_mod, &cam_mod->vts_min);
if (IS_ERR_VALUE(ret))
goto err;

ret = ov_camera_module_write_reg(cam_mod, 0x0100, 1); //write 0x0100 register, select streaming mode 0:standby 1:streaming
if (IS_ERR_VALUE(ret))
goto err;


return 0;
ov_camera_module_pr_err(cam_mod, “failed with error (%d)\n”,
return ret;
The main thing is to operate the register and open the data stream transmission. Some other operation functions are basically similar.


We can see from the above content that the driver on the sensor side is not particularly complicated, mainly related to some parameters and control. The sensor is mainly the production data, and the data processing is mainly handed over to the ISP.

Reviewing Editor: Liu Qing

Leave a Reply

Your email address will not be published.