MTK平台camera驱动架构分析

MTK平台camera驱动架构分析MTK6580Andro android8 1 版本 camera 驱动分析 CAMERA 驱动整个框架分为 三个部分 hal 部分逻辑调用 kernel 层的通用驱动 sensorlist c 和具体 IC 的驱动 xxxx mipi raw c 这里主要介绍 kernel 部分和 HAL 层部分 camera 开机流程 poweron 上电开机 然后通过 i2c 地址匹配 i2c 通讯 rest 和 powerdown 上电

景物通过镜头(LENS)生成的光学图像投射到图像传感器(Sensor)表面上,然后转为模拟的电信号,经过 A/D(模数转换)转换后变为数字图像信号,再送到数字信号处理芯片(DSP)中加工处理,再通过 IO 接口传输到 CPU 中处理,通过 LCD 就可以看到图像了。

2、Camera 常见的数据输出格式:

CAMERA驱动整个框架分为:三个部分hal部分逻辑调用,kernel层的通用驱动sensorlist.c 和具体IC的驱动xxxx_mipi_raw.c

这里主要介绍kernel部分和HAL层部分。

camera开机流程:poweron上电开机,然后通过i2c地址匹配i2c通讯,rest和powerdown上电(上电代码在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为拍照做准备,然后执行下电操作。

总结:

HAL层运行Search sensor这个线程

HAL层遍历sensorlist列表并挂载HAL层性能3A等一些参数获取的接口

HAL层下达setDriver的cmd,并下传正在遍历的sensorlist列表中的ID

Driver层根据这个ID,挂载Driver层sensorlist中对应的Sensorlist中对应的Sensor和具体Sensor底层操作接口(例如Sub_GC2355_MIPI_RAW_SensorInit)

HAL层对正确遍历的sensor下达check ID的指令

Driver层为对应sensor上电,通过I2C读取预存在寄存器中的sensor id

比较读取ID结果(配置的和读到的ID),不匹配,return error,继续遍历

匹配,HAL层下达其他指令收集sensor信息

最后sensor下电

一、MT6580 平台 Camera 驱动整体框架

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

二、 Camera 驱动的具体实现

从vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6580/hal/sensor/imgsensor_drv.cpp中的impSearchSensor()函数说起。

———————–HAL 层部分—————————-

GetSensorInitFuncList(&m_pstSensorInitFunc);

LOG_MSG(“SENSOR search start \n”);

获取sensor列表后,紧接着通过:

  1. 针对前后摄注册platform 设备和驱动

主摄平台驱动的定义:

副摄平台驱动的定义:

主副摄cam在dts中(注册设备)定义设备信息:

当内核启动后,会解析dts编译生成的dtb文件,注册里面定义的device,如果和驱动中定义compatible字段一致,则挂载启动。上面注册了两个platform 驱动g_stCAMERA_HW_Driver,g_stCAMERA_HW_Driver2,

如果compatible匹配成功会调用各自的probe函数CAMERA_HW_probe,CAMERA_HW_probe2

  1. 平台probe 函数的实现
    主摄probe,CAMERA_HW_probe的实现如下:
    static int CAMERA_HW_probe(struct platform_device *pdev)
    {

    #if !defined(CONFIG_MTK_LEGACY)
    mtkcam_gpio_init(pdev);
    mtkcam_pin_mux_init(pdev);
    #endif
    return i2c_add_driver(&CAMERA_HW_i2c_driver);
    }
    副摄probe,CAMERA_HW_probe的实现如下:
    static int CAMERA_HW_probe2(struct platform_device *pdev)
    {

    return i2c_add_driver(&CAMERA_HW_i2c_driver2);
    }
    从上可以看出在main/sub 的平台probe中分别注册了各自的i2c驱动CAMERA_HW_i2c_driver,
    CAMERA_HW_i2c_driver2,main sensor 的CAMERA_HW_i2c_driver定义如下:
    #ifdef CONFIG_OF
    static const struct of_device_id CAMERA_HW_i2c_of_ids[] = {

    { .compatible = “mediatek,camera_main”, },
    {}
    };
    #endif
    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,
    };
    sub sensor 的CAMERA_HW_i2c_driver定义如下:
    #ifdef CONFIG_OF
    static const struct of_device_id CAMERA_HW2_i2c_driver_of_ids[] = {

    { .compatible = “mediatek,camera_sub”, },
    {}
    };
    #endif
    struct i2c_driver CAMERA_HW_i2c_driver2 = {

    .probe = CAMERA_HW_i2c_probe2,
    .remove = CAMERA_HW_i2c_remove2,
    .driver = {

    .name = CAMERA_HW_DRVNAME2,
    .owner = THIS_MODULE,
    #ifdef CONFIG_OF
    .of_match_table = CAMERA_HW2_i2c_driver_of_ids,
    #endif
    },
    .id_table = CAMERA_HW_i2c_id2,
    };




















































  2. I2c probe的实现
    从上可以看出main/sub sensor在各自的平台probe中,注册了i2c_driver,当各自的i2c_driver和设备匹配
    匹配规则:
    (1)当在dts有创建设备节点注册设备的时候:当i2c_driver和i2c_device的.compatible字段一致,就会执行i2c_driver里面的probe入口函数
    (2)当调用i2c_register_board_info注册i2c设备时,当i2c_driver驱动中ids_table中name字段匹配i2c设备中的name就可调用i2c_driver驱动中的probe函数。
    成功后,会调用各自的i2c_probe函数。




main sensor 的i2c_probe函数

sub sensor 的i2c_probe函数

/* Attatch file operation. /
cdev_init(g_pCAMERA_HW_CharDrv2, &g_stCAMERA_HW_fops0);//初始化字符设备
/

Add to system */
cdev_add(g_pCAMERA_HW_CharDrv2, g_CAMERA_HWdevno2, 1));//注册到内核
//创建目录 /sys/class/sensordrv2/
sensor2_class = class_create(THIS_MODULE, “sensordrv2”);
//创建目录/sys/class/sensordrv2/kd_camera_hw_bus2
sensor_device2 = device_create(sensor2_class, NULL, g_CAMERA_HWdevno2, NULL, CAMERA_HW_DRVNAME2);

return 0;
}







main/sub 创建各自的字符设备过程中绑定各自的 fops(fops是上层操作底层驱动的函数接口),g_stCAMERA_HW_fops和g_stCAMERA_HW_fops0

};

};

从上可以看出各自的fops指定了相同的Ioctl函数,意味着上层操作main/sub sensor 只需要对应一个底层的ioctl即可,至于sensor的区分可以借助idx,后面会讲到

/*

  • CAMERA_HW_Ioctl
    /

}

这里ioctl和上层一一对应,上层要控制camera 只需要传入相应的cmd和data即可。

——————- HAL 调用Kernel 层驱动的逻辑 ————————-

前面介绍了HAL层调用ioctl 和 kernel层注册驱动,接下来继续分析,HAL层调用后驱动具体的实现流程。

  1. ioctl 底层的实现

4.1 先来看ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] );

当 KDIMGSENSORIOC_X_SET_DRIVER 被传下时,会调用 kernel 层的 kdSetDriver 接口

kdGetSensorInitFuncList(&pSensorList)) //获得sensor初始化列表

for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {

UINT32 GC5025MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT pfFunc)
{

/

To Do : Check Sensor status here */
if (pfFunc!=NULL)
pfFunc=&sensor_func;
return ERROR_NONE;
} /

GC5025MIPI_RAW_SensorInit */

从中可以看出,gc5025的Init函数地址传给了pfFunc,也就是后面在通用驱动中可以直接凭借pfun指针调用sensorlist中的驱动

4.2 再来看 ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);

当 KDIMGSENSORIOC_T_CHECK_IS_ALIVE 被传下时,会调用kernel层的 adopt_CAMERA_HW_Feature

Control接口

在kdModulePowerOn中又调用_kdCISModulePowerOn

在_kdCISModulePowerOn又调用 kdCISModulePowerOn 函数

文件:kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6580/camera_hw/kd_camera_hw.c

u32 pinSetIdx = 0; /* default main sensor */

printk(“fangkuiccm %d ,currSensorName = %s pinSetIdx = %d “,LINE,currSensorName,pinSetIdx );

mdelay(50);

mdelay(10);

mdelay(10);

mdelay(10);

mdelay(50);

上电操作完成后,紧接着读取SensorID,通用驱动使用 SensorFeatureControl 来读取ID如:

g_pSensorFunc->SensorFeatureControl(g_invokeSocketIdx[i],SENSOR_FEATURE_CHECK_SENSOR_ID,(MUINT8 *) &sensorID,&retLen);

此时传入的cmd为SENSOR_FEATURE_CHECK_SENSOR_ID,就会调用 feature_control 中的get_imgsensor_id 再看 get_imgsensor_id 的实现

再看return_sensor_id的实现

return get_byte;

}

文件:kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6580/kd_sensorlist.c

/* Remove i2c ack error log during search sensor /
/
PK_ERR(“g_pstI2Cclient->ext_flag: %d”, g_IsSearchSensor); */
if (g_IsSearchSensor == 1) {

g_pstI2Cclient->ext_flag = (g_pstI2Cclient->ext_flag) | I2C_A_FILTER_MSG;
} else {

g_pstI2Cclient->ext_flag = (g_pstI2Cclient->ext_flag) & (~I2C_A_FILTER_MSG);
}




/* Remove i2c ack error log during search sensor /
/
PK_ERR(“g_pstI2Cclient2->ext_flag: %d”, g_IsSearchSensor); */
if (g_IsSearchSensor == 1) {

g_pstI2Cclient2->ext_flag = (g_pstI2Cclient2->ext_flag) | I2C_A_FILTER_MSG;
} else {

g_pstI2Cclient2->ext_flag = (g_pstI2Cclient2->ext_flag) & (~I2C_A_FILTER_MSG);
}
spin_unlock(&kdsensor_drv_lock);
i4RetValue = i2c_master_send(g_pstI2Cclient2, a_pSendData, a_sizeSendData);
if (i4RetValue != a_sizeSendData) {

PK_ERR(“[CAMERA SENSOR] I2C send failed!!, Addr = 0x%x\n”, a_pSendData[0]);
return -1;
}










这一步完成I2c的读取,也就是说如果I2c配置正确,并且上电正确,到这一步就可以正确的读取ID,整个camera也就基本就调通了。

三、总结

通过上述分析,我们可以看出,camera驱动先是注册platform平台驱动,再注册I2c驱动,然后又为前后摄注册字符设备,封装底层方法CAMERA_HW_Ioctl,,上层访问底层驱动时候先是使用setdriver将具体IC的驱动入口获取,然后使用checkisalive对sensorlist中的IC进行上电,上电完成就通过i2c读取设备ID,到此为止,上层应用与底层驱动挂接完成,紧接着就是预览和拍照,不过这都是具体IC驱动的实现了。

简要概括过程:

1.开机时,camera完成了sensor框架的初始化,id检测,以及上下电操作;

Hal层在开机初始化调用文件vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6580/hal/sensor/imgsensor_drv.cpp中的

impSearchSensor(pfExIdChk pExIdChkCbf) 函数,这个函数执行4个功能:

1).用GetSensorInitFuncList(&m_pstSensorInitFunc)函数获取目前所有的camera sensor(需加log打印确认一下是获取全部sensor还是ProjectConfig.mk中配置的sensor)列表,这些 前后 camera 都在 projectconfig. mk已经设置。

2).用KDIMGSENSORIOC_X_SET_DRIVER向Kd_sensorlist.c(kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6580) 中的CAMERA_HW_Ioctl传值,通过case分支最终调用kdSetDriver函数,根据在projectconfig.mk文件里面的main sub camera的配置,找到相应的前后camera具体的驱动文件,即对于正在遍历的这颗sensor,挂接上具体的底层驱动接口Init函数。

3).用KDIMGSENSORIOC_T_CHECK_IS_ALIVE向Kd_sensorlist.c 中的CAMERA_HW_Ioctl(即前面讲到的上层操作底层的接口)传值,通过case分支最终调用adopt_CAMERA_HW_CheckIsAlive函数,在这个函数里开始给前面找到的所有camera上电,并通过向具体驱动里面的ioctrl函数传递SENSOR_FEATURE_CHECK_SENSOR_ID参数,最终通过case分支调用对应的函数通过I2C读取并核对是否为该sensor的 id,去识别具体的camera sensor id。

4).分别对前后已经配对了sensor id的camera执行m_pSubSensorInfo =m_pstSensorInitFunc.pSensorInfo;通过这个函数会调用具体驱动(这里以GC2145M 的前摄像头为例) UINT32GC2145mipiGetInfo()函数,这个函数是获取sensor IC preview capture video时的帧率 丢帧 打开时候的默认窗口,数据传输的type等基本信息。通过上面的4步,kernel内核已经识别了主板上的硬件camera IC了,并获取具体sensorIC的基本信息。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/205369.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午6:11
下一篇 2026年3月19日 下午6:11


相关推荐

  • 众数,中位数,平均_平均数中位数

    众数,中位数,平均_平均数中位数导读:本文带你了解各种形式的平均值,并理解其重要性。作者:尼尔·布朗(NeilBrowne)、斯图尔特·基利(StuartKeeley)来源:大数据DT(ID:hzdashuju)01…

    2025年12月12日
    4
  • python中object转为string_java中Object转String

    python中object转为string_java中Object转StringObject 转为 String 的几种形式在 java 项目的实际开发和应用中 常常需要用到将对象转为 String 这一基本功能 本文将对常用的转换方法进行一个总结 常用的方法有 Object toString String 要转换的对象 String valueOf Object 等 下面对这些方法一一进行分析 方法 1 采用 Object toString 方法请看下面的例子 Objectobje

    2026年3月19日
    0
  • vscode中搭建Golang开发环境(图文并茂)

    vscode中搭建Golang开发环境(图文并茂)vscode中搭建Golang开发环境第一步下载Go安装包,地址:Go语言中文网,安装完成后的目录如下:通过命令行查看当前版本:第二步配置环境变量,新建两个环境变量,如下:其他平台的配置,可以参考goproxy官网。第三步打开vscode,安装一个Go插件,如下:然后打开一个已有的文件夹,并创建一个hello.go的文件,此时,右下角会提示你要安装相应的应用,选择InstallAll,等待安装即可,安装成功如下:到这里环境就搭建完成了第四步在hello.go文件中编写

    2022年10月12日
    5
  • ChatGPT 国内使用保姆教程,含GPT

    ChatGPT 国内使用保姆教程,含GPT

    2026年3月16日
    2
  • Coze Studio 文档处理实战(一)– 从分段策略到向量化检索的完整链路解析

    Coze Studio 文档处理实战(一)– 从分段策略到向量化检索的完整链路解析

    2026年3月12日
    2
  • RNN模型

    RNN模型RNN 模型我们先来看一个 RNN 经典结构 图 1 展示了一个典型按时间展开后的 RNN 结构 从图 1 可以看出 RNN 在每一个时刻都有一个输入 Xt 然后根据当前节点的状态 At 计算输出值 ht 而 At 是根据上一时刻的状态 At 1 和当前的输入 Xt 共同决定的 和卷积神经网络卷积核或池化核的参数共享类似 这里 RNN 结构中的参数在不同时刻中也是共享的 1 2 1RNN 前向传播过程图 2RNN 的前

    2026年3月26日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号