高通camera马达驱动工作流程

来源:互联网 发布:软件架构.pdf 编辑:程序博客网 时间:2024/06/02 19:16

        手机自动对焦功能是通过将摄像头锁入音圈马达来实现的,音圈马达简称(VCM),它主要有线圈,磁铁组和弹片构成,线圈通过上下两个弹片固定在磁铁组成,当给线圈通电时,线圈会产生磁场,线圈磁场和磁石组相互作用,线圈会向上移动,而锁在线圈里的摄像头便一起移动,当断电时,线圈在弹片弹力下返回,这样就实现了自动对焦功能

        这里重点是讲解一下关于高通平台camera的马达驱动,和驱动驱动一样,高通平台端的马达的入口函数也是module_init();
    module_init(msm_actuator_init_module);
    
        msm_actuator_init_module()函数主要是实现了两个功能:一个是通过platform_driver_register函数注册驱动msm_actuator_platform_driver),还有一个是将msm_actuator_i2c_driver挂载i2c总线上;
static struct platform_driver msm_actuator_platform_driver = {
    .probe = msm_actuator_platform_probe,      //注册成功后就会调用这个探测函数(重要)
    .driver = {
.name = "qcom,actuator",   
 .owner = THIS_MODULE,
.of_match_table = msm_actuator_dt_match   //通过设备树的compatible匹配资源,具体见下图
}
}
<span style="font-size:18px;color:#33cc00;">static int32_t msm_actuator_platform_probe(struct platform_device *pdev){      ··············    rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index",        &pdev->id);                </span><span style="font-size:18px;color:#003333;">//获取设备资源信息</span><span style="font-size:18px;color:#33cc00;">    CDBG("cell-index %d, rc %d\n", pdev->id, rc);    if (rc < 0) {        kfree(msm_actuator_t);        pr_err("failed rc %d\n", rc);        return rc;    }</span>
<span style="color: rgb(51, 204, 0);font-size:18px; line-height: 1.5; font-family: 微软雅黑;">     /*初始化msm_actuator_t*/</span>
<span style="color: rgb(51, 204, 0);font-size:18px; line-height: 1.5; font-family: 微软雅黑;">   msm_actuator_t->act_v4l2_subdev_ops = &</span><span style="font-size:18px; line-height: 1.5; font-family: 微软雅黑;"><span style="color:#ff0000;">msm_actuator_subdev_ops</span></span><span style="color: rgb(51, 204, 0);font-size:18px; line-height: 1.5; font-family: 微软雅黑;">;</span>
<span style="color: rgb(51, 204, 0);font-size:18px; line-height: 1.5; font-family: 微软雅黑;">    msm_actuator_t->actuator_mutex = &msm_actuator_mutex;        //互斥锁</span>
<span style="color: rgb(51, 204, 0);font-size:18px; line-height: 1.5; font-family: 微软雅黑;">    msm_actuator_t->cam_name = pdev->id;</span>
<span style="font-size:18px;color:#33cc00;">    /* Set platform device handle */    msm_actuator_t->pdev = pdev;    /* Set device type as platform device */    msm_actuator_t->act_device_type = MSM_CAMERA_PLATFORM_DEVICE;    msm_actuator_t->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;    msm_actuator_t->i2c_client.cci_client = kzalloc(sizeof(        struct msm_camera_cci_client), GFP_KERNEL);    if (!msm_actuator_t->i2c_client.cci_client) {        kfree(msm_actuator_t->vreg_cfg.cam_vreg);        kfree(msm_actuator_t);        pr_err("failed no memory\n");        return -ENOMEM;    }    cci_client = msm_actuator_t->i2c_client.cci_client;    cci_client->cci_subdev = msm_cci_get_subdev();    cci_client->cci_i2c_master = msm_actuator_t->cci_master;    v4l2_subdev_init(&msm_actuator_t->msm_sd.sd,        msm_actuator_t->act_v4l2_subdev_ops);    v4l2_set_subdevdata(&msm_actuator_t->msm_sd.sd, msm_actuator_t);    msm_actuator_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops;    msm_actuator_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;    snprintf(msm_actuator_t->msm_sd.sd.name,        ARRAY_SIZE(msm_actuator_t->msm_sd.sd.name), "msm_actuator");    media_entity_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL, 0);    msm_actuator_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;    msm_actuator_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR;    msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;    msm_sd_register(&msm_actuator_t->msm_sd);    msm_actuator_t->actuator_state = ACT_DISABLE_STATE;    msm_cam_copy_v4l2_subdev_fops(&msm_actuator_v4l2_subdev_fops);#ifdef CONFIG_COMPAT    msm_actuator_v4l2_subdev_fops.compat_ioctl32 =        msm_actuator_subdev_fops_ioctl;#endif    msm_actuator_t->msm_sd.sd.devnode->fops =        &msm_actuator_v4l2_subdev_fops;    CDBG("Exit\n");    return rc;}</span><span style="font-size: 14px;"></span>

static struct msm_actuator msm_vcm_actuator_table = {    .act_type = ACTUATOR_VCM,                      //类型:音圈马达    .func_tbl = {        .actuator_init_step_table = msm_actuator_init_step_table,                       .actuator_move_focus = msm_actuator_move_focus,        .actuator_write_focus = msm_actuator_write_focus,        .actuator_set_default_focus = msm_actuator_set_default_focus,        .actuator_init_focus = msm_actuator_init_focus,        .actuator_parse_i2c_params = msm_actuator_parse_i2c_params,        .actuator_set_position = msm_actuator_set_position,        .actuator_park_lens = msm_actuator_park_lens,    },};
msm_actuator_init_step_table()函数主要是初始化step_table:
1、先通过ADC多少位确定max_code_size,例如10位的就是1024;
2、a_ctrl->step_position_table = NULL;清空位置表并重新设置;
3、cur_code = set_info->af_tuning_params.initial_code;设置最初的编码;
4、其他

msm_actuator_move_focus:主要是计算出位置,然后通过i2c发送命令移动焦距:
    rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
        &a_ctrl->i2c_client, &reg_setting);

msm_actuator_write_focus:
Write code based on damping_code_step in a loop

msm_actuator_set_default_focus设置默认的焦距:
rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, move_params);




msm_actuator_init_focus初始化对焦:
设置i2c通信的地址和数据类型(word或者byte型);
i2c的通信方式MSM_ACT_WRITE或者MSM_ACT_POLL;
根据传入的参数进行初始化。

msm_actuator_parse_i2c_params解析i2c参数:就是把各组i2c通信数据和地址解析到i2c_tbl中
value = (next_lens_position << write_arr[i].data_shift) | ((hw_dword & write_arr[i].hw_mask) >>write_arr[i].hw_shift);

i2c_byte1 = (value & 0xFF00) >> 8;
i2c_byte2 = value & 0xFF;

把i2c的地址和数据解析存放到a_ctrl->i2c_reg_tbl中

static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl,
    int16_t next_lens_position, uint32_t hw_params, uint16_t delay)
{
    struct msm_actuator_reg_params_t *write_arr = a_ctrl->reg_tbl;
    uint32_t hw_dword = hw_params;
    uint16_t i2c_byte1 = 0, i2c_byte2 = 0;
    uint16_t value = 0;
    uint32_t size = a_ctrl->reg_tbl_size, i = 0;
    struct msm_camera_i2c_reg_array *i2c_tbl = a_ctrl->i2c_reg_tbl;
    CDBG("Enter\n");
    for (i = 0; i < size; i++) {
        /* check that the index into i2c_tbl cannot grow larger that
        the allocated size of i2c_tbl */
        if ((a_ctrl->total_steps + 1) < (a_ctrl->i2c_tbl_index)) {
            break;
        }
 //先是判断是否属于DAC类型,如果不属于,则有:
  i2c_byte1 = write_arr[i].reg_addr;
 i2c_byte2 = (hw_dword & write_arr[i].hw_mask) >>write_arr[i].hw_shift;
这个说明不属于DAC所以直接简第一位进行地址,第二位通过上面运算得到数据value作为byte2
如果属于DAC类型,value = (next_lens_position <<
                write_arr[i].data_shift) | ((hw_dword & write_arr[i].hw_mask) >> write_arr[i].hw_shift);
然后判断是其寄存器地址是否等于0xFFF,如果不等于0xFFFF,则说明不是具体的某个寄存器,则:
i2c_byte1 = write_arr[i].reg_addr; i2c_byte2 = value;
如果DAC的寄存器不止一个的时候,i2c_byte2 = value & 0xFF;先存放到i2c_tbl中,然后第二个(貌似这里最多都只支持两个集训器)

如果寄存器的地址就是0xFFFF的时候,i2c_byte1 = (value & 0xFF00) >> 8;i2c_byte2 = value & 0xFF;高八位作为地址,第八位作为数据传输
代码实现见如下:
        if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) {    
 value = (next_lens_position << write_arr[i].data_shift) |((hw_dword & write_arr[i].hw_mask) >>  write_arr[i].hw_shift);
            if (write_arr[i].reg_addr != 0xFFFF) {
                i2c_byte1 = write_arr[i].reg_addr;
                i2c_byte2 = value;
                if (size != (i+1)) {
                    i2c_byte2 = value & 0xFF;
                    CDBG("byte1:0x%x, byte2:0x%x\n",
                        i2c_byte1, i2c_byte2);
                    i2c_tbl[a_ctrl->i2c_tbl_index].
                        reg_addr = i2c_byte1;
                    i2c_tbl[a_ctrl->i2c_tbl_index].
                        reg_data = i2c_byte2;
                    i2c_tbl[a_ctrl->i2c_tbl_index].
                        delay = 0;
                    a_ctrl->i2c_tbl_index++;
                    i++;
                    i2c_byte1 = write_arr[i].reg_addr;
                    i2c_byte2 = (value & 0xFF00) >> 8;
                }
            } else {
                i2c_byte1 = (value & 0xFF00) >> 8;
                i2c_byte2 = value & 0xFF;
            }
        }
        else {
            i2c_byte1 = write_arr[i].reg_addr;
            i2c_byte2 = (hw_dword & write_arr[i].hw_mask) >>
                write_arr[i].hw_shift;
        }
        CDBG("i2c_byte1:0x%x, i2c_byte2:0x%x\n", i2c_byte1, i2c_byte2);
        i2c_tbl[a_ctrl->i2c_tbl_index].reg_addr = i2c_byte1;
        i2c_tbl[a_ctrl->i2c_tbl_index].reg_data = i2c_byte2;
        i2c_tbl[a_ctrl->i2c_tbl_index].delay = delay;
        a_ctrl->i2c_tbl_index++;
    }
    CDBG("Exit\n");
}












0 0
原创粉丝点击