在android 4.0 上面移植camera的一些心得 包括 单双camera 型号 hi253 gc0308 hi704 hm2055 ut2055

[html]  view plain copy
  1. <span style="font-family:Arial, Verdana, sans-serif;"><span style="WHITE-SPACE: normal">  
  2. span>span>  


[html]  view plain copy
  1. <span style="font-family:Arial, Verdana, sans-serif;BACKGROUND-COLOR: rgb(255,255,255); WHITE-SPACE: normal">目前在移植android下面的camera 现在大部分工作已经做完,想写一下自己的移植心得。。。。  
  2. span>  
首先要把一个型号的camera的移植到android的4.0上面,我认为应该要了解以下几点:

1:camera的硬件接口

2:camera的datashe一定要好好看看
3:要开始你的代码之旅了 在android4.0的kernel下面添加您的驱动
4:对于一些特效和效果会涉及到上层代码的修改 这里我也会说明一下。

第一:说明camera的硬件接口

      我想大家看见这样的camera接口,应该是很熟悉的了,呵呵 下面我就说说比较关键的几点:
1:是camera的上电时序 我的camera的上电时序的接口是在cpu的S5PV210_GPH2(2):GPH2(2)口是来控制camera的上电的时序的 请看下图




主要是来控制3.3v的上电 下面是我的上电时序的代码 不过这个也要看camera的datasheet才会知道的
[html]  view plain copy
  1. gpio_direction_output(S5PV210_GPH2(2), 1);  
  2.             msleep(20);  
  3.             gpio_direction_output(S5PV210_GPH2(2), 0);  
  4.             msleep(500);  

2:来看看第8个管教(PWDN)网络标号是:CAM_PD/GPJ4_4  有些人肯定会问为何要关注这个管教呐,呵呵 这个管脚是比较重要的哦
对于不同的camera 对这个管脚的高低电平是有要求的哦 一定要好好看看camera的datasheet。
以gc0308 为例在初始化的时候是要拉低的  gpio_direction_output(S5PV210_GPJ4(4), 0);
3:再来看看CAM_CLKOUT 这个管脚 这个是cpu提供的时钟 根据您的设置 我的设置是 24mhz 刚开始调试的时候 时钟老是出不来,我还以为是配置和其他的问题 最后发现是自己的cpu的管教没有配置好 呵呵 最低级的错误啊 代码的路径是:arch/arm/mach-s5pv210 里面的setup-fimc0.c文件 主要代码是 
[html]  view plain copy
  1. void s3c_fimc0_cfg_gpio(struct platform_device *pdev)  
  2. {  
  3.     int i = 0;  
  4.   
  5.   
  6.     /* CAM A port(b0010) : PCLK, VSYNC, HREF, DATA[0-4] */  
  7.     for (i = 0; i < 8; i++) {  
  8.         s3c_gpio_cfgpin(S5PV210_GPE0(i), S3C_GPIO_SFN(2));  
  9.         s3c_gpio_setpull(S5PV210_GPE0(i), S3C_GPIO_PULL_NONE);  
  10.     }  
  11.     /* CAM A port(b0010) : DATA[5-7], CLKOUT(MIPI CAM also), FIELD */  
  12.     for (i = 0; i < 5; i++) {   //主要是这个  
  13.         s3c_gpio_cfgpin(S5PV210_GPE1(i), S3C_GPIO_SFN(2));//把GPIO_E1配置为clk的输出模式  
  14.         s3c_gpio_setpull(S5PV210_GPE1(i), S3C_GPIO_PULL_NONE);  
  15.     }  
  16. 。。。。。  

4:有关camera的架构和流程我这里就不多说了 有兴趣的朋友可以看看我的另两篇博文  
S5PC100平台上Linux Camera驱动开发详解(一)

S5PC100平台上Linux Camera驱动开发详解(二)



这两篇博文对camera的架构有详细的讲解


开始说说对kenel里面的camera的配置吧

arch/arm/mach-s5pv210 里面的 mach-smdkv210.c有一段关于camera的配置 是这样的

[html]  view plain copy
  1. static struct ut2055_platform_data ut2055_plat = {  
  2.     .default_width = 640,  
  3.     .default_height = 480,  
  4.     .pixelformat = V4L2_PIX_FMT_YUYV,  
  5.     .freq = 24000000,   //48000000,  // what1  
  6.     .is_mipi = 0,  
  7. };  
  8.   
  9. static struct i2c_board_info ut2055_i2c_info = {  
  10.     I2C_BOARD_INFO("UT2055", 0x22 >> 1),  
  11.     .platform_data = &ut2055_plat,  
  12. };  
  13.   
  14. static struct s3c_platform_camera ut2055 = {  
  15.     .id     = CAMERA_PAR_A,  
  16.     .type       = CAM_TYPE_ITU,  
  17.     .fmt        = ITU_601_YCBCR422_8BIT,  
  18.     .order422   = CAM_ORDER422_8BIT_YCBYCR,// hi253,hi704  
  19. //  .order422   = CAM_ORDER422_8BIT_CBYCRY,// hm2055,gc0308  
  20.     .i2c_busnum = 1,  
  21.     .info       = &ut2055_i2c_info,  
  22.     .pixelformat    = V4L2_PIX_FMT_YUYV,  
  23.     .srclk_name = "mout_mpll",  
  24.     .clk_name   = "sclk_cam1",  
  25.     .clk_rate   = 24000000, //48000000,             /* 24MHz */  
  26.     .line_length    = 1600,              /* 640*480 */  
  27.     /* default resol for preview kind of thing */  
  28.     .width      = 640,  
  29.     .height     = 480,  
  30.     .window     = {  
  31.         .left   = 0,  
  32.         .top    = 0,  
  33.         .width  = 640,  
  34.         .height = 480,  
  35.     },  
  36.   
  37.     /* Polarity */  
  38.     .inv_pclk   = 0,  
  39.     .inv_vsync  = 1,  
  40.     .inv_href   = 0,  
  41.     .inv_hsync  = 0,  
  42.   
  43.     .initialized    = 0,  
  44.     .cam_power  = ut_cam0_power,  
  45. };  

[html]  view plain copy
  1. static struct s3c_platform_fimc fimc_plat_lsi = {  
  2.     .srclk_name = "mout_mpll",  
  3.     .clk_name   = "sclk_fimc",  
  4.     .lclk_name  = "fimc",   
  5.     .clk_rate   = 166750000,  
  6.     .default_cam    = CAMERA_PAR_A,  
  7.     .camera     = {  
  8.             &ut2055,  
  9.                 &ut2055,  
  10.     },  
  11.     .hw_ver     = 0x43,  
  12. };  

有人会问为何我配置两次ut2055 呵呵 应为我的是单双都支持的camera 如果上面胆码配置一个的话 点击后置camera会报错的哦


这个配置对于我的hi703 和hi253 和hm2055 以及gc0308 的配置是全部支持的 唯一的差别是order422的格式不一样 这个我已经在代码上有标志了 大家注意哦


5::主要的核心代码:drivers/media/video  里面需要添加 ut2055.c 和 ut2055.h
 由于代码量比较大 这里我就不贴出来了


6:drivers/media/video/samsung/fimc  这个路径的两个文件也是很重要的
比如:
fimc_capture.c 这个文件  的一个函数 比如:

[html]  view plain copy
  1. int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp)  
  2. {  
  3.     struct fimc_global *fimc = get_fimc_dev();  
  4.     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
  5.     fimc_dbg("%s: index %d\n", __func__, inp->index);  
  6.     if (inp->index < 0 || inp->index >= FIMC_MAXCAMS) {  
  7.         return -EINVAL;  
  8.     }  
  9.         gCameraId = inp->index;//这句话得目的是获取camera的id 也就是上层传先来的是camear 0 或是 camera 1 这样就知道你打开的是前置或是后置了,在ut2055.c里面就好区分了。  
  10.     if (!fimc->camera_isvalid[inp->index])  
  11.         {  
  12.             printk(" ::::fimc_enum_input erro:\n"); //如果你的camera是双的话 没有在第4歩的fimc_plat_lsi 里面的camera 的数组有两个&ut2055,的话打开camera 1 的时候 通常是前置camera 会进入这个错误的。  
  13.             return -EINVAL;  
  14.         }  
  15.     strcpy(inp->name, fimc->camera[inp->index].info->type);  
  16.     inp->type = V4L2_INPUT_TYPE_CAMERA;  
  17.     return 0;  
  18. }  
[html]  view plain copy
  1. pre>fimc_regs.c这个文件  的一个函数 比如:<pre class="html" name="code">extern int camera_Ycbcr_type; //这个变量是在ut2055.c文件里面又定义 和赋值 比如我检测到的camera是hi253,hi704 哪就是给camera_Ycbcr_type = 1;hm2055 gc0308 的是0 ,不同的camera的配置不一样的,在前面我说过了。  
  2.   
  3. int fimc_hwset_camera_source(struct fimc_control *ctrl)  
  4. {  
  5.     struct s3c_platform_camera *cam = ctrl->cam;  
  6.     u32 cfg = 0;  
  7.   
  8.         /* for now, we support only ITU601 8 bit mode */  
  9.   
  10.         if (camera_Ycbcr_type)  
  11.             cam->order422 = CAM_ORDER422_8BIT_YCBYCR;  
  12.         else  
  13.             cam->order422 = CAM_ORDER422_8BIT_CBYCRY;  
  14.   
  15.     /* for now, we support only ITU601 8 bit mode */  
  16.     cfg |= S3C_CISRCFMT_ITU601_8BIT;  
  17.     cfg |= cam->order422;  
  18.   
  19.     if (cam->type == CAM_TYPE_ITU)  
  20.         cfg |= cam->fmt;  
  21.   
  22.     cfg |= S3C_CISRCFMT_SOURCEHSIZE(cam->width);  
  23.     cfg |= S3C_CISRCFMT_SOURCEVSIZE(cam->height);  
  24.   
  25.     writel(cfg, ctrl->regs + S3C_CISRCFMT);  
  26.   
  27.     return 0;  
  28. }  
7:还有一个文件是不可少的:
include/media路径里面的是:ut2055_platform.h
[html]  view plain copy
  1. /*  
  2.  * This program is free software; you can redistribute it and/or modify  
  3.  * it under the terms of the GNU General Public License as published by  
  4.  * the Free Software Foundation; either version 2 of the License, or  
  5.  * (at your option) any later version.  
  6.  */  
  7.   
  8. struct ut2055_platform_data {  
  9.     unsigned int default_width;  
  10.     unsigned int default_height;  
  11.     unsigned int pixelformat;  
  12.     int freq;   /* MCLK in KHz */  
  13.   
  14.     /* This SoC supports Parallel & CSI-2 */  
  15.     int is_mipi;  
  16. };  
这个文件要在
arch/arm/mach-s5pv210 里面的 mach-smdkv210.c文件里面包含 #include


基本上在kernel里面的调试说完了 下一篇我说说在上层的一些调试吧:

在android 4.0 上面移植camera的一些心得 包括 单双camera 型号 hi253 gc0308 hi704 hm2055 ut2055 上层代码的调试

一、Camera 工作原理介绍
1. 结构 .

一般来说,camera 主要是由 lens 和 sensor IC 两部分组成,其中有的 sensor IC 集成 了 DSP,有的没有集成,但也需要外部 DSP 处理。细分的来讲,camera 设备由下边几部 分构成:

 1) lens(镜头) 一般 camera 的镜头结构是有几片透镜组成,分有塑胶透镜(Plastic)和玻璃透 镜(Glass) ,通常镜头结构有:1P,2P,1G1P,1G3P,2G2P,4G 等。

 2) sensor(图像传感器) Senor 是一种半导体芯片,有两种类型:CCD 和 CMOS。Sensor 将从 lens 上传导过来的光线转换为电信号, 再通过内部的 AD 转换为数字信号。 由于 Sensor 的每个 pixel 只能感光 R 光或者 B 光或者 G 光, 因此每个像素此时存贮的是单色的, 我们称之为 RAW DATA 数据。 要想将每个像素的 RAW DATA 数据还原成三基色,就需要 ISP 来处理。 

3)ISP(图像信号处理) 主要完成数字图像的处理工作,把 sensor 采集到的原始数据转换为显示支持 的格式。 

4)CAMIF(camera 控制器) 芯片上的 camera 接口电路,对设备进行控制,接收 sensor 采集的数据交给 CPU,并送入 LCD 进行显示。


2. 工作原理 .
外部光线穿过 lens 后, 经过 color filter 滤波后照射到 Sensor 面上, Sensor 将从 lens 上传导过来的光线转换为电信号,再通过内部的 AD 转换为数字信号。如果 Sensor 没有集 成 DSP,则通过 DVP 的方式传输到 baseband,此时的数据格式是 RAW DATA。如果集成 了 DSP, RAW DATA 数据经过 AWB、 则 color matrix、 lens shading、 gamma、 sharpness、 AE 和 de-noise 处理,后输出 YUV 或者 RGB 格式的数据。
最后会由 CPU 送到 framebuffer 中进行显示,这样我们就看到 camera 拍摄到的景象 了。

3. YUV 与 YCbCr .
YUV 和 RGB 一样,是色彩空间中常用的色彩模型之一,两者可以相互转换。YUV 中 得 Y 表示亮度,U 和 V 表示色度。与 RGB 相比,它的优点在于占用更少的空间。 YCbCr 则是在世界数字组织视频标准研制过程中作为 ITU - R BT601 建议的一部分, 其实是 YUV 经过缩放和偏移的翻版。 其中 Y 与 YUV 中的 Y 含义一致, Cb , Cr 同样都指色 彩, 只是在表示方法上不同而已。在 YUV 家族中, YCbCr 是在计算机系统中应用最多的成 员, 其应用领域很广泛,JPEG、 MPEG 均采用此格式。 一般人们所讲的 YUV 大多是指 YCbCr。 YCbCr 有许多取样格式, 如 4∶4∶4 , 4∶2∶2 , 4∶1∶1 和 4∶2∶0。

二、Camera 硬件
1. CAMIF .

如下是 S5PV210 的 camera 系统的结构图:



S5PV210 的 camera 接口控制器叫 FIMC4.3,它支持 ITU R BT-601/656、AXI 和 MIPI(CSI)三种接口方式,最大输入像素是 8192*8192。S5PV210 有三组 camera 接口。

主要特性: 支持多种输入接口类型:



ITU-R BT 601/656 模式 DMA(AXI 64 位)模式 MIPI(CSI)模式 Direct FIFO 模式 支持多种输出接口:DMA 模式/Direct FIFO 模式 支持数码调焦(DZI) 最大输入像素 8192*8192 支持图像翻转、旋转等处理效果 生成多种图片格式 支持采集帧控制

2. 接口信号 .

FIMC 信号定义如下所示(YCbCr 模式)

Signal

VSYNC HREF PCLK DATA[7:0] FIELD CAM_MCLK I I I I


I/O
帧同步信号 行同步信号 像素时钟 像素数据 FIELD 信号

Description

Type

Muxed

O O

系统时钟信号



通过 CAM_MCLK 给摄像头提供时钟,RST 是复位线,PWDN 在摄像头工作时应该始终 为低。HREF 是行参考信号,PCLK 是像素时钟,VSYNC 是场同步信号。一旦给摄像头提供了 时钟,并且复位摄像头,摄像头就开始工作了,通过 HREF,PCLK 和 VSYNC 同步传输数字图 像信号。数据是通过 DATA0~DATA7 这八根数据线并行送出的。

3. 工作时序 .
FIMC43 支持如下两种视频数据:

ITU-R BT 601 输入时序图 这种方式下行和帧同步信号独立于视频数据,因此需要同步信号。



ITU-R BT 656 输入时序图



这种方式下同步信号已经内嵌到视频数据中了,因此不需要额外的行和帧同步信号。

(ITU-R BT 601: 16 位数据传输;21 芯;Y、U、V 信号同时传输。 ITU-R BT 656: 9 芯,不需要同步信号;8 位数据传输;串行视频传输;传输速率是 601 的 2 倍;先传 Y, 后传 UV。 )

同步信号的时延参数 t1:表示 VSYNC 前、后插入周期 t2:表示 HREF 前插入周期 t3:表示 HREF 宽度 t4:表示 HREF 后插入周期



4. 外部接口 . 外部接口
硬件原理图的 CAM A 部分:

CAM B 部分

5. Camera 内部结构图 .
下图是 camera 内部结构框图,以 OV sensor 为例:

三、Camera 驱动
1. V4L2 .

1)简介 ) 在 Linux 中,摄像头方面的标准化程度比较高,这个标准就是 V4L2 驱动程序,这也是 业界比较公认的方式。 V4L 全称是 Video for Linux,是 Linux 内核中标准的关于视频驱动程序,目前使用比 较多的版本是 Video for Linux 2, 简称 V4L2。 它为 Linux 下的视频驱动提供了统一的接口, 使得应用程序可以使用统一的 API 操作不同的视频设备。从内核空间到用户空间,主要的 数据流和控制类均由 V4L2 驱动程序的框架来定义。 V4L2 驱动程序一般只提供 Video 数据的获得,而如何实现视频预览,如何向上层发送 数据,如何把纯视频流和取景器、视频录制等实际业务组织起来,都是 camera 的硬件抽象 层需要负责的工作。

 V4L2 驱动核心实现为如下文件:drivers/media/video/v4l2-dev.c。 V4l2-dev.h 中定义的 video_device 是 V4L2 驱动程序的核心数据结构,它为具体的摄 像头 sensor 驱动提供了接口调用。 V4l2 的采集过程(应用程序):

1)打开设备,获得文件描述符; 

2) 设置图片格式;

3) 分配缓冲区;

4)启动采集过程,读取数据;

5) 停止采集,关闭设备。


2)数据结构 )

 V4L2 的主要数据结构是 video_device,定义在 v4l2_dev.h 中:

struct video_device { 

/* device ops */ 

const struct v4l2_file_operations *fops; /*接口函数指针*/


/* sysfs */

 struct device dev; struct cdev *cdev; /* v4l 设备结构 */ 

/* 字符设备结构*/


/* Set either parent or v4l2_dev if your driver uses v4l2_device */ 

struct device *parent; struct v4l2_device *v4l2_dev; /* 设备父指针 */

/* v4l2 设备指针*/


/* device info */ 

char name[32]; 

int vfl_type; /* 'minor' is set to -1 if the registration failed */ 

int minor; u16 num; /* use bitops to set/clear/test flags */ 

unsigned long flags; /* attribute to differentiate multiple indices on one physical device */ 

int index; /*次设备号*/ 

/*设备名称*/


/* V4L2 file handles */ 

spinlock_t fh_lock; /* Lock for all v4l2_fhs */


struct list_head fh_list; /* List of struct v4l2_fh */

int debug;

/* debug 级别*/

/* Video 标准变量 */ 

v4l2_std_id tvnorms; /* Supported tv norms */


v4l2_std_id current_norm; /* Current tvnorm */

/* 回调函数 */ 

void (*release)(struct video_device *vdev);


/* ioctl 回调函数 */ 

const struct v4l2_ioctl_ops *ioctl_ops; 

};


主要接口函数有: int video_register_device(struct video_device *vdev, int type, int nr);

static int v4l2_ioctl(struct inode *inode, struct file *filp, long arg);

unsigned int cmd, unsigned

2. FIMC
1)简介 ) FIMC 这个模块不仅仅是一个摄像头的控制接口,它还承担着 V4L2 的 output 功能和 overlay 的功能。 FIMC 的驱动在内核中的位置:drivers/media/video/samsung/fimc 它包含下边的文件:
fimc_regs.c fimc_capture.c fimc_dev.c fimc_output.c fimc_overlay.c fimc_v4l2.c

它们的组织关系如下:

可以看到,FIMC 的驱动实现了 v4l2 所有的接口,可以分为 v4l2-input 设备接口, v4l2-output 设备接口以及 v4l2-overlay 设备接口。这里我们主要关注 v4l2-input 设备接口, 因为摄像头属于视频输入设备。 fimc_v4l2.c 里面注册了很多的回调函数,都是用于实现 v4l2 的标准接口的,但是这些 回调函数基本上都不是在 fimc_v4l2.c 里面实现的,而是有相应的.c 分别去实现。比如:

v4l2-input 设备的操作实现: fimc_capture.c v4l2-output 

设备的操作实现: fimc_output.c v4l2-overlay 

设备的操作实现: fimc_overlay.c


这些代码其实都是和具体硬件操作无关的, 这个驱动把所有操作硬件寄存器的代码都写 到一个文件里面了,就是 fimc40_regs.c。这样把硬件相关的代码和硬件无关的代码分开来 实现是非常好的方式,可以最大限度的实现代码复用。

 2) 数据结构 ) FIMC 的主要数据结构 fimc_control,定义在 fimc.h 中:


struct fimc_control {
        int                             id;             /* controller id */
        char                            name[16];
        atomic_t                        in_use;
        void __iomem                    *regs;          /* register i/o */
        struct clk                      *clk;           /* interface clock */
        struct regulator        *regulator;             /* pd regulator */
        struct fimc_meminfo             mem;            /* for reserved mem */


        /* kernel helpers */
        struct mutex                    lock;           /* controller lock */
        struct mutex                    alloc_lock;
        struct mutex                    v4l2_lock;
        wait_queue_head_t               wq;
        struct device                   *dev;
        int                             irq;


        /* v4l2 related */
        struct video_device             *vd;
        struct v4l2_device              v4l2_dev;


        /* fimc specific */
        struct fimc_limit               *limit;         /* H/W limitation */
        struct s3c_platform_camera      *cam;           /* activated camera */
        struct fimc_capinfo             *cap;           /* capture dev info */
        struct fimc_outinfo             *out;           /* output dev info */
        struct fimc_fbinfo              fb;             /* fimd info */
        struct fimc_scaler              sc;             /* scaler info */
        struct fimc_effect              fe;             /* fimc effect info */


        enum fimc_status                status;
        enum fimc_log                   log;


        u32                             ctx_busy[FIMC_MAX_CTXS];
};


因为 FIMC 一共有三套一样的控制器(fimc0, fimc1, fimc2) ,所以驱动里使用了一个数组来描述:: 

struct video_device fimc_video_device[FIMC_DEVICES] = { 

[0] = { .fops = &fimc_fops, .ioctl_ops = &fimc_v4l2_ops, .release = fimc_vdev_release, }, 

[1] = { .fops = &fimc_fops, .ioctl_ops = &fimc_v4l2_ops, .release = fimc_vdev_release, }, 

[2] = { .fops = &fimc_fops, .ioctl_ops = &fimc_v4l2_ops, .release = fimc_vdev_release, }, 

};


fb_ops 结构体是针对 v4l2 设备的基本操作,定义如下:

static const struct v4l2_file_operations fimc_fops = { 

            .owner  = THIS_MODULE,

             .open = fimc_open, 

             .release  = fimc_release,

             .ioctl = video_ioctl2,

             .read = fimc_read,

             .write = fimc_write,

             .mmap = fimc_mmap,

             .poll = fimc_poll,

}; 

3)FIMC 初始设置 

) 在 S5PV210 中, FIMC 初始设置代码在 /drivers/ arch/arm/mach-s5pv210/mach-t34h.c 中:

static struct s3c_platform_fimc fimc_plat_lsi = {
        .srclk_name     = "mout_mpll",
        .clk_name       = "sclk_fimc",
        .lclk_name      = "sclk_fimc_lclk",
        .clk_rate       = 166750000,
#if defined(CONFIG_VIDEO_S5K4EA)
        .default_cam    = CAMERA_CSI_C,
#else
#ifdef CAM_ITU_CH_A
        .default_cam    = CAMERA_PAR_A,
#else
        .default_cam    = CAMERA_PAR_B,
#endif
#endif
        .camera         = {
#ifdef CONFIG_VIDEO_S5K4ECGX
                        &s5k4ecgx,
#endif
#ifdef CONFIG_VIDEO_S5KA3DFX
                        &s5ka3dfx,
#endif
#ifdef CONFIG_VIDEO_S5K4BA
                        &s5k4ba,
#endif
#ifdef CONFIG_VIDEO_S5K4EA
                        &s5k4ea,
#endif
#ifdef CONFIG_VIDEO_HM2055
                        &hm2055,
#endif
#ifdef CONFIG_VIDEO_GC0308
                        &gc0308,
#endif
#ifdef CONFIG_VIDEO_HIMAX2055
                        &himax2055,
#endif
#ifdef CONFIG_VIDEO_ADV7181
                        &adv7181,
#endif
        },
        .hw_ver         = 0x43,
};



对于 GPIO 的配置代码在 /drivers/ arch/arm/mach-s5pv210/setup-fimc0.c 中:

void s3c_fimc0_cfg_gpio(struct platform_device *pdev) { 

int i = 0;


/* CAM A port(b0010) : PCLK, VSYNC, HREF, DATA[0-4] */ 

for (i = 0; i < 8; i++) { 

s3c_gpio_cfgpin(S5PV210_GPE0(i), S3C_GPIO_SFN(2)); 

s3c_gpio_setpull(S5PV210_GPE0(i), S3C_GPIO_PULL_NONE);

 } 

/* CAM A port(b0010) : DATA[5-7], CLKOUT(MIPI CAM also), FIELD */ 


for (i = 0; i < 5; i++) { 

s3c_gpio_cfgpin(S5PV210_GPE1(i), S3C_GPIO_SFN(2)); 

s3c_gpio_setpull(S5PV210_GPE1(i), S3C_GPIO_PULL_NONE); 

} /* CAM B port(b0011) : DATA[0-7] */ 


for (i = 0; i < 8; i++) { 

s3c_gpio_cfgpin(S5PV210_GPJ0(i), S3C_GPIO_SFN(3));

 s3c_gpio_setpull(S5PV210_GPJ0(i), S3C_GPIO_PULL_NONE); 

} /* CAM B port(b0011) : PCLK, VSYNC, HREF, FIELD, CLCKOUT */ 


for (i = 0; i < 5; i++) { 

s3c_gpio_cfgpin(S5PV210_GPJ1(i), S3C_GPIO_SFN(3)); 

s3c_gpio_setpull(S5PV210_GPJ1(i), S3C_GPIO_PULL_NONE); 

}


4)接口函数 ) 

FIMC 的主要回调函数如下,实现在 fimc_v4l2.c 中:


const struct v4l2_ioctl_ops fimc_v4l2_ops = {
        .vidioc_querycap                = fimc_querycap,
        .vidioc_reqbufs                 = fimc_reqbufs,
        .vidioc_querybuf                = fimc_querybuf,
        .vidioc_g_ctrl                  = fimc_g_ctrl,
        .vidioc_s_ctrl                  = fimc_s_ctrl,
        .vidioc_s_ext_ctrls             = fimc_s_ext_ctrls,
        .vidioc_cropcap                 = fimc_cropcap,
        .vidioc_g_crop                  = fimc_g_crop,
        .vidioc_s_crop                  = fimc_s_crop,
        .vidioc_streamon                = fimc_streamon,
        .vidioc_streamoff               = fimc_streamoff,
        .vidioc_qbuf                    = fimc_qbuf,
        .vidioc_dqbuf                   = fimc_dqbuf,
        .vidioc_enum_fmt_vid_cap        = fimc_enum_fmt_vid_capture,
        .vidioc_g_fmt_vid_cap           = fimc_g_fmt_vid_capture,
        .vidioc_s_fmt_vid_cap           = fimc_s_fmt_vid_capture,
        .vidioc_try_fmt_vid_cap         = fimc_try_fmt_vid_capture,
        .vidioc_enum_input              = fimc_enum_input,
        .vidioc_g_input                 = fimc_g_input,
        .vidioc_s_input                 = fimc_s_input,
        .vidioc_g_parm                  = fimc_g_parm,
        .vidioc_s_parm                  = fimc_s_parm,
        .vidioc_queryctrl               = fimc_queryctrl,
        .vidioc_querymenu               = fimc_querymenu,
        .vidioc_g_fmt_vid_out           = fimc_g_fmt_vid_out,
        .vidioc_s_fmt_vid_out           = fimc_s_fmt_vid_out,
        .vidioc_try_fmt_vid_out         = fimc_try_fmt_vid_out,
        .vidioc_g_fbuf                  = fimc_g_fbuf,
        .vidioc_s_fbuf                  = fimc_s_fbuf,
        .vidioc_try_fmt_vid_overlay     = fimc_try_fmt_overlay,
        .vidioc_g_fmt_vid_overlay       = fimc_g_fmt_vid_overlay,
        .vidioc_s_fmt_vid_overlay       = fimc_s_fmt_vid_overlay,
};
                                                              


5)寄存器操作(fimc_regs.c) )寄存器操作( )

对于寄存器的操作,实现都在 fimc_regs.c 文件中,如

int fimc_hwset_camera_source(struct fimc_control *ctrl) {


 struct s3c_platform_camera *cam = ctrl->cam; u32 cfg = 0;


cfg |= S3C_CISRCFMT_ITU601_8BIT; cfg |= cam->order422;

if (cam->type == CAM_TYPE_ITU)

cfg |= cam->fmt;

cfg |= S3C_CISRCFMT_SOURCEHSIZE(cam->width); 

cfg |= S3C_CISRCFMT_SOURCEVSIZE(cam->height);


writel(cfg, ctrl->regs + S3C_CISRCFMT);

return 0; 

}


int fimc_hwset_enable_irq(struct fimc_control *ctrl, int overflow, int level) { 

u32 cfg = readl(ctrl->regs + S3C_CIGCTRL);


cfg &= ~(S3C_CIGCTRL_IRQ_OVFEN | S3C_CIGCTRL_IRQ_LEVEL); 

cfg |= S3C_CIGCTRL_IRQ_ENABLE;


if (overflow) cfg |= S3C_CIGCTRL_IRQ_OVFEN;

if (level) cfg |= S3C_CIGCTRL_IRQ_LEVEL;

writel(cfg, ctrl->regs + S3C_CIGCTRL);

return 0; 

}


3. Sensor 驱动

1)简介, 

)简介 本方案中使用了两个摄像头模组: MT9P111 和 S5K6AAFX。 其中 MT9P111 是 APTINA 公司推出的 1/4 英寸光学格式 5M 单芯片传感器,用作后摄像头;S5K6AAFX 是三星出的 1.3M CMOS 高清图像传感器,用作前摄像头。 

2)参数设置 

)参数设置 MT9P111 的参数设置

#ifdef MT9P111_ENABLED 

static struct mt9p111_platform_data mt9p111_plat = { 

.default_width = 1024, 

.default_height = 600, 

.pixelformat = V4L2_PIX_FMT_UYVY, 

.freq = 24000000, 

.is_mipi = 0, 

}; 


static struct i2c_board_info mt9p111_i2c_info = { 

I2C_BOARD_INFO("MT9P111", 0x3D),//0x7a,0x7b .

platform_data = &mt9p111_plat, 

}; 


static struct s3c_platform_camera mt9p111 = { 

.id = CAMERA_PAR_A,

.type = CAM_TYPE_ITU,

.fmt =  = ITU_601_YCBCR422_8BIT,


.order422 = CAM_ORDER422_8BIT_CBYCRY, 

.i2c_busnum 

.info = 7,


= &mt9p111_i2c_info, = V4L2_PIX_FMT_UYVY, = "xusbxti",

.pixelformat .srclk_name

.clk_name = "sclk_cam0",

.clk_rate = 24000000,

.line_length 

.width 

.height

.window 

.left = 0, 

.top = 0, 

.width 

.height 

}, = 1024, = 600, = 1920, = 1024, = 600, ={


/* Polarity */ .inv_pclk = 0, .inv_vsync .inv_href = 0, .inv_hsync = 0, = 0,

.initialized = 0, .cam_power }; #endif = smdkv210_cam0_power,

S5K6AAFX 的参数设置

#ifdef S5K6AAFX_ENABLED 

static struct s5k6aafx_platform_data s5k6aafx_plat = { 

.default_width = 800, 

.default_height = 600,

 .pixelformat = V4L2_PIX_FMT_YUYV, 

.freq = 24000000,


.is_mipi = 0, 

}; 

static struct i2c_board_info s5k6aafx_i2c_info = {


I2C_BOARD_INFO("s5k6aafx", 0x3c), 

.platform_data = &s5k6aafx_plat,

 }; 


static struct s3c_platform_camera s5k6aafx = { 

.id 

.type 

.fmt = CAMERA_PAR_B, = CAM_TYPE_ITU, = ITU_601_YCBCR422_8BIT,


.order422 = CAM_ORDER422_8BIT_YCBYCR, .i2c_busnum .info = 4,

= &s5k6aafx_i2c_info, = V4L2_PIX_FMT_YUYV, = "xusbxti",

.pixelformat .srclk_name

.clk_name = "sclk_cam1", .clk_rate = 24000000, .line_length = 1280,

/* default resol for preview kind of thing */ 

.width .height 

.window .left = 0, 

.top = 0, .width 

.height }, /* Polarity */

 .inv_pclk = 0, 

.inv_vsync = 0, = 800, = 600, = 800, = 600, ={


.inv_href = 0, 

.inv_hsync = 0,


.initialized = 0, 

.cam_power }; 

#endif = smdkv210_cam1_power,


3)数据结构 )

(未注释)

struct v4l2_subdev { 

struct list_head list; 

struct module *owner; 

u32 flags; 

struct v4l2_device *v4l2_dev; 

const struct v4l2_subdev_ops *ops; /* name must be unique */ 

char name[V4L2_SUBDEV_NAME_SIZE]; /* can be used to group similar subdevs, value is driver-specific */ 

u32 grp_id; /* pointer to private data */ 

void *priv;

 }; 

#endif


4)接口函数 )

(未注释)

static const struct v4l2_subdev_core_ops mt9p111_core_ops = { 

.init = mt9p111_init, /* initializing API */


.s_config = mt9p111_s_config, /* Fetch platform data */ 

.queryctrl = mt9p111_queryctrl, 

.querymenu = mt9p111_querymenu,

 .g_ctrl = mt9p111_g_ctrl, 

.s_ctrl = mt9p111_s_ctrl,

 };


static const struct v4l2_subdev_video_ops mt9p111_video_ops = { 

// .s_crystal_freq = mt9p111_s_crystal_freq, 

.g_fmt = mt9p111_g_fmt, 

.s_fmt = mt9p111_s_fmt,

 .enum_framesizes = mt9p111_enum_framesizes, // //

 .enum_frameintervals = mt9p111_enum_frameintervals, 

.enum_fmt = mt9p111_enum_fmt, 

.try_fmt = mt9p111_try_fmt, 

.g_parm = mt9p111_g_parm, 

.s_parm = mt9p111_s_parm, 

.s_stream = mt9p111_s_stream, };


static const struct v4l2_subdev_ops mt9p111_ops = { 

.core = &mt9p111_core_ops, 

.video = &mt9p111_video_ops, 

};

 #endif


你可能感兴趣的:(210)