MTK Camera驱动代码分析

一、Camera调用过程:


image.png

imgsensor起到承上启下的作用,在系统起来时会创建整个camera驱动运行的环境,其中主要的文件和函数如下框图所示,先设备挂载时会调用注册platform设备platform_driver_register,在匹配成功后会调用probe函数进行初始相关的设备:


image.png

其中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 id  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/

原文链接:https://blog.csdn.net/qq_40405527/article/details/108767345

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容