camera驱动框架分析(上)

前言

  camera驱动框架涉及到的知识点比较多,特别是camera本身的接口就有很多,有些是直接连接到soc的camif口上的,有些是通过usb接口导出的,如usb camera。我这里主要讨论前者,也就是与soc直连的。我认为凡是涉及到usb的,都不是一两句话可以说明白的!如有错误,欢迎指正,谢谢!!!

环境说明

涉及到的基础知识点:
字符设备驱动
设备模型
平台设备驱动
v4l2框架
i2c驱动框架

涉及到的术语:
camera : 指的是整个camera,包括它本身的硬件连接方式及支持i2c控制的i2c设备
sensor : 指的是支持i2c控制的i2c设备,它属于camera的一部分,在内核实现里也能体现出来
camera host: 指的是与camera相连接的,一般内嵌在soc里面的控制器

涉及到的文件夹:
drivers/media/platform/soc_camera/ 主要存放camera host驱动,通用的camera驱动也存放在此
drivers/media/i2c/soc_camera/ 主要存放sensor驱动

分析所采用的内核版本:

VERSION = 3                                                                                                                                                   
PATCHLEVEL = 15                                                                 
SUBLEVEL = 0                                                                    
EXTRAVERSION =                                                                  
NAME = Shuffling Zombie Juror    

camera的驱动包括通用camera的驱动、camera host的驱动以及sensor的驱动,下面一个个来分析

这里先插一张图,来自:http://blog.csdn.net/kickxxx/article/details/8484498(该图片及图片后的文字是在我写完这篇博文后发现的,我认为对理解camera驱动会有帮助,所以就摘抄了^_^)
soc camera 子系统 系统架构图

Soc camera sub-system对应着drivers/media/video/下的soc_camera.c soc_camera_platform.c

Soc camera host 是host端实现,是由平台厂商实现的,向上实现soc_camera_host_ops接口,向下操作Camera host硬件以及通过平台特定的接口操作Soc camera device

Soc camera device 是平台的camera device(同时也是subdev),由驱动开发者来实现v4l2_subdev_call调用的subdev 接口,同时还要为soc camera host实现平台特定的操作接口;向下操作camera sensor或者video AD芯片。

Camera host hardware是平台硬件相关的,不同的平台有不同的host硬件,比如imx51的ipu,三星s5pv210的fimc控制器等。

soc_camera_host,soc_camera_device,v4l2_device,v4l2_subdev关系如下:理论上系统内可以有多个soc_camera_host,物理上soc_camera_host就是系统的camera处理模块驱动一个soc_camera_host可以对应多个soc_camera_device,物理上soc_camera_device是一个camera接口,每个soc_camera_host对应一个v4l2_dev每个soc_camera_device,系统会为他们创建设备节点/dev/videoX。每个soc_camera_device有多个v4l2_subdev,物理上v4l2_subdev可以是sensor,video AD芯片v4l2_subdev可以通过i2c挂接到v4l2_device,也可以通过soc_camera_link提供的add_device来增加,这依赖于sensor和video AD芯片挂接到MCU camera接口的方式。

通用camera驱动

对应文件drivers/media/platform/soc_camera/soc_camera.c

static struct platform_driver __refdata soc_camera_pdrv = {.probe = soc_camera_pdrv_probe,.remove  = soc_camera_pdrv_remove,.driver  = {.name   = "soc-camera-pdrv",.owner  = THIS_MODULE,},
};module_platform_driver(soc_camera_pdrv);

从这里可以看出,我们要使该驱动probe得到调用,先得注册一个平台设备,且名字为soc-camera-pdrv。通用camera的驱动就是定义了一套数据结构,然后告诉大家,你如果想用通用的camera驱动,那就照着数据结构填好,然后用soc-camera-pdrv的名字通过平台总线注册上来就可以了。平台设备的注册可以通过两种方式来实现,一种是通过设备树,它是最新的一种机制,通过dts文件来描述硬件信息,使得内核里面不会再硬编码一堆和用于描述硬件信息的代码。对应到这里的硬件信息就是camera sensor硬件信息以及camera硬件布线信息。另一种就是以前采用的方式,直接用代码在板子相关的启动文件里来描述那些信息并通过平台设备的注册。soc_camera_pdrv里面没有设备树的相关支持,说明这类设备的添加还是采用后面那种方式,通过下面的命令输出也可以证实这一点:

我用命令(grep -rns soc-camera-pdrv arch/arm*/)搜索一下,就可以得到以下结果:

arch/arm/mach-shmobile/board-lager.c:394:   platform_device_register_data(&platform_bus, "soc-camera-pdrv", 1,
arch/arm/mach-shmobile/board-bockw.c:606:   platform_device_register_data(&platform_bus, "soc-camera-pdrv", 0,
arch/arm/mach-shmobile/board-bockw.c:609:   platform_device_register_data(&platform_bus, "soc-camera-pdrv", 1,
arch/arm/mach-shmobile/board-mackerel.c:1224:   .name   = "soc-camera-pdrv",
arch/arm/mach-shmobile/board-armadillo800eva.c:910: .name   = "soc-camera-pdrv",
arch/arm/mach-shmobile/board-marzen.c:299:  .name   = "soc-camera-pdrv",                \
arch/arm/mach-at91/board-sam9m10g45ek.c:241:    .name   = "soc-camera-pdrv",
arch/arm/mach-omap1/board-ams-delta.c:435:  .name   = "soc-camera-pdrv",
arch/arm/mach-pxa/ezx.c:788:    .name   = "soc-camera-pdrv",
arch/arm/mach-pxa/ezx.c:1062:   .name   = "soc-camera-pdrv",
arch/arm/mach-pxa/em-x270.c:1034:   .name   = "soc-camera-pdrv",
arch/arm/mach-pxa/palmz72.c:339:    .name   = "soc-camera-pdrv",
arch/arm/mach-pxa/pcm990-baseboard.c:507:       .name   = "soc-camera-pdrv",
arch/arm/mach-pxa/pcm990-baseboard.c:513:       .name   = "soc-camera-pdrv",
arch/arm/mach-pxa/mioa701.c:682:MIO_SIMPLE_DEV(mioa701_camera,    "soc-camera-pdrv",&iclink);
arch/arm/mach-imx/mach-imx27_visstrim_m10.c:572:    platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
arch/arm/mach-imx/mach-mx31_3ds.c:248:  .name   = "soc-camera-pdrv",
arch/arm/mach-imx/mach-mx31_3ds.c:412:  REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx31_3ds.c:444:  REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx35_3ds.c:305:  .name   = "soc-camera-pdrv",
arch/arm/mach-imx/mach-mx35_3ds.c:324:  REGULATOR_SUPPLY("cmos_vio", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx27_3ds.c:272:  REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx27_3ds.c:302:  REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx27_3ds.c:410:  .name   = "soc-camera-pdrv",
arch/arm/mach-imx/mx31moboard-smartbot.c:91:        .name   = "soc-camera-pdrv",
arch/arm/mach-imx/mx31moboard-marxbot.c:181:        .name   = "soc-camera-pdrv",
arch/arm/mach-imx/mach-pcm037.c:329:    .name   = "soc-camera-pdrv",
arch/arm/mach-imx/mach-pcm037.c:337:    .name   = "soc-camera-pdrv",

我选一个稍微简单的mach来进行后面的分析,at91平台(arch/arm/mach-at91/board-sam9m10g45ek.c),我把相关的代码截取出来:

   * soc-camera OV2640                                                            */                                                                             #if defined(CONFIG_SOC_CAMERA_OV2640) || \                                      defined(CONFIG_SOC_CAMERA_OV2640_MODULE)                                    static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)   {                                                                               /* ISI board for ek using default 8-bits connection */                      return SOCAM_DATAWIDTH_8;                                                   }                                                                               static int i2c_camera_power(struct device *dev, int on)                         {                                                                               /* enable or disable the camera */                                          pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");       at91_set_gpio_output(AT91_PIN_PD13, !on);                                   if (!on)                                                                    goto out;                                                               /* If enabled, give a reset impulse */                                      at91_set_gpio_output(AT91_PIN_PD12, 0);                                     msleep(20);                                                                 at91_set_gpio_output(AT91_PIN_PD12, 1);                                     msleep(100);                                                                out:                                                                            return 0;                                                                   }                                                                               static struct i2c_board_info i2c_camera = {                                     I2C_BOARD_INFO("ov2640", 0x30),                                             };                                                                              static struct soc_camera_link iclink_ov2640 = {                                 .bus_id         = 0,                                                        .board_info     = &i2c_camera,                                              .i2c_adapter_id     = 0,                                                    .power          = i2c_camera_power,                                         .query_bus_param    = isi_camera_query_bus_param,                           };                                                                              static struct platform_device isi_ov2640 = {                                    .name   = "soc-camera-pdrv",                                                .id = 0,                                                                    .dev    = {                                                                 .platform_data = &iclink_ov2640,                                        },                                                                          };                                                                              #endif   

最重要的结构就是soc_camera_link,它是所有camera这类设备都需要用到的结构体。bus_id用来描述它是连接到哪条soc camera host总线上,后面会再讲这个。board_info用来描述i2c设备的信息,比如它的型号名称,它的i2c地址,相信研究过i2c驱动的人都比较熟悉。i2c_adapter_id用来描述i2c设备挂载哪条i2c总线上。sensor的控制一般通过i2c来实现,所以这里才会有i2c设备的描述,因为需要对应的i2c驱动来驱动它啊。power一般指sensor的电源模块的开启和关闭,一般是单独通过一个gpio来控制的。query_bus_param这个成员先不看吧,用到的时候再看。

总之,通过上面的信息以及后面的平台设备注册后,就将soc-camera-pdrv平台设备添加到平台总线了。也就是说只要这段代码编译进入了内核并调用了这段代码,那么soc_camera_pdrv_probe就一定会执行了。下面继续分析前面列出来的soc_camera_pdrv_probe吧!

soc_camera_pdrv_probe的实现很短,为了方面说明,也贴出来吧:

static int soc_camera_pdrv_probe(struct platform_device *pdev)
{struct soc_camera_desc *sdesc = pdev->dev.platform_data;struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;struct soc_camera_device *icd;int ret;if (!sdesc)return -EINVAL;icd = devm_kzalloc(&pdev->dev, sizeof(*icd), GFP_KERNEL);if (!icd)return -ENOMEM;/** In the asynchronous case ssdd->num_regulators == 0 yet, so, the below* regulator allocation is a dummy. They are actually requested by the* subdevice driver, using soc_camera_power_init(). Also note, that in* that case regulators are attached to the I2C device and not to the* camera platform device.*/ret = devm_regulator_bulk_get(&pdev->dev, ssdd->sd_pdata.num_regulators,ssdd->sd_pdata.regulators);if (ret < 0)return ret;icd->iface = sdesc->host_desc.bus_id;icd->sdesc = sdesc;icd->pdev = &pdev->dev;platform_set_drvdata(pdev, icd);icd->user_width     = DEFAULT_WIDTH;icd->user_height    = DEFAULT_HEIGHT;return soc_camera_device_register(icd);
}

这里我们会开始接触第二个重要的数据结构soc_camera_device,它在内核里代表的就是一个camera sensor设备。有一点需要提前说明下,我们之前谈到数据结构soc_camera_link,对应到驱动使用的时候,将其拆分成两个结构体了,我想也是为了代码更清晰吧!对应的结构如下:

struct soc_camera_desc {struct soc_camera_subdev_desc subdev_desc;struct soc_camera_host_desc host_desc;
};

因此,soc_camera_pdrv_probe里面的icd->iface = sdesc->host_desc.bus_id其实就是上面我说过的bus_id,用来描述它是连接到哪条soc camera host线上。soc_camera_pdrv_probe主要是创建对象 soc_camera_device,它代表着一个camera sensor设备。当然可以有多个这样的设备同时存在,且都由该驱动负责创建。并将platform设备传过来的各种数据放到soc_camera_device里面,最终调用soc_camera_device_register将该camera sensor注册。

soc_camera_device_register的代码就不贴了,它其实主要就做了一件事情,将代表着camera sensor的对象soc_camera_device放到了全局链表devices中,其他的就是做参数检查等等。

好了,到这里,我们的系统里的devices全局链表里已经有一个用于代表camera sensor的设备了,它就在这里静静的等待着负责它的驱动的到来,我们应该可以想象到,负责它的就是camera host咯。顺便说一下,如果我们仅仅需要写一个sensor驱动,那么到这里,就算完成了一小半了,剩下的就是完成我们camera sensor里对应的i2c设备的驱动(参考drivers/media/i2c/soc_camera/,里面有一些已经实现了的i2c sensor驱动),至于camera host驱动,一般对应的soc的sdk都会实现啦。

未完,待续!
2015年6月

转载于:https://www.cnblogs.com/rongpmcu/p/7662738.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/391118.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工程项目管理需要注意哪些问题

在社会科学技术发展和市场经济繁荣昌盛的今天&#xff0c;为更好的满足社会人性化的需求&#xff0c;建设施工企业在建筑施工、布局以及内部运行都给予了落实。而工程项目是建筑施工企业面向建筑市场的窗口&#xff0c;是企业建筑活动的前沿阵地&#xff0c;管理需更严谨。 虽说…

leetcode 872. 叶子相似的树(dfs)

请考虑一棵二叉树上所有的叶子&#xff0c;这些叶子的值按从左到右的顺序排列形成一个 叶值序列 。 举个例子&#xff0c;如上图所示&#xff0c;给定一棵叶值序列为 (6, 7, 4, 9, 8) 的树。 如果有两棵二叉树的叶值序列是相同&#xff0c;那么我们就认为它们是 叶相似 的。 …

探索感染了COVID-19的动物的数据

数据 (The data) With the number of cases steadily rising day by day, COVID-19 has been pretty much in the headlines of every newspaper known to man. Despite the massive amount of attention, a topic that has remained mostly untouched (some exceptions being …

Facebook哭晕在厕所,调查显示用VR体验社交的用户仅为19%

美国娱乐软件协会ESA调查显示&#xff0c;有74%的用户使用VR玩游戏&#xff0c;而仅有19%的用户会用VR进行社交。 当我们说到VR社交&#xff0c;必然离不开Facebook。在刚刚结束的F8大会上&#xff0c;小扎展示了VR社交平台Facebook Spaces测试版&#xff0c;巧的是此前也有好…

网页自动刷新

eg1&#xff1a;<meta http-equiv”refresh” content”4” /> 间隔4秒网页自动刷新 eg2&#xff1a;<meta http-equiv”refresh” content”8;http://www.baidu.com” /> 等待8秒自动跳转到百度页面转载于:https://www.cnblogs.com/zwtqf/p/7667774.html

解决Javascript疲劳的方法-以及其他所有疲劳

Learn your fundamentals, and never worry again. 了解您的基础知识&#xff0c;再也不用担心。 新工具让我担心 (New Tools Worry Me) When JavaScripts shiny tool of the day comes out, I sometimes overreact. 当JavaScript一天一度的闪亮工具问世时&#xff0c;我有时R…

Java 8 的List<V> 转成 Map<K, V>

问题&#xff1a; Java 8 的List 转成 Map<K, V> 我想要使用Java 8的streams和lambdas转换一个 List 对象为 Map 下面是我在Java 7里面的写法 private Map<String, Choice> nameMap(List<Choice> choices) {final Map<String, Choice> hashMap new…

已知两点坐标拾取怎么操作_已知的操作员学习-第4部分

已知两点坐标拾取怎么操作有关深层学习的FAU讲义 (FAU LECTURE NOTES ON DEEP LEARNING) These are the lecture notes for FAU’s YouTube Lecture “Deep Learning”. This is a full transcript of the lecture video & matching slides. We hope, you enjoy this as mu…

北京供销大数据集团发布SinoBBD Cloud 一体化推动产业云发展

9月5日&#xff0c;第五届全球云计算大会在上海世博展览馆盛大开幕&#xff0c;国内外顶尖企业汇聚一堂&#xff0c;新一代云计算技术产品纷纷亮相。作为国内领先的互联网基础服务提供商&#xff0c;北京供销大数据集团(以下简称“SinoBBD”)受邀参加此次大会&#xff0c;并正式…

windows下有趣的小玩意

1.显示文件和隐藏文件。在当前目录下shift右键 选择cmd命令 运行显示文件: attrib -s -h 文件名 隐藏文件: attrib -s h 文件名 2.查看电脑支持的最大内存 在cmd下运行wmic memphysical get maxcapacity所得结果单位mb 所得/1024/1024 得到单位G 3.windowsR 输入…

rxjs angular_Angular RxJS深度

rxjs angularIn this tutorial, well learn to use the RxJS 6 library with Angular 6 or Angular 7. Well learn about:在本教程中&#xff0c;我们将学习将RxJS 6库与Angular 6或Angular 7结合使用。我们将了解&#xff1a; How to import the Observable class and the ot…

HashMap, LinkedHashMap 和 TreeMap的区别

HashMap, LinkedHashMap 和 TreeMap的区别 Java里面的HashMap, LinkedHashMap 和 TreeMap 有什么区别?我看不出以下3个key和value有什么不同的。Hashtables里面又是怎么样的呢&#xff1f; Map m1 new HashMap(); m1.put("map", "HashMap"); m1.put(&q…

“陪护机器人”研报:距离真正“陪护”还差那么一点

一款有“缺陷”的机器人&#xff0c;怎能做到真正的“陪护”&#xff1f; 近日&#xff0c;鼎盛智能发布了一款名为Ibotn的&#xff08;爱蹦&#xff09;幼儿陪伴机器人&#xff0c;核心看点就是通过人脸识别、场景识别等计算机视觉技术来实现机器人对儿童的陪护。不过&#xf…

neo-6m uno_Uno-统治所有人的平台

neo-6m unoFirst, we should start off with what Uno is and why you should care. 首先&#xff0c;我们应该从Uno是什么以及为什么要关心开始。 As stated on their website, Uno is "The only platform for building native mobile, desktop and WebAssembly apps wi…

【转】消息队列应用场景

一、消息队列概述 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合&#xff0c;异步消息&#xff0c;流量削锋等问题。实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。 目前在生产环境&#xff0c;…

JDK和JRE区别是什么

问题&#xff1a;JDK和JRE区别是什么 他们的角色分别是什么&#xff1f;我们应该什么时候使用他们&#xff1f; 回答一 JRE是Java Runtime Environment&#xff08;Java运行时环境&#xff09;。它是一个包&#xff0c;集合了运行一个编译好的Java程序的一切必须的东西&…

树莓派新手入门教程

http://www.ruanyifeng.com/blog/2017/06/raspberry-pi-tutorial.html

lime 模型_使用LIME的糖尿病预测模型解释— OneZeroBlog

lime 模型Article outline文章大纲 Introduction 介绍 Data Background 资料背景 Aim of the article 本文的目的 Exploratory analysis 探索性分析 Training a Random Forest Model 训练随机森林模型 Global Importance 全球重要性 Local Importance 当地重要性 介绍 (Introd…

react 生命挂钩_如何在GraphQL API中使用React挂钩来管理状态

react 生命挂钩In this blog post, we are going to learn -在这篇博客中&#xff0c;我们将学习- What React hooks are 什么是React钩子 How to use hooks for state management 如何使用挂钩进行状态管理 Before we start working with hooks, let us take a brief moment …

Linux第三周作业

1.三个法宝 ①存储程序计算机工作模型&#xff0c;计算机系统最最基础性的逻辑结构&#xff1b; ②函数调用堆栈&#xff0c;堆栈完成了计算机的基本功能&#xff1a;函数的参数传递机制和局部变量存取 &#xff1b; ③中断&#xff0c;多道程序操作系统的基点&#xff0c;没有…