【高通SDM660平台 Android 10.0】20 --- Actuator 与 Kernel Actuator代码分析

  • 一、[vendor] 库文件 libactuator_lc898217xc.so
    • 1.1 Android.mk
    • 1.2 lc898217xc_actuator.c
    • 1.3 lc898217xc_actuator.h
  • 二、[vendor] 马达通用驱动
    • 2.1 actuator 操作方法初始化
    • 2.2 actuator 的调用
      • 2.2.1 马达初始化 module_sensor_actuator_init_calibrate( )
        • 2.2.1.1 马达初始化 af_actuator_init()
        • 2.2.1.2 马达参数设置 af_actuator_set_params()
        • 2.2.1.3 移动对焦 af_actuator_move_focus()
        • 2.2.1.4 设置lens 位置 actuator_set_position()
  • 三、[kernel] 马达驱动
    • 3.1 Kernel Actuator Probe 过程
    • 3.2 下发 VIDIOC_MSM_ACTUATOR_CFG 设置参数
    • 3.3 下发 CFG_ACTUATOR_POWERUP 上电
    • 3.4 下发 CFG_ACTUATOR_INIT 初始化马达驱动


《【高通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 驱动中马达相关的


一、[vendor] 库文件 libactuator_lc898217xc.so

代码路径位于: mm-camera/mm-camera2/media-controller/modules/sensors/actuator/libs/lc898217xc

1.1 Android.mk

# mm-camera/mm-camera2/media-controller/modules/sensors/actuator/libs/lc898217xc/Android.mkLOCAL_C_INCLUDES := lc898217xc_actuator.hLOCAL_SRC_FILES:= lc898217xc_actuator.cLOCAL_MODULE     ##      := lc898217xc_actuator.cLOCAL_SHARED_LIBRARIES := libcutilsinclude $(BUILD_SHARED_LIBRARY)

Android.mk 可以看出,最终将lc898217xc_actuator.c 编译成 lc898217xc_actuator.so

1.2 lc898217xc_actuator.c

代码比较简单,返回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;}

1.3 lc898217xc_actuator.h

{    .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] 马达通用驱动

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.cint32_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;}

2.1 actuator 操作方法初始化

# 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()


2.2 actuator 的调用

在 《【高通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.cvoid 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;    }  }}

2.2.1 马达初始化 module_sensor_actuator_init_calibrate( )

主要工作如下:

  1. 获取马达name ,本文 name = lc898217xc
  2. 调用 af_actuator_init() 初始化马达,加载马达的库,获取马达参数,触发kernel 马达上电,初始化马达驱动
  3. 获取 马达参数,定义在mm-camera/mm-camera2/media-controller/modules/sensors/actuator/libs/lc898217xc/lc898217xc_actuator.h
  4. 将马达参数,保存在 eeprom 的 af_driver_ptr 中
  5. 设置马达参数
# mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.cboolean 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;}

2.2.1.1 马达初始化 af_actuator_init()

  1. 根据 actuator name,拼凑 lib 字符串,打开lib 库,且映射 actuator_driver_open_lib() 方法,获取马达参数保存在 driver_params
  2. 下发 CFG_ACTUATOR_POWERUP 上电
  3. 下发 CFG_ACTUATOR_INIT, 马达 驱动初始化
# mm-camera/mm-camera2/media-controller/modules/sensors/actuator/module/actuator.cstatic 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;}

2.2.1.2 马达参数设置 af_actuator_set_params()

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;}

2.2.1.3 移动对焦 af_actuator_move_focus()

# 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;

主要工作如下:

  1. 如果是 reset_lens ,则调用 actuator_set_position 设置为初始位置
  2. 根据turning 计算的结果,统计需要移动的步数 num_of_steps, 及 移动的方向 direction,最终高用
/** 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;}

2.2.1.4 设置lens 位置 actuator_set_position()

可以看出,最终是通过下发 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;}

三、[kernel] 马达驱动

vendor 中马达通用驱动代码位于:msm-4.14/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c


3.1 Kernel Actuator Probe 过程

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 函数中,主要工作如下:

  1. 解析DTS 信息,包括 cell-indexqcom,cci-masterqcom,cam-vreg-name
  2. 如果有配置GPIO,则初始化 gpio
  3. 注册V4L2 设备
  4. 初始化 V4L2 subdev,配置 subdev 操作函数
  5. 注册 subdev 节点,/dev/v4l-subdev0
  6. 修改当前状态为 disable, 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,则初始化 gpiorc = 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_actuatorsnprintf(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-subdev0msm_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-subdev0ret = device_register(&vdev->dev);ret = video_register_media_controller(vdev, type);<=======================// 6. 修改当前状态为 disable, ACT_DISABLE_STATEmsm_actuator_t->actuator_state = ACT_DISABLE_STATE;msm_cam_copy_v4l2_subdev_fops(&msm_actuator_v4l2_subdev_fops);// v4l2_subdev_fops#ifdef CONFIG_COMPATmsm_actuator_v4l2_subdev_fops.compat_ioctl32 = msm_actuator_subdev_fops_ioctl;#endifmsm_actuator_t->msm_sd.sd.devnode->fops = &msm_actuator_v4l2_subdev_fops;CDBG("Exit\n");return rc;}

3.2 下发 VIDIOC_MSM_ACTUATOR_CFG 设置参数

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.cbreak;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;}

3.3 下发 CFG_ACTUATOR_POWERUP 上电

# msm-4.14/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.crc = 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 控制上电,则遍历配置 gpiofor (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_STATEa_ctrl->actuator_state = ACT_ENABLE_STATE;CDBG("Exit\n");return rc;}

3.4 下发 CFG_ACTUATOR_INIT 初始化马达驱动

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 的动作。

详细的对焦过程,我们后续学习更深的时候,再来分析其逻辑。

更多相关文章

  1. android ListView内容无限循环显示
  2. Android(安卓)8/9高通平台客制化虚拟导航按键隐藏
  3. android平台移植valgrind
  4. Android(安卓)高通平台camera hal层调试方法和命令
  5. Android(安卓)TTS 使用教程
  6. tess_two Android图片文字识别
  7. Android(安卓)OpenCV java.lang.UnsatisfiedLinkError n_mat
  8. 1. Android启动过程
  9. Android菜单定制总结

随机推荐

  1. ListView(Adapter实现)
  2. 终于上班了
  3. Android下拉刷新上拉加载控件的使用
  4. Android(安卓)Studio 项目gradle构建 仓
  5. android:json解析库的选择
  6. Android(安卓)4.2 JellyBean Graphic Com
  7. android设置多个类似APP其中的一个为默认
  8. 【Android】【基础】获取屏幕宽高
  9. Android 标题栏、状态栏隐藏
  10. Android打开页面