一、Camera的硬件接口
引脚 | 名称及作用 |
---|---|
VCAMA | 就是AVDD,模拟供电,主要给感光区和ADC部分供电,2.8V |
VCAMD | 就是DVDD,数字供电,主要给 ISP 供电,1.2V |
VCAM_IO | 就是VDDIO,数字IO供电,主要给 I2C 部分供电,1.8V |
VCAM_AF | 自动对焦马达供电 |
RESET | 复位引脚 |
PDN | 工作状态控制引脚 |
CMMCLK | 时钟引脚 |
SCL、SDA | I2C接口 |
RCN、RCP | MIPI时钟接口 |
RDN0、RDP0 | MIPI数据接口通道0 |
注:MIPI数据接口可能有多通道。
二、代码路径
描述 | 路径 | 文件 |
---|---|---|
系统设置 | device\top\top6737t_36_a_m0 kernel-3.18\arch\arm\configs |
ProjectConfig.mk user版本和userdebug版本对应: top6737t_36_a_m0_defconfig debug版本对应: top6737t_36_a_m0_debug_defconfig |
接口设置 | kernel-3.18\arch\arm\boot\dts |
top6737t_36_a_m0.dts cust_i2c.dtsi |
Kernel代码 | kernel-3.18\drivers\misc\mediatek\imgsensor |
|
HAL代码 | vendor\mediatek\proprietary\custom\mt6735\hal\D2\imgsensor |
|
镜头、闪光灯等相关代码 | kernel-3.18\drivers\misc\mediatek\lens kernel-3.18\drivers\misc\mediatek\flashlight vendor\mediatek\proprietary\custom\mt6735\hal\D2\lens vendor\mediatek\proprietary\custom\mt6735\hal\D2\flashlight |
三、Camera代码分析
1、硬件接口设置
在dts文件中,对照硬件接口,修改对应GPIO设置:
// top6737t_36_a_m0.dts
/* CAMERA GPIO standardization */
&pio {
camera_pins_cam0_rst0: cam0@0 {
pins_cmd_dat {
pins = <PINMUX_GPIO44__FUNC_GPIO44>;/*GPIO_CAMERA_CMRST_PIN*/
slew-rate = <1>; /*direction 0:in, 1:out*/
output-low;/*direction out used only. output_low or high*/
};
};
camera_pins_cam0_rst1: cam0@1 {
pins_cmd_dat {
pins = <PINMUX_GPIO44__FUNC_GPIO44>;/*GPIO_CAMERA_CMRST_PIN*/
slew-rate = <1>;
output-high;
};
};
camera_pins_cam0_pnd0: cam0@2 {
pins_cmd_dat {
pins = <PINMUX_GPIO7__FUNC_GPIO7>;/*GPIO_CAMERA_CMPDN_PIN*/
slew-rate = <1>;
output-low;
};
};
camera_pins_cam0_pnd1: cam0@3 {
pins_cmd_dat {
pins = <PINMUX_GPIO7__FUNC_GPIO7>;/*GPIO_CAMERA_CMPDN_PIN*/
slew-rate = <1>;
output-high;
};
};
camera_pins_cam1_rst0: cam1@0 {
pins_cmd_dat {
pins = <PINMUX_GPIO11__FUNC_GPIO11>;/*GPIO_CAMERA_CMRST1_PIN*/
slew-rate = <1>; /*direction 0:in, 1:out*/
output-low;/*direction out used only. output_low or high*/
};
};
camera_pins_cam1_rst1: cam1@1 {
pins_cmd_dat {
pins = <PINMUX_GPIO11__FUNC_GPIO11>;/*GPIO_CAMERA_CMRST1_PIN*/
slew-rate = <1>;
output-high;
};
};
camera_pins_cam1_pnd0: cam1@2 {
pins_cmd_dat {
pins = <PINMUX_GPIO12__FUNC_GPIO12>;/*GPIO_CAMERA_CMPDN1_PIN*/
slew-rate = <1>;
output-low;
};
};
camera_pins_cam1_pnd1: cam1@3 {
pins_cmd_dat {
pins = <PINMUX_GPIO12__FUNC_GPIO12>;/*GPIO_CAMERA_CMPDN1_PIN*/
slew-rate = <1>;
output-high;
};
};
camera_pins_cam_ldo0_0: cam@0 {
pins_cmd_dat {
pins = <PINMUX_GPIO68__FUNC_GPIO68>;
slew-rate = <1>;
output-low;
};
};
camera_pins_cam_ldo0_1: cam@1 {
pins_cmd_dat {
pins = <PINMUX_GPIO68__FUNC_GPIO68>;
slew-rate = <1>;
output-high;
};
};
camera_pins_default: camdefault {
};
};
&kd_camera_hw1 {
pinctrl-names = "default", "cam0_rst0", "cam0_rst1", "cam0_pnd0", "cam0_pnd1",
"cam1_rst0", "cam1_rst1", "cam1_pnd0", "cam1_pnd1",
"cam_ldo0_0", "cam_ldo0_1";
pinctrl-0 = <&camera_pins_default>;
pinctrl-1 = <&camera_pins_cam0_rst0>;
pinctrl-2 = <&camera_pins_cam0_rst1>;
pinctrl-3 = <&camera_pins_cam0_pnd0>;
pinctrl-4 = <&camera_pins_cam0_pnd1>;
pinctrl-5 = <&camera_pins_cam1_rst0>;
pinctrl-6 = <&camera_pins_cam1_rst1>;
pinctrl-7 = <&camera_pins_cam1_pnd0>;
pinctrl-8 = <&camera_pins_cam1_pnd1>;
pinctrl-9 = <&camera_pins_cam_ldo0_0>;
pinctrl-10 = <&camera_pins_cam_ldo0_1>;
status = "okay";
};
/* CAMERA GPIO end */
还有对应的I2C设置:
/* cust_i2c.dtsi */
&i2c0 {
camera_main@10 {
compatible = "mediatek,camera_main";
reg = <0x10>;
};
camera_main_af@0c {
compatible = "mediatek,camera_main_af";
reg = <0x0c>;
};
camera_sub@3c {
compatible = "mediatek,camera_sub";
reg = <0x3c>;
};
};
2、Camera设备驱动
文件kd_sensorlist.c
是摄像头作为字符型设备驱动的入口,可以通过分析本文件简单捋一下摄像头驱动的代码结构。
首先,是一个I2C设备的驱动:
//kd_sensorlist.c
#ifdef CONFIG_OF
static const struct of_device_id CAMERA_HW_i2c_of_ids[] = {
{
.compatible = "mediatek,camera_main", }, //在文件cust_i2c.dtsi中找对应的描述,设置用哪组I2C,以及地址
{
}
};
#endif
//实现I2C设备驱动的几个标准接口
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,
};
在I2C的设备驱动probe函数中,注册摄像头模组的字符型设备:
//kd_sensorlist.c
static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
......
//注册摄像头模组的字符型设备
i4RetValue = RegisterCAMERA_HWCharDrv();
......
PK_DBG("[CAMERA_HW] Attached!!\n");
return 0;
}
在注册摄像头字符型设备函数RegisterCAMERA_HWCharDrv();
中,可以看到这个字符型设备的操作函数:
//kd_sensorlist.c
static inline int RegisterCAMERA_HWCharDrv(void)
{
......
//操作函数
cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops);
......
sensor_device = device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1);
return 0;
}
//操作函数结构体
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_Ioctl
中,具体的一些操作:
//kd_sensorlist.c
static long CAMERA_HW_Ioctl(struct file *a_pstFile,unsigned int a_u4Command,unsigned long a_u4Param)
{
......
switch (a_u4Command)
{
//找到控制摄像头的驱动函数,以便获取摄像头的SensorOpen、SensorGetInfo等接口;
case KDIMGSENSORIOC_X_SET_DRIVER:
i4RetValue = kdSetDriver((unsigned int *)pBuff);
break;
//调用接口SensorOpen,给摄像头上电,通过I2C读取摄像头ID,以及设置寄存器相关参数;
case KDIMGSENSORIOC_T_OPEN:
i4RetValue = adopt_CAMERA_HW_Open();
break;
//调用接口SensorGetInfo,获取摄像头MIPI、CLOCK等参数;
case KDIMGSENSORIOC_X_GETINFO:
i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);
break;
//调用接口SensorGetResolution,获取摄像头分辨率等参数;
case KDIMGSENSORIOC_X_GETRESOLUTION2:
i4RetValue = adopt_CAMERA_HW_GetResolution(pBuff);
break;
case KDIMGSENSORIOC_X_GETINFO2:
i4RetValue = adopt_CAMERA_HW_GetInfo2(pBuff);
break;
//调用接口SensorFeatureControl,获取或设置摄像头增益、进入不同模式等操作;
case KDIMGSENSORIOC_X_FEATURECONCTROL:
i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff);
break;
//调用接口SensorControl,控制摄像头预览、拍照等操作;
case KDIMGSENSORIOC_X_CONTROL:
i4RetValue = adopt_CAMERA_HW_Control(pBuff);
break;
//调用接口SensorClose,关闭摄像头;
case KDIMGSENSORIOC_T_CLOSE:
i4RetValue = adopt_CAMERA_HW_Close();
break;
//通过读ID方式检查摄像头是否存在;
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
i4RetValue = adopt_CAMERA_HW_CheckIsAlive();
break;
......
default:
PK_DBG("No such command\n");
i4RetValue = -EPERM;
break;
}
......
}
查找并加载摄像头驱动功能函数的过程如下:
//kd_sensorlist.c
int kdSetDriver(unsigned int *pDrvIndex)
{
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL;
u32 drvIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {
0, 0};
u32 i;
//KDIMGSENSOR_INVOKE_DRIVER_0和KDIMGSENSOR_INVOKE_DRIVER_1表示摄像头位置,目前支持两个位置:前摄和后摄
//传进来的int型参数,高16位表示main还是sub,低16位表示摄像头Index
PK_INF("pDrvIndex:0x%08x/0x%08x\n", pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0], pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_1]);
gDrvIndex = pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0];
//获取摄像头列表
if (0 != kdGetSensorInitFuncList(&pSensorList)) {
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;
//根据传进来的参数,赋值main还是sub
g_invokeSocketIdx[i] = (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);
//若传进来的参数是NONE,表示当前位置没有摄像头
if (DUAL_CAMERA_NONE_SENSOR == g_invokeSocketIdx[i]) {
continue;
}
//根据摄像头位置,确定使用那一组I2C
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"); */
}
PK_INF("g_invokeSocketIdx[%d]=%d,drvIdx[%d]=%d\n", i, g_invokeSocketIdx[i], i, drvIdx[i]);
//Index不能超过定义的最大指:MAX_NUM_OF_SUPPORT_SENSOR
if (MAX_NUM_OF_SUPPORT_SENSOR > drvIdx[i]) {
//利用SensorInit函数将摄像头的具体函数放到g_pInvokeSensorFunc中
if (NULL == pSensorList[drvIdx[i]].SensorInit) {
PK_ERR("ERROR:kdSetDriver()\n");
return -EIO;
}
pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);
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);
//把摄像头的名字copy到g_invokeSensorNameStr
memcpy((char *)g_invokeSensorNameStr[i], (char *)pSensorList[drvIdx[i]].drvname, sizeof(pSensorList[drvIdx[i]].drvname));
PK_INF("[%d][%d][%d][%s]\n", i, g_bEnableDriver[i], g_invokeSocketIdx[i], g_invokeSensorNameStr[i]);
}
}
return 0;
}
打开摄像头的操作,包括上电、读ID等操作,是在kd_MultiSensorOpen函数中实现的,具体如下:
//kd_sensorlist.c
MUINT32 kd_MultiSensorOpen(void)
{
......
for (i = (KDIMGSENSOR_MAX_INVOKE_DRIVERS - 1); i >= KDIMGSENSOR_INVOKE_DRIVER_0; i--)
{
if (g_bEnableDriver[i] && g_pInvokeSensorFunc[i])
{
if (0 != (g_CurrentSensorIdx & g_invokeSocketIdx[i]))
{
#ifndef CONFIG_FPGA_EARLY_PORTING
//给摄像头上电,kdCISModulePowerOn函数在tb_kd_camera_hw.c文件中实现;
ret = kdCISModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM)g_invokeSocketIdx[i], (char *)g_invokeSensorNameStr[i], true,CAMERA_HW_DRVNAME1);
#endif
if (ERROR_NONE != ret)
{
PK_ERR("[%s]", __func__);
return ret;
}
//调用这颗摄像头的open函数,里边有读ID等操作
ret = g_pInvokeSensorFunc[i]->SensorOpen();
if (ERROR_NONE != ret)
{
#ifndef CONFIG_FPGA_EARLY_PORTING
//如果open失败,还要下电;
kdCISModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM)g_invokeSocketIdx[i], (char *)g_invokeSensorNameStr[i], false, CAMERA_HW_DRVNAME1);
#endif
PK_ERR("SensorOpen");
return ret;
}
}
}
}
......
KD_MULTI_FUNCTION_EXIT();
return ERROR_NONE;
}
函数kd_MultiSensorOpen中调用的给摄像头上下电的函数,是在文件tb_kd_camera_hw.c中实现。不同模组,打开和关闭时,硬件接口的操作上会有差异,比如:先给哪路上电或下电?复位操作对应高电平还是低电平?上电后需要多长时间模组才Ready?具体的操作时序,可以参考模组的规格书。下面的代码就是上电和下电的具体操作:
// kd_camera_hw.c
int kdCISModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM SensorIdx, char *currSensorName, bool On, char *mode_name)
{
......
//上电操作
if (On)
{
......
//判断要操作的模组,SensorIdx用来判断前摄还是后摄,currSensorName用来判断模组名字
if (SensorIdx == DUAL_CAMERA_MAIN_SENSOR && currSensorName && (0 == strcmp(SENSOR_DRVNAME_GC030A_MIPI_RAW, currSensorName)))
{
//第1步:使能CMMCLK
ISP_MCLK1_EN(1);
// 第2步:操作PDN脚和RESET脚,为芯片正常工作做准备;
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(5);
//第3步:分别给VDDIO、AVDD、DVDD上电,如果自动对焦马达需要供电,也需要给VCAM_AF上电
if (TRUE != _hwPowerOnCnt(VCAMIO, VOL_1800, mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to enable IO power (VCAM_IO),power id = %d\n",VCAMIO);
goto _kdCISModulePowerOn_exit_;
}
mdelay(1);
if (TRUE != _hwPowerOnCnt(VCAMA, VOL_2800, mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to enable analog power (VCAM_A),power id = %d\n",VCAMA);
goto _kdCISModulePowerOn_exit_;
}
mdelay(5);
if (TRUE != _hwPowerOnCnt(VCAMD, VOL_1200, mode_name))
{
PK_DBG ("[CAMERA SENSOR] Fail to enable digital power (VCAM_D),power id = %d\n", VCAMD);
goto _kdCISModulePowerOn_exit_;
}
if (TRUE != _hwPowerOnCnt(VCAMAF, VOL_2800, mode_name))
{
PK_DBG ("[CAMERA SENSOR] Fail to enable analog power (VCAM_AF),power id = %d\n", VCAMAF);
goto _kdCISModulePowerOn_exit_;
}
//第4步:使模组进入Nomal模式
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]);
}
mdelay(5);
}
......
}
else //下电操作
{
......
//判断要操作的模组,SensorIdx用来判断前摄还是后摄,currSensorName用来判断模组名字
if (SensorIdx == DUAL_CAMERA_MAIN_SENSOR && currSensorName && (0 == strcmp(SENSOR_DRVNAME_GC030A_MIPI_RAW, currSensorName)))
{
//第1步:操作PDN脚和RESET脚,停止模组工作
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]);
}
//第2步:分别关闭VDDIO、AVDD、DVDD、VCAM_AF的电
if (TRUE != _hwPowerDownCnt(VCAMA, mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to OFF analog power (VCAM_A), power id= (%d)\n",VCAMA);
goto _kdCISModulePowerOn_exit_;
}
if (TRUE != _hwPowerDownCnt(VCAMIO, mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to OFF digital power (VCAM_IO), power id = %d\n",VCAMIO);
goto _kdCISModulePowerOn_exit_;
}
if (TRUE != _hwPowerDownCnt(VCAMD, mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to OFF analog power (VCAMD), power id= (%d)\n",VCAMD);
goto _kdCISModulePowerOn_exit_;
}
if (TRUE != _hwPowerDownCnt(VCAMAF, mode_name))
{
PK_DBG("[CAMERA SENSOR] Fail to OFF digital power (VCAMAF), power id = %d\n",VCAMAF);
goto _kdCISModulePowerOn_exit_;
}
mdelay(5);
// 第3步:关闭CMMCLK
ISP_MCLK1_EN(0);
}
......
}
......
return 0;
_kdCISModulePowerOn_exit_:
return -EIO;
}
至此,Kernel中给摄像头上电、打开摄像头、控制摄像头、关闭摄像头等实现,就比较清晰了。
3、模组驱动代码
分析设备驱动代码时,已经知晓在kdSetDriver操作中会根据不同模组找到对应的驱动代码,根据不同的模组有不同的上下电操作。不同模组的不同驱动代码都在下面这个文件中:
//kd_sensorlist.h
......
UINT32 GC030AMIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc);
......
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] =
{
......
#if defined(GC030A_MIPI_RAW)
{
GC030AMIPI_SENSOR_ID, SENSOR_DRVNAME_GC030A_MIPI_RAW,GC030AMIPI_RAW_SensorInit},
#endif
......
}
不同模组列表kdSensorList,其实是不同的模组以结构体ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT格式进行填充,结构体定义如下:
//kd_imgsensor_define.h
typedef struct {
MUINT32 SensorId; //模组ID
MUINT8 drvname[32];//模组名字
MUINT32(*SensorInit)(PSENSOR_FUNCTION_STRUCT *pfFunc);//模组初始化函数
} ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT, *PACDK_KD_SENSOR_INIT_FUNCTION_STRUCT;
模组的初始化函数是用来获取模组驱动函数接口的,模组驱动函数接口定义在:
//kd_imgsensor_define.h
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;
#endif
} SENSOR_FUNCTION_STRUCT, *PSENSOR_FUNCTION_STRUCT;
分析不同模组驱动代码,就是分析不同模组实现SENSOR_FUNCTION_STRUCT的具体函数,比如 gc030a_mipi_raw :
//gc030amipi_Sensor.c
static SENSOR_FUNCTION_STRUCT sensor_func = {
open,
get_info,
get_resolution,
feature_control,
control,
close
};
首先,看open函数:
//gc030amipi_Sensor.c
static kal_uint32 open(void)
{
......
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
{
//通过I2C读取模组ID
sensor_id = return_sensor_id();
if (sensor_id == imgsensor_info.sensor_id)
{
LOG_INF("GC030A open i2c write id: 0x%x, sensor id: 0x%x\n", imgsensor.i2c_write_id,sensor_id);
break;
}
LOG_INF("GC030A open Read sensor id fail, write id: 0x%x, id: 0x%x\n", imgsensor.i2c_write_id,sensor_id);
retry--;
} while(retry > 0);
i++;
if (sensor_id == imgsensor_info.sensor_id) break;
retry = 2;
}
//ID不匹配则直接退出
if (imgsensor_info.sensor_id != sensor_id)
{
return ERROR_SENSOR_CONNECT_FAIL;
}
//通过I2C把摄像头Sensor的寄存器初始化参数写进去,包括镜像、增益、MIPI等基础参数
sensor_init();
......
return ERROR_NONE;
}
open函数中调用的sensor_init函数,是通过I2C写摄像头模组的初始化参数,调试过程中可能会遇到成像镜像等问题,可以通过调试这些参数来修正:
//gc030amipi_Sensor.c
static void sensor_init(void)
{
/*SYS*/
write_cmos_sensor(0xfe, 0x80);
write_cmos_sensor(0xfe, 0x80);
write_cmos_sensor(0xfe, 0x80);
write_cmos_sensor(0xf7, 0x01);
write_cmos_sensor(0xf8, 0x05);
write_cmos_sensor(0xf9, 0x0f);
write_cmos_sensor(0xfa, 0x00);
write_cmos_sensor(0xfc, 0x0f);
write_cmos_sensor(0xfe, 0x00);
/*ANALOG & CISCTL*/
write_cmos_sensor(0x03, 0x01);
write_cmos_sensor(0x04, 0xc8);
write_cmos_sensor(0x05, 0x03);
write_cmos_sensor(0x06, 0x7b);
write_cmos_sensor(0x07, 0x00);
write_cmos_sensor(0x08, 0x06);
write_cmos_sensor(0x0a, 0x00);
write_cmos_sensor(0x0c, 0x08);
write_cmos_sensor(0x0d, 0x01);
write_cmos_sensor(0x0e, 0xe8);
write_cmos_sensor(0x0f, 0x02);
write_cmos_sensor(0x10, 0x88);
write_cmos_sensor(0x12, 0x28);//23 add 20170110
write_cmos_sensor(0x17, MIRROR);//Don't Change Here!!!
write_cmos_sensor(0x18, 0x12);
write_cmos_sensor(0x19, 0x07);
write_cmos_sensor(0x1a, 0x1b);
write_cmos_sensor(0x1d, 0x48);//40 travis20160318
write_cmos_sensor(0x1e, 0x50);
write_cmos_sensor(0x1f, 0x80);
write_cmos_sensor(0x23, 0x01);
write_cmos_sensor(0x24, 0xc8);
write_cmos_sensor(0x27, 0xaf);
write_cmos_sensor(0x28, 0x24);
write_cmos_sensor(0x29, 0x1a);
write_cmos_sensor(0x2f, 0x14);
write_cmos_sensor(0x30, 0x00);
write_cmos_sensor(0x31, 0x04);
write_cmos_sensor(0x32, 0x08);
write_cmos_sensor(0x33, 0x0c);
write_cmos_sensor(0x34, 0x0d);
write_cmos_sensor(0x35, 0x0e);
write_cmos_sensor(0x36, 0x0f);
write_cmos_sensor(0x72, 0x98);
write_cmos_sensor(0x73, 0x9a);
write_cmos_sensor(0x74, 0x47);
write_cmos_sensor(0x76, 0x82);
write_cmos_sensor(0x7a, 0xcb);
write_cmos_sensor(0xc2, 0x0c);
write_cmos_sensor(0xce, 0x03);
write_cmos_sensor(0xcf, 0x48);
write_cmos_sensor(0xd0, 0x10);
write_cmos_sensor(0xdc, 0x75);
write_cmos_sensor(0xeb, 0x78);
/*ISP*/
write_cmos_sensor(0x90, 0x01);
write_cmos_sensor(0x92, STARTY);//Don't Change Here!!!
write_cmos_sensor(0x94, STARTX);//Don't Change Here!!!
write_cmos_sensor(0x95, 0x01);
write_cmos_sensor(0x96, 0xe0);
write_cmos_sensor(0x97, 0x02);
write_cmos_sensor(0x98, 0x80);
/*Gain*/
write_cmos_sensor(0xb0, 0x46);
write_cmos_sensor(0xb1, 0x01);
write_cmos_sensor(0xb2, 0x00);
write_cmos_sensor(0xb3, 0x40);
write_cmos_sensor(0xb4, 0x40);
write_cmos_sensor(0xb5, 0x40);
write_cmos_sensor(0xb6, 0x00);
/*BLK*/
write_cmos_sensor(0x40, 0x26);
write_cmos_sensor(0x4e, 0x00);
write_cmos_sensor(0x4f, 0x3c);
/*Dark Sun*/
write_cmos_sensor(0xe0, 0x9f);
write_cmos_sensor(0xe1, 0x90);
write_cmos_sensor(0xe4, 0x0f);
write_cmos_sensor(0xe5, 0xff);
/*MIPI*/
write_cmos_sensor(0xfe, 0x03);
write_cmos_sensor(0x10, 0x00);
write_cmos_sensor(0x01, 0x03);
write_cmos_sensor(0x02, 0x33);
write_cmos_sensor(0x03, 0x96);
write_cmos_sensor(0x04, 0x01);
write_cmos_sensor(0x05, 0x00);
write_cmos_sensor(0x06, 0x80);
write_cmos_sensor(0x11, 0x2b);
write_cmos_sensor(0x12, 0x20);
write_cmos_sensor(0x13, 0x03);
write_cmos_sensor(0x15, 0x00);
write_cmos_sensor(0x21, 0x10);
write_cmos_sensor(0x22, 0x00);
write_cmos_sensor(0x23, 0x30);
write_cmos_sensor(0x24, 0x02);
write_cmos_sensor(0x25, 0x12);
write_cmos_sensor(0x26, 0x02);
write_cmos_sensor(0x29, 0x01);
write_cmos_sensor(0x2a, 0x0a);
write_cmos_sensor(0x2b, 0x03);
write_cmos_sensor(0xfe, 0x00);
write_cmos_sensor(0xf9, 0x0e);
write_cmos_sensor(0xfc, 0x0e);
write_cmos_sensor(0xfe, 0x00);
write_cmos_sensor(0x25, 0xa2);
write_cmos_sensor(0x3f, 0x1a);
Sleep(100);
write_cmos_sensor(0x25,0xe2);
}
接下来,再看get_info、get_resolution函数,主要是获取摄像头模组的工作参数,参考如下:
//gc030amipi_Sensor.c
static kal_uint32 get_info(MSDK_SCENARIO_ID_ENUM scenario_id,MSDK_SENSOR_INFO_STRUCT *sensor_info,MSDK_SENSOR_CONFIG_STRUCT *sensor_config_data)
{
LOG_INF("scenario_id = %d\n", scenario_id);
sensor_info->SensorClockPolarity = SENSOR_CLOCK_POLARITY_LOW;
sensor_info->SensorClockFallingPolarity = SENSOR_CLOCK_POLARITY_LOW; /* not use */
sensor_info->SensorHsyncPolarity = SENSOR_CLOCK_POLARITY_LOW; // inverse with datasheet
sensor_info->SensorVsyncPolarity = SENSOR_CLOCK_POLARITY_LOW;
sensor_info->SensorInterruptDelayLines = 4; /* not use */
sensor_info->SensorResetActiveHigh = FALSE; /* not use */
sensor_info->SensorResetDelayCount = 5; /* not use */
sensor_info->SensroInterfaceType = imgsensor_info.sensor_interface_type;
sensor_info->MIPIsensorType = imgsensor_info.mipi_sensor_type;
sensor_info->SettleDelayMode = imgsensor_info.mipi_settle_delay_mode;
sensor_info->SensorOutputDataFormat = imgsensor_info.sensor_output_dataformat;
sensor_info->CaptureDelayFrame = imgsensor_info.cap_delay_frame;
sensor_info->PreviewDelayFrame = imgsensor_info.pre_delay_frame;
sensor_info->VideoDelayFrame = imgsensor_info.video_delay_frame;
sensor_info->HighSpeedVideoDelayFrame = imgsensor_info.hs_video_delay_frame;
sensor_info->SlimVideoDelayFrame = imgsensor_info.slim_video_delay_frame;
sensor_info->SensorMasterClockSwitch = 0; /* not use */
sensor_info->SensorDrivingCurrent = imgsensor_info.isp_driving_current;
sensor_info->AEShutDelayFrame = imgsensor_info.ae_shut_delay_frame; /* The frame of setting shutter default 0 for TG int */
sensor_info->AESensorGainDelayFrame = imgsensor_info.ae_sensor_gain_delay_frame; /* The frame of setting sensor gain */
sensor_info->AEISPGainDelayFrame = imgsensor_info.ae_ispGain_delay_frame;
sensor_info->IHDR_Support = imgsensor_info.ihdr_support;
sensor_info->IHDR_LE_FirstLine = imgsensor_info.ihdr_le_firstline;
sensor_info->SensorModeNum = imgsensor_info.sensor_mode_num;
sensor_info->SensorMIPILaneNumber = imgsensor_info.mipi_lane_num;
sensor_info->SensorClockFreq = imgsensor_info.mclk;
sensor_info->SensorClockDividCount = 3; /* not use */
sensor_info->SensorClockRisingCount = 0;
sensor_info->SensorClockFallingCount = 2; /* not use */
sensor_info->SensorPixelClockCount = 3; /* not use */
sensor_info->SensorDataLatchCount = 2; /* not use */
sensor_info->MIPIDataLowPwr2HighSpeedTermDelayCount = 0;
sensor_info->MIPICLKLowPwr2HighSpeedTermDelayCount = 0;
sensor_info->SensorWidthSampling = 0; // 0 is default 1x
sensor_info->SensorHightSampling = 0; // 0 is default 1x
sensor_info->SensorPacketECCOrder = 1;
switch (scenario_id) {
case MSDK_SCENARIO_ID_CAMERA_PREVIEW:
sensor_info->SensorGrabStartX = imgsensor_info.pre.startx;
sensor_info->SensorGrabStartY = imgsensor_info.pre.starty;
sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.pre.mipi_data_lp2hs_settle_dc;
break;
case MSDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG:
sensor_info->SensorGrabStartX = imgsensor_info.cap.startx;
sensor_info->SensorGrabStartY = imgsensor_info.cap.starty;
sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.cap.mipi_data_lp2hs_settle_dc;
break;
case MSDK_SCENARIO_ID_VIDEO_PREVIEW:
sensor_info->SensorGrabStartX = imgsensor_info.normal_video.startx;
sensor_info->SensorGrabStartY = imgsensor_info.normal_video.starty;
sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.normal_video.mipi_data_lp2hs_settle_dc;
break;
case MSDK_SCENARIO_ID_HIGH_SPEED_VIDEO:
sensor_info->SensorGrabStartX = imgsensor_info.hs_video.startx;
sensor_info->SensorGrabStartY = imgsensor_info.hs_video.starty;
sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.hs_video.mipi_data_lp2hs_settle_dc;
break;
case MSDK_SCENARIO_ID_SLIM_VIDEO:
sensor_info->SensorGrabStartX = imgsensor_info.slim_video.startx;
sensor_info->SensorGrabStartY = imgsensor_info.slim_video.starty;
sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.slim_video.mipi_data_lp2hs_settle_dc;
break;
default:
sensor_info->SensorGrabStartX = imgsensor_info.pre.startx;
sensor_info->SensorGrabStartY = imgsensor_info.pre.starty;
sensor_info->MIPIDataLowPwr2HighSpeedSettleDelayCount = imgsensor_info.pre.mipi_data_lp2hs_settle_dc;
break;
}
return ERROR_NONE;
}
static kal_uint32 get_resolution(MSDK_SENSOR_RESOLUTION_INFO_STRUCT *sensor_resolution)
{
LOG_INF("E\n");
sensor_resolution->SensorFullWidth = imgsensor_info.cap.grabwindow_width;
sensor_resolution->SensorFullHeight = imgsensor_info.cap.grabwindow_height;
sensor_resolution->SensorPreviewWidth = imgsensor_info.pre.grabwindow_width;
sensor_resolution->SensorPreviewHeight = imgsensor_info.pre.grabwindow_height;
sensor_resolution->SensorVideoWidth = imgsensor_info.normal_video.grabwindow_width;
sensor_resolution->SensorVideoHeight = imgsensor_info.normal_video.grabwindow_height;
sensor_resolution->SensorHighSpeedVideoWidth = imgsensor_info.hs_video.grabwindow_width;
sensor_resolution->SensorHighSpeedVideoHeight = imgsensor_info.hs_video.grabwindow_height;
sensor_resolution->SensorSlimVideoWidth = imgsensor_info.slim_video.grabwindow_width;
sensor_resolution->SensorSlimVideoHeight = imgsensor_info.slim_video.grabwindow_height;
return ERROR_NONE;
}
然后,我们看下feature_control和control函数,feature_control主要用来获取或设置模组的一些特征参数,contral主要用来控制模组拍照、预览、录像等,参考如下:
//gc030amipi_Sensor.c
static kal_uint32 feature_control(MSDK_SENSOR_FEATURE_ENUM feature_id,UINT8 *feature_para,UINT32 *feature_para_len)
{
UINT16 *feature_return_para_16=(UINT16 *) feature_para;
UINT16 *feature_data_16=(UINT16 *) feature_para;
UINT32 *feature_return_para_32=(UINT32 *) feature_para;
UINT32 *feature_data_32=(UINT32 *) feature_para;
unsigned long long *feature_data=(unsigned long long *) feature_para;
SENSOR_WINSIZE_INFO_STRUCT *wininfo;
MSDK_SENSOR_REG_INFO_STRUCT *sensor_reg_data=(MSDK_SENSOR_REG_INFO_STRUCT *) feature_para;
LOG_INF("feature_id = %d\n", feature_id);
switch (feature_id) {
case SENSOR_FEATURE_GET_PERIOD:
*feature_return_para_16++ = imgsensor.line_length;
*feature_return_para_16 = imgsensor.frame_length;
*feature_para_len=4;
break;
case SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ:
*feature_return_para_32 = imgsensor.pclk;
*feature_para_len=4;
break;
case SENSOR_FEATURE_SET_ESHUTTER:
set_shutter(*feature_data);
break;
case SENSOR_FEATURE_SET_NIGHTMODE:
night_mode((BOOL) *feature_data);
break;
case SENSOR_FEATURE_SET_GAIN:
set_gain((UINT16) *feature_data);
break;
case SENSOR_FEATURE_SET_FLASHLIGHT:
break;
case SENSOR_FEATURE_SET_ISP_MASTER_CLOCK_FREQ:
break;
case SENSOR_FEATURE_SET_REGISTER:
write_cmos_sensor(sensor_reg_data->RegAddr, sensor_reg_data->RegData);
break;
case SENSOR_FEATURE_GET_REGISTER:
sensor_reg_data->RegData = read_cmos_sensor(sensor_reg_data->RegAddr);
break;
case SENSOR_FEATURE_GET_LENS_DRIVER_ID:
// get the lens driver ID from EEPROM or just return LENS_DRIVER_ID_DO_NOT_CARE
// if EEPROM does not exist in camera module.
*feature_return_para_32=LENS_DRIVER_ID_DO_NOT_CARE;
*feature_para_len=4;
break;
case SENSOR_FEATURE_SET_VIDEO_MODE:
set_video_mode(*feature_data);
break;
case SENSOR_FEATURE_CHECK_SENSOR_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;
case SENSOR_FEATURE_SET_MAX_FRAME_RATE_BY_SCENARIO:
set_max_framerate_by_scenario((MSDK_SCENARIO_ID_ENUM)*feature_data, *(feature_data+1));
break;
case SENSOR_FEATURE_GET_DEFAULT_FRAME_RATE_BY_SCENARIO:
get_default_framerate_by_scenario((MSDK_SCENARIO_ID_ENUM)*(feature_data), (MUINT32 *)(uintptr_t)(*(feature_data+1)));
break;
case SENSOR_FEATURE_SET_TEST_PATTERN:
set_test_pattern_mode((BOOL)*feature_data);
break;
case SENSOR_FEATURE_GET_TEST_PATTERN_CHECKSUM_VALUE: //for factory mode auto testing
*feature_return_para_32 = imgsensor_info.checksum_value;
*feature_para_len=4;
break;
case SENSOR_FEATURE_SET_FRAMERATE:
LOG_INF("current fps :%d\n", (UINT32)*feature_data);
spin_lock(&imgsensor_drv_lock);
imgsensor.current_fps = *feature_data;
spin_unlock(&imgsensor_drv_lock);
break;
case SENSOR_FEATURE_SET_HDR:
LOG_INF("ihdr enable :%d\n", (BOOL)*feature_data);
spin_lock(&imgsensor_drv_lock);
imgsensor.ihdr_en = (BOOL)*feature_data;
spin_unlock(&imgsensor_drv_lock);
break;
case SENSOR_FEATURE_GET_CROP_INFO:
LOG_INF("SENSOR_FEATURE_GET_CROP_INFO scenarioId:%d\n", (UINT32)*feature_data);
wininfo = (SENSOR_WINSIZE_INFO_STRUCT *)(uintptr_t)(*(feature_data+1));
switch (*feature_data_32) {
case MSDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[1],sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
case MSDK_SCENARIO_ID_VIDEO_PREVIEW:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[2],sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
case MSDK_SCENARIO_ID_HIGH_SPEED_VIDEO:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[3],sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
case MSDK_SCENARIO_ID_SLIM_VIDEO:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[4],sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
case MSDK_SCENARIO_ID_CAMERA_PREVIEW:
default:
memcpy((void *)wininfo,(void *)&imgsensor_winsize_info[0],sizeof(SENSOR_WINSIZE_INFO_STRUCT));
break;
}
break;
case SENSOR_FEATURE_SET_IHDR_SHUTTER_GAIN:
LOG_INF("SENSOR_SET_SENSOR_IHDR LE=%d, SE=%d, Gain=%d\n",(UINT16)*feature_data,(UINT16)*(feature_data+1),(UINT16)*(feature_data+2));
ihdr_write_shutter_gain((UINT16)*feature_data,(UINT16)*(feature_data+1),(UINT16)*(feature_data+2));
break;
default:
break;
}
return ERROR_NONE;
}
static kal_uint32 control(MSDK_SCENARIO_ID_ENUM scenario_id, MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT *image_window,MSDK_SENSOR_CONFIG_STRUCT *sensor_config_data)
{
LOG_INF("scenario_id = %d\n", scenario_id);
spin_lock(&imgsensor_drv_lock);
imgsensor.current_scenario_id = scenario_id;
spin_unlock(&imgsensor_drv_lock);
switch (scenario_id) {
case MSDK_SCENARIO_ID_CAMERA_PREVIEW:
preview(image_window, sensor_config_data);
break;
case MSDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG:
capture(image_window, sensor_config_data);
break;
case MSDK_SCENARIO_ID_VIDEO_PREVIEW:
normal_video(image_window, sensor_config_data);
break;
case MSDK_SCENARIO_ID_HIGH_SPEED_VIDEO:
hs_video(image_window, sensor_config_data);
break;
case MSDK_SCENARIO_ID_SLIM_VIDEO:
slim_video(image_window, sensor_config_data);
break;
default:
LOG_INF("Error ScenarioId setting");
preview(image_window, sensor_config_data);
return ERROR_INVALID_SCENARIO_ID;
}
return ERROR_NONE;
}
最后,是close函数,用来关闭模组,如果不需要特殊操作,在设备驱动的Close操作中,对模组进行下电等操作即可,模组的close函数只是一个空函数:
//gc030amipi_Sensor.c
static kal_uint32 close(void)
{
LOG_INF("E\n");
/*No Need to implement this function*/
return ERROR_NONE;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/38091.html