《【高通SDM660平台】(1) — Camera 驱动 Bringup Guide》
《【高通SDM660平台】(2) — Camera Kernel 驱动层代码逻辑分析》
《【高通SDM660平台】(3) — Camera V4L2 驱动层分析 》
《【高通SDM660平台】(4) — Camera Init 初始化流程 》
《【高通SDM660平台】(5) — Camera Open 流程》
《【高通SDM660平台】(6) — Camera getParameters 及 setParameters 流程》
《【高通SDM660平台】(7) — Camera onPreview 代码流程》
《【高通SDM660平台】(8) — Camera MetaData介绍》
《【高通SDM660平台 Android 10.0】(9) — Qcom Camera Daemon 代码分析》
《【高通SDM660平台 Android 10.0】(10) — Camera Sensor lib 与 Kernel Camera Probe 代码分析》
《【高通SDM660平台 Android 10.0】(11) — Eeprom lib 与 Kernel eeprom代码分析》
《【高通SDM660平台 Android 10.0】(12) — Camera Chromatix 代码分析》
《【高通SDM660平台 Android 10.0】(18) — Camera start_session() 过程分析》
《【高通SDM660平台 Android 10.0】(19) — Camera_focus、Camera_snapshot、volume_up 按键工作原理分析》
《【高通SDM660平台 Android 10.0】(20) — Actuator 与 Kernel Actuator代码分析》
本文以 mm-camera/mm-camera2/media-controller/modules/sensors/configs/sdm660_camera.xml
中的第一颗Camera 马达 lc898217xc 为例,
借由他来分析下,马达库中相关的逻辑,及kernel 驱动中马达相关的
代码路径位于: mm-camera/mm-camera2/media-controller/modules/sensors/actuator/libs/lc898217xc
# mm-camera/mm-camera2/media-controller/modules/sensors/actuator/libs/lc898217xc/Android.mk
LOCAL_C_INCLUDES := lc898217xc_actuator.h
LOCAL_SRC_FILES:= lc898217xc_actuator.c
LOCAL_MODULE ## := lc898217xc_actuator.c
LOCAL_SHARED_LIBRARIES := libcutils
include $(BUILD_SHARED_LIBRARY)
从Android.mk
可以看出,最终将lc898217xc_actuator.c
编译成 lc898217xc_actuator.so
库
代码比较简单,返回actuator_lib_ptr 结构体。
#include "actuator_driver.h"
static actuator_driver_ctrl_t actuator_lib_ptr = {
#include "lc898217xc_actuator.h"
};
void *actuator_driver_open_lib(void)
{
return &actuator_lib_ptr;
}
{
.actuator_params =
{
.module_name = "onsemi",
.actuator_name = "lc898217xc",
.i2c_addr = 0xE4, // 马达的七位地址
.i2c_freq_mode = SENSOR_I2C_MODE_FAST,
.i2c_data_type = CAMERA_I2C_WORD_DATA,
.i2c_addr_type = CAMERA_I2C_BYTE_ADDR,
.act_type = ACTUATOR_TYPE_BIVCM,
.data_size = 12,
.reg_tbl =
{
.reg_tbl_size = 1,
.reg_params =
{
{
.reg_write_type = ACTUATOR_WRITE_DAC,
.hw_mask = 0x0000,
.reg_addr = 0x84,
.hw_shift = 0,
.data_shift = 0,
},
},
},
.init_setting_size = 1,
.init_settings = // 马达初始化数组
{
{ 0xB3, CAMERA_I2C_BYTE_ADDR,
0x00, CAMERA_I2C_BYTE_DATA, ACTUATOR_I2C_OP_POLL, 10 },
},
}, /* actuator_params */
.actuator_tuned_params =
{
.scenario_size =
{
1, /* MOVE_NEAR */
1, /* MOVE_FAR */
},
.ringing_scenario =
{
/* MOVE_NEAR */
{
400,
},
/* MOVE_FAR */
{
400,
},
},
.initial_code = 400,
.region_size = 1,
.region_params =
{
{
.step_bound =
{
400, /* Macro step boundary*/
0, /* Infinity step boundary*/
},
.code_per_step = 1,
.qvalue = 128,
},
},
/* damping used as direction value */
.damping =
{
/* damping[MOVE_NEAR] */
{
/* Scenario 0 */
{
.ringing_params =
{
/* Region 0 */
{
.damping_step = 0xFFF,
.damping_delay = 1000,
.hw_params = 0x0000180,
},
},
},
},
/* damping[MOVE_FAR] */
{
/* Scenario 0 */
{
.ringing_params =
{
/* Region 0 */
{
.damping_step = 0xFFF,
.damping_delay = 1000,
.hw_params = 0x0000FE80,
},
},
},
},
},
}, /* actuator_tuned_params */
},
vendor 中马达通用驱动代码位于:mm-camera/mm-camera2/media-controller/modules/sensors/actuator/module/actuator.c
马达驱动的主要入口在于 actuator_sub_module_init()
函数中,用于获取马达open, process,close 等方法。
# mm-camera/mm-camera2/media-controller/modules/sensors/actuator/module/actuator.c
int32_t actuator_sub_module_init(sensor_func_tbl_t *func_tbl)
{
SDBG("Enter");
func_tbl->open = actuator_open;
func_tbl->process = actuator_process;
func_tbl->close = actuator_close;
return 0;
}
# mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
/** Initialization table **/
static int32_t (*sub_module_init[SUB_MODULE_MAX])(sensor_func_tbl_t *) = {
[SUB_MODULE_SENSOR] = sensor_sub_module_init,
[SUB_MODULE_CHROMATIX] = chromatix_sub_module_init,
[SUB_MODULE_ACTUATOR] = actuator_sub_module_init,
[SUB_MODULE_EEPROM] = eeprom_sub_module_init,
[SUB_MODULE_LED_FLASH] = led_flash_sub_module_init,
};
mct_module_t *module_sensor_init(const char *name)
{
ret = sensor_init_probe(module_ctrl);
ret = module_sensor_find_other_subdev(module_ctrl);
/* Init sensor modules */
ret = mct_list_traverse(module_ctrl->sensor_bundle, module_sensors_subinit, NULL);
}
static boolean module_sensors_subinit(void *data, void *user_data __attribute__((unused)))
{
module_sensor_bundle_info_t *s_
bundle = (module_sensor_bundle_info_t *)data;
for (i = 0; i < SUB_MODULE_MAX; i++)
{
s_bundle->module_sensor_params[i] = malloc(sizeof(module_sensor_params_t));
memset(s_bundle->module_sensor_params[i], 0, sizeof(module_sensor_params_t));
rc = sub_module_init[i](&s_bundle->module_sensor_params[i]->func_tbl);
if (rc < 0 || !s_bundle->module_sensor_params[i]->func_tbl.open ||
!s_bundle->module_sensor_params[i]->func_tbl.process ||
!s_bundle->module_sensor_params[i]->func_tbl.close) {
SERR("failed");
goto ERROR;
}
switch(i) {
case SUB_MODULE_SENSOR:
s_bundle->subdev_info[i].data = &(s_bundle->sensor_common_info);
s_bundle->subdev_info[i].sub_mod_open_flag = 0;
break;
case SUB_MODULE_CHROMATIX:
s_bundle->subdev_info[i].sub_mod_open_flag = 0;
break;
case SUB_MODULE_ACTUATOR:
s_bundle->subdev_info[i].sub_mod_open_flag = 0;
break;
}
}
从上面log, 可以看出,在 mm-qcamera-daemon 启动过程中,将actuator 相关的操作方法,
保存在 module_ctrl->sensor_bundle->module_sensor_params[SUB_MODULE_ACTUATOR]->func_tbl
中,
调用方法为: module_ctrl->sensor_bundle->module_sensor_params[SUB_MODULE_ACTUATOR]->func_tbl.process()
在 《【高通SDM660平台 Android 10.0】(18) — Camera start_session() 过程分析》中,
我们分析到了,flashlight、actuator 等是在 start_session()
时,
在 module_sensor_offload_open()
中打开所有外设节点,当然也包括 马达的节点。
而在module_sensor_offload_init_config( )
中调用马达初始化函数,对马达进行初始化的。
我们来看下马达初始化过程吧。
# mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor_offload.c
void module_sensor_offload_init_config( void* param1, void* param2, void* param3 __attribute__((unused)), void* param4 __attribute__((unused)))
{
if (s_bundle->sensor_info->subdev_id[SUB_MODULE_ACTUATOR] != -1) {
status = module_sensor_actuator_init_calibrate(s_bundle);
if (status != TRUE) {
SERR("module_sensor_actuator_init_calibrate failed");
goto ERROR0;
}
}
}
主要工作如下:
name = lc898217xc
af_actuator_init()
初始化马达,加载马达的库,获取马达参数,触发kernel 马达上电,初始化马达驱动mm-camera/mm-camera2/media-controller/modules/sensors/actuator/libs/lc898217xc/lc898217xc_actuator.h
中# mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
boolean module_sensor_actuator_init_calibrate( module_sensor_bundle_info_t *s_bundle)
{
int32_t rc = 0;
char *a_name = NULL;
sensor_get_af_algo_ptr_t af_algo;
eeprom_set_chroma_af_t eeprom_set;
af_algo_tune_parms_t *af_algo_cam_ptr = NULL;
actuator_driver_params_t *af_driver_ptr = NULL;
// 1. 获取马达name ,本文 name = lc898217xc
/* Get the actuator name from camera config read during daemon init */
a_name = s_bundle->sensor_common_info.camera_config.actuator_name;
SLOW("Actuator init and calibrate for %s", a_name);
// 2. 调用 af_actuator_init() 初始化马达,加载马达的库,获取马达参数,触发kernel 马达上电,初始化马达驱动
/* Initialize the actuator */
SENSOR_SUB_MODULE_PROCESS_EVENT(s_bundle, SUB_MODULE_ACTUATOR, ACTUATOR_INIT, a_name, rc);
// 3. 获取 马达参数,定义在mm-camera/mm-camera2/media-controller/modules/sensors/actuator/libs/lc898217xc/lc898217xc_actuator.h 中
/* Get diver param from actuator */
SENSOR_SUB_MODULE_PROCESS_EVENT(s_bundle, SUB_MODULE_ACTUATOR,
ACTUATOR_GET_AF_DRIVER_PARAM_PTR, &af_driver_ptr, rc);
// 4. 将马达参数,保存在 eeprom 的 af_driver_ptr 中
/* Set driver param to eeprom */
eeprom_set.af_driver_ptr = af_driver_ptr;
/* Perform calibration if eeprom is present */
if (s_bundle->sensor_info->subdev_id[SUB_MODULE_EEPROM] != -1)
{
SENSOR_SUB_MODULE_PROCESS_EVENT(s_bundle, SUB_MODULE_EEPROM, EEPROM_CALIBRATE_FOCUS_DATA, &eeprom_set, rc);
/* calcualte actuator sensitivity assuming total_steps is tuned to number of um */
s_bundle->actuator_sensitivity = (float)af_driver_ptr->actuator_tuned_params.region_params[0].qvalue /
af_driver_ptr->actuator_tuned_params.region_params[0].code_per_step;
}
/* protect the qvalue */
else {
af_driver_ptr->actuator_tuned_params.region_params[0].qvalue = 1;
}
// 5. 设置马达参数
SENSOR_SUB_MODULE_PROCESS_EVENT(s_bundle, SUB_MODULE_ACTUATOR, ACTUATOR_SET_PARAMETERS, NULL, rc);
return TRUE;
}
actuator name
,拼凑 lib 字符串,打开lib 库,且映射 actuator_driver_open_lib()
方法,获取马达参数保存在 driver_params
中CFG_ACTUATOR_POWERUP
上电CFG_ACTUATOR_INIT
, 马达 驱动初始化# mm-camera/mm-camera2/media-controller/modules/sensors/actuator/module/actuator.c
static int32_t af_actuator_init(void *ptr, void* data)
{
actuator_data_t *af_actuator_ptr = (actuator_data_t *)ptr;
char *name = (char *)data;
struct msm_actuator_cfg_data cfg;
SLOW("name = %s", (name) ? name : "null");
af_actuator_ptr->ctrl = NULL;
af_actuator_ptr->curr_step_pos = 0;
af_actuator_ptr->cur_restore_pos = 0;
af_actuator_ptr->name = name;
af_actuator_ptr->is_af_supported = 1;
af_actuator_ptr->params_loaded = 0;
af_actuator_ptr->ctrl = calloc(1, sizeof(actuator_ctrl_t));
// 1. 根据 actuator name,拼凑 lib 字符串,打开lib 库,且映射 actuator_driver_open_lib() 方法,获取马达参数保存在 driver_params 中
rc = actuator_load_lib(ptr);
=====================>
snprintf(driver_lib_name, PATH_SIZE_255, "libactuator_%s.so", af_actuator_ptr->name);
snprintf(driver_open_lib_func_name, 64, "actuator_driver_open_lib");
snprintf(driver_lib_name, PATH_SIZE_255, "libactuator_%s.so", af_actuator_ptr->name);
/* open actuator driver library */
af_actuator_ptr->driver_lib_handle = dlopen(driver_lib_name, RTLD_NOW);
*(void **)&open_lib_func = dlsym(af_actuator_ptr->driver_lib_handle, driver_open_lib_func_name);
driver_lib_data = (actuator_driver_ctrl_t *)open_lib_func();
af_actuator_ptr->ctrl->driver_params = &(driver_lib_data->actuator_driver_params);
<=====================
// 2. 下发 CFG_ACTUATOR_POWERUP 上电
rc = af_actuator_power_up(af_actuator_ptr);
=====================>
cfg.cfgtype = CFG_ACTUATOR_POWERUP;
rc = ioctl(af_actuator_ptr->fd, VIDIOC_MSM_ACTUATOR_CFG, &cfg);
<=====================
// 3. 下发 CFG_ACTUATOR_INIT, 马达 驱动初始化
cfg.cfgtype = CFG_ACTUATOR_INIT;
/* Invoke the IOCTL to initialize the actuator */
rc = ioctl(af_actuator_ptr->fd, VIDIOC_MSM_ACTUATOR_CFG, &cfg);
return rc;
}
static int32_t af_actuator_set_params(void *ptr)
{
af_driver_ptr = af_actuator_ptr->ctrl->driver_params;
if (af_actuator_ptr->is_af_supported) {
actuator_tuned_params = &af_driver_ptr->actuator_tuned_params;
actuator_params = &af_driver_ptr->actuator_params;
SLOW("Enter");
memset(&cfg, 0, sizeof(struct msm_actuator_cfg_data));
cfg.cfgtype = CFG_SET_ACTUATOR_INFO;
total_steps = actuator_tuned_params->region_params[
actuator_tuned_params->region_size - 1].step_bound[0] -
actuator_tuned_params->region_params[0].step_bound[1];
/* Translate reg params from uspace structure to kernel struct */
reg_params = (struct msm_actuator_reg_params_t *) malloc(
sizeof(*reg_params) * actuator_params->reg_tbl.reg_tbl_size);
translate_actuator_reg_params(reg_params,
&(actuator_params->reg_tbl.reg_params[0]),
actuator_params->reg_tbl.reg_tbl_size);
/* Translate reg settings from uspace structure to kernel struct */
init_settings = (struct reg_settings_t *) malloc(
sizeof(*init_settings) * actuator_params->init_setting_size);
translate_actuator_reg_settings(init_settings,
&(actuator_params->init_settings[0]),
actuator_params->init_setting_size);
/* Translate region params from uspace structure to kernel struct */
region_params = (struct region_params_t *) malloc(
sizeof(*region_params) * actuator_tuned_params->region_size);
translate_actuator_region_params(region_params,
&(actuator_tuned_params->region_params[0]),
actuator_tuned_params->region_size);
af_actuator_ptr->total_steps = total_steps;
cfg.cfg.set_info.af_tuning_params.total_steps = total_steps;
switch (actuator_params->act_type) {
case ACTUATOR_TYPE_VCM:
cfg.cfg.set_info.actuator_params.act_type = ACTUATOR_VCM;
break;
case ACTUATOR_TYPE_PIEZO:
cfg.cfg.set_info.actuator_params.act_type = ACTUATOR_PIEZO;
break;
case ACTUATOR_TYPE_HVCM:
cfg.cfg.set_info.actuator_params.act_type = ACTUATOR_HVCM;
break;
case ACTUATOR_TYPE_BIVCM:
cfg.cfg.set_info.actuator_params.act_type = ACTUATOR_BIVCM;
break;
default:
SERR("invalid act_type = %d", actuator_params->act_type);
break;
}
cfg.cfg.set_info.af_tuning_params.initial_code = actuator_tuned_params->initial_code;
cfg.cfg.set_info.actuator_params.reg_tbl_size = actuator_params->reg_tbl.reg_tbl_size;
cfg.cfg.set_info.actuator_params.reg_tbl_params = reg_params;
cfg.cfg.set_info.actuator_params.data_size = actuator_params->data_size;
cfg.cfg.set_info.actuator_params.i2c_addr = actuator_params->i2c_addr;
cfg.cfg.set_info.actuator_params.i2c_freq_mode = sensor_sdk_util_get_i2c_freq_mode(
actuator_params->i2c_freq_mode);
cfg.cfg.set_info.actuator_params.i2c_addr_type = sensor_sdk_util_get_kernel_i2c_addr_type(
actuator_params->i2c_addr_type);
cfg.cfg.set_info.af_tuning_params.region_size = actuator_tuned_params->region_size;
cfg.cfg.set_info.af_tuning_params.region_params = region_params;
cfg.cfg.set_info.actuator_params.init_setting_size = actuator_params->init_setting_size;
cfg.cfg.set_info.actuator_params.i2c_data_type = sensor_sdk_util_get_kernel_i2c_data_type(
actuator_params->i2c_data_type);
cfg.cfg.set_info.actuator_params.init_settings = init_settings;
/* Lens parking data */
cfg.cfg.set_info.actuator_params.park_lens.damping_step =
actuator_tuned_params->damping[0][0].ringing_params[0].damping_step;
cfg.cfg.set_info.actuator_params.park_lens.damping_delay =
actuator_tuned_params->damping[0][0].ringing_params[0].damping_delay;
cfg.cfg.set_info.actuator_params.park_lens.hw_params =
actuator_tuned_params->damping[0][0].ringing_params[0].hw_params;
cfg.cfg.set_info.actuator_params.park_lens.max_step = ACTUATOR_PARK_STEP;
/* Invoke the IOCTL to set the af parameters to the kernel driver */
rc = ioctl(af_actuator_ptr->fd, VIDIOC_MSM_ACTUATOR_CFG, &cfg);
free(reg_params);
free(init_settings);
free(region_params);
}
SDBG("Exit");
return rc;
}
# mm-camera/mm-camera2/media-controller/modules/sensors/actuator/module/actuator.c
case ACTUATOR_MOVE_FOCUS:
rc = af_actuator_move_focus(actuator_ctrl, data);
break;
主要工作如下:
actuator_set_position
设置为初始位置/** af_actuator_move_focus: function to move lens to desired
* position
*
* @ptr: pointer to actuator_data_t struct
* @data: pointer to af_update_t struct
*
* Return: 0 for success and negative error on failure
*
* This function moves lens to desired position as dictated
* by 3A algorithm **/
static int32_t af_actuator_move_focus(void *ptr, void *data)
{
af_driver_ptr = af_actuator_ptr->ctrl->driver_params;
// 1. 如果是 reset_lens ,则调用 actuator_set_position 设置为初始位置
if (af_update->reset_lens == TRUE) {
if (0 == af_actuator_ptr->curr_lens_pos) {
SLOW("Reset lens: calling actuator_set_position");
af_update->num_of_interval = 1;
/*For bi-vcm MOVE_FAR as the lens will be in the centre for other
types MOVE_NEAR*/
if (af_driver_ptr->actuator_params.act_type == ACTUATOR_TYPE_BIVCM) {
af_update->direction = MOVE_FAR;
} else {
af_update->direction = MOVE_NEAR;
}
af_update->pos[0] = af_driver_ptr->actuator_tuned_params.initial_code;
af_update->delay[0] = 0;
rc = actuator_set_position(ptr, data);
af_update->dac_value = af_driver_ptr->actuator_tuned_params.initial_code;
} else {
SLOW("calling af_actuator_set_default_focus");
rc = af_actuator_set_default_focus(ptr);
af_update->dac_value = af_actuator_ptr->curr_lens_pos;
}
return rc;
}
// 2. 统计需要移动的步数 num_of_steps, 及 移动的方向 direction
num_steps = (int32_t)af_update->num_of_steps;
direction = af_update->direction;
SLOW("num_steps %d dir %d", num_steps, direction);
if (direction == MOVE_NEAR)
sign_dir = 1;
else if (direction == MOVE_FAR)
sign_dir = -1;
dest_step_pos = (int16_t)(af_actuator_ptr->curr_step_pos + (sign_dir * num_steps));
if (dest_step_pos < 0)
dest_step_pos = 0;
else if (dest_step_pos > af_actuator_ptr->total_steps)
dest_step_pos = (int16_t)af_actuator_ptr->total_steps;
cfg.cfgtype = CFG_MOVE_FOCUS;
cfg.cfg.move.dir = (int8_t)direction;
cfg.cfg.move.sign_dir = sign_dir;
cfg.cfg.move.num_steps = num_steps;
cfg.cfg.move.dest_step_pos = dest_step_pos;
curr_scene = 0;
/* Determine scenario */
scenario_size = af_driver_ptr->actuator_tuned_params.scenario_size[direction];
for (index = 0; index < scenario_size; index++) {
if (num_steps <=
af_driver_ptr->actuator_tuned_params.ringing_scenario[direction][index]) {
curr_scene = index;
break;
}
}
/* Translate ringing params from uspace structure to kernel struct */
ringing_params = (struct damping_params_t *)malloc(
sizeof(*ringing_params) * af_driver_ptr->actuator_tuned_params.region_size);
translate_actuator_damping_param(ringing_params,
&(af_driver_ptr->actuator_tuned_params.
damping[direction][curr_scene].ringing_params[0]),
(uint32_t)af_driver_ptr->actuator_tuned_params.region_size);
cfg.cfg.move.ringing_params = ringing_params;
/* Invoke the IOCTL to move the focus */
rc = ioctl(af_actuator_ptr->fd, VIDIOC_MSM_ACTUATOR_CFG, &cfg);
af_actuator_ptr->curr_step_pos = dest_step_pos;
af_actuator_ptr->curr_lens_pos = cfg.cfg.move.curr_lens_pos;
/* sign extension for BIVCM type to indicate negative value */
if(af_driver_ptr->actuator_params.act_type == ACTUATOR_TYPE_BIVCM) {
bit_shift = (sizeof(af_update->dac_value) * 8) - af_driver_ptr->actuator_params.data_size;
af_actuator_ptr->curr_lens_pos = ((short)((af_actuator_ptr->curr_lens_pos) <<bit_shift))>>bit_shift;
}
af_update->dac_value = af_actuator_ptr->curr_lens_pos;
SLOW("bit_shift:%d, curr_step_pos:%d, curr_len_pos:%d",
bit_shift, af_actuator_ptr->curr_step_pos,
af_actuator_ptr->curr_lens_pos);
free(ringing_params);
if (af_actuator_ptr->plot_info.size < MAX_ACTUATOR_PLOT_INFO) {
af_actuator_ptr->plot_info.step_pos[af_actuator_ptr->plot_info.size] = af_actuator_ptr->curr_step_pos;
af_actuator_ptr->plot_info.lens_pos[af_actuator_ptr->plot_info.size++] = af_actuator_ptr->curr_lens_pos;
} else {
af_actuator_ptr->plot_info.size = 0;
}
return rc;
}
可以看出,最终是通过下发 VIDIOC_MSM_ACTUATOR_CFG 命令由底层来实现移动sensor,下发 VIDIOC_MSM_ACTUATOR_CFG 设置参数
static int actuator_set_position(void *ptr, void *data)
{
af_tune_ptr= &(af_actuator_ptr->ctrl->driver_params->actuator_tuned_params);
direction = af_update->direction;
if (direction < NUM_ACTUATOR_DIR) {
hw_params = af_tune_ptr->damping[direction][0].ringing_params->hw_params;
}
cfg.cfgtype = CFG_SET_POSITION;
cfg.cfg.setpos.number_of_steps = af_update->num_of_interval;
cfg.cfg.setpos.hw_params = hw_params;
for (index = 0; index < cfg.cfg.setpos.number_of_steps; index++) {
cfg.cfg.setpos.pos[index] = af_update->pos[index];
cfg.cfg.setpos.delay[index] = af_update->delay[index];
SLOW("pos:%d, delay:%d\n", cfg.cfg.setpos.pos[index], cfg.cfg.setpos.delay[index]);
af_update->dac_value = af_update->pos[index];
}
/* Invoke the IOCTL to set the positions */
rc = ioctl(af_actuator_ptr->fd, VIDIOC_MSM_ACTUATOR_CFG, &cfg);
return rc;
}
vendor 中马达通用驱动代码位于:msm-4.14/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
Kernel 中 dts 配置如下:
# msm-4.14/arch/arm64/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi
&cci {
actuator0: qcom,actuator@0 {
cell-index = <0>;
reg = <0x0>;
compatible = "qcom,actuator";
qcom,cci-master = <0>;
cam_vaf-supply = <&cam_actuator_regulator>;
qcom,cam-vreg-name = "cam_vaf";
qcom,cam-vreg-min-voltage = <3600000>;
qcom,cam-vreg-max-voltage = <3600000>;
qcom,cam-vreg-op-mode = <0>;
};
对应代码在 msm-4.14/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
static const struct of_device_id msm_actuator_dt_match[] = {
{.compatible = "qcom,actuator", .data = NULL},
{}
};
MODULE_DEVICE_TABLE(of, msm_actuator_dt_match);
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,
},
};
在 probe 函数中,主要工作如下:
cell-index
,qcom,cci-master
,qcom,cam-vreg-name
/dev/v4l-subdev0
ACT_DISABLE_STATE
static int32_t msm_actuator_platform_probe(struct platform_device *pdev)
{
struct msm_camera_cci_client *cci_client = NULL;
struct msm_actuator_ctrl_t *msm_actuator_t = NULL;
struct msm_actuator_vreg *vreg_cfg;
CDBG("Enter\n");
// 1. 解析DTS 信息,包括 cell-index,qcom,cci-master, qcom,cam-vreg-name 等信息
msm_actuator_t = kzalloc(sizeof(struct msm_actuator_ctrl_t), GFP_KERNEL);
rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index", &pdev->id);
rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master", &msm_actuator_t->cci_master);
if (of_find_property((&pdev->dev)->of_node,"qcom,cam-vreg-name", NULL)) {
vreg_cfg = &msm_actuator_t->vreg_cfg;
rc = msm_camera_get_dt_vreg_data((&pdev->dev)->of_node,&vreg_cfg->cam_vreg, &vreg_cfg->num_vreg);
}
// 2. 如果有配置GPIO,则初始化 gpio
rc = msm_sensor_driver_get_gpio_data(&(msm_actuator_t->gconf),(&pdev->dev)->of_node);
if (rc <= 0) {
pr_err("%s: No/Error Actuator GPIOs\n", __func__);
} else {
msm_actuator_t->cam_pinctrl_status = 1;
rc = msm_camera_pinctrl_init(&(msm_actuator_t->pinctrl_info), &(pdev->dev));
}
// 3. 注册V4L2 设备
msm_actuator_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops; // 包括 msm_actuator_subdev_ioctl() 函数
msm_actuator_t->actuator_mutex = &msm_actuator_mutex;
msm_actuator_t->cam_name = pdev->id; // cell-index
/* 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; // I2C 操作函数配置
msm_actuator_t->i2c_client.cci_client = kzalloc(sizeof(struct msm_camera_cci_client), GFP_KERNEL);
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;
// 4. 初始化 V4L2 subdev,配置 subdev 操作函数
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; // 需要初始化一个 device 屡有
// subdev name = msm_actuator
snprintf(msm_actuator_t->msm_sd.sd.name,ARRAY_SIZE(msm_actuator_t->msm_sd.sd.name), "msm_actuator");
media_entity_pads_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL);
msm_actuator_t->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_ACTUATOR;
msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
// 5. 注册 subdev 节点,/dev/v4l-subdev0
msm_sd_register(&msm_actuator_t->msm_sd);
=======================>
# msm-4.14/drivers/media/v4l2-core/v4l2-dev.c
__video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, sd->owner);
name_base = "v4l-subdev";
dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); // v4l-subdev0
ret = device_register(&vdev->dev);
ret = video_register_media_controller(vdev, type);
<=======================
// 6. 修改当前状态为 disable, ACT_DISABLE_STATE
msm_actuator_t->actuator_state = ACT_DISABLE_STATE;
msm_cam_copy_v4l2_subdev_fops(&msm_actuator_v4l2_subdev_fops); // 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;
}
case VIDIOC_MSM_ACTUATOR_CFG:
return msm_actuator_config(a_ctrl, argp);
static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, void *argp)
{
switch (cdata->cfgtype) {
case CFG_ACTUATOR_INIT:
rc = msm_actuator_init(a_ctrl); break;
case CFG_GET_ACTUATOR_INFO:
cdata->is_af_supported = 1;
cdata->cfg.cam_name = a_ctrl->cam_name;
rc = 0;
break;
case CFG_SET_ACTUATOR_INFO:
rc = msm_actuator_set_param(a_ctrl, &cdata->cfg.set_info);
break;
case CFG_SET_DEFAULT_FOCUS:
if (a_ctrl->func_tbl &&
a_ctrl->func_tbl->actuator_set_default_focus)
rc = a_ctrl->func_tbl->actuator_set_default_focus( a_ctrl, &cdata->cfg.move);
break;
case CFG_MOVE_FOCUS:
if (a_ctrl->func_tbl &&
a_ctrl->func_tbl->actuator_move_focus)
rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, &cdata->cfg.move);
# msm-4.14/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
break;
case CFG_ACTUATOR_POWERDOWN:
rc = msm_actuator_power_down(a_ctrl);
break;
case CFG_SET_POSITION:
if (a_ctrl->func_tbl &&
a_ctrl->func_tbl->actuator_set_position)
rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl, &cdata->cfg.setpos);
break;
case CFG_ACTUATOR_POWERUP:
rc = msm_actuator_power_up(a_ctrl);
break;
default:
break;
}
mutex_unlock(a_ctrl->actuator_mutex);
CDBG("Exit\n");
return rc;
}
# msm-4.14/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
rc = msm_actuator_power_up(a_ctrl);
static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl)
{
int rc = 0;
enum msm_sensor_power_seq_gpio_t gpio;
CDBG("%s called\n", __func__);
// 根据 dts 中 vreg 的信息来上电
rc = msm_actuator_vreg_control(a_ctrl, 1);
=======================>
vreg_cfg = &a_ctrl->vreg_cfg;
cnt = vreg_cfg->num_vreg;
for (i = 0; i < cnt; i++) {
if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE)
{
rc = msm_camera_config_single_vreg(&(a_ctrl->pdev->dev),&vreg_cfg->cam_vreg[i],
(struct regulator **)&vreg_cfg->data[i],config);
}
else if(a_ctrl->act_device_type == MSM_CAMERA_I2C_DEVICE)
{
rc = msm_camera_config_single_vreg(&(a_ctrl->i2c_client.client->dev),
&vreg_cfg->cam_vreg[i],(struct regulator **)&vreg_cfg->data[i], config);
}
}
<=======================
// 如果配置了 gpio 控制上电,则遍历配置 gpio
for (gpio = SENSOR_GPIO_AF_PWDM; gpio < SENSOR_GPIO_MAX; gpio++) {
if (a_ctrl->gconf && a_ctrl->gconf->gpio_num_info && a_ctrl->gconf->gpio_num_info->valid[gpio] == 1) {
rc = msm_camera_request_gpio_table( a_ctrl->gconf->cam_gpio_req_tbl,
a_ctrl->gconf->cam_gpio_req_tbl_size, 1);
if (a_ctrl->cam_pinctrl_status) {
rc = pinctrl_select_state(a_ctrl->pinctrl_info.pinctrl, a_ctrl->pinctrl_info.gpio_state_active);
}
gpio_set_value_cansleep(a_ctrl->gconf->gpio_num_info->gpio_num[gpio], 1);
}
}
/* VREG needs some delay to power up */
usleep_range(2000, 3000);
// 修改当前状态为 ENABLE, ACT_ENABLE_STATE
a_ctrl->actuator_state = ACT_ENABLE_STATE;
CDBG("Exit\n");
return rc;
}
static int msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl)
{
int rc = 0;
CDBG("Enter\n");
if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_util(&a_ctrl->i2c_client, MSM_CCI_INIT);
=========================>
+ # msm-4.14/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
+ .i2c_util = msm_sensor_cci_i2c_util,
+ rc = v4l2_subdev_call(client->cci_client->cci_subdev,core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+ ======>
+ #msm-4.14/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_dev.c
+ case VIDIOC_MSM_CCI_CFG:
+ rc = cam_cci_core_cfg(sd, arg);
+ ======>
+ # msm-4.14/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c
+ case MSM_CCI_INIT:
+ rc = cam_cci_init(sd, cci_ctrl);
+ break;
<=========================
}
a_ctrl->actuator_state = ACT_OPS_ACTIVE;
CDBG("Exit\n");
return rc;
}
好了,马达的代码,就分析到这,
对于 Camera 来说,马达是个被动器件,由上层来下发对焦移动的距离,所以底动,其实只是写 i2c 的动作。
详细的对焦过程,我们后续学习更深的时候,再来分析其逻辑。