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

mtk平台三大件调试中,camera的调试难度最大,问题也就最多,为此特地分析了一下整个camera驱动部分

实现过程,以下为camera驱动框架序列图:

从图中可以看出,整个框架分为三个部分hal部分逻辑调用,kernel层的通用驱动sensorlist.c 和具体IC的驱动

xxxx_mipi_raw.c,kernel起来后不会直接去访问硬件sensor,而是会注册相关的驱动,之后Android系统起来后

会启动相关的服务如:camera_service,在camera服务中会直接去访问hal,kernel驱动,进而操作camera。

为此本文也穿插了部分hal层的调用,至于camera_service后面章节会继续补充。

二、 Camera 驱动的具体实现

========================HAL 层部分初始调用========================
文件:vendor/mediatek/proprietary/hardware/mtkcam/common/module_hal/devicemgr/CamDeviceManagerBase.cpp

[cpp] view plain copy

  1. int32_t
  2. CamDeviceManagerBase::
  3. getNumberOfDevices()
  4. {
  5. mi4DeviceNum = enumDeviceLocked();
  6. }
int32_t CamDeviceManagerBase:: getNumberOfDevices() { … mi4DeviceNum = enumDeviceLocked();
    ...

}文件:vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6580/devicemgr/CamDeviceManagerImp.cpp

[cpp] view plain copy

  1. int32_t
  2. CamDeviceManagerImp::
  3. enumDeviceLocked()
  4. {
  5. //——————————————————————————
  6. #if ‘1’==MTKCAM_HAVE_SENSOR_HAL
  7. //
  8. IHalSensorList*const pHalSensorList = IHalSensorList::get();
  9. size_t const sensorNum = pHalSensorList->searchSensors();
  10. #endif
  11. return  i4DeviceNum;
  12. }
int32_t CamDeviceManagerImp:: enumDeviceLocked() { … //——————————————————————————

if ‘1’==MTKCAM_HAVE_SENSOR_HAL

//
IHalSensorList*const pHalSensorList = IHalSensorList::get();
size_t const sensorNum = pHalSensorList->searchSensors();

endif

...
return  i4DeviceNum;

}文件:vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6580/hal/sensor/HalSensorList.cpp

[cpp] view plain copy

  1. MUINT
  2. HalSensorList::
  3. searchSensors()
  4. {
  5. Mutex::Autolock _l(mEnumSensorMutex);
  6. //
  7. MY_LOGD(”searchSensors”);
  8. return  enumerateSensor_Locked();
  9. }
MUINT HalSensorList:: searchSensors() { Mutex::Autolock _l(mEnumSensorMutex); // MY_LOGD("searchSensors"); return  enumerateSensor_Locked(); }

文件:vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6580/hal/sensor/HalSensorList.enumList.cpp

[cpp] view plain copy

  1. MUINT
  2. HalSensorList::
  3. enumerateSensor_Locked()
  4. {
  5. ….
  6. MUINT halSensorDev = SENSOR_DEV_NONE;
  7. NSFeature::SensorInfoBase* pSensorInfo ;
  8. SensorDrv const pSensorDrv = SensorDrv::get();  
  9. SeninfDrv const pSeninfDrv = SeninfDrv::createInstance();
  10. int const iSensorsList = pSensorDrv->impSearchSensor(NULL);
  11. ….
  12. }
MUINT HalSensorList:: enumerateSensor_Locked() { ….
MUINT halSensorDev = SENSOR_DEV_NONE;
NSFeature::SensorInfoBase* pSensorInfo ;SensorDrv *const pSensorDrv = SensorDrv::get();
SeninfDrv *const pSeninfDrv = SeninfDrv::createInstance();int const iSensorsList = pSensorDrv->impSearchSensor(NULL);....

}文件:vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6580/hal/sensor/imgsensor_drv.cpp

[cpp] view plain copy

  1. MINT32
  2. ImgSensorDrv::impSearchSensor(pfExIdChk pExIdChkCbf)
  3. {
  4. ….
  5. GetSensorInitFuncList(&m_pstSensorInitFunc);
  6. LOG_MSG(”SENSOR search start \n”);
  7. sprintf(cBuf,”/dev/%s”,CAMERA_HW_DEVNAME);
  8. m_fdSensor = ::open(cBuf, O_RDWR);
  9. ……
  10. for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {
  11. ….
  12. err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] );
  13. err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);
  14. ……
  15. }
MINT32 ImgSensorDrv::impSearchSensor(pfExIdChk pExIdChkCbf) { ….
GetSensorInitFuncList(&amp;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 &lt; MAX_NUM_OF_SUPPORT_SENSOR; i++) {....err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&amp;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

[cpp] view plain copy

  1. UINT32 GetSensorInitFuncList(MSDK_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)
  2. {
  3. if (NULL == ppSensorList) {
  4. ALOGE(”ERROR: NULL pSensorList\n”);
  5. return MHAL_UNKNOWN_ERROR;
  6. }
  7. *ppSensorList = &SensorList[0];
  8. return MHAL_NO_ERROR;
  9. }
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 列表的定义如下:

[cpp] view plain copy

  1. MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] =
  2. {
  3. //xc add camera start
  4. #if defined(GC2365MIPI_RAW)
  5. RAW_INFO(GC2365MIPI_SENSOR_ID, SENSOR_DRVNAME_GC2365MIPI_RAW, NULL),
  6. #endif
  7. #if defined(GC2355_MIPI_RAW_BAIKANG_M8112)
  8. RAW_INFO(GC2355_SENSOR_ID, SENSOR_DRVNAME_GC2355_MIPI_RAW,NULL),
  9. #endif
  10. ….
  11. }
MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] = { //xc add camera start

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),
  • 1

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

[cpp] view plain copy

  1. static int __init CAMERA_HW_i2C_init(void)
  2. {
  3. ….
  4. if (platform_driver_register(&g_stCAMERA_HW_Driver)) //注册主摄platform 驱动
  5. if (platform_driver_register(&g_stCAMERA_HW_Driver2)) //注册副摄platform 驱动
  6. ….
  7. return 0;
  8. }
static int __init CAMERA_HW_i2C_init(void) { ….
if (platform_driver_register(&amp;g_stCAMERA_HW_Driver)) //注册主摄platform 驱动
if (platform_driver_register(&amp;g_stCAMERA_HW_Driver2)) //注册副摄platform 驱动....
return 0;

}主摄平台驱动的定义:

[cpp] view plain copy

  1. #ifdef CONFIG_OF
  2. static const struct of_device_id CAMERA_HW_of_ids[] = {
  3. {.compatible = ”mediatek,camera_hw”,},  //主摄匹配规则
  4. {}
  5. };
  6. #endif
  7. static struct platform_driver g_stCAMERA_HW_Driver = {
  8. .probe = CAMERA_HW_probe,
  9. .remove = CAMERA_HW_remove,
  10. .suspend = CAMERA_HW_suspend,
  11. .resume = CAMERA_HW_resume,
  12. .driver = {
  13. .name = ”image_sensor”,
  14. .owner = THIS_MODULE,
  15. #ifdef CONFIG_OF
  16. .of_match_table = CAMERA_HW_of_ids,
  17. #endif
  18. }
  19. };
#ifdef CONFIG_OF static const struct of_device_id CAMERA_HW_of_ids[] = { {.compatible = “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

       }

};副摄平台驱动的定义:

[cpp] view plain copy

  1. #ifdef CONFIG_OF
  2. static const struct of_device_id CAMERA_HW2_of_ids[] = {
  3. {.compatible = ”mediatek,camera_hw2”,},//副摄匹配规则
  4. {}
  5. };
  6. #endif
  7. static struct platform_driver g_stCAMERA_HW_Driver2 = {
  8. .probe = CAMERA_HW_probe2,
  9. .remove = CAMERA_HW_remove2,
  10. .suspend = CAMERA_HW_suspend2,
  11. .resume = CAMERA_HW_resume2,
  12. .driver = {
  13. .name = ”image_sensor_bus2”,
  14. .owner = THIS_MODULE,
  15. #ifdef CONFIG_OF
  16. .of_match_table = CAMERA_HW2_of_ids,
  17. #endif
  18. }
  19. };
#ifdef CONFIG_OF static const struct of_device_id CAMERA_HW2_of_ids[] = { {.compatible = “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中定义设备信息:

[cpp] view plain copy

  1. kd_camera_hw1:kd_camera_hw1@15008000 {
  2. compatible = ”mediatek,camera_hw”; //这里必须和主摄一致
  3. reg = <0x15008000 0x1000>;  / SENINF_ADDR /
  4. vcama-supply = <&mt_pmic_vcama_ldo_reg>;
  5. vcamd-supply = <&mt_pmic_vcamd_ldo_reg>;
  6. vcamaf-supply = <&mt_pmic_vcamaf_ldo_reg>;
  7. vcamio-supply = <&mt_pmic_vcamio_ldo_reg>;
  8. };
  9. kd_camera_hw2:kd_camera_hw2@15008000 {
  10. compatible = ”mediatek,camera_hw2”; //这里必须和副摄一致
  11. reg = <0x15008000 0x1000>;  / SENINF_ADDR /
  12. };
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,如果和驱动中定义id一致,则挂载启动。

上面注册了两个platform 驱动g_stCAMERA_HW_Driver,g_stCAMERA_HW_Driver2,如果匹配成功会调用各自的

probe函数CAMERA_HW_probe,CAMERA_HW_probe2

2. 平台probe 函数的实现
主摄probe,CAMERA_HW_probe的实现如下:

[cpp] view plain copy

  1. static int CAMERA_HW_probe(struct platform_device *pdev)
  2. {
  3. #if !defined(CONFIG_MTK_LEGACY)
  4. mtkcam_gpio_init(pdev);
  5. mtkcam_pin_mux_init(pdev);
  6. #endif
  7. return i2c_add_driver(&CAMERA_HW_i2c_driver);
  8. }
static int CAMERA_HW_probe(struct platform_device *pdev) {
  • 1

if !defined(CONFIG_MTK_LEGACY)

mtkcam_gpio_init(pdev);
mtkcam_pin_mux_init(pdev);

endif

return i2c_add_driver(&amp;CAMERA_HW_i2c_driver);

}副摄probe,CAMERA_HW_probe的实现如下:

[cpp] view plain copy

  1. static int CAMERA_HW_probe2(struct platform_device *pdev)
  2. {
  3. return i2c_add_driver(&CAMERA_HW_i2c_driver2);
  4. }
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定义如下:

[cpp] view plain copy

  1. #ifdef CONFIG_OF
  2. static const struct of_device_id CAMERA_HW_i2c_of_ids[] = {
  3. { .compatible = ”mediatek,camera_main”, },
  4. {}
  5. };
  6. #endif
  7. struct i2c_driver CAMERA_HW_i2c_driver = {
  8. .probe = CAMERA_HW_i2c_probe,
  9. .remove = CAMERA_HW_i2c_remove,
  10. .driver = {
  11. .name = CAMERA_HW_DRVNAME1,
  12. .owner = THIS_MODULE,
  13. #ifdef CONFIG_OF
  14. .of_match_table = CAMERA_HW_i2c_of_ids,
  15. #endif
  16. },
  17. .id_table = CAMERA_HW_i2c_id,
  18. };
  19. sub sensor 的CAMERA_HW_i2c_driver定义如下:
  20. #ifdef CONFIG_OF
  21. static const struct of_device_id CAMERA_HW2_i2c_driver_of_ids[] = {
  22. { .compatible = ”mediatek,camera_sub”, },
  23. {}
  24. };
  25. #endif
  26. struct i2c_driver CAMERA_HW_i2c_driver2 = {
  27. .probe = CAMERA_HW_i2c_probe2,
  28. .remove = CAMERA_HW_i2c_remove2,
  29. .driver = {
  30. .name = CAMERA_HW_DRVNAME2,
  31. .owner = THIS_MODULE,
  32. #ifdef CONFIG_OF
  33. .of_match_table = CAMERA_HW2_i2c_driver_of_ids,
  34. #endif
  35. },
  36. .id_table = CAMERA_HW_i2c_id2,
  37. };
#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,
  • 1

endif

       },
.id_table = CAMERA_HW_i2c_id2,
  • 1
  • 2

};对应main/sub camera i2c 设备dts定义如下
文件:kernel-3.18/arch/arm/boot/dts/cust_i2c.dtsi

[cpp] view plain copy

  1. &i2c0 {
  2. camera_main@10 {
  3. compatible = ”mediatek,camera_main”; //和 CAMERA_HW_i2c_driver定义的一致
  4. reg = <0x10>;
  5. };
  6. camera_main_af@0c {
  7. compatible = ”mediatek,camera_main_af”;
  8. reg = <0x0c>;
  9. };
  10. camera_sub@3c {
  11. compatible = ”mediatek,camera_sub”; //和CAMERA_HW_i2c_driver2定义的一致
  12. reg = <0x3c>;
  13. };
  14. };
&i2c0 { camera_main@10 { compatible = “mediatek,camera_main”; //和 CAMERA_HW_i2c_driver定义的一致 reg = <0x10>; };
camera_main_af@0c {compatible = "mediatek,camera_main_af";reg = &lt;0x0c&gt;;
};camera_sub@3c {compatible = "mediatek,camera_sub"; //和CAMERA_HW_i2c_driver2定义的一致reg = &lt;0x3c&gt;;
};

};3. I2c probe的实现

从上可以看出main/sub sensor在各自的平台probe中,注册了i2c_driver,当各自的i2c_driver和设备匹配

(如何匹配本章不作分析)成功后,会调用各自的i2c_probe函数。main sensor 的probe函数
CAMERA_HW_i2c_probe:

[cpp] view plain copy

  1. static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
  2. {
  3. …..
  4. /* Register char driver */
  5. i4RetValue = RegisterCAMERA_HWCharDrv();
  6. …..
  7. return 0;
  8. }
static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{...../* Register char driver */i4RetValue = RegisterCAMERA_HWCharDrv();.....return 0;
}

sub sensor 的probe函数CAMERA_HW_i2c_probe2:

[cpp] view plain copy

  1. static int CAMERA_HW_i2c_probe2(struct i2c_client *client, const struct i2c_device_id *id)
  2. {
  3. …..
  4. /* Register char driver */
  5. i4RetValue = RegisterCAMERA_HWCharDrv2();
  6. …..
  7. }
static int CAMERA_HW_i2c_probe2(struct i2c_client *client, const struct i2c_device_id *id)
{...../* Register char driver */i4RetValue = RegisterCAMERA_HWCharDrv2();.....
}

从上可以看出main/sub 在各自的i2cprobe中,通过该调用RegisterCAMERA_HWCharDrv,RegisterCAMERA_HWCharDrv2注册了字符设备。各自注册cdev函数实现如下:

[cpp] view plain copy

  1. static inline int RegisterCAMERA_HWCharDrv(void)//main sensor 注册cdev
  2. {
  3. …..
  4. /* Attatch file operation. */
  5. cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops); //初始化字符设备
  6. /* Add to system */
  7. cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1) //注册到内核
  8. //创建目录 /sys/class/sensordrv/
  9. sensor_class = class_create(THIS_MODULE, ”sensordrv”);
  10. //创建目录/sys/class/sensordrv/kd_camera_hw
  11. sensor_device = device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1);
  12. ….
  13. return 0;
  14. }
  15. static inline int RegisterCAMERA_HWCharDrv2(void)//sub sensor 注册cdev
  16. {
  17. ….
  18. /* Attatch file operation. */
  19. cdev_init(g_pCAMERA_HW_CharDrv2, &g_stCAMERA_HW_fops0);//初始化字符设备
  20. /* Add to system */
  21. cdev_add(g_pCAMERA_HW_CharDrv2, g_CAMERA_HWdevno2, 1));//注册到内核
  22. //创建目录 /sys/class/sensordrv2/
  23. sensor2_class = class_create(THIS_MODULE, ”sensordrv2”);
  24. //创建目录/sys/class/sensordrv2/kd_camera_hw_bus2
  25. sensor_device2 = device_create(sensor2_class, NULL, g_CAMERA_HWdevno2, NULL, CAMERA_HW_DRVNAME2);
  26. ….
  27. return 0;
  28. }
  29. main/sub 创建各自的字符设备过程中绑定各自的fops,g_stCAMERA_HW_fops和g_stCAMERA_HW_fops0
  30. 他们各自定义如下
  31. static const struct file_operations g_stCAMERA_HW_fops = { //main sensor fops
  32. .owner = THIS_MODULE,
  33. .open = CAMERA_HW_Open,
  34. .release = CAMERA_HW_Release,
  35. .unlocked_ioctl = CAMERA_HW_Ioctl,
  36. #ifdef CONFIG_COMPAT
  37. .compat_ioctl = CAMERA_HW_Ioctl_Compat,
  38. #endif
  39. };
  40. static const struct file_operations g_stCAMERA_HW_fops0 = { //sub sensor fops
  41. .owner = THIS_MODULE,
  42. .open = CAMERA_HW_Open2,
  43. .release = CAMERA_HW_Release2,
  44. .unlocked_ioctl = CAMERA_HW_Ioctl,
  45. #ifdef CONFIG_COMPAT
  46. .compat_ioctl = CAMERA_HW_Ioctl_Compat,
  47. #endif
  48. };
static inline int RegisterCAMERA_HWCharDrv(void)//main sensor 注册cdev
{...../* Attatch file operation. */cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops); //初始化字符设备/* Add to system */cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1) //注册到内核//创建目录 /sys/class/sensordrv/sensor_class = class_create(THIS_MODULE, "sensordrv"); //创建目录/sys/class/sensordrv/kd_camera_hw sensor_device = device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1); ....    return 0;
}
static inline int RegisterCAMERA_HWCharDrv2(void)//sub sensor 注册cdev
{..../* 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_bus2sensor_device2 = device_create(sensor2_class, NULL, g_CAMERA_HWdevno2, NULL, CAMERA_HW_DRVNAME2);....return 0;
}
main/sub 创建各自的字符设备过程中绑定各自的fops,g_stCAMERA_HW_fops和g_stCAMERA_HW_fops0
他们各自定义如下
static const struct file_operations g_stCAMERA_HW_fops = { //main sensor fops.owner = THIS_MODULE,.open = CAMERA_HW_Open,.release = CAMERA_HW_Release,.unlocked_ioctl = CAMERA_HW_Ioctl,

ifdef CONFIG_COMPAT

.compat_ioctl = CAMERA_HW_Ioctl_Compat,
  • 1

endif

};

static const struct file_operations g_stCAMERA_HW_fops0 = { //sub sensor fops
.owner = THIS_MODULE,
.open = CAMERA_HW_Open2,
.release = CAMERA_HW_Release2,
.unlocked_ioctl = CAMERA_HW_Ioctl,

ifdef CONFIG_COMPAT

.compat_ioctl = CAMERA_HW_Ioctl_Compat,
  • 1

endif

};

从上可以看出各自的fops指定了相同的Iioctl函数,意味着上层操作main/sub sensor 只需要对应一个底层

的ioctl即可,至于sensor的区分可以借助idx,后面会讲到

[cpp] view plain copy

  1. /*******************************************************************************
  2. * CAMERA_HW_Ioctl
  3. ********************************************************************************/
  4. static long CAMERA_HW_Ioctl(struct file *a_pstFile,
  5. unsigned int a_u4Command, unsigned long a_u4Param)
  6. {
  7. pIdx = (u32 *) pBuff;
  8. switch (a_u4Command) {
  9. case KDIMGSENSORIOC_X_SET_DRIVER:
  10. i4RetValue = kdSetDriver((unsigned int *)pBuff);
  11. break;
  12. case KDIMGSENSORIOC_X_FEATURECONCTROL:
  13. i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff);
  14. break;
  15. case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
  16. i4RetValue = adopt_CAMERA_HW_CheckIsAlive();
  17. break;
  18. ….
  19. default:
  20. PK_DBG(”No such command\n”);
  21. i4RetValue = -EPERM;
  22. break;
  23. }
  24. …..
  25. }
/*******************************************************************************
* CAMERA_HW_Ioctl
********************************************************************************/static long CAMERA_HW_Ioctl(struct file *a_pstFile,unsigned int a_u4Command, unsigned long a_u4Param)
{...pIdx = (u32 *) pBuff;switch (a_u4Command) {...case KDIMGSENSORIOC_X_SET_DRIVER:i4RetValue = kdSetDriver((unsigned int *)pBuff);break;case KDIMGSENSORIOC_X_FEATURECONCTROL:i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff);break;case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:i4RetValue = adopt_CAMERA_HW_CheckIsAlive();break;....default:PK_DBG("No such command\n");i4RetValue = -EPERM;break;}.....
}

这里ioctl和上层一一对应,上层要控制caemra 只需要传入相应的cmd和data而已

============================== HAL 调用Kernel 层驱动的逻辑 ========================
       前面介绍了HAL层调用ioctl 和 kernel层注册驱动,接下来继续分析,HAL层调用后驱动具体的实现流程。
4. ioctl 底层的实现
4.1先来看ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] );
当KDIMGSENSORIOC_X_SET_DRIVER被传下时,会调用kernel层的kdSetDriver接口

[cpp] view plain copy

  1. int kdSetDriver(unsigned int *pDrvIndex)
  2. {
  3. kdGetSensorInitFuncList(&pSensorList))   //获得sensor初始化列表
  4. for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {
  5. ….
  6. pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]); //获取各个cam驱动中Init函数入口
  7. ….
  8. }
  9. return 0;
  10. }
int kdSetDriver(unsigned int *pDrvIndex)
{...kdGetSensorInitFuncList(&pSensorList))   //获得sensor初始化列表for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {....pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]); //获取各个cam驱动中Init函数入口....}return 0;
}

kdGetSensorInitFuncList的实现:

[cpp] view plain copy

  1. UINT32 kdGetSensorInitFuncList(ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)
  2. {
  3. if (NULL == ppSensorList) {
  4. PK_ERR(”[kdGetSensorInitFuncList]ERROR: NULL ppSensorList\n”);
  5. return 1;
  6. }
  7. *ppSensorList = &kdSensorList[0];  //获取sensorlist数组首地址
  8. return 0;
  9. }               /* kdGetSensorInitFuncList() */
UINT32 kdGetSensorInitFuncList(ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)
{if (NULL == ppSensorList) {PK_ERR("[kdGetSensorInitFuncList]ERROR: NULL ppSensorList\n");return 1;}*ppSensorList = &kdSensorList[0];  //获取sensorlist数组首地址return 0;
}               /* kdGetSensorInitFuncList() */

kdSensorList定义如下:
文件:kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6580/kd_sensorlist.h

[cpp] view plain copy

  1. ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] =
  2. {
  3. ….
  4. #if defined(SUB_GC2355_MIPI_RAW)
  5. {GC2355S_SENSOR_ID, SENSOR_DRVNAME_GC2355S_MIPI_RAW,Sub_GC2355_MIPI_RAW_SensorInit},
  6. #endif
  7. ….
  8. }
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] =
{....

if defined(SUB_GC2355_MIPI_RAW)

{GC2355S_SENSOR_ID, SENSOR_DRVNAME_GC2355S_MIPI_RAW,Sub_GC2355_MIPI_RAW_SensorInit},
  • 1

endif

....

}获取列表之后紧接着调用各自的Init函数,这里以GC2355为例

[cpp] view plain copy

  1. UINT32 GC2235MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT pfFunc)  
  2. {
  3. / To Do : Check Sensor status here /
  4. if (pfFunc!=NULL)
  5. *pfFunc=&sensor_func;
  6. return ERROR_NONE;
  7. }   /  GC2235MIPI_RAW_SensorInit   */
UINT32 GC2235MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc) { /* To Do : Check Sensor status here */ if (pfFunc!=NULL) *pfFunc=&sensor_func; return ERROR_NONE; }   /*  GC2235MIPI_RAW_SensorInit   */

丛中可以看出,gc2355的Init函数地址传给了pfFunc,也就是时候,后面在通用驱动可以直接凭借

pfun指针调用sensorlist中的驱动
4.2 再来看ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);

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

Control接口

[cpp] view plain copy

  1. static inline int adopt_CAMERA_HW_CheckIsAlive(void)
  2. {
  3. ….
  4. /* power on sensor */
  5. kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM *) g_invokeSocketIdx, g_invokeSensorNameStr,
  6. true, CAMERA_HW_DRVNAME1);
  7. ….
  8. if (g_pSensorFunc) {
  9. for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {
  10. if (DUAL_CAMERA_NONE_SENSOR != g_invokeSocketIdx[i]) {
  11. err =
  12. g_pSensorFunc->SensorFeatureControl(g_invokeSocketIdx[i],
  13. SENSOR_FEATURE_CHECK_SENSOR_ID,
  14. (MUINT8 *) &sensorID,
  15. &retLen);
  16. if (sensorID == 0) {    /* not implement this feature ID */
  17. PK_DBG
  18. (” Not implement!!, use old open function to check\n”);
  19. err = ERROR_SENSOR_CONNECT_FAIL;
  20. } else if (sensorID == 0xFFFFFFFF) {    /* fail to open the sensor */
  21. PK_DBG(” No Sensor Found”);
  22. err = ERROR_SENSOR_CONNECT_FAIL;
  23. } else {
  24. PK_INF(” Sensor found ID = 0x%x\n”, sensorID);
  25. snprintf(mtk_ccm_name, sizeof(mtk_ccm_name),
  26. ”%s CAM[%d]:%s;”, mtk_ccm_name,
  27. g_invokeSocketIdx[i], g_invokeSensorNameStr[i]);
  28. psensorResolution[0] = &sensorResolution[0];
  29. psensorResolution[1] = &sensorResolution[1];
  30. // don’t care of the result
  31. g_pSensorFunc->SensorGetResolution(psensorResolution);
  32. if(g_invokeSocketIdx[i] == DUAL_CAMERA_MAIN_SENSOR)
  33. curr_sensor_id = 0;
  34. else if(g_invokeSocketIdx[i] == DUAL_CAMERA_SUB_SENSOR)
  35. curr_sensor_id = 1;
  36. /* fill the cam infos with name/width/height */
  37. snprintf(g_cam_infos, sizeof(g_cam_infos),“%s CAM[%d]:%s,Width:%d, Height:%d;”,
  38. g_cam_infos, g_invokeSocketIdx[i], g_invokeSensorNameStr[i],
  39. sensorResolution[curr_sensor_id].SensorFullWidth, sensorResolution[curr_sensor_id].SensorFullHeight);
  40. err = ERROR_NONE;
  41. }
  42. if (ERROR_NONE != err) {
  43. PK_DBG
  44. (”ERROR:adopt_CAMERA_HW_CheckIsAlive(), No imgsensor alive\n”);
  45. }
  46. }
  47. }
  48. } else {
  49. PK_DBG(”ERROR:NULL g_pSensorFunc\n”);
  50. }
  51. }               /* adopt_CAMERA_HW_Open() */
static inline int adopt_CAMERA_HW_CheckIsAlive(void)
{..../* power on sensor */kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM *) g_invokeSocketIdx, g_invokeSensorNameStr,true, CAMERA_HW_DRVNAME1);....if (g_pSensorFunc) {for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {if (DUAL_CAMERA_NONE_SENSOR != g_invokeSocketIdx[i]) {err =g_pSensorFunc->SensorFeatureControl(g_invokeSocketIdx[i],SENSOR_FEATURE_CHECK_SENSOR_ID,(MUINT8 *) &sensorID,&retLen);if (sensorID == 0) {    /* not implement this feature ID */PK_DBG(" Not implement!!, use old open function to check\n");err = ERROR_SENSOR_CONNECT_FAIL;} else if (sensorID == 0xFFFFFFFF) {    /* fail to open the sensor */PK_DBG(" No Sensor Found");err = ERROR_SENSOR_CONNECT_FAIL;} else {PK_INF(" Sensor found ID = 0x%x\n", sensorID);snprintf(mtk_ccm_name, sizeof(mtk_ccm_name),"%s CAM[%d]:%s;", mtk_ccm_name,g_invokeSocketIdx[i], g_invokeSensorNameStr[i]);psensorResolution[0] = &sensorResolution[0];psensorResolution[1] = &sensorResolution[1];// don't care of the resultg_pSensorFunc->SensorGetResolution(psensorResolution);if(g_invokeSocketIdx[i] == DUAL_CAMERA_MAIN_SENSOR)curr_sensor_id = 0;else if(g_invokeSocketIdx[i] == DUAL_CAMERA_SUB_SENSOR)curr_sensor_id = 1;/* fill the cam infos with name/width/height */snprintf(g_cam_infos, sizeof(g_cam_infos),"%s CAM[%d]:%s,Width:%d, Height:%d;",g_cam_infos, g_invokeSocketIdx[i], g_invokeSensorNameStr[i],sensorResolution[curr_sensor_id].SensorFullWidth, sensorResolution[curr_sensor_id].SensorFullHeight);err = ERROR_NONE;}if (ERROR_NONE != err) {PK_DBG("ERROR:adopt_CAMERA_HW_CheckIsAlive(), No imgsensor alive\n");}}}} else {PK_DBG("ERROR:NULL g_pSensorFunc\n");}
}               /* adopt_CAMERA_HW_Open() */

这个函数非常重要,它主要进行了以下几个动作,
1)通过kdModulePowerOn给Sensor上电
2)通过SensorFeatureControl读取SensorID 
先看kdModulePowerOn的实现

[cpp] view plain copy

  1. int
  2. kdModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM socketIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS],
  3. char sensorNameStr[KDIMGSENSOR_MAX_INVOKE_DRIVERS][32], BOOL On, char *mode_name)
  4. {
  5. MINT32 ret = ERROR_NONE;
  6. u32 i = 0;
  7. for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {
  8. if (g_bEnableDriver[i]) {
  9. /* PK_XLOG_INFO(“[%s][%d][%d][%s][%s]\r\n”,__FUNCTION__,g_bEnableDriver[i],socketIdx[i],sensorNameStr[i],mode_name); */
  10. #ifndef CONFIG_FPGA_EARLY_PORTING
  11. ret = _kdCISModulePowerOn(socketIdx[i], sensorNameStr[i], On, mode_name);
  12. #endif
  13. if (ERROR_NONE != ret) {
  14. PK_ERR(”[%s]”, __func__);
  15. return ret;
  16. }
  17. }
  18. }
  19. return ERROR_NONE;
  20. }
int
kdModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM socketIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS],char sensorNameStr[KDIMGSENSOR_MAX_INVOKE_DRIVERS][32], BOOL On, char *mode_name)
{MINT32 ret = ERROR_NONE;u32 i = 0;for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {if (g_bEnableDriver[i]) {/* PK_XLOG_INFO("[%s][%d][%d][%s][%s]\r\n",__FUNCTION__,g_bEnableDriver[i],socketIdx[i],sensorNameStr[i],mode_name); */

ifndef CONFIG_FPGA_EARLY_PORTING

        ret = _kdCISModulePowerOn(socketIdx[i], sensorNameStr[i], On, mode_name);
  • 1

endif

        if (ERROR_NONE != ret) {PK_ERR("[%s]", __func__);return ret;}}
}
return ERROR_NONE;

}在kdModulePowerOn中又调用_kdCISModulePowerOn

[cpp] view plain copy

  1. int _kdCISModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM SensorIdx, char *currSensorName, BOOL On,
  2. char *mode_name)
  3. {
  4. ….
  5. ret = kdCISModulePowerOn(SensorIdx, currSensorName, On, mode_name);
  6. ….
  7. return ret;
  8. }
int _kdCISModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM SensorIdx, char *currSensorName, BOOL On, char *mode_name) { ….
ret = kdCISModulePowerOn(SensorIdx, currSensorName, On, mode_name);
....
return ret;

}在kdCISModulePowerOn又调用kdCISModulePowerOn函数
文件:kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6580/camera_hw/kd_camera_hw.c
//改函数为上下电函数,通过传入BOOL值来判断上/下电

[cpp] view plain copy

  1. int kdCISModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM SensorIdx, char *currSensorName, BOOL On,
  2. char *mode_name)
  3. {
  4. u32 pinSetIdx = 0;  /* default main sensor */
  5. #define IDX_PS_CMRST 0
  6. #define IDX_PS_CMPDN 4
  7. #define IDX_PS_MODE 1
  8. #define IDX_PS_ON   2
  9. #define IDX_PS_OFF  3
  10. #define VOL_2800 2800000
  11. #define VOL_1800 1800000
  12. #define VOL_1500 1500000
  13. #define VOL_1200 1200000
  14. #define VOL_1000 1000000
  15. u32 pinSet[3][8] = {
  16. /* for main sensor */
  17. {       /* The reset pin of main sensor uses GPIO10 of mt6306, please call mt6306 API to set */
  18. CAMERA_CMRST_PIN,
  19. CAMERA_CMRST_PIN_M_GPIO,   /* mode */
  20. GPIO_OUT_ONE,  /* ON state */
  21. GPIO_OUT_ZERO, /* OFF state */
  22. CAMERA_CMPDN_PIN,
  23. CAMERA_CMPDN_PIN_M_GPIO,
  24. GPIO_OUT_ONE,
  25. GPIO_OUT_ZERO,
  26. },
  27. /* for sub sensor */
  28. {
  29. CAMERA_CMRST1_PIN,
  30. CAMERA_CMRST1_PIN_M_GPIO,
  31. GPIO_OUT_ONE,
  32. GPIO_OUT_ZERO,
  33. CAMERA_CMPDN1_PIN,
  34. CAMERA_CMPDN1_PIN_M_GPIO,
  35. GPIO_OUT_ONE,
  36. GPIO_OUT_ZERO,
  37. },
  38. /* for main_2 sensor */
  39. {
  40. GPIO_CAMERA_INVALID,
  41. GPIO_CAMERA_INVALID,   /* mode */
  42. GPIO_OUT_ONE,  /* ON state */
  43. GPIO_OUT_ZERO, /* OFF state */
  44. GPIO_CAMERA_INVALID,
  45. GPIO_CAMERA_INVALID,
  46. GPIO_OUT_ONE,
  47. GPIO_OUT_ZERO,
  48. }
  49. };
  50. if (DUAL_CAMERA_MAIN_SENSOR == SensorIdx)
  51. pinSetIdx = 0;
  52. else if (DUAL_CAMERA_SUB_SENSOR == SensorIdx)
  53. pinSetIdx = 1;
  54. else if (DUAL_CAMERA_MAIN_2_SENSOR == SensorIdx)
  55. pinSetIdx = 2;
  56. /* power ON */
  57. if (On) {
  58. #if 0
  59. ISP_MCLK1_EN(1);
  60. ISP_MCLK2_EN(1);
  61. ISP_MCLK3_EN(1);
  62. #else
  63. if (pinSetIdx == 0)
  64. ISP_MCLK1_EN(1);
  65. else if (pinSetIdx == 1)
  66. ISP_MCLK2_EN(1);
  67. #endif
  68. printk(”fangkuiccm %d ,currSensorName = %s pinSetIdx = %d ”,LINE,currSensorName,pinSetIdx );
  69. //通过DriverName来区分SensorIC
  70. if (currSensorName && (0 == strcmp(SENSOR_DRVNAME_GC2355_MIPI_RAW, currSensorName))) {
  71. /* First Power Pin low and Reset Pin Low */
  72. if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN])
  73. mtkcam_gpio_set(pinSetIdx, CAMPDN,
  74. pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]);
  75. if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST])
  76. mtkcam_gpio_set(pinSetIdx, CAMRST,
  77. pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_OFF]);
  78. mdelay(50);
  79. /* VCAM_A */
  80. if (TRUE != _hwPowerOn(VCAMA, VOL_2800)) {
  81. PK_DBG
  82. (”[CAMERA SENSOR] Fail to enable analog power (VCAM_A),power id = %d\n”,
  83. VCAMA);
  84. goto _kdCISModulePowerOn_exit;
  85. }
  86. mdelay(10);
  87. / VCAM_IO /
  88. if (TRUE != hwPowerOn(VCAMIO, VOL_1800)) {  
  89. PK_DBG
  90. (”[CAMERA SENSOR] Fail to enable IO power (VCAM_IO),power id = %d\n”,
  91. VCAMIO);
  92. goto _kdCISModulePowerOn_exit;
  93. }
  94. mdelay(10);
  95. if (TRUE != hwPowerOn(VCAMD, VOL_1500)) {  
  96. PK_DBG
  97. (”[CAMERA SENSOR] Fail to enable digital power (VCAM_D),power id = %d\n”,
  98. VCAMD);
  99. goto _kdCISModulePowerOn_exit;
  100. }
  101. mdelay(10);
  102. / AF_VCC /
  103. if (TRUE != hwPowerOn(VCAMAF, VOL_2800)) {  
  104. PK_DBG
  105. (”[CAMERA SENSOR] Fail to enable analog power (VCAM_AF),power id = %d\n”,
  106. VCAMAF);
  107. goto _kdCISModulePowerOn_exit;
  108. }
  109. mdelay(50);
  110. if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST]) {
  111. mtkcam_gpio_set(pinSetIdx, CAMRST,
  112. pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_OFF]);
  113. mdelay(5);
  114. mtkcam_gpio_set(pinSetIdx, CAMRST,
  115. pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_ON]);
  116. }
  117. mdelay(5);
  118. / enable active sensor /
  119. if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN]) {
  120. mtkcam_gpio_set(pinSetIdx, CAMPDN,
  121. pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_ON]);
  122. mdelay(5);
  123. mtkcam_gpio_set(pinSetIdx, CAMPDN,
  124. pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]);
  125. }
  126. mdelay(5);
  127. }
  128. }else{ //poweroff
  129. if (currSensorName   //上完电就要下电不然会造成漏电,最终会影响手机功耗
  130. && (0 == strcmp(SENSOR_DRVNAME_GC2355_MIPI_RAW, currSensorName))) {
  131. #if 0
  132. mt_set_gpio_mode(GPIO_SPI_MOSI_PIN, GPIO_MODE_00);
  133. mt_set_gpio_dir(GPIO_SPI_MOSI_PIN, GPIO_DIR_OUT);
  134. mt_set_gpio_out(GPIO_SPI_MOSI_PIN, GPIO_OUT_ONE);
  135. #endif
  136. / First Power Pin low and Reset Pin Low /
  137. if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN]) {
  138. if (mt_set_gpio_mode
  139. (pinSet[pinSetIdx][IDX_PS_CMPDN],
  140. pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_MODE])) {
  141. PK_DBG(”[CAMERA LENS] set gpio mode failed!! (CMPDN)\n”);
  142. }
  143. if (mt_set_gpio_dir(pinSet[pinSetIdx][IDX_PS_CMPDN], GPIO_DIR_OUT)) {
  144. PK_DBG(”[CAMERA LENS] set gpio dir failed!! (CMPDN)\n”);
  145. }
  146. if (mt_set_gpio_out
  147. (pinSet[pinSetIdx][IDX_PS_CMPDN],
  148. pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF])) {
  149. PK_DBG(”[CAMERA LENS] set gpio failed!! (CMPDN)\n”);
  150. }
  151. }
  152. }
  153. }
int kdCISModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM SensorIdx, char *currSensorName, BOOL On, char *mode_name) {
  • 1
  • 2
u32 pinSetIdx = 0;  /* default main sensor */
  • 1

define IDX_PS_CMRST 0

define IDX_PS_CMPDN 4

define IDX_PS_MODE 1

define IDX_PS_ON 2

define IDX_PS_OFF 3

define VOL_2800 2800000

define VOL_1800 1800000

define VOL_1500 1500000

define VOL_1200 1200000

define VOL_1000 1000000

u32 pinSet[3][8] = {/* for main sensor */{       /* The reset pin of main sensor uses GPIO10 of mt6306, please call mt6306 API to set */CAMERA_CMRST_PIN,CAMERA_CMRST_PIN_M_GPIO,   /* mode */GPIO_OUT_ONE,  /* ON state */GPIO_OUT_ZERO, /* OFF state */CAMERA_CMPDN_PIN,CAMERA_CMPDN_PIN_M_GPIO,GPIO_OUT_ONE,GPIO_OUT_ZERO,},/* for sub sensor */{CAMERA_CMRST1_PIN,CAMERA_CMRST1_PIN_M_GPIO,GPIO_OUT_ONE,GPIO_OUT_ZERO,CAMERA_CMPDN1_PIN,CAMERA_CMPDN1_PIN_M_GPIO,GPIO_OUT_ONE,GPIO_OUT_ZERO,},/* for main_2 sensor */{GPIO_CAMERA_INVALID,GPIO_CAMERA_INVALID,   /* mode */GPIO_OUT_ONE,  /* ON state */GPIO_OUT_ZERO, /* OFF state */GPIO_CAMERA_INVALID,GPIO_CAMERA_INVALID,GPIO_OUT_ONE,GPIO_OUT_ZERO,}
};if (DUAL_CAMERA_MAIN_SENSOR == SensorIdx)pinSetIdx = 0;
else if (DUAL_CAMERA_SUB_SENSOR == SensorIdx)pinSetIdx = 1;
else if (DUAL_CAMERA_MAIN_2_SENSOR == SensorIdx)pinSetIdx = 2;/* power ON */
if (On) {

if 0

    ISP_MCLK1_EN(1);ISP_MCLK2_EN(1);ISP_MCLK3_EN(1);

else

    if (pinSetIdx == 0)ISP_MCLK1_EN(1);else if (pinSetIdx == 1)ISP_MCLK2_EN(1);

endif

printk("fangkuiccm %d ,currSensorName = %s pinSetIdx = %d ",__LINE__,currSensorName,pinSetIdx );//通过DriverName来区分SensorIC
if (currSensorName &amp;&amp; (0 == strcmp(SENSOR_DRVNAME_GC2355_MIPI_RAW, currSensorName))) {/* First Power Pin low and Reset Pin Low */if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN])mtkcam_gpio_set(pinSetIdx, CAMPDN,pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]);if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST])mtkcam_gpio_set(pinSetIdx, CAMRST,pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_OFF]);mdelay(50);/* VCAM_A */if (TRUE != _hwPowerOn(VCAMA, VOL_2800)) {PK_DBG("[CAMERA SENSOR] Fail to enable analog power (VCAM_A),power id = %d\n",VCAMA);goto _kdCISModulePowerOn_exit_;}mdelay(10);/* VCAM_IO */if (TRUE != _hwPowerOn(VCAMIO, VOL_1800)) {PK_DBG("[CAMERA SENSOR] Fail to enable IO power (VCAM_IO),power id = %d\n",VCAMIO);goto _kdCISModulePowerOn_exit_;}mdelay(10);if (TRUE != _hwPowerOn(VCAMD, VOL_1500)) {PK_DBG("[CAMERA SENSOR] Fail to enable digital power (VCAM_D),power id = %d\n",VCAMD);goto _kdCISModulePowerOn_exit_;}mdelay(10);/* AF_VCC */if (TRUE != _hwPowerOn(VCAMAF, VOL_2800)) {PK_DBG("[CAMERA SENSOR] Fail to enable analog power (VCAM_AF),power id = %d\n",VCAMAF);goto _kdCISModulePowerOn_exit_;}mdelay(50);if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST]) {mtkcam_gpio_set(pinSetIdx, CAMRST,pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_OFF]);mdelay(5);mtkcam_gpio_set(pinSetIdx, CAMRST,pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_ON]);}mdelay(5);/* enable active sensor */if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN]) {mtkcam_gpio_set(pinSetIdx, CAMPDN,pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_ON]);mdelay(5);mtkcam_gpio_set(pinSetIdx, CAMPDN,pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]);}mdelay(5);}
}else{ //poweroffif (currSensorName   //上完电就要下电不然会造成漏电,最终会影响手机功耗&amp;&amp; (0 == strcmp(SENSOR_DRVNAME_GC2355_MIPI_RAW, currSensorName))) {

if 0

        mt_set_gpio_mode(GPIO_SPI_MOSI_PIN, GPIO_MODE_00);mt_set_gpio_dir(GPIO_SPI_MOSI_PIN, GPIO_DIR_OUT);mt_set_gpio_out(GPIO_SPI_MOSI_PIN, GPIO_OUT_ONE);

endif

        /* First Power Pin low and Reset Pin Low */if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN]) {if (mt_set_gpio_mode(pinSet[pinSetIdx][IDX_PS_CMPDN],pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_MODE])) {PK_DBG("[CAMERA LENS] set gpio mode failed!! (CMPDN)\n");}if (mt_set_gpio_dir(pinSet[pinSetIdx][IDX_PS_CMPDN], GPIO_DIR_OUT)) {PK_DBG("[CAMERA LENS] set gpio dir failed!! (CMPDN)\n");}if (mt_set_gpio_out(pinSet[pinSetIdx][IDX_PS_CMPDN],pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF])) {PK_DBG("[CAMERA LENS] set gpio failed!! (CMPDN)\n");}}
}

}上电操作完成后,紧接着读取SensorID,通用驱动使用SensorFeatureControl来读取ID如:
 g_pSensorFunc->SensorFeatureControl(g_invokeSocketIdx[i],
SENSOR_FEATURE_CHECK_SENSOR_ID,
(MUINT8 *) &sensorID,
&retLen);
这步操作会调用GC2355中的feature_control函数如下:
文件:kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6580/gc2355_mipi_raw/gc2355mipi_Sensor.c

[cpp] view plain copy

  1. static kal_uint32 feature_control(MSDK_SENSOR_FEATURE_ENUM feature_id,
  2. UINT8 *feature_para,UINT32 *feature_para_len)
  3. {
  4. ….
  5. LOG_INF(”feature_id = %d\n”, feature_id);
  6. switch (feature_id) {
  7. ….
  8. case SENSOR_FEATURE_CHECK_SENSOR_ID:
  9. get_imgsensor_id(feature_return_para_32);
  10. break;
  11. ….
  12. default:
  13. break;
  14. }
  15. return ERROR_NONE;
  16. }
static kal_uint32 feature_control(MSDK_SENSOR_FEATURE_ENUM feature_id, UINT8 *feature_para,UINT32 *feature_para_len) { …. LOG_INF(“feature_id = %d\n”, feature_id); switch (feature_id) { …. case SENSOR_FEATURE_CHECK_SENSOR_ID: get_imgsensor_id(feature_return_para_32); break; …. default: break; }
return ERROR_NONE;
  • 1

}

优化传入的cmd为SENSOR_FEATURE_CHECK_SENSOR_ID,则会调用feature_control中的

get_imgsensor_id再看get_imgsensor_id的实现

[cpp] view plain copy

  1. static kal_uint32 get_imgsensor_id(UINT32 *sensor_id)
  2. {
  3. kal_uint8 i = 0;
  4. kal_uint8 retry = 2;
  5. //sensor have two i2c address 0x6c 0x6d & 0x21 0x20, we should detect the module used i2c address
  6. while (imgsensor_info.i2c_addr_table[i] != 0xff) {
  7. spin_lock(&imgsensor_drv_lock);
  8. imgsensor.i2c_write_id = imgsensor_info.i2c_addr_table[i];
  9. spin_unlock(&imgsensor_drv_lock);
  10. do {
  11. *sensor_id = return_sensor_id(); //return_sensor_id读取IC的ID
  12. if (*sensor_id == imgsensor_info.sensor_id) {
  13. LOG_INF(”i2c write id: 0x%x, sensor id: 0x%x\n”, imgsensor.i2c_write_id,*sensor_id);
  14. return ERROR_NONE;
  15. }
  16. LOG_INF(”Read sensor id fail, write id: 0x%x, id: 0x%x\n”, imgsensor.i2c_write_id,*sensor_id);
  17. retry–;
  18. } while(retry > 0);
  19. i++;
  20. retry = 2;
  21. }
  22. ….
  23. return ERROR_NONE;
  24. }
static kal_uint32 get_imgsensor_id(UINT32 *sensor_id)
{kal_uint8 i = 0;kal_uint8 retry = 2;//sensor have two i2c address 0x6c 0x6d & 0x21 0x20, we should detect the module used i2c addresswhile (imgsensor_info.i2c_addr_table[i] != 0xff) {spin_lock(&imgsensor_drv_lock);imgsensor.i2c_write_id = imgsensor_info.i2c_addr_table[i];spin_unlock(&imgsensor_drv_lock);do {*sensor_id = return_sensor_id(); //return_sensor_id读取IC的IDif (*sensor_id == imgsensor_info.sensor_id) {LOG_INF("i2c write id: 0x%x, sensor id: 0x%x\n", imgsensor.i2c_write_id,*sensor_id);return ERROR_NONE;}LOG_INF("Read sensor id fail, write id: 0x%x, id: 0x%x\n", imgsensor.i2c_write_id,*sensor_id);retry--;} while(retry > 0);i++;retry = 2;}....return ERROR_NONE;
}

再看return_sensor_id的实现

[cpp] view plain copy

  1. static kal_uint32 return_sensor_id(void)
  2. {
  3. return ((read_cmos_sensor(0xf0) << 8) | read_cmos_sensor(0xf1));
  4. }
  5. static kal_uint16 read_cmos_sensor(kal_uint32 addr)
  6. {
  7. kal_uint16 get_byte=0;
  8. char pu_send_cmd[1] = {(char)(addr & 0xFF) };
  9. iReadRegI2C(pu_send_cmd, 1, (u8*)&get_byte, 1, imgsensor.i2c_write_id);
  10. return get_byte;
  11. }
static kal_uint32 return_sensor_id(void)
{return ((read_cmos_sensor(0xf0) << 8) | read_cmos_sensor(0xf1));
}
static kal_uint16 read_cmos_sensor(kal_uint32 addr)
{kal_uint16 get_byte=0;char pu_send_cmd[1] = {(char)(addr & 0xFF) };iReadRegI2C(pu_send_cmd, 1, (u8*)&get_byte, 1, imgsensor.i2c_write_id);return get_byte;}

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

[cpp] view plain copy

  1. int iReadRegI2C(u8 *a_pSendData, u16 a_sizeSendData, u8 *a_pRecvData, u16 a_sizeRecvData,
  2. u16 i2cId)
  3. {
  4. int i4RetValue = 0;
  5. if (gI2CBusNum == SUPPORT_I2C_BUS_NUM1) {
  6. spin_lock(&kdsensor_drv_lock);
  7. g_pstI2Cclient->addr = (i2cId >> 1);
  8. g_pstI2Cclient->ext_flag = (g_pstI2Cclient->ext_flag) & (~I2C_DMA_FLAG);
  9. /* Remove i2c ack error log during search sensor */
  10. /* PK_ERR(“g_pstI2Cclient->ext_flag: %d”, g_IsSearchSensor); */
  11. if (g_IsSearchSensor == 1) {
  12. g_pstI2Cclient->ext_flag = (g_pstI2Cclient->ext_flag) | I2C_A_FILTER_MSG;
  13. } else {
  14. g_pstI2Cclient->ext_flag = (g_pstI2Cclient->ext_flag) & (~I2C_A_FILTER_MSG);
  15. }
  16. spin_unlock(&kdsensor_drv_lock);
  17. /*  */
  18. i4RetValue = i2c_master_send(g_pstI2Cclient, a_pSendData, a_sizeSendData);
  19. if (i4RetValue != a_sizeSendData) {
  20. PK_ERR(”[CAMERA SENSOR] I2C send failed!!, Addr = 0x%x\n”, a_pSendData[0]);
  21. return -1;
  22. }
  23. i4RetValue = i2c_master_recv(g_pstI2Cclient, (char *)a_pRecvData, a_sizeRecvData);
  24. if (i4RetValue != a_sizeRecvData) {
  25. PK_ERR(”[CAMERA SENSOR] I2C read failed!!\n”);
  26. return -1;
  27. }
  28. } else {
  29. spin_lock(&kdsensor_drv_lock);
  30. g_pstI2Cclient2->addr = (i2cId >> 1);
  31. /* Remove i2c ack error log during search sensor */
  32. /* PK_ERR(“g_pstI2Cclient2->ext_flag: %d”, g_IsSearchSensor); */
  33. if (g_IsSearchSensor == 1) {
  34. g_pstI2Cclient2->ext_flag = (g_pstI2Cclient2->ext_flag) | I2C_A_FILTER_MSG;
  35. } else {
  36. g_pstI2Cclient2->ext_flag = (g_pstI2Cclient2->ext_flag) & (~I2C_A_FILTER_MSG);
  37. }
  38. spin_unlock(&kdsensor_drv_lock);
  39. i4RetValue = i2c_master_send(g_pstI2Cclient2, a_pSendData, a_sizeSendData);
  40. if (i4RetValue != a_sizeSendData) {
  41. PK_ERR(”[CAMERA SENSOR] I2C send failed!!, Addr = 0x%x\n”, a_pSendData[0]);
  42. return -1;
  43. }
  44. i4RetValue = i2c_master_recv(g_pstI2Cclient2, (char *)a_pRecvData, a_sizeRecvData);
  45. if (i4RetValue != a_sizeRecvData) {
  46. PK_ERR(”[CAMERA SENSOR] I2C read failed!!\n”);
  47. return -1;
  48. }
  49. }
  50. return 0;
  51. }
int iReadRegI2C(u8 *a_pSendData, u16 a_sizeSendData, u8 *a_pRecvData, u16 a_sizeRecvData,u16 i2cId)
{int i4RetValue = 0;if (gI2CBusNum == SUPPORT_I2C_BUS_NUM1) {spin_lock(&kdsensor_drv_lock);g_pstI2Cclient->addr = (i2cId >> 1);g_pstI2Cclient->ext_flag = (g_pstI2Cclient->ext_flag) & (~I2C_DMA_FLAG);/* 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);}spin_unlock(&kdsensor_drv_lock);/*  */i4RetValue = i2c_master_send(g_pstI2Cclient, a_pSendData, a_sizeSendData);if (i4RetValue != a_sizeSendData) {PK_ERR("[CAMERA SENSOR] I2C send failed!!, Addr = 0x%x\n", a_pSendData[0]);return -1;}i4RetValue = i2c_master_recv(g_pstI2Cclient, (char *)a_pRecvData, a_sizeRecvData);if (i4RetValue != a_sizeRecvData) {PK_ERR("[CAMERA SENSOR] I2C read failed!!\n");return -1;}} else {spin_lock(&kdsensor_drv_lock);g_pstI2Cclient2->addr = (i2cId >> 1);/* 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;}i4RetValue = i2c_master_recv(g_pstI2Cclient2, (char *)a_pRecvData, a_sizeRecvData);if (i4RetValue != a_sizeRecvData) {PK_ERR("[CAMERA SENSOR] I2C read failed!!\n");return -1;}}return 0;
}

这一步完成I2c的读取,也就是说如果I2c配置正确,并且上电正确,到这一步就可以正确的读取ID,

整个camera也就基本就调通了。

三、总结

通过上述分析,我们可以看出,camera驱动先是注册平台驱动,再注册I2c驱动,然后又为前后摄

注册字符设备,封装底层方法,上层访问底层驱动时候显示使用setdriver将具体IC的驱动入口获取,

然后使用checkisalive对sensorlist中的IC进行上电,上电完成就读取设备ID,到此为止,上层应用与

底层驱动挂接完成,紧接着就是预览和拍照,不过这都是具体IC驱动的实现了。

本人建了个android camera系统 微信群,不过现在群成员超200了,不能通过二维码扫码加入,有兴趣的,可以加我微信号:xuhui_7810,到时拉你们入群。

MTK6580(Android6.0)-camera 驱动分析相关推荐

  1. [RK3288][Android6.0] AT24C02驱动分析及功能增加小结

    Platform: Rockchip OS: Android 6.0 Kernel: 3.10.92 Spec: 网上很多,如 https://wenku.baidu.com/view/0020131 ...

  2. android6.0源码分析之Camera API2.0下的Preview(预览)流程分析

    1.Camera2 preview的应用层流程分析 preview流程都是从startPreview开始的,所以来看startPreview方法的代码: <code class="hl ...

  3. android6.0源码分析之Camera API2.0下的初始化流程分析

    1.Camera2初始化的应用层流程分析 Camera2的初始化流程与Camera1.0有所区别,本文将就Camera2的内置应用来分析Camera2.0的初始化过程.Camera2.0首先启动的是C ...

  4. android6.0源码分析之Camera2 HAL分析

    1.Camera HAL的初始化 Camera HAL的初始加载是在Native的CameraService初始化流程中的,而CameraService初始化是在Main_mediaServer.cp ...

  5. android6.0源码分析之Zygote进程分析

    在android6.0源码分析之Runtime的初始化一文中,对Zygote进程的初期的Runtime初始化过程进行了分析,在Runtime启动结束后,会对Zygote进程进行初始化,其它Java进程 ...

  6. android6.0源码分析之Runtime的初始化

    Android运行时作为android架构的一部分,起着非常重要的作用,它和核心库(Core Libraries)组成了Android运行时库层.本文将依据android源码对AndroidRunti ...

  7. Android Camera驱动分析

    文章目录 一.Camera的硬件接口 二.代码路径 三.Camera代码分析 1.硬件接口设置 2.Camera设备驱动 3.模组驱动代码 一.Camera的硬件接口 引脚 名称及作用 VCAMA 就 ...

  8. Android6.0源码分析—— Zygote进程分析(补充)

    原文地址: http://blog.csdn.net/a34140974/article/details/50915307 此博文为<Android5.0源码分析-- Zygote进程分析> ...

  9. android6.0源码分析之AMS服务源码分析

    activitymanagerservice服务源码分析 1.ActivityManagerService概述 ActivityManagerService(以下简称AMS)作为Android中最核心 ...

最新文章

  1. 不改一行代码定位线上性能问题
  2. node.js 搭建blog
  3. php ip to int_ip地址和int相互转换
  4. opengl加载显示3D模型ase类型文件
  5. 约束,MySQL约束,非空默认值,主键外键唯一自增,完整详细可收藏
  6. 计算机专业sci二区论文难吗,通信专业二区sci难吗
  7. Python_大众点评网站数据爬虫
  8. python tqdm自定义更新进度条
  9. 5009. tinyfsm有限状态机
  10. 我的世界服务器为什么显示崩溃,我的世界服务器崩溃的指令 | 手游网游页游攻略大全...
  11. matplotlib制作多张图
  12. Mail_Android_Video_SW_DDK_Intergration_Guide_And_Codec_User_Manual中文翻译【chapter2】
  13. Python脚本之批量重命名文件
  14. revit常用机电工具,如何实现管线快速翻弯
  15. 和睦家 php研发,豹小秘落户和睦家,探索医疗场景新应用
  16. 通过Hook进行游戏的全局加速
  17. 微信小程序云开发(2)— 云数据库
  18. OFFICE 您正试图运行的函数包含有宏或需要宏语言的解决方法
  19. VB中ByVal与ByRef有什么区别
  20. VERTU全球首款WEB3手机METAVERTU伦敦亮相

热门文章

  1. Bean Searcher——多条件查询神器
  2. 新零售电商系统都包含哪些功能
  3. 常用视频会议产品对比分析
  4. 【软件测试】测试外包,我们该去吗?看看资深测试工程师的见解......
  5. 小白的《HTML5权威指南》笔记(第一部分)
  6. 咕泡-spring中常用设计模式概述
  7. WebKit技术内幕
  8. RAD Studio 10.3.x RIO 常规快捷键操作
  9. 全国及重点城市适婚人口占比数据(2009-2019年)
  10. 电脑上将PPT转换成PDF格式方法