现在ov9650驱动里的probe和s_config函数的调用时间和功能都已经清楚了,还剩下一个ov9650_init函数还没有被调用。其实我们可以在任何希望调用它的时候利用v4l2_subdev_call来调用这init方法。不过在摄像头控制器的驱动里面已经有相应的地方调用了,就是在fimc_capture.c里面,有一个静态函数fimc_init_camera,这里会调用:
178 /* subdev call for init */
179 ret = v4l2_subdev_call(cam->sd, core, init, 0);
180 if (ret == -ENOIOCTLCMD) {
181 fimc_err("%s: init subdev api not supported\n", __func__);
182 return ret;
183 }
这时ov9650.c里的ov9650_init就会被调到了。Ov9650_init做的工作其实就是初始化摄像头的寄存器,初始化可以有两种方法,一个是通过sccb.c里面提供的方法(gpio模拟i2c),另一个就是直接利用内核提供的i2c总线数据读写方法来操作,我们的代码里两种方法都实现了,不过用sccb更稳妥一些,因为不知道什么原因,直接操作i2c总线有时候会失败,这个问题仍需解决。fimc_init_camera这个函数可能会在fimc_s_input或者fimc_streamon_capture两个函数中被调用。也就是当应用程序中调用ioctl( v4l2_fd, VIDIOC_S_INPUT, &index )或者ioctl(v4l2_fd, VIDIOC_STREAMON, &type)时都有可能调用到fimc_init_camera。,当然它只会被调用一次。
还有最后一个问题就是何时给摄像头发送复位信号(原理图上第4管脚,CAM_RST),因为摄像头只有接到复位信号(高电平或者低电平)才能正常工作。我们这里是在打开v4l2设备的时候,也就是open(“/dev/video0”, RD_WR)时复位的,具体就是在fimc_dev.c里对应得v4l2的open方法:fimc_open:
653 if (pdata->hw_ver == 0x40)
654 fimc_hw_reset_camera(ctrl);
这个fimc_hw_reset_camera就是复位函数,定义在fimc40_reg.c中:
1113 int fimc_hw_reset_camera(struct fimc_control *ctrl)
1114 {
1115 u32 cfg;
1116
1117 #ifdef CONFIG_VIDEO_OV9650
1118 /* high reset */
1119 cfg = readl(ctrl->regs + S3C_CIGCTRL);
1120 cfg |= S3C_CIGCTRL_CAMRST_A;
1121 writel(cfg, ctrl->regs + S3C_CIGCTRL);
1122 mdelay(20);
1123
1124 cfg = readl(ctrl->regs + S3C_CIGCTRL);
1125 cfg &= ~S3C_CIGCTRL_CAMRST_A;
1126 writel(cfg, ctrl->regs + S3C_CIGCTRL);
1127 udelay(2000);
1128 #endif
1129 #ifdef CONFIG_VIDEO_OV9655
1130 /* low reset */
1131 cfg = readl(ctrl->regs + S3C_CIGCTRL);
1132 cfg &= ~S3C_CIGCTRL_CAMRST_A;
1133 writel(cfg, ctrl->regs + S3C_CIGCTRL);
1134 mdelay(20);
1135
1136 cfg = readl(ctrl->regs + S3C_CIGCTRL);
1137 cfg |= S3C_CIGCTRL_CAMRST_A;
1138 writel(cfg, ctrl->regs + S3C_CIGCTRL);
1139 udelay(2000);
}
因为ov9650是高电平复位,ov9655是低电平复位,所以需要分开来写。
5. 应用程序如何操作摄像头
细节请参考代码:ov9650_v4l2.c
操作摄像头需要符合v4l2的标准接口,接口描述及示例请参考v4l2官网