一.開機camera啟動流程framework到hal
Main_mediaserver.cpp (frameworks\av\media\mediaserver)
CameraService::instantiate();
//mediaserver的main函數中調用了CameraService的instantiate函數來創建實例,該函數的實現在其父類BinderService中實現
//CameraService.cpp (frameworks\av\services\camera\libcameraservice)
CameraService::onFirstRef
// Update battery life tracking if service is restarting
BatteryNotifier& notifier(BatteryNotifier::getInstance());
notifier.noteResetCamera();
notifier.noteResetFlashlight();
//通過hw_get_module函數加載了一個hw_module_t模塊,這個模塊是與hal層對接的接口,ID為CAMERA_HARDWARE_MODULE_ID,並將它保存在mModule成員變量中。
int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&rawModule);
mModule = new CameraModule(rawModule);
err = mModule->init();
//通過mModule->get_number_of_cameras函數進入到hal層,獲取到了camera的個數。這個函數很重要,對於frameworks層來說只是拿到了camera的個數,
//但對於hal層和drivers層來說Camera的上電和初始化流程都是從這里開始的
mNumberOfCameras = mModule->getNumberOfCameras();
//CameraModule.cpp (frameworks\av\services\camera\libcameraservice\common)
return mModule->get_number_of_cameras(); //調用到HAL層
Module.h (vendor\mediatek\proprietary\hardware\mtkcam\legacy\module_hal\module)
NSCam::getCamDeviceManager()->getNumberOfDevices();
//CamDeviceManagerImp.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6735\devicemgr)
&gCamDeviceManager;
getNumberOfDevices
//CamDeviceManagerBase.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\module_hal\devicemgr)
mi4DeviceNum = enumDeviceLocked();
//CamDeviceManagerImp.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6735\devicemgr)
IHalSensorList*const pHalSensorList = IHalSensorList::get();
size_t const sensorNum = pHalSensorList->searchSensors(); //搜索看從HAL層開始分析
具體分析可以參考
http://blog.csdn.net/eternity9255/article/details/52085864
二.開機打開sensor總結
- HAL層運行Search sensor這個線程
- HAL層遍歷sensorlist列表並掛載HAL層性能3A等一些參數獲取的接口
- HAL層下達setDriver的cmd,並下傳正在遍歷的sensorlist列表中的ID
- Driver層根據這個ID,掛載Driver層sensorlist中對應的Sensorlist中對應的Sensor和具體Sensor底層操作接口
- HAL層對正確遍歷的sensor下達check ID的指令
- Driver層為對應sensor上電,通過I2C讀取預存在寄存器中的sensor id
- 比較讀取結果,不匹配,return error,繼續遍歷
- 匹配,HAL層下達其他指令收集sensor信息
- sensor下電
kdSetDriver()函數有一個參數,這個參數是由impSearchSensor()傳下來的,如果主(后)camera,那么這個值是10000、10001、10002等,如果是次(前)camera,那么這個值是20000、20001、20002等
如果是后camera,那么g_invokeSocketIdx[0]的值應為1,如果是前camera,那么應是2。而drvIdx[0]的值是sensor驅動列表的索引號,例如0、1、2等。
這就是找到一個sensor的流程,先主(后)camera,后次(前)camera。
找后camera,會遍歷一遍sensor列表,找前camera,再遍歷一遍sensor列表,注意模塊的上電,id值的讀取。
找后camera,會遍歷一遍sensor列表,找前camera,再遍歷一遍sensor列表,注意模塊的上電,id值的讀取。
1.從HAL層開始分析
CamDeviceManagerImp.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6735\devicemgr)的enumDeviceLocked()函數
pHalSensorList->searchSensors() 將調用SensorDrv::searchSensor(NULL)函數,該函數再調用ImgSensor_drv.cpp文件中中的ImgSensorDrv::impSearchSensor函數
enumDeviceLocked()
sensorNum = pHalSensorList->searchSensors();
//Imgsensor_drv.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6735\hal\sensor)
ImgSensorDrv::impSearchSensor
//If imp sensor search process already done before,only need to return the sensorDevs, not need to search again.
//如果已經運行了搜索進程,就不會再進程搜索,直接返回。
GetSensorInitFuncList(&m_pstSensorInitFunc); //沒有搜索的情況下,調用這個函數,單獨分析1
sprintf(cBuf,"/dev/%s",CAMERA_HW_DEVNAME); //這個宏在device/mediatek/common/kernel-headers/kd_imgsensor.h中
#define CAMERA_HW_DEVNAME "kd_camera_hw"
m_fdSensor = ::open(cBuf, O_RDWR); //打開/dev/kd_camera_hw節點,在Kd_sensorlist.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)生成 的file_operations的open
for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) //MAX_NUM_OF_SUPPORT_SENSOR是32個
//在device/mediatek/common/kernel-headers/kd_imgsensor_define.h中
#define KDIMGSENSOR_INVOKE_DRIVER_0 (0)
#define KDIMGSENSOR_DUAL_SHIFT 16
DUAL_CAMERA_MAIN_SENSOR = 1
////因為前面SensorEnum = (MUINT32)DUAL_CAMERA_MAIN_SENSOR;,所以SensorEnum = 1;
id[KDIMGSENSOR_INVOKE_DRIVER_0] = (SensorEnum << KDIMGSENSOR_DUAL_SHIFT) | i; 化簡==>id[0] = 0x10000 | i;
err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] ); //獲取底層的攝像頭相應的操作函數
err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE); //檢測攝像頭是否存在,主要是讀ID
sensorType = this->getCurrentSensorType((SENSOR_DEV_ENUM)SensorEnum);
getInfo(scenarioId, m_psensorInfo, m_psensorConfigData)
ioctl(m_fdSensor, KDIMGSENSORIOC_X_GETINFO , &getInfo); //得到sensor的信息
socketPos = this->getSocketPosition((CAMERA_DUAL_CAMERA_SENSOR_ENUM)SensorEnum);
err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_GET_SOCKET_POS , &socketPos); //得到分辨率
//保存一些信息
m_mainSensorDrv.index[m_mainSensorDrv.number] = i;
m_mainSensorDrv.position = socketPos;
。。。。。。。。。。。。。。。
//close system call may be off sensor power. check first!!!
::close(m_fdSensor);
err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_CURRENT_SENSOR, &sensorIdx);
err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CLOSE); //關閉攝像頭
單獨分析1
GetSensorInitFuncList(&m_pstSensorInitFunc); //沒有搜索的情況下,調用這個函數,單獨分析
//Sensorlist.cpp (vendor\mediatek\proprietary\custom\mt6735\hal\d1\imgsensor_src)
GetSensorInitFuncList //調用這個函數,獲取hal層sensor列表
MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] = {
#if defined(GC5005_MIPI_RAW)
RAW_INFO(GC5005_SENSOR_ID, SENSOR_DRVNAME_GC5005_MIPI_RAW,NULL), //單獨分析2
#endif
}
//單獨分析2
RAW_INFO和YUV_INFO
#define YUV_INFO(_id, name, getCalData)\ //
{ \
_id, name, \
NSFeature::YUVSensorInfo<_id>::createInstance(name, #name), \
(NSFeature::SensorInfoBase*(*)()) \
NSFeature::YUVSensorInfo<_id>::getInstance, \
NSFeature::YUVSensorInfo<_id>::getDefaultData, \
getCalData, \
NSFeature::YUVSensorInfo<_id>::getNullFlickerPara \
#define RAW_INFO(_id, name, getCalData)\
{ \
_id, name, \
NSFeature::RAWSensorInfo<_id>::createInstance(name, #name), \
(NSFeature::SensorInfoBase*(*)()) \
NSFeature::RAWSensorInfo<_id>::getInstance, \
NSFeature::RAWSensorInfo<_id>::getDefaultData, \
getCalData, \
NSFeature::RAWSensorInfo<_id>::getFlickerPara \
}
根據不同的sensor類型使用RAW_INFO或YUV_INFO,再根據ID和name生成結構體,所以ID和NAME需要唯一。
二.驅動分析
Kd_sensorlist.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)
1.初始化
static struct platform_device camerahw_platform_device = {
.name = "image_sensor",
.id = 0,
.dev = {
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
static struct platform_device camerahw2_platform_device = {
.name = "image_sensor_bus2",
.id = 0,
.dev = {
}
};
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
}
};
tatic 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
CAMERA_HW_i2C_init
platform_device_register(&camerahw_platform_device); //注冊device
platform_device_register(&camerahw2_platform_device);
platform_driver_register(&g_stCAMERA_HW_Driver) //注冊driver,進入CAMERA_HW_probe
platform_driver_register(&g_stCAMERA_HW_Driver2) ////注冊driver,進入CAMERA_HW_probe2
proc_create("driver/camsensor", 0, NULL, &fcamera_proc_fops); // proc/driver/camsensor調試文件節點,寫寄存器
proc_create("driver/camsensor2", 0, NULL, &fcamera_proc_fops2);
proc_create("driver/camsensor3", 0, NULL, &fcamera_proc_fops3);
proc_create(PROC_CAMERA_INFO, 0, NULL, &fcamera_proc_fops1); //#define PROC_CAMERA_INFO "driver/camera_info",讀取攝像頭信息
2.平台probe函數
truct 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,
};
CAMERA_HW_probe
mtkcam_gpio_init(pdev); //獲取DTS的端口
camctrl = devm_pinctrl_get(&pdev->dev);
cam0_pnd_h = pinctrl_lookup_state(camctrl, "cam0_pnd1");
i2c_add_driver(&CAMERA_HW_i2c_driver); //注冊I2C設備,進入I2C的CAMERA_HW_i2c_probe函數
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,
};
CAMERA_HW_probe2
i2c_add_driver(&CAMERA_HW_i2c_driver2); //注冊
3.I2C的probe函數
static const struct file_operations g_stCAMERA_HW_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
CAMERA_HW_i2c_probe
/* set I2C clock rate */
g_pstI2Cclient2->timing = 100;/* 100k */
/* Register char driver */
RegisterCAMERA_HWCharDrv();、
alloc_chrdev_region(&g_CAMERA_HWdevno, 0, 1, CAMERA_HW_DRVNAME1) // #define CAMERA_HW_DRVNAME1 "kd_camera_hw"
g_pCAMERA_HW_CharDrv = cdev_alloc(); ///* Allocate driver */
cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops); //設置操作函數
cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1) //添加到系統
sensor_class = class_create(THIS_MODULE, "sensordrv"); //sysfs類型
device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1); //sysfs節點
static const struct file_operations g_stCAMERA_HW_fops0 = {
.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
};
CAMERA_HW_i2c_probe2
g_pstI2Cclient2->timing = 100;/* 100k */
RegisterCAMERA_HWCharDrv2();
alloc_chrdev_region(&g_CAMERA_HWdevno2, 0, 1, CAMERA_HW_DRVNAME2) //#define CAMERA_HW_DRVNAME2 "kd_camera_hw_bus2"
g_pCAMERA_HW_CharDrv2 = cdev_alloc();
cdev_init(g_pCAMERA_HW_CharDrv2, &g_stCAMERA_HW_fops0); //操作函數
cdev_add(g_pCAMERA_HW_CharDrv2, g_CAMERA_HWdevno2, 1)
sensor2_class = class_create(THIS_MODULE, "sensordrv2");
device_create(sensor2_class, NULL, g_CAMERA_HWdevno2, NULL, CAMERA_HW_DRVNAME2);
四.驅動層給HAL層提供的IOCTL函數
Kd_sensorlist.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)
CAMERA_HW_Ioctl
_IOC_NONE == _IOC_DIR(a_u4Command) // 獲取讀寫屬性域值 (bit30 ~ bit31)
pBuff = kmalloc(_IOC_SIZE(a_u4Command), GFP_KERNEL); //分配4個字節
if (_IOC_WRITE & _IOC_DIR(a_u4Command)) //如果是寫
copy_from_user(pBuff , (void *) a_u4Param, _IOC_SIZE(a_u4Command)) //拷貝用戶空間的數據
switch (a_u4Command) //執行IOCTL
case KDIMGSENSORIOC_X_SET_DRIVER: //設置對應攝像頭的操作函數
i4RetValue = kdSetDriver((unsigned int *)pBuff); //單獨分析1,這個pBuff是從上層傳下來的
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE: //檢查攝像頭是否存在,上電和讀取id
i4RetValue = adopt_CAMERA_HW_CheckIsAlive(); //單獨分析2
case KDIMGSENSORIOC_X_GETINFO: //獲取攝像頭信息
i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);
g_pSensorFunc->SensorGetInfo(pScenarioId, pInfo, pConfig);
SensorGetInfo //調用具體攝像頭驅動的SensorGetInfo
copy_to_user((void __user *)(pSensorGetInfo->pInfo[i]), (void *)pInfo[i] , sizeof(MSDK_SENSOR_INFO_STRUCT)) /* SenorInfo */
copy_to_user((void __user *)(pSensorGetInfo->pConfig[i]) , (void *)pConfig[i] , sizeof(MSDK_SENSOR_CONFIG_STRUCT)) /* SensorConfig */
case KDIMGSENSORIOC_X_SET_CURRENT_SENSOR: //設置現在的攝像頭id
i4RetValue = kdSetCurrentSensorIdx(*pIdx);
g_CurrentSensorIdx = idx;
case KDIMGSENSORIOC_T_CLOSE: //關閉攝像頭
i4RetValue = adopt_CAMERA_HW_Close();
g_pSensorFunc->SensorClose(); //調用具體的攝像頭的函數
static SENSOR_FUNCTION_STRUCT sensor_func = {
open,
get_info,
get_resolution,
feature_control,
control,
close
};
//單獨分析1
kdSetDriver
kdGetSensorInitFuncList(&pSensorList) //得到sensor列表
*ppSensorList = &kdSensorList[0]; //Kd_sensorlist.h (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)中的
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] = {
#if defined(IMX220_MIPI_RAW)
{IMX220_SENSOR_ID, SENSOR_DRVNAME_IMX220_MIPI_RAW, IMX220_MIPI_RAW_SensorInit},
#endif
}
for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) //化簡得到==> for(i=0;i<2;i++)
g_bEnableDriver[i] = FALSE;
//化簡下面的==》g_invokeSocketIdx[i] = (CAMERA_DUAL_CAMERA_SENSOR_ENUM)((pDrvIndex[i] & 0xFFFF0000) >> 16); 得到高16位是1還是2,1就是主攝像頭
g_invokeSocketIdx[i] = (CAMERA_DUAL_CAMERA_SENSOR_ENUM)((pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_MSB) >> KDIMGSENSOR_DUAL_SHIFT);
//化簡下面==》 drvIdx[i] = (pDrvIndex[i] & 0x0000FFFF); 得到低16位,就也是攝像頭在表中的位置,所以kdSensorList和SensorList要一一對應
drvIdx[i] = (pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_LSB);
if (DUAL_CAMERA_SUB_SENSOR == g_invokeSocketIdx[i]) //如果是前置攝像頭
gI2CBusNum = SUPPORT_I2C_BUS_NUM2;
else //否則
gI2CBusNum = SUPPORT_I2C_BUS_NUM1;
pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]); //執行 SensorInit函數,這里就是kdSensorList里面填的函數,得到sensor的接口函數,賦值
GC2355_MIPI_RAW_SensorInit //比如GC2355
*pfFunc=&sensor_func;
g_bEnableDriver[i] = TRUE;
memcpy((char *)g_invokeSensorNameStr[i], (char *)pSensorList[drvIdx[i]].drvname, sizeof(pSensorList[drvIdx[i]].drvname)); //得到sensor的名字
//單獨分析2
adopt_CAMERA_HW_CheckIsAlive
//上電,/* power on sensor */
g_invokeSocketIdx:是前攝還是后攝; g_invokeSensorNameStr:攝像頭名稱; true:上電; CAMERA_HW_DRVNAME1:名稱
kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM *)g_invokeSocketIdx, g_invokeSensorNameStr, true, CAMERA_HW_DRVNAME1);
if (g_bEnableDriver[i])
ret = kdCISModulePowerOn(socketIdx[i], sensorNameStr[i], On, mode_name);
if (On) {
if (pinSetIdx == 0) //主攝像頭
ISP_MCLK1_EN(1); //第一路ISP時鍾打開
else if (pinSetIdx == 1) //副攝像頭
ISP_MCLK1_EN(1); //第一路ISP時鍾打開
if (currSensorName && (0 == strcmp(SENSOR_DRVNAME_OV5648_MIPI_RAW, currSensorName))) //匹配具體攝像頭
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN]) //攝像頭的上電腳
//pinSetIdx:主攝像頭還是攝像頭; CAMPDN:那個引腳; pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]:拉高還是拉低
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]); //拉低復位腳
_hwPowerOn(VCAMIO, VOL_1800) //IO供電1.8V
_hwPowerOn(VCAMA, VOL_2800) //模擬供電腳2.8v
_hwPowerOn(VCAMD, VOL_1500) //數字供電聊2.5V
_hwPowerOn(VCAMAF, VOL_2800) //AF供電2.8v
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN])
mtkcam_gpio_set(pinSetIdx, CAMPDN, pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_ON]); //拉高使能腳
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST])
mtkcam_gpio_set(pinSetIdx, CAMRST, pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_ON]); //拉高復位腳
else //如果沒有特殊要求,使用默認供電函數
。。。。。。。。。。。。。
else { /* power OFF */ 下電
if (pinSetIdx == 0)
ISP_MCLK1_EN(0); //關閉ISP時鍾
else if (pinSetIdx == 1)
ISP_MCLK1_EN(0);
。。。。。。。。。。根據上電下電。。。。。。。。
if (g_pSensorFunc)
for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++)
g_pSensorFunc->SensorFeatureControl(g_invokeSocketIdx[i], SENSOR_FEATURE_CHECK_SENSOR_ID, (MUINT8 *)&sensorID, &retLen);
feature_control //調用具體攝像頭的feature_control函數
case SENSOR_FEATURE_CHECK_SENSOR_ID: //這里獲取sensor ID
get_imgsensor_id(feature_return_para_32); //通過I2C讀取攝像頭的ID
//如果讀取到了ID就把攝像頭的名字和前后攝狀態記錄
snprintf(mtk_ccm_name, sizeof(mtk_ccm_name), "%s CAM[%d]:%s;", mtk_ccm_name, g_invokeSocketIdx[i], g_invokeSensorNameStr[i]);
/* reset sensor state after power off */
err1 = g_pSensorFunc->SensorClose(); //關閉sensor
kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM *)g_invokeSocketIdx, g_invokeSensorNameStr, false, CAMERA_HW_DRVNAME1); //下電
五.camera的i2c注冊
1. 首先注冊一個假的I2C設備,然后通訊的時候用真的I2C地址,因為有兩個攝像頭,所以注冊兩個設備。
i2c_add_driver(&CAMERA_HW_i2c_driver); //注冊I2C設備,進入I2C的CAMERA_HW_i2c_probe函數,在probe里面沒有讀取i2c設備,所以可以注冊成功。
g_pstI2Cclient = client; //把
client保存在
g_pstI2Cclient
gc2355mipi_Sensor.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735m\gc2355_mipi_raw)
1.上層函數檢查sensor是否存在的時候,也是就是四章中的單獨分析2
get_imgsensor_id(feature_return_para_32); //通過I2C讀取攝像頭的ID
imgsensor.i2c_write_id = imgsensor_info.i2c_addr_table[i]; //這是當前攝像頭的I2C地址
*sensor_id = return_sensor_id();
return ((read_cmos_sensor(0xf0) << 8) | read_cmos_sensor(0xf1));
iReadRegI2C(pu_send_cmd, 1, (u8*)&get_byte, 1, imgsensor.i2c_write_id); //讀取i2c
//調用Kd_sensorlist.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)中的iReadRegI2C
g_pstI2Cclient->addr = (i2cId >> 1); //給
I2Cclient賦值真正的I2C地址
i4RetValue = i2c_master_send(g_pstI2Cclient, a_pSendData, a_sizeSendData); //寫設備,如果能寫成功,說明設備存在
i4RetValue = i2c_master_recv(g_pstI2Cclient, (char *)a_pRecvData, a_sizeRecvData); //讀,如果成功,說明存在