完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
RK VCM 设备保护参数说明:
[tr] 名称定义[/tr]
例子: vm149c: vm149c@0c { // vcm驱动配置,支持AF 时需要有这个设置 compatible = "silicon touch,vm149c"; 状态=“好的”; 注册 = <0x0c>; rockchip,vcm-start-current = <0>; // 马达的启动电流 rockchip,vcm-rated-current = <100>; // 马达的电流电流 -rockchip,vcm-mode = <4>; // 马达输出驱动 ic 的电流模式 rockchip,camera-module-index = <0>; // 模组编号 rockchip,camera-module-facing = "back"; // 模组有“正面”和“背面” }; gc8034: gc8034@37 { ...... 镜头焦点 = <&vm149c>; // vcm 驱动设置,支持 AF 时需要有这个设置 ...... }; VCM驱动说明 移植驱动步骤 1。 struct driver.name struct driver.pm struct driver。of_match_table probe 函数 remove 函数 probe 函数实现细节描述 VCM设备资源获取,主要获取DTS资源 1、RK资源定义,定义如rockchip,camera-module-xxx,主要是提供设备参数和Camera设备进行匹配。 2、 VCM参数定义,定义参数如rockchip,vcm-xxx,涉及硬件启动电流、电流跟电流、移动模式,参数范围和马达移动的 相关 。 ret |= of_property_read_string(np, RKMODULE_CAMERA_MODULE_FACING, &vm149c_dev->module_facing); if (ret) { dev_err(&client->dev, "无法获取模块信息!n"); 返回-EINVAL; } ... memset(面对,0,sizeof(面对)); if (strcmp(vm149c_dev->module_facing, "back") == 0) faces [0] = 'b'; 否则 面对[0] = 'f'; snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", vm149c_dev->module_index, 面对, VM149C_NAME, dev_name(sd->dev)); ret = v4l2_async_register_subdev(sd); if (ret) dev_err(&client->dev, "v4l2 async register subdev failedn"); v4l2子设备: v4l2_i2c_subdev_init, RK VCM 要求子设备拥有自己的设备供用户状态camera_engine访问,通过该设备节点实现调焦控制; v4l2_i2c_subdev_init(&vm149c_dev->sd, client, &vm149c_ops); vm149c_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; vm149c_dev->sd.internal_ops = &vm149c_int_ops; ret = vm149c_init_controls(vm149c_dev); if (ret) goto err_cleanup; ret = media_entity_pads_init(&vm149c_dev->sd.entity, 0, NULL); if (ret < 0) goto err_cleanup; sd = &vm149c_dev->sd; sd->entity.function = MEDIA_ENT_F_LENS; AF算法 RK AF算法将整个镜头可移动系列的模组参数定义为[0, 实现 v4 子设备驱动,实现以下 2 个子设备成员: 1、struct v4l2_subdev_FOcore_ops v4l2_subdev_FOcore_ops 实现.ioctl(.ioctl32)通过主要获取函数的 该命令实现RK主要控制一个命令,涉及: [tr]RK_VIDIOC_VCM_TIMEcamera_engine镜头移动时间要求,据此来镜头何时停止以及CIS帧曝光时间段是否与镜头移动时间段有重叠;移动镜头时间与镜头、VCM驱动器电流输出模式相关。[/tr] 2、struct vl2_ctrl_ops v2_ctrl_ops 主要实现,volatile_ctrl.s_ctrl4以下和整个功能。 标准的v4l2控制实现了命令: [tr]V4L2_FOCUS_ABSOLUTEcamera_engine命令来命令和获取的镜头中的移动,RK AF算法将在中设置范围的位置参数定义为[0,64]。[/tr] 数据类型简要说明 1、struct v4l2_subdev_core_ops 为子开发定义核心操作回调。自定义ioctl的实现,主要包含获取移动移动的信息, [tr]时间名称描述[/tr]
静态常量结构 v4l2_subdev_core_ops vm149c_core_ops = { .ioctl = vm149c_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl32 = vm149c_compat_ioctl32 #endif }; 2、struct v4l2_ctrl_ops 驱动必须提供的控制操作。 [tr]成员姓名描述[/tr]
静态常量结构 v4l2_ctrl_ops vm149c_vcm_ctrl_ops = { .g_volatile_ctrl = vm149c_get_ctrl, .s_ctrl = vm149c_set_ctrl, }; API 简要说明 1、xxxx_get_ctrl :获取马达的移动位置。 static int vm149c_get_ctrl(struct v4l2_ctrl *ctrl) { struct vm149c_device *dev_vcm = to_vm149c_vcm(ctrl); if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) 返回 vm149c_get_pos(dev_vcm, &ctrl->val); 返回-EINVAL; } 2、xxxx_set_ctrl :设置马达的移动位置。 static int vm149c_set_ctrl(struct v4l2_ctrl *ctrl) { struct vm149c_device *dev_vcm = to_vm149c_vcm(ctrl); struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd); 无符号 int dest_pos = ctrl->val; int move_pos; 长 int mv_us; int ret = 0; if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { if (dest_pos > VCMDRV_MAX_LOG) { dev_info(&client->dev, "%s dest_pos 错误。%d > %dn", __func__, dest_pos, VCMDRV_MAX_LOG); 返回-EINVAL; } /* 计算移动时间 */ move_pos = dev_vcm->current_related_pos - dest_pos; 如果 (move_pos < 0) move_pos = -move_pos; ret = vm149c_set_pos(dev_vcm, dest_pos); dev_vcm->move_ms = ((dev_vcm->vcm_movefull_t * (uint32_t)move_pos) / VCMDRV_MAX_LOG); dev_dbg(&client->dev, "dest_pos %d, move_ms %ldn", dest_pos, dev_vcm->move_ms); dev_vcm->start_move_tv = ns_to_timeval(ktime_get_ns()); mv_us = dev_vcm->start_move_tv.tv_usec + dev_vcm->move_ms * 1000; 如果 (mv_us >= 1000000) { dev_vcm->end_move_tv.tv_sec = dev_vcm->start_move_tv.tv_sec + 1; dev_vcm->end_move_tv.tv_usec = mv_us - 1000000; } 否则 { dev_vcm->end_move_tv.tv_sec = dev_vcm->start_move_tv.tv_sec; dev_vcm->end_move_tv.tv_usec = mv_us; } } 返回 ret; } 3、xxxx_ioctl/xxxx_compat_ioctl32 自定义ioctl的实现函数,主要包含获取移动移动的时间信息, 实现了自定义RK_VIDIOC_COMPAT_VCM_TIMEINFO。 static long vm149c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct i2c_client *client = v4l2_get_subdevdata(sd); 结构 vm149c_device *vm149c_dev = sd_to_vm149c_vcm(sd); 结构 rk_cam_vcm_tim *vcm_tim; 结构 rk_cam_vcm_cfg *vcm_cfg; int ret = 0; if (cmd == RK_VIDIOC_VCM_TIMEINFO) { vcm_tim = (struct rk_cam_vcm_tim *)arg; vcm_tim->vcm_start_t.tv_sec = vm149c_dev->start_move_tv.tv_sec; vcm_tim->vcm_start_t.tv_usec = vm149c_dev->start_move_tv.tv_usec; vcm_tim->vcm_end_t.tv_sec = vm149c_dev->end_move_tv.tv_sec; vcm_tim->vcm_end_t.tv_usec = vm149c_dev->end_move_tv.tv_usec; dev_dbg(&client->dev, "vm149c_get_move_res 0x%lx, 0x%lx, 0x%lx, 0x%lxn", vcm_tim->vcm_start_t.tv_sec、vcm_tim->vcm_start_t.tv_usec、 vcm_tim->vcm_end_t.tv_sec、vcm_tim->vcm_end_t.tv_usec); } else if (cmd == RK_VIDIOC_GET_VCM_CFG) { vcm_cfg = (struct rk_cam_vcm_cfg *)arg; vcm_cfg->start_ma = vm149c_dev->vcm_cfg.start_ma; vcm_cfg->rated_ma = vm149c_dev->vcm_cfg.rated_ma; vcm_cfg->step_mode = vm149c_dev->vcm_cfg.step_mode; } else if (cmd == RK_VIDIOC_SET_VCM_CFG) { vcm_cfg = (struct rk_cam_vcm_cfg *)arg; vm149c_dev->vcm_cfg.start_ma = vcm_cfg->start_ma; vm149c_dev->vcm_cfg.rated_ma = vcm_cfg->rated_ma; vm149c_dev->vcm_cfg.step_mode = vcm_cfg->step_mode; vm149c_update_vcm_cfg(vm149c_dev); } else { dev_err(&client->dev, "cmd 0x%x 不支持n", cmd); 返回-EINVAL; } 返回 ret; } |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
基于米尔瑞芯微RK3576核心板/开发板的人脸疲劳检测应用方案
892 浏览 0 评论
1101 浏览 1 评论
920 浏览 1 评论
2148 浏览 1 评论
3441 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-27 11:08 , Processed in 0.748029 second(s), Total 70, Slave 54 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号