深入学习Linux摄像头系列
深入学习Linux摄像头(四)三星平台fimc驱动详解
文章目录
一、硬件接口
-
摄像头
摄像头传感器由摄像头接口和控制接口(一般为i2c)组成
摄像头接口用于传输传感器采集到的数据
控制接口用于控制摄像头传感器(例如设置图像格式…)
-
芯片
芯片上由多个摄像头控制器,多个摄像头接口,多个i2c控制器(i2c总线)
摄像头控制器负责控制摄像头接口和处理接收到的数据,摄像头接口负责传输图像数据,i2c控制器负责传输控制信息
摄像头传感器和芯片的接法如下
其中摄像头控制器和摄像头接口是分离的,摄像头控制器可以选择控制哪一个摄像头接口
fimc是三星平台摄像头控制器的一套驱动程序
二、fimc驱动总览
fimc的文件集中在drivers/media/video/samsung/fimc
目录下
有以下文件
-
fimc_dev.c
fimc的平台驱动
-
fimc_v4l2.c
实现了一系列的ioctl操作
-
fimc_capture.c
实现了capture功能
-
fimc_output.c
实现了output功能
-
fimc_overlay.c
实现了overlay功能
-
fimc_regs.c
fimc控制器的寄存器操作
-
csis.c
csis接口的摄像头
各文件的组织形式如下
fimc_dev.c
是平台的驱动,负责一些初始化的工作,fimc_v4l2.c
设置了一系列的ioctl操作,fimc_capture.c
、fimc_output.c
、fimc_overlay.c
实现了一些具体功能的ioctl,通过fimc_regs.c
实现对摄像头控制器的硬件操作
三、源码分析
3.1 几个主要对象
在分析源码前,先介绍几个对象
-
s3c_platform_camera
摄像头传感器
struct s3c_platform_camera { /* 标记摄像头在哪个摄像头接口 */ enum fimc_cam_index id; /* 摄像头接口类型 */ enum fimc_cam_type type; //ITU or MIPI /* 像素格式 */ enum fimc_cam_format fmt; /* i2c相关信息 */ int i2c_busnum; //摄像头所接的i2c总线 struct i2c_board_info *info; //摄像头的i2c信息 struct v4l2_subdev *sd; //表明这是一个v4l2_subdev int width; //图像的宽 int height; //图像的高 /* 摄像头接口的时序极性 */ int inv_pclk; int inv_vsync; int inv_href; int inv_hsync; /* 使能摄像头 */ int (*cam_power)(int onoff); };
-
s3c_platform_fimc
摄像头接口的平台信息
struct s3c_platform_fimc { /* 时钟相关 */ const char srclk_name[16]; /* source of interface clock name */ const char clk_name[16]; /* interface clock name */ const char lclk_name[16]; /* interface clock name */ u32 clk_rate; /* clockrate for interface clock */ /* 保存摄像头的信息 */ struct s3c_platform_camera *camera[5]; /* FIXME */ void (*cfg_gpio)(struct platform_device *pdev); int (*clk_on)(struct platform_device *pdev, struct clk *clk); int (*clk_off)(struct platform_device *pdev, struct clk *clk); };
-
fimc_control
摄像头控制器
struct fimc_control { /* 寄存器地址 */ void __iomem *regs; /* video_device和v4l2_device */ struct video_device *vd; struct v4l2_device v4l2_dev; ... };
-
fimc_global
fimc驱动的全局变量
struct fimc_global { struct fimc_control ctrl[FIMC_DEVICES]; //摄像头控制器 struct s3c_platform_camera camera[FIMC_MAXCAMS]; //摄像头 int camera_isvalid[FIMC_MAXCAMS]; //标记是否存在摄像头 int active_camera; // 当前使用的摄像头 };
介绍完上面几个结构体后,开始分析源码
3.2 fimc的平台设备
fimc的驱动采用的platform总线,分成设备和驱动,我们先介绍设备
首先看mach-smdkc110.c
文件,这里描述了一系列的硬件信息
这里有多个摄像头描述,其中一个如下
static struct s3c_platform_camera s5k4ba = {
.id = CAMERA_PAR_A, //摄像头在接口A
.type = CAM_TYPE_ITU, //ITU模式
.fmt = ITU_601_YCBCR422_8BIT, //传感器输入格式YCbCr422
.order422 = CAM_ORDER422_8BIT_CBYCRY, //输入Y U V的顺序
.i2c_busnum = 0, //i2c总线0
.info = &s5k4ba_i2c_info, //i2c的设备描述
.pixelformat = V4L2_PIX_FMT_UYVY, //经过摄像头控制器后的输出格式
.srclk_name = "mout_mpll",
.clk_name = "sclk_cam1",
.clk_rate = 44000000, //时钟频率
.line_length = 1920,
.width = 800, //图像宽
.height = 600, //图像高
/* 裁剪 */
.window = {
.left = 0,
.top = 0,
.width = 800,
.height = 600,
},
/* 时序极性 */
.inv_pclk = 0,
.inv_vsync = 1,
.inv_href = 0,
.inv_hsync = 0,
.initialized = 0,
.cam_power = s5k5ba_power_en,
};
看一看s5k4ba_i2c_info
static struct i2c_board_info s5k4ba_i2c_info = {
I2C_BOARD_INFO("S5K4BA", 0x2d),
.platform_data = &s5k4ba_plat,
};
其中表明i2c设备名称为S5K4BA
,i2c从地址0x2d
再看一看s5k5ba_power_en
如何使能摄像头
static int s5k5ba_power_en(int onoff)
{
smdkv210_cam1_power(onoff);
}
/* 设置GPIO */
static int smdkv210_cam0_power(int onoff)
{
int err;
/* Camera A */
err = gpio_request(GPIO_PS_VOUT, "GPH0");
if (err)
printk(KERN_ERR "failed to request GPH0 for CAM_2V8\n");
s3c_gpio_setpull(GPIO_PS_VOUT, S3C_GPIO_PULL_NONE);
gpio_direction_output(GPIO_PS_VOUT, 0);
gpio_direction_output(GPIO_PS_VOUT, 1);
gpio_free(GPIO_PS_VOUT);
return 0;
}
s3c_platform_camera
描述一个摄像头的信息(哪个摄像头接口,在哪个i2c总线,像素格式…)
s5k4ba
被嵌入到fimc的平台数据中
static struct s3c_platform_fimc fimc_plat_lsi = {
.srclk_name = "mout_mpll",
.clk_name = "sclk_fimc",
.lclk_name = "sclk_fimc_lclk",
.clk_rate = 166750000,
.default