我是靠谱客的博主 自觉皮卡丘,最近开发中收集的这篇文章主要介绍【高通SDM660平台 Android 10.0】(22) --- Flashlight 及 Kernel Flashlight 代码分析一、[硬件] 闪光灯硬件原理图二、[vendor] 库文件 lib三、[vendor] 通用代码 flash.c 初始化四、[Kernel] flashlight 驱动,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

【高通SDM660平台 Android 10.0】22 --- Flashlight 及 Kernel Flashlight 代码分析

  • 一、[硬件] 闪光灯硬件原理图
  • 二、[vendor] 库文件 lib
  • 三、[vendor] 通用代码 flash.c 初始化
    • 3.1 module_sensor_flash_init()
    • 3.2 flash_process()
  • 四、[Kernel] flashlight 驱动
    • 4.1 Kernel probe 初始化 msm_flash_platform_probe()
    • 4.2 CFG_FLASH_INIT 初始化闪光灯
    • 4.3 CFG_FLASH_LOW 开启手电筒或开启预闪
    • 4.4 CFG_FLASH_OFF 关闭闪光灯
    • 4.5 CFG_FLASH_HIGH 开启主闪


原创文章列表:

《【高通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代码分析》
《【高通SDM660平台 Android 10.0】(22) — Flashlight 及 Kernel Flashlight 代码分析》



一、[硬件] 闪光灯硬件原理图

本文以 mm-camera/mm-camera2/media-controller/modules/sensors/configs/sdm660_camera.xml 中的flash 为例,
先来看下原理图:
在这里插入图片描述

从原理图中可以看出,闪光灯的电 VDD_FLASH 及 开关控制引脚 FLASH_STROBE、FLASH_LED1、FLASH_LED2、FLASH_LED3 都是由 PM660L 来控制的。
其中 :

  • VDD_FLASH : 是主供电
  • FLASH_STROBE : 手电筒模式时的PWM输出脚
  • FLASH_LED1、FLASH_LED2、FLASH_LED3 : 闪光灯模式时的PWM输出脚,可以包含单闪、双闪需求

这个是一个方框图,由电池供电,经过升压,接着通过脉宽引脚的高电平来控制LED 的亮暗程度。。
在这里插入图片描述

所以整个原理是比较清晰的,代码方面要需对上述引脚做如下控制

  • 闪光灯的上下电
  • 手电筒模式还是闪光灯模式
  • 根据亮度来控制PWM 输出的高电平脉宽占比

二、[vendor] 库文件 lib

sdm660_camera.xml 中可以看出,<FlashName>pmic</FlashName>
其代码位于:mm-camera/mm-camera2/media-controller/modules/sensors/flash/libs/pmic/pmic_flash.h,最终编译生成 libflash_pmic.so 库

在其头文件中:

# mm-camera/mm-camera2/media-controller/modules/sensors/flash/libs/pmic/pmic_flash.h

#include "flash_lib.h"

/*
 * if flash_driver_type is set to FLASH_DRIVER_DEFAULT
 * flash specifications are taken from kernel and the flash is driven by kernel.
 * For other value FLASH_DRIVER_PMIC / FLASH_DRIVER_GPIO
 * FLASH_DRIVER_I2C all the information like max current
 * max duration and num of flashes must be provided in this driver.
 */
static flash_lib_t flash_lib_ptr = {
  .flash_name = "pmic",
  .flash_driver_type = FLASH_DRIVER_TYPE_DEFAULT,
  .main_flash_on_frame_skip = 3,
  .main_flash_off_frame_skip = 3,
  .torch_on_frame_skip = 2,
  .torch_off_frame_skip = 2,
};

头文件中主要是定义了在闪光灯打开时,摄像头需要跳过的帧数,及在手机筒打开时需要跳过的帧数。
还是一个比较重要的就是 flash_driver_type

  1. .flash_driver_type = FLASH_DRIVER_TYPE_DEFAULT, 时,闪光灯的相关配置是由kernel 来定义的。
  2. .flash_driver_type = FLASH_DRIVER_PMIC, 和其他值时,闪光灯的相关配置需要由本lib 库来定义。

三、[vendor] 通用代码 flash.c 初始化

在前在 《【高通SDM660平台 Android 10.0】(18) — Camera start_session() 过程分析》 中,我们分析过了,
flash open动作是在 module_sensor_offload_open()中调用打开 闪光灯节点的。
flash 初始化是由 module_sensor_offload_init_config() 中来调用的。

void module_sensor_offload_init_config( void* param1,  void* param2,  void* param3 __attribute__((unused)),
  					void* param4 __attribute__((unused)))
{
  // 初始化闪光灯 ,调用 flash_init(),打开闪光灯 lib 库
  SLOW("flash subdev id = %d",
  status = module_sensor_flash_init(s_bundle);
  
  // 获取使用闪光灯时,跳过的帧数,如果没设置,默认过滤 2 帧
  /* Get led frame skip timing parameters */
  SENSOR_SUB_MODULE_PROCESS_EVENT(s_bundle, SUB_MODULE_LED_FLASH, LED_FLASH_GET_FRAME_SKIP_TIME_PARAMS, s_bundle, rc);
  if (rc < 0) {
    SERR("failed to get led off frame skip time");
    s_bundle->main_flash_on_frame_skip = 2;
    s_bundle->main_flash_off_frame_skip = 2;
    s_bundle->torch_on_frame_skip = 2;
    s_bundle->torch_off_frame_skip = 2;
  }
}

3.1 module_sensor_flash_init()

# mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c

boolean module_sensor_flash_init(module_sensor_bundle_info_t *s_bundle)
{
  /* Get flash name from camera config read from daemon init */
  a_name = s_bundle->sensor_common_info.camera_config.flash_name;

  SENSOR_SUB_MODULE_PROCESS_EVENT(s_bundle, SUB_MODULE_LED_FLASH, LED_FLASH_INIT, a_name, rc);
  return TRUE;
}

可以看出,在 module_sensor_flash_init() 中主要是调用 flash_init() 来做初始化的。

  case LED_FLASH_INIT:
    rc = flash_init(flash_ctrl, data);
    goto flash_process_Exit;

我们来看下 flash_init() 的内容。

  1. 根据传递的name ,拼凑lib 库的字符串,此处为 libflash_pmic.so,同步将 pmic_flash.h中的结构体内容保存在 flash_ptr->driver_lib_data 中。
  2. 解析 pmic 参数信息,及 flash_driver_type 信息。
  3. 配置 I2C 地址信息
  4. 解析上下电信息,准备下发到 Kernel 中
  5. 下发 CFG_FLASH_INIT 命令到 Kernel 中,相关信息保存在 .flash_init_info
static int32_t flash_init(void *ptr, void *data)
{
  sensor_flash_data_t *flash_ctrl = (sensor_flash_data_t*)ptr;
  struct msm_flash_init_info_t flash_init_info;
  struct msm_flash_cfg_data_t flash_cfg;
  struct msm_camera_i2c_reg_setting_array *flash_init_settings = NULL;
  struct msm_sensor_power_setting_array *power_setting_array = NULL;

  SDBG("Enter");

  /* memset flash init info */
  memset(&flash_init_info, 0, sizeof(flash_init_info));

  // 1. 根据传递的name ,拼凑lib 库的字符串,此处为 libflash_pmic.so,同步将 pmic_flash.h中的结构体内容保存在 flash_ptr->driver_lib_data 中
  /* Load flash library */
  rc = flash_load_lib(ptr, name);
  // 2. 解析 pmic 参数信息。
  flash_update_settings_size(flash_ctrl->driver_lib_data);
  // 3. 解析 flash_driver_type 信息
  switch (flash_ctrl->driver_lib_data->flash_driver_type) {
    case FLASH_DRIVER_TYPE_PMIC:
        flash_init_info.flash_driver_type = FLASH_DRIVER_PMIC;
        break;
    case FLASH_DRIVER_TYPE_I2C:
        flash_init_info.flash_driver_type = FLASH_DRIVER_I2C;
        break;
    case FLASH_DRIVER_TYPE_GPIO:
        flash_init_info.flash_driver_type = FLASH_DRIVER_GPIO;
        break;
    case FLASH_DRIVER_TYPE_DEFAULT:
        flash_init_info.flash_driver_type = FLASH_DRIVER_DEFAULT;
        break;
  }
  // 4. 配置I2C 地址
  flash_init_info.slave_addr = flash_ctrl->driver_lib_data->i2c_flash_info.slave_addr;
  flash_init_info.i2c_freq_mode = sensor_sdk_util_get_i2c_freq_mode(
    			flash_ctrl->driver_lib_data->i2c_flash_info.i2c_freq_mode);
    			
  // 5. 解析上下电信息,准备下发到 Kernel 中
  /* Translate power settings from uspace structure to kernel struct */
  power_setting_array = (struct msm_sensor_power_setting_array *)malloc(sizeof(*power_setting_array));
  translate_camera_power_setting(power_setting_array,&(flash_ctrl->driver_lib_data->power_setting_array));

  /* Translate reg array settings from uspace structure to kernel struct */
  flash_init_settings = (struct msm_camera_i2c_reg_setting_array *)malloc(sizeof(*flash_init_settings));

  translate_sensor_reg_setting_array(flash_init_settings,
   			 &(flash_ctrl->driver_lib_data->i2c_flash_info.flash_init_settings));

  flash_init_info.power_setting_array = power_setting_array;
  flash_init_info.settings = flash_init_settings;


  for (i = 0; i < MAX_LED_TRIGGERS; i++) {
    flash_cfg.flash_current[i] = flash_ctrl->driver_lib_data->max_flash_current[i];
    flash_cfg.flash_duration[i] = flash_ctrl->driver_lib_data->max_flash_duration[i];
    SLOW("i = %d flash_current = %d flash_duration = %d", i, flash_cfg.flash_current[i], flash_cfg.flash_duration[i]);
  }

  // 6. 下发 CFG_FLASH_INIT 命令到 Kernel 中,相关信息保存在 .flash_init_info 中
  flash_cfg.cfg_type = CFG_FLASH_INIT;
  flash_cfg.cfg.flash_init_info = &flash_init_info;

  rc = ioctl(flash_ctrl->fd, VIDIOC_MSM_FLASH_CFG, &flash_cfg);

  for (i = 0; i < MAX_LED_TRIGGERS; i++) {
    flash_ctrl->flash_max_current[i] = flash_cfg.flash_current[i];
    flash_ctrl->flash_max_duration[i] = flash_cfg.flash_duration[i];
    SLOW("i = %d flash_max_current = %d flash_max_duration = %d",
      			i, flash_ctrl->flash_max_current[i], flash_ctrl->flash_max_duration[i]);
  }

  SDBG("Exit");
  free(power_setting_array);
  free(flash_init_settings);
  return SENSOR_SUCCESS;
}

3.2 flash_process()

flash_process() 是 flashlight 的核心函数

# mm-camera/mm-camera2/media-controller/modules/sensors/flash/module/flash.c

static int32_t flash_process(void *ctrl, sensor_submodule_event_type_t event, void *data)
{
  flash_ctrl = (sensor_flash_data_t *)ctrl;
  rer = flash_ctrl->rer;
  dual_led_setting = &flash_ctrl->dual_led_setting;

  /* Initilize to invalid value
   * Kernel uses default values if not updated */
  cfg.flash_current[0] = default_current;
  cfg.flash_current[1] = default_current;

  /* Translate reg array settings from uspace structure to kernel struct */
  flash_settings = (struct msm_camera_i2c_reg_setting_array *)malloc( sizeof(*flash_settings));
  SLOW("event %d", event);

  switch (event) {
  case LED_FLASH_GET_MAX_CURRENT: {				// 1. 获得闪光灯的最大电流
    int32_t ** flash_current = (int32_t **)data;
    *flash_current = &(flash_ctrl->flash_max_current[0]);
    goto flash_process_Exit;
  }
  case LED_FLASH_GET_MAX_DURATION: {			// 2. 获得双闪的最大电流
    uint32_t* flash_duration = (uint32_t*)data;
    *flash_duration = flash_ctrl->flash_max_duration[0];
    goto flash_process_Exit;
  }
  case LED_FLASH_SET_CURRENT: {					// 3. 设置闪光灯的最大电流
    /* Get currents for dual LED */
    rc = flash_set_current(data, dual_led_setting);
    goto flash_process_Exit;
  }
  case LED_FLASH_INIT:							// 4. 闪光灯初始化
    rc = flash_init(flash_ctrl, data);
    goto flash_process_Exit;
  case LED_FLASH_SET_RER_CHROMATIX: {			// 5. 设置 红眼 chromatix 参数
    rer_chromatix = (red_eye_reduction_type *)data;
    /* Get (RER) data from chromatix */
    rc = flash_rer_set_chromatix(rer, rer_chromatix);
    goto flash_process_Exit;
  }
  case LED_FLASH_GET_RER_PARAMS: {				// 6. 获取 红眼 参数
    *(int32_t *) data = rer->cfg->red_eye_reduction_led_flash_enable;
    goto flash_process_Exit;
  }
  case LED_FLASH_SET_RER_PARAMS: {				// 7. 设置 红眼 参数
    mode = (int32_t *)data;
    rc = flash_rer_set_parm(rer, *mode);
    goto flash_process_Exit;
  }
  case LED_FLASH_SET_FIRING_POWER:{				// 8. 设置电流
    flashPower = *(uint8_t *)data;
    goto flash_process_Exit;
  }
  case LED_FLASH_SET_RER_PROCESS: {				// 9. 配置红眼处理函数
    led_module_params = (module_sensor_params_t *)data;
    rc = flash_rer_sequence_process(rer, led_module_params);
    goto flash_process_Exit;
  }
  case LED_FLASH_SET_OFF:						// 10. 关闭闪光灯
    SHIGH("Turning off flash");
    translate_sensor_reg_setting_array(flash_settings,
      &(flash_ctrl->driver_lib_data->i2c_flash_info.flash_off_settings));
    cfg.cfg_type = CFG_FLASH_OFF;
    cfg.cfg.settings = flash_settings;
    break;
  case LED_FLASH_SET_TORCH:
  case LED_FLASH_SET_PRE_FLASH: {				// 11. 开启 手电筒 或 开启预闪,下发参数 CFG_FLASH_LOW
    SHIGH("Turning on torch/pre flash");
    /* Pre flash mode */
    translate_sensor_reg_setting_array(flash_settings,
      		&(flash_ctrl->driver_lib_data->i2c_flash_info.flash_low_settings));
    cfg.cfg_type = CFG_FLASH_LOW;
    cfg.cfg.settings = flash_settings;

    if (dual_led_setting->low_setting[0] == 0 && dual_led_setting->low_setting[1] == 0) {
      cfg.flash_current[0] = data ? *(int32_t *)data : default_current;
      cfg.flash_current[1] = data ? *(int32_t *)data : default_current;
    } else {
      cfg.flash_current[0] = dual_led_setting->low_setting[0];
      cfg.flash_current[1] = dual_led_setting->low_setting[1];
    }
    break;
  }
  case LED_FLASH_SET_RER_PULSE_FLASH: {			// 12. 设置红眼 脉冲 电平
    /* RER flash pulses */
    translate_sensor_reg_setting_array(flash_settings,
      &(flash_ctrl->driver_lib_data->i2c_flash_info.flash_high_settings));
    cfg.cfg_type = CFG_FLASH_HIGH;

    /* Use chromatix current if exist (set in RER_PROCESS)*/
    cfg.flash_current[0] = data ? *(int32_t *)data : default_current;
    cfg.flash_current[1] = data ? *(int32_t *)data : default_current;
    cfg.cfg.settings = flash_settings;

    temp = (dual_led_setting->high_setting[0] + dual_led_setting->high_setting[1]);
    if (temp > 0) {
      /* Update with Dual LED current */
      cfg.flash_current[0] = (cfg.flash_current[0] * dual_led_setting->high_setting[0]) / temp;
      cfg.flash_current[1] = (cfg.flash_current[1] * dual_led_setting->high_setting[1]) / temp;
    }
    break;
  }
  case LED_FLASH_SET_MAIN_FLASH: {				// 13. 开启主闪
    SHIGH("Turning on main flash");
    /* Main flash mode */
    translate_sensor_reg_setting_array(flash_settings,
      		&(flash_ctrl->driver_lib_data->i2c_flash_info.flash_high_settings));
    cfg.cfg_type = CFG_FLASH_HIGH;
    cfg.cfg.settings = flash_settings;

    if (dual_led_setting->high_setting[0] == 0 && dual_led_setting->high_setting[1] == 0) {
      cfg.flash_current[0] = data ? *(int32_t *)data : default_current;
      cfg.flash_current[1] = data ? *(int32_t *)data : default_current;
    } else {
      cfg.flash_current[0] = dual_led_setting->high_setting[0];
      cfg.flash_current[1] = dual_led_setting->high_setting[1];
    }
    rc = flash_rer_wait_pupil_contract(rer, led_module_params);
    break;
  }
  case LED_FLASH_GET_FRAME_SKIP_TIME_PARAMS:	// 14. 获取 帧数过滤 参数
  {
    module_sensor_bundle_info_t* s_bundle = (module_sensor_bundle_info_t*)data;
    rc = flash_get_frame_skip_timing_params(s_bundle,flash_ctrl);
    goto flash_process_Exit;
  }
  }

  rc = ioctl(flash_ctrl->fd, VIDIOC_MSM_FLASH_CFG, &cfg);

flash_process_Exit:
  free(flash_settings);
  return rc;
}

可以看出,操作闪光灯,都是操作 flash_process() 函数,最终都是通过 ioctl 来下发指令和参数的,还是比较好理解的。
接下来我们来看下 Kernel 中的代码。


四、[Kernel] flashlight 驱动

4.1 Kernel probe 初始化 msm_flash_platform_probe()

# msm-4.14/arch/arm64/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi
&soc {
	led_flash0: qcom,camera-flash@0 {
		cell-index = <0>;
		compatible = "qcom,camera-flash";
		qcom,flash-source = <&pm660l_flash0 &pm660l_flash1>;
		qcom,torch-source = <&pm660l_torch0 &pm660l_torch1>;
		qcom,switch-source = <&pm660l_switch0>;
		status = "ok";
	};

	led_flash1: qcom,camera-flash@1 {
		cell-index = <1>;
		compatible = "qcom,camera-flash";
		qcom,flash-source = <&pm660l_flash2>;
		qcom,torch-source = <&pm660l_torch2>;
		qcom,switch-source = <&pm660l_switch1>;
		status = "ok";
	};

对应的c 代码位于: msm-4.14/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c

static const struct of_device_id msm_flash_dt_match[] = {
	{.compatible = "qcom,camera-flash", .data = NULL},
	{}
};
MODULE_DEVICE_TABLE(of, msm_flash_dt_match);

static struct platform_driver msm_flash_platform_driver = {
	.probe = msm_flash_platform_probe,
	.driver = {
		.name = "qcom,camera-flash",
		.owner = THIS_MODULE,
		.of_match_table = msm_flash_dt_match,
	},
};

主要工作流程:

  1. 解析dts 信息,包括 cell-indexqcom,cci-masterqcom,switch-sourceqcom,flash-sourceqcom,max-currentqcom,duration 等。
  2. 初始化V4L2 subdev,节点名为 /dev/v4l-subdevX
  3. 如果type = FLASH_DRIVER_PMIC
    会对每一个 touch_source 注册为 led 设备,创建一个sys 节点, qcom,led-name = "led:torch_0";
static int32_t msm_flash_platform_probe(struct platform_device *pdev)
{
	struct msm_flash_ctrl_t *flash_ctrl = NULL;
	struct msm_camera_cci_client *cci_client = NULL;

	flash_ctrl = kzalloc(sizeof(struct msm_flash_ctrl_t), GFP_KERNEL);

	memset(flash_ctrl, 0, sizeof(struct msm_flash_ctrl_t));

	flash_ctrl->pdev = pdev;
	// 1. 解析dts 信息,包括 cell-index、qcom,cci-master、
	// qcom,switch-source、qcom,flash-source、qcom,max-current、qcom,duration
	// qcom,torch-source、qcom,gpio-vana、qcom,gpio-vio、qcom,gpio-vaf、qcom,gpio-vdig、qcom,gpio-reset
	// qcom,gpio-standby、qcom,gpio-af-pwdm、qcom,gpio-flash-en、qcom,gpio-flash-reset
	rc = msm_flash_get_dt_data(pdev->dev.of_node, flash_ctrl);

	// 2. 初始化 V4L2 subdev,节点名为 /dev/v4l-subdevX
	flash_ctrl->flash_state = MSM_CAMERA_FLASH_RELEASE;
	flash_ctrl->power_info.dev = &flash_ctrl->pdev->dev;
	flash_ctrl->flash_device_type = MSM_CAMERA_PLATFORM_DEVICE;
	flash_ctrl->flash_mutex = &msm_flash_mutex;
	flash_ctrl->flash_i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;
	flash_ctrl->flash_i2c_client.cci_client = kzalloc(
		sizeof(struct msm_camera_cci_client), GFP_KERNEL);

	cci_client = flash_ctrl->flash_i2c_client.cci_client;
	cci_client->cci_subdev = msm_cci_get_subdev();
	cci_client->cci_i2c_master = flash_ctrl->cci_i2c_master;

	/* Initialize sub device */
	v4l2_subdev_init(&flash_ctrl->msm_sd.sd, &msm_flash_subdev_ops);
	v4l2_set_subdevdata(&flash_ctrl->msm_sd.sd, flash_ctrl);

	flash_ctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops;
	flash_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	snprintf(flash_ctrl->msm_sd.sd.name, ARRAY_SIZE(flash_ctrl->msm_sd.sd.name),"msm_camera_flash");
	media_entity_pads_init(&flash_ctrl->msm_sd.sd.entity, 0, NULL);
	flash_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_FLASH;
	flash_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
	msm_sd_register(&flash_ctrl->msm_sd);

	CDBG("%s:%d flash sd name = %s", __func__, __LINE__,
		flash_ctrl->msm_sd.sd.entity.name);
	msm_cam_copy_v4l2_subdev_fops(&msm_flash_v4l2_subdev_fops);
#ifdef CONFIG_COMPAT
	msm_flash_v4l2_subdev_fops.compat_ioctl32 =
		msm_flash_subdev_fops_ioctl;
#endif
	flash_ctrl->msm_sd.sd.devnode->fops = &msm_flash_v4l2_subdev_fops;

	// 3. 如果 type = FLASH_DRIVER_PMIC,
	// 会对每一个 touch_source 注册为 led 设备,创建一个sys 节点, qcom,led-name = "led:torch_0";
	if (flash_ctrl->flash_driver_type == FLASH_DRIVER_PMIC)
		rc = msm_torch_create_classdev(pdev, flash_ctrl);
		=========>
			for (i = 0; i < fctrl->torch_num_sources; i++) {
			if (fctrl->torch_trigger[i]) {
				led_classdev_register(&pdev->dev, &msm_torch_led[i]);
					----->
						ret = led_add_brightness_hw_changed(led_cdev);
						led_update_brightness(led_cdev);
						led_init_core(led_cdev);
						led_trigger_set_default(led_cdev);
			}
		<=========
	CDBG("probe successn");
	return rc;
}

好了,probe 流程,到这就完了,很常规的解析节点,注册V4L2,注册LED 设备,没啥好说的。
接下来,我们来看下上层操作闪光灯时,下发的一些指令是怎么跑的。


4.2 CFG_FLASH_INIT 初始化闪光灯

在闪光灯代码中,主要包括如下五种 ioctrl 指令:

enum msm_flash_cfg_type_t {
	CFG_FLASH_INIT,		// 初始化
	CFG_FLASH_RELEASE,	// 释放
	CFG_FLASH_OFF,		// 关闭
	CFG_FLASH_LOW,		// 手电筒 或 预闪
	CFG_FLASH_HIGH,		// 主闪
};

接下来,看下 init 做了什么事:

static int32_t msm_flash_config(struct msm_flash_ctrl_t *flash_ctrl, void *argp)
{
	switch (flash_data->cfg_type) {
	case CFG_FLASH_INIT:
		rc = msm_flash_init_prepare(flash_ctrl, flash_data);
		break;
	}
	rc = msm_flash_prepare(flash_ctrl);
}

在 msm_flash_init_prepare() 中主要是,保存闪光灯电流参数,及保存上层下发的所有参数

static int32_t msm_flash_init_prepare(struct msm_flash_ctrl_t *flash_ctrl,	struct msm_flash_cfg_data_t *flash_data)
{
	struct msm_flash_cfg_data_t flash_data_k;
	struct msm_flash_init_info_t flash_init_info;
	int32_t i = 0;

	flash_data_k.cfg_type = flash_data->cfg_type;
	for (i = 0; i < MAX_LED_TRIGGERS; i++) {
		flash_data_k.flash_current[i] = flash_data->flash_current[i];
		flash_data_k.flash_duration[i] = flash_data->flash_duration[i];
	}

	flash_data_k.cfg.flash_init_info = &flash_init_info;
	if (copy_from_user(&flash_init_info,(void __user *)(flash_data->cfg.flash_init_info),
		sizeof(struct msm_flash_init_info_t))) {
		pr_err("%s copy_from_user failed %dn",__func__, __LINE__);
		return -EFAULT;
	}
	return msm_flash_init(flash_ctrl, &flash_data_k);
}

接着调用 msm_flash_init()
在函数中,通过 camera_flash_init() 函数来下发参数, 初始化 flash_state = MSM_CAMERA_FLASH_INIT

# msm-4.14/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
static int32_t msm_flash_init(struct msm_flash_ctrl_t *flash_ctrl,struct msm_flash_cfg_data_t *flash_data)
{
	uint32_t i = 0;
	int32_t rc = -EFAULT;
	enum msm_flash_driver_type flash_driver_type = FLASH_DRIVER_DEFAULT;

	CDBG("Enter");
	if (flash_data->cfg.flash_init_info->flash_driver_type == FLASH_DRIVER_DEFAULT) {
		flash_driver_type = flash_ctrl->flash_driver_type;
		for (i = 0; i < MAX_LED_TRIGGERS; i++) {
			flash_data->flash_current[i] = flash_ctrl->flash_max_current[i];
			flash_data->flash_duration[i] = flash_ctrl->flash_max_duration[i];
		}
	} else if (flash_data->cfg.flash_init_info->flash_driver_type == flash_ctrl->flash_driver_type) {
		flash_driver_type = flash_ctrl->flash_driver_type;
		for (i = 0; i < MAX_LED_TRIGGERS; i++) {
			flash_ctrl->flash_max_current[i] = flash_data->flash_current[i];
			flash_ctrl->flash_max_duration[i] = flash_data->flash_duration[i];
		}
	}
	for (i = 0; i < ARRAY_SIZE(flash_table); i++) {
		if (flash_driver_type == flash_table[i]->flash_driver_type) {
			flash_ctrl->func_tbl = &flash_table[i]->func_tbl;
			rc = 0;
		}
	}
	if (flash_ctrl->func_tbl->camera_flash_init) {
		rc = flash_ctrl->func_tbl->camera_flash_init(flash_ctrl, flash_data);
	}

	flash_ctrl->flash_state = MSM_CAMERA_FLASH_INIT;

	CDBG("Exit");
	return 0;
}

camera_flash_init定义如下:
可以看出,当使和pmic 时,是不需要进行 camera_flash_init() 的,函数 为空。
如果走的是 gpio ,就会开始关闭所有的gpio,详细可以自行分析 msm_flash_gpio_init()
如果 i2c ,则会初始化上电,然后通过 i2c 定义闪光灯相关的配置。

#msm-4.14/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c 
static struct msm_flash_table msm_pmic_flash_table = {
	.flash_driver_type = FLASH_DRIVER_PMIC,
	.func_tbl = {
		.camera_flash_init = NULL,
		.camera_flash_release = msm_flash_release,
		.camera_flash_off = msm_flash_off,
		.camera_flash_low = msm_flash_low,
		.camera_flash_high = msm_flash_high,
		.camera_flash_query_current = msm_flash_query_current,
	},
};

static struct msm_flash_table msm_gpio_flash_table = {
	.flash_driver_type = FLASH_DRIVER_GPIO,
	.func_tbl = {
		.camera_flash_init = msm_flash_gpio_init,
		.camera_flash_release = msm_flash_release,
		.camera_flash_off = msm_flash_off,
		.camera_flash_low = msm_flash_low,
		.camera_flash_high = msm_flash_high,
		.camera_flash_query_current = NULL,
	},
};

static struct msm_flash_table msm_i2c_flash_table = {
	.flash_driver_type = FLASH_DRIVER_I2C,
	.func_tbl = {
		.camera_flash_init = msm_flash_i2c_init,
		.camera_flash_release = msm_flash_i2c_release,
		.camera_flash_off = msm_flash_i2c_write_setting_array,
		.camera_flash_low = msm_flash_i2c_write_setting_array,
		.camera_flash_high = msm_flash_i2c_write_setting_array,
		.camera_flash_query_current = NULL,
	},
};

最终,还会调用 rc = msm_flash_prepare(flash_ctrl);
switch_trigger 对应的就是 dts 中的 qcom,switch-source = <&pm660l_switch0>;
其内容如下:

pm660l_switch0: qcom,led_switch_0 {
				label = "switch";
				qcom,led-name = "led:switch_0";
				qcom,led-mask = <3>;
				qcom,default-led-trigger = "switch0_trigger";
			};

我们来看下 msm_flash_prepare 的代码,在代码中,就是 通过 switch 进行上电。

static int32_t msm_flash_prepare(struct msm_flash_ctrl_t *flash_ctrl)
{
	if (flash_ctrl->switch_trigger == NULL) {
		pr_err("%s:%d Invalid argumentn",__func__, __LINE__);
		return -EINVAL;
	}
	// 1. 上电
	if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT &&
		flash_ctrl->is_regulator_enabled == 0) {
		ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, ENABLE_REGULATOR, NULL);
		flash_ctrl->is_regulator_enabled = 1;
	} else if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_RELEASE &&
		flash_ctrl->is_regulator_enabled) {
		ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger,DISABLE_REGULATOR, NULL);
		flash_ctrl->is_regulator_enabled = 0;
	}
	CDBG("%s:%d:Exitn", __func__, __LINE__);
	return ret;
}

看下 qpnp_flash_led_prepare() 代码:
有关 led 子系统的代码,可以分析下 msm-4.14/drivers/leds/leds-qpnp-flash-v2.c,有机会我们后面分析,
今天主要分析闪光灯的流程,点到为止,不然篇幅会太长了。

int qpnp_flash_led_prepare(struct led_trigger *trig, int options,int *max_current)
{
	// 通过 led:switch_0 名字,找到 led dev设备
	led_cdev = trigger_to_lcdev(trig);
	// 上电
	rc = qpnp_flash_led_regulator_control(led_cdev, options, max_current);
	return rc;
}

4.3 CFG_FLASH_LOW 开启手电筒或开启预闪

static int32_t msm_flash_config(struct msm_flash_ctrl_t *flash_ctrl, void *argp)
{
case CFG_FLASH_LOW:
		if ((flash_ctrl->flash_state == MSM_CAMERA_FLASH_OFF) || (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT)) {
			rc = flash_ctrl->func_tbl->camera_flash_low(flash_ctrl, flash_data);
		}
		break;
}

接下来,我们进入 msm_flash_low() 函数看下,
通过 led_trigger_event() 来点亮。

static int32_t msm_flash_low(struct msm_flash_ctrl_t *flash_ctrl,struct msm_flash_cfg_data_t *flash_data)
{
	CDBG("Entern");
	/* Turn off flash triggers */
	for (i = 0; i < flash_ctrl->flash_num_sources; i++)
		if (flash_ctrl->flash_trigger[i])
			led_trigger_event(flash_ctrl->flash_trigger[i], 0);

	/* Turn on flash triggers */
	for (i = 0; i < flash_ctrl->torch_num_sources; i++) {
		if (flash_ctrl->torch_trigger[i]) {
			max_current = flash_ctrl->torch_max_current[i];
			if (flash_data->flash_current[i] >= 0 && flash_data->flash_current[i] < max_current) {
				curr = flash_data->flash_current[i];
			} else {
				curr = flash_ctrl->torch_op_current[i];
				pr_debug("LED current clamped to %dn", curr);
			}
			CDBG("low_flash_current[%d] = %d", i, curr);
			led_trigger_event(flash_ctrl->torch_trigger[i], curr);
		}
	}
	if (flash_ctrl->switch_trigger)
		led_trigger_event(flash_ctrl->switch_trigger, 1);
	CDBG("Exitn");
	return 0;
}

4.4 CFG_FLASH_OFF 关闭闪光灯

	case CFG_FLASH_OFF:
		rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, flash_data);

很好理解,通过 led_trigger_event() 来触发 关闭

static int32_t msm_flash_off(struct msm_flash_ctrl_t *flash_ctrl,struct msm_flash_cfg_data_t *flash_data)
{
	int32_t i = 0;

	CDBG("Entern");

	for (i = 0; i < flash_ctrl->flash_num_sources; i++)
		if (flash_ctrl->flash_trigger[i])
			led_trigger_event(flash_ctrl->flash_trigger[i], 0);

	for (i = 0; i < flash_ctrl->torch_num_sources; i++)
		if (flash_ctrl->torch_trigger[i])
			led_trigger_event(flash_ctrl->torch_trigger[i], 0);
			
	if (flash_ctrl->switch_trigger)
		led_trigger_event(flash_ctrl->switch_trigger, 0);

	CDBG("Exitn");
	return 0;
}

4.5 CFG_FLASH_HIGH 开启主闪

case CFG_FLASH_HIGH:
		rc = flash_ctrl->func_tbl->camera_flash_high(flash_ctrl, flash_data);
static int32_t msm_flash_high( struct msm_flash_ctrl_t *flash_ctrl, struct msm_flash_cfg_data_t *flash_data)
{
	/* Turn off torch triggers */
	for (i = 0; i < flash_ctrl->torch_num_sources; i++)
		if (flash_ctrl->torch_trigger[i])
			led_trigger_event(flash_ctrl->torch_trigger[i], 0);

	/* Turn on flash triggers */
	for (i = 0; i < flash_ctrl->flash_num_sources; i++) {
		if (flash_ctrl->flash_trigger[i]) {
			max_current = flash_ctrl->flash_max_current[i];
			if (flash_data->flash_current[i] >= 0 && flash_data->flash_current[i] < max_current) {
				curr = flash_data->flash_current[i];
			} else {
				curr = flash_ctrl->flash_op_current[i];
				pr_debug("LED flash_current[%d] clamped %dn", i, curr);
			}
			CDBG("high_flash_current[%d] = %d", i, curr);
			led_trigger_event(flash_ctrl->flash_trigger[i], curr);
		}
	}
	if (flash_ctrl->switch_trigger)
		led_trigger_event(flash_ctrl->switch_trigger, 1);
	return 0;
}

好啦,闪光灯代码,就先看到这里,前面逻辑还是比较好理解的,
后面到了kernel 层,主要就是led 子系统的工作了,由它来实现点亮和关闭灯。

后面有时间,我们再来单独分析下,LED 子系统。

最后

以上就是自觉皮卡丘为你收集整理的【高通SDM660平台 Android 10.0】(22) --- Flashlight 及 Kernel Flashlight 代码分析一、[硬件] 闪光灯硬件原理图二、[vendor] 库文件 lib三、[vendor] 通用代码 flash.c 初始化四、[Kernel] flashlight 驱动的全部内容,希望文章能够帮你解决【高通SDM660平台 Android 10.0】(22) --- Flashlight 及 Kernel Flashlight 代码分析一、[硬件] 闪光灯硬件原理图二、[vendor] 库文件 lib三、[vendor] 通用代码 flash.c 初始化四、[Kernel] flashlight 驱动所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部