camera 模组驱动优化
来源:互联网 发布:centos yum本地源 编辑:程序博客网 时间:2024/06/10 19:31
因为项目比较多,平台支持的 camera 模组已经有 10 多个了,代码比较繁杂,就把 camera 模组端的驱动架构优化了一下。总的思路就是将公共的接口统一起来,减少代码的耦合度,建立新的公共接口文件 cam_core.c 和 cam_core.h。
一、基础数据结构
新建立的数据结构如下:
struct cam_info {struct i2c_client *i2c_dev; /* 指向模组的i2c从设备 */struct cam_priv *priv; /* 指向模组的操作接口 */struct v4l2_subdev sd; /* v4l2子设备 */uint32_t maxwidth; /* 模组支持的最大分辨率 */uint32_t maxheight;uint32_t minwidth; /* 模组支持的最小分辨率 */uint32_t minheight;/* current param used for each frame */uint32_t width; /* 模组的当前分辨率及帧率 */uint32_t height;uint32_t fps;uint8_t bl; /*0:auto, 1:50Hz light, 2:60Hz light */uint8_taf;unsigned long flags; /* flags for cam on/off, af on/off */unsigned long res_flags; /* flags for resolution */unsigned long night_mode;struct clk *camera; /* camera clk */};struct cam_info 结构主要负责和 cam_core.c 交互,通过指针 priv 指向模组的私有操作接口struct cam_priv,该结构定义如下:
struct cam_priv {char *name; /* 模组名称 */uint16_t addr; /* 模组i2c地址 */uint32_t i2c_bus; /* 模组i2c总线号 */uint32_t subdev_id; /* 前后camera标记 */uint32_t fmt_num; /* 模组支持的格式数量 */uint32_t res_num; /* 模组支持的分辨率数量 */uint32_t ctl_num; /* 模组支持的特殊操作数量 */struct camera_fmt *fmt_list; /* 模组支持的格式列表 */struct camera_res *res_list; /* 模组支持的分辨率列表 */struct camera_control *ctl_list; /* 模组支持的特殊操作列表 */struct i2c_device_id *id_table; /* i2c id 列表 */int (*Open)(struct cam_info *info); /* 打开模组 */int (*Close)(struct cam_info *info); /* 关闭模组 */int (*Set_Preview)(struct cam_info *info); /* 预览操作接口 */int (*Set_Capture)(struct cam_info *info); /* 拍照操作接口 */int (*Set_Config)(struct cam_info *info); /* 配置操作接口 */int (*Set_Resolution)(struct cam_info *info, int val); /* 分辨率操作接口 */int (*Request_Gpio)(void); /* Gpio申请和释放 */int (*Free_Gpio)(void);int (*Detect_PowerON)(struct cam_info *info); /* 模组自动探测接口 */int (*Detect_PowerOFF)(struct cam_info *info);int (*Detect_ReadId)(struct cam_info *info);};二、cam_core 主要接口解析
1、register 接口
模组注册到内核用 init_atxx_cam -> register_cam_device 接口,接口定义如下:
/* 主要完成camera模组的探测工作并将其注册到内核中 */static int register_cam_device(struct cam_info *info){int ret;struct i2c_adapter *adapter;struct i2c_board_info board_info;memset(&board_info, 0, sizeof(struct i2c_board_info));board_info.addr = info->priv->addr;strlcpy(board_info.type, info->priv->name, I2C_NAME_SIZE);/* 动态创建i2c从设备 */adapter = i2c_get_adapter(info->priv->i2c_bus);if (adapter == NULL) {cam_err("can't get i2c adapter %d\n", info->priv->i2c_bus);return -ENODEV;}info->i2c_dev = i2c_new_device(adapter, &board_info);i2c_put_adapter(adapter);if (info->i2c_dev == NULL) {cam_err("can't add i2c device at 0x%x\n", board_info.addr);return -ENODEV;}info->camera = clk_get(&info->i2c_dev->dev, "camera");if (IS_ERR(info->camera)) {cam_err("can't get camera clock\n");ret = -ENODEV;goto exit;}/* 申请Gpio并打开模组电源 */info->priv->Request_Gpio();info->priv->Detect_PowerON(info);/* 设置时钟 */clk_set_rate(info->camera, ATXX_CAM_CLOCK);clk_enable(info->camera);msleep(10);/* 读取模组id */ret = info->priv->Detect_ReadId(info);if(ret) {cam_err("can't detect this camera: %s\n", info->priv->name);goto exit_detect;}if(info->priv->subdev_id == ATXX_SUBDEV_FORE_CAM) {fore_cam_driver.id_table = info->priv->id_table;ret = i2c_add_driver(&fore_cam_driver);if(ret) {cam_err("can't add i2c driver\n");goto exit_detect;}} else {rear_cam_driver.id_table = info->priv->id_table;ret = i2c_add_driver(&rear_cam_driver);if(ret) {cam_err("can't add i2c driver\n");goto exit_detect;}}/* 初始化v4l2子设备 */v4l2_i2c_subdev_init(&info->sd, info->i2c_dev, &cam_ops);info->priv->Set_Config(info);/* 注册到内核 */ret = atxx_cam_register_sensor(&info->sd, info->priv->subdev_id);if(ret) {cam_err("can't register this camera: %s\n", info->priv->name);goto exit_detect;}clk_disable(info->camera);info->priv->Detect_PowerOFF(info);info->priv->Free_Gpio();info->flags = 0;return 0;exit_detect:clk_disable(info->camera);clk_put(info->camera);info->priv->Detect_PowerOFF(info);info->priv->Free_Gpio();exit:i2c_unregister_device(info->i2c_dev);return ret;}/* 初始化模组调用接口,参数为模组的cam_priv */int init_atxx_cam(struct cam_priv *priv){int ret;struct cam_info *info;info = kzalloc(sizeof(struct cam_info), GFP_KERNEL);if(info == NULL)return -ENOMEM;info->priv = priv;ret = register_cam_device(info);if(ret) {kfree(info);return ret;}return 0;}EXPORT_SYMBOL(init_atxx_cam);2、v4l2 接口
在 cam_core 中主要完成 v4l2 子设备相关的操作,涉及到的数据结构和接口如下:
static const struct v4l2_subdev_core_ops cam_core_ops = {.g_ctrl = cam_g_ctrl, /* 获取当前命令值 */.s_ctrl = cam_s_ctrl, /* 发送命令值 */.queryctrl = cam_queryctrl, /* 查询模组是否支持该命令 */.reset = cam_reset, /* 复位模组 */.init = cam_init, /* 初始化模组 */.ioctl = cam_ioctl, /* 保留备用 */};static const struct v4l2_subdev_video_ops cam_video_ops = {.s_fmt = cam_s_fmt, /* 设置模组捕获视频的格式 */.try_fmt = cam_try_fmt, /* 尝试是否支持该格式 */.enum_fmt = cam_enum_fmt, /* 枚举设备支持的格式 */};static const struct v4l2_subdev_ops cam_ops = {.core = &cam_core_ops, /* v4l2通用接口 */.video = &cam_video_ops, /* v4l2视频接口 */};3、i2c 通信接口
大部分 camera 寄存器的地址和值都是 8 位或者 16 位数据,因此可以将 i2c 通信接口简化,建立如下结构来描述寄存器地址和值:
/* 8 bit */struct cam_reg {unsigned char reg; /* 8位寄存器地址 */unsigned char val; /* 8位寄存器值 */};/* 16 bit */struct cam_reg {unsigned short reg; /* 16位寄存器地址 */unsigned char val; /* 8位寄存器值 */};
封装的 8 位通信接口如下:
uint8_t cam_read_byte(struct i2c_client *client, uint8_t reg_idx);int cam_write_byte(struct i2c_client *client, uint8_t reg_idx, uint8_t val);
在模组驱动中使用示例如下:
/*********************************************************************** * Camera Common Function * ***********************************************************************/struct cam_reg {unsigned char reg;unsigned char val;};static int write_regs(struct cam_info *info, const struct cam_reg reglist[]){const struct cam_reg *next = reglist;while (!((next->reg == REG_TERM) && (next->val == VAL_TERM))){cam_write_byte(info->i2c_dev, next->reg, next->val);next++;}return 0;}/*********************************************************************** * Camera Initialize Function * ***********************************************************************/static struct cam_reg cam_set_initialize[] = {{0xfc, 0x16},...{REG_TERM, VAL_TERM}};static struct cam_reg cam_set_preview[] = {{REG_TERM, VAL_TERM}};static struct cam_reg cam_set_capture[] = {{REG_TERM, VAL_TERM}};struct cam_reg* cam_reg_init[CAM_INIT_MAX] ={cam_set_initialize,cam_set_preview,cam_set_capture};static int cam_initialize(struct cam_info *info){return write_regs(info, cam_reg_init[CAM_INIT]);}static int cam_preview(struct cam_info *info){return write_regs(info, cam_reg_init[CAM_PREVIEW]);}static int cam_capture(struct cam_info *info){return write_regs(info, cam_reg_init[CAM_CAPTRUE]);}三、camera 模组驱动接口解析
在模组驱动中主要工作是实现 struct cam_priv 中的接口,然后调用 init_atxx_cam 注册:
static struct cam_priv priv = {.name = ATXX_CAM_NAME,.addr = ATXX_CAM_ADDR,.i2c_bus = ATXX_CAM_BUS,.subdev_id = ATXX_CAM_SUBDEV,.fmt_num = N_FORMATS,.res_num = N_RESOLUTIONS,.ctl_num = N_CONTROLS,.fmt_list = cam_fmt_list,.res_list = cam_res_list,.ctl_list = cam_ctl_list,.id_table = cam_id_table,.Open = cam_open,.Close = cam_close,.Set_Preview = cam_preview,.Set_Capture = cam_capture,.Set_Config = cam_config,.Set_Resolution = cam_resolution,.Request_Gpio = cam_gpio_request,.Free_Gpio = cam_gpio_free,.Detect_PowerON = detect_poweron,.Detect_PowerOFF = detect_poweroff,.Detect_ReadId = detect_readid,};static int __init cam_init(void){return init_atxx_cam(&priv);}经过优化之后 camera 模组的代码耦合度很低,新增模组 driver 时只需要将别的模组 driver 拷贝一份然后修改一下宏定义和寄存器值就可以用了,而且每个模组 driver 的代码比之前少了500行左右,看起来也比较整洁,达到了预期目标。
- camera 模组驱动优化
- camera 模组驱动优化
- camera 模组驱动优化
- camera模组优化
- camera模组CMM介绍
- camera模组介绍
- camera模组CMM介绍
- 手机Camera模组分析
- Camera模组详解
- Camera模组布线规则
- Camera模组散热设计
- camera 模组(一)
- camera 模组(二)
- camera 模组(三)
- camera 模组(四)
- android camera(一):camera模组CMM介绍
- android camera(一):camera模组CMM介绍
- android camera(一):camera模组CMM介绍
- jqGrid与Struts2的结合应用(七) —— 浅谈排序
- 方便易用的.net 无刷新上传控件
- 编译MAD时出错
- linux下查看cpu及操作系统信息
- shell编程
- camera 模组驱动优化
- C++ 成长历程 之 上机任务
- 架设服务器
- http://blog.csdn.net/kangojian/article/details/3990206
- 走进JVM,浅水也能捉鱼
- Receiver type 'CALayer' for instance message is a forward declaration编译错误解决办法
- 命令和查询责任分离(CQRS)架构模式
- 删除快捷方式小箭头.bat
- 第十七周上机任务项目5-数组的排序