1. vcm介绍
4. 代码及otp介绍
.initial_code = 180,
.region_size = 1,
.region_params =
{
{
.step_bound =
{
414, /* Macro step boundary*/
0, /* Infinity step boundary*/
},
.code_per_step = 1,
.qvalue = 128,
},
},
initial_code = 180
total step = step_bound[0] - step_bound[1]
qvalue:如果没有otp,设置为1,有otp设置成128,通常情况code_per_step 为1.
获取actuator驱动中配置参数,进行actuator的初始化
static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_set_info_t *set_info) {
struct reg_settings_t *init_settings = NULL;
int32_t rc = -EFAULT;
uint16_t i = 0;
struct msm_camera_cci_client *cci_client = NULL;
CDBG("Enter\n");
/*根据vcm的type 获取具体的操作函数*/
for (i = 0; i < ARRAY_SIZE(actuators); i++) {
if (set_info->actuator_params.act_type ==
actuators[i]->act_type) {
a_ctrl->func_tbl = &actuators[i]->func_tbl;
rc = 0;
}
}
……………………………………………………………………
a_ctrl->region_size = set_info->af_tuning_params.region_size;
a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step;
a_ctrl->total_steps = set_info->af_tuning_params.total_steps;
……………………………………………………………………
if (set_info->actuator_params.init_setting_size &&
set_info->actuator_params.init_setting_size
<= MAX_ACTUATOR_INIT_SET) {
if (a_ctrl->func_tbl->actuator_init_focus) {
rc = a_ctrl->func_tbl->actuator_init_focus(a_ctrl,
set_info->actuator_params.init_setting_size,
init_settings);
……………………………………………………………………
}
}
a_ctrl->initial_code = set_info->af_tuning_params.initial_code;
if (a_ctrl->func_tbl->actuator_init_step_table)
rc = a_ctrl->func_tbl->
actuator_init_step_table(a_ctrl, set_info);
CDBG("Exit\n");
return rc;
}
init中主要的就是actuator_init_focus和actuator_init_step_table两个函数,其中actuator_init_focus里面就是基本的i2c写操作,将驱动中的文件init setting下发给sensor,在这里不做分解
static int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_set_info_t *set_info)
{
………………………………………………
for (; data_size > 0; data_size--)
max_code_size *= 2; //获取最大的DAC值,根据driver ic的位数来确定,一般都是2^10 = 1024
a_ctrl->max_code_size = max_code_size;
………………………………………………
/* Fill step position table */ // 这个step pos table 很重要,在整个对焦过程中都会用到
a_ctrl->step_position_table =
kmalloc(sizeof(uint16_t) *
(set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);
if (a_ctrl->step_position_table == NULL)
return -ENOMEM;
cur_code = set_info->af_tuning_params.initial_code;
a_ctrl->step_position_table[step_index++] = cur_code;
for (region_index = 0;
region_index < a_ctrl->region_size;
region_index++) {
code_per_step =
a_ctrl->region_params[region_index].code_per_step;
qvalue =
a_ctrl->region_params[region_index].qvalue;
step_boundary =
a_ctrl->region_params[region_index].
step_bound[MOVE_NEAR];
if (step_boundary >
set_info->af_tuning_params.total_steps) {
pr_err("invalid step_boundary = %d, max_val = %d",
step_boundary,
set_info->af_tuning_params.total_steps);
kfree(a_ctrl->step_position_table);
a_ctrl->step_position_table = NULL;
return -EINVAL;
}
for (; step_index <= step_boundary;
step_index++) {
if (qvalue > 1 && qvalue <= MAX_QVALUE)
cur_code = step_index * code_per_step / qvalue; //有otp的时候需要进行转换
else
cur_code = step_index * code_per_step; //没有otp时候走这个
cur_code += set_info->af_tuning_params.initial_code;
if (cur_code < max_code_size)
a_ctrl->step_position_table[step_index] =
cur_code; //幅值table
else {
for (; step_index <
set_info->af_tuning_params.total_steps;
step_index++)
a_ctrl->
step_position_table[
step_index] =
max_code_size;
}
CDBG("step_position_table[%d] = %d\n", step_index,
a_ctrl->step_position_table[step_index]);
}
}
CDBG("Exit\n");
return 0;
}
最终初始化之后的table的排列如下,该table 覆盖远焦(init_code)到近焦(init_code+total_step)整个对焦过程,所以如果远焦模糊,需要降低init_code的值,如果近焦对不清,需要增大init_code+total_step的值,即需要扩充整个table的size
dac_range = afcalib_data->macro_dac - afcalib_data->infinity_dac; //otp 中读出来的range
afcalib_data->infinity_dac +=
afcalib_data->infinity_margin * (float)dac_range; //一般infinity_margin是负数,算出最终的infinity_dac比读出来的小
afcalib_data->macro_dac +=
afcalib_data->macro_margin * (float)dac_range;//macro_margin 是正数,计算出来的macro_dac 比读出来的大
eeprom_autofocus_calibration 校准af
//效果参数中的total_steps
total_steps = af_driver_tune->region_params[af_driver_tune->region_size - 1].
step_bound[0] - af_driver_tune->region_params[0].step_bound[1];
//otp中的远焦和近焦值
macro_dac = ectrl->eeprom_data.afc.macro_dac;
infinity_dac = ectrl->eeprom_data.afc.infinity_dac;
//用于转换,有otp的时候是128,没有otp的时候是1
qvalue = af_driver_tune->region_params[0].qvalue;
//计算step,没有otp的时候从效果参数中获取,有otp的时候计算如下
if(qvalue >= 1 && qvalue <= 4096) {
code_per_step =
(macro_dac - infinity_dac) / (float)total_steps * qvalue;
af_driver_tune->region_params[0].code_per_step = code_per_step;
}
/* adjust af_driver_ptr */
//otp中的远焦值替换效果参数中的远焦值,此时的远焦值是经过margin之后的。
af_driver_tune->initial_code = ectrl->eeprom_data.afc.infinity_dac;
以上initial_code,code_per_step,qvalue和total step值都有了,然后会更新kernel中的pos table
需要注意的是:total step是从效果参数里面获取的,otp不会改变此值,pos table数组的长度不变
只不过把计算方案替换了,新的计算方式是:
//step_index的范围是从0-tatal_steps
pos_table[step_index] = step_index * code_per_step / qvalue + initial_code;
此时根据otp里面的值重新映射了pos table,在后续对焦中获取此表的index值对应的DAC值,然后下发给driver ic
输出对应的电流,驱动vcm移动。