M1710U Camera OV8858移植详解

原文网址(转载请注明出处):

链接:http://t.csdnimg.cn/91Sq5

源码基于:Android Q


展锐平台sl8541移植OV8858进行详细讲解。

1.硬件

1.1.OV8858 结构图(连接器)

在这里插入图片描述

1.2.开发板MIPI原理图

在这里插入图片描述
在这里插入图片描述

1.3.Camera引脚编号介绍

在这里插入图片描述
引脚编号 引脚名称 其他
83 CAM_I2C_SCL SCL1
84 CAM_I2C_SDA SDA1
基于MIPI CSI标准,M1710U模块摄像头接口默认支持1路2-lane CSI1+ 1 路 1-lane CSI0,最高速率达 1.5Gbps/lane。可支持 2 路摄像头:前摄使用 1-lane MIPI,可最大支持 2 MP 拍照;后摄使用 2-lane MIPI,可最大支持 8 MP 拍照。摄像和照相质量由摄像头传感器、镜头规格参数等多种因素决定。

如上所述,模块的 CSI0 默认为 1-lane,但能最大扩展为 4-lane,另外3 组数据 lane 信息在模块硬件设计手册中未作体现,客户可以通过下文了解关于模块 4-lane CSI0 的详细信息,以满足最大 13 MP 像素摄像头的应用需求。

开发板现在支持情况:

  • 前摄:5M(500万像素)
  • 后摄:8M(800万像素)

1.4.OV8858 datesheet

在这里插入图片描述
在这里插入图片描述

1.5.camera主要硬件介绍

主要由如下五部分组成,协同工作:
(1)三路电压AVDD/DVDD/IOVDD:

AVDD模拟电源,主要给感光区和ADC供电,要求比较干净;
DVDD数字电源,主要是给ISP供电;
IOVDD数字I0电源,给I2C和DVP供电。
(2) PDN/RST:

RST:用来reset sensor; RESET- 般是低电平有效,当脉冲为低电平时,reset sensor, 而正常工作时,应该设置为高电平。
复位时序时序通常是:高->低->高,根据硬件需要加一定的延时;
电源实测数据如下:

开发板电压状态:

打开摄像头: MCAM_VAAM_2V8 129 2.8V MCAM_IOVDD 125 1.8V
关闭摄像头 MCAM_VAAM_2V8 129 0V MCAM_IOVDD 125 1.8V

1.6.上电时序

在这里插入图片描述
在这里插入图片描述
重要:
这里需要注意的是,XSHUTDN就是reset引脚,低电平复位,正常工作的时候,应该是高电平

PWDNB是和复位脚差不多功能的,给寄存器复位,所以这两个,比较关键,我这里是使用了DOVDD和XSHUTDN连接的情况,所以驱动中power_on处理的时候,拉高reset以后,不延时,直接拉高pwdn,然后延时,才能让模块上电

dvdd avdd iovdd上电时序其实要求并不严格,之前我一直读取不到模块id,就是因为我们分开供电XSHUYDN和PWDNB,而驱动中是先拉低reset然后拉高延时2Ms再拉高pwdn,所以导致系统一直没有工作起来,去读i2c的时候返回-5

这里rk也有案例

实际上很简单,驱动中probe以后,就开始检测获dts配置,然后就power_on执行上电流程,上电以后,第一步就是check_id,也就是读取摄像头id,如果i2c通信异常,那么久无法进行下面的工作,直接return

经过一番折腾,i2c正常读取id,解决了前面最关键的一步

切记:如果i2c读取不到,确保硬件电压,时钟正常,然后基本上就是时序了

如果硬件都没问题,但是读取的时候没有一直错,可能先考虑给一个for循环,循环发送0x00-0xff,看看有没有回应,避免因为地址错误这种低级错误

2.Camera软件移植

2.1.dts移植

vddcamio: LDO_VDDCAMIO {
				regulator-name = "vddcamio";
				regulator-min-microvolt = <1400000>;//调节器最小微伏
				regulator-max-microvolt = <2187500>;//调节器最大微伏
				regulator-ramp-delay = <25000>;
			};

vddcama: LDO_VDDCAMA {
				regulator-name = "vddcama";
				regulator-min-microvolt = <1612500>;//调节器最小微伏
				regulator-max-microvolt = <3200000>;//调节器最大微伏
				regulator-ramp-delay = <25000>;
			};
&i2c1 {//使用的i2c总线
	status = "okay";//okay 才会进行匹配
	clock-frequency = <100000>;//数据传输频率

	sensor_main: sensor-main@40 {//主摄
		compatible = "sprd,sensor-main";
		reg = <0x40>;//主摄寄存器地址
		clock-names = "clk_src","sensor_eb",
				"clk_96m","clk_76m8",
				"clk_48m","clk_26m";//代表所使用的mclk
		clocks = <&mm_clk CLK_SENSOR0>, <&mm_gate CLK_SENSOR0_EB>,
			<&pll CLK_TWPLL_96M>,<&pll CLK_TWPLL_76M8>,
			<&pll CLK_TWPLL_48M>,<&ext_26m>;
		vddio-supply = <&vddcamio>;//所使用的avdd,dvdd,iovdd
		//vddcama-supply = <&vddcama>;
		//vddcamd-supply = <&vddcamd>;
		vddcammot-supply = <&vddcama>;//所使用的avdd,dvdd,iovdd
		sprd,phyid = <2>;//phyid是硬件上mipi上连接的方式有关系,1lane,2lane,4lane,4lane phyid设为0
		csi = <&csi0>;//选择的CSI总线
		reset-gpios = <&ap_gpio 44 0>;//复位引脚
		//power-down-gpios = <&ap_gpio 46 0>;
		dvdd-gpios = <&ap_gpio 32 0>;//dvdd电源控制引脚
		avdd-gpios = <&ap_gpio 8 0>;//avdd电源控制引脚
	};

DTS冒号前都是别名,引用用&符号。如上:vddcama是别名,应用则是&vddcamio。

2.2.源码定位

sl8541e_1h10wifi5g_32b_Natv$ find . -name "*ov8858*"
./bsp/kernel/kernel4.14/drivers/staging/media/atomisp/i2c/ov8858_btns.h
./bsp/kernel/kernel4.14/drivers/staging/media/atomisp/i2c/ov8858.c
./bsp/kernel/kernel4.14/drivers/staging/media/atomisp/i2c/ov8858.h
./vendor/sprd/modules/libcamera/sensor/otp_drv/driver/ov8858_cmk
./vendor/sprd/modules/libcamera/sensor/otp_drv/driver/ov8858_cmk/ov8858_cmk_otp_drv.c
./vendor/sprd/modules/libcamera/sensor/otp_drv/driver/ov8858_cmk/ov8858_cmk_golden_otp.h
./vendor/sprd/modules/libcamera/sensor/otp_drv/driver/ov8858_cmk/ov8858_cmk_otp_drv.h
./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858
./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858/sensor_ov8858_mipi_raw.c
./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858/sensor_ov8858_mipi_raw.h
./out/target/product/sl8541e_1h10wifi5g_32b/obj/SHARED_LIBRARIES/libsensor_ov8858_intermediates
./out/target/product/sl8541e_1h10wifi5g_32b/obj/SHARED_LIBRARIES/libsensor_ov8858_intermediates/libsensor_ov8858.so
./out/target/product/sl8541e_1h10wifi5g_32b/obj/SHARED_LIBRARIES/libsensor_ov8858_intermediates/sensor_ov8858_mipi_raw.o
./out/target/product/sl8541e_1h10wifi5g_32b/obj/SHARED_LIBRARIES/libsensor_ov8858_intermediates/LINKED/libsensor_ov8858.so
./out/target/product/sl8541e_1h10wifi5g_32b/obj/SHARED_LIBRARIES/libsensor_ov8858_intermediates/sensor_ov8858_mipi_raw.d
./out/target/product/sl8541e_1h10wifi5g_32b/obj/SHARED_LIBRARIES/libsensor_ov8858_intermediates/libsensor_ov8858.so.d
./out/target/product/sl8541e_1h10wifi5g_32b/obj/PACKAGING/target_files_intermediates/sl8541e_1h10wifi5g_32b_Natv-target_files-20230519.163824/VENDOR/lib/libsensor_ov8858.so
./out/target/product/sl8541e_1h10wifi5g_32b/archive_symbols/symbols.vendor/vendor/lib/libsensor_ov8858.so
./out/target/product/sl8541e_1h10wifi5g_32b/symbols/vendor/lib/libsensor_ov8858.so
./out/target/product/sl8541e_1h10wifi5g_32b/vendor/lib/libsensor_ov8858.so

源码定位在:

./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858
./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858/sensor_ov8858_mipi_raw.c
./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858/sensor_ov8858_mipi_raw.h

$ ls ./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858
Android.mk(编译ov8858脚本)  sensor_ov8858_mipi_raw.c  sensor_ov8858_mipi_raw.h

sensor的操作函数为ops,在sensor_ov8858_mipi_raw.c 中查到ops函数为s_ov8858_ops_tab
//sensor_ov8858_mipi_raw.c

/*==============================================================================
 * Description:
 * 所有ioctl函数
 * 您可以从sensor_drv_u.h中添加引用SENSOR_IOCTL_FUNC_TAB_T的函数
 *
 * 像这样添加ioctl函数:
 * .power = ov8858_power_on,
 *============================================================================*/
static struct sensor_ic_ops s_ov8858_ops_tab = {
    .create_handle =    ,
    .delete_handle = ov8858_drv_handle_delete,
    .get_data = ov8858_drv_get_private_data,
    /*---------------------------------------*/
    .power = ov8858_drv_power_on,//上电
    .identify = ov8858_drv_identify,//识别传感器id
    .ex_write_exp = ov8858_drv_write_exposure,//将曝光写入传感器寄存器并获得当前快门,请注意帧长,如有必要请勿更改此功能
    .write_gain_value = ov8858_drv_write_gain_value,//写入增益值传感器,你可以改变这个功能,如果它是必要的
    .read_aec_info = ov8858_drv_read_aec_info,

    .ext_ops = {
        
            [SENSOR_IOCTL_BEFORE_SNAPSHOT].ops = ov8858_drv_before_snapshot,//在快照之前,您可以根据需要更改此功能
            [SENSOR_IOCTL_STREAM_ON].ops = ov8858_drv_stream_on,//请根据您的规格修改此功能
            [SENSOR_IOCTL_STREAM_OFF].ops = ov8858_drv_stream_off,//请根据您的规格修改此功能
            /** 展开界面,如果你想添加你的子CMD ,
             *  你可以在enum中添加它{@SENSOR_IOCTL_VAL_TYPE}
             */
            [SENSOR_IOCTL_ACCESS_VAL].ops = ov8858_drv_access_val,//CFG otp设置请根据您的规格修改此功能
    }};
sl8541e_1h10wifi5g_32b_Natv$ cgrep -r "s_ov8858_ops_tab" ./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858/sensor_ov8858_mipi_raw.c:905:static struct sensor_ic_ops s_ov8858_ops_tab = { ./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858/sensor_ov8858_mipi_raw.h:1083:static struct sensor_ic_ops s_ov8858_ops_tab; ./vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858/sensor_ov8858_mipi_raw.h:1117: .sns_ops = &s_ov8858_ops_tab,

2.3. ov8858_mipi_raw_info

//vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/OmniVision/ov8858/sensor_ov8858_mipi_raw.h
//模块基本信息
static struct sensor_module_info s_ov8858_module_info_tab[VENDOR_NUM] = {
    {.module_id = MODULE_SUNNY,
     .module_info = {.major_i2c_addr = I2C_SLAVE_ADDR >> 1,
                     .minor_i2c_addr = 0x20 >> 1,

                     .reg_addr_value_bits = SENSOR_I2C_REG_16BIT |
                                            SENSOR_I2C_VAL_8BIT |
                                            SENSOR_I2C_FREQ_400,

                     .avdd_val = SENSOR_AVDD_2800MV,    //模拟电源,主要给感光区和ADC供电
                     .iovdd_val = SENSOR_AVDD_1800MV,   //数字电源,主要是给ISP供电;
                     .dvdd_val = SENSOR_AVDD_1200MV,    //数字I0电源,给I2C和DVP供电。

                     .image_pattern = SENSOR_IMAGE_PATTERN_RAWRGB_B,

                     .preview_skip_num = 1,             //预览前跳过帧数
                     .capture_skip_num = 3,             //在捕获之前跳过帧数
                     .flash_capture_skip_num = 6,       //闪光捕捉跳过帧数
                     .mipi_cap_skip_num = 0,            //mipi cap跳过帧数 
                     .preview_deci_num = 0,             //预览期间的十进制帧数
                     .video_preview_deci_num = 0,       //视频预览期间的十进制帧数

                     .threshold_eb = 0,
                     .threshold_mode = 0,
                     .threshold_start = 0,
                     .threshold_end = 0,

                     .sensor_interface =
                         {
                             .type = SENSOR_INTERFACE_TYPE_CSI2,
                             .bus_width = LANE_NUM,     //连接的lane数   #define LANE_NUM 2
                             .pixel_width = RAW_BITS,   //camera sensor输出格式    #define RAW_BITS 10
                             .is_loose = 0,
                         },
                     .change_setting_skip_num = 1,
                     .horizontal_view_angle = 35,
                     .vertical_view_angle = 35}}

    /*If there are multiple modules,please add here*/
};

static struct sensor_ic_ops s_ov8858_ops_tab;
struct sensor_raw_info *s_ov8858_mipi_raw_info_ptr = PNULL;

SENSOR_INFO_T g_ov8858_mipi_raw_info = {
    .hw_signal_polarity = SENSOR_HW_SIGNAL_PCLK_P | SENSOR_HW_SIGNAL_VSYNC_P |
                          SENSOR_HW_SIGNAL_HSYNC_P,
    .environment_mode = SENSOR_ENVIROMENT_NORMAL | SENSOR_ENVIROMENT_NIGHT,
    .image_effect = SENSOR_IMAGE_EFFECT_NORMAL |
                    SENSOR_IMAGE_EFFECT_BLACKWHITE | SENSOR_IMAGE_EFFECT_RED |
                    SENSOR_IMAGE_EFFECT_GREEN | SENSOR_IMAGE_EFFECT_BLUE |
                    SENSOR_IMAGE_EFFECT_YELLOW | SENSOR_IMAGE_EFFECT_NEGATIVE |
                    SENSOR_IMAGE_EFFECT_CANVAS,

    .wb_mode = 0,
    .step_count = 7,
    .reset_pulse_level = SENSOR_LOW_PULSE_RESET,
    .reset_pulse_width = 50,
    .power_down_level = SENSOR_LOW_LEVEL_PWDN,
    .identify_count = 1,
    .identify_code =
        {
            {.reg_addr = ov8858_PID_ADDR, .reg_value = ov8858_PID_VALUE},
            {.reg_addr = ov8858_VER_ADDR, .reg_value = ov8858_VER_VALUE},
        },

    .source_width_max = SNAPSHOT_WIDTH,
    .source_height_max = SNAPSHOT_HEIGHT,
    .name = (cmr_s8 *)SENSOR_NAME,
    .image_format = SENSOR_IMAGE_FORMAT_RAW,                //原数据格式

    .module_info_tab = s_ov8858_module_info_tab,            //sensor信息表
    .module_info_tab_size = ARRAY_SIZE(s_ov8858_module_info_tab),

    .resolution_tab_info_ptr = s_ov8858_resolution_tab_raw, //摄像头图形分辨率表
    .sns_ops = &s_ov8858_ops_tab,                           //ops函数操作集合
    .raw_info_ptr = &s_ov8858_mipi_raw_info_ptr,

    .video_tab_info_ptr = NULL,
    .sensor_version_info = (cmr_s8 *)"ov8858v1",
};

2.4.重要函数

2.4.1.ov8858_drv_power_on

static cmr_int ov8858_drv_power_on()
{
    define BOOLEAN unsigned int 
    /* 1: high level valid; 0: low level valid */
    cmr_u32 power_down_level;
    
    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 = MIPI_RAW_INFO.power_down_level;
    BOOLEAN reset_level = 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(1 * 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(1 * 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);

        hw_sensor_set_mipi_level(sns_drv_cxt->hw_handle, 0);
        usleep(1 * 1000);
    }
    else
    {
        // hw_sensor_set_mclk(sns_drv_cxt->hw_handle, SENSOR_DISABLE_MCLK);
        usleep(500);
        hw_sensor_set_mipi_level(sns_drv_cxt->hw_handle, 1);
        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_dvdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        hw_sensor_set_avdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        hw_sensor_set_iovdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
    }
}

2.4.2ov8858_drv_identify

/*==============================================================================
 * Description:
 * 识别传感器id
 * 请根据您的规格修改此功能
 *============================================================================*/
static cmr_int ov8858_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");

    //IIC 传感器IC读寄存器接口
    pid_value = hw_sensor_read_reg(sns_drv_cxt->hw_handle, ov8858_PID_ADDR);//#define ov8858_PID_ADDR 0x300B

    if (ov8858_PID_VALUE == pid_value) {                                    //#define ov8858_PID_VALUE 0x88
        ver_value = hw_sensor_read_reg(sns_drv_cxt->hw_handle, ov8858_VER_ADDR);//#define ov8858_VER_ADDR 0x300C
        SENSOR_LOGI("Identify: PID = %x, VER = %x", pid_value, ver_value);
        if (ov8858_VER_VALUE == ver_value) {                                //#define ov8858_VER_VALUE 0x58
            SENSOR_LOGI("this is ov8858 sensor");
            // ov8858_drv_init_fps_info(handle);
            ret_value = SENSOR_SUCCESS;
        } else {
            SENSOR_LOGI("Identify this is %x%x sensor", pid_value, ver_value);
        }
    } else {
        SENSOR_LOGE("sensor identify fail, pid_value = %x", pid_value);
    }

    return ret_value;
}

2.5.sensor cfg介绍

//vendor/sprd/modules/libcamera/sensor/sensor_cfg.c
#ifdef OV8858
extern SENSOR_INFO_T g_ov8858_mipi_raw_info;
#endif

const SENSOR_MATCH_T back_sensor_infor_tab[] = {
    ...
#ifdef OV8858
    {MODULE_SUNNY, "ov8858", &g_ov8858_mipi_raw_info, {&dw9763a_drv_entry, 0}, {&general_otp_entry, 0xB0, DUAL_CAM_ONE_EEPROM, 8192}},
#endif

...

#ifdef OV8858
    {MODULE_SUNNY, "ov8858", &g_ov8858_mipi_raw_info, {&dw9763a_drv_entry, 0}, {&ov8858_cmk_drv_entry, 0xB0, DUAL_CAM_ONE_EEPROM, 8192}},
#endif

2.6.sensor 模组属性配置

<!-- device/sprd/sharkle/sl8541e_1h10wifi5g_32b/camera/sensor_config.xml -->
<CameraModuleCfg>
        <SlotId>0</SlotId>
        <SensorName>ov8858</SensorName>
        <Facing>BACK</Facing>
        <Orientation>90</Orientation>
        <Resource_cost>50</Resource_cost>
        <TuningParameter>
            <TuningName>hi846_160</TuningName>
        </TuningParameter>
      </CameraModuleCfg>
      <CameraModuleCfg>
        <SlotId>0</SlotId>
        <SensorName>gc02m1b_js_1</SensorName>
        <Facing>BACK</Facing>
        <Orientation>90</Orientation>
        <Resource_cost>50</Resource_cost>
        <TuningParameter>
            <TuningName>hi846_160</TuningName>
        </TuningParameter>
      </CameraModuleCfg>

2.7.sensor_config xml配置文件

<!-- device/sprd/sharkle/sl8541e_1h10wifi5g_32b/camera/sensor_config.xml -->

<root>
  <!-->
  sensor id 0
  <-->
      <CameraModuleCfg>
        <SlotId>0</SlotId>
        <SensorName>ov64b40</SensorName><!-->与sensor驱动文件夹名称相同<-->
        <Facing>BACK</Facing><!-->Sensor朝向<-->
        <Orientation>90</Orientation><!-->Sensor安装角度<-->
        <Resource_cost>50</Resource_cost><!-->该sensor资源占用比例,0-100<-->
        <OTP>
            <E2prom>
                <OtpName>ov64b40_085</OtpName><!-->与OTP驱动文件夹名称相同<-->
                <I2cAddr>0xa0</I2cAddr><!-->E2prom I2C地址<-->
                <E2promNum>1</E2promNum><!-->E2prom数量及存放方式<-->
                <E2promSize>2542</E2promSize><!-->E2prom大小,单位byte<-->
            </E2prom>
        </OTP>
        <VCM>
            <AfName>dw9800</AfName><!-->与AF驱动文件夹名称相同<-->
            <Mode>0</Mode><!-->AF工作模式,默认为0<-->
        </VCM>
        <TuningParameter>
            <TuningName>ov64b40</TuningName><!-->tuning参数的名称<-->
        </TuningParameter>
      </CameraModuleCfg>
      ...
  <!-->
  sensor id 1

3.mk文件配置

3.1.BoardConfig.mk

修改对应的 camera 的对应像素信息配置,根据camera 规格书配置。

#camera sensor support list
#example
#CAMERA_SENSOR_TYPE_BACK :="ov8856,ov8858"
CAMERA_SENSOR_TYPE_BACK := "s5k4h7_wifi5g"
CAMERA_SENSOR_TYPE_FRONT := "gc2385_wifi5g"
CAMERA_SENSOR_TYPE_BACK_EXT := ""
CAMERA_SENSOR_TYPE_FRONT_EXT :=

#tuning param support list
TUNING_PARAM_LIST := "s5k4h7_front_main_wifi5g,gc2385_wifi5g"
追踪 CAMERA_SENSOR_TYPE_BACK



//vendor/sprd/modules/libcamera/sensor/sensor_cfg.c

char *sensor_get_name_list(cmr_u32 sensor_id) {
    char *sensor_name_list_ptr = NULL;

    switch (sensor_id) {
    case SENSOR_MAIN:
        sensor_name_list_ptr = (char *)CAMERA_SENSOR_TYPE_BACK;
        break;
    ...
    return (char *)sensor_name_list_ptr;
}

//sensor_get_name_list
cmr_int sensor_check_name(cmr_u32 sensor_id, SENSOR_MATCH_T *reg_tab_ptr) {
    cmr_int ret = SENSOR_SUCCESS;
    const char *delimiters = ",";
    char *sns_name_list_ptr = sensor_get_name_list(sensor_id);
    char sns_name_str[MAX_SENSOR_NAME_LEN] = {0};
    char *token;

    memcpy(sns_name_str, sns_name_list_ptr,
           MIN(strlen(sns_name_list_ptr), MAX_SENSOR_NAME_LEN));
    for (token = strtok(sns_name_str, delimiters); token != NULL;
         token = strtok(NULL, delimiters)) {
        if (strcasecmp(reg_tab_ptr->sn_name, token) == 0) {
            SENSOR_LOGI("%s name match succesful\n", token);
            return ret;
        }
    }
    return SENSOR_FAIL;
}

//sensor_check_name
//未被调用
M1710U/sl8541e_1h10wifi5g_32b_Natv/out/target/product/sl8541e_1h10wifi5g_32b$ find . -name "*sensor_cfg*"
./obj/SHARED_LIBRARIES/libcamsensor_intermediates/sensor_cfg.o
./obj/SHARED_LIBRARIES/libcamsensor_intermediates/sensor_cfg.d

3.2.Android.mk

#vendor/sprd/modules/libcamera/sensor/Android.mk

LOCAL_SRC_FILES += \
    sensor_cfg.c \
LOCAL_MODULE := libcamsensor    #生成libcamsensor库
编译的so库

sl8541e_1h10wifi5g_32b_Natv/out/target/product/sl8541e_1h10wifi5g_32b$ find . -name "libcamsensor.*"
./obj/SHARED_LIBRARIES/libcamsensor_intermediates/libcamsensor.so
./obj/SHARED_LIBRARIES/libcamsensor_intermediates/LINKED/libcamsensor.so
./obj/SHARED_LIBRARIES/libcamsensor_intermediates/libcamsensor.so.toc
./obj/SHARED_LIBRARIES/libcamsensor_intermediates/libcamsensor.so.d
./obj/PACKAGING/target_files_intermediates/sl8541e_1h10wifi5g_32b_Natv-target_files-20230519.163824/VENDOR/lib/libcamsensor.so
./archive_symbols/symbols.vendor/vendor/lib/libcamsensor.so
./symbols/vendor/lib/libcamsensor.so
./vendor/lib/libcamsensor.so

4.平台OTP驱动

OTP:一次编程的可编程只读存储器

文件路径:vendor/sprd/modules/libcamera/sensor/otp_drv/driver
按照平台OTP规范烧录,数据存储在E2PROM中,可以在该目录下添加驱动,可以参考general驱动。

5.AF驱动移植

AF:自动对焦技术

文件路径:vendor/sprd/modules/libcamera/sensor/af_drv
在该目录下添加AF的驱动,然后在vcm_lib_cfg.mk中添加AF驱动编译关系。

6.闪光灯驱动移植

文件路径:

bsp/modules/common/camera/flash_bsp/kernel/kernel4.14/arch/arm/boot/dts/M1710U_Q/sl8541e-1h10wifi5g_32b.dts
在bsp/modules/common/camera/flash下添加驱动文件夹,并在dts文件中对flash进行设置

flash_ic: flash-ic@63 {
		compatible = "sprd,flash-aw36518";
		reg = <0x63>;
		sprd,flash-ic = <36518>;
		sprd,torch = <1>;
		sprd,preflash = <1>;
		sprd,highlight = <1>;
		sprd,torch-level = <128>;
		sprd,preflash-level = <128>;
		sprd,highlight-level = <128>;
		sprd,lvfm-enable = <1>;
		flash-torch-en-gpios = <&ap_gpio 88 0>;
		flash-chip-en-gpios = <&ap_gpio 89 0>;
		flash-sync-gpios = <&ap_gpio 141 0>;
	};

7.问题

7.1.Camera读取不到ID

打印log .

dev_ err(dev, “Unexpected sensor id(%06x), ret(%d)n”, id, ret);
os04a10 1-0036- 1: Unexpected sensor id(000000), ret(-5)
i2c不通,在读取id之前_os04a10_ power_ on(os04a10);会上电,
所以操作都在这个函数里,确定在这里面供电,clk,各管脚都正常了。仔细量了。
如果是其他摄像头要确定

i2c 地址正常
挂在哪个i2c通道下面
dts 里面都是7位地址
注意不要写错了。
建议i2c的问题客户自己查,这种,只要是_ os04a10 power_ _on 操作对了就不会有问题。
参考:

https://www.cnblogs.com/ChenChangXiong/p/14919931.html
https://blog.csdn.net/lovemengx/article/details/105166764

2017/8/24 14:04 R:\wyb\thl_r16_tinav2.0_hm1375\lichee\linux-3.4\drivers\media\video\sunxi-vfe\device\hm1375.c 2¡¢ R:\wyb\thl_r16_tinav2.0_hm1375\lichee\linux-3.4\drivers\media\video\sunxi-vfe\device\Makefile EXTRA_LDFLAGS += --strip-debug ifneq ($(strip $(CONFIG_ARCH_SUN8IW8)),) obj-$(CONFIG_OV2710_MIPI)+= ov2710_mipi.o obj-$(CONFIG_OV4689)+= ov4689.o obj-$(CONFIG_OV4689_60FPS)+= ov4689_60fps.o obj-$(CONFIG_AR0330_MIPI)+= ar0330_mipi.o obj-$(CONFIG_OV4689_SDV)+= ov4689_sdv.o obj-$(CONFIG_GC1004_MIPI)+= gc1004_mipi.o obj-$(CONFIG_H22_MIPI)+= h22_mipi.o obj-$(CONFIG_NT99231_MIPI)+= nt99231_mipi.o else obj-m+= hm1375.o #obj-m+= ov5640.o #obj-m+= ov2640.o #obj-m+= ov7736.o #obj-m+= s5k4ec.o #obj-m+= s5k4ec_mipi.o #obj-m+= gc2035.o #obj-m+= gt2005.o #obj-m+= gc0307.o #obj-m+= gc0308.o #obj-m+= gc0328.o #obj-m+= gc0328c.o #obj-m+= gc0329.o #obj-m+= gc0311.o #obj-m+= hi253.o #obj-m+= sp2518.o #obj-m+= sp2519.o #obj-m+= sp0718.o #obj-m+= sp0838.o #obj-m+= ov16825.o #obj-m+= ov5650.o #obj-m+= ov5647.o #obj-m+= ov5647_mipi.o #obj-m+= t8et5.o #obj-m+= s5k4e1.o #obj-m+= s5k4e1_mipi.o #obj-m+= sp2518.o #obj-m+= sp0718.o #obj-m+= gc5004.o #obj-m+= gc5004_mipi.o #obj-m+= ov5648.o #obj-m+= ar0330.o #obj-m+= ov5648.o #obj-m+= sp5408.o #obj-m+= ov12830.o #obj-m+= ov8825.o #obj-m+= ov8850.o #obj-m+= gc2155.o #obj-m+= gc2145.o #obj-m+= gc2145d.o #obj-m+= ov8858.o #obj-m+= ov13850.o #obj-m+= imx214.o #obj-m+= ov8858_4lane.o #obj-m+= sp5409.o #obj-m+= s5k5e2yx.o #obj-m+= ov2710_mipi.o #obj-m+= siv121d.o #obj-m+= ov2710_mipi.o #obj-m+= bg0703.o #obj-m+= gc1014_mipi.o #obj-m+= imx219.o #obj-m+= imx224.o #obj-m+= imx322.o #obj-m+= ov8858_r2a_4lane.o #obj-m+= ov8865_4lane.o #obj-m+= ps1210.o #obj-m+= imx291.o endif 3¡¢ÈÃtinav2.0Æô¶¯Ö®ºó²»ÈÃÉãÏñÍ·cameraÐÝÃߣº R:\wyb\thl_r16_tinav2.0_hm1375\lichee\linux-3.4\drivers\media\video\sunxi-vfe\vfe.c static void probe_work_handle(struct work_struct *work) { struct vfe_dev *dev= container_of(work, struct vfe_dev, probe_work.work); int ret = 0; int input_num; int device_valid_count = 0; struct video_device *vfd; char vfe_name[16] = {0}; mutex_lock(&probe_hdl_lock); vfe_print("probe_work_handle start!\n"); vfe_dbg(0,"v4l2_device_register\n"); #ifdef USE_SPECIFIC_CCI vfe_clk_open(dev); #endif /* v4l2 device register */ ret = v4l2_device_register(&dev->pdev->dev, &dev->v4l2_dev); if (ret) { vfe_err("Error registering v4l2 device\n"); goto probe_hdl_free_dev; } dev_set_drvdata(&dev->pdev->dev, (dev)); vfe_dbg(0,"v4l2 subdev register\n"); /* v4l2 subdev register */ dev->is_same_module = 0; for(input_num=0; input_num<dev->dev_qty; input_num++) { vfe_print("v4l2 subdev register input_num = %d\n",input_num); if(!strcmp(dev->ccm_cfg[input_num]->ccm,"")) { vfe_err("Sensor name is NULL!\n"); goto snesor_register_end; } if(dev->is_same_module) { dev->ccm_cfg[input_num]->sd = dev->ccm_cfg[input_num-1]->sd; vfe_dbg(0,"num = %d , sd_0 = %p,sd_1 = %p\n",input_num,dev->ccm_cfg[input_num]->sd,dev->ccm_cfg[input_num-1]->sd); goto snesor_register_end; } if((dev->dev_qty > 1) && (input_num+1<dev->dev_qty)) { if((!strcmp(dev->ccm_cfg[input_num]->ccm,dev->ccm_cfg[input_num+1]->ccm))) dev->is_same_module = 1; } if(dev->vip_define_sensor_list == 1) { if(dev->ccm_cfg[input_num]->sensor_cfg_ini->power_settings_enable == 1) { cpy_ccm_power_settings(dev->ccm_cfg[input_num]); } } #ifdef _REGULATOR_CHANGE_ #else if(vfe_device_regulator_get(dev->ccm_cfg[input_num])) { vfe_err("vfe_device_regulator_get error at input_num = %d\n",input_num); goto snesor_register_end; } #endif vfe_print("vfe sensor detect start! input_num = %d\n",input_num); dev->input = input_num; if(vfe_sensor_register_check(dev,&dev->v4l2_dev,dev->ccm_cfg[input_num],&dev->dev_sensor[input_num],input_num) == NULL) { vfe_err("vfe sensor register check error at input_num = %d\n",input_num); dev->device_valid_flag[input_num] = 0; //goto snesor_register_end; } else{ dev->device_valid_flag[input_num] = 1; device_valid_count ++; } if(dev->ccm_cfg[input_num]->is_isp_used && dev->ccm_cfg[input_num]->is_bayer_raw) { if(read_ini_info(dev,input_num, "/system/etc/hawkview/")) { vfe_warn("read ini info fail\n"); } } if(dev->ccm_cfg[input_num]->act_used == 1) { dev->dev_act[input_num].addr = (unsigned short)(dev->ccm_cfg[input_num]->act_slave>>1); strcpy(dev->dev_act[input_num].type,dev->ccm_cfg[input_num]->act_name); if(vfe_actuator_subdev_register(dev,dev->ccm_cfg[input_num], &dev->dev_act[input_num]) != 0) ;//goto probe_hdl_free_dev; } snesor_register_end: vfe_dbg(0,"dev->ccm_cfg[%d] = %p\n",input_num,dev->ccm_cfg[input_num]); vfe_dbg(0,"dev->ccm_cfg[%d]->sd = %p\n",input_num,dev->ccm_cfg[input_num]->sd); vfe_dbg(0,"dev->ccm_cfg[%d]->power.iovdd = %p\n",input_num,dev->ccm_cfg[input_num]->power.iovdd); vfe_dbg(0,"dev->ccm_cfg[%d]->power.avdd = %p\n",input_num,dev->ccm_cfg[input_num]->power.avdd); vfe_dbg(0,"dev->ccm_cfg[%d]->power.dvdd = %p\n",input_num,dev->ccm_cfg[input_num]->power.dvdd); vfe_dbg(0,"dev->ccm_cfg[%d]->power.afvdd = %p\n",input_num,dev->ccm_cfg[input_num]->power.afvdd); } dev->input = -1; /*video device register */ ret = -ENOMEM; vfd = video_device_alloc(); if (!vfd) { goto probe_hdl_unreg_dev; } *vfd = vfe_template[dev->id]; vfd->v4l2_dev = &dev->v4l2_dev; sprintf(vfe_name,"vfe-%d",dev->id); dev_set_name(&vfd->dev, vfe_name); if (0 != device_valid_count) { ret = video_register_device(vfd, VFL_TYPE_GRABBER, dev->id); if (ret < 0) { goto probe_hdl_rel_vdev; } } video_set_drvdata(vfd, dev); /*add device list*/ /* Now that everything is fine, let's add it to device list */ list_add_tail(&dev->devlist, &devlist); dev->vfd = vfd; vfe_print("V4L2 device registered as %s\n",video_device_node_name(vfd)); /*initial video buffer queue*/ videobuf_queue_dma_contig_init(&dev->vb_vidq, &vfe_video_qops, NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,//default format, can be changed by s_fmt sizeof(struct vfe_buffer), dev,NULL); ret = sysfs_create_group(&dev->pdev->dev.kobj, &vfe_attribute_group); #ifdef CONFIG_ES dev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1; dev->early_suspend.suspend = vfe_early_suspend; dev->early_suspend.resume = vfe_late_resume; // [hawkview_err]xxxxcan't open /dev/video0(Resource temporarily unavailable) // 2016/10/25 14:33 wenyuanbo cloase suspend. // register_early_suspend(&dev->early_suspend); vfe_print("register_early_suspend @ probe handle!\n"); #endif #ifdef USE_SPECIFIC_CCI vfe_clk_close(dev); #endif vfe_print("probe_work_handle end!\n"); mutex_unlock(&probe_hdl_lock); return ; probe_hdl_rel_vdev: video_device_release(vfd); vfe_print("video_device_release @ probe_hdl!\n"); probe_hdl_unreg_dev: vfe_print("v4l2_device_unregister @ probe_hdl!\n"); v4l2_device_unregister(&dev->v4l2_dev); probe_hdl_free_dev: vfe_print("vfe_resource_release @ probe_hdl!\n"); #ifdef USE_SPECIFIC_CCI csi_cci_exit_helper(dev->cci_sel); vfe_clk_close(dev); #endif //vfe_resource_release(dev); vfe_err("Failed to install at probe handle\n"); mutex_unlock(&probe_hdl_lock); return ; } 4¡¢ R:\wyb\thl_r16_tinav2.0_hm1375\package\allwinner\cameratest\src\common\hawkview.c int fetch_sub_cmd(const char* buf,int buf_len,char** cmd,int* cmd_num,int lenght) { int i = 0,j = 0,n = 0; while(buf[i] != '#'){ //the sub cmd end by '#' while(buf[i] != 'x' && buf[i] != ':' && buf[i] != '#') { if((i+1) > buf_len) return 0; ÐÞ¸ÄΪ£º if(i++ > buf_len) return 0; *((char*)cmd + n*lenght + j++) = buf[i++]; if(j > lenght) { hv_err("sub cmd over long\n"); *cmd_num = n + 1; return -1; } } *((char*)cmd + n*lenght + j++) = '\0'; n++; j = 0; if(buf[i] != '#'){ i++; } if(n > *cmd_num){ hv_err("the max cmd num is %d\n",*cmd_num); return -1; } } *cmd_num = n; return 0; } R:\wyb\thl_r16_tinav2.0_hm1375\package\allwinner\cameratest\src\common\video.c static int capture_frame(void* capture,int (*set_disp_addr)(int,int,unsigned int*),pthread_mutex_t* mutex) { capture_handle* cap = (capture_handle*)capture; int ret; int i; struct v4l2_buffer buf; enum v4l2_buf_type type; fd_set fds; struct timeval tv; pthread_mutex_lock(mutex); //used for cammand and status debug if (old_vi_cmd != cap->cmd){ hv_dbg("capture frame command %d --> %d\n",old_vi_cmd,cap->cmd); old_vi_cmd = (int)cap->cmd; } if(old_status != cap->status){ hv_dbg("capture frame status %d --> %d\n",old_status,cap->status); old_status = cap->status; } if(cap->status == OFF && cap->cmd == START_STREAMMING){ hv_dbg("capture start streaming\n"); type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(videofh, VIDIOC_STREAMON, &type) == -1) { hv_err("VIDIOC_STREAMON error! %s\n",strerror(errno)); goto quit; } cap->status = ON; cap->cmd = COMMAND_UNUSED; pthread_mutex_unlock(mutex); return 0; } if(cap->status == ON && cap->cmd == STOP_STREAMMING){ hv_dbg("capture stop streaming\n"); type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if(-1 == ioctl(videofh, VIDIOC_STREAMOFF, &type)){ hv_err("VIDIOC_STREAMOFF error! %s\n",strerror(errno)); goto quit; } cap->status = OFF; cap->cmd = COMMAND_UNUSED; capture_quit(capture); pthread_mutex_unlock(mutex); return 2; } if(cap->status == OFF) { pthread_mutex_unlock(mutex); return 0; } FD_ZERO(&fds); FD_SET(videofh, &fds); tv.tv_sec = 2; tv.tv_usec = 0; pthread_mutex_unlock(mutex); ret = select(videofh + 1, &fds, NULL, NULL, &tv); pthread_mutex_lock(mutex); //hv_dbg("select video ret: %d\n",ret); if (ret == -1) { if (errno == EINTR) { return 0; } hv_err("select error\n"); goto stream_off; } else if (ret == 0) { hv_err("select timeout\n"); pthread_mutex_unlock(mutex); return 0; } memset(&buf, 0, sizeof(struct v4l2_buffer)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = ioctl(videofh, VIDIOC_DQBUF, &buf); if (ret == -1) { hv_err("VIDIOC_DQBUF failed!\n"); goto stream_off; } float framerate; framerate = get_framerate((long long)(buf.timestamp.tv_sec),(long long)(buf.timestamp.tv_usec)); if(framerate > 1.0){ cap->cap_fps = framerate; //hv_dbg("framerate: %0.2ffps\n",cap->cap_fps); } //sync capture info perp x second #define M_SECOND 200 if(is_x_msec(M_SECOND,(long long)(buf.timestamp.tv_sec),(long long)(buf.timestamp.tv_usec))){ getExifInfo(&(cap->frame.exif)); set_cap_info((void*)cap); ÐÞ¸ÄΪ£º // set_cap_info((void*)cap); } if(cap->cmd == STOP_SAVE_FRAME && cap->save_status == ON) cap->save_status = OFF; //save frame , the frame will be get by PC Tool to preview on PC screen //frame format: /dev/frame_x (x:0~21) if(cap->cmd == SAVE_FRAME || cap->save_status == ON ) { if(cap->cmd == SAVE_FRAME){ cap->save_status = ON; cap->cmd = COMMAND_UNUSED; } ret = do_save_frame(capture,buf.index); } //take yuv image,it will save the target frame exif info in the same time //image name: xxxx (set by usered through command) //exif info name: xxxx.exif if(cap->cmd == SAVE_IMAGE ) { ret = 0;//getExifInfo(&(cap->picture.exif)); //get target frame exif info successfully then save the target image //if get the exif info fail,it will try next frame if(ret == 0){ buffers[buf.index].phy_addr = buf.m.offset - 0x20000000; hv_dbg("index: %d buffers[buf.index].start = %p\n",buf.index,buffers[buf.index].start); //do_save_image(capture,buf.index); do_save_sub_image(capture,buf.index); cap->cmd = COMMAND_UNUSED; } } //get display addr int w,h; unsigned int addr; get_disp_addr(capture, buf.m.offset,&addr,&w,&h); // set disp buffer if (set_disp_addr){ set_disp_addr(w,h,&addr); } ret = ioctl(videofh, VIDIOC_QBUF, &buf); if (ret == -1) { hv_err("VIDIOC_DQBUF failed!\n"); goto stream_off; } pthread_mutex_unlock(mutex); return 0; stream_off: hv_err("err stream off\n"); ioctl(videofh, VIDIOC_STREAMOFF, &type); quit: capture_quit(capture); pthread_mutex_unlock(mutex); return -1; } R:\wyb\thl_r16_tinav2.0_hm1375\package\allwinner\cameratest\src\common\video_helper.c int set_cap_info(void* capture) { char info[500]; char exif[500]; char file_path[20]; capture_handle* cap = (capture_handle*)capture; memset(info,0,sizeof(info)); strcpy(file_path,"dev/info"); ÐÞ¸ÄΪ£º //strcpy(file_path, "dev/info"); sprintf(file_path, "%s/%s.info", PATH, cap->picture.path_name); //sync string: sensor_type:save_status:framrate:capture_w:capture_h,sub_w,sub_h# sprintf(info, \ "sensor_type = %s\n" \ "status = %d\n" \ "framerate = %0.2f\n" \ "subchanel_width = %d\n" \ "subchanel_height = %d\n" \ "rotation = %d\n\n", \ (cap->sensor_type == 1)?"raw":"yuv", \ cap->save_status, \ cap->cap_fps, \ cap->sub_w, \ cap->sub_h, \ cap->sub_rot); make_exif_info(exif,"none",&(cap->frame.exif),cap->cap_w,cap->cap_h); strcat(info,exif); //hv_dbg("info str:\n%s\n",info); return write_file(file_path,info,sizeof(info)); } int do_save_sub_image(void* capture,int buf_index) { int ret; char image_name[30]; capture_handle* cap = (capture_handle*)capture; memset(image_name,0,sizeof(image_name)); sprintf(image_name,"%s/%s", PATH,cap->picture.path_name); hv_dbg("image_name: %s\n",image_name); £¨½¨ÒéÔö¼ÓÕâÀ set_cap_info(capture); set_exif_info(capture); hv_dbg("--------set_exif_info end\n"); void* vir_sub_start = NULL; unsigned int phy_sub_start = 0; int w,h; if(cap->sensor_type == V4L2_SENSOR_TYPE_RAW){ vir_sub_start = (unsigned int)(buffers[buf_index].start) + ALIGN_4K(ALIGN_16B(cap->cap_w) * cap->cap_h * 3 >> 1); phy_sub_start = buffers[buf_index].phy_addr + ALIGN_4K(ALIGN_16B(cap->cap_w) * cap->cap_h * 3 >> 1); w = cap->sub_w; h = cap->sub_h; } else { vir_sub_start = buffers[buf_index].start; phy_sub_start = buffers[buf_index].phy_addr; w = cap->cap_w; h = cap->cap_h; } #ifdef ANDROID_ENV ret = save_jpeg_frame(image_name,phy_sub_start,w,h); //sprintf(image_name,"/data/camera/yuv%s", cap->picture.path_name); //ret = save_jpeg_frame_by_viraddr(image_name,(void*)vir_sub_start,cap->sub_w,cap->sub_h); #else sprintf(image_name,"%s/yuv%s", PATH,cap->picture.path_name); ret = save_frame_to_file(image_name, \ (void*)(vir_sub_start), \ w,h,cap->cap_fmt, \ 1); #endif if(ret == -1) hv_err("save image failed!\n"); return 0; } 5¡¢¿ÉÑ¡Ôö¼Ófpscamera£º R:\wyb\thl_r16_tinav2.0_hm1375\package\allwinner\fpscamera 6¡¢ define KernelPackage/sunxi-vfe SUBMENU:=$(VIDEO_MENU) TITLE:=sunxi-vfe support FILES:=$(LINUX_DIR)/drivers/media/video/videobuf-core.ko FILES+=$(LINUX_DIR)/drivers/media/video/videobuf-dma-contig.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/csi_cci/cci.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/vfe_os.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/vfe_subdev.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/device/gc0308.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/vfe_v4l2.ko AUTOLOAD:=$(call AutoLoad,90,videobuf-core videobuf-dma-contig cci vfe_os vfe_subdev gc0308 vfe_v4l2) endef ÐÞ¸ÄΪ£º define KernelPackage/sunxi-vfe SUBMENU:=$(VIDEO_MENU) TITLE:=sunxi-vfe support FILES:=$(LINUX_DIR)/drivers/media/video/videobuf-core.ko FILES+=$(LINUX_DIR)/drivers/media/video/videobuf-dma-contig.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/csi_cci/cci.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/vfe_os.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/vfe_subdev.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/device/hm1375.ko FILES+=$(LINUX_DIR)/drivers/media/video/sunxi-vfe/vfe_v4l2.ko AUTOLOAD:=$(call AutoLoad,90,videobuf-core videobuf-dma-contig cci vfe_os vfe_subdev hm1375 vfe_v4l2) endef 7¡¢ R:\wyb\thl_r16_tinav2.0_hm1375\target\allwinner\astar-parrot\configs\sys_config.fex ;---------------------------------------------------------------------------------- ;dcdc1_vol ---set dcdc1 voltage,mV,1600-3400,100mV/step ;dcdc2_vol ---set dcdc2 voltage,mV,600-1540,20mV/step ;dcdc3_vol ---set dcdc3 voltage,mV,600-1860,20mV/step ;dcdc4_vol ---set dcdc4 voltage,mV,600-1540,20mV/step ;dcdc5_vol ---set dcdc5 voltage,mV,1000-2550,50mV/step ;aldo2_vol ---set aldo2 voltage,mV,700-3300,100mV/step ;aldo3_vol ---set aldo3 voltage,mV,700-3300,100mV/step ;---------------------------------------------------------------------------------- [power_sply] dcdc1_vol = 3000 dcdc2_vol = 1100 dcdc3_vol = 1200 dcdc4_vol = 0 dcdc5_vol = 1500 aldo2_vol = 2500 aldo3_vol = 3000 dldo3_vol = 2800 ;gpio0_vol = 2800 ldoio0_vol = 2800 [twi2] twi_used = 1 twi_scl = port:PE12<3><default><default><default> twi_sda = port:PE13<3><default><default><default> ;-------------------------------------------------------------------------------- ;vip (video input port) configuration ;vip_used: 0:disable 1:enable ;vip_mode: 0:sample one interface to one buffer 1:sample two interface to one buffer ;vip_dev_qty: The quantity of devices linked to capture bus ; ;vip_define_sensor_list: If you want use sensor detect function, please set vip_define_sensor_list = 1, and ; verify that file /system/etc/hawkview/sensor_list_cfg.ini is properly configured! ; ;vip_dev(x)_pos: sensor position, "rear" or "front", if vip_define_sensor_list = 1,vip_dev(x)_pos must be configured! ; ;vip_dev(x)_isp_used 0:not use isp 1:use isp ;vip_dev(x)_fmt: 0:yuv 1:bayer raw rgb ;vip_dev(x)_stby_mode: 0:not shut down power at standby 1:shut down power at standby ;vip_dev(x)_vflip: flip in vertical direction 0:disable 1:enable ;vip_dev(x)_hflip: flip in horizontal direction 0:disable 1:enable ;vip_dev(x)_iovdd: camera module io power handle string, pmu power supply ;vip_dev(x)_iovdd_vol: camera module io power voltage, pmu power supply ;vip_dev(x)_avdd: camera module analog power handle string, pmu power supply ;vip_dev(x)_avdd_vol: camera module analog power voltage, pmu power supply ;vip_dev(x)_dvdd: camera module core power handle string, pmu power supply ;vip_dev(x)_dvdd_vol: camera module core power voltage, pmu power supply ;vip_dev(x)_afvdd: camera module vcm power handle string, pmu power supply ;vip_dev(x)_afvdd_vol: camera module vcm power voltage, pmu power supply ;x indicates the index of the devices which are linked to the same capture bus ;fill voltage in uV, e.g. iovdd = 2.8V, vip_devx_iovdd_vol = 2800000 ;fill handle string as below: ;axp22_eldo3 ;axp22_dldo4 ;axp22_eldo2 ;fill handle string "" when not using any pmu power supply ;-------------------------------------------------------------------------------- [csi0] vip_used = 1 vip_mode = 0 vip_dev_qty = 1 vip_define_sensor_list = 0 vip_csi_pck = port:PE00<2><default><default><default> vip_csi_mck = port:PE01<2><default><default><default> vip_csi_hsync = port:PE02<2><default><default><default> vip_csi_vsync = port:PE03<2><default><default><default> vip_csi_d0 = port:PE04<2><default><default><default> vip_csi_d1 = port:PE05<2><default><default><default> vip_csi_d2 = port:PE06<2><default><default><default> vip_csi_d3 = port:PE07<2><default><default><default> vip_csi_d4 = port:PE08<2><default><default><default> vip_csi_d5 = port:PE09<2><default><default><default> vip_csi_d6 = port:PE10<2><default><default><default> vip_csi_d7 = port:PE11<2><default><default><default> ;vip_csi_sck = port:PE12<2><default><default><default> ;vip_csi_sda = port:PE13<2><default><default><default> vip_dev0_mname = "hm1375" vip_dev0_pos = "rear" vip_dev0_lane = 1 vip_dev0_twi_id = 2 vip_dev0_twi_addr = 0x48 vip_dev0_isp_used = 0 vip_dev0_fmt = 0 £¨µ÷ÊÔµÄʱºòÍÆ¼öÑ¡0£¬¸øÉãÏñͷʱÖÓ¹©µç£¬·½±ã²âÁ¿µçѹ£º£© vip_dev0_stby_mode = 0 vip_dev0_vflip = 0 vip_dev0_hflip = 0 vip_dev0_iovdd = "" vip_dev0_iovdd_vol = 2800000 vip_dev0_avdd = "axp22_ldoio0" vip_dev0_avdd_vol = 2800000 vip_dev0_dvdd = "" vip_dev0_dvdd_vol = 1800000 vip_dev0_afvdd = "" vip_dev0_afvdd_vol = 2800000 vip_dev0_power_en = vip_dev0_reset = port:PE14<1><default><default><0> vip_dev0_pwdn = port:PE15<1><default><default><1> vip_dev0_flash_en = vip_dev0_flash_mode = vip_dev0_af_pwdn = 8¡¢¿ÉÑ¡£º rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ make menuconfig Äں˵ÄÐ޸ı£´æÔÚÕâÀ R:\wyb\thl_r16_tinav2.0_hm1375\target\allwinner\astar-parrot\config-3.4 rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ make menuconfig ϵͳµÄÐ޸ı£´æÔÚÕâÀ R:\wyb\thl_r16_tinav2.0_hm1375\target\allwinner\astar-parrot\defconfig 9¡¢ÎªÁ˵÷ÊÔ·½±ã£¬¿ÉÑ¡Ð޸ģº R:\wyb\thl_r16_tinav2.0_hm1375\target\allwinner\generic\configs\env.cfg bootdelay=3 #default bootcmd, will change at runtime according to key press bootcmd=run setargs_nand boot_normal#default nand boot #kernel command arguments console=ttyS0,115200 nor_root=/dev/mtdblock4 nand_root=/dev/nandd mmc_root=/dev/mmcblk0p7 init=/sbin/init loglevel=8 #set kernel cmdline if boot.img or recovery.img has no cmdline we will use this setargs_nor=setenv bootargs console=${console} root=${nor_root} rootwait init=${init} ion_cma_list="8m,32m,64m,128m,256m"loglevel=${loglevel} partitions=${partitions} setargs_nand=setenv bootargs console=${console} root=${nand_root} rootwait init=${init} ion_cma_list="8m,32m,64m,128m,256m" loglevel=${loglevel} partitions=${partitions} setargs_mmc=setenv bootargs console=${console} root=${mmc_root} rootwait init=${init} ion_cma_list="8m,32m,64m,128m,256m" loglevel=${loglevel} partitions=${partitions} #nand command syntax: sunxi_flash read address partition_name read_bytes #0x40007800 = 0x40008000(kernel entry) - 0x800(boot.img header 2k) boot_normal=fatload sunxi_flash boot 43800000 uImage;bootm 43800000 boot_recovery=fatload sunxi_flash extend 43800000 uImage;bootm 43800000 boot_fastboot=fastboot #recovery key recovery_key_value_max=0x13 recovery_key_value_min=0x10 #fastboot key fastboot_key_value_max=0x8 fastboot_key_value_min=0x2 10¡¢ÏȱàÒëÒ»±étianv2.0µÄϵͳ£¬È»ºóÔö¼Ósunxi-vfe supportÖ§³Ö£º rootroot@rootroot-E400:~$ cd wyb/thl_r16_tinav2.0_hm1375/ rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ 7za x thl_r16_tinav2.0_hm1375µÈ´ý×îÖÕÑéÖ¤_20170824_1141.7z -r -o./ rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ source build/envsetup.sh including target/allwinner/octopus-dev/vendorsetup.sh including target/allwinner/astar-parrot/vendorsetup.sh including target/allwinner/astar-evb/vendorsetup.sh including target/allwinner/generic/vendorsetup.sh including target/allwinner/tulip-d1/vendorsetup.sh including target/allwinner/astar-spk/vendorsetup.sh rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ lunch You're building on Linux Lunch menu... pick a combo: 1. octopus_dev-tina 2. octopus_dev-dragonboard 3. astar_parrot-tina 4. astar_parrot-dragonboard 5. astar_evb-tina 6. tulip_d1-tina 7. tulip_d1-dragonboard 8. astar_spk-tina 9. astar_spk-dragonboard Which would you like?3 ============================================ PLATFORM_VERSION_CODENAME=Neptune PLATFORM_VERSION=2.0.0 TARGET_PRODUCT=astar_parrot TARGET_BUILD_VARIANT=tina TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a-neon TARGET_CPU_VARIANT=cortex-a7 TARGET_2ND_ARCH= TARGET_2ND_ARCH_VARIANT= TARGET_2ND_CPU_VARIANT= HOST_ARCH=x86_64 HOST_OS=linux HOST_OS_EXTRA=Linux-3.13.0-24-generic-x86_64-with-Ubuntu-14.04-trusty HOST_BUILD_TYPE=release BUILD_ID=57513AA3 OUT_DIR= ============================================ rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ make -j8 rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ pack -d rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ make menuconfig Allwinner ---> < > fpscamera................................. fpscamera just test the camera ÐÞ¸ÄΪ£º <*> fpscamera................................. fpscamera just test the camera Kernel modules ---> Video Support ---> < > kmod-sunxi-vfe......................................... sunxi-vfe support ÐÞ¸ÄΪ£º <*> kmod-sunxi-vfe......................................... sunxi-vfe support rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ make -j12 rootroot@rootroot-E400:~/wyb/thl_r16_tinav2.0_hm1375$ pack -d 11¡¢¼ÓÔØhm1375µÄÇý¶¯µÄʱºò²é¿´I2CÊÇ·ñÊÇͨµÄ£º R:\wyb\thl_r16_tinav2.0_hm1375\lichee\linux-3.4\drivers\media\video\sunxi-vfe\device\hm1375.c static int sensor_detect(struct v4l2_subdev *sd) { int ret; unsigned char rdval; printk("****wyb %s:%d/%s()! verify HM1375\n", __FILE__, __LINE__, __func__); LOG_ERR_RET(sensor_read(sd, 0x0001, &rdval)) ret = sensor_read(sd, 0x0001,&rdval); printk("****wyb %s:%d/%s()! reg:0x0001=value:0xx right=0x03/0x13\n", __FILE__, __LINE__, __func__, rdval); if (ret < 0) { vfe_dev_err("sensor_read err at sensor_detect!\n"); return ret; } if((rdval != 0x03) && (rdval != 0x13)) { vfe_dev_err("read high val: %d\n", rdval); return -ENODEV; } LOG_ERR_RET(sensor_read(sd, 0x0002, &rdval)) printk("****wyb %s:%d/%s()! reg:0x0002=value:0xx right=0x75\n", __FILE__, __LINE__, __func__, rdval); if(rdval != 0x75) { vfe_dev_err("read low val: %d\n", rdval); return -ENODEV; } printk("HM1375 sensor_detect OK\r\n"); return 0; } £¨Ææ¹ÖµÄʱºòHM1375µÄ0x0001ºÅ¼Ä´æÆ÷£¬µÚÒ»´Î¶ÁÊÇ0x03£¬ÒÔºó¶¼ÊÇ0x13£¬ºÃÉñÆæ£¡£© [ 16.030894] ****wyb drivers/media/video/sunxi-vfe/device/hm1375.c:2891/sensor_detect()! verify HM1375 [ 16.042100] ****wyb drivers/media/video/sunxi-vfe/device/hm1375.c:2895/sensor_detect()! reg:0x0001=value:0x03 right=0x03/0x13 [ 16.055259] ****wyb drivers/media/video/sunxi-vfe/device/hm1375.c:2909/sensor_detect()! reg:0x0002=value:0x75 right=0x75 [ 16.067560] HM1375 sensor_detect OK [ 47.398156] ****wyb drivers/media/video/sunxi-vfe/device/hm1375.c:2891/sensor_detect()! verify HM1375 [ 47.409351] ****wyb drivers/media/video/sunxi-vfe/device/hm1375.c:2895/sensor_detect()! reg:0x0001=value:0x13 right=0x03/0x13 [ 47.422492] ****wyb drivers/media/video/sunxi-vfe/device/hm1375.c:2909/sensor_detect()! reg:0x0002=value:0x75 right=0x75 [ 47.434769] HM1375 sensor_detect OK [ 88.217828] ****wyb drivers/media/video/sunxi-vfe/device/hm1375.c:2891/sensor_detect()! verify HM1375 [ 88.228920] ****wyb drivers/media/video/sunxi-vfe/device/hm1375.c:2895/sensor_detect()! reg:0x0001=value:0x13 right=0x03/0x13 [ 88.242056] ****wyb drivers/media/video/sunxi-vfe/device/hm1375.c:2909/sensor_detect()! reg:0x0002=value:0x75 right=0x75 [ 88.254325] HM1375 sensor_detect OK
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lion_heart001

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

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

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

打赏作者

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

抵扣说明:

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

余额充值