MT6739的Android9.0 Camera kernel 驱动

文章目录
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驱动文件的执行流程
总结
 

Kernel 层驱动的实现


camera 整个驱动框架分为三个部分: hal层 逻辑调用,kernel层 的通用驱动 sensorlist.c 和 具体IC 的驱动, 比如 gc2385_mipi_raw.c ,kernel 起来后不会直接去访问 硬件sensor ,而是会注册相关的驱动,之后 Android系统 起来后会启动相关的服务如: camera_service ,在 camera 服务中会直接去访问 hal层 , kernel驱动 ,进而操作 camera 。这里只分析 kernel层中 camera驱动的实现。
 

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 为拍照做准备,然后执行下电操作。

Camera 驱动的文件结构


参考 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
 

FileDecription(英文)Decription(中文)
imgsensor.cSensor driver adapter and driver entry pointsensor 驱动适配器和驱动入口函数的实现
imgsensor_hw.cSensor power controlsensor 电源控制的实现
imgsensor_i2c.cI2C read/writeI2C 读写函数的实现
imgsensor_proc.cPROC related partproc文件系统相关部分的实现
imgsensor_sensor_list.cList of all sensors init function包含所有sensor初始化函数的表单
imgsensor_legacy.cLegacy part of sensor. Mainly I2c related APIsensor的旧的接口部分。主要是与I2c相关API
imgsensor_cfg_table.cSensor Power and I2C configruation tablesensor电源和I2C的配置表

Camera 驱动初始化流程

Camera 入口函数 imgsensor_init

文件路径:

./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;
}
 

注册的平台驱动结构体 gimgsensor_platform_driver

#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 驱动。

 

imgsensor_probe 探测函数的实现

文件路径:

./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 驱动。

imgsensor_driver_register 注册函数的实现


imgsensor_driver_register 由函数 imgsensor_probe() 调用,在 imgsensor_driver_register() 函数中实现了 camera 驱动的主次设备号创建,注册对应的设备文件操作结构体 gimgsensor_file_operations 。

文件路径:

./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 函数。

 

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;
    }
    ...

通过 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_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 = <PINMUX_GPIO29__FUNC_GPIO29>;                                                     slew-rate = <1>; /*direction 0:in, 1:out*/
                 output-low;/*direction out used only. output_low or high*/                            };
        };
        camera_pins_cam0_rst1: cam0@1 {
            pins_cmd_dat {
                pins = <PINMUX_GPIO29__FUNC_GPIO29>;
                slew-rate = <1>;
                output-high;
            };
        };
        camera_pins_cam0_pnd0: cam0@2 {
            pins_cmd_dat {
                pins = <PINMUX_GPIO30__FUNC_GPIO30>;
                slew-rate = <1>;
                output-low;
            };
        };
        camera_pins_cam0_pnd1: cam0@3 {
            pins_cmd_dat {
                pins = <PINMUX_GPIO30__FUNC_GPIO30>;
                slew-rate = <1>;
                output-high;
            };
        };
        camera_pins_cam1_rst0: cam1@0 {
            pins_cmd_dat {
                pins = <PINMUX_GPIO22__FUNC_GPIO22>;
                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 = <PINMUX_GPIO22__FUNC_GPIO22>;
                slew-rate = <1>;
                output-high;
            };
        };
        camera_pins_cam1_pnd0: cam1@2 {
            pins_cmd_dat {
                pins = <PINMUX_GPIO23__FUNC_GPIO23>;
                slew-rate = <1>;
                output-low;
            };
        };
        camera_pins_cam1_pnd1: cam1@3 {
            pins_cmd_dat {
                pins = <PINMUX_GPIO23__FUNC_GPIO23>;
                slew-rate = <1>;
                output-high;
            };
        };
        camera_pins_cam_ldo_sub_vcamd_0: cam1@vcamd0 {
            pins_cmd_dat {
                pins = <PINMUX_GPIO9__FUNC_GPIO9>;
                slew-rate = <1>;
                output-low;
            };
        };
        camera_pins_cam_ldo_sub_vcamd_1: cam1@vcamd1 {
            pins_cmd_dat {
                pins = <PINMUX_GPIO9__FUNC_GPIO9>;
                slew-rate = <1>;
                output-high;
            };
        };
        camera_pins_cam0_mclk_on: camera_pins_cam0_mclk_on {
            pins_cmd_dat {
                pins = <PINMUX_GPIO126__FUNC_CMMCLK0>;
            };
        };
        camera_pins_cam0_mclk_off: camera_pins_cam0_mclk_off {
            pins_cmd_dat {
                pins = <PINMUX_GPIO126__FUNC_GPIO126>;
            };
        };
        camera_pins_cam1_mclk_on: camera_pins_cam1_mclk_on {
            pins_cmd_dat {
                pins = <PINMUX_GPIO126__FUNC_CMMCLK0>;
            };
        };
        camera_pins_cam1_mclk_off: camera_pins_cam1_mclk_off {
            pins_cmd_dat {
                pins = <PINMUX_GPIO126__FUNC_GPIO126>;
            };
        };
        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 驱动的实现了。
 

 

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值