4-3 摄像头的初始化流程及v4l2子设备驱动
这个问题弄清楚了以后下面就来看获得Camera信息以后如何做后续的处理:
在fimc_init_global调用结束之后我们获得了OV9650的信息,之后在probe函数里面就会继续调用一个函数:fimc_configure_subdev().
这个函数的实现如下:
/*
* Assign v4l2 device and subdev to fimc
* it is called per every fimc ctrl registering
*/
static int fimc_configure_subdev(struct platform_device *pdev, int id)
{
struct s3c_platform_fimc *pdata;
struct s3c_platform_camera *cam;
struct i2c_adapter *i2c_adap;
struct i2c_board_info *i2c_info;
struct v4l2_subdev *sd;
struct fimc_control *ctrl;
unsigned short addr;
char *name;
int cfg;
ctrl = get_fimc_ctrl(id);
pdata = to_fimc_plat(&pdev->dev);
cam = pdata->camera[id];
/* Subdev registration */
if (cam) {
i2c_adap = i2c_get_adapter(cam->i2c_busnum);
// 省略结果判断语句
i2c_info = cam->info;
// 省略结果判断语句
name = i2c_info->type;
// 省略结果判断语句
addr = i2c_info->addr;
// 省略结果判断语句
/*
* NOTE: first time subdev being registered,
* s_config is called and try to initialize subdev device
* but in this point, we are not giving MCLK and power to subdev
* so nothing happens but pass platform data through
*/
sd = v4l2_i2c_new_subdev_board(&ctrl->v4l2_dev, i2c_adap,name, i2c_info, &addr);
if (!sd) {
fimc_err("%s: v4l2 subdev board registering failed\n",
__func__);
}
/* Assign camera device to fimc */
fimc_dev->camera[cam->id] = cam;
/* Assign subdev to proper camera device pointer */
fimc_dev->camera[cam->id]->sd = sd;
return 0;
}
这里面涉及到一些内核中I2C总线的操作,因为OV9650本身从总线的角度来讲可以看做是一个I2C的设备。实际上刚才分析平台数据的时候忽略了一个重要的信息,就是camera_c里面有一个成员是info,类型为struct i2c_board_info,熟悉Linux内核I2C驱动架构就应该知道i2c_board_info是用来描述一个I2C设备。平台代码里是这样定义的:
/* Add by ys for ov9650 sensor */
static struct ov9650_platform_data ov9650 = {
.default_width = 640,
.default_height = 480,
/* ITU-R BT 601: 16 */
.pixelformat = V4L2_PIX_FMT_YUYV, // 16 YUV 4:2:2
.freq = 22000000, // 24MHz
.is_mipi = 0, // Don't use MIPI-CSI-2
};
static struct i2c_board_info camer