1. 简介

2. 详细流程

 1)kernel

 2)vendor

3. 思路总结

1)本文思路

2)另一种简单方法

4. 后续改进

1. 简介

Multi module 指的是同样的sensor,但是出自于不同的模组供应商,即sensor 的 ID 相同,module 的 ID 不同。如果使用当前的方法,在 driver 端 probe 都会成功,但是由于不同的模组具有不同的 OTP,lens 等等特性,如果错误的 module 被注册使用, 将会对效果调试产生负面效果。

当前,手机公司或 OEM,可以对 module 供应商,提出 OTP 的烧录规范,这就保证了 OTP eeprom 数据格式, 多模组保持一致,便于读写eeprom,通过区分 module ID,进行兼容性匹配。

2. 详细流程

在当前代码中,module sensor 初始化的步骤大致为 eebin,sensor,eeprom,所以在通过 eeprom 去区分 module ID,为时已晚。所幸,在当前代码中,我们可以通过 eebin 提供的接口,提前获取到 eeprom 的数据。详细如下:

1) Kernel

在 kernel 中,主要包括 dts 和 driver 部分

DTS 中,以msm8937-camera-sensor-mtp.dtsi 为例,主要是注册相关的设备,如 eeprom,camera 等,并且会在 qcom,camera 设备节点,关联相关设备:

eeprom0: qcom,eeprom@0{cell-index=<0>;reg=<0x00>;qcom,eeprom-name="s5k3l8";compatible="qcom,eeprom";qcom,slave-addr=<0xA0>;qcom,cci-master=<0>;qcom,num-blocks=<1>;
......};
qcom,camera@0{cell-index=<0>;compatible="qcom,camera";reg=<0x00>;qcom,csiphy-sd-index=<0>;qcom,csid-sd-index=<0>;qcom,eeprom-src=<&eeprom0>;
......};

Driver,路径为drivers/media/platform/msm/camera_v2/sensor/。对 camera node,只会进行dummy 注册并会默认 probe 成功,具体 camera sensor 的 probe 过程,会在userspace 调用完成。
但对于 eeprom,可以通过配置 userspace_probe 变量,来决定是在 userspace 进行 probe,还是在 kernel 驱动初始化时进行 probe。
当前,为了兼容性匹配,需要设置 eeprom-name 在下层进行数据的读取,即在 eeprom 驱动初始化时,读取出完整的 eeprom 数据,待用。

static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl, struct msm_eeprom_memory_block_t *block)
{
......
uint8_t *memptr = block->mapdata;
......for(j = 0; j < block->num_map; j++){
......if(emap[j].mem.valid_size){e_ctrl->i2c_client.addr_type = emap[j].mem.addr_t;rc=e_ctrl->i2c_client.i2c_func_tbl->i2c_read_seq(&(e_ctrl->i2c_client), emap[j].mem.addr,memptr, emap[j].mem.valid_size);if(rc < 0){pr_err("%s: read failed\n", __func__);return rc;}memptr += emap[j].mem.valid_size;}
......}return rc;
}

在 msm_eeprom.c 中,会通过调用 msm_eeprom_platform_probe 的 read_eeprom_memory 函数,读取 eeprom 的 OTP 数据,并存放于 mapdata 中,此数据会用来在 user space 做 eeprom 数据解析。
通过代码流程,userspace 在 sensor init 调用前,会通过 eebin read 来获取此信息。
在 user space,通过 eebin read 获取到 eeprom 的数据后,即可通过 OTP 规范解析出对应 module 的 module ID,待用。
2) vendor
Probe 函数在 sensor_init.c 文件中,主要调用流程为:先去 probe eebin,再去 probe sensor,最后解析其 OTP 的具体信息。
其 probe 函数位于 module_sensor.c 的 module_sensor_init,如下

mct_module_t *module_sensor_init(const char *name)
{
……
bin_ctl.cmd = EEPROM_BIN_GET_BIN_DATA;
rc = <span>eebin_interface_control</span>(module_ctrl->eebin_hdl, &bin_ctl);
if (rc < 0) {
SERR("failed");
}
/* module_sensor_probe_sensors */
ret = sensor_init_probe(module_ctrl);
if (ret == FALSE) {
SERR("failed");
goto ERROR1;
}
……
/* intiialize the eeprom */
ret = mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_init_eeprom,
module_ctrl->eebin_hdl);
if (ret == FALSE) {
SERR("failed");
goto ERROR1;
}
……
}

通过此函数,可以看出,首先会对 eebin 操作,获取有用的信息,其次进行 sensor_init_probe,最后,将会对 eeprom 进行解析。
完成 multi module 的兼容,需要针对的地方为 eebin_interface_control。
在 eebin_interface_control 函数中,会通过 eebin_interface_control -->> eebin_get_bin_data -->> eebin_read -->> eebin_dev_read 函数读取 cmm-data。需要修改的就是 eebin_dev_read 函数。

static boolean eebin_dev_read(eebin_hdl_t *eebin_hdl,
const char* dev_name, char**buff, uint32_t *num)
{
……
dev_fd = open(dev_name, O_RDWR);
if (dev_fd < 0) {
SHIGH("Open eeprom dev failed: %s", dev_name);
return FALSE;
}
cfg.cfgtype = CFG_EEPROM_GET_MM_INFO;
cfg.cfg.get_cmm_data.cmm_support = 0;
cfg.cfg.get_cmm_data.cmm_compression = 0;
cfg.cfg.get_cmm_data.cmm_size = 0;
if (ioctl(dev_fd, VIDIOC_MSM_EEPROM_CFG, &cfg) < 0) {
SHIGH("VIDIOC_MSM_EEPROM_CFG failed!");
goto end;
}
if (!cfg.cfg.get_cmm_data.cmm_support || !cfg.cfg.get_cmm_data.cmm_size)
goto end;
buff_l = malloc(cfg.cfg.get_cmm_data.cmm_size);
if (!buff_l){
SERR("%s failed allocating memory\n",__func__);
goto end;
}
cfg.cfgtype = CFG_EEPROM_READ_CAL_DATA;
cfg.cfg.read_data.num_bytes = cfg.cfg.get_cmm_data.cmm_size;
cfg.cfg.read_data.dbuffer = buff_l;
if (ioctl(dev_fd, VIDIOC_MSM_EEPROM_CFG, &cfg) < 0) {
SERR("CFG_EEPROM_READ_CAL_DATA failed!");
goto end_free;
}
……
}

对于这个函数中,我们可以通过修改 cmm 结构体,来获取相关信息。关于 cmm 相关设置,可以参考:kernel/Documentation/devicetree/bindings/media/video/msm-eeprom.txt。
如下:

Optional properties -EEPROM Camera Multimodule
- qcom,cmm-data-support - Camera MultiModule data capability flag.
- qcom,cmm-data-compressed - Camera MultiModule data compression flag.
- qcom,cmm-data-offset - Camera MultiModule data start offset.
- qcom,cmm-data-size - Camera MultiModule data size.

在读取 buff_l 前,可以通过比较当前设备名是否为"/dev/v4l-subdevX“来确定是否是我们需要的能获取到 module ID 的 eebin 的值,当前 8937 平台,前后摄分别为"/dev/v4l-subdev6“,"/dev/v4l-subdev7“。具体设备名,可以在 kernel 启动 probe 并注册时获取到。因此在代码中,添加类似代码,如:

cfg.cfgtype = CFG_EEPROM_READ_CAL_DATA;
cfg.cfg.read_data.num_bytes = cfg.cfg.get_cmm_data.cmm_size;
cfg.cfg.read_data.dbuffer = buff_l;
if (ioctl(dev_fd, VIDIOC_MSM_EEPROM_CFG, &cfg) < 0) {
SERR("CFG_EEPROM_READ_CAL_DATA failed!");
goto end_free;
}
<span>if (!strcmp(dev_name,"/dev/v4l-subdev6")) {
ID-0 = Special_FUNC(buff_l)
} else if (!strcmp(dev_name,"/dev/v4l-subdev7")) {
ID-1 = Special_FUNC(buff_l)
}</span>

其中 ID-0, ID-1 为全局变量,会在 sensor_init_probe 时,通过此 ID,对 XML 中注册的模组进行过滤操作。
通过此上步骤,即可获取 ID-0, ID-1。
而对 sensor_init_probe -->> sensor_init_xml_probe 时,在此函数中:

static boolean sensor_init_xml_probe(module_sensor_ctrl_t *module_ctrl,
int32_t sd_fd)
{
……
/* Get number of camera module configurations */
num_cam_config = sensor_xml_util_get_num_nodes(rootPtr, "CameraModuleConfig");
SLOW("num_cam_config = %d", num_cam_config);
if (!num_cam_config || num_cam_config > MAX_CAMERA_CONFIG) {
SERR(" invalid num_cam_config = %d", num_cam_config);
ret = FALSE;
goto XML_PROBE_EXIT;
}xmlConfig.docPtr = docPtr;
xmlConfig.configPtr = &camera_cfg;for (i = 0; i < num_cam_config; i++) {
nodePtr = sensor_xml_util_get_node(rootPtr, "CameraModuleConfig", i);
RETURN_ON_NULL(nodePtr);xmlConfig.nodePtr = nodePtr;
ret = sensor_xml_util_get_camera_probe_config(&xmlConfig);
if (ret == FALSE) {
ret = FALSE;
goto XML_PROBE_EXIT;
}if (slot_probed[camera_cfg.camera_id]) {
SHIGH("slot %d already probed", camera_cfg.camera_id);
continue;
}rc = sensor_probe(module_ctrl, sd_fd, camera_cfg.sensor_name,
NULL, &xmlConfig);
if (rc == FALSE) {
SERR("failed: to probe %s", camera_cfg.sensor_name);
} else {
slot_probed[camera_cfg.camera_id] = TRUE;
}
}
……
}

在此函数中,会获取 xml 文件定义的所有支持的 sensor 的个数,保存为 num_cam_config,在对 num_cam_config 的循环时,我们就可以通过刚才获得的 ID-0, ID-1 等对 xml 文件中定义的 sensor 进行 probe 的操作。Xml 文件中,通常的模式为:

<CameraModuleConfig>
<CameraId>0</CameraId>
<SensorName>s5k3l8</SensorName>
<FlashName>pmic</FlashName>
<EepromName>s5k3l8</EepromName>
……
<ChromatixName>qtech_s5k3l8_f3l8yam_chromatix</ChromatixName>
……
</CameraModuleConfig>

由于不同的模组,会对应不同的 chromatx tuning 文件,因此,在获取不同的 module ID,即 ID-0, ID-1 后,在对不同的 ChromatixName 进行筛选,剔除 sensor ID 一致,但 module ID 不一致的 module 文件。
大致代码如下:

for (i = 0; i < num_cam_config; i++) {
……
int main_camera_eeprom_id = ID-0;
…...
<span>if (!strcmp(camera_cfg.sensor_name, "sensor-name")) { //confirm the module name
which we need to do filter
if (main_camera_eeprom_id == moduleID-1) { //compare the Module ID
//only when the module ID and chromatix name is matched, probe
this ensor
if (strcmp(camera_cfg.actuator_name, "chromatix-name1"))
continue;
} else if (main_camera_eeprom_id == moduleID-1) {
if (strcmp(camera_cfg.actuator_name, "chromatix-name2"))
continue;
}
}</span>
……
}

从此,即可通过 module ID 过滤掉即使 sensor ID 一致的 module,并且阻止这些模组进行 kernel 的 probe 过程。

3. 思路总结
1) 本文思路:
综上所述,完成 multi module 的适配。
需要做的准备是:
1. 按照统一的格式完成 OTP 的烧录
2. 在 DTS 文件中,写入正确的 map 信息
3. 在 xml 文件中,正确注册不同 module 的信息,包括所需的 chromatixName
4. 做好 Module ID 和 chromatixName 的对应关系
代码的流程是:
1. 在 msm_eeprom.c 的 driver 中,完成 eeprom 的 probe 以及 memory 的读入存储
2. 在 vendor probe sensor 的过程中
a) 通过 eebin_interface_control -->> eebin_get_bin_data -->> eebin_read -->> eebin_dev_read 获取 module ID, 并存储于 vendor 进程中,以备后用
b) 通过 sensor_init_probe -->> sensor_init_xml_probe,对 module 进行筛选,通过 module ID 和 chromatixName 的匹配关系,过滤掉不匹配的 module,即不进行 kernel 层 sensor ID 的匹配

2) 另一种简单方法:
1. 在 msm_eeprom.c 的 driver 中,完成 eeprom 的 probe 以及 memory 的读入存储
2. 对于读取的 eeprom 数据,在 kernel 层驱动中,即使 OTP 规范不同,也可以根据不同的 eeprom name 进行区分,进而简单的解析,保存对应的 module ID
3. 添加新的 dummy 设备,其功能只需要使得 user space 能够通过设备节点,获取 module ID
4. 在 sensor_init_probe 之前,通过此新的设备,获取 module ID
5. 通过 sensor_init_probe -->> sensor_init_xml_probe,对 module 进行筛选,通过 module ID 和 chromatixName 的匹配关系,过滤掉不匹配的 module,即不进行 kernel 层 sensor ID 的匹配
此方法,不用修改 eebin 函数,并且流程上更为清晰。

4.后续改进
1. Xml 文件中添加 module ID 参数,用以唯一定位 module 型号,以取代 chromatixName 模式
2. 增加接口和参数,在传递 sensor ID 的同时传递 module ID,进行 kernel 层的 sensor probe 工作。
3. 添加 eeprom 的 map 参数接口,或者 module ID。

如何在软件中实现多camera模组的兼容相关推荐

  1. 手机摄像头的心得体会---camera模组生产流程

    首先开始做一款手机,要提前做好一个时间表,这个时间表从讨论做什么样的手机一直到最后的手机量产.一般过程PE-----PDR----PCL----PEL-----POR-----EVT-----DVT- ...

  2. camera模组 ------- super Good

    come from :https://blog.csdn.net/xubin341719/article/details/7723725 关键词:android  camera CMM 模组 came ...

  3. Camera模组详解

    一 Camera模组 大家都知道,手机背面的那个小小的孔,就叫摄像头.这个小孔幽幽的泛着光泽,深邃又迷人,如同一个含苞待放的小萝莉一样,这个小萝莉还是个傲娇娘,像零之使魔的614一样惹人怜爱,而且在小 ...

  4. opencv实现camera模组的暗电流和lenshading补偿

    简介 在接触过的qcom和mtk平台中,camera调试软件和流程基本都是大同小异.所以查了点资料,然后模仿这些软件,自己练习写了下最开始的 两步:暗电流和len shading补偿. 基本原理 产生 ...

  5. 中移M5310A NBIoT模组通信测试命令

    总结一下中移M5310A NBIoT模组的常用测试命令,这个命令是个脚本,可以编辑,在自己开发的串口软件上可用,有需要的请留言. 脚本是.ini格式的文件,可以直接编辑文件然后加载到脚本区.字段用\t ...

  6. Android Camera(一):camera模组CMM介绍

    关键词:android camera CMM 模组 camera参数 平台信息: 内核:linux 系统:android 平台:S5PV310(samsung exynos 4210) 新项目开案,代 ...

  7. S5PV210开发板 camera模组CMM介绍

    关键词:android camera CMM 模组 camera参数 平台信息: 内核:linux 系统:android 平台:S5PV310(samsung exynos 4210) 作者:xubi ...

  8. Android开发之十四: camera(一):camera模组CMM介绍

    https://blog.csdn.net/gabbzang/article/details/9457459 android camera(一):camera模组CMM介绍 android camer ...

  9. camera基础知识——1、camera模组简介

    1. 前言 博主作为一个camera驱动码农,在刚接触camera知识的时候难免有点转变不过来,难以接受,博主也深有体会.看着厚厚的camera datasheet,不知道如何下手编写驱动代码.但是在 ...

最新文章

  1. Nginx安装方式介绍
  2. JS制作常见通知信息(适用于手机通知信息和电脑通知信息)
  3. 程序开机全屏且不能见任何windows界面、不能使用系统热键
  4. disconf mysql_disconf-web 安装
  5. 华为p7刷android go,华为首款Android GO手机发布 1G内存也流畅
  6. edittext在哪可以获取有效值_java-从EditText获取文本字符串?
  7. Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送...
  8. sentinel3数据批量下载——sentinelsat
  9. 38个敏感词_敏感词运营体系搭建手册—正则关键词
  10. java gb28181网关_视频网关GB28181协议转换解决方案
  11. 彻底关闭win10自动更新
  12. python小世界网络生成
  13. ni visa pci_VISA/MASTER信用卡在线缴费友邦、保诚步骤!
  14. NOI2016 滚粗记
  15. win7计算机图标排列,win7系统桌面图标排列顺序打乱的操作方法
  16. Hi3519v101 uart驱动
  17. 【最终总结版】linux内核编译过程
  18. 隐马尔科夫模型(HMM)理解与总结
  19. 还在为创业资金发愁?1000万元+产业资源等你来拿!
  20. Android 用Groovy实现扇贝阅读APP的自动阅读功能

热门文章

  1. 2021广东省高考成绩查询时间,广东省高考成绩查询时间及方式公布
  2. 006_Topic消息模式发送对象消息
  3. 024_Jedis连接池
  4. 045_CSS3过渡
  5. 004-SLF4J的简单使用
  6. mysql hostname uroot_CACTI网络流量监控
  7. mysql raiserror_RAISERROR在SQL Server数据库中的用法
  8. python分解word文档为多个_将一个word文档按一页或多页拆分成多个文档
  9. Observer模式在J2EE中的实现
  10. Oracle表空间查询及扩充表空间