一、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 = 2
IMGSENSOR_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_PORTING
imgsensor_clk_init(&pgimgsensor->clk);
#endif
imgsensor_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 driver
mmdvfs_register_mmclk_switch_cb(mmsys_clk_change_cb,MMDVFS_CLIENT_ID_ISP);
#endif
return 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_NAME
dev_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_device
if (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_config
for (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)) &&
copy_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/