MTK Camera驅動上電與初始化 一、概序 二、上電相關的結構體之間的聯繫 三、系統初始化: 5、imgsensor_i2c_create I2C設備初始化:

和你一起終身學習,這裏是程序員 Android

經典好文推薦,通過閱讀本文,您將收穫以下知識點:

一、概序

這篇主要介紹紅框部分的內容:


imgsensor起到承上啓下的作用,在系統起來時會創建整個camera驅動運行的環境,其中主要的文件和函數如下框圖所示,先通過platform_driver_register函數註冊platform設備,在匹配成功後會調用probe函數進行初始相關的設備:

其中camera的三路電壓的上電方式可以通過GPIO來控制,也可以通過PMIC(REGULATOR)的方式來進行控制,在imgsensor_hw中通過不同的pdev信息,調用不同的set函數。涉及的文件路徑:

kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c
kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_hw.c
kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6765/camera_hw/regulator/regulator.c
kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6765/camera_hw/gpio/gpio.c

二、上電相關的結構體之間的聯繫

(1) IMGSENSOR_HW結構體:

IMGSENSOR_HW結構體包含了pdev(gpio/regulator)的設備結構體和上電時序相關的結構體:

(2) 上電時序控制相關:

上電方式控制: GPIO? REGULATOR?

上電時序控制結構體:


三、系統初始化:

1、設備加載:

imgsensor和其他的驅動模塊相同,也是通過module_init來初始化模塊,在init中註冊platform總線驅動,從而需要對應的platform_driver結構體信息:

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

gimgsensor_of_device_id的信息在dtsmatch上以後回調執行到對應的probe函數,probe中主要註冊了sensor drv的字符設備和初始化imgsensor的硬件信息(時鐘及上電):

static int imgsensor_probe(struct platform_device *pdev)
{
    /* Register char driver */
    imgsensor_driver_register();

    gpimgsensor_hw_platform_device = pdev;

    imgsensor_clk_init(&pgimgsensor->clk);
    imgsensor_hw_init(&pgimgsensor->hw);
    imgsensor_i2c_create();
    imgsensor_proc_init();

    atomic_set(&pgimgsensor->imgsensor_open_cnt, 0);
    return 0;
}

2、imgsensor_driver_register創建字符設備

//字符設備的file_operation結構體
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
};

static inline int imgsensor_driver_register(void){
    //分配一個設備號和nanme
    alloc_chrdev_region(&dev_no, 0, 1, IMGSENSOR_DEV_NAME)

     /* Allocate driver */
    gpimgsensor_cdev = cdev_alloc();

    /* Attatch file operation. */
    cdev_init(gpimgsensor_cdev, &gimgsensor_file_operations);

    /* Add to system */
    cdev_add(gpimgsensor_cdev, dev_no, 1);

    gpimgsensor_class = class_create(THIS_MODULE, "sensordrv");

    device_create(gpimgsensor_class, NULL, dev_no, NULL, IMGSENSOR_DEV_NAME);
}

3、imgsensor_clk_init 時鐘初始化:

enum IMGSENSOR_RETURN imgsensor_clk_init(struct IMGSENSOR_CLK *pclk)
{
    int i;
    struct platform_device *pplatform_dev = gpimgsensor_hw_platform_device;

    /* get all possible using clocks */
    for (i = 0; i < IMGSENSOR_CCF_MAX_NUM; i++)
        pclk->imgsensor_ccf[i] =
            devm_clk_get(&pplatform_dev->dev, gimgsensor_mclk_name[i]);

    return IMGSENSOR_RETURN_SUCCESS;
}

4、imgsensor_hw_init電壓初始化:

(1) 依次調用GPIO/REGULATOR/MCLKinit接口;

(2) 解析出imgsensor_custom_config,獲取到對應sensor的對應管腳(DVDD/AVDD...)的上電方式(GPIO/REGULATOR);

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");
    //依次調用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對應{IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_AVDD}
        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設備初始化:

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

6、具體類型的上電介紹(以pmic控制的regulator方式爲例)

前面imgsensor_hw_init中有去調用imgsensor_hw_regulator_openregulator_init

(1) 傳入對應的設備的device結構體

static struct IMGSENSOR_HW_DEVICE device = {
    .pinstance = (void *)&reg_instance,
    .init      = regulator_init,//開機初始化時調用
    .set       = regulator_set,//在上電設置電壓時會調用
    .release   = regulator_release,
    .id        = IMGSENSOR_HW_ID_REGULATOR
};

enum IMGSENSOR_RETURN imgsensor_hw_regulator_open(
    struct IMGSENSOR_HW_DEVICE **pdevice)
{
    *pdevice = &device;
    return IMGSENSOR_RETURN_SUCCESS;
}

(2) 調用對應的init進行初始化

因爲MTK平臺的PMIC上電是通過統一的REGULATOR進行統一管理的,每一種上電方式需要申請對應typeregulator控制的結構體,纔可以來進行設置:

enum REGULATOR_TYPE {
    REGULATOR_TYPE_VCAMA,
    REGULATOR_TYPE_VCAMD,
    REGULATOR_TYPE_VCAMIO,
    REGULATOR_TYPE_MAX_NUM
};

static enum IMGSENSOR_RETURN regulator_init(void *pinstance)
{
    struct REGULATOR *preg = (struct REGULATOR *)pinstance;
    struct device            *pdevice;
    struct device_node       *pof_node;
    int j, i;
    char str_regulator_name[LENGTH_FOR_SNPRINTF];

    pdevice  = gimgsensor_device;

    for (j = IMGSENSOR_SENSOR_IDX_MIN_NUM;j < IMGSENSOR_SENSOR_IDX_MAX_NUM;j++) {
        for (i = 0; i < REGULATOR_TYPE_MAX_NUM; i++) {
            snprintf(str_regulator_name,
                sizeof(str_regulator_name),
                "cam%d_%s", j,
                regulator_control[i].pregulator_type);
            preg->pregulator[j][i] =
                regulator_get(pdevice, str_regulator_name);

            if (preg->pregulator[j][i] == NULL)
                pr_err("regulator[%d][%d]  %s fail!\n",
                    j, i, str_regulator_name);

            atomic_set(&preg->enable_cnt[j][i], 0);
        }
    }
    pdevice->of_node = pof_node;
    imgsensor_oc_init();
    return IMGSENSOR_RETURN_SUCCESS;
}

到這裏imgsensor部分的內容,就還有對上(hal層)承接的ioctl相關的內容沒有介紹,這部分的內容會在後續的整個系統調用流程中進行梳理。

至此,本篇已結束。轉載網絡的文章,小編覺得很優秀,歡迎點擊閱讀原文,支持原創作者,如有侵權,懇請聯繫小編刪除,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章