MTK平台camera驱动架构分析
MTK6580 AndroidO(android8.1)版本camera 驱动分析
⾸先说说2点:
1、Camera 的成像原理:
景物通过镜头(LENS)⽣成的光学图像投射到图像传感器(Sensor)表⾯上,然后转为模拟的电信号,经过 A/D(模数转换)转换后变为数字图像信号,再送到数字信号处理芯⽚(DSP)中加⼯处理,再通过 IO 接⼝传输到 CPU 中处理,通过 LCD 就可以看到图像了。
图像传感器(SENSOR)是⼀种半导体芯⽚,其表⾯包含有⼏⼗万到⼏百万的光电⼆极管。光电⼆极管受到光照射时,就会产⽣电荷。⽬前的SENSOR 类型有两种:
CCD(Charge Couple Device),电荷耦合器件,它是⽬前⾼像素类 sensor 中⽐较成熟的成像器件,是以⼀⾏为单位的电流信号。
CMOS(Complementary Metal Oxide Semiconductor),互补⾦属氧化物半导体。CMOS的信号是以点为单位的电荷信号,更为敏感,速度也更快,更为省电。
ISP 的性能是决定影像流畅的关键,JPEG encoder 的性能也是关键指标之⼀。⽽ JPEG encoder ⼜分为硬件 JPEG 压缩⽅式,和软件 RGB 压缩⽅式。
DSP 控制芯⽚的作⽤是:将感光芯⽚获取的数据及时快速地传到 baseband 中并刷新感光芯⽚,因此控制芯⽚的好坏,直接决定画⾯品质(⽐如⾊彩饱和度、清晰度)与流畅度。
李京奎
2、Camera 常见的数据输出格式:
常见的数据输出格式有:Rawdata 格式、YUV 格式、RGB 格式。
RGB 格式:采⽤这种编码⽅法,每种颜⾊都可⽤三个变量来表⽰红⾊、绿⾊以及蓝⾊的强度。每⼀个像素有三原⾊ R 红⾊、G 绿⾊、B 蓝⾊组成。
YUV 格式:其中“Y”表⽰明亮度(Luminance 或 Luma),就是灰阶值;⽽“U”和“V”表⽰⾊度(Chrominance 或 Chroma),是描述影像⾊彩及饱和度,⽤于指定像素的颜⾊。
RAW DATA 格式:是 CCD 或 CMOS 在将光信号转换为电信号时的电平⾼低的原始记录,单纯地将没有进⾏任何处理的图像数据,即摄像元件直接得到的电信号进⾏数字化处理⽽得到的。
⽀持 YUV/RGB 格式的模组,⼀般会在模组上集成 ISP(Image Single Processor),经过A/D 转换过的原
始数据经过 ISP 处理⽣成 YUV 标准格式传到 BB。⼀般来说,这种设计适⽤于低像素 Camera 的要求,会在主板上省去⼀个 DSP,可降低成本。在调试过程中,YUV/RGB 格式的摄像头,其所有参数都可在 kernel 层通过寄存器来控制。调试⼀般由 sensor的原⼚⽀持。
⽀持 RawData 格式的模组,由于感光区域的需求,不会再模组内集成 ISP 以最⼤程度的增⼤感光区域的⾯积,提⾼照⽚质量。模组把原始的数字信号传给 BB 上的 DSP 进⾏处理,MTK ⾃带的 DSP ⼀般包含 ISP、JPEG encoder、和 DSP 控制芯⽚。在调试的时候图像的效果需要MTK 在 HAL 层的参数进⾏⽀持。
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 层部分----------------------------
⽂件:vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6580/hal/sensor/imgsensor_drv.cpp
MINT32
王澜菲ImgSensorDrv::impSearchSensor(pfExIdChk pExIdChkCbf)
{
GetSensorInitFuncList(&m_pstSensorInitFunc);
LOG_MSG(“SENSOR search start \n”);
sprintf(cBuf,"/dev/%s",CAMERA_HW_DEVNAME);
m_fdSensor = ::open(cBuf, O_RDWR);
for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {
err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] );
err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);
}
GetSensorInitFuncList的实现:
⽂件:vendor/mediatek/proprietary/custom/mt6580/hal/imgsensor_src/sensorlist.cpp
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;
}
Sensor 列表的定义如下:
MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] =
{
孔燕松妹
#if defined(GC2365MIPI_RAW)
RAW_INFO(GC2365MIPI_SENSOR_ID, SENSOR_DRVNAME_GC2365MIPI_RAW, NULL),
#endif
#if defined(GC2355_MIPI_RAW_BAIKANG_M8112)
RAW_INFO(GC2355_SENSOR_ID, SENSOR_DRVNAME_GC2355_MIPI_RAW,NULL),
#endif
}
获取sensor列表后,紧接着通过:
err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] ); err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);
访问kernel层的数据:
--------------------- Kernel 层驱动的实现 --------------------
1. 针对前后摄注册platform 设备和驱动
⽂件:kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6580/kd_sensorlist.c
static int __init CAMERA_HW_i2C_init(void)
{
if (platform_driver_register(&g_stCAMERA_HW_Driver)) //注册主摄platform 驱动
if (platform_driver_register(&g_stCAMERA_HW_Driver2)) //注册副摄platform 驱动
return 0;
}
主摄平台驱动的定义:
#ifdef CONFIG_OF
static const struct of_device_id CAMERA_HW_of_ids[] = {
{patible = “mediatek,camera_hw”,}, //主摄匹配规则
{}
};
#endif
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
}
};养牛的利润与成本
副摄平台驱动的定义:
#ifdef CONFIG_OF
static const struct of_device_id CAMERA_HW2_of_ids[] = {
{patible = “mediatek,camera_hw2”,},//副摄匹配规则
{}
};
#endif
static struct platform_driver g_stCAMERA_HW_Driver2 = {
.probe = CAMERA_HW_probe2,
.remove = CAMERA_HW_remove2,
.suspend = CAMERA_HW_suspend2,
.resume = CAMERA_HW_resume2,
.driver = {
.name = “image_sensor_bus2”,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.
of_match_table = CAMERA_HW2_of_ids,
#endif
}
};
主副摄cam在dts中(注册设备)定义设备信息:
kd_camera_hw1:kd_camera_hw1@15008000 {
compatible = “mediatek,camera_hw”; //这⾥必须和主摄⼀致
reg = <0x15008000 0x1000>; /* SENINF_ADDR */
vcama-supply = <&mt_pmic_vcama_ldo_reg>;
vcamd-supply = <&mt_pmic_vcamd_ldo_reg>;
vcamaf-supply = <&mt_pmic_vcamaf_ldo_reg>;
vcamio-supply = <&mt_pmic_vcamio_ldo_reg>;
};
kd_camera_hw2:kd_camera_hw2@15008000 {
compatible = “mediatek,camera_hw2”; //这⾥必须和副摄⼀致
reg = <0x15008000 0x1000>; /* SENINF_ADDR */
};
当内核启动后,会解析dts编译⽣成的dtb⽂件,注册⾥⾯定义的device,如果和驱动中定义compatible字段⼀致,则挂载启动。上⾯注册了两个platform 驱动g_stCAMERA_HW_Driver,g_stCAMERA_HW_Driver2,
如果compatible匹配成功会调⽤各⾃的probe函数CAMERA_HW_probe,CAMERA_HW_probe2
2. 平台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[] = {
{ patible = “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[] = {
{ patible = “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,
};
3. I2c probe的实现
从上可以看出main/sub sensor在各⾃的平台probe中,注册了i2c_driver,当各⾃的i2c_driver和设备匹配
匹配规则:
(1)当在dts有创建设备节点注册设备的时候:当i2c_driver和i2c_device的patible字段⼀致,就会执⾏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函数
CAMERA_HW_i2c_probe:
static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id id)
{
/ Register char driver */
i4RetValue = RegisterCAMERA_HWCharDrv();
return 0;
}