MTK平台CAMERA驱动框架解析

 一,Camera架构及流程简析

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

-Kernel部分主要有两块:一块是imagesensor驱动,负责具体型号的sensor的id检测,上电,以及在preview,capture,初始化,3A等等功能设定时的寄存器配置。另一块是ispdriver,通过DMA将sensor数据流上传。

-HAL层这边主要分3块:一块是imageio,主要是数据buffer上传的pipe。一块是drv,包含imgsensor和isp的hal层控制。最后是featureio,包含各种3A等性能配置。

流程图:

                                    

主要发生在两个时间点:开机过程中camera的动作以及打开应用时camera的动作。

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

-打开应用时:camera会有上电,完成寄存器的初始配置,向上层传送基本参数及配置信息,以及preview和capture模式循环。

二,配置相关文件

(下面的文件如不知道路径,请在代码中查找)

1,系统配置文件---ProjectConfig.mk

          

2,Sensor ID 和一些枚举类型的定义---kd_imgsensor.h,kd_imgsensor_define.h

定义sensor id和sensor name

此处填写正确的sensor ID

#define OV5648MIPI_SENSOR_ID                    0x5648

此处填写的字符串包含 sensor的 part no 格式(YUV or RAW)

#define SENSOR_DRVNAME_OV5648_MIPI_RAW          "ov5648_mipi_raw"

3,kd_sensorlist.hsensorlist.cpp

声明初始化函数

UINT32 OV5648MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc);

kdSensorList[] :

#if defined(OV5648_MIPI_RAW)    //与xxxxxSensor.c中的函数名对应,即驱动文件夹名大写
{OV5648MIPI_SENSOR_ID, SENSOR_DRVNAME_OV5648_MIPI_RAW, OV5648MIPI_RAW_SensorInit},
#endif

SensorList[] :

#if defined(OV5648_MIPI_RAW)
YUV_INFO(OV5648MIPI_SENSOR_ID,SENSOR_DRVNAME_OV5648_MIPI_RAW, NULL),
#endif

sensor 在kdSensorList[] 中的顺序必须和SensorList[]中的顺序保持一致 ,通常按照resolution从大到小的顺序依次排列下来。

4,hal层--camera_info_ov5648mipiraw.h

#define SENSOR_ID                           OV5648MIPI_SENSOR_ID
#define SENSOR_DRVNAME             SENSOR_DRVNAME_OV5648_MIPI_RAW   //为kd_imgsensor.h中定义的宏

5,AF定义---lenslist.cpp

MSDK_LENS_INIT_FUNCTION_STRUCT LensList_main[MAX_NUM_OF_SUPPORT_LENS] =
{
   #if defined(AD5820AF)
   {OV5648MIPI_SENSOR_ID, AD5820AF_LENS_ID, "AD5820AF", pAD5820AF_getDefaultData},
   #endif
}

{ YOUR SENSOR ID(在kd_imgsensor.h里面定义的一致),LENS ID(不用改变),“lens名称”(不需要改),Lens Para(不需要改)}

三,驱动代码分析

(有点长,是按照代码的调用逻辑排版的,所以会有点乱,边看边阅读代码会比较好理解)

1,kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6580\kd_sensorlist.c

在驱动装载函数 CAMERA_HW_i2C_init 中注册了 platform driver

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
		   }
};

if (platform_driver_register(&g_stCAMERA_HW_Driver)) {	// 注册platform总线的driver
		PK_ERR("failed to register CAMERA_HW driver\n");
		return -ENODEV;
}

与设备树里的 platform device 匹配成功后调用 CAMERA_HW_probe 方法注册 i2c driver

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,
};

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);    //注册 i2c driver
}

I2c匹配成功之后调用 CAMERA_HW_i2c_probe 方法

static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int i4RetValue = 0;

	PK_DBG("[CAMERA_HW] Attach I2C\n");

	/* get sensor i2c client */
	spin_lock(&kdsensor_drv_lock);
	g_pstI2Cclient = client;	//这里是获得我们的clientdevice,并且以platform方式进行注册
	/* set I2C clock rate */
	g_pstI2Cclient->timing = 100;	/* 100k */
	g_pstI2Cclient->ext_flag &= ~I2C_POLLING_FLAG;	/* No I2C polling busy waiting */

	spin_unlock(&kdsensor_drv_lock);

	/* Register char driver */
	i4RetValue = RegisterCAMERA_HWCharDrv();	// 注册字符驱动

	if (i4RetValue) {
		PK_ERR("[CAMERA_HW] register char device failed!\n");
		return i4RetValue;
	}

	/* spin_lock_init(&g_CamHWLock); */
#if !defined(CONFIG_MTK_LEGACY)
	Get_Cam_Regulator();
#endif

	PK_DBG("[CAMERA_HW] Attached!!\n");
	return 0;
}

在 CAMERA_HW_i2c_probe 函数里面主要就是调用了 RegisterCAMERA_HWCharDrv 函数来注册一个字符驱动

static inline int RegisterCAMERA_HWCharDrv(void)
{
#if CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO
	if (alloc_chrdev_region(&g_CAMERA_HWdevno, 0, 1, CAMERA_HW_DRVNAME1)) {
		PK_DBG("[CAMERA SENSOR] Allocate device no failed\n");

		return -EAGAIN;
	}
#else
	if (register_chrdev_region(g_CAMERA_HWdevno, 1, CAMERA_HW_DRVNAME1)) {
		PK_DBG("[CAMERA SENSOR] Register device no failed\n");

		return -EAGAIN;
	}
#endif
	/* Allocate driver */
	g_pCAMERA_HW_CharDrv = cdev_alloc();		// 申请一个cdev结构体

	if (NULL == g_pCAMERA_HW_CharDrv) {
		unregister_chrdev_region(g_CAMERA_HWdevno, 1);

		PK_DBG("[CAMERA SENSOR] Allocate mem for kobject failed\n");

		return -ENOMEM;
	}
	/* Attatch file operation. */	        //关联到file_operation进入字符设备
	cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops);	//初始化字符设备

	g_pCAMERA_HW_CharDrv->owner = THIS_MODULE;

	/* Add to system */
	if (cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1)) {		//注册到内核
		PK_DBG("[mt6516_IDP] Attatch file operation failed\n");

		unregister_chrdev_region(g_CAMERA_HWdevno, 1);

		return -EAGAIN;
	}
	sensor_class = class_create(THIS_MODULE, "sensordrv");		//创建一个sensordrv类
	if (IS_ERR(sensor_class)) {
		int ret = PTR_ERR(sensor_class);

		PK_DBG("Unable to create class, err = %d\n", ret);
		return ret;
	}
	sensor_device =
	    device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1);

	return 0;
}

g_stCAMERA_HW_fops 如下:

static const struct file_operations g_stCAMERA_HW_fops = {
	.owner = THIS_MODULE,
	.open = CAMERA_HW_Open,	 //对g_CamDrvOpenCnt变量进行了一个原子读的过程
	.release = CAMERA_HW_Release,
	.unlocked_ioctl = CAMERA_HW_Ioctl,		//上层跟驱动进行通讯
#ifdef CONFIG_COMPAT
	.compat_ioctl = CAMERA_HW_Ioctl_Compat,
#endif
};

代码开始先判断是否定义了 CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO 变量来判断动态还是静态分配一个字符设备,然后通过 cdev_alloc 申请了一个cdev结构体后,通过cdev_init将 g_stCAMERA_HW_fops 关联到字符设备,这是这个函数往下走下去的关键。然后就是将我们分配的字符设备,attach上 file_operation 添加到sys,最后在sys/class目录下创建一个sensordrv类。open函数没有做一些实际的行为,只是做了一个原子操作,用来计数打开cameradde的数量。

重点的操作行为在ioctl函数中,CAMERA_HW_Ioctl这个函数很重要,沟通上下层,提供接口,通过 switch case,将ioctl传下来的参数选择调用分支

static long CAMERA_HW_Ioctl(struct file *a_pstFile,
			    unsigned int a_u4Command, unsigned long a_u4Param)
{

	int i4RetValue = 0;
	void *pBuff = NULL;
	u32 *pIdx = NULL;

	mutex_lock(&kdCam_Mutex);


	if (_IOC_NONE == _IOC_DIR(a_u4Command)) {
	} else {
		pBuff = kmalloc(_IOC_SIZE(a_u4Command), GFP_KERNEL);	//申请分配一个buffer

		if (NULL == pBuff) {
			PK_DBG("[CAMERA SENSOR] ioctl allocate mem failed\n");
			i4RetValue = -ENOMEM;
			goto CAMERA_HW_Ioctl_EXIT;
		}
		/*
		判断是否可写
		将用户传递过来的命令参数复制到内核空间,接下来我们会根据这个数据进行选择
		*/
		if (_IOC_WRITE & _IOC_DIR(a_u4Command)) {
			if (copy_from_user(pBuff, (void *)a_u4Param, _IOC_SIZE(a_u4Command))) {
				kfree(pBuff);
				PK_DBG("[CAMERA SENSOR] ioctl copy from user failed\n");
				i4RetValue = -EFAULT;
				goto CAMERA_HW_Ioctl_EXIT;
			}
		}
	}

	pIdx = (u32 *) pBuff;	//使用pIdx指针,储存从用户空间拷贝过来的数据
	switch (a_u4Command) {

#if 0
	case KDIMGSENSORIOC_X_POWER_ON:
		i4RetValue =
		kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM) *pIdx, true,
				    CAMERA_HW_DRVNAME);
		break;
	case KDIMGSENSORIOC_X_POWER_OFF:
		i4RetValue =
		kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM) *pIdx, false,
				    CAMERA_HW_DRVNAME);
		break;
#endif
	//会调用kernel层的kdSetDriver接口,获取sensor初始化列表,获取各个camera驱动中的Init函数入口	
	case KDIMGSENSORIOC_X_SET_DRIVER:
		i4RetValue = kdSetDriver((unsigned int *)pBuff);
		break;
	//打来camera硬件
	case KDIMGSENSORIOC_T_OPEN:
		i4RetValue = adopt_CAMERA_HW_Open();
		break;
	//获取对应的camera硬件节点信息
	case KDIMGSENSORIOC_X_GETINFO:
		i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);
		break;
	//获取摄像头分辨率
	case KDIMGSENSORIOC_X_GETRESOLUTION2:
		i4RetValue = adopt_CAMERA_HW_GetResolution(pBuff);
		break;
	case KDIMGSENSORIOC_X_GETINFO2:
		i4RetValue = adopt_CAMERA_HW_GetInfo2(pBuff);
		break;
	//摄像头特征控制
	case KDIMGSENSORIOC_X_FEATURECONCTROL:
		i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff);
		break;
	//摄像头硬件控制
	case KDIMGSENSORIOC_X_CONTROL:
		i4RetValue = adopt_CAMERA_HW_Control(pBuff);
		break;
	//关闭摄像头硬件
	case KDIMGSENSORIOC_T_CLOSE:
		i4RetValue = adopt_CAMERA_HW_Close();
		break;
	//会调用kernel层的adopt_CAMERA_HW_CheckIsAlive进行上电,获取sensor id,
	case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
		i4RetValue = adopt_CAMERA_HW_CheckIsAlive();
		break;
	case KDIMGSENSORIOC_X_GET_SOCKET_POS:
		i4RetValue = kdGetSocketPostion((unsigned int *)pBuff);
		break;
	case KDIMGSENSORIOC_X_SET_I2CBUS:
		/* i4RetValue = kdSetI2CBusNum(*pIdx); */
		break;
	case KDIMGSENSORIOC_X_RELEASE_I2C_TRIGGER_LOCK:
		/* i4RetValue = kdReleaseI2CTriggerLock(); */
		break;

	case KDIMGSENSORIOC_X_SET_SHUTTER_GAIN_WAIT_DONE:
		/* i4RetValue = kdSensorSetExpGainWaitDone((int *)pBuff); */
		break;

	case KDIMGSENSORIOC_X_SET_CURRENT_SENSOR:
		i4RetValue = kdSetCurrentSensorIdx(*pIdx);
		break;

	case KDIMGSENSORIOC_X_SET_MCLK_PLL:
		i4RetValue = kdSetSensorMclk(pBuff);
		break;

	case KDIMGSENSORIOC_X_SET_GPIO:
		i4RetValue = kdSetSensorGpio(pBuff);
		break;

	case KDIMGSENSORIOC_X_GET_ISP_CLK:
		/* PK_DBG("get_isp_clk=%d\n",get_isp_clk()); */
		/* *(unsigned int*)pBuff = get_isp_clk(); */
		break;

	default:
		PK_DBG("No such command\n");
		i4RetValue = -EPERM;
		break;

	}
	//判断是否可读
	if (_IOC_READ & _IOC_DIR(a_u4Command)) {
		//将获得的数据传递给user空间
		if (copy_to_user((void __user *)a_u4Param, pBuff, _IOC_SIZE(a_u4Command))) {
			kfree(pBuff);
			PK_DBG("[CAMERA SENSOR] ioctl copy to user failed\n");
			i4RetValue = -EFAULT;
			goto CAMERA_HW_Ioctl_EXIT;
		}
	}

	kfree(pBuff);
CAMERA_HW_Ioctl_EXIT:
	mutex_unlock(&kdCam_Mutex);
	return i4RetValue;
}

KDIMGSENSORIOC_X_SET_DRIVER 和 KDIMGSENSORIOC_T_CHECK_IS_ALIVE 这两个在开机初始化监测id会被hal层调用

代码路径:\\vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6580\hal\senso\imgsensor_drv.cpp

MINT32//在开机过程中被调用,用于检测id,匹配main/sub image
ImgSensorDrv::impSearchSensor(pfExIdChk pExIdChkCbf)
{
........................................................
    //! If imp sensor search process already done before,
    //! only need to return the sensorDevs, not need to
    //! search again.
    if (SENSOR_DOES_NOT_EXIST != m_mainSensorId) {
    ....................................................
    }

    GetSensorInitFuncList(&m_pstSensorInitFunc);//获取sensorlist

    LOG_MSG("SENSOR search start \n");

    if (-1 != m_fdSensor) {
        ::close(m_fdSensor);
        m_fdSensor = -1;
    }
........................................................
    // search main/main_2/sub 3 sockets
#ifdef MTK_MAIN2_IMGSENSOR
    for (SensorEnum = DUAL_CAMERA_MAIN_SENSOR; SensorEnum <= DUAL_CAMERA_MAIN_2_SENSOR; SensorEnum <<= 1)  {
        LOG_MSG("impSearchSensor search to main_2\n");
#else
   #ifdef MTK_SUB_IMGSENSOR
    for (SensorEnum = DUAL_CAMERA_MAIN_SENSOR; SensorEnum <= DUAL_CAMERA_SUB_SENSOR; SensorEnum <<= 1)  {
        LOG_MSG("impSearchSensor search to sub\n");
   #else
    for (SensorEnum = DUAL_CAMERA_MAIN_SENSOR; SensorEnum < DUAL_CAMERA_SUB_SENSOR; SensorEnum <<= 1)  {
        LOG_MSG("impSearchSensor search to main\n");
   #endif
#endif
        //hal层开始探测sensor,因为有两颗sensor,外层循环两次
		//内层循环根据上面的sensor列表来,最大支持兼容16颗sensor,hal层特效,
		//如果没有整合特定imagesensor的hal层代码,这边会直接退出。
        for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {
            //end of driver list
            if (m_pstSensorInitFunc[i].getCameraDefault == NULL) {//设定hal层camera所有特效参数	
            										//通过之前的sensorlist来连接特定imagesensor的具体实现
                LOG_MSG("m_pstSensorInitFunc[i].getCameraDefault is NULL: %d \n", i);
                break;
            }
                //set sensor driver
            id[KDIMGSENSOR_INVOKE_DRIVER_0] = (SensorEnum << KDIMGSENSOR_DUAL_SHIFT) | i;
            LOG_MSG("set sensor driver id =%x\n", id[KDIMGSENSOR_INVOKE_DRIVER_0]);
			//ioctl向驱动层下command,下传的id就是目前正在检测的imagesensor的id,然后回到kd_sensorlist.c
            err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] );
                if (err < 0) {
                    LOG_ERR("ERROR:KDCAMERAHWIOC_X_SET_DRIVER\n");
                }

                //err = open();//对于正在遍历的这颗sensor,已经挂接上具体的底层驱动接口了
                				//那么下达check id的真正指令
                err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);

........................................................
}

GetSensooInitFuncList 这个函数主要为了获得下表:

\vendor\mediatek\proprietary\custom\tb8321p2_bsp\hal\imgsensor_src\sensorlist.cpp

包含了 id,name 和一些方法的调用 

MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] =
{* 500w */
#if defined(AR0543_MIPI_RAW)
	RAW_INFO(AR0543MIPI_SENSOR_ID,SENSOR_DRVNAME_AR0543_MIPI_RAW,NULL),
#endif

#if defined(SP5506_MIPI_RAW)
    RAW_INFO(SP5506MIPI_SENSOR_ID, SENSOR_DRVNAME_SP5506_MIPI_RAW, NULL),
#endif
/* 800w */
#if defined(OV8858_MIPI_RAW)
    RAW_INFO(OV8858MIPI_SENSOR_ID,SENSOR_DRVNAME_OV8858_MIPI_RAW,NULL), 
#endif

#if defined(GC8024_MIPI_RAW)
    RAW_INFO(GC8024MIPI_SENSOR_ID, SENSOR_DRVNAME_GC8024_MIPI_RAW, NULL), 
#endif
/* 1300w */
#if defined(OV13850_MIPI_RAW)
    RAW_INFO(OV13850_SENSOR_ID, SENSOR_DRVNAME_OV13850_MIPI_RAW, NULL), 
#endif
};
typedef struct
{
    MUINT32 SensorId;
    MUINT8  drvname[32];
    NSFeature::SensorInfoBase* pSensorInfo;
    NSFeature::SensorInfoBase* (*pfGetSensorInfoInstance)();
    MUINT32 (*getCameraDefault)(CAMERA_DATA_TYPE_ENUM CameraDataType, MVOID *pDataBuf, MUINT32 size);
    MUINT32 (*getCameraCalData)(MUINT32* pGetCalData);
    MUINT32 (*getCameraFlickerPara)(MINT32 sensorMode, MVOID *pDataBuf);
} MSDK_SENSOR_INIT_FUNCTION_STRUCT, *PMSDK_SENSOR_INIT_FUNCTION_STRUCT;

getCameraDefault 调用很重要,hal层camera的所有特效参数,包括3A,shading都在这边设定,通过之前的sensorlist来连接特定imagesensor的具体实现。

ioctl向下层传入 KDIMGSENSORIOC_X_SET_DRIVER,下层调用kdSetDriver,回到 kd_sensorlist.c

/*******************************************************************************
* kdSetDriver
********************************************************************************/
int kdSetDriver(unsigned int *pDrvIndex)
{
	ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL;
	u32 drvIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = { 0, 0 };
	u32 i;

	/* set driver for MAIN or SUB sensor */
	PK_INF("pDrvIndex:0x%08x/0x%08x\n", pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0],
	       pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_1]);
	/* Camera information */
	gDrvIndex = pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0];

	if (0 != kdGetSensorInitFuncList(&pSensorList)) {	//获得sensor初始化列表
		PK_ERR("ERROR:kdGetSensorInitFuncList()\n");
		return -EIO;
	}

	for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {
		/*  */
		spin_lock(&kdsensor_drv_lock);
		g_bEnableDriver[i] = FALSE;
		g_invokeSocketIdx[i] =			//区分目前正在匹配的是main还是sub
		    (CAMERA_DUAL_CAMERA_SENSOR_ENUM) ((pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_MSB) >>
						      KDIMGSENSOR_DUAL_SHIFT);
		spin_unlock(&kdsensor_drv_lock);
		drvIdx[i] = (pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_LSB);	//列表的序列号
		/*  */
		if (DUAL_CAMERA_NONE_SENSOR == g_invokeSocketIdx[i]) {
			continue;
		}
#if 0
		if (DUAL_CAMERA_MAIN_SENSOR == g_invokeSocketIdx[i]
		    || DUAL_CAMERA_SUB_SENSOR == g_invokeSocketIdx[i]
		    || DUAL_CAMERA_MAIN_2_SENSOR == g_invokeSocketIdx[i]) {
			spin_lock(&kdsensor_drv_lock);
			gI2CBusNum = SENSOR_I2C_BUS_NUM[g_invokeSocketIdx[i]];
			spin_unlock(&kdsensor_drv_lock);
			PK_XLOG_INFO("kd_MultiSensorOpen: switch I2C BUS%d\n", gI2CBusNum);
		}
#else

		if (DUAL_CAMERA_SUB_SENSOR == g_invokeSocketIdx[i]) {
			spin_lock(&kdsensor_drv_lock);
			gI2CBusNum = SUPPORT_I2C_BUS_NUM2;
			spin_unlock(&kdsensor_drv_lock);
			/* PK_XLOG_INFO("kdSetDriver: switch I2C BUS2\n"); */
		} else {
			spin_lock(&kdsensor_drv_lock);
			gI2CBusNum = SUPPORT_I2C_BUS_NUM1;
			spin_unlock(&kdsensor_drv_lock);
			/* PK_XLOG_INFO("kdSetDriver: switch I2C BUS1\n"); */
		}
#endif
		PK_INF("g_invokeSocketIdx[%d]=%d,drvIdx[%d]=%d\n", i, g_invokeSocketIdx[i], i,
		       drvIdx[i]);
		/* PK_INF("[kdSetDriver]drvIdx[%d] = %d\n", i, drvIdx[i]); */
		/*  */
		if (MAX_NUM_OF_SUPPORT_SENSOR > drvIdx[i]) {
			if (NULL == pSensorList[drvIdx[i]].SensorInit) {//判断模块驱动的init函数是否为NULL
				PK_ERR("ERROR:kdSetDriver()\n");
				return -EIO;
			}

			pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);	//获取各个cam驱动中Init函数入口
			if (NULL == g_pInvokeSensorFunc[i]) {
				PK_ERR("ERROR:NULL g_pSensorFunc[%d]\n", i);
				return -EIO;
			}
			/*  */
			spin_lock(&kdsensor_drv_lock);
			g_bEnableDriver[i] = TRUE;
			spin_unlock(&kdsensor_drv_lock);
			/* get sensor name */
			memcpy((char *)g_invokeSensorNameStr[i],
			       (char *)pSensorList[drvIdx[i]].drvname,
			       sizeof(pSensorList[drvIdx[i]].drvname));
			/* return sensor ID */
			/* pDrvIndex[0] = (unsigned int)pSensorList[drvIdx].SensorId; */
			PK_INF("[%d][%d][%d][%s][%d]\n", i, g_bEnableDriver[i],
			       g_invokeSocketIdx[i], g_invokeSensorNameStr[i],
			       sizeof(pSensorList[drvIdx[i]].drvname));
		}
	}
	return 0;
}
typedef struct {
	MUINT32 SensorId;
	MUINT8 drvname[32];
	MUINT32(*SensorInit)(PSENSOR_FUNCTION_STRUCT *pfFunc);
} ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT, *PACDK_KD_SENSOR_INIT_FUNCTION_STRUCT;
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] =
{
#if defined(OV5648_MIPI_RAW)
	{OV5648MIPI_SENSOR_ID,SENSOR_DRVNAME_OV5648_MIPI_RAW,OV5648MIPI_RAW_SensorInit},
#endif
..............
}

kdSetDriver 这个函数比较重要,上层调用底层的命令应该第一步就是调用这个命令的,函数开头定义了一个ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL 这样的结构体,ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT 变量是为 kd_sensorlist.h 文件里面保存sensor的ID,NAME以及init的结构体,if (0 !=kdGetSensorInitFuncList(&pSensorList)) 通过调用 kdGetSensorInitFuncList 函数,将 pSensorList 的首地址指向 kd_sensorlist.h 里面 ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT 变量的首地址。

/*******************************************************************************
* general camera image sensor kernel driver
*******************************************************************************/
UINT32 	SensorInitFuncList(ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)
{
	if (NULL == ppSensorList) {
		PK_ERR("[kdGetSensorInitFuncList]ERROR: NULL ppSensorList\n");
		return 1;
	}
	*ppSensorList = &kdSensorList[0];				//获取sensorlist数组首地址
	//kdSensorList 在 kd_sensorlist.h文件里面,就是保存cameraId,cameraName,模块入口函数结构体
	return 0;
}				/* kdGetSensorInitFuncList() */

调用了 kdGetSensorInitFuncList 后,代码先将 g_bEnableDriver 置为 FALSE,而这个变量在open函数里面出现过的。然后通过if (NULL ==pSensorList[drvIdx[i]].SensorInit) 判断模块驱动的init函数是否为NULL

if (NULL == pSensorList[drvIdx[i]].SensorInit) {		//判断模块驱动的init函数是否为NULL
		PK_ERR("ERROR:kdSetDriver()\n");
		return -EIO;
}

pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);		//获取各个cam驱动中Init函数入口
if (NULL == g_pInvokeSensorFunc[i]) {
		PK_ERR("ERROR:NULL g_pSensorFunc[%d]\n", i);
	    return -EIO;
}

pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);

传递 &g_pInvokeSensorFunc[i] 为参数,其中还是传递的地址,这就将 g_pInvokeSensorFunc 的首地址指向了模块驱动函数中的 UINT32 OV5648MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc) 这个函数

static SENSOR_FUNCTION_STRUCT sensor_func = {
    open,
    get_info,
    get_resolution,
    feature_control,
    control,
    close
};

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

这样就实现了驱动代码的分离,hal层只需调用Sensorlist.c这样一个虚拟设备的驱动,就可以和具体的Sensor Driver通信。

typedef struct {
	MUINT32(*SensorOpen)(void);
	MUINT32(*SensorGetInfo)(MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_INFO_STRUCT *pSensorInfo,
				MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData);
	MUINT32(*SensorGetResolution)(MSDK_SENSOR_RESOLUTION_INFO_STRUCT *pSensorResolution);
	MUINT32(*SensorFeatureControl)(MSDK_SENSOR_FEATURE_ENUM FeatureId, MUINT8 *pFeaturePara, MUINT32 *pFeatureParaLen);
	MUINT32(*SensorControl)(MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT *pImageWindow, MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData);
	MUINT32(*SensorClose)(void);
#if 1 /* isp suspend resume patch */
	MSDK_SCENARIO_ID_ENUM ScenarioId;
	MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT imageWindow;
	MSDK_SENSOR_CONFIG_STRUCT sensorConfigData;
	SENSOR_STATE_ENUM sensorState;
#endif
	MUINT8  arch;
	void   *psensor_inst; /* IMGSENSOR_SENSOR_INST */
} SENSOR_FUNCTION_STRUCT, *PSENSOR_FUNCTION_STRUCT;

这就就可以通过 g_pInvokeSensorFunc 直接调用模块驱动中的接口函数。

ioctl 里面的其他几条cmd命令基本都是在获取到了 g_pInvokeSensorFunc 后然后调用模块驱动中的各个接口函数

回到hal层

=> \\vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6580\hal\senso\imgsensor_drv.cpp

还是 impSearchSensor 这个函数

//err = open();//对于正在遍历的这颗sensor,已经挂接上具体的底层驱动接口了
                				//那么下达check id的真正指令
                err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);


                if (err < 0) {
                    LOG_MSG("[impSearchSensor] Err-ctrlCode (%s) \n", strerror(errno));
                }

底层调用 adopt_CAMERA_HW_CheckIsAlive

//会调用kernel层的adopt_CAMERA_HW_CheckIsAlive进行上电,获取sensor id,
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
	i4RetValue = adopt_CAMERA_HW_CheckIsAlive();
	break;

第一步是上电 power on,第二步是读sensor id

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],//读取SensorID
									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;
				..........................
}

调用之前挂接的具体sensor的 Feature control,并带参

case SENSOR_FEATURE_SET_VIDEO_MODE:
            set_video_mode(*feature_data);
            break;
        case SENSOR_FEATURE_CHECK_SENSOR_ID:    //优化传入的cmd为SENSOR_FEATURE_CHECK_SENSOR_ID,
        										//则会调用feature_control中的get_imgsensor_id
            get_imgsensor_id(feature_return_para_32);
            break;
        case SENSOR_FEATURE_SET_AUTO_FLICKER_MODE:
            set_auto_flicker_mode((BOOL)*feature_data_16,*(feature_data_16+1));
            break;

读id一般在 开机 和 打开sensor 时执行,读之前软件 reset sensor,保证所读取的id的正确性,读到id后和预先设定的id作比较,如果一致,那么就找到了要找的sensor,因为有前后摄像头,所以这个动作要执行两次以上

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;
    }
    if (*sensor_id != imgsensor_info.sensor_id) {
        // if Sensor ID is not correct, Must set *sensor_id to 0xFFFFFFFF
        *sensor_id = 0xFFFFFFFF;
        return ERROR_SENSOR_CONNECT_FAIL;
    }
    return ERROR_NONE;
}

这边读id是通过i2c通信

/*******************************************************************************
* iReadRegI2C
这一步完成I2c的读取,也就是说如果I2c配置正确,并且上电正确,
到这一步就可以正确的读取ID,整个camera也就基本调通了
********************************************************************************/
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) {

		.....................

	return 0;
}

读完id并没有结束,因为还处于开机初始化阶段,并不是打开camera应用,check完id,还要给sensor下电,匹配上id后,又回到hal层,id不对的 return err<0

回到hal层

=>\\vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6580\hal\senso\imgsensor_drv.cpp

还是impSearchSensor这个函数

sensorType = this->getCurrentSensorType((SENSOR_DEV_ENUM)SensorEnum);
            //
            socketPos = this->getSocketPosition((CAMERA_DUAL_CAMERA_SENSOR_ENUM)SensorEnum);
                //check extra ID , from EEPROM maybe
                //may need to keep power here
                if (NULL != pExIdChkCbf) {
                    err2 = pExIdChkCbf();
                    if (err2 < 0) {
                        LOG_ERR("Error:pExIdChkCbf() \n");
                    }
                }

匹配上的sensor则继续下传cmd,获取一些sensordde的信息和配置,流程和之前的id检测类似。

总结

hal层运行 Search sensor 这个线程

hal层遍历 sensorlist 并挂接hal层性能如:3A等一些参数获取接口

hal层下达 setDriver 的cmd,并下传正在遍历的sensor在 sensorlist 列表中的id

Driver层根据这个id,挂接Driver层 sensorlist 中对应的Sensor和具体Sensor底层操作接口

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

比较读取结果,不匹配,return error,继续遍历。

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

下电

参考博文 https://blog.csdn.net/xiaopangzi313/article/details/52205561

发布了6 篇原创文章 · 获赞 29 · 访问量 1049

猜你喜欢

转载自blog.csdn.net/dthua888/article/details/102490973