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

【高通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.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

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

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

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

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

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,则初始化 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;
}


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


3.3 下发 CFG_ACTUATOR_POWERUP 上电

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


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

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

你可能感兴趣的:(Qualcomm经验总结,Android,Camera)