文章目录
Kernel 层驱动的实现
Camera 开机流程
Camera 驱动的文件结构
Camera 驱动初始化流程
Camera 入口函数 imgsensor_init
注册的平台驱动结构体 gimgsensor_platform_driver
imgsensor_probe 探测函数的实现
imgsensor_driver_register 注册函数的实现
gimgsensor_file_operations 文件操作结构体的实现
imgsensor_ioctl 的定义
adopt_CAMERA_HW_FeatureControl 的定义
imgsensor_set_driver 的实现
kdSensorList 结构体中的实现
GC2385_MIPI_RAW_SensorInit 的实现
sensor_func 的实现
open 的实现
feature_control 的实现
imgsensor_i2c_init 的实现
imgsensor_hw_init 的实现
imgsensor_i2c_create() 的实现
gi2c_driver 结构体的实现
设备树中的配置
cust.dtsi 中对camera的配置
k39tv1_bsp.dws 中对camera的配置
camera驱动文件的执行流程
总结
camera 整个驱动框架分为三个部分: hal层 逻辑调用,kernel层 的通用驱动 sensorlist.c 和 具体IC 的驱动, 比如 gc2385_mipi_raw.c ,kernel 起来后不会直接去访问 硬件sensor ,而是会注册相关的驱动,之后 Android系统 起来后会启动相关的服务如: camera_service ,在 camera 服务中会直接去访问 hal层 , kernel驱动 ,进而操作 camera 。这里只分析 kernel层中 camera驱动的实现。
Power On 上电开机,然后通过 i2c 地址匹配 i2c 通讯, reset 和 Power Down 上电 (上电代码在 kd_camera_hw.c 中的 kdCISModulePowerOn , VCAM ** 主要给 ISP 供电; VCAM_IO 是数字IO电源,主要给I2C** 供电, VCAMA 是模拟供电,主要给 感光区 和 ADC 部分供电, VCAMAF 主要给对焦马达供电;具体使用可以根据 datasheet 添加,有时会影响 cts ),读取 sensor ID (具体 ic 驱动里面的 open 和 get_imgsensor_id 都有读取 id 的操作, sensor id 只要大于 0 、小于 0xffffffff 都是合法的),然后软复位,下载 preview 参数为预览做准备,下载 capture 为拍照做准备,然后执行下电操作。
参考 MTK 的 mt6739_Sensor_Porting_guide 可以发现,在 kernel-3.18 中的 camera 驱动有 kd_sensorlist.c 和 kd_camera_hw.c 这两个文件,但是在 MT6739 平台的 kernel-4.4 中将这个文件拆分成了多个文件,如下图所示:
各个文件功能描述
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_hw.c
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_i2c.c
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_proc.c
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_sensor_list.c
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_legacy.c
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/mt6739/camera_hw/imgsensor_cfg_table.c
File | Decription(英文) | Decription(中文) |
---|---|---|
imgsensor.c | Sensor driver adapter and driver entry point | sensor 驱动适配器和驱动入口函数的实现 |
imgsensor_hw.c | Sensor power control | sensor 电源控制的实现 |
imgsensor_i2c.c | I2C read/write | I2C 读写函数的实现 |
imgsensor_proc.c | PROC related part | proc文件系统相关部分的实现 |
imgsensor_sensor_list.c | List of all sensors init function | 包含所有sensor初始化函数的表单 |
imgsensor_legacy.c | Legacy part of sensor. Mainly I2c related API | sensor的旧的接口部分。主要是与I2c相关API |
imgsensor_cfg_table.c | Sensor Power and I2C configruation table | sensor电源和I2C的配置表 |
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
module_init(imgsensor_init);
/* camera sensor入口函数 */
static int __init imgsensor_init(void)
{
PK_DBG("[camerahw_probe] start\n");
/* 注册一个平台驱动gimgsensor_platform_driver */
if (platform_driver_register(&gimgsensor_platform_driver)) {
PK_PR_ERR("failed to register CAMERA_HW driver\n");
return -ENODEV;
}
...
return 0;
}
module_init(imgsensor_init);
/* camera sensor入口函数 */
static int __init imgsensor_init(void)
{
PK_DBG("[camerahw_probe] start\n");
/* 注册一个平台驱动gimgsensor_platform_driver */
if (platform_driver_register(&gimgsensor_platform_driver)) {
PK_PR_ERR("failed to register CAMERA_HW driver\n");
return -ENODEV;
}
...
return 0;
}
#ifdef CONFIG_OF /* 通过设备树进行match */
static const struct of_device_id gimgsensor_of_device_id[] = {
{ .compatible = "mediatek,camera_hw", },
{}
};
#endif
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, /* 保存与设备树compatible进行匹配的字符串 */
#endif
}
};
当 platform_devices 和 platform_driver 通过 match 函数匹配上后,会调用 imgsensor_probe 函数注册前后摄 camera 驱动。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
/* 平台driver成功与device匹配后调用imgsensor_probe */
static int imgsensor_probe(struct platform_device *pdev)
{
/* 分配设置注册camera驱动的字符设备文件/dev/kd_camera_hw,创建主次设备号 */
if (imgsensor_driver_register()) {
PK_PR_ERR("[CAMERA_HW] register char device failed!\n");
return -1;
}
gpimgsensor_hw_platform_device = pdev;
... /* 省略部分代码 */
/* camera硬件初始化,包含对power引脚的配置 */
imgsensor_hw_init(&pgimgsensor->hw);
/* 注册前后摄像头驱动 */
imgsensor_i2c_create();
imgsensor_proc_init();
atomic_set(&pgimgsensor->imgsensor_open_cnt, 0);
#ifdef CONFIG_MTK_SMI_EXT
mmdvfs_register_mmclk_switch_cb(mmsys_clk_change_cb, MMDVFS_CLIENT_ID_ISP);
#endif
return 0;
}
在 imgsensor_probe() 函数中一开始先为 camera 驱动分配设置注册了 camera 字符驱动设备,然后通过函数 imgsensor_i2c_create() 注册前后 camera 驱动。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
static inline int imgsensor_driver_register(void)
{
int i, error = 0;
dev_t dev_no = MKDEV(IMGSENSOR_DEVICE_NNUMBER, 0);
/* 申请主设备号 */
/***************************************************************
* 让内核分配给我们一个尚未使用的主设备号,不是由我们自己指定的
*
* dev : alloc_chrdev_region函数向内核申请下来的主设备号
* baseminor: 次设备号的起始
* count : 申请次设备号的个数
* name : 执行 cat /proc/devices显示的名称
***************************************************************/
if (alloc_chrdev_region(&dev_no, 0, 1, IMGSENSOR_DEV_NAME)) {
PK_DBG("[CAMERA SENSOR] Allocate device no failed\n");
return -EAGAIN;
}
/* Allocate driver */
/* 给 gpimgsensor_cdev 分配内存,会在 cdev_del 中自动释放 */
gpimgsensor_cdev = cdev_alloc();
if (gpimgsensor_cdev == NULL) {
unregister_chrdev_region(dev_no, 1);
PK_DBG("[CAMERA SENSOR] Allocate mem for kobject failed\n");
return -ENOMEM;
}
/* Attatch file operation. */
/*************************************************************
* cdev_init 与 cdev_del 函数基本一致,但是多出来对 cdev->ops
* 的赋值,用来将 gimgsensor_file_operations 加入到系统中,
* gimgsensor_file_operations 中包含着实际处理与设备通信的
* 函数。
*************************************************************/
cdev_init(gpimgsensor_cdev, &gimgsensor_file_operations);
gpimgsensor_cdev->owner = THIS_MODULE;
/* Add to system */
/*************************************************************
* 初始化 cdev 后,需要通过 cdev_add 把它添加到系统中去。
* 传入 cdev 结构的指针 gpimgsensor_cdev , 起始设备编号,
* 以及设备编号范围。
*
* 可以在 /dev/ 目录下找到设备文件 "kd_camera_hw"
*************************************************************/
if (cdev_add(gpimgsensor_cdev, dev_no, 1)) {
PK_DBG("Attatch file operation failed\n");
unregister_chrdev_region(dev_no, 1);
return -EAGAIN;
}
/*************************************************************
* class_create 动态创建设备的逻辑类,并完成部分字段的初始化,
* 然后将其添加到内核中。创建的逻辑类位于/sys/class/。
*
* owner: 拥有者。一般赋值为THIS_MODULE。
* name: 创建的逻辑类的名称。
*************************************************************/
gpimgsensor_class = class_create(THIS_MODULE, "sensordrv");
if (IS_ERR(gpimgsensor_class)) {
int ret = PTR_ERR(gpimgsensor_class);
PK_DBG("Unable to create class, err = %d\n", ret);
return ret;
}
/************************************************************
* 通过 device_create 在 /sys/class/sensordrv/ 目录下创建一个
* 设备文件目录,目录名为 "kd_camera_hw"
************************************************************/
gimgsensor_device = device_create(gpimgsensor_class, NULL, dev_no, NULL, IMGSENSOR_DEV_NAME);
if (!gimgsensor_device) {
pr_err("Failed to create kd_camera_hw device\n");
return -1;
}
for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
error = device_create_file(gimgsensor_device, &device_attrs[i]);
if (error) {
PK_DBG("device_attrs[%d] create failed!!!\n", i);
break;
}
}
return 0;
}
通过 cdev_init 函数将 gimgsensor_file_operations 设备文件操作结构体注册内核,这样就可以让上层应用调用时使用到底层相关的 open、read、write、ioctl 函数。
imgsensor_ioctl 函数被赋值给 file_operations 结构体 gimgsensor_file_operations 的成员变量 .unlocked_ioctl 。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
static const struct file_operations gimgsensor_file_operations = {
.owner = THIS_MODULE,
.open = imgsensor_open,
.release = imgsensor_release,
.unlocked_ioctl = imgsensor_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = imgsensor_compat_ioctl
#endif
};
在 gimgsensor_file_operations 中可以发现,camera 控制函数是有 imgsensor_ioctl 实现的。
通过 imgsensor_ioctl 这个函数来提供 camera 硬件驱动的控制接口。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
static long imgsensor_ioctl(
struct file *a_pstFile,
unsigned int a_u4Command,
unsigned long a_u4Param)
{
int i4RetValue = 0;
void *pBuff = NULL;
...
switch (a_u4Command) {
case KDIMGSENSORIOC_X_GET_CONFIG_INFO:
i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);
break;
case KDIMGSENSORIOC_X_GETINFO2:
i4RetValue = adopt_CAMERA_HW_GetInfo2(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, (ACDK_SENSOR_MCLK_STRUCT *)pBuff);
break;
case KDIMGSENSORIOC_X_GET_ISP_CLK:
/*E1(High):490, (Medium):364, (low):273*/
#define ISP_CLK_LOW 273
#define ISP_CLK_MEDIUM 364
#define ISP_CLK_HIGH 490
#ifdef CONFIG_MTK_SMI_EXT
PK_DBG("KDIMGSENSORIOC_X_GET_ISP_CLK current_mmsys_clk=%d\n", current_mmsys_clk);
if (mmdvfs_get_stable_isp_clk() == MMSYS_CLK_HIGH)
*(unsigned int *)pBuff = ISP_CLK_HIGH;
else if (mmdvfs_get_stable_isp_clk() == MMSYS_CLK_MEDIUM)
*(unsigned int *)pBuff = ISP_CLK_MEDIUM;
else
*(unsigned int *)pBuff = ISP_CLK_LOW;
#else
*(unsigned int *)pBuff = ISP_CLK_HIGH;
#endif
break;
case KDIMGSENSORIOC_X_GET_CSI_CLK:
i4RetValue = imgsensor_clk_ioctrl_handler(pBuff);
break;
case KDIMGSENSORIOC_T_OPEN:
case KDIMGSENSORIOC_T_CLOSE:
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
case KDIMGSENSORIOC_X_SET_DRIVER:
case KDIMGSENSORIOC_X_GETRESOLUTION2:
case KDIMGSENSORIOC_X_GET_SOCKET_POS:
case KDIMGSENSORIOC_X_SET_GPIO:
case KDIMGSENSORIOC_X_SET_I2CBUS:
case KDIMGSENSORIOC_X_RELEASE_I2C_TRIGGER_LOCK:
case KDIMGSENSORIOC_X_SET_SHUTTER_GAIN_WAIT_DONE:
case KDIMGSENSORIOC_X_SET_CURRENT_SENSOR:
i4RetValue = 0;
break;
default:
PK_DBG("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);
PK_DBG("[CAMERA SENSOR] ioctl copy to user failed\n");
i4RetValue = -EFAULT;
goto CAMERA_HW_Ioctl_EXIT;
}
kfree(pBuff);
CAMERA_HW_Ioctl_EXIT:
return i4RetValue;
}
对 camera 硬件的初始化操作是在函数 adopt_CAMERA_HW_FeatureControl() 中实现的。
adopt_CAMERA_HW_FeatureControl 的定义
adopt_CAMERA_HW_FeatureControl 由函数 imgsensor_ioctl() 调用。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
static inline int adopt_CAMERA_HW_FeatureControl(void *pBuf)
{
...
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;
}
...
通过 cdev_init 函数将 gimgsensor_file_operations 设备文件操作结构体注册内核,这样就可以让上层应用调用时使用到底层相关的 open、read、write、ioctl 函数。
gimgsensor_file_operations 文件操作结构体的实现
imgsensor_ioctl 函数被赋值给 file_operations 结构体 gimgsensor_file_operations 的成员变量 .unlocked_ioctl 。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
static const struct file_operations gimgsensor_file_operations = {
.owner = THIS_MODULE,
.open = imgsensor_open,
.release = imgsensor_release,
.unlocked_ioctl = imgsensor_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = imgsensor_compat_ioctl
#endif
};
在 gimgsensor_file_operations 中可以发现,camera 控制函数是有 imgsensor_ioctl 实现的。
imgsensor_ioctl 的定义
通过 imgsensor_ioctl 这个函数来提供 camera 硬件驱动的控制接口。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
static long imgsensor_ioctl(
struct file *a_pstFile,
unsigned int a_u4Command,
unsigned long a_u4Param)
{
int i4RetValue = 0;
void *pBuff = NULL;
...
switch (a_u4Command) {
case KDIMGSENSORIOC_X_GET_CONFIG_INFO:
i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);
break;
case KDIMGSENSORIOC_X_GETINFO2:
i4RetValue = adopt_CAMERA_HW_GetInfo2(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, (ACDK_SENSOR_MCLK_STRUCT *)pBuff);
break;
case KDIMGSENSORIOC_X_GET_ISP_CLK:
/*E1(High):490, (Medium):364, (low):273*/
#define ISP_CLK_LOW 273
#define ISP_CLK_MEDIUM 364
#define ISP_CLK_HIGH 490
#ifdef CONFIG_MTK_SMI_EXT
PK_DBG("KDIMGSENSORIOC_X_GET_ISP_CLK current_mmsys_clk=%d\n", current_mmsys_clk);
if (mmdvfs_get_stable_isp_clk() == MMSYS_CLK_HIGH)
*(unsigned int *)pBuff = ISP_CLK_HIGH;
else if (mmdvfs_get_stable_isp_clk() == MMSYS_CLK_MEDIUM)
*(unsigned int *)pBuff = ISP_CLK_MEDIUM;
else
*(unsigned int *)pBuff = ISP_CLK_LOW;
#else
*(unsigned int *)pBuff = ISP_CLK_HIGH;
#endif
break;
case KDIMGSENSORIOC_X_GET_CSI_CLK:
i4RetValue = imgsensor_clk_ioctrl_handler(pBuff);
break;
case KDIMGSENSORIOC_T_OPEN:
case KDIMGSENSORIOC_T_CLOSE:
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
case KDIMGSENSORIOC_X_SET_DRIVER:
case KDIMGSENSORIOC_X_GETRESOLUTION2:
case KDIMGSENSORIOC_X_GET_SOCKET_POS:
case KDIMGSENSORIOC_X_SET_GPIO:
case KDIMGSENSORIOC_X_SET_I2CBUS:
case KDIMGSENSORIOC_X_RELEASE_I2C_TRIGGER_LOCK:
case KDIMGSENSORIOC_X_SET_SHUTTER_GAIN_WAIT_DONE:
case KDIMGSENSORIOC_X_SET_CURRENT_SENSOR:
i4RetValue = 0;
break;
default:
PK_DBG("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);
PK_DBG("[CAMERA SENSOR] ioctl copy to user failed\n");
i4RetValue = -EFAULT;
goto CAMERA_HW_Ioctl_EXIT;
}
kfree(pBuff);
CAMERA_HW_Ioctl_EXIT:
return i4RetValue;
}
对 camera 硬件的初始化操作是在函数 adopt_CAMERA_HW_FeatureControl() 中实现的。
adopt_CAMERA_HW_FeatureControl 的定义
adopt_CAMERA_HW_FeatureControl 由函数 imgsensor_ioctl() 调用。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
static inline int adopt_CAMERA_HW_FeatureControl(void *pBuf)
{
...
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;
}
...
imgsensor_set_driver 是在文件 imgsensor.c 中的 adopt_CAMERA_HW_FeatureControl 函数中被调用的 ,即在开机过程中,vendor 会寻找 Sensor ,并对它做些硬件初始化。
imgsensor_set_driver 的实现
imgsensor_set_driver() 在函数 adopt_CAMERA_HW_FeatureControl() 中被调用。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
int imgsensor_set_driver(struct IMGSENSOR_SENSOR *psensor)
{
u32 drv_idx = 0;
int ret = -EIO;
struct IMGSENSOR_SENSOR_INST *psensor_inst = &psensor->inst;
/* kdSensorList 中包含操作具体硬件的摄像头驱动代码 */
struct IMGSENSOR_INIT_FUNC_LIST *pSensorList = kdSensorList;
#define TOSTRING(value) #value
#define STRINGIZE(stringizedName) TOSTRING(stringizedName)
char *psensor_list_with_end = NULL;
char *sensor_kconfig = STRINGIZE(CONFIG_CUSTOM_KERNEL_IMGSENSOR);
static int orderedSearchList[MAX_NUM_OF_SUPPORT_SENSOR] = {-1};
static bool get_search_list = true;
int i = 0;
int j = 0;
char *driver_name = NULL;
const char *pDTS_sensors = NULL;
struct device_node *of_node = of_find_compatible_node(NULL, NULL,
"mediatek,camera_hw");
imgsensor_mutex_init(psensor_inst);
imgsensor_i2c_init(&psensor_inst->i2c_cfg, imgsensor_custom_config[psensor->inst.sensor_idx].i2c_dev);
imgsensor_i2c_filter_msg(&psensor_inst->i2c_cfg, true);
if (get_search_list) {
psensor_list_with_end = kmalloc(strlen(sensor_kconfig)-1, GFP_KERNEL);
}
if (psensor_list_with_end != NULL) {
for (j = 0; j < MAX_NUM_OF_SUPPORT_SENSOR; j++)
orderedSearchList[j] = -1;
memcpy(psensor_list_with_end, sensor_kconfig+1, strlen(sensor_kconfig)-2);
*(psensor_list_with_end+strlen(sensor_kconfig)-2) = '\0';
of_property_read_string(of_node, "enable-sensor", &pDTS_sensors);
PK_DBG("psensor_list_with_end %s ,pDTS_sensors %s\n",
psensor_list_with_end, pDTS_sensors == NULL ? "null" : pDTS_sensors);
driver_name = strsep(&psensor_list_with_end, " \0");
while (driver_name != NULL) {
for (j = 0; j < MAX_NUM_OF_SUPPORT_SENSOR; j++) {
if (pSensorList[j].init == NULL)
break;
else if (!strcmp(driver_name, pSensorList[j].name)) {
if (pDTS_sensors != NULL && !strstr(pDTS_sensors, driver_name))
continue;
orderedSearchList[i++] = j;
break;
}
}
driver_name = strsep(&psensor_list_with_end, " \0");
}
get_search_list = false;
kfree(psensor_list_with_end);
}
for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {
/*PK_DBG("orderedSearchList[%d]=%d\n", i, orderedSearchList[i]);*/
if (orderedSearchList[i] == -1)
continue;
drv_idx = orderedSearchList[i];
if (pSensorList[drv_idx].init) {
pSensorList[drv_idx].init(&psensor->pfunc);
if (psensor->pfunc) {
/* get sensor name */
psensor_inst->psensor_name = (char *)pSensorList[drv_idx].name;
#ifdef IMGSENSOR_LEGACY_COMPAT
psensor_inst->status.arch = psensor->pfunc->arch;
#endif
if (!imgsensor_check_is_alive(psensor)) {
PK_INFO("[imgsensor_set_driver] :[%d][%d][%s]\n",
psensor->inst.sensor_idx,
drv_idx,
psensor_inst->psensor_name);
ret = drv_idx;
break;
}
} else {
PK_PR_ERR("ERROR:NULL g_pInvokeSensorFunc[%d][%d]\n",
psensor->inst.sensor_idx,
drv_idx);
}
} else {
PK_PR_ERR("ERROR:NULL sensor list[%d]\n", drv_idx);
}
}
imgsensor_i2c_filter_msg(&psensor_inst->i2c_cfg, false);
return ret;
}
kdSensorList 在文件 imgsensor.c 中被函数 imgsensor_set_driver() 调用获取设备信息。
kdSensorList 结构体中的实现
kdSensorList 在函数 imgsensor_set_driver 中被调用, imgsensor_sensor_list.c 存放 sensor 的 id , 比如 gc2385 的驱动信息
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_sensor_list.c
struct IMGSENSOR_INIT_FUNC_LIST kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR] = {
... /* 省略部分代码 */
#if defined(GC2385_MIPI_RAW)
{GC2385_SENSOR_ID, SENSOR_DRVNAME_GC2385_MIPI_RAW, GC2385_MIPI_RAW_SensorInit},
#endif
#if defined(GC5035CMIPI_RAW)
{GC5035CMIPI_SENSOR_ID, SENSOR_DRVNAME_GC5035C_MIPI_RAW, GC5035CMIPI_RAW_SensorInit},
#endif
... /* 省略部分代码 */
/* ADD sensor driver before this line */
{0, {0}, NULL}, /* end of list */
};
GC2385_MIPI_RAW_SensorInit 的实现
GC2385_MIPI_RAW_SensorInit 在结构体 kdSensorList 中被调用。
文件路径:
./kernel-4.4/drivers/misc/mediatek/imgsnesor/src/mt6739/gc2385_mipi_raw.c
UINT32 GC2385_MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc)
{
/* To Do : Check Sensor status here */
if (pfFunc!=NULL)
*pfFunc=&sensor_func;
return ERROR_NONE;
} /* GC2385MIPI_RAW_SensorInit */
重点关注结构体 sensor_func。
sensor_func 的实现
static SENSOR_FUNCTION_STRUCT sensor_func = {
open,
get_info,
get_resolution,
feature_control,
control,
close
};
open 的实现
该函数实现了对 CMOS sensor 的初始化和注册
static kal_uint32 open(void)
{
kal_uint8 i = 0;
kal_uint8 retry = 2;
kal_uint32 sensor_id = 0;
LOG_1;
while (imgsensor_info.i2c_addr_table[i] != 0xff) {
spin_lock(&imgsensor_drv_lock);
imgsensor.i2c_write_id = imgsensor_info.i2c_addr_table[i];
spin_unlock(&imgsensor_drv_lock);
do {
/* 通过I2C协议由寄存器中读取sensor id */
sensor_id = return_sensor_id()&0xffef;
/* 根据回读的sensor id与设定值是否相等来判断是否添加了对应的sensor驱动 */
if (sensor_id == imgsensor_info.sensor_id) {
LOG_INF("i2c write id: 0x%x, sensor id: 0x%x\n",
imgsensor.i2c_write_id,sensor_id);
break;
}
LOG_INF("Read sensor id fail, write id: 0x%x, id: 0x%x\n",
imgsensor.i2c_write_id,sensor_id);
retry--;
} while(retry > 0);
i++;
if (sensor_id == imgsensor_info.sensor_id)
break;
retry = 2;
}
if (imgsensor_info.sensor_id != sensor_id)
return ERROR_SENSOR_CONNECT_FAIL;
/* initail sequence write in */
/* 这里具体对应着IC的初始化数据 */
sensor_init();
spin_lock(&imgsensor_drv_lock);
imgsensor.autoflicker_en= KAL_FALSE;
imgsensor.sensor_mode = IMGSENSOR_MODE_INIT;
imgsensor.pclk = imgsensor_info.pre.pclk;
imgsensor.frame_length = imgsensor_info.pre.framelength;
imgsensor.line_length = imgsensor_info.pre.linelength;
imgsensor.min_frame_length = imgsensor_info.pre.framelength;
imgsensor.dummy_pixel = 0;
imgsensor.dummy_line = 0;
imgsensor.ihdr_en = 0;
imgsensor.test_pattern = KAL_FALSE;
imgsensor.current_fps = imgsensor_info.pre.max_framerate;
spin_unlock(&imgsensor_drv_lock);
GC2385DuringTestPattern = KAL_FALSE;
return ERROR_NONE;
} /* open */
feature_control 的实现
static kal_uint32 feature_control(MSDK_SENSOR_FEATURE_ENUM feature_id,
UINT8 *feature_para,UINT32 *feature_para_len)
{
UINT16 *feature_return_para_16=(UINT16 *) feature_para;
UINT16 *feature_data_16=(UINT16 *) feature_para;
UINT32 *feature_return_para_32=(UINT32 *) feature_para;
UINT32 *feature_data_32=(UINT32 *) feature_para;
unsigned long long *feature_data=(unsigned long long *) feature_para;
//unsigned long long *feature_return_para=(unsigned long long *) feature_para;
SENSOR_WINSIZE_INFO_STRUCT *wininfo;
MSDK_SENSOR_REG_INFO_STRUCT *sensor_reg_data
=(MSDK_SENSOR_REG_INFO_STRUCT *) feature_para;
//printk("feature_id = %d\n", feature_id);
switch (feature_id) {
case SENSOR_FEATURE_GET_PERIOD:
*feature_return_para_16++ = imgsensor.line_length;
*feature_return_para_16 = imgsensor.frame_length;
*feature_para_len=4;
break;
case SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ:
LOG_INF("feature_Control imgsensor.pclk = %d,imgsensor.current_fps = %d\n",
imgsensor.pclk,imgsensor.current_fps);
*feature_return_para_32 = imgsensor.pclk;
*feature_para_len=4;
break;
case SENSOR_FEATURE_SET_ESHUTTER:
set_shutter(*feature_data);
break;
case SENSOR_FEATURE_SET_NIGHTMODE:
night_mode((BOOL) *feature_data);
break;
case SENSOR_FEATURE_SET_GAIN:
set_gain((UINT16) *feature_data);
break;
case SENSOR_FEATURE_SET_FLASHLIGHT:
break;
case SENSOR_FEATURE_SET_ISP_MASTER_CLOCK_FREQ:
break;
case SENSOR_FEATURE_SET_REGISTER:
write_cmos_sensor(sensor_reg_data->RegAddr, sensor_reg_data->RegData);
break;
case SENSOR_FEATURE_GET_REGISTER:
sensor_reg_data->RegData = read_cmos_sensor(sensor_reg_data->RegAddr);
break;
case SENSOR_FEATURE_GET_LENS_DRIVER_ID:
/*****************************************************
* get the lens driver ID from EEPROM or just return
* LENS_DRIVER_ID_DO_NOT_CARE
* if EEPROM does not exist in camera module.
*****************************************************/
*feature_return_para_32=LENS_DRIVER_ID_DO_NOT_CARE;
*feature_para_len=4;
break;
case SENSOR_FEATURE_SET_VIDEO_MODE:
set_video_mode(*feature_data);
break;
case SENSOR_FEATURE_CHECK_SENSOR_ID:
get_imgsensor_id(feature_return_para_32);
break;
case SENSOR_FEATURE_SET_AUTO_FLICKER_MODE:
set_auto_flicker_mode((BOOL)*feature_data_16,*(feature_data_16+1));
break;
case SENSOR_FEATURE_SET_MAX_FRAME_RATE_BY_SCENARIO:
set_max_framerate_by_scenario((MSDK_SCENARIO_ID_ENUM)*feature_data,
*(feature_data+1));
break;
case SENSOR_FEATURE_GET_DEFAULT_FRAME_RATE_BY_SCENARIO:
get_default_framerate_by_scenario((MSDK_SCENARIO_ID_ENUM)*(feature_data),
(MUINT32 *)(uintptr_t)(*(feature_data+1)));
break;
case SENSOR_FEATURE_SET_TEST_PATTERN:
set_test_pattern_mode((BOOL)*feature_data);
break;
//for factory mode auto testing
case SENSOR_FEATURE_GET_TEST_PATTERN_CHECKSUM_VALUE:
*feature_return_para_32 = imgsensor_info.checksum_value;
*feature_para_len=4;
break;
case SENSOR_FEATURE_SET_FRAMERATE:
LOG_INF("current fps :%d\n", (UINT32)*feature_data);
spin_lock(&imgsensor_drv_lock);
imgsensor.current_fps = *feature_data;
spin_unlock(&imgsensor_drv_lock);
break;
case SENSOR_FEATURE_SET_HDR:
LOG_INF("ihdr enable :%d\n", (BOOL)*feature_data);
spin_lock(&imgsensor_drv_lock);
imgsensor.ihdr_en = (BOOL)*feature_data;
spin_unlock(&imgsensor_drv_lock);
break;
case SENSOR_FEATURE_GET_CROP_INFO:
LOG_INF("SENSOR_FEATURE_GET_CROP_INFO scenarioId:%d\n",
(UINT32)*feature_data);
wininfo = (SENSOR_WINSIZE_INFO_STRUCT *)(uintptr_t)(*(feature_data+1));
switch (*feature_data_32) {
case MSDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[1],
sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
case MSDK_SCENARIO_ID_VIDEO_PREVIEW:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[2],
sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
case MSDK_SCENARIO_ID_HIGH_SPEED_VIDEO:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[3],
sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
case MSDK_SCENARIO_ID_SLIM_VIDEO:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[4],
sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
case MSDK_SCENARIO_ID_CAMERA_PREVIEW:
default:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[0],
sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
}
case SENSOR_FEATURE_SET_IHDR_SHUTTER_GAIN:
LOG_INF("SENSOR_SET_SENSOR_IHDR LE=%d, SE=%d, Gain=%d\n",(UINT16)*feature_data,(UINT16)*(feature_data+1),(UINT16)*(feature_data+2));
ihdr_write_shutter_gain((UINT16)*feature_data,(UINT16)*(feature_data+1),
(UINT16)*(feature_data+2));
break;
default:
break;
}
return ERROR_NONE;
} /* feature_control() */
imgsensor_i2c_init 的实现
imgsensor_i2c_init() 在函数 imgsensor_set_driver() 中被调用。
enum IMGSENSOR_RETURN imgsensor_i2c_init(
struct IMGSENSOR_I2C_CFG *pi2c_cfg,
enum IMGSENSOR_I2C_DEV device)
{
if (!pi2c_cfg ||
device >= IMGSENSOR_I2C_DEV_MAX_NUM ||
device < IMGSENSOR_I2C_DEV_0)
return IMGSENSOR_RETURN_ERROR;
pi2c_cfg->pinst = &gi2c.inst[device];
pi2c_cfg->pi2c_driver = &gi2c_driver[device];
mutex_init(&pi2c_cfg->i2c_mutex);
return IMGSENSOR_RETURN_SUCCESS;
}
imgsensor_hw_init 的实现
imgsensor_hw_init() 在函数 imgsensor_probe() 中被调用。
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;
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);
}
for (i = 0; i < IMGSENSOR_SENSOR_IDX_MAX_NUM; i++) {
pcust_pwr_cfg = imgsensor_custom_config;
while (pcust_pwr_cfg->sensor_idx != IMGSENSOR_SENSOR_IDX_NONE) {
if (pcust_pwr_cfg->sensor_idx == i)
break;
pcust_pwr_cfg++;
}
if (pcust_pwr_cfg->sensor_idx == IMGSENSOR_SENSOR_IDX_NONE)
continue;
psensor_pwr = &phw->sensor_pwr[i];
ppwr_info = pcust_pwr_cfg->pwr_info;
while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE) {
for (j = 0; j < IMGSENSOR_HW_ID_MAX_NUM; j++)
if (ppwr_info->id == phw->pdev[j]->id)
break;
psensor_pwr->id[ppwr_info->pin] = j;
ppwr_info++;
}
}
return IMGSENSOR_RETURN_SUCCESS;
}
imgsensor_i2c_create() 在函数 imgsensor_probe() 中被调用。 在这个函数中注册了对应的 camera 驱动。
文件路径:
./kernel-4.4/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;
}
IMGSENSOR_I2C_DEV_MAX_NUM 通过枚举进行赋值,其值为3,说明最多可以注册的摄像头驱动为3个。因为camera 驱动是挂载在 I2C总线 上,所以通过函数 i2c_add_driver() 进行注册。gi2c_driver 结构体对应一个具体 camera 设备的驱动。
gi2c_driver 结构体的实现
/* 如果使用了设备树,则CONFIG_OF会被定义 */
#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, },
{}
};
#endif
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,
}
}
上面匹配涉及到的匹配名称是在文件 imgsensor_cfg_table.h 中定义的,文件路径是:
./kernel-4.4/drivers/misc/mediatek/imgsensor/src/mt6739/camera_hw/imgsensor_cfg_table.h
/* 如果不使用设备树,会匹配这三个宏 */
#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"
这些字符串会和设备树里的 compatible 进行匹配,匹配成功了会调用对应的 probe() 函数。
设备树里的 compatible 最开始是在哪里产生的呢?
答案: 通过 dws 工具匹配出来的,通过dws 工具修改,生成文件 k39tv1_bsp.dws 。
dws 工具路径:
./vendor/mediatek/proprietary/scripts/dct/DrvGen.exe
dws 文件路径:
./kernel-4.4/drivers/misc/mediatek/dws/mt6739/k39tv1_bsp.dws
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rUs1FTbU-1584518996982)(D:\libaojian\camera\picture\dws文件.png)]
通过 DrvGen.exe 这个工具可以修改 k39tv1_bsp.dws 文件中各参数的配置。
通过上述截图可以发现,主摄像头 CAMERA_MAIN 的I2C通讯地址是 0x37 , CAMERA_SUB 的 I2C 通讯地址是 0x3C ,对应生成的文件是 cust.dtsi。
cust.dtsi 中对camera的配置
文件路径:
./out/target/product/k39tv1_bsp/obj/KERNEL_OBJ/arch/arm/boot/dts/k39tv1_bsp/cust.dtsi
&i2c2 {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
mediatek,use-open-drain;
camera_main_mtk:camera_main@37 {
compatible = "mediatek,camera_main";
reg = <0x37>;
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 。
k39tv1_bsp.dws 中对camera的配置
通过 k39tv1_bsp.dws 文件会生成对应的 DTS 文件 mt6739 和 k39tv1_bsp.dts
文件路径:
./kernel-4.4/arch/arm/boot/dts/mt6739.dts
kd_camera_hw1: kd_camera_hw1@15008000 {
compatible = "mediatek,camera_hw";
reg = <0 0x15008000 0 0x1000>; /* SENINF_ADDR */
/* Camera Common Clock Framework (CCF) */
clocks = <&topckgen CLK_TOP_CAMTG_SEL>,
<&topckgen CLK_TOP_CAMTG2_SEL>,
<&clk26m>,
<&topckgen CLK_TOP_UNIVPLL_48M_D2>,
<&topckgen CLK_TOP_UNIVPLL2_D8>,
<&topckgen CLK_TOP_UNIVPLL_D26>,
<&topckgen CLK_TOP_UNIVPLL2_D32>,
<&topckgen CLK_TOP_UNIVPLL_48M_D4>,
<&topckgen CLK_TOP_UNIVPLL_48M_D8>,
<&topckgen CLK_TOP_SENIF_SEL>,
<&topckgen CLK_TOP_SCAM_SEL>;
clock-names = "CLK_TOP_CAMTG_SEL",
"CLK_TOP_CAMTG2_SEL",
"CLK_TOP_CLK26M",
"CLK_TOP_UNIVPLL_48M_D2",
"CLK_TOP_UNIVPLL2_D8",
"CLK_TOP_UNIVPLL_D26",
"CLK_TOP_UNIVPLL2_D32",
"CLK_TOP_UNIVPLL_48M_D4",
"CLK_TOP_UNIVPLL_48M_D8",
"CLK_TOP_SENINF_SEL",
"CLK_TOP_SCAM_SEL";
};
文件路径:
./kernel-4.4/arch/arm/boot/dts/k39tv1_bsp.dts
&pio {
camera_pins_cam0_rst0: cam0@0 {
pins_cmd_dat {
pins =
output-low;/*direction out used only. output_low or high*/ };
};
camera_pins_cam0_rst1: cam0@1 {
pins_cmd_dat {
pins =
slew-rate = <1>;
output-high;
};
};
camera_pins_cam0_pnd0: cam0@2 {
pins_cmd_dat {
pins =
slew-rate = <1>;
output-low;
};
};
camera_pins_cam0_pnd1: cam0@3 {
pins_cmd_dat {
pins =
slew-rate = <1>;
output-high;
};
};
camera_pins_cam1_rst0: cam1@0 {
pins_cmd_dat {
pins =
slew-rate = <1>; /*direction 0:in, 1:out*/
output-low;/*direction out used only. output_low or high*/
};
};
camera_pins_cam1_rst1: cam1@1 {
pins_cmd_dat {
pins =
slew-rate = <1>;
output-high;
};
};
camera_pins_cam1_pnd0: cam1@2 {
pins_cmd_dat {
pins =
slew-rate = <1>;
output-low;
};
};
camera_pins_cam1_pnd1: cam1@3 {
pins_cmd_dat {
pins =
slew-rate = <1>;
output-high;
};
};
camera_pins_cam_ldo_sub_vcamd_0: cam1@vcamd0 {
pins_cmd_dat {
pins =
slew-rate = <1>;
output-low;
};
};
camera_pins_cam_ldo_sub_vcamd_1: cam1@vcamd1 {
pins_cmd_dat {
pins =
slew-rate = <1>;
output-high;
};
};
camera_pins_cam0_mclk_on: camera_pins_cam0_mclk_on {
pins_cmd_dat {
pins =
};
};
camera_pins_cam0_mclk_off: camera_pins_cam0_mclk_off {
pins_cmd_dat {
pins =
};
};
camera_pins_cam1_mclk_on: camera_pins_cam1_mclk_on {
pins_cmd_dat {
pins =
};
};
camera_pins_cam1_mclk_off: camera_pins_cam1_mclk_off {
pins_cmd_dat {
pins =
};
};
camera_pins_default: camdefault {
};
};
&kd_camera_hw1 {
pinctrl-names = "default",
"cam0_rst0", "cam0_rst1", "cam0_pnd0", "cam0_pnd1",
"cam1_rst0", "cam1_rst1", "cam1_pnd0", "cam1_pnd1",
"cam_ldo_sub_vcamd_0", "cam_ldo_sub_vcamd_1",
"cam0_mclk_on", "cam0_mclk_off",
"cam1_mclk_on", "cam1_mclk_off";
pinctrl-0 = <&camera_pins_default>;
pinctrl-1 = <&camera_pins_cam0_rst0>;
pinctrl-2 = <&camera_pins_cam0_rst1>;
pinctrl-3 = <&camera_pins_cam0_pnd0>;
pinctrl-4 = <&camera_pins_cam0_pnd1>;
pinctrl-5 = <&camera_pins_cam1_rst0>;
pinctrl-6 = <&camera_pins_cam1_rst1>;
pinctrl-7 = <&camera_pins_cam1_pnd0>;
pinctrl-8 = <&camera_pins_cam1_pnd1>;
pinctrl-9 = <&camera_pins_cam_ldo_sub_vcamd_0>;
pinctrl-10 = <&camera_pins_cam_ldo_sub_vcamd_1>;
pinctrl-11 = <&camera_pins_cam0_mclk_on>;
pinctrl-12 = <&camera_pins_cam0_mclk_off>;
pinctrl-13 = <&camera_pins_cam1_mclk_on>;
pinctrl-14 = <&camera_pins_cam1_mclk_off>;
status = "okay";
};
由上面代码可以发现有两个 kd_camera_hw1 ,这里遵循一种规则:
如果第一个 kd_camera_hw1 中定义的属性在第二个 kd_camera_hw1 中也有定义则使用第二个 kd_camera_hw1 中定义的属性;
如果第一个 kd_camera_hw1 中定义的属性在第二个 kd_camera_hw1 中没有定义,则使用第一个 kd_camera_hw1 中定义的属性;
camera驱动文件的执行流程
主要执行 kernel-4.4\drivers\misc\mediatek\imgsensor\src\common\v1 目录下的 imgsensor.c --> imgsensor_sensor_list.c 获取 camera 设备信息。 执行 imgsensor.c --> imgsensor_hw.c --> imgsensor_cfg_table.c 获取平台的上电信息。
总结
通过上述分析,我们可以看出, camera 驱动先是注册 platform 平台驱动,再注册 I2c 驱动,然后又为前后摄注册字符设备,封装底层方法 imgsensor_ioctl,上层访问底层驱动时候先是使用 setdriver 获取具体IC的驱动的入口,然后使用 checkisalive 对 sensorlist 中的 IC 进行上电,上电完成就通过 I2C 读取设备 ID ,到此为止,上层应用与底层驱动挂接完成,紧接着就是预览和拍照,不过这都是具体 IC 驱动的实现了。