MTK camera驱动浅析(2)

一.主要文件

kernel-4.19/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_hw.c

1.1 主要函数

imgsensor_hw.c共计就四个函数:

  • imgsensor_hw_init
  • imgsensor_hw_power
  • imgsensor_hw_power_sequence
  • imgsensor_hw_release_all

看名字就可以知道函数实现的功能。

1.2 上电相关的结构体

 

  • pdev[IMGSENSOR_HW_ID_MAX_NUM]这个结构体指针数组用来保存控制上电方式的设备(gpio/regulator)和控制时钟相关的设备,这个结构主要保存了一些函数指针,用来调用设备的init、set等方法。

 

  • sensor_pwr[IMGSENSOR_SENSOR_IDX_MAX_NUM]用来保存上电方式和上电顺序等信息,这是一个数组,可以保存多个sensor的信息。
    ppwr_info保存pin的信息,比如状态,延迟等,指针类型,通过加减操作移动到下一个位置,和数组差不多,能保存多个pin。
    id[]数组用来保存每个pin的上电方式。

 

二.上电流程

2.1 imgsensor_hw_init()

在probe()函数中已经初始化上电所需要的信息,用到了imgsensor_hw_init()函数:

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];//LENGTH_FOR_SNPRINTF 256
    struct device_node *of_node
            = of_find_compatible_node(NULL, NULL, "mediatek,camera_hw");

    /* 初始化pdev数组,绑定上电和时钟控制设备 */
    for (i = 0; i < IMGSENSOR_HW_ID_MAX_NUM; i++) {//IMGSENSOR_HW_ID_MAX_NUM 3
        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++) {//IMGSENSOR_SENSOR_IDX_MAX_NUM 3
        psensor_pwr = &phw->sensor_pwr[i];

        pcust_pwr_cfg = imgsensor_custom_config;
        while (pcust_pwr_cfg->sensor_idx != i &&
               pcust_pwr_cfg->sensor_idx != IMGSENSOR_SENSOR_IDX_NONE)//IMGSENSOR_SENSOR_IDX_NONE 6
            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_HW_PIN_NONE 0
            for (j = 0; j < IMGSENSOR_HW_ID_MAX_NUM; j++)//IMGSENSOR_HW_ID_MAX_NUM 3
                if (ppwr_info->id == phw->pdev[j]->id)
                    break;

            psensor_pwr->id[ppwr_info->pin] = j;
            ppwr_info++;
        }
    }

    /* 读设备树,? */
    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;
}

分析这个函数,依次做了下面这些事:

1.第一个for循环初始化了pdev数组,绑定上电和时钟控制设备。程序中hw_open数组定义如下:

enum IMGSENSOR_RETURN
(*hw_open[IMGSENSOR_HW_ID_MAX_NUM])(struct IMGSENSOR_HW_DEVICE **) = {
        imgsensor_hw_regulator_open,
        imgsensor_hw_gpio_open,
        imgsensor_hw_mclk_open
};

也就是保存了三个函数指针,调用这三个函数就可以初始化pdev数组,例如imgsensor_hw_regulator_open()函数定义如下:

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

可以看到就是绑定了一些操作函数,通过对某个pin脚调用set函数就可以完成对它的上电操作。

2.第二个for循环是为sensor设置上电顺序,前面提到的enum IMGSENSOR_HW_ID id[IMGSENSOR_HW_PIN_MAX_NUM]数组就保存了当前sensor引脚的上电方式。 

分析代码,这里有一个数组imgsensor_custom_config[ ],它的作用是配置sensor每个引脚的上电方式,在imgsensor_cfg_table.c中:

struct IMGSENSOR_HW_CFG imgsensor_custom_config[] = {
        {
                IMGSENSOR_SENSOR_IDX_MAIN,//sensor_id
                IMGSENSOR_I2C_DEV_0,//sensor_i2c dev
                {           
                        //上电方式                                      pin脚
                        {IMGSENSOR_HW_ID_MCLK, IMGSENSOR_HW_PIN_MCLK},
                        {IMGSENSOR_HW_ID_REGULATOR, IMGSENSOR_HW_PIN_AVDD},
                        {IMGSENSOR_HW_ID_REGULATOR, IMGSENSOR_HW_PIN_DOVDD},
                        {IMGSENSOR_HW_ID_GPIO,      IMGSENSOR_HW_PIN_DVDD},
                        {IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_PDN},
                        {IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_RST},
                        {IMGSENSOR_HW_ID_NONE, IMGSENSOR_HW_PIN_NONE},
                },
        },
        /* 省略部分代码 */
};

首先通过第一个while循环将sensorid和当前要操作的sensor对应起来,然后通过第二个while循环来拿到imgsensor_custom_config[]中的上电方式,将这个上电方式与一开始初始化的pdev中的设备对应起来,得到pdev对应设备的索引 j ,最后通过赋值操作把上电方式和引脚保存到enum IMGSENSOR_HW_ID id[IMGSENSOR_HW_PIN_MAX_NUM]这个数组中,匹配结果如下:

 3.最后一个for循环读设备树,读到的是sensor的名字,在后面imgsensor_hw_power()函数会进行字符串匹配验证,这里的作用以后在探究。

2.2imgsensor_hw_power()

就是用来上电的函数:

enum IMGSENSOR_RETURN imgsensor_hw_power(
        struct IMGSENSOR_HW *phw,
        struct IMGSENSOR_SENSOR *psensor,
        char *curr_sensor_name,
        enum IMGSENSOR_HW_POWER_STATUS pwr_status) {
    enum IMGSENSOR_SENSOR_IDX sensor_idx = psensor->inst.sensor_idx;
    char str_index[LENGTH_FOR_SNPRINTF];
    int ret = 0;

    pr_info(
            "sensor_idx %d, power %d curr_sensor_name %s, enable list %s\n",
            sensor_idx,
            pwr_status,
            curr_sensor_name,
            phw->enable_sensor_by_index[(uint32_t) sensor_idx] == NULL
            ? "NULL"
            : phw->enable_sensor_by_index[(uint32_t) sensor_idx]);

    if (phw->enable_sensor_by_index[(uint32_t) sensor_idx] &&
        !strstr(phw->enable_sensor_by_index[(uint32_t) sensor_idx], curr_sensor_name))
        return IMGSENSOR_RETURN_ERROR;


    ret = snprintf(str_index, sizeof(str_index), "%d", sensor_idx);
    if (ret == 0) {
        pr_info("Error! snprintf allocate 0");
        ret = IMGSENSOR_RETURN_ERROR;
        return ret;
    }

    imgsensor_hw_power_sequence(
            phw,
            sensor_idx,
            pwr_status,
            platform_power_sequence,
            str_index);

    imgsensor_hw_power_sequence(
            phw,
            sensor_idx,
            pwr_status,
            sensor_power_sequence,
            curr_sensor_name);

    return IMGSENSOR_RETURN_SUCCESS;
}

这个函数主要就调用了imgsensor_hw_power_sequence(),这里调用了两次,主要是第四个参数不同,platform_power_sequence[]配置的是平台上电顺序,sensor_power_sequence[]配置的是sensor上电顺序,它们都在imgsensor_cfg_table.c中。在某个sensor上电的时候会匹配上其中一种进行上电。

2.3 imgsensor_hw_power_sequence()

static enum IMGSENSOR_RETURN imgsensor_hw_power_sequence(
        struct IMGSENSOR_HW *phw,
        enum IMGSENSOR_SENSOR_IDX sensor_idx,
        enum IMGSENSOR_HW_POWER_STATUS pwr_status,
        struct IMGSENSOR_HW_POWER_SEQ *ppower_sequence,
        char *pcurr_idx) {
    struct IMGSENSOR_HW_SENSOR_POWER *psensor_pwr =
            &phw->sensor_pwr[sensor_idx];

    struct IMGSENSOR_HW_POWER_SEQ *ppwr_seq = ppower_sequence;
    struct IMGSENSOR_HW_POWER_INFO *ppwr_info;
    struct IMGSENSOR_HW_DEVICE *pdev;
    int pin_cnt = 0;

    /* 匹配上电的方式,是platform还是sensor */
    while (ppwr_seq < ppower_sequence + IMGSENSOR_HW_SENSOR_MAX_NUM &&
           ppwr_seq->name != NULL) {
        if (!strcmp(ppwr_seq->name, PLATFORM_POWER_SEQ_NAME)) {
            if (sensor_idx == ppwr_seq->_idx)
                break;
        } else {
            if (!strcmp(ppwr_seq->name, pcurr_idx))
                break;
        }
        ppwr_seq++;
    }

    if (ppwr_seq->name == NULL) {
        return IMGSENSOR_RETURN_ERROR;
    }

    ppwr_info = ppwr_seq->pwr_info;

    /* 依次为pin上电 */
    while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE &&
           ppwr_info < ppwr_seq->pwr_info + IMGSENSOR_HW_POWER_INFO_MAX) {

        if (pwr_status == IMGSENSOR_HW_POWER_STATUS_ON &&
            ppwr_info->pin != IMGSENSOR_HW_PIN_UNDEF) {
            /* 匹配上电的设备,是gpio还是regulator等等 */
            pdev = phw->pdev[psensor_pwr->id[ppwr_info->pin]];

            if (pdev->set != NULL)
                /* 调用设备的set()进行上电 */
                pdev->set(
                        pdev->pinstance,
                        sensor_idx,
                        ppwr_info->pin,
                        ppwr_info->pin_state_on);

            mdelay(ppwr_info->pin_on_delay);
        }

        ppwr_info++;
        pin_cnt++;
    }
    
    /* 下电方式类似 */
    if (pwr_status == IMGSENSOR_HW_POWER_STATUS_OFF) {
        while (pin_cnt) {
            ppwr_info--;
            pin_cnt--;

            if (ppwr_info->pin != IMGSENSOR_HW_PIN_UNDEF) {
                pdev =
                        phw->pdev[psensor_pwr->id[ppwr_info->pin]];
                mdelay(ppwr_info->pin_on_delay);

                if (pdev->set != NULL)
                    pdev->set(
                            pdev->pinstance,
                            sensor_idx,
                            ppwr_info->pin,
                            ppwr_info->pin_state_off);
            }
        }
    }

    /* wait for power stable */
    if (pwr_status == IMGSENSOR_HW_POWER_STATUS_ON)
        mdelay(5);
    return IMGSENSOR_RETURN_SUCCESS;
}

这里匹配上电的设备就用到了上面那个id[]数组,通过pin的序号拿到其上电所需要的对应的设备,然后set即可完成上电。

暂时写到这里,别的后面在写,希望大家提出意见,共同学习。

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: MTK平台上的camera驱动教学课程旨在教授学员有关MTK平台上如何编写、安装和调试camera驱动程序的知识和技能。在这门课程中,学员将学习如何使用MTK平台提供的相应工具和接口来开发和优化camera驱动,以实现更好的图像质量和性能。 课程的内容包括以下几个方面: 1. 理论知识:学员将了解摄像头驱动的基本原理和工作原理,包括硬件架构、设备驱动接口和底层算法等。 2. 驱动开发环境搭建:学员将学习如何在MTK平台上搭建合适的开发环境,包括操作系统、编译器和调试工具等。 3. 驱动编写:学员将学习如何编写MTK平台上的camera驱动程序,包括设备初始化、图像采集和处理等功能的实现。 4. 驱动安装与调试:学员将学习如何将开发好的驱动程序安装到MTK平台上,并进行调试和优化,以确保驱动的稳定性和性能。 5. 实践项目:学员将完成一个实际的项目,如编写一个简单的camera应用程序或实现某种特定的图像处理算法,以应用所学知识并提升实践能力。 通过这门课程,学员将掌握MTK平台上camera驱动开发的基本技能,能够独立完成camera驱动的编写、安装和调试工作,并具备进一步深入研究和优化的能力。这对于从事手机软件开发、图像处理等领域的工程师和研究人员来说,将是一门非常实用和重要的课程。 ### 回答2: MTK平台的Camera驱动教学课程是针对使用MTK芯片的开发人员设计的一门课程。该课程旨在教授学员有关MTK平台中Camera驱动的基础知识、开发技巧和调试方法。 首先,课程将介绍MTK平台和其特点,帮助学员了解MTK芯片及其应用领域。接下来,课程将重点讲解Camera驱动的原理和工作机制,涵盖Camera传感器的工作原理、图像采集和处理流程等方面的知识。 课程还将介绍Camera驱动开发环境和工具,如MTK平台上的Camera HAL层和相应的调试工具。学员将学会如何配置和编译Camera驱动,以及如何使用调试工具进行驱动的调试和性能优化。 除了理论知识的讲解,课程还将通过实例演示和实践操作帮助学员掌握Camera驱动开发技巧。学员将有机会参与实际的Camera驱动开发项目,通过实践来加深对课程知识的理解和应用能力。 总结起来,MTK平台的Camera驱动教学课程旨在提供一套系统化的学习资源,帮助学员全面了解和掌握MTK平台上的Camera驱动开发。通过学习这门课程,学员将能够独立进行MTK平台上Camera驱动开发和调试工作,从而为MTK芯片应用的开发和优化提供支持。 ### 回答3: MTK平台CMOS摄像头驱动开发是一门与软硬件结合紧密的技术课程。首先,学习者需要熟悉MTK平台的基本知识,包括芯片结构、嵌入式系统以及Linux操作系统的基本原理。其次,学习者需要了解摄像头工作原理和常用的摄像头传感器类型,例如CMOS和CCD传感器。在掌握这些基础知识后,学习者可以开始学习MTK平台上的摄像头驱动开发。 在开发摄像头驱动时,学习者需要掌握如何通过MTK平台提供的驱动接口与摄像头硬件进行通信。这包括配置摄像头的分辨率、帧率、曝光时间以及白平衡等参数。此外,还需要了解如何处理摄像头的数据传输和处理,例如图像的压缩、旋转、镜像等操作。 在学习过程中,学习者可以通过阅读相关的文档和资料,参考MTK平台提供的示例代码来加深理解。同时,实际动手开发和调试也是非常重要的,可以通过连接MTK平台开发板和摄像头来调试和验证自己的驱动代码。学习者还可以通过与其他开发者交流和分享经验,提升自己的开发能力。 总之,MTK平台摄像头驱动开发是一门需要结合软硬件知识的综合性课程,通过学习掌握相关的理论知识和实践经验,可以帮助学习者深入了解摄像头驱动的工作原理和开发流程,提高自己的技术水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值