MTK camera驱动浅析(1)

news/2024/11/23 2:09:39/

目录

一.主要文件

二.camera框架中的结构

三.camera驱动初始化流程


一.主要文件

         1.文件路径         

        kernel-4.19/drivers/misc/mediatek/imgsensor/src/common/v1/

         2.文件内容介绍

 

二.camera框架中的结构

         整个框架的关键结构体是IMGSENSOR,可以看到它包含了IMGSENSOR_HW(上电相关)结构体和IMGSENSOR_SENSOR sensor[ ]结构体数组等一些成员,当前项目使用到的cmos sensor(图像传感器,后面都称呼为sensor)的各种信息就会随着这个驱动框架的启动在这个数组中完成初始化以及调用,如果项目中有一个前摄像头一个后摄像头,这个结构体数组中就会有两个元素将它们分别保存起来。具体结构如下:

struct IMGSENSOR {struct IMGSENSOR_STATUS status;struct IMGSENSOR_HW hw;//上电用到struct IMGSENSOR_CLK clk;struct IMGSENSOR_SENSOR sensor[IMGSENSOR_SENSOR_IDX_MAX_NUM];//操作sensor用到/* 省略部分成员 */
};

三.camera驱动初始化流程

         入口函数注册一个platform驱动:      

static int __init imgsensor_init(void) {if (platform_driver_register(&gimgsensor_platform_driver)) {PK_DBG("failed to register CAMERA_HW driver\n");return -ENODEV;}/* ...省略部分代码... */return 0;
}

         platform驱动结构体如下:

#ifdef CONFIG_OF
static const struct of_device_id gimgsensor_of_device_id[] = {{.compatible = "mediatek,imgsensor",},    //与设备树进行匹配{}
};
#endifstatic struct platform_driver gimgsensor_platform_driver = {.probe   = imgsensor_probe,    //匹配成功调用probe函数.remove  = imgsensor_remove,.suspend = imgsensor_suspend,.resume  = imgsensor_resume,.driver  = {.name  = "image_sensor",.owner = THIS_MODULE,
#ifdef CONFIG_OF.of_match_table = gimgsensor_of_device_id,
#endif}
};

         与设备树匹配成功之后会调用probe()函数:

static int imgsensor_probe(struct platform_device *pdev) {/* 注册字符设备 */if (imgsensor_driver_register()) {PK_DBG("[CAMERA_HW] register char device failed!\n");return -1;}/* ...省略部分代码... *//* 上电初始化 */imgsensor_hw_init(&pgimgsensor->hw);/* 注册i2c driver */imgsensor_i2c_create();/* proc文件系统初始化  */imgsensor_proc_init();/* ...省略部分代码... */return 0;
}

         probe()函数主要做了创建字符设备、上电信息初始化、添加i2c设备等工作。其中的注册字符设备时添加了文件操作集:

static const struct file_operations gimgsensor_file_operations = {.owner          = THIS_MODULE,.open           = imgsensor_open,.release        = imgsensor_release,.unlocked_ioctl = imgsensor_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl   = imgsensor_compat_ioctl
#endif
};

         这里可以看到camera设备驱动使用ioctl来控制,imgsensor_ioctl()函数实现如下:

static long imgsensor_ioctl(struct file *a_pstFile,unsigned int a_u4Command,unsigned long a_u4Param) {int i4RetValue = 0;void *pBuff = NULL;if (_IOC_DIR(a_u4Command) != _IOC_NONE) {pBuff = kmalloc(_IOC_SIZE(a_u4Command), GFP_KERNEL);/* ...省略部分代码... */if (_IOC_WRITE & _IOC_DIR(a_u4Command)) {if (copy_from_user(pBuff, (void *) a_u4Param, _IOC_SIZE(a_u4Command)))/* ...省略部分代码... */} elsememset(pBuff, 0, _IOC_SIZE(a_u4Command));} /* ...省略部分代码... */switch (a_u4Command) {case KDIMGSENSORIOC_X_GET_CONFIG_INFO:i4RetValue = adopt_CAMERA_HW_GetInfo(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_X_SET_MCLK_PLL:i4RetValue = imgsensor_clk_set(&pgimgsensor->clk,(struct ACDK_SENSOR_MCLK_STRUCT *) pBuff);break;/* ...省略部分代码... */}/* ...省略部分代码... */return i4RetValue;
}

         这里除了获取一些信息之外,有一个adopt_CAMERA_HW_FeatureControl()函数实现通过ioctl来控制硬件:

static inline int adopt_CAMERA_HW_FeatureControl(void *pBuf) {struct ACDK_SENSOR_FEATURECONTROL_STRUCT *pFeatureCtrl;struct IMGSENSOR_SENSOR *psensor;unsigned int FeatureParaLen = 0;void *pFeaturePara = NULL;struct ACDK_KD_SENSOR_SYNC_STRUCT *pSensorSyncInfo = NULL;signed int ret = 0;pFeatureCtrl = (struct ACDK_SENSOR_FEATURECONTROL_STRUCT *) pBuf;/* InvokeCamera与sensor枚举对应,例如0代表前摄,1代表后摄 */psensor = imgsensor_sensor_get_inst(pFeatureCtrl->InvokeCamera);if (copy_from_user((void *) &FeatureParaLen,(void *) pFeatureCtrl->pFeatureParaLen,sizeof(unsigned int))) {PK_DBG(" ioctl copy from user failed\n");return -EFAULT;}/* ...省略部分代码... */pFeaturePara = kmalloc(FeatureParaLen, GFP_KERNEL);memset(pFeaturePara, 0x0, FeatureParaLen);/* copy from user */switch (pFeatureCtrl->FeatureId) {case SENSOR_FEATURE_OPEN:ret = imgsensor_sensor_open(psensor);break;case SENSOR_FEATURE_CLOSE:ret = imgsensor_sensor_close(psensor);/* reset the delay frame flag */break;case SENSOR_FEATURE_SET_DRIVER: {MINT32 drv_idx;psensor->inst.sensor_idx = pFeatureCtrl->InvokeCamera;drv_idx = imgsensor_set_driver(psensor);memcpy(pFeaturePara, &drv_idx, FeatureParaLen);break;}case SENSOR_FEATURE_CHECK_IS_ALIVE:imgsensor_check_is_alive(psensor);break;/* ...省略部分代码... */imgsensor_sensor_feature_control(psensor,SENSOR_FEATURE_SET_ESHUTTER,(unsigned char *) &pSensorSyncInfo->u2SensorNewExpTime,(unsigned int *) &FeatureParaLen);imgsensor_sensor_feature_control(psensor,SENSOR_FEATURE_SET_GAIN,(unsigned char *) &pSensorSyncInfo->u2SensorNewGain,(unsigned int *) &FeatureParaLen);break;return ret;}
}

         imgsensor_sensor_get_inst()这个函数传入的是ioctl的参数,这个参数直接作为数组索引,拿到了文章开头的struct IMGSENSOR_SENSOR sensor[ ]数组中的一个元素地址,准备开始初始化这个ioctl参数所代表的sensor:

struct IMGSENSOR_SENSOR *imgsensor_sensor_get_inst(enum IMGSENSOR_SENSOR_IDX idx) {if (idx < IMGSENSOR_SENSOR_IDX_MIN_NUM ||idx >= IMGSENSOR_SENSOR_IDX_MAX_NUM)return NULL;elsereturn &pgimgsensor->sensor[idx];
}

         之后会调用imgsensor_set_driver()函数用来设定某一个具体的sensor:

int imgsensor_set_driver(struct IMGSENSOR_SENSOR *psensor) {u32 drv_idx = 0;int ret = -EIO;struct IMGSENSOR_SENSOR_INST *psensor_inst = &psensor->inst;/* kdSensorList[]数组包含具体sensor的驱动信息 */struct IMGSENSOR_INIT_FUNC_LIST *pSensorList = kdSensorList;
#define TOSTRING(value)           #value
#define STRINGIZE(stringizedName) TOSTRING(stringizedName)
/** 在配置文件xxx_defconfig中申明可使用的sensor名字,* 例如当前项目的配置:* CONFIG_CUSTOM_KERNEL_IMGSENSOR="ovxxxx_qtech_main_mipi_raw gcxxxx_kingc_front_mipi_raw*                         s5k4xxxx_kingc_main_mipi_raw ovxxxx_ofilm_front_mipi_raw"* 这就表示当前项目支持ovxxxx、gcxxxx、三星xxx等这四个摄像头*/char *psensor_list_config = NULL, *psensor_list = NULL;char *sensor_configs = STRINGIZE(CONFIG_CUSTOM_KERNEL_IMGSENSOR);static int orderedSearchList[MAX_NUM_OF_SUPPORT_SENSOR] = {-1};static bool get_search_list = true;int i = 0;int j = 0;char *driver_name = NULL;imgsensor_mutex_init(psensor_inst);/* 绑定i2c */imgsensor_i2c_init(&psensor_inst->i2c_cfg,imgsensor_custom_config[(unsigned int) psensor_inst->sensor_idx].i2c_dev);imgsensor_i2c_filter_msg(&psensor_inst->i2c_cfg, true);/* 配置文件和kdSensorList[]数组中的信息匹配 */if (get_search_list) {psensor_list = psensor_list_config =kmalloc(strlen(sensor_configs) - 1, GFP_KERNEL);if (psensor_list_config) {for (j = 0; j < MAX_NUM_OF_SUPPORT_SENSOR; j++)orderedSearchList[j] = -1;memcpy(psensor_list_config,sensor_configs + 1,strlen(sensor_configs) - 2);*(psensor_list_config + strlen(sensor_configs) - 2) = '\0';PK_DBG("sensor_list %s\n", psensor_list_config);driver_name = strsep(&psensor_list_config, " \0");while (driver_name != NULL) {for (j = 0;j < MAX_NUM_OF_SUPPORT_SENSOR;j++) {if (pSensorList[j].init == NULL)break;else if (!strcmp(driver_name,pSensorList[j].name)) {orderedSearchList[i++] = j;break;}}driver_name =strsep(&psensor_list_config, " \0");}get_search_list = false;}kfree(psensor_list);}for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {/*PK_DBG("orderedSearchList[%d]=%d\n",*i, orderedSearchList[i]);*/if (orderedSearchList[i] == -1)continue;drv_idx = orderedSearchList[i];if (pSensorList[drv_idx].init) {/* 匹配完成之后调用具体的某个sensor的初始化函数 */pSensorList[drv_idx].init(&psensor->pfunc);if (psensor->pfunc) {/* get sensor name */psensor_inst->psensor_name =(char *) pSensorList[drv_idx].name;
#ifdef IMGSENSOR_LEGACY_COMPATpsensor_inst->status.arch =psensor->pfunc->arch;
#endif/* 上下电 */if (!imgsensor_check_is_alive(psensor)) {PK_DBG("[%s]:[%d][%d][%s]\n",__func__,psensor->inst.sensor_idx,drv_idx,psensor_inst->psensor_name);ret = drv_idx;break;}} else {PK_DBG("ERROR:NULL g_pInvokeSensorFunc[%d][%d]\n",psensor->inst.sensor_idx,drv_idx);}} else {PK_DBG("ERROR:NULL sensor list[%d]\n", drv_idx);}}imgsensor_i2c_filter_msg(&psensor_inst->i2c_cfg, false);return ret;
}

         具体分析这段代码,发现它主要做了这样一些工作:

  1.  根据ioctl参数初始化i2c设备
  2. 检查当前项目支持哪些sensor
  3. 初始化ioctl参数代表的这个sensor,绑定sensor的操作函数
  4. 执行一次上下电操作来试验一下这个sensor。

         其中,检查当前支持的sensor过程如下:

         ①申明一个数组orderedSearchList[MAX_NUM_OF_SUPPORT_SENSOR],从命名来看是“有序地搜索”,长度是最大支持的sensor,用来保存当前项目支持的sensor信息。

         ②把配置文件中保存的sensor名字取出来保存到psensor_list_config。

         ③用strsep()函数来分解psensor_list_config,结果用driver_name保存。

         ④把driver_name和pSensorList[]中保存的sensor的name相比对,如果名字对应,就把该sensor在pSensorList[]中的索引值保存到orderedSearchList[]数组。

         匹配过程如下图所示:


 

         为sensor绑定操作函数,通过调用sensor_func就可以实现对sensor的操作:

static struct SENSOR_FUNCTION_STRUCT sensor_func = {open,//初始化和注册get_info,get_resolution,feature_control,//对sensor工作模式等进行设置control,close
};/* init */
UINT32 OV8856_QTECH_MAIN_MIPI_RAW_SensorInit(struct SENSOR_FUNCTION_STRUCT **pfFunc) {if (pfFunc != NULL)*pfFunc = &sensor_func;return ERROR_NONE;
}

         使用imgsensor_check_is_alive()函数来试验sensor,也就是执行上下电操作:

static inline int imgsensor_check_is_alive(struct IMGSENSOR_SENSOR *psensor) {struct IMGSENSOR_SENSOR_INST *psensor_inst = &psensor->inst;UINT32 err = 0;MUINT32 sensorID = 0;MUINT32 retLen = sizeof(MUINT32);IMGSENSOR_PROFILE_INIT(&psensor_inst->profile_time);/* 上电 */err = imgsensor_hw_power(&pgimgsensor->hw,psensor,psensor_inst->psensor_name,IMGSENSOR_HW_POWER_STATUS_ON);/* 检查sensor id */if (err == IMGSENSOR_RETURN_SUCCESS)imgsensor_sensor_feature_control(psensor,SENSOR_FEATURE_CHECK_SENSOR_ID,(MUINT8 * ) & sensorID,&retLen);if (sensorID == 0 || sensorID == 0xFFFFFFFF) {PK_DBG("Fail to get sensor ID %x\n", sensorID);err = ERROR_SENSOR_CONNECT_FAIL;} else {PK_DBG(" Sensor found ID = 0x%x\n", sensorID);err = ERROR_NONE;}if (err != ERROR_NONE)PK_DBG("ERROR: No imgsensor alive\n");/* 下电 */imgsensor_hw_power(&pgimgsensor->hw,psensor,psensor_inst->psensor_name,IMGSENSOR_HW_POWER_STATUS_OFF);IMGSENSOR_PROFILE(&psensor_inst->profile_time, "CheckIsAlive");return err ? -EIO : err;
}

         具体上电过程后续分析。(未完待续)

         本人还在入门阶段,欢迎大家指出错误。

参考巨佬博客:karaskass的博客_CSDN博客-camera driver+hal+framework,《Android深度探索 卷1 HAL与驱动开发》笔记,audio driver+hal+framework领域博主

                  


http://www.ppmy.cn/news/435747.html

相关文章

mtk最新刷机平台SP_Flash_Tool_v6.2208_Win

SP Flash Tool v6.2208是一款针对Windows电脑的小应用&#xff0c;可以让你在联发科芯片组驱动的设备手机 平板上刷新或安装rom固件 无论是智能手机、平板电脑还是功能手机。它还允许 您刷新或安装自定义恢复(CWM/TWRP)、引导文件&#xff0c;并从联发科设备中移除工厂重置保护…

mtkwin10驱动_联发科MTK刷机驱动(支持WIN10)驱动

这是联发科MTK刷机驱动(支持WIN10)驱动,能够帮助电脑连接MTK系统的智能手机,拥有ADB联机驱动和刷机驱动自动安装版,并且兼容win7系统。‍ 驱动介绍 本驱动由本站独家制作的MTK全系列刷机驱动。 适用于全系列MTK芯片的COM口刷机驱动,包括手机,手表等设备。 支持WINXP,WIN7…

MTK 安卓核心板 / 安卓开发板 4G/5G 核心板相关方案定制

安卓核心板是将核心功能封装的一块电子主板&#xff0c;集成芯片、存储器和功放器件等&#xff0c;并提供标准接口的芯片。接口主要包括 LCD 电路&#xff0c;Camera 电路&#xff0c;USB 电路&#xff0c;SIM 电路&#xff0c;键盘电路等接口电路&#xff0c;内置主控芯片和内…

mtkwin10驱动_MTK手机刷机驱动下载|MTK通用USB刷机驱动 Win7/Win10 自动安装版 下载_当下软件园_软件下载...

MTK通用USB刷机驱动是一款非常好用联发科MTK处理器刷机驱动程序。之前有不少用户表示自己无法正常进行刷机操作&#xff0c;这是因为没有安装程序的原因&#xff0c;现在下载安装之后&#xff0c;电脑就可以和MTK系统的智能手机正确连接进行操作&#xff0c;支持Win7/8/10操作系…

es6 的模块化由来

es 模块化&#xff0c;之前是没有的。没有的时候&#xff0c;用的是社区创建的commjs模块化 commjs模块其实是一个对象&#xff0c;这个对象要在代码运行的时候才会创建出来的 这有个不好的地方&#xff0c;就是不能在编译的时候找到依赖文件&#xff0c;也不能进行类型检查&…

想变现,但还不知道做什么课程,给你4个方向

哈喽&#xff0c;大家好&#xff0c;我是海哥&#xff0c;知识付费变现创业教练&#xff0c;教育公司培训总监&#xff0c;从事知识付费变现咨询10年&#xff0c;已助力3000人实现知识付费变现。 自媒体博主&#xff0c;可以做什么课程赚钱&#xff1f; 想变现&#xff0c;但还…

文学作品中常见的20个修辞手法(含示例)

比喻:用一个事物来说明另一个事物,以便更好地描述它。示例:他的眼睛像夜空中的明星一样闪耀。 拟人:将非人类的事物描述成有人类的思想、感情和行为。示例:花儿在微笑,风儿在唱歌。 暗示:通过暗示来表达意思,而不是直接说出来。示例:他轻轻地摇了摇头,示意我不要再问…

硬盘盘面损伤

出现下列某种现象时&#xff0c;应当考虑一下硬盘盘面是否已有物理损伤&#xff1a; &#xff08;1&#xff09;读写硬盘时&#xff0c;屏幕经常提示“Sector not found”&#xff08;扇区未找到&#xff09;或“General error in reading drive C”&#xff08;读取C盘时的常规…