Camera 驱动加载

一、概述

  一般在 Linux 设备驱动模型中,我们只需要关心总线、设备、驱动这三个实体。总线会充当红娘对加载于其上的设备与驱动进行配对,对于 Camera 模块也不例外,下面从总线、设备、驱动的角度来分析 Camera 模块驱动的注册、匹配与加载过程。本文以MTK平台为例。

二、驱动加载过程

  驱动加载都是以module_init(XXX)开始,如下所示:

module_init(CAMERA_HW_i2C_init);

1、入口函数

/*=======================================================
  * CAMERA_HW_i2C_init()
  *======================================================*/
static int __init CAMERA_HW_i2C_init(void)
{
    PK_DBG("[camerahw_probe] start\n");
#ifndef CONFIG_OF
    int ret = 0;
    //注册平台总线的设备
    ret = platform_device_register(&camerahw_platform_device);
    if (ret) {
        PK_ERR("[camerahw_probe] platform_device_register fail\n");
        return ret;
    }

    ret = platform_device_register(&camerahw2_platform_device);
    if (ret) {
        PK_ERR("[camerahw2_probe] platform_device_register fail\n");
        return ret;
    }
#endif
    //注册平台总线的驱动
    if (platform_driver_register(&g_stCAMERA_HW_Driver)) {
        PK_ERR("failed to register CAMERA_HW driver\n");
        return -ENODEV;
    }
    if (platform_driver_register(&g_stCAMERA_HW_Driver2)) {
        PK_ERR("failed to register CAMERA_HW driver\n");
        return -ENODEV;
    }
    /* FIX-ME: linux-3.10 procfs API changed */
//在proc下创建driver/camsensor这个节点,用于前置摄像头进行adb效果调试
    proc_create("driver/camsensor", 0, NULL, &fcamera_proc_fops);
//在proc下创建driver/camsensor2这个节点,用于后置摄像头进行adb效果调试
    proc_create("driver/camsensor2", 0, NULL, &fcamera_proc_fops2);
    proc_create("driver/camsensor3", 0, NULL, &fcamera_proc_fops3);

    /* Camera information */
    memset(mtk_ccm_name, 0, camera_info_size);
    proc_create(PROC_CAMERA_INFO, 0, NULL, &fcamera_proc_fops1);
    …………
    return 0;
}

  CAMERA_HW_i2C_init函数主要做的是首先要进行I2C总线板极设备的注册及初始化工作,然后注册platform总线的driver,通过g_stCAMERA_HW_Driver结构体里面的name来与device进行匹配。同时,在函数里面还在proc目录下创建了driver/camsensor和driver/camsensor2两个节点,这样做主要是方便sensor的IC原厂FAE利用adb进行效果调试的。

2、g_stCAMERA_HW_Driver结构体

static struct platform_driver g_stCAMERA_HW_Driver = {
    .probe      = CAMERA_HW_probe,//匹配成功则调用
    .remove     = CAMERA_HW_remove,
    .suspend    = CAMERA_HW_suspend,//休眠时调用
    .resume     = CAMERA_HW_resume,//唤醒时调用
    .driver     = {
        .name   = "image_sensor",
        .owner  = THIS_MODULE,
#ifdef CONFIG_OF
        .of_match_table = CAMERA_HW_of_ids,
#endif
    }
};

  g_stCAMERA_HW_Driver结构体中主要有probe、remove、suspend等接口的实现,尤其是probe接口为设备注册的匹配函数,在driver与device匹配后就会调用 .probe = CAMERA_HW_probe进入CAMERA_HW_probe函数。

3、探测函数CAMERA_HW_probe

static int CAMERA_HW_probe(struct platform_device *pdev)
{

#if !defined(CONFIG_MTK_CLKMGR)
    Get_ccf_clk(pdev);
#endif

#if !defined(CONFIG_MTK_LEGACY)/*GPIO Pin control*/
    mtkcam_gpio_init(pdev);//GPIO管脚通过pinctl进行初始化
#endif
    //注册I2C驱动
    return i2c_add_driver(&CAMERA_HW_i2c_driver);
}

4、CAMERA_HW_i2c_driver结构体

struct i2c_driver CAMERA_HW_i2c_driver = {
    .probe = CAMERA_HW_i2c_probe,
    .remove = CAMERA_HW_i2c_remove,
    .driver = {
        .name = CAMERA_HW_DRVNAME1,
        .owner = THIS_MODULE,

#ifdef CONFIG_OF
        .of_match_table = CAMERA_HW_i2c_of_ids,
#endif
    },
    .id_table = CAMERA_HW_i2c_id,
};

  sensor驱动最终还是会注册I2C设备,I2C总线的注册其实跟platform总线的注册大致相同,注册完I2C driver后就会进行匹配,匹配成功后系统就会调用CAMERA_HW_i2c_driver 结构体里面的 .probe = CAMERA_HW_i2c_probe。

5、探测函数CAMERA_HW_probe

static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int i4RetValue = 0;
    PK_DBG("[CAMERA_HW] Attach I2C\n");

    /* get sensor i2c client */
    spin_lock(&kdsensor_drv_lock);
    g_pstI2Cclient = client;
    /* set I2C clock rate */
    g_pstI2Cclient->timing = 100;/* 100k */
    g_pstI2Cclient->ext_flag &= ~I2C_POLLING_FLAG; /* No I2C polling busy waiting */

    spin_unlock(&kdsensor_drv_lock);

    /* Register char driver */
    i4RetValue = RegisterCAMERA_HWCharDrv();//注册一个字符设备

    if (i4RetValue) {
        PK_ERR("[CAMERA_HW] register char device failed!\n");
        return i4RetValue;
    }

    /* spin_lock_init(&g_CamHWLock); */
#if !defined(CONFIG_MTK_LEGACY)
    Get_Cam_Regulator();//获取电源
#endif

    PK_DBG("[CAMERA_HW] Attached!!\n");
    return 0;
}

6、字符设备注册

static inline int RegisterCAMERA_HWCharDrv(void)
{

#if CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO
    // 动态分配一个字符设备
    if (alloc_chrdev_region(&g_CAMERA_HWdevno, 0, 1, CAMERA_HW_DRVNAME1)) {
        PK_DBG("[CAMERA SENSOR] Allocate device no failed\n");

        return -EAGAIN;
    }
#else
    // 静态分配一个字符设备
    if (register_chrdev_region(g_CAMERA_HWdevno , 1 , CAMERA_HW_DRVNAME1)) {
        PK_DBG("[CAMERA SENSOR] Register device no failed\n");

        return -EAGAIN;
    }
#endif

    /* Allocate driver */
    g_pCAMERA_HW_CharDrv = cdev_alloc(); // 申请一个cdev结构体

    if (NULL == g_pCAMERA_HW_CharDrv) {
        unregister_chrdev_region(g_CAMERA_HWdevno, 1);

        PK_DBG("[CAMERA SENSOR] Allocate mem for kobject failed\n");

        return -ENOMEM;
    }

    /* Attatch file operation. */
    //关联到file_operation进入字符设备
    cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops);

    g_pCAMERA_HW_CharDrv->owner = THIS_MODULE;

    /* Add to system */
    //将我们分配的字符设备,attach上file_operation添加到system
    if (cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1)) {
        PK_DBG("[mt6516_IDP] Attatch file operation failed\n");

        unregister_chrdev_region(g_CAMERA_HWdevno, 1);

        return -EAGAIN;
    }
    //创建一个sensordrv类
    sensor_class = class_create(THIS_MODULE, "sensordrv");
    if (IS_ERR(sensor_class)) {
        int ret = PTR_ERR(sensor_class);
        PK_DBG("Unable to create class, err = %d\n", ret);
        return ret;
    }

    sensor_device = device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1);

    return 0;
}

  camera的模块驱动为字符驱动,所以RegisterCAMERA_HWCharDrv函数主要是对camera_image进行字符驱动注册,代码开始先判断是否定义了CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO变量来判断动态还是静态分配一个字符设备,然后通过cdev_alloc申请了一个cdev结构体后,通过cdev_init将g_stCAMERA_HW_fops关联到字符设备,g_stCAMERA_HW_fops是HAL层与内核驱动进行交互的渠道。然后就是将我们分配的字符设备,attach上file_operation添加到system,最后在sys/class目录下创建一个sensordrv类。

三、总结

  到目前为止,我们大致了解camera驱动模块大致的加载过程,值得注意的是注册字符设备时,关联着结构体g_stCAMERA_HW_fops;下一篇将围绕这个结构体,一起分析HAL层与驱动的交互过程

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值