Design and analysis of camera sensor driver code on zhanrui platform

Posted by cluce on Wed, 10 Nov 2021 07:01:18 +0100

Basic configuration and file path description of Camera driver

  1. The driver configuration path is: \ device\sprd\platform\board\camera\sensor_config.xml
  2. The path of the driver code is: \ vendor \ SPRD \ modules \ libcamera \ sensor \ sensor_ Under DRV \ classic, there are drivers from various sensor manufacturers, such as Galaxy core, Superpix, Samsung, etc.

Configuration analysis of driver. c file

When opening the camera call library, the following functions will be called

void *sensor_ic_open_lib(void)
{
	return &g_ov8856_mipi_raw_info;
}

For the function interface in. c, all functions in it are the function interface corresponding to the function pointer of the following structure

/*==============================================================================
 * Description:
 * all ioctl functoins
 * you can add functions reference SENSOR_IOCTL_FUNC_TAB_T from sensor_drv_u.h
 *
 * add ioctl functions like this:
 * .power = ov8856_power_on,
 *============================================================================*/
static struct sensor_ic_ops s_ov8856_ops_tab = {
    .create_handle = ov8856_drv_handle_create,
    .delete_handle = ov8856_drv_handle_delete,
    /*get privage data*/
    .get_data = ov8856_drv_get_private_data,
    /*common interface*/
	.power = ov8856_drv_power_on,
	.identify = ov8856_drv_identify,
	.ex_write_exp = ov8856_drv_write_exposure,
	.write_gain_value = ov8856_drv_write_gain_value,
	
#if defined(CONFIG_DUAL_MODULE)
	.read_aec_info = ov8856_drv_read_aec_info,
#endif

    .ext_ops = {
        [SENSOR_IOCTL_BEFORE_SNAPSHOT].ops = ov8856_drv_before_snapshot,
        [SENSOR_IOCTL_STREAM_ON].ops = ov8856_drv_stream_on,
        [SENSOR_IOCTL_STREAM_OFF].ops = ov8856_drv_stream_off,
        /* expand interface,if you want to add your sub cmd ,
         *  you can add it in enum {@SENSOR_IOCTL_VAL_TYPE}
         */
        [SENSOR_IOCTL_ACCESS_VAL].ops = ov8856_drv_access_val,
		[SENSOR_IOCTL_CONTRAST].ops = ov8856_drv_set_saturation,
    }
};

ov8856_drv_handle_create

static cmr_int ov8856_drv_handle_create(struct sensor_ic_drv_init_para *init_param, cmr_handle* sns_ic_drv_handle) 
{
    cmr_int ret = SENSOR_SUCCESS;
    struct sensor_ic_drv_cxt * sns_drv_cxt = NULL;
    void *pri_data = NULL;

    ret = sensor_ic_drv_create(init_param,sns_ic_drv_handle);
    sns_drv_cxt = *sns_ic_drv_handle;

    sns_drv_cxt->sensor_ev_info.preview_shutter = PREVIEW_FRAME_LENGTH - FRAME_OFFSET;
    sns_drv_cxt->sensor_ev_info.preview_gain = SENSOR_BASE_GAIN;
    sns_drv_cxt->sensor_ev_info.preview_framelength = PREVIEW_FRAME_LENGTH;

    sns_drv_cxt->frame_length_def = PREVIEW_FRAME_LENGTH;
	
	ov8856_drv_write_frame_length(sns_drv_cxt, &ov8856_aec_info, sns_drv_cxt->sensor_ev_info.preview_framelength);
	ov8856_drv_write_gain(sns_drv_cxt, &ov8856_aec_info, sns_drv_cxt->sensor_ev_info.preview_gain);
	ov8856_drv_write_shutter(sns_drv_cxt, &ov8856_aec_info, sns_drv_cxt->sensor_ev_info.preview_shutter);

    sensor_ic_set_match_module_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_module_info_tab), s_ov8856_module_info_tab);
    sensor_ic_set_match_resolution_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_resolution_tab_raw), s_ov8856_resolution_tab_raw);
    sensor_ic_set_match_trim_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_resolution_trim_tab), s_ov8856_resolution_trim_tab);
    sensor_ic_set_match_static_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_static_info), s_ov8856_static_info);
    sensor_ic_set_match_fps_info(sns_drv_cxt, ARRAY_SIZE(s_ov8856_mode_fps_info), s_ov8856_mode_fps_info);

    /*init exif info,this will be deleted in the future*/
    ov8856_drv_init_fps_info(sns_drv_cxt);
	ov8856_drv_init_exif_info(sns_drv_cxt, &sns_drv_cxt->exif_ptr);
	
    /*add private here*/
    return ret;
}

drv_ handle_ The create function will be called at the beginning. For example, it will be called when you start up to identify, initialize and configure the whole driver, and allocate the memory space required by a driver, including various structures.

ov8856_drv_handle_delete

static cmr_int ov8856_drv_handle_delete(cmr_handle handle, void *param) 
{
    cmr_int ret = SENSOR_SUCCESS;

    SENSOR_IC_CHECK_HANDLE(handle);
    struct sensor_ic_drv_cxt * sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;

    ret = sensor_ic_drv_delete(handle,param);
    return ret;
}

drv_ handle_ The delete function is mainly used to delete the previous DRV when exiting camera_ handle_ Create to destroy and release the allocated memory.

Power on and power off sequence

/*==============================================================================
 * Description:
 * sensor power on
 * please modify this function acording your spec
 *============================================================================*/
static cmr_int ov8856_drv_power_on(cmr_handle handle, cmr_uint power_on)
{
    SENSOR_IC_CHECK_HANDLE(handle);
    struct sensor_ic_drv_cxt * sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;
    struct module_cfg_info *module_info = sns_drv_cxt->module_info;

    SENSOR_AVDD_VAL_E dvdd_val = module_info->dvdd_val;
    SENSOR_AVDD_VAL_E avdd_val = module_info->avdd_val;
    SENSOR_AVDD_VAL_E iovdd_val = module_info->iovdd_val;
    BOOLEAN power_down = g_ov8856_mipi_raw_info.power_down_level;
    BOOLEAN reset_level = g_ov8856_mipi_raw_info.reset_pulse_level;	
	
    if (SENSOR_TRUE == power_on) 
	{
        hw_sensor_power_down(sns_drv_cxt->hw_handle, power_down);
        hw_sensor_set_reset_level(sns_drv_cxt->hw_handle, reset_level);
        hw_sensor_set_mclk(sns_drv_cxt->hw_handle, SENSOR_DISABLE_MCLK);
        hw_sensor_set_avdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        hw_sensor_set_dvdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        hw_sensor_set_iovdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
		
        usleep(10 * 1000);
		hw_sensor_set_iovdd_val(sns_drv_cxt->hw_handle, iovdd_val);
        hw_sensor_set_avdd_val(sns_drv_cxt->hw_handle, avdd_val);
        hw_sensor_set_dvdd_val(sns_drv_cxt->hw_handle, dvdd_val);

        usleep(10 * 1000);
		hw_sensor_set_mclk(sns_drv_cxt->hw_handle, EX_MCLK);
        hw_sensor_power_down(sns_drv_cxt->hw_handle, !power_down);
        hw_sensor_set_reset_level(sns_drv_cxt->hw_handle, !reset_level);
        usleep(5 * 1000);
        
    } else 
	{
        //usleep(500);
        //hw_sensor_set_reset_level(sns_drv_cxt->hw_handle, reset_level);
        //hw_sensor_power_down(sns_drv_cxt->hw_handle, power_down);
        //hw_sensor_set_mclk(sns_drv_cxt->hw_handle, SENSOR_DISABLE_MCLK);
		//usleep(200);
        //hw_sensor_set_avdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        //hw_sensor_set_dvdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        //hw_sensor_set_iovdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
    }
	
    SENSOR_LOGI("mydebug(1:on, 0:off): %lu", power_on);
    return SENSOR_SUCCESS;
}

drv_power_on is the Power on and power off timing, which should be measured with an oscilloscope to correspond to the Power on and power off timing of the datasheet. The Power on function first controls the three-way power supply and obtains the initial values of power down and reset. The other two if statements are powered on when true and powered off when false. The operation of Power on and power off must be carried out in strict accordance with the sequence diagram in the sensor spec.

identify

/*==============================================================================
 * Description:
 * identify sensor id
 * please modify this function acording your spec
 *============================================================================*/
static cmr_int ov8856_drv_identify(cmr_handle handle, cmr_uint param)
{
	cmr_u16 pid_value = 0x00;
	cmr_u16 ver_value = 0x00;
	cmr_int ret_value = SENSOR_FAIL;
	
    SENSOR_IC_CHECK_HANDLE(handle);
    struct sensor_ic_drv_cxt * sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;
  
	SENSOR_LOGI("mipi raw identify");

	pid_value = hw_sensor_read_reg(sns_drv_cxt->hw_handle, ov8856_PID_ADDR);

	if (ov8856_PID_VALUE == pid_value) {
		ver_value = hw_sensor_read_reg(sns_drv_cxt->hw_handle, ov8856_VER_ADDR);
		SENSOR_LOGI("Identify: pid_value = %x, ver_value = %x", pid_value, ver_value);
		if (ov8856_VER_VALUE == ver_value) {
			SENSOR_LOGI("this is ov8856 sensor");
			ret_value = SENSOR_SUCCESS;
		} else {
			SENSOR_LOGE("sensor identify fail, pid_value = %x, ver_value = %x", pid_value, ver_value);
		}
	} else {
		SENSOR_LOGE("sensor identify fail, pid_value = %x, ver_value = %x", pid_value, ver_value);
	}

	return ret_value;
}

drv_ The identify function mainly checks the PID and vid of the sensor. Indirectly, it can also check the power on of the sensor and the clock supplied by mclk. This function will be called every time the camera is started and opened. log often knows the situation of the sensor through this function.

/*==============================================================================
 * Description:
 * cfg otp setting
 * please modify this function acording your spec
 *============================================================================*/
static cmr_int ov8856_drv_access_val(cmr_handle handle, cmr_uint param)
{
	cmr_int ret = SENSOR_FAIL;
    SENSOR_VAL_T *param_ptr = (SENSOR_VAL_T *)param;
    
	SENSOR_IC_CHECK_HANDLE(handle);
	SENSOR_IC_CHECK_PTR(param_ptr);
    struct sensor_ic_drv_cxt * sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;

	SENSOR_LOGI("sensor ov8856: param_ptr->type=%x", param_ptr->type);
	
	switch(param_ptr->type)
	{
		case SENSOR_VAL_TYPE_GET_STATIC_INFO:
			ret = ov8856_drv_get_static_info(handle, param_ptr->pval);
			break;
		case SENSOR_VAL_TYPE_GET_FPS_INFO:
			ret = ov8856_drv_get_fps_info(handle, param_ptr->pval);
			break;
		case SENSOR_VAL_TYPE_SET_SENSOR_CLOSE_FLAG:
			ret = sns_drv_cxt->is_sensor_close = 1;
			break;
		case SENSOR_VAL_TYPE_GET_PDAF_INFO:
			//ret = ov8856_drv_get_pdaf_info(handle, param_ptr->pval);
			break;
	#ifdef FEATURE_OTP
		case SENSOR_VAL_TYPE_READ_OTP;
			ret = ov8856_identify_otp(handle,param_ptr);
			break;
	#endif
	    case SENSOR_VAL_TYPE_READ_OTP:
	        //property_get("persist.vendor.bypass.sensor.otp", value, "0");
	        //if (atoi(value) == 0) {
	            //if (ov8856_otp_module_vendor_id == 0 && sns_drv_cxt->sensor_id == 1)
	                ov8856_read_otp(handle, param_ptr);
	        //}
	        break;
		default:
			break;
    }

    return ret;
}

Each driver has a drv_access_val function, which is mainly used by the oem layer to call some feature related functions in the driver, including some interfaces that need to be added privately. It can be implemented in this function and called by the oem to the upper layer, such as the otp driver of sensor. You can add case sentence sensor in the following functions_ VAL_ TYPE_ READ_ otp to realize the calibration of the sensor's own otp. Other interfaces can also be added for reference.

summary

The explanation of the camera driver is basically completed. When developing or bringing up the camera driver, you need to carefully check the driver and complete each configuration and function. All these need to be completed jointly by the original sensor factory and the drive engineer. Any incorrect configuration may lead to many problems, such as incorrect bps may lead to error in receiving data, incorrect linetime may lead to water ripple, etc. For the power on timing, it is best to pass the strict oscilloscope inspection, and the proportion of VB in one frame should not exceed 3%. The timing of mipi also needs to be confirmed by waveform test.

Topics: Android