MTK6580(Android6.0)-camera 驱动分析

    xiaoxiao2025-04-29  7

    一、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 int32_t CamDeviceManagerBase:: getNumberOfDevices() { ... mi4DeviceNum = enumDeviceLocked(); ... } 文件:vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6580/devicemgr/CamDeviceManagerImp.cpp 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 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 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 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[] = { //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), #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[] = { {.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 } }; 副摄平台驱动的定义: #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中定义设备信息: 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的实现如下: 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, }; 对应main/sub camera i2c 设备dts定义如下 文件:kernel-3.18/arch/arm/boot/dts/cust_i2c.dtsi &i2c0 { camera_main@10 { compatible = "mediatek,camera_main"; //和 CAMERA_HW_i2c_driver定义的一致 reg = <0x10>; }; camera_main_af@0c { compatible = "mediatek,camera_main_af"; reg = <0x0c>; }; camera_sub@3c { compatible = "mediatek,camera_sub"; //和CAMERA_HW_i2c_driver2定义的一致 reg = <0x3c>; }; }; 3. I2c probe的实现

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

    (如何匹配本章不作分析)成功后,会调用各自的i2c_probe函数。main sensor 的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; } sub sensor 的probe函数CAMERA_HW_i2c_probe2: 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函数实现如下: 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_bus2 sensor_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, #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, #endif };

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

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

    /******************************************************************************* * 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接口 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的实现: 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 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}, #endif .... } 获取列表之后紧接着调用各自的Init函数,这里以GC2355为例 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_Feature

    Control接口

    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 result g_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的实现 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); #endif if (ERROR_NONE != ret) { PK_ERR("[%s]", __func__); return ret; } } } return ERROR_NONE; } 在kdModulePowerOn中又调用_kdCISModulePowerOn 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值来判断上/下电 int kdCISModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM SensorIdx, char *currSensorName, BOOL On, char *mode_name) { u32 pinSetIdx = 0; /* default main sensor */ #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 && (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{ //poweroff if (currSensorName //上完电就要下电不然会造成漏电,最终会影响手机功耗 && (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 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; }

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

    get_imgsensor_id再看get_imgsensor_id的实现

    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 address while (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的ID if (*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的实现 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 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驱动的实现了。

    转载请注明原文地址: https://ju.6miu.com/read-1298577.html
    最新回复(0)