高通camera马达驱动工作流程

    xiaoxiao2023-03-25  6

            手机自动对焦功能是通过将摄像头锁入音圈马达来实现的,音圈马达 简称(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"); }
    转载请注明原文地址: https://ju.6miu.com/read-1203456.html
    最新回复(0)