imx6之camera mipi

来源:互联网 发布:php实现断点续传 编辑:程序博客网 时间:2024/05/22 16:49
1.IPU
imx6qp有2个IPU,每个IPU有2个CSI,这个CSI并不是MIPI-CSI,是内部的功能模块。


static struct mipi_csi2_platform_data mipi_csi2_pdata = {
.chans = 4,//max is 4
.chans_data = {
{
.ipu_id  = 0,
.csi_id = 0,
.v_channel = 0,


},
{
.ipu_id  = 0,
.csi_id = 1,
.v_channel = 1,


},
{
.ipu_id  = 1,
.csi_id = 0,
.v_channel = 2,


},
{
.ipu_id  = 1,
.csi_id = 1,
.v_channel = 3,


},
},
.lanes = 4,
.dphy_clk = "mipi_pllref_clk",
.pixel_clk = "emi_clk",
};


imx6的mipi根据上面这个结构体,判断每个IPU,和每个CSI和对应的虚拟通道V_CHANNEL,最终会放到static struct mipi_csi2_info *gmipi_csi2;里面。


2.关于摄像头的master的生成

根据下面的这个结构体确定catpure模块的IPU,CSI参数,必须和上面对应才行。每次imx6q_add_v4l2_capture(0, &capture_data[0]);都会生成一个/dev/video设备

static struct fsl_mxc_capture_platform_data capture_data[] = {
{
.csi = 0,
.ipu = 0,
.mclk_source = 0,
.is_mipi = 1,
}, 
{
.csi = 1,
.ipu = 0,
.mclk_source = 0,
.is_mipi = 1,
},
{
.csi = 0,
.ipu = 1,
.mclk_source = 0,
.is_mipi = 1,
},
{
.csi = 1,
.ipu = 1,
.mclk_source = 0,
.is_mipi = 1,
},
};


每个master对应一个cam_data, 每个master对应一个/dev/video

video_set_drvdata(cam->video_dev, cam);video的驱动数据指向cam_data
dev_set_drvdata(&pdev->dev, (void *)cam);平台的私有数据指向cam_data
cam->self->priv = cam;//master的私有数据指向cam


master的名字生成在init_camera_struct()函数里面

if (cam->ipu_id == 0){
sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi);
}
else{
sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi + 2);
}

cam->self->type = v4l2_int_type_master;
cam->self->u.master = &mxc_v4l2_master;


会根据IPU和CSI生成master的名字为“”mxc_v4l2_cap*”


3.master的注册

在mxc_v4l2_probe()函数里面v4l2_int_device_register(cam->self);注册v4l2_int_device,类型是V4L2_INT_TYPE_MASTER,名字是mxc_v4l2_cap%d,
master的struct v4l2_int_master指向static struct v4l2_int_master mxc_v4l2_master;

4.master的attach连接函数


static int mxc_v4l2_master_attach(struct v4l2_int_device *slave)
主要就是判断一下slaver的ipu,csi的参数与master是否一致,并且根据自己已经匹配的slaver数目基础上,增加现有的slave.

一个master可以挂很多slaver,会根据sensor_index来判断

if (cam->sensor_index < MXC_SENSOR_NUM) {
cam->all_sensors[cam->sensor_index] = slave;
cam->sensor_index++;
} else {
pr_err("ERROR: v4l2 capture: slave number exceeds the maximum.\n");
return -1;
}


5.slave的生成

首先有个static struct sensor_data ov5640_data;来存放sensor数据,

slave
static struct v4l2_int_slave ov5640_slave = {
.ioctls = ov5640_ioctl_desc,
.num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc),
};


static struct v4l2_int_device ov5640_int_device = {
.module = THIS_MODULE,
.name = "ov5640",
.type = v4l2_int_type_slave,
.u = {
.slave = &ov5640_slave,
},
};


注:


ov5640_data.mclk = 24000000; /* 6 - 54 MHz, typical 24MHz */
ov5640_data.mclk = plat_data->mclk;
ov5640_data.mclk_source = plat_data->mclk_source;
ov5640_data.ipu_id = plat_data->ipu_id;
ov5640_data.csi = plat_data->csi;
ov5640_data.io_init = plat_data->io_init;




ov5640_data.i2c_client = client;
ov5640_data.pix.pixelformat = V4L2_PIX_FMT_UYVY;
ov5640_data.pix.width = 640;
ov5640_data.pix.height = 480;
ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
  V4L2_CAP_TIMEPERFRAME;
ov5640_data.streamcap.capturemode = 0;
ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
ov5640_data.streamcap.timeperframe.numerator = 1;
ov5640_data.is_mipi = 1;
这里初始化了slave的ipu和CSI,在与master匹配的时候,也会匹配这些参数


ov5640_int_device.priv = &ov5640_data;slave的私有数据指向sensor_data


v4l2_int_device_register(&ov5640_int_device);注册了的slver


6,slave和master的匹配

每次v4l2_int_device_register()的时候都讲v4l2_int_device挂在
list_add(&d->head, &int_list);,int_list链表上面,只是v4l2_int_device的类型有v4l2_int_type_maste和v4l2_int_type_slave.

v4l2_int_device_try_attach_all();
每个master都去匹配slver如果可以匹配成功,就调用master的attatch()函数。并将slaver的master指向master


s->u.slave->master = m;
if (m->u.master->attach(s)) {
s->u.slave->master = NULL;
module_put(m->module);
continue;
原创粉丝点击