【高通SDM660平台 Android 10.0】(10) --- Camera Sensor lib 与 Kernel Camera Probe 代码分析


【高通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平台】Camera Capture 流程》
《【高通SDM660平台】Camera mm-qcamera-app 代码分析》



在前面《【高通SDM660平台 Android 10.0】Qcom Camera Daemon 代码分析》 中,
我们分析了 Camera module_sensor_init() 的整个过程,考虑到篇幅的问题,本文是接module_sensor_init() 继续分析的。
主题如下:

  1. 分析 Camera lib 库的代码
  2. vendor 下发 CFG_SINIT_PROBE 后,Kernel 中 Camera Probe的流程

好, 开始吧!


一、libmmcamera_imx258.so 代码分析

Sensor LIB 库代码位于 /vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/sensor/libs
本文以 imx258 为例。

先来看下imx258_lib.c,其最核心的函数就是 sensor_open_lib
返回 sensor_lib_ptr 结构体,所有的 Camera 信息,都保存在该结构体中。

@ /vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/sensor/libs/imx258/imx258_lib.c

/**
 * FUNCTION: sensor_open_lib
 * DESCRIPTION: Open sensor library and returns data pointer
 **/
void *sensor_open_lib(void)
{
  return &sensor_lib_ptr;
}

我们来看下 sensor_lib_ptr 结构体的定义

1.1 struct sensor_lib_t 结构体

@ /vendor/qcom/proprietary/mm-camerasdk/sensor/includes/sensor_lib.h
typedef struct {
  /* sensor slave info */ 
  // 从设备包括,I2C地址、I2C速率、Sensor_id 寄存器地址及Sensor_id 值、上下电的时序及电压值
  struct camera_sensor_slave_info sensor_slave_info;

  /* sensor output settings */
  // 包括 出图的格式(BAYER / YCbCr), 连接类型为 MIPI CSI
  sensor_output_t sensor_output;
  
  /* sensor output register address */
  // 输出寄存器的地址,pclk,及line length pclk 、 frame length lines
  struct sensor_output_reg_addr_t output_reg_addr;

  /* sensor exposure gain register address */
  // 曝光增益
  struct sensor_exp_gain_info_t exp_gain_info;

  /* sensor aec info */
  sensor_aec_data_t aec_info;

  /* number of frames to skip after start stream info */
  // preview 前丢弃过的 帧数
  unsigned short sensor_num_frame_skip;

  /* number of frames to skip after start HDR stream info */
  // HDR 丢弃的帧数
  unsigned short sensor_num_HDR_frame_skip;

  /* sensor pipeline delay */
  // pipeline 帧延时
  unsigned int sensor_max_pipeline_frame_delay;

  /* sensor lens info */
  // sensor line info 信息
  sensor_property_t sensor_property;

  /* imaging pixel array size info */
  // 像素点大小,宽高
  sensor_imaging_pixel_array_size pixel_array_size_info;

  /* Sensor color level information */
  // 颜色等级
  sensor_color_level_info color_level_info;

  /* sensor port info that consists of cid mask and fourcc mapaping */
  sensor_stream_info_array_t sensor_stream_info_array;

  /* Sensor Settings */
  // 初始化Camera 寄存器配置
  struct camera_i2c_reg_setting_array start_settings;
  // 关闭Camera 时的寄存器配置
  struct camera_i2c_reg_setting_array stop_settings;
  struct camera_i2c_reg_setting_array groupon_settings;
  struct camera_i2c_reg_setting_array groupoff_settings;
  struct camera_i2c_reg_setting_array embedded_data_enable_settings;
  struct camera_i2c_reg_setting_array embedded_data_disable_settings;
  struct camera_i2c_reg_setting_array aec_enable_settings;
  struct camera_i2c_reg_setting_array aec_disable_settings;
  struct camera_i2c_reg_setting_array dualcam_master_settings;
  struct camera_i2c_reg_setting_array dualcam_slave_settings;

  /* sensor test pattern info */
  // 测试图信息
  sensor_test_info test_pattern_info;
  /* sensor effects info */
  struct sensor_effect_info effect_info;

  /* Sensor Settings Array */
  //初始化 Camera 寄存器配置
  struct sensor_lib_reg_settings_array init_settings_array;
  struct sensor_lib_reg_settings_array res_settings_array;
  
  // 不同辨率的输出信息,xy像素大小,pclk,fps,数据传输速率
  struct sensor_lib_out_info_array     out_info_array;
  // MIPI CSI 信息
  struct sensor_csi_params             csi_params;
  struct sensor_csid_lut_params_array  csid_lut_params_array;
  struct sensor_lib_crop_params_array  crop_params_array;

  /* Exposure Info */
  sensor_exposure_table_t exposure_func_table;

  /* video_hdr mode info*/
  struct sensor_lib_meta_data_info_array meta_data_out_info_array;

  /* sensor optical black regions */
  sensor_optical_black_region_t optical_black_region_info;

  /* sensor_capability */
  sensor_capability_t sensor_capability;

  /* sensor_awb_table_t */
  sensor_awb_table_t awb_func_table;

    /* sensor_awb_table_t */
  sensor_fps_table_t fps_func_table;

  /* Parse RDI stats callback function */
  sensor_RDI_parser_stats_t parse_RDI_stats;

  /* full size info */
  sensor_rolloff_config rolloff_config;

  /* analog-digital conversion time */
  long long adc_readout_time;

  /* number of frames to skip for fast AEC use case */
  unsigned short sensor_num_fast_aec_frame_skip;

  /* add soft delay for sensor settings like exposure, gain ...*/
  unsigned char app_delay[SENSOR_DELAY_MAX];

  /* for noise profile calculation
     Tuning team must update with proper values. */
  struct sensor_noise_coefficient_t noise_coeff;

  /* Flag to be set if any external library are to be loaded */
  unsigned char external_library;

  sensorlib_pdaf_apis_t sensorlib_pdaf_api;
  // PDAF 配轩
  pdaf_lib_t            pdaf_config;

  /* sensor orientation flag */
  sensor_orientation_type_t  sensor_orientation;

} sensor_lib_t;


1.2 imx258_lib.h 头文件分析

@ /vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/sensor/libs/imx258/imx258_lib.h


/* imx258_lib.h
 *
 * Copyright (c) 2015-2018 Qualcomm Technologies, Inc.
 * All Rights Reserved.
 * Confidential and Proprietary - Qualcomm Technologies, Inc.
 */

#ifndef __IMX258_LIB_H__
#define __IMX258_LIB_H__

#include "sensor_lib.h"
#include "eeprom_lib.h"
#include "pdaf_api.h"
#include "pdaf_camif_api.h"
#define SENSOR_MODEL "imx258"

/* IMX258 Regs */
#define IMX258_DIG_GAIN_GR_ADDR       0x020E
#define IMX258_DIG_GAIN_R_ADDR        0x0210
#define IMX258_DIG_GAIN_B_ADDR        0x0212
#define IMX258_DIG_GAIN_GB_ADDR       0x0214
#define IMX258_EXP_RATIO_ADDR         0x0222
#define IMX258_ABS_GAIN_R_WORD_ADDR   0x0B90
#define IMX258_ABS_GAIN_B_WORD_ADDR   0x0B92

/* IMX258 CONSTANTS */
#define IMX258_MAX_INTEGRATION_MARGIN   20

/* STATS DATA TYPE */
#define IMX258_CSI_PD_ISTATS            0x2F

#define IMX258_DATA_PEDESTAL            0x40 /* 10bit value */

#define IMX258_MIN_AGAIN_REG_VAL        0 /* 1.0x */
#define IMX258_MAX_AGAIN_REG_VAL        480 /* 16.0x */

#define IMX258_MIN_DGAIN_REG_VAL        256 /* 1.0x */
#define IMX258_MAX_DGAIN_REG_VAL        256 /* 1.0x */

#define IMX258_MAX_DGAIN_DECIMATOR      256

/* IMX258 FORMULAS */
#define IMX258_MIN_AGAIN    (512 / (512 - IMX258_MIN_AGAIN_REG_VAL))
#define IMX258_MAX_AGAIN    (512 / (512 - IMX258_MAX_AGAIN_REG_VAL))

#define IMX258_MIN_DGAIN    (IMX258_MIN_DGAIN_REG_VAL / 256)
#define IMX258_MAX_DGAIN    (IMX258_MAX_DGAIN_REG_VAL / 256)

#define IMX258_MIN_GAIN     IMX258_MIN_AGAIN * IMX258_MIN_DGAIN
#define IMX258_MAX_GAIN     IMX258_MAX_AGAIN * IMX258_MAX_DGAIN

/* uncomment FLIP_MIRROR macro to
   enable flip and mirror in sensor readout
   change bayer pattern
   load pdaf flip and mirror header
*/
//#define FLIP_MIRROR
#define START_REG_ARRAY \
{ \
  {0x0100, 0x01, 0x00}, \
}

#define STOP_REG_ARRAY \
{ \
  {0x0100, 0x00, 0x00}, \
}

#define GROUPON_REG_ARRAY \
{ \
  {0x0104, 0x01, 0x00}, \
}

#define GROUPOFF_REG_ARRAY \
{ \
  {0x0104, 0x00, 0x00}, \
}

// 初始化 寄存器配置
#define INIT0_REG_ARRAY \
{ \
  /* External Clock Settings */ \
  {0x0136, 0x18, 0x00}, \
  {0x0137, 0x00, 0x00}, \
  /* Global Settings */ \
  {0x3051, 0x00, 0x00}, \
  ......  //配置一系烈的寄存器
  {0x3006, 0x00, 0x00}, \
  {0x3007, 0x00, 0x00}, \
}

#ifndef FLIP_MIRROR
  #define FLIP_MIRROR_SETTING {{0x0101, 0x00, 0x00}}
#else
  #define FLIP_MIRROR_SETTING {{0x0101, 0x03, 0x00}}
#endif
// 分辨率0 寄存器配置
#define RES0_REG_ARRAY \
{ \
  /* Mode A1: 4208x3120 Full 30fps */ \
  /* Output Format Settings */ \
  {0x0112, 0x0A, 0x00}, \
  {0x0113, 0x0A, 0x00}, \
  ......  //配置一系烈的寄存器
  {0x0818, 0x00, 0x00}, \
  {0x0819, 0x47, 0x00}, \
}
// 分辨率1 寄存器配置
#define RES1_REG_ARRAY \
{\
  /* (Reg-10)Mode: Full 16:9 30 fps */ \
  /* Output Format Settings */ \
  {0x0112, 0x0A, 0x00}, \
  {0x0113, 0x0A, 0x00}, \
  /* Clock Settings */ \
  {0x0301, 0x05, 0x00}, \
  {0x0303, 0x02, 0x00}, \
  ......  //配置一系烈的寄存器
  {0x0818, 0x00, 0x00}, \
  {0x0819, 0x47, 0x00}, \
}
// 分辨率2 寄存器配置
#define RES2_REG_ARRAY \
{ \
  /* Mode: 2100x1560 2x2 binning 30 fps */ \
  /* Output Format Settings */ \
  {0x0112, 0x0A, 0x00}, \
  {0x0113, 0x0A, 0x00}, \
  ......  //配置一系烈的寄存器
  {0x0819, 0x47, 0x00}, \
  {0x3031, 0x00, 0x00}, \
}
// 分辨率3 寄存器配置
#define RES3_REG_ARRAY \
{ \
  /* Mode: 2100x1176 60 fps */ \
  /* Output Format Settings */ \
  {0x0112, 0x0A, 0x00}, \
  {0x0113, 0x0A, 0x00}, \
   ......  //配置一系列的寄存器
  {0x0819, 0x47, 0x00}, \
  {0x3031, 0x00, 0x00}, \
}
// 分辨率4 寄存器配置
#define RES4_REG_ARRAY \
{ \
  /* Mode: 1400x784 90 fps*/ \
  /* Output Format Settings */ \
  {0x0112, 0x0A, 0x00}, \
  {0x0113, 0x0A, 0x00}, \
   ......  //配置一系列的寄存器
  {0x0819, 0x47, 0x00}, \
  {0x3031, 0x00, 0x00}, \
}
// 分辨率5 寄存器配置
#define RES5_REG_ARRAY \
{ \
  /* Mode: 1400x760 120 fps*/ \
  /* Output Format Settings */ \
  {0x0112, 0x0A, 0x00}, \
  {0x0113, 0x0A, 0x00}, \
   ......  //配置一系列的寄存器
  {0x0819, 0x47, 0x00}, \
  {0x3031, 0x00, 0x00}, \
}

/* Sensor Handler */
static sensor_lib_t sensor_lib_ptr =
{
  .sensor_slave_info =
  {
    .sensor_name = SENSOR_MODEL,			// "imx258"
    .slave_addr = 0x20,						// 7位地址0x20, 010 0000, 对应的8位地址为0100 0000, 0x40
    .i2c_freq_mode = SENSOR_I2C_MODE_FAST,
    .addr_type = CAMERA_I2C_WORD_ADDR,
    .sensor_id_info =
    {
      .sensor_id_reg_addr = 0x0016,
      .sensor_id = 0x0258,
    },
    .power_setting_array =
    {
      .power_setting_a =
      {
        {
          .seq_type = CAMERA_POW_SEQ_GPIO,
          .seq_val = CAMERA_GPIO_RESET,
          .config_val = GPIO_OUT_LOW,
          .delay = 1,
        },
        {
          .seq_type = CAMERA_POW_SEQ_GPIO,
          .seq_val = CAMERA_GPIO_VANA,
          .config_val = GPIO_OUT_HIGH,
          .delay = 1,
        },
        {
          .seq_type = CAMERA_POW_SEQ_VREG,
          .seq_val = CAMERA_VANA,
          .config_val = 0,
          .delay = 0,
        },
        {
          .seq_type = CAMERA_POW_SEQ_GPIO,
          .seq_val = CAMERA_GPIO_VDIG,
          .config_val = GPIO_OUT_HIGH,
          .delay = 1,
        },
        {
          .seq_type = CAMERA_POW_SEQ_VREG,
          .seq_val = CAMERA_VDIG,
          .config_val = 0,
          .delay = 0,
        },
        {
          .seq_type = CAMERA_POW_SEQ_VREG,
          .seq_val = CAMERA_VIO,
          .config_val = 0,
          .delay = 0,
        },
        {
          .seq_type = CAMERA_POW_SEQ_GPIO,
          .seq_val = CAMERA_GPIO_VAF,
          .config_val = GPIO_OUT_HIGH,
          .delay = 1,
        },
        {
          .seq_type = CAMERA_POW_SEQ_CLK,
          .seq_val = CAMERA_MCLK,
          .config_val = 24000000,
          .delay = 1,
        },
        {
          .seq_type = CAMERA_POW_SEQ_GPIO,
          .seq_val = CAMERA_GPIO_RESET,
          .config_val = GPIO_OUT_HIGH,
          .delay = 12,
        },
      },
      .size = 9,
      .power_down_setting_a =
      {
        {
          .seq_type = CAMERA_POW_SEQ_GPIO,
          .seq_val = CAMERA_GPIO_RESET,
          .config_val = GPIO_OUT_LOW,
          .delay = 1,
        },
        {
          .seq_type = CAMERA_POW_SEQ_CLK,
          .seq_val = CAMERA_MCLK,
          .config_val = 0,
          .delay = 1,
        },
        {
          .seq_type = CAMERA_POW_SEQ_VREG,
          .seq_val = CAMERA_VIO,
          .config_val = 0,
          .delay = 0,
        },
        {
          .seq_type = CAMERA_POW_SEQ_VREG,
          .seq_val = CAMERA_VDIG,
          .config_val = 0,
          .delay = 0,
        },
        {
          .seq_type = CAMERA_POW_SEQ_GPIO,
          .seq_val = CAMERA_GPIO_VDIG,
          .config_val = GPIO_OUT_LOW,
          .delay = 1,
        },
        {
          .seq_type = CAMERA_POW_SEQ_VREG,
          .seq_val = CAMERA_VANA,
          .config_val = 0,
          .delay = 0,
        },
        {
          .seq_type = CAMERA_POW_SEQ_GPIO,
          .seq_val = CAMERA_GPIO_VANA,
          .config_val = GPIO_OUT_LOW,
          .delay = 1,
        },
        {
          .seq_type = CAMERA_POW_SEQ_GPIO,
          .seq_val = CAMERA_GPIO_VAF,
          .config_val = GPIO_OUT_LOW,
          .delay = 1,
        },
      },
      .size_down = 8,
    },
  },
  .sensor_output =
  {
    .output_format = SENSOR_BAYER,
    .connection_mode = SENSOR_MIPI_CSI,
    .raw_output = SENSOR_10_BIT_DIRECT,
#ifndef FLIP_MIRROR
    .filter_arrangement = SENSOR_RGGB,
#else
    .filter_arrangement = SENSOR_BGGR,
#endif
  },
  .output_reg_addr =
  {
    .x_output = 0x034C,
    .y_output = 0x034E,
    .line_length_pclk = 0x0342,
    .frame_length_lines = 0x0340,
  },
  .exp_gain_info =
  {
    .coarse_int_time_addr = 0x0202,
    .global_gain_addr = 0x0204,
    .vert_offset = IMX258_MAX_INTEGRATION_MARGIN,
  },
  .aec_info =
  {
    .min_gain = IMX258_MIN_GAIN,
    .max_gain = IMX258_MAX_GAIN,
    .max_analog_gain = IMX258_MAX_AGAIN,
    .max_linecount = 65525 - IMX258_MAX_INTEGRATION_MARGIN,
  },
  .sensor_num_frame_skip = 2,
  .sensor_num_HDR_frame_skip = 2,
  .sensor_max_pipeline_frame_delay = 2,
  .sensor_property =
  {
    .pix_size = 1.12, /* um */
    .sensing_method = SENSOR_SMETHOD_ONE_CHIP_COLOR_AREA_SENSOR,
    .crop_factor = 5.78,
  },
  .pixel_array_size_info =
  {
    .active_array_size =
    {
      .width = 4208,
      .height = 3120,
    },
    .left_dummy = 8,
    .right_dummy = 8,
    .top_dummy = 8,
    .bottom_dummy = 8,
  },
  .color_level_info =
  {
    .white_level = 1023,
    .r_pedestal = IMX258_DATA_PEDESTAL,
    .gr_pedestal = IMX258_DATA_PEDESTAL,
    .gb_pedestal = IMX258_DATA_PEDESTAL,
    .b_pedestal = IMX258_DATA_PEDESTAL,
  },
  .start_settings =
  {
    .reg_setting_a = START_REG_ARRAY,
    .addr_type = CAMERA_I2C_WORD_ADDR,
    .data_type = CAMERA_I2C_BYTE_DATA,
    .delay = 0,
  },
  .stop_settings =
  {
    .reg_setting_a = STOP_REG_ARRAY,
    .addr_type = CAMERA_I2C_WORD_ADDR,
    .data_type = CAMERA_I2C_BYTE_DATA,
    .delay = 0,
  },
  .groupon_settings =
  {
    .reg_setting_a = GROUPON_REG_ARRAY,
    .addr_type = CAMERA_I2C_WORD_ADDR,
    .data_type = CAMERA_I2C_BYTE_DATA,
    .delay = 0,
  },
  .groupoff_settings =
  {
    .reg_setting_a = GROUPOFF_REG_ARRAY,
    .addr_type = CAMERA_I2C_WORD_ADDR,
    .data_type = CAMERA_I2C_BYTE_DATA,
    .delay = 0,
  },
  .dualcam_master_settings =
  {
    .reg_setting_a = DUALCAM_MASTER_REG_ARRAY,
    .addr_type = CAMERA_I2C_WORD_ADDR,
    .data_type = CAMERA_I2C_BYTE_DATA,
    .delay = 0,
    .size = 8,
  },
  .embedded_data_enable_settings =
  {
    .reg_setting_a = {},
    .addr_type = 0,
    .data_type = 0,
    .delay = 0,
  },
  .embedded_data_disable_settings =
  {
    .reg_setting_a = {},
    .addr_type = 0,
    .data_type = 0,
    .delay = 0,
  },
  .test_pattern_info =
  {
    .test_pattern_settings =
    {
      {
        .mode = SENSOR_TEST_PATTERN_OFF,
        .settings =
        {
          .reg_setting_a =
          {
            {0x0600, 0x0000, 0x00},
          },
          .addr_type = CAMERA_I2C_WORD_ADDR,
          .data_type = CAMERA_I2C_WORD_DATA,
          .delay = 0,
        }
      },
      {
        .mode = SENSOR_TEST_PATTERN_SOLID_COLOR,
        .settings =
        {
          .reg_setting_a =
          {
            {0x0600, 0x0001, 0x00},
          },
          .addr_type = CAMERA_I2C_WORD_ADDR,
          .data_type = CAMERA_I2C_WORD_DATA,
          .delay = 0,
        },
      },
      {
        .mode = SENSOR_TEST_PATTERN_COLOR_BARS,
        .settings =
        {
          .reg_setting_a =
          {
            {0x0600, 0x0002, 0x00},
          },
          .addr_type = CAMERA_I2C_WORD_ADDR,
          .data_type = CAMERA_I2C_WORD_DATA,
          .delay = 0,
        },
      },
      {
        .mode = SENSOR_TEST_PATTERN_COLOR_BARS_FADE_TO_GRAY,
        .settings =
        {
          .reg_setting_a =
          {
            {0x0600, 0x0003, 0x00},
          },
          .addr_type = CAMERA_I2C_WORD_ADDR,
          .data_type = CAMERA_I2C_WORD_DATA,
          .delay = 0,
        },
      },
      {
        .mode = SENSOR_TEST_PATTERN_PN9,
        .settings =
        {
          .reg_setting_a =
          {
            {0x0600, 0x0004, 0x00},
          },
          .addr_type = CAMERA_I2C_WORD_ADDR,
          .data_type = CAMERA_I2C_WORD_DATA,
          .delay = 0,
        },
      },
    },
    .size = 5,
    .solid_mode_addr =
    {
      .r_addr = 0x0602,
      .gr_addr = 0x0604,
      .gb_addr = 0x0608,
      .b_addr = 0x0606,
    },
  },
  .init_settings_array =
  {
    .reg_settings =
    {
      {
        .reg_setting_a = INIT0_REG_ARRAY,
        .addr_type = CAMERA_I2C_WORD_ADDR,
        .data_type = CAMERA_I2C_BYTE_DATA,
        .delay = 0,
      },
      {
        .reg_setting_a = FLIP_MIRROR_SETTING,
        .addr_type = CAMERA_I2C_WORD_ADDR,
        .data_type = CAMERA_I2C_BYTE_DATA,
        .delay = 0,
      },
    },
    .size = 2,
  },
  .res_settings_array =
  {
    .reg_settings =
    {
      /* Res 0 */
      {
        .reg_setting_a = RES0_REG_ARRAY,
        .addr_type = CAMERA_I2C_WORD_ADDR,
        .data_type = CAMERA_I2C_BYTE_DATA,
        .delay = 0,
      },
      /* Res 1 */
      {
        .reg_setting_a = RES1_REG_ARRAY,
        .addr_type = CAMERA_I2C_WORD_ADDR,
        .data_type = CAMERA_I2C_BYTE_DATA,
        .delay = 0,
      },
      /* Res 2 */
      {
        .reg_setting_a = RES2_REG_ARRAY,
        .addr_type = CAMERA_I2C_WORD_ADDR,
        .data_type = CAMERA_I2C_BYTE_DATA,
        .delay = 0,
      },
      /* Res 3 */
      {
        .reg_setting_a = RES3_REG_ARRAY,
        .addr_type = CAMERA_I2C_WORD_ADDR,
        .data_type = CAMERA_I2C_BYTE_DATA,
        .delay = 0,
      },
      /* Res 4 */
      {
        .reg_setting_a = RES4_REG_ARRAY,
        .addr_type = CAMERA_I2C_WORD_ADDR,
        .data_type = CAMERA_I2C_BYTE_DATA,
        .delay = 0,
      },
      /* Res 5 */
      {
        .reg_setting_a = RES5_REG_ARRAY,
        .addr_type = CAMERA_I2C_WORD_ADDR,
        .data_type = CAMERA_I2C_BYTE_DATA,
        .delay = 0,
      },
      },
    .size = 6,
  },
  .out_info_array =
  {
    .out_info =
    { /* Res 0 */
      {
        .x_output = 4208,
        .y_output = 3120,
        .line_length_pclk = 5352,
        .frame_length_lines = 3224,
        .op_pixel_clk = 480000000,
        .binning_factor = 1,
        .min_fps = 7.500,
        .max_fps = 30.04,
        .mode = SENSOR_DEFAULT_MODE,
        .offset_x = 0,
        .offset_y = 0,
        .scale_factor = 1.000,
        .is_pdaf_supported = 1,
        .data_rate = 1296000000ULL * 4
      },
      /* Res 1 */
      {
        .x_output = 4208,
        .y_output = 2352,
        .line_length_pclk = 5352,
        .frame_length_lines = 2852,
        .op_pixel_clk = 458400000,
        .binning_factor = 1,
        .min_fps = 7.500,
        .max_fps = 30.03,
        .mode = SENSOR_DEFAULT_MODE,
        .offset_x = 0,
        .offset_y = 384,
        .scale_factor = 1.000,
        .is_pdaf_supported = 1,
        .data_rate = 1296000000ULL * 4
      },
      /* Res 2 */
      {
        .x_output = 2100,
        .y_output = 1560,
        .line_length_pclk = 5352,
        .frame_length_lines = 2851,
        .op_pixel_clk = 458400000,
        .binning_factor = 2,
        .min_fps = 7.500,
        .max_fps = 30.04,
        .mode = SENSOR_DEFAULT_MODE,
        .offset_x = 0,
        .offset_y = 0,
        .scale_factor = 1.000,
        .is_pdaf_supported = 0,
        .data_rate = 1296000000ULL * 4
      },
      /* Res 3*/
      {
        .x_output = 2100,
        .y_output = 1176,
        .line_length_pclk = 5352,
        .frame_length_lines = 1424,
        .op_pixel_clk = 458400000,
        .binning_factor = 2,
        .min_fps = 7.500,
        .max_fps = 60.14,
        .mode = SENSOR_HFR_MODE | SENSOR_DEFAULT_MODE,
        .offset_x = 0,
        .offset_y = 384,
        .scale_factor = 1.000,
        .is_pdaf_supported = 0,
        .data_rate = 1296000000ULL * 4
      },
      /* Res 4 */
      {
        .x_output = 1400,
        .y_output = 784,
        .line_length_pclk = 5352,
        .frame_length_lines = 948,
        .op_pixel_clk = 458400000,
        .binning_factor = 2,
        .min_fps = 7.500,
        .max_fps = 90.18,
        .mode = SENSOR_HFR_MODE,
        .offset_x = 0,
        .offset_y = 384,
        .scale_factor = 1.000,
        .is_pdaf_supported = 0,
        .data_rate = 1296000000ULL * 4
      },
      /* Res 5 */
      {
        .x_output = 1400,
        .y_output = 760,
        .line_length_pclk = 5352,
        .frame_length_lines = 828,
        .op_pixel_clk = 480000000,
        .binning_factor = 2,
        .min_fps = 7.500,
        .max_fps = 120.47,
        .mode = SENSOR_HFR_MODE,
        .offset_x = 0,
        .offset_y = 384,
        .scale_factor = 1.000,
        .is_pdaf_supported = 0,
        .data_rate = 1296000000ULL * 4
      },
    },
    .size = 6,
  },
  .csi_params =
  {
    .lane_cnt = 4,
    .settle_cnt = 0xB,
    .is_csi_3phase = 0,
  },
  .exposure_func_table =
  {
    .sensor_calculate_exposure = sensor_calculate_exposure,
    .sensor_fill_exposure_array = sensor_fill_exposure_array,
  },
  .meta_data_out_info_array =
  {
    .meta_data_out_info =
    {
      {
        /* set the meta half size which it should be to overcome the isp bug */
        .width = 80,
        .height = 1920,
        .stats_type = PD_STATS,
        .dt = IMX258_CSI_PD_ISTATS,
      },
    },
    .size = 1,
  },
  .sensor_capability = 0,
  .awb_func_table =
  {
    .sensor_fill_awb_array = 0,
    .awb_table_size = 0,
  },
  .parse_RDI_stats =
  {
    .parse_VHDR_stats = NULL,
  },
  .rolloff_config =
  {
    .enable = FALSE,
    .full_size_info =
    {
      .full_size_width = 0,
      .full_size_height = 0,
      .full_size_left_crop = 0,
      .full_size_top_crop = 0,
    },
  },
  .adc_readout_time = 0,
  .sensor_num_fast_aec_frame_skip = 0,
  .noise_coeff = {
    .gradient_S = 3.738032e-06,
    .offset_S = 3.651935e-04,
    .gradient_O = 6.396835e-11,
    .offset_O = -2.968624e-04,
  },
  .pdaf_config = {
#ifndef FLIP_MIRROR
    #include "imx258_pdaf.h"
#else
    #include "imx258_pdaf_flip_mirror.h"
#endif
  },
};

#endif /* __IMX258_LIB_H__ */

二、 Kernel Camera Probe 代码分析

前面我们 mm-camera/mm-camera2/media-controller/modules/sensors/module/sensor_init.c 中,会下发 CFG_SINIT_PROBE 给到kernel 中。


  memset(&cfg, 0, sizeof(cfg));
  cfg.cfgtype = CFG_SINIT_PROBE;
  cfg.cfg.setting = slave_info;
  ioctl(fd, VIDIOC_MSM_SENSOR_INIT_CFG, &cfg);

Kernel 中处理的地方为:

@/kernel/msm-4.14/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c

/* Static function definition */
static int32_t msm_sensor_driver_cmd(struct msm_sensor_init_t *s_init,void *arg)
{
	struct sensor_init_cfg_data *cfg = (struct sensor_init_cfg_data *)arg;
	
	switch (cfg->cfgtype) {
	case CFG_SINIT_PROBE:
		s_init->module_init_status = 0;
		rc = msm_sensor_driver_probe(cfg->cfg.setting, &cfg->probed_info, cfg->entity_name);
		break;
}

前面代码中, cfg.setting 就是 cfg.cfg.setting = slave_info;, 而最终probe 的结果,保存在 cfg->probed_info 中。

2.1 msm_sensor_driver_probe() 代码分析

  1. 获取上层下发的slave_info 信息
  2. 根据camera id 获取该camera 的控制函数
  3. 如果已经probe 过了,则更新 probed_info 信息
  4. 获取 power 上下电信息
  5. 保存 Camera_info 结构体,包括 slave_addr,sensor id, setting
  6. 填充上电信息
  7. 填充下电信息
  8. 更新外设设备信息
  9. 解析eeprom、actuator、flash 等的dts 信息
  10. 开始上电,上电后会进行check_id 操作,如果 sensor id 匹配成功,则返回成功
  11. 将sensor 加加载到V4L2 subdev 中,创建 节点 /dev/videoX
  12. 下电,保存 sensor_info 信息到 s_strl 中
@ /kernel/msm-4.14/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
/* static function definition */
int32_t msm_sensor_driver_probe(void *setting,struct msm_sensor_info_t *probed_info, char *entity_name)
{
	/* Allocate memory for slave info */
	slave_info = kzalloc(sizeof(*slave_info), GFP_KERNEL);
	{
		// 1. 获取上层下发的slave_info 信息。
		copy_from_user(slave_info, (void __user *)setting, sizeof(*slave_info));
		id_info = &(slave_info->sensor_id_info);
		reg_setting = kzalloc(id_info->setting.size * (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
		copy_from_user(reg_setting, (void __user *) slave_info->sensor_id_info.setting.reg_setting,
				slave_info->sensor_id_info.setting.size * sizeof(struct msm_camera_i2c_reg_array));
		slave_info->sensor_id_info.setting.reg_setting = reg_setting;
	}
	/* Print slave info */
	CDBG("camera id %d Slave addr 0x%X addr_type %d\n",
		slave_info->camera_id, slave_info->slave_addr,
		slave_info->addr_type);
	CDBG("sensor_id_reg_addr 0x%X sensor_id 0x%X sensor id mask %d",
		slave_info->sensor_id_info.sensor_id_reg_addr,
		slave_info->sensor_id_info.sensor_id,
		slave_info->sensor_id_info.sensor_id_mask);
	CDBG("power up size %d power down size %d\n",
		slave_info->power_setting_array.size,
		slave_info->power_setting_array.size_down);
	CDBG("position %d",
		slave_info->sensor_init_params.position);
	CDBG("mount %d",
		slave_info->sensor_init_params.sensor_mount_angle);
	CDBG("bypass video node creation %d",
		slave_info->bypass_video_node_creation);

	// 2. 根据camera id 获取该camera 的控制函数
	/* Extract s_ctrl from camera id */
	s_ctrl = g_sctrl[slave_info->camera_id];
	CDBG("s_ctrl[%d] %pK", slave_info->camera_id, s_ctrl);
	// 3. 如果已经probe 过了,则更新 probed_info 信息
	if (s_ctrl->is_probe_succeed == 1) {
		/* Different sensor on this camera slot has been connected
		 * and probe already succeeded for that sensor. Ignore this probe */
		if (slave_info->sensor_id_info.sensor_id == s_ctrl->sensordata->cam_slave_info->sensor_id_info.sensor_id 
			&& !(strcmp(slave_info->sensor_name,s_ctrl->sensordata->cam_slave_info->sensor_name))) {
			pr_err("slot%d: sensor name: %s sensor id%d already probed\n",
				slave_info->camera_id,
				slave_info->sensor_name,
				s_ctrl->sensordata->cam_slave_info
				->sensor_id_info.sensor_id);
				
			msm_sensor_fill_sensor_info(s_ctrl,	probed_info, entity_name);
		} 
		rc = 0;
		goto free_slave_info;
	}

	// 4.获取 power 上下电信息
	rc = msm_sensor_get_power_settings(setting, slave_info, &s_ctrl->sensordata->power_info);

	// 5. 保存 Camera_info 结构体,包括 slave_addr,sensor id, setting
	camera_info = kzalloc(sizeof(struct msm_camera_slave_info), GFP_KERNEL);
	s_ctrl->sensordata->slave_info = camera_info;

	/* Fill sensor slave info */
	camera_info->sensor_slave_addr = slave_info->slave_addr;
	camera_info->sensor_id_reg_addr = slave_info->sensor_id_info.sensor_id_reg_addr;
	camera_info->sensor_id = slave_info->sensor_id_info.sensor_id;
	camera_info->sensor_id_mask = slave_info->sensor_id_info.sensor_id_mask;
	camera_info->setting = &(slave_info->sensor_id_info.setting);

	/* Fill sensor address type */
	s_ctrl->sensor_i2c_client->addr_type = slave_info->addr_type;
	if (s_ctrl->sensor_i2c_client->client)
		s_ctrl->sensor_i2c_client->client->addr = camera_info->sensor_slave_addr;

	cci_client = s_ctrl->sensor_i2c_client->cci_client;

	cci_client->cci_i2c_master = s_ctrl->cci_i2c_master;
	cci_client->sid = slave_info->slave_addr >> 1;
	cci_client->retries = 3;
	cci_client->id_map = 0;
	cci_client->i2c_freq_mode = slave_info->i2c_freq_mode;

	// 6. 填充上电信息
	/* Parse and fill vreg params for powerup settings */
	rc = msm_camera_fill_vreg_params(
		s_ctrl->sensordata->power_info.cam_vreg,
		s_ctrl->sensordata->power_info.num_vreg,
		s_ctrl->sensordata->power_info.power_setting,
		s_ctrl->sensordata->power_info.power_setting_size);
	// 7. 填充下电信息
	/* Parse and fill vreg params for powerdown settings*/
	rc = msm_camera_fill_vreg_params(
		s_ctrl->sensordata->power_info.cam_vreg,
		s_ctrl->sensordata->power_info.num_vreg,
		s_ctrl->sensordata->power_info.power_down_setting,
		s_ctrl->sensordata->power_info.power_down_setting_size);

CSID_TG:
	/* Update sensor, actuator and eeprom name in
	 * sensor control structure
	 */
	 // 8. 更新外设设备信息
	s_ctrl->sensordata->sensor_name = slave_info->sensor_name;
	s_ctrl->sensordata->eeprom_name = slave_info->eeprom_name;
	s_ctrl->sensordata->actuator_name = slave_info->actuator_name;
	s_ctrl->sensordata->ois_name = slave_info->ois_name;
	s_ctrl->sensordata->flash_name = slave_info->flash_name;
	// 9. 解析eeprom、actuator、flash 等的dts 信息
	/* Update eeporm subdevice Id by input eeprom name */
	rc = msm_sensor_fill_eeprom_subdevid_by_name(s_ctrl);
	/* Update actuator subdevice Id by input actuator name */
	rc = msm_sensor_fill_actuator_subdevid_by_name(s_ctrl);
	rc = msm_sensor_fill_laser_led_subdevid_by_name(s_ctrl);
	rc = msm_sensor_fill_ois_subdevid_by_name(s_ctrl);
	rc = msm_sensor_fill_flash_subdevid_by_name(s_ctrl);

	// 10. 开始上电,上电后会进行check_id 操作,如果 sensor id 匹配成功,则返回成功,
	/* Power up and probe sensor */
	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
	========================>
	+	@ /kernel/msm-4.14/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
	+	static struct msm_sensor_fn_t msm_sensor_func_tbl = {
	+		.sensor_config = msm_sensor_config,
	+		.sensor_power_up = msm_sensor_power_up,
	+		.sensor_power_down = msm_sensor_power_down,
	+		.sensor_match_id = msm_sensor_match_id,
	+	};
	+	
	+	rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type, sensor_i2c_client);
	+	rc = msm_sensor_check_id(s_ctrl);
	<========================
	pr_err("%s probe succeeded", slave_info->sensor_name);

	s_ctrl->bypass_video_node_creation = slave_info->bypass_video_node_creation;

	/*
	 * Create /dev/videoX node, comment for now until dummy /dev/videoX
	 * node is created and used by HAL
	 */
	// 11. 将sensor 加加载到V4L2 subdev 中,创建 节点 /dev/videoX
	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE)
		rc = msm_sensor_driver_create_v4l_subdev(s_ctrl);
	else
		rc = msm_sensor_driver_create_i2c_v4l_subdev(s_ctrl);

	// 12. 下电,保存 sensor_info 信息到 s_strl 中。
	/* Power down */
	s_ctrl->func_tbl->sensor_power_down(s_ctrl);

	rc = msm_sensor_fill_slave_info_init_params(slave_info, s_ctrl->sensordata->sensor_info);
	rc = msm_sensor_validate_slave_info(s_ctrl->sensordata->sensor_info);
	
	/*Save sensor info*/
	s_ctrl->sensordata->cam_slave_info = slave_info;
	msm_sensor_fill_sensor_info(s_ctrl, probed_info, entity_name);
	/*
	 * Set probe succeeded flag to 1 so that no other camera shall
	 * probed on this slot
	 */
	s_ctrl->is_probe_succeed = 1;
	return rc;
}

2.1.1 创建 /dev/videoX、 /dev/v4l-subdevX 节点

  1. 创建 /dev/videoX 节点
  2. 初始化 s_ctrl->msm_sd.sd 节构体信息,将ops 绑定到 sd 中
  3. 更新 subdev 信息,并注册subdev
  4. 将 subdev 添回到 subdev list 链表中
  5. 创建 /dev/v4l-subdevX 节点
@ msm-4.14/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
static int32_t msm_sensor_driver_create_v4l_subdev(struct msm_sensor_ctrl_t *s_ctrl)
{
	// 1. 创建 /dev/videoX 字付设备节点
	if (s_ctrl->bypass_video_node_creation == 0) {
		rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
		=============>
		+	@ msm-4.14/drivers/media/platform/msm/camera_v2/camera/camera.c
		+	strlcpy(pvdev->vdev->name, "msm-sensor", sizeof(pvdev->vdev->name));
		+	pvdev->vdev->fops     = &camera_v4l2_fops;
		+	pvdev->vdev->ioctl_ops = &camera_v4l2_ioctl_ops;
		+	video_register_device(pvdev->vdev,VFL_TYPE_GRABBER, -1);
		+	----------------->
		+		@ msm-4.14/include/media/v4l2-dev.h
		+		__video_register_device(vdev, type, nr, 1, vdev->fops->owner);
		+		------------>
		+			name_base = "video";
		+			/* Pick a device node number */
		+			minor_offset = 0;
		+			minor_cnt = 64;
		+			nr = devnode_find(vdev, 0, minor_cnt);
		+			video_device[vdev->minor] = vdev;
		+			/* Part 3: Initialize the character device */
		+			vdev->cdev->ops = &v4l2_fops;
		+			vdev->cdev->owner = owner;
		+			ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
		+			/* Part 4: register the device with sysfs */
		+			vdev->dev.class = &video_class;
		+			vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
		+			vdev->dev.parent = vdev->dev_parent;
		+			dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
		+			ret = device_register(&vdev->dev);
		+		<------------
		+	<-----------------
		<=============
	}

	CDBG("rc %d session_id %d", rc, session_id);
	s_ctrl->sensordata->sensor_info->session_id = session_id;
	
	// 2. 初始化 s_ctrl->msm_sd.sd 节构体信息,将ops 绑定到 sd 中
	/* Create /dev/v4l-subdevX device */
	v4l2_subdev_init(&s_ctrl->msm_sd.sd, s_ctrl->sensor_v4l2_subdev_ops);
	// 3. 更新 subdev 信息,并注册
	// imx258
	snprintf(s_ctrl->msm_sd.sd.name, sizeof(s_ctrl->msm_sd.sd.name), "%s",
		s_ctrl->sensordata->sensor_name);
	v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev);
	s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	media_entity_pads_init(&s_ctrl->msm_sd.sd.entity, 0, NULL);
	s_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_SENSOR;
	s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name;    // imx258
	s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
	rc = msm_sd_register(&s_ctrl->msm_sd);
	=======================>
		@ msm-4.14/drivers/media/platform/msm/camera_v2/msm.c
		__msm_sd_register_subdev(&msm_subdev->sd);
		----------->
			// 3.1 将 subdev 添回到  subdev list 链表中
			rc = v4l2_device_register_subdev(msm_v4l2_dev, sd);
			--------->
				list_add_tail(&sd->list, &v4l2_dev->subdevs);
			<---------
			strlcpy(vdev->name, sd->name, sizeof(vdev->name));	// imx258
			vdev->v4l2_dev = msm_v4l2_dev;
			vdev->fops = msm_cam_get_v4l2_subdev_fops_ptr();
			vdev->release = msm_sd_unregister_subdev;
			// 3.2 创建 /dev/v4l-subdevX 节点
			rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,sd->owner);
			--------->
				@ msm-4.14/drivers/media/v4l2-core/v4l2-dev.c
				name_base = "v4l-subdev";
				minor_offset = 128;
				minor_cnt = 64;
				/* Pick a device node number */
				nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
				video_device[vdev->minor] = vdev;
				/* Part 3: Initialize the character device */
				vdev->cdev->ops = &v4l2_fops;
				vdev->cdev->owner = owner;
				ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
				/* Part 4: register the device with sysfs */
				vdev->dev.class = &video_class;
				vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
				vdev->dev.parent = vdev->dev_parent;
				dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); // v4l-subdevX
				ret = device_register(&vdev->dev);
			<---------
		<-----------
	<=======================

	msm_cam_copy_v4l2_subdev_fops(&msm_sensor_v4l2_subdev_fops);
#ifdef CONFIG_COMPAT
	msm_sensor_v4l2_subdev_fops.compat_ioctl32 = msm_sensor_subdev_fops_ioctl;
#endif
	s_ctrl->msm_sd.sd.devnode->fops = &msm_sensor_v4l2_subdev_fops;

	return rc;
}

至此,整个probe 过程就 完毕了。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

"小夜猫&小懒虫&小财迷"的男人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值