[sdm660 android9.0]补光灯代码分析
时间:2023-05-30 18:37:00
高通相关dtsi解析
驱动程序 v2 用于在背景光昏暗时为相机传感器提供照明,以捕捉良好的图像。它也可用于手电筒/手电筒应用。 它是 Qualcomm Technologies Inc. 参考平台上 PMIC 的一部分。 主节点: 所需属性: - 兼容:应该是兼容qcom,qpnp-flash-led-v2” - reg : 闪光灯 LED 模块的基址和大小 - qcom,pmic-revid : PMIC revid 模块模型。用于识别 PMIC 子类型。 可选属性: - 中断:指定与闪光灯相关的中断。 - 中断名称:指定与中断相关的中断名称。 - qcom,hdrm-auto-mode : 选择是否使用布尔类型的净空自动模式 - qcom,isc-delay-us : 指定短路延迟的整数类型。有效值为 32、64、128、192。单位为 uS。 - qcom,warmup-delay-us : 指定预热延迟的整数类型。有效值为 32、64、128、192。单位为 uS。 - qcom,short-circuit-det :使用布尔属性进行短路故障检测。 - qcom,open-circuit-det :启用开路故障检测的布尔属性。 - qcom,vph-droop-det :启用 VPH 布尔属性下垂检测。 - qcom,vph-droop-hys-mv : 指定 VPH 下垂滞后的整数属性。 qcom,vph-droop-det 使用时间。有效值为 0、25、50 和 75。 单位为毫伏。 - qcom,vph-droop-thresh-mv : 指定 VPH 下降阈值的整数属性。 qcom,vph-droop-det 使用时间。有效值为 2500 到 3200,步长为 100。单位为 mV。 - qcom,vph-droop-debounce-us : 指定 VPH 下垂抖动时间的整数属性。 qcom,vph-droop-det 使用时间。有效值为 0、8、16 和 26。单位为 uS。 - qcom,led1n2-iclamp-low-ma :用于缓解指定电流钳低电平的整数属性。 mA。允许 值与 qcom,max-current 下相同。 - qcom,led1n2-iclamp-mid
-ma :整数属性,用于指定电流钳位中间电平以进行缓解。单位为 mA。允许 值与 qcom
,max
-current 下相同。
- qcom
,led3
-iclamp
-low
-ma :整数属性,用于指定电流钳低电平以进行缓解。单位为 mA。允许 值与 qcom
,max
-current 下相同。
- qcom
,led3
-iclamp
-mid
-ma :整数属性,用于指定电流钳位中间电平以进行缓解。单位为 mA。允许 值与 qcom
,max
-current 下相同。
- qcom
,vled
-max
-uv :闪电流预测缓解的整数属性。默认值为
3500000 uV。
- qcom
,ibatt
-ocp
-threshold
-ua :闪电流预测缓解的整数属性。默认值为
4500000 uA。
- qcom
,rparasitic
-uohm:用于指示电池电阻寄生分量的闪光电流预测缓解的整数属性。默认值为
0 uOhm。
- qcom
,lmh
-ocv
-threshold
-uv :闪存电流抢占式 LMH 缓解所需的属性。默认值为
3700000 uV。
- qcom
,lmh
-rbatt
-threshold
-uohm :闪存电流抢占式 LMH 缓解所需的属性。默认值为
400000 uOhm。
- qcom
,lmh
-mitigation
-sel :配置闪存电流抢占式 LMH 缓解的可选属性。接受的值为:
0:MITIGATION_DISABLED
1:MITIGATION_BY_ILED_THRESHOLD
2:MITIGATION_BY_SW 默认值为
2。
- qcom
,chgr
-mitigation
-sel :可选属性,用于配置闪光电流抢占式充电器缓解。 接受的值为:
0:MITIGATION_DISABLED
1:MITIGATION_BY_ILED_THRESHOLD
2:MITIGATION_BY_SW 默认值为
2。
- qcom
,lmh
-level :配置闪存电流抢占式 LMH 缓解的可选属性。接受的值为
0、
1 和
3。默认值为
0。
- qcom
,iled
-thrsh
-ma:可选属性,用于配置触发硬件抢占式缓解的 LED 电流阈值。单位为 mA。默认值为
1000。可接受的值在
0
-
3100 范围内,步长为
100。
0 禁用自主硬件缓解。
- qcom
,thermal
-derate
-en :启用闪电流热缓解的布尔属性。
- qcom
,thermal
-derate
-current :用于散热的一系列电流限制。如果指定了 qcom
,thermal
-derate
-en,则为必需。单位为 mA。格式是qcom,热降额电流
=
<OTST1_LIMIT
, OTST2_LIMIT
, OTST3_LIMIT
>。
- qcom
,otst
-ramp
-back
-up
-dis
: 在热降额触发后禁用电流斜坡备份的布尔属性
- qcom
,thermal
-derate
-slow :整数属性来指定缓慢降低热速率。单位在美国。允许 值为:
128、
256、
512、
1024、
2048、
4096、
8192 和
314592。
- qcom
,thermal
-derate
-fast :整数属性,用于指定快速降低热速率。单位在美国。允许 值为:
32、
64、
96、
128、
256、
384 和
512.
- qcom
,thermal
-debounce
: 指定热去抖动时间的整数属性。仅当 qcom
,thermal
-derate
-en 时使用被指定。 子节点内的必需属性。智利节点包含每个单独 LED 的设置。每个 LED 硬件都需要一个自己的节点和一个开关节点来控制亮度。为了打开
/关闭LED和更好的调节器控制,引入了“led
:
switch”节点。 “led
:
switch”从其他节点获取几个现有属性以简化操作。为了向后兼容,切换节点可以是可选的:
- 标签:将使用的 LED 类型,“闪光灯”或“手电筒”。
- qcom
,led
-name
: LED 的名称。可接受的值为“led
:flash_0”、“led
:flash_1”、“led
:torch_0”、“led
:torch_1”
- qcom
,
default
-led
-trigger:触发相机闪光灯和手电筒。可接受的值为“flash0_trigger”、“flash1_trigger”、“torch0_trigger”、torch1_trigger”
- qcom
,id
: 每个物理 LED 的枚举 ID。可接受的值为“
0”、“
1”等。
- qcom
,max
-current
: 此 LED 允许的最大电流。有效值应该是
0 到
1000 之间的整数,表示
0 到
1000 mA。
- qcom
,pmic
-revid
: PMIC 修订 ID 源。 PMI8996 修订检查需要此属性。 子节点内的可选属性:
- qcom
,current
: LED 的默认电流强度。可接受的值应该是
0 t
1000 之间的整数,表示
0 到
1000 mA。
- qcom
,duration
: 闪光灯 LED 的持续时间。当持续时间到期时,硬件将关闭闪光灯 LED。值应为
10 ms 到
1280 ms,增量步长为
10 ms。不适用于手电筒。 LED
:SWITCH 节点需要处理用作闪光灯的 LED。
- reg
<n
>
:
reg<n>
(
<n
> 代表数字。例如
0
,
1
,
2
,
.
.
) 属性是添加对多个电源的支持。它包括两个属性调节器名称和最大电压。调节器节点内的必需属性:
- max
-voltage:这指定调节器的最大电压。某些开关或升压调节器不需要此属性。
补光灯有两种工作模式:
Camera flash led分flash和torch两种模式。
Flash: 拍照时闪光灯瞬间亮一下的情况,电流比较大,目前是1000mA,最大电流不能超过led的最大承受能力。
Torch: 只用于录video或者拿led当手电筒的情况,电流不能太大,例如现在用的是200mA。
Flash的开启需要先从torch过渡,也就是电流慢慢增大,减小冲击。
1.库文件:
从sdm660_camera.xml中,pmic,
其代码位于:vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/flash/libs/pmic/pmic_flash.h,最终编译生成 libflash_pmic.so 库
定义 使用闪光灯和手电筒时 跳过的帧数
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,
当 .flash_driver_type = FLASH_DRIVER_TYPE_DEFAULT, 时,闪光灯的相关配置是由kernel 来定义的。
当 .flash_driver_type = FLASH_DRIVER_PMIC, 和其他值时,闪光灯的相关配置需要由本lib 库来定义。
2.通用代码vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/flash/module/flash.c
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor_offload.c
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;
}
}
2.1 初始化:flash_init()
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
module_sensor_flash_init()
vendor/qcom/proprietary/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() 来做初始化的。—LED_FLASH_INIT
flash_init()
根据传递的name ,拼凑lib 库的字符串,此处为 libflash_pmic.so,同步将 pmic_flash.h中的结构体内容保存在 flash_ptr->driver_lib_data 中。
解析 pmic 参数信息,及 flash_driver_type 信息。
配置 I2C 地址信息
解析上下电信息,准备下发到 Kernel 中
下发 CFG_FLASH_INIT 命令到 Kernel 中,相关信息保存在 .flash_init_info 中
tatic 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;
}
2.2核心函数:flash_process()
操作闪光灯,都是操作 flash_process() 函数,最终都是通过 ioctl 来下发指令和参数的
# 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.