Android MTK Camera驱动代码分析
一、Camera调用过程:
imgsensor起到承上启下的作用,在系统起来时会创建整个camera驱动运行的环境,其中主要的文件和函数如下框图所示,先设备挂载时会调用注册platform设备platform_driver_register,在匹配成功后会调用probe函数进行初始相关的设备:
其中camera的三路电压的上电方式可以通过GPIO来控制,也可以通过PMIC(REGULATOR)的方式来进行控制,在imgsensor_hw中通过不同的pdev信息,调用不同的set函数。涉及文件路径:
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_hw.c
kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6765/camera_hw/regulator/regulator.c
kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6765/camera_hw/gpio/gpio.c
二、上电相关的结构体之间的联系:
(1) 上电时序控制相关:
kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6765/camera_hw/imgsenor_cfg_table.h
kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6765/camera_hw/imgsenor_cfg_table.c
上电方式控制:GPIO供电还是REGULATOR供电 查看原理图与规格书
上电时序控制结构体:
enum IMGSENSOR_SENSOR_IDX { //sensor di MAIN = 0 SUB = 1 MAIN2 = 2IMGSENSOR_SENSOR_IDX_MIN_NUM = 0,IMGSENSOR_SENSOR_IDX_MAIN = IMGSENSOR_SENSOR_IDX_MIN_NUM,IMGSENSOR_SENSOR_IDX_SUB,IMGSENSOR_SENSOR_IDX_MAIN2,IMGSENSOR_SENSOR_IDX_SUB2,IMGSENSOR_SENSOR_IDX_MAIN3,IMGSENSOR_SENSOR_IDX_MAX_NUM,IMGSENSOR_SENSOR_IDX_NONE,
};
struct IMGSENSOR_HW_CFG { //供电信息配置的结构体 PMIC供电 或 GPIO供电enum IMGSENSOR_SENSOR_IDX sensor_idx;enum IMGSENSOR_I2C_DEV i2c_dev;struct IMGSENSOR_HW_CUSTOM_POWER_INFO pwr_info[IMGSENSOR_HW_POWER_INFO_MAX];//电源信息结构体数组
};
struct IMGSENSOR_HW_CUSTOM_POWER_INFO {enum IMGSENSOR_HW_ID id;enum IMGSENSOR_HW_PIN pin;
};
struct IMGSENSOR_HW_CFG imgsensor_custom_config[] = {{IMGSENSOR_SENSOR_IDX_MAIN,IMGSENSOR_I2C_DEV_0,{{IMGSENSOR_HW_ID_MCLK, IMGSENSOR_HW_PIN_MCLK},{IMGSENSOR_HW_ID_REGULATOR, IMGSENSOR_HW_PIN_AVDD},//REGULATOR即为PMIC供电{IMGSENSOR_HW_ID_REGULATOR, IMGSENSOR_HW_PIN_DOVDD},{IMGSENSOR_HW_ID_REGULATOR, IMGSENSOR_HW_PIN_DVDD},{IMGSENSOR_HW_ID_REGULATOR, IMGSENSOR_HW_PIN_AFVDD},{IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_AF_EN}, //GPIO即为GPIO供电{IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_PDN},{IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_RST},{IMGSENSOR_HW_ID_NONE, IMGSENSOR_HW_PIN_NONE},},}, ...
(2)上电时序控制结构体
struct IMGSENSOR_HW_POWER_INFO {enum IMGSENSOR_HW_PIN pin;enum IMGSENSOR_HW_PIN_STATE pin_state_on;u32 pin_on_delay;enum IMGSENSOR_HW_PIN_STATE pin_state_off;u32 pin_off_delay;
};
struct IMGSENSOR_HW_POWER_SEQ { //上电时序结构体char *name;struct IMGSENSOR_HW_POWER_INFO pwr_info[IMGSENSOR_HW_POWER_INFO_MAX];u32 _idx;
};
struct IMGSENSOR_HW_POWER_SEQ platform_power_sequence[] = {#ifdef MIPI_SWITCH{PLATFORM_POWER_SEQ_NAME,{{IMGSENSOR_HW_PIN_MIPI_SWITCH_EN,IMGSENSOR_HW_PIN_STATE_LEVEL_0,0,IMGSENSOR_HW_PIN_STATE_LEVEL_HIGH,0},{IMGSENSOR_HW_PIN_MIPI_SWITCH_SEL,IMGSENSOR_HW_PIN_STATE_LEVEL_HIGH,0,IMGSENSOR_HW_PIN_STATE_LEVEL_0,0},},IMGSENSOR_SENSOR_IDX_SUB,},{PLATFORM_POWER_SEQ_NAME,{{IMGSENSOR_HW_PIN_MIPI_SWITCH_EN,IMGSENSOR_HW_PIN_STATE_LEVEL_0,0,IMGSENSOR_HW_PIN_STATE_LEVEL_HIGH,0},{IMGSENSOR_HW_PIN_MIPI_SWITCH_SEL,IMGSENSOR_HW_PIN_STATE_LEVEL_0,0,IMGSENSOR_HW_PIN_STATE_LEVEL_0,0},},IMGSENSOR_SENSOR_IDX_MAIN2,},
#endif
struct IMGSENSOR_HW_POWER_SEQ sensor_power_sequence[] = {#if defined(HI1336_MIPI_RAW){SENSOR_DRVNAME_HI1336_MIPI_RAW, //上电时序{{DOVDD, Vol_1800, 1}, //电压相关查看规格书配置表{DVDD, Vol_1100, 5},{AVDD, Vol_2800, 1},{AFVDD, Vol_2800, 1}, //马达上电相关{AFVDD_EN, Vol_Low, 0}, //马达上电相关{AFVDD_EN, Vol_High, 1}, //马达上电相关{SensorMCLK, Vol_High, 0},{RST, Vol_Low, 10},{RST, Vol_High, 1},},},#endif ......VCAMD 主要给 ISP 供电; VCAM_IO 是数字IO电源,主要给I2C供电, VCAMA 是模拟供电,主要给 感光区 和 ADC 部分供电, VCAMAF 主要给对焦马达供电;
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_hw.c
上述的上电配置、时序最终都会在Imgsensor_hw.c中调用
├── imgsensor_power
├── imgsensor_power_sequence
├── imgsensor_hw_init
└── imgsensor_hw_release_all
三、平台设备驱动的注册加载
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_proc.c
kernel-4.9/drivers/base/platform.c
kernel-4.9/include/linux/of_device.h
平台设备驱动匹配的进化过程https://www.cnblogs.com/zzb-Dream-90Time/p/7250010.html
camera 驱动先是注册 platform 平台驱动,然后注册Camera字符设备,创建class类,再通过 I2c 注册前后摄注册字符设备,封装底层方法 imgsensor_ioctl,上层访问底层驱动时候先是使用 setdriver 获取具体IC的驱动的入口,然后使用 checkisalive 对 sensorlist 中的 IC 进行上电,上电完成就通过 I2C 读取设备 ID ,到此为止,上层应用与底层驱动挂接完成,紧接着就是预览和拍照,具体 IC 驱动的实现了。
(1)设备加载 module_init加载模块,注册platform总线驱动
static const struct of_device_id gimgsensor_of_device_id[] = {{ .compatible = "mediatek,camera_hw", },{}
};static struct platform_driver gimgsensor_platform_driver = {.probe = imgsensor_probe,.remove = imgsensor_remove,.suspend = imgsensor_suspend,.resume = imgsensor_resume,.driver = {.name = "image_sensor",.owner = THIS_MODULE,#ifdef CONFIG_OF.of_match_table = gimgsensor_of_device_id,#endif}
};Platform.c调用of_driver_match_device → of_match_device(drv->of_match_table, dev) → __of_match_node()去匹配,
通过把device_driver的of_match_table(of_device_id结构体的数组)和device里的of_node(device_node结构体)进行匹配,匹配方式
是分别比较两者的name、type、和compatible字符串,三者要同时相同(一般name、和type为空,只比较compatible字符串),设备树加载
的时候构建了device设备,被初始化了of_node成员,即设备树加载之后,内核会自动把设备树节点转换成 platform_device这种格式,同时把
名字放到of_node这个地方static int imgsensor_probe(struct platform_device *pdev)
{/* Register char driver */if (imgsensor_driver_register()) { //注册imgsensor字符设备驱动pr_err("[CAMERA_HW] register char device failed!\n");return -1;}gpimgsensor_hw_platform_device = pdev;#ifndef CONFIG_FPGA_EARLY_PORTINGimgsensor_clk_init(&pgimgsensor->clk);#endifimgsensor_hw_init(&pgimgsensor->hw);imgsensor_i2c_create();imgsensor_proc_init();//与proc文件系统有关 ↓↓atomic_set(&pgimgsensor->imgsensor_open_cnt, 0);//原子操作#ifdef CONFIG_MTK_SMI_EXT //mmdevfs is set for mtk multimedia drivermmdvfs_register_mmclk_switch_cb(mmsys_clk_change_cb,MMDVFS_CLIENT_ID_ISP);#endifreturn 0;
}
proc_create("driver/camsensor", 0664, NULL,&fcamera_proc_fops); //在proc文件夹下创建虚拟文件及其权限
static const struct file_operations fcamera_proc_fops = {.owner = THIS_MODULE,.read = seq_read,.open = proc_camsensor_open,.write = CAMERA_HW_Reg_Debug
};
(2)创建字符设备
static const struct file_operations gimgsensor_file_operations = {.owner = THIS_MODULE,.open = imgsensor_open,.release = imgsensor_release,.unlocked_ioctl = imgsensor_ioctl,// camera的控制函数 adopt_CAMERA_HW_FeatureControl 硬件初始化#ifdef CONFIG_COMPAT //上调用imgsensor_set_driver() 寻找sensor进行硬件初始化 .compat_ioctl = imgsensor_compat_ioctl //上调用imgsensor_i2c_init() #endif
};
static inline int imgsensor_driver_register(void)
{dev_t dev_no = MKDEV(IMGSENSOR_DEVICE_NNUMBER, 0);//申请主设备号 if (alloc_chrdev_region(&dev_no, 0, 1, IMGSENSOR_DEV_NAME)) { // 主 次设备号 申请次设备号的个数 cat /proc/devices显示的名称pr_debug("[CAMERA SENSOR] Allocate device no failed\n");return -EAGAIN;}
/* Allocate driver */gpimgsensor_cdev = cdev_alloc(); //cdev 分配空间if (gpimgsensor_cdev == NULL) {unregister_chrdev_region(dev_no, 1);pr_debug("[CAMERA SENSOR] Allocate mem for kobject failed\n");return -ENOMEM;}/* Attatch file operation. */cdev_init(gpimgsensor_cdev, &gimgsensor_file_operations);//字符设备的操作函数gpimgsensor_cdev->owner = THIS_MODULE;/* Add to system */if (cdev_add(gpimgsensor_cdev, dev_no, 1)) { //初始化cdev,通过cdev_add加入到系统中pr_debug("Attatch file operation failed\n");unregister_chrdev_region(dev_no, 1);//没有add成功,需要释放设备号return -EAGAIN;}gpimgsensor_class = class_create(THIS_MODULE, "sensordrv");//创建类 /sys/class/if (IS_ERR(gpimgsensor_class)) {int ret = PTR_ERR(gpimgsensor_class);pr_debug("Unable to create class, err = %d\n", ret);return ret;}gimgsensor_device =device_create(gpimgsensor_class,NULL, // sys/class/sensordrv/IMGSENSOR_DEV_NAMEdev_no,NULL,IMGSENSOR_DEV_NAME);return 0;
}
(3)时钟初始化
kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6765/imgsensor_clk.c
enum IMGSENSOR_RETURN imgsensor_clk_init(struct IMGSENSOR_CLK *pclk)
{int i;struct platform_device *pplatform_dev = gpimgsensor_hw_platform_device;//extern外部//在imgsensor.c中 imgsensor_probe传入的platform_device*pdev赋值给gpimgsensor_hw_platform_deviceif (pplatform_dev == NULL) {pr_err("[%s] pdev is null\n", __func__);return IMGSENSOR_RETURN_ERROR;}/* get all possible using clocks */for (i = 0; i < IMGSENSOR_CCF_MAX_NUM; i++)//imgsensor_clk.h中enum IMGSENSOR_CCF中定义pclk->imgsensor_ccf[i] = // ccf clock common framework devm_clk_get(&pplatform_dev->dev,gimgsensor_mclk_name[i]); return IMGSENSOR_RETURN_SUCCESS;
}devm_clk_get,和clk_get一样,只是使用了device resource management,可以自动释放;在申请资源会判断是否失败,因此会充斥着大量繁琐的代码,设备资源管理即可driver你只管申请就行了,不用考虑释放,我设备模型帮你释放。clk_get,以device指针或者id字符串(可以看作name)为参数,查找clock。(1)dev和id的任意一个可以为空。如果id为空,则必须有device tree的支持才能获得device对应的clk;(2)根据具体的平台实现,id可以是一个简单的名称,也可以 是一个预先定义的、唯一的标识(一般在平台提供的头文件中定义,如mach/clk.h);(3)不可以在中断上下文调用。
char *gimgsensor_mclk_name[IMGSENSOR_CCF_MAX_NUM] = {"CLK_TOP_CAMTG_SEL","CLK_TOP_CAMTG1_SEL","CLK_TOP_CAMTG2_SEL","CLK_TOP_CAMTG3_SEL","CLK_MCLK_6M","CLK_MCLK_12M","CLK_MCLK_13M","CLK_MCLK_24M","CLK_MCLK_26M","CLK_MCLK_48M","CLK_MCLK_52M","CLK_CAM_SENINF_CG","CLK_MIPI_C0_26M_CG","CLK_MIPI_C1_26M_CG","CLK_MIPI_ANA_0A_CG","CLK_MIPI_ANA_0B_CG","CLK_MIPI_ANA_1A_CG","CLK_MIPI_ANA_1B_CG","CLK_MIPI_ANA_2A_CG","CLK_MIPI_ANA_2B_CG","CLK_TOP_CAMTM_SEL_CG","CLK_TOP_CAMTM_208_CG","CLK_SCP_SYS_CAM",
};
(4)电压初始化
(1)依次调用GPIO/REGULATOR/MCLK的init接口;
(2)解析出imgsensor_custom_config,获取到对应sensor的对应管脚(DVDD/AVDD…)的上电方式(GPIO/REGULATOR);
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_hw.c
enum IMGSENSOR_RETURN imgsensor_hw_init(struct IMGSENSOR_HW *phw)
{struct IMGSENSOR_HW_SENSOR_POWER *psensor_pwr;struct IMGSENSOR_HW_CFG *pcust_pwr_cfg;struct IMGSENSOR_HW_CUSTOM_POWER_INFO *ppwr_info;int i, j;char str_prop_name[LENGTH_FOR_SNPRINTF];struct device_node *of_node= of_find_compatible_node(NULL, NULL, "mediatek,camera_hw");//匹配节点,of操作之一//依次调用GPIO/REGULATOR/MCLK的init接口for (i = 0; i < IMGSENSOR_HW_ID_MAX_NUM; i++) {if (hw_open[i] != NULL)(hw_open[i])(&phw->pdev[i]);if (phw->pdev[i]->init != NULL)(phw->pdev[i]->init)(phw->pdev[i]->pinstance);}//解析出imgsensor_custom_configfor (i = 0; i < IMGSENSOR_SENSOR_IDX_MAX_NUM; i++) {psensor_pwr = &phw->sensor_pwr[i];pcust_pwr_cfg = imgsensor_custom_config;//上电时序while (pcust_pwr_cfg->sensor_idx != i)pcust_pwr_cfg++;if (pcust_pwr_cfg->sensor_idx == IMGSENSOR_SENSOR_IDX_NONE)continue;//退出循环ppwr_info = pcust_pwr_cfg->pwr_info;while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE) {//查询imgsensor_custom_config中ID_PIN 是否在GPIO/REGULATOR/Mclk中for (j = 0; j < IMGSENSOR_HW_ID_MAX_NUM; j++)if (ppwr_info->id == phw->pdev[j]->id)break;//将对应sensor的对应PIN(DVDD/AVDD...)设置为系统的ID_PIN(GPIO/REGULATOR/MCKL)psensor_pwr->id[ppwr_info->pin] = j;ppwr_info++;}}//判断dts中是否设定对应的index为对应的name,如:cam3_enable_sensor = "gc2375hmain3_mipi_raw";for (i = 0; i < IMGSENSOR_SENSOR_IDX_MAX_NUM; i++) {memset(str_prop_name, 0, sizeof(str_prop_name));snprintf(str_prop_name, sizeof(str_prop_name), "cam%d_%s", i, "enable_sensor");if (of_property_read_string(of_node,str_prop_name,&phw->enable_sensor_by_index[i]) < 0) {pr_info("Property cust-sensor not defined\n");phw->enable_sensor_by_index[i] = NULL;}}return IMGSENSOR_RETURN_SUCCESS;
}
(5)imgsensor_i2c_create I2C设备初始化 //注册前后摄像头驱动
IMGSENSOR_I2C_DEV_MAX_NUM 通过枚举进行赋值,其值为3,说明最多可以注册的摄像头驱动为3个。因为camera 驱动是挂载在 I2C总线 上,所以通过函数 i2c_add_driver() 进行注册。gi2c_driver 结构体对应一个具体 camera 设备的驱动。
/kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6739/camera_hw/imgsensor_cfg_table.h
下方匹配的名称都使用了imgsensor_cfg_table.h中
/* 如果不使用设备树,会匹配这三个宏 */ static const struct i2c_device_id gi2c_dev_id[] = {{IMGSENSOR_I2C_DRV_NAME_0, 0},{IMGSENSOR_I2C_DRV_NAME_1, 0},{IMGSENSOR_I2C_DRV_NAME_2, 0},{}};
#define IMGSENSOR_I2C_DRV_NAME_0 "kd_camera_hw"
#define IMGSENSOR_I2C_DRV_NAME_1 "kd_camera_hw_bus2"
#define IMGSENSOR_I2C_DRV_NAME_2 "kd_camera_hw_bus3"
/* 如果使用设备树,则会匹配这三个宏 */
#define IMGSENSOR_I2C_OF_DRV_NAME_0 "mediatek,camera_main"
#define IMGSENSOR_I2C_OF_DRV_NAME_1 "mediatek,camera_sub"
#define IMGSENSOR_I2C_OF_DRV_NAME_2 "mediatek,camera_main_two"
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_i2c.c
enum IMGSENSOR_RETURN imgsensor_i2c_create(void)
{int i;for (i = 0; i < IMGSENSOR_I2C_DEV_MAX_NUM; i++)i2c_add_driver(&gi2c_driver[i]);return IMGSENSOR_RETURN_SUCCESS;
}
#ifdef CONFIG_OF
static const struct of_device_id gof_device_id_0[] = {/* "mediatek,camera_main" */{ .compatible = IMGSENSOR_I2C_OF_DRV_NAME_0, },{}
};
static const struct of_device_id gof_device_id_1[] = {/* "mediatek,camera_sub" */{ .compatible = IMGSENSOR_I2C_OF_DRV_NAME_1, },{}
};
static const struct of_device_id gof_device_id_2[] = {/* "mediatek,camera_main_two" */{ .compatible = IMGSENSOR_I2C_OF_DRV_NAME_2, },{}
};
static struct i2c_driver gi2c_driver[IMGSENSOR_I2C_DEV_MAX_NUM] = {{.probe = imgsensor_i2c_probe_0,.remove = imgsensor_i2c_remove,.driver = {.name = IMGSENSOR_I2C_DRV_NAME_0, // "kd_camera_hw".owner = THIS_MODULE,
#ifdef CONFIG_OF.of_match_table = gof_device_id_0,
#endif},.id_table = gi2c_dev_id,},{.probe = imgsensor_i2c_probe_1,.remove = imgsensor_i2c_remove,.driver = {.name = IMGSENSOR_I2C_DRV_NAME_1, // "kd_camera_hw_bus2".owner = THIS_MODULE,
#ifdef CONFIG_OF.of_match_table = gof_device_id_1,
#endif},.id_table = gi2c_dev_id,},{.probe = imgsensor_i2c_probe_2,.remove = imgsensor_i2c_remove,.driver = {.name = IMGSENSOR_I2C_DRV_NAME_2, // "kd_camera_hw_bus3".owner = THIS_MODULE,
#ifdef CONFIG_OF.of_match_table = gof_device_id_2,
#endif},.id_table = gi2c_dev_id,}
}
#endif
使用MTK DrvGen生成
./out/target/product/xxx/obj/KERNEL_OBJ/arch/arm/boot/dts/xxx/cust.dtsi
xxx.dts中包含cust_mt6765_camera.dtsi中包含kd_camera_hw1节点;
cust.dtsi中也包含kd_camera_hw1节点,后者会出现下相同会进行覆盖
&i2c2 {#address-cells = <1>;#size-cells = <0>;clock-frequency = <400000>;mediatek,use-open-drain;camera_main_mtk:camera_main@20 {compatible = "mediatek,camera_main";reg = <0x20>;status = "okay";};camera_main_af_mtk:camera_main_af@0c {compatible = "mediatek,camera_main_af";reg = <0x0c>;status = "okay";};camera_sub_mtk:camera_sub@3c {compatible = "mediatek,camera_sub";reg = <0x3c>;status = "okay";};
};
...
...
当内核启动后,会解析dts编译生成的dtb文件,注册里面定义的 device ,代码中设置的 of_device_id 需要分别匹配上 cust.dtsi 文件中的 compatible 节点 “mediatek,camera_main” 和 “mediatek,camera_sub” 。如果和驱动中定义 compatible 字段一致,则挂载启动。上面注册了两个platform 驱动 gi2c_driver 。如果 compatible 匹配成功会调用各自的 probe 函数 imgsensor_i2c_probe_0,imgsensor_i2c_probe_1 。
(6) imgsensor_ioctl上层用于摄像头的具体操作
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/kd_sensorlist.c
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/kd_sensorlist.h
#define KDIMGSENSORIOC_T_OPEN _IO(IMGSENSORMAGIC, 0)
#define KDIMGSENSORIOC_X_SET_DRIVER _IOWR(IMGSENSORMAGIC, 35, SENSOR_DRIVER_INDEX_STRUCT)
#define HI1336_SENSOR_ID 0x1336
#define SENSOR_DRVNAME_HI1336_MIPI_RAW "hi1336_mipi_raw"
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_sensor_list.c
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_sensor_list.h
UINT32 HI1336_MIPI_RAW_SensorInit(struct SENSOR_FUNCTION_STRUCT **pfFunc);最终实现在具体sensor的驱动函数中hi336mipiraw_Sensor.c,操作寄存器去完成功能 ↓↓↓
struct IMGSENSOR_INIT_FUNC_LIST kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR] = {#if defined(HI1336_MIPI_RAW){HI1336_SENSOR_ID,SENSOR_DRVNAME_HI1336_MIPI_RAW,HI1336_MIPI_RAW_SensorInit},
#endif
.../* ADD sensor driver before this line */{0, {0}, NULL}, /* end of list */
};
vendor/mediatek/proprietary/custom/mt6765/hal/imgsensor_src/sensorlist.cpp
注意Kernel层中的kdSensorList和HAL层中的sensorList的顺序必须保持一致
MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] =
{#if defined(HI1336_MIPI_RAW)RAW_INFO(HI1336_SENSOR_ID, SENSOR_DRVNAME_HI1336_MIPI_RAW,
CAM_CALGetCalData),
#endif
/* ADD sensor driver before this line */{0, 0,{0}, NULL, NULL, NULL}//end of list
};UINT32 GetSensorInitFuncList(MSDK_SENSOR_INIT_FUNCTION_STRUCT
**ppSensorList)
{if (NULL == ppSensorList) {ALOGE("ERROR: NULL pSensorList\n");return MHAL_UNKNOWN_ERROR;}*ppSensorList = &SensorList[0];return MHAL_NO_ERROR;
}
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/hi1336_mipi_raw/hi1336mipiraw_Sensor.c
static struct SENSOR_FUNCTION_STRUCT sensor_func = {open,get_info,get_resolution,feature_control,control,close
};
UINT32 HI1336_MIPI_RAW_SensorInit(struct SENSOR_FUNCTION_STRUCT **pfFunc)
{/* To Do : Check Sensor status here */if (pfFunc != NULL)*pfFunc = &sensor_func;return ERROR_NONE;
} /* HI1336_MIPI_RAW_SensorInit */
Hal层发送 ioctl(m_fdSensor, KDIMGSENSORIOC_X_FEATURECONCTROL, &sensorIdx);
Kernel 接受 KDIMGSENSORIOC_X_FEATURECONCTROL指令,调用 adopt_CAMERA_HW_FeatureControl()
static long imgsensor_ioctl(struct file *a_pstFile,unsigned int a_u4Command,unsigned long a_u4Param)
{//还有一个函数imgsensor_compat_ioctl具体用于操作什么还未分析int i4RetValue = 0;void *pBuff = NULL;if (_IOC_DIR(a_u4Command) != _IOC_NONE) { //_IOC_xx都是宏解析相关的 pBuff = kmalloc(_IOC_SIZE(a_u4Command), GFP_KERNEL);if (pBuff == NULL) {pr_debug("[CAMERA SENSOR] ioctl allocate mem failed\n");i4RetValue = -ENOMEM;goto CAMERA_HW_Ioctl_EXIT;}if (_IOC_WRITE & _IOC_DIR(a_u4Command)) {if (copy_from_user(pBuff, (void *)a_u4Param, _IOC_SIZE(a_u4Command))) {kfree(pBuff);pr_debug("[CAMERA SENSOR] ioctl copy from user failed\n");i4RetValue = -EFAULT;goto CAMERA_HW_Ioctl_EXIT;}}} else {i4RetValue = -EFAULT;goto CAMERA_HW_Ioctl_EXIT;}switch (a_u4Command) {case KDIMGSENSORIOC_X_GET_CONFIG_INFO:i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);break;case KDIMGSENSORIOC_X_FEATURECONCTROL:i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff);break;case KDIMGSENSORIOC_X_CONTROL:i4RetValue = adopt_CAMERA_HW_Control(pBuff);break;case KDIMGSENSORIOC_X_SET_MCLK_PLL:i4RetValue = imgsensor_clk_set(&pgimgsensor->clk,(struct ACDK_SENSOR_MCLK_STRUCT *)pBuff);break;case KDIMGSENSORIOC_T_OPEN:case KDIMGSENSORIOC_T_CLOSE:case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:case KDIMGSENSORIOC_X_SET_DRIVER:...default:pr_debug("No such command %d\n", a_u4Command);i4RetValue = -EPERM;break;}if ((_IOC_READ & _IOC_DIR(a_u4Command)) &©_to_user((void __user *) a_u4Param, pBuff,_IOC_SIZE(a_u4Command))) {kfree(pBuff);pr_debug("[CAMERA SENSOR] ioctl copy to user failed\n");i4RetValue = -EFAULT;goto CAMERA_HW_Ioctl_EXIT;}kfree(pBuff);
CAMERA_HW_Ioctl_EXIT: //goto操作return i4RetValue;
}
static inline int adopt_CAMERA_HW_FeatureControl(void *pBuf)
{struct ACDK_SENSOR_FEATURECONTROL_STRUCT *pFeatureCtrl;struct IMGSENSOR_SENSOR *psensor;unsigned int FeatureParaLen = 0;void *pFeaturePara = NULL;struct ACDK_KD_SENSOR_SYNC_STRUCT *pSensorSyncInfo = NULL;signed int ret = 0;pFeatureCtrl = (struct ACDK_SENSOR_FEATURECONTROL_STRUCT *)pBuf;if (pFeatureCtrl == NULL) {pr_err(" NULL arg.\n");return -EFAULT;}psensor = imgsensor_sensor_get_inst(pFeatureCtrl->InvokeCamera);if (psensor == NULL) {pr_err("[adopt_CAMERA_HW_FeatureControl] NULL psensor.\n");return -EFAULT;}if (pFeatureCtrl->FeatureId == SENSOR_FEATURE_SINGLE_FOCUS_MODE ||pFeatureCtrl->FeatureId == SENSOR_FEATURE_CANCEL_AF ||pFeatureCtrl->FeatureId == SENSOR_FEATURE_CONSTANT_AF ||pFeatureCtrl->FeatureId == SENSOR_FEATURE_INFINITY_AF) {/* YUV AF_init and AF_constent and AF_single has no params */} else {if (pFeatureCtrl->pFeaturePara == NULL ||pFeatureCtrl->pFeatureParaLen == NULL) {pr_err(" NULL arg.\n");return -EFAULT;}if (copy_from_user((void *)&FeatureParaLen,(void *) pFeatureCtrl->pFeatureParaLen, sizeof(unsigned int))) {pr_err(" ioctl copy from user failed\n");return -EFAULT;}if (FeatureParaLen > FEATURE_CONTROL_MAX_DATA_SIZE ||FeatureParaLen == 0)return -EINVAL;ret = check_length_of_para(pFeatureCtrl->FeatureId, FeatureParaLen);if (ret != 0)return ret;pFeaturePara = kmalloc(FeatureParaLen, GFP_KERNEL);if (pFeaturePara == NULL)return -ENOMEM;memset(pFeaturePara, 0x0, FeatureParaLen);}/* copy from user */switch (pFeatureCtrl->FeatureId) {case SENSOR_FEATURE_OPEN:ret = imgsensor_sensor_open(psensor);break;case SENSOR_FEATURE_CLOSE:ret = imgsensor_sensor_close(psensor);/* reset the delay frame flag */break;case SENSOR_FEATURE_SET_DRIVER:{MINT32 drv_idx;psensor->inst.sensor_idx = pFeatureCtrl->InvokeCamera;drv_idx = imgsensor_set_driver(psensor);memcpy(pFeaturePara, &drv_idx, FeatureParaLen);break;}case SENSOR_FEATURE_CHECK_IS_ALIVE:imgsensor_check_is_alive(psensor);break;....case SENSOR_FEATURE_SET_PDAF:case SENSOR_FEATURE_GET_PDAF_INFO:...case SENSOR_FEATURE_SET_STREAMING_RESUME:if (copy_from_user((void *)pFeaturePara,(void *) pFeatureCtrl->pFeaturePara,FeatureParaLen)) {kfree(pFeaturePara);pr_err("[CAMERA_HW][pFeaturePara] ioctl copy from user failed\n");return -EFAULT;}break;
/ * keep the information to wait Vsync synchronize */pSensorSyncInfo =(struct ACDK_KD_SENSOR_SYNC_STRUCT *)pFeaturePara;FeatureParaLen = 2;imgsensor_sensor_feature_control(psensor,SENSOR_FEATURE_SET_GAIN,(unsigned char *)&pSensorSyncInfo->u2SensorNewGain,(unsigned int *) &FeatureParaLen);break;}kfree(pFeaturePara);if (copy_to_user((void __user *) pFeatureCtrl->pFeatureParaLen,(void *)&FeatureParaLen,sizeof(unsigned int))) {pr_debug("[CAMERA_HW][pFeatureParaLen] ioctl copy to user failed\n"); return -EFAULT;}return ret;}
http://blog.csdn.net/LinuxArmbiggod/article/details/91884229
https://www.it610.com/article/1282418947416670208.htm
https://blog.csdn.net/u010783226/article/details/105658842
https://blog.csdn.net/LinuxArmbiggod/article/details/91884229
https://blog.csdn.net/wuye110/article/details/78536322/
Android MTK Camera驱动代码分析相关推荐
- 【高通SDM660平台 Android 10.0】(10) --- Camera Sensor lib 与 Kernel Camera Probe 代码分析
[高通SDM660平台 Android 10.0]Camera Sensor lib 与 Kernel Camera Probe 代码分析 一.libmmcamera_imx258.so 代码分析 1 ...
- Android 8.1/9.0 MTK Camera源码分析之快门声音控制流程
Android 8.1/9.0 MTK Camera源码分析之快门声音控制 在Android 8.1上mtk camera有控制快门声音的接口,但是并没有了控制录像快门声音的接口.之所以会有这个现象, ...
- 【高通SDM660平台 Android 10.0】(12) --- Camera Chromatix 代码分析
[高通SDM660平台 Android 10.0]Qcom Camera Daemon 代码分析 一.chromatix_imx258_lc898217xc 目录 1.1 例:imx258_lc898 ...
- Android 8.1/9.0 MTK Camera源码分析之录像快门声音控制流程
前面已经针对拍照快门声音控制流程进行了分析,接下来分析一下录像快门声音的控制流程. Android 8.1/9.0 MTK Camera源码分析之快门声音控制流程 这两篇文章其实都是相对于手机系统RO ...
- Android MTK Camera博客分享
MTK Camera博客分享 MTK Camera OTP调用过程 MTK Camera Flashlight调用过程 MTK Camera 应用层到底层过程 MTK Camera HAL层分析 深入 ...
- android mtk camera startpreview,android8.1 mtk camera hal各种操作流程
最近一年,一直在做android上的视频编解码和录相.以及camera hal和系统框架这一块.随着做的慢慢的深入,越发觉得mtk的camera hal这一块,有其独到之处.偏偏网上相关的资料却是极少 ...
- MTK Camera驱动移植
对于MTK Camera驱动移植一般分为四部分: 1.硬件IO口配置: 2.Camera驱动移植: 3.上电时序: 4.修改i2c控制器: 硬件电路: 1.GPIO配置 打开 mediatek\dct ...
- MTK6735 Android之Camera驱动移植篇
MTK6735 Android之Camera驱动移植篇 首先我们需要向sensor原厂拿到我们对应平台型号的驱动hal层和kernel层的代码. 1.拷贝hal层代码到\vendor\mediatek ...
- DRM驱动代码分析:开机过程中显示驱动做了什么
前言: 有些信息是在网上查资料后总结的,没有去追代码验证.如果有说得不对的地方,欢迎提出指正.感谢! 手机启动的大致流程 1.长按开机键 2.执行存储在ROM里(应该是某一个固定地址或是预定义的地址) ...
最新文章
- 什么?Spring Boot CommandLineRunner 有坑!?
- Codeforces Round #183 (Div. 2)
- Ⅲ:zookeeper之查看节点的状态及其监听器的使用
- CSS的六种垂直居中
- SWIFT(Society for Worldwide Interbank Financial SWIFT Telecommunications---环球同业银行金融电讯协会)
- lucene全文搜索之三:生成索引字段,创建索引文档(给索引字段加权)基于lucene5.5.3...
- 编写一个学生类 student,包含的属性有学号、姓名年龄,将所有学生存储在一个数组中
- 基于JAVA+SpringMVC+Mybatis+MYSQL的保险业务管理系统
- Java web Tomcat Server总结
- python不等于缺陷
- Spring单一类型依赖查找Bean
- Code For Better 谷歌开发者之声——谷歌Web工具包(GWT)
- 微型计算机原理与接口技术知识点
- 解决使用Keil5不能生成bin文件或生成的是.bin文件夹问题
- Redis集群-哨兵
- vue tab页面缓存处理
- Auto.js Pro安卓免ROOT引流脚本开发系列教程28网易公开课(6)-取随机话术
- Spring如何用“声明式事务”保护亿万数据安全?【万字解决并发冲突】
- PHP 中GET、POST、REQUEST用法
- 常用的排序算法-快速记忆
热门文章
- h5活动是什么意思_H5是什么_H5页面是什么_什么意思_企业服务汇
- 台式计算机用电视机做显示器,电脑怎么一次连接显示器和电视
- OpenVPN 技术支持
- LaTeX入门|(2)定制专属模板
- 单片机很好玩 ,制作呼吸灯(转载)
- 输入netsh winsock reset 重启电脑生效
- 微信小程序开发(五) - 全局(app.js)逻辑 - js 文件
- namedtuple使用
- 【GPGPU编程】GPGPU架构剖析之谓词寄存器
- 记录vultr搭建https爬虫代理