前言

  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驱动

分析所采用的内核版本:

  1. VERSION = 3
  2. PATCHLEVEL = 15
  3. SUBLEVEL = 0
  4. EXTRAVERSION =
  5. NAME = Shuffling Zombie Juror

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

这里先插一张图,来自:http://blog.csdn.net/kickxxx/article/details/8484498(该图片及图片后的文字是在我写完这篇博文后发现的,我认为对理解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控制器等。

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

通用camera驱动

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

  1. static struct platform_driver __refdata soc_camera_pdrv = {
  2. .probe = soc_camera_pdrv_probe,
  3. .remove = soc_camera_pdrv_remove,
  4. .driver = {
  5. .name = "soc-camera-pdrv",
  6. .owner = THIS_MODULE,
  7. },
  8. };
  9. 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*/)搜索一下,就可以得到以下结果:

  1. arch/arm/mach-shmobile/board-lager.c:394: platform_device_register_data(&platform_bus, "soc-camera-pdrv", 1,
  2. arch/arm/mach-shmobile/board-bockw.c:606: platform_device_register_data(&platform_bus, "soc-camera-pdrv", 0,
  3. arch/arm/mach-shmobile/board-bockw.c:609: platform_device_register_data(&platform_bus, "soc-camera-pdrv", 1,
  4. arch/arm/mach-shmobile/board-mackerel.c:1224: .name = "soc-camera-pdrv",
  5. arch/arm/mach-shmobile/board-armadillo800eva.c:910: .name = "soc-camera-pdrv",
  6. arch/arm/mach-shmobile/board-marzen.c:299: .name = "soc-camera-pdrv", \
  7. arch/arm/mach-at91/board-sam9m10g45ek.c:241: .name = "soc-camera-pdrv",
  8. arch/arm/mach-omap1/board-ams-delta.c:435: .name = "soc-camera-pdrv",
  9. arch/arm/mach-pxa/ezx.c:788: .name = "soc-camera-pdrv",
  10. arch/arm/mach-pxa/ezx.c:1062: .name = "soc-camera-pdrv",
  11. arch/arm/mach-pxa/em-x270.c:1034: .name = "soc-camera-pdrv",
  12. arch/arm/mach-pxa/palmz72.c:339: .name = "soc-camera-pdrv",
  13. arch/arm/mach-pxa/pcm990-baseboard.c:507: .name = "soc-camera-pdrv",
  14. arch/arm/mach-pxa/pcm990-baseboard.c:513: .name = "soc-camera-pdrv",
  15. arch/arm/mach-pxa/mioa701.c:682:MIO_SIMPLE_DEV(mioa701_camera, "soc-camera-pdrv",&iclink);
  16. arch/arm/mach-imx/mach-imx27_visstrim_m10.c:572: platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
  17. arch/arm/mach-imx/mach-mx31_3ds.c:248: .name = "soc-camera-pdrv",
  18. arch/arm/mach-imx/mach-mx31_3ds.c:412: REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
  19. arch/arm/mach-imx/mach-mx31_3ds.c:444: REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"),
  20. arch/arm/mach-imx/mach-mx35_3ds.c:305: .name = "soc-camera-pdrv",
  21. arch/arm/mach-imx/mach-mx35_3ds.c:324: REGULATOR_SUPPLY("cmos_vio", "soc-camera-pdrv.0"),
  22. arch/arm/mach-imx/mach-mx27_3ds.c:272: REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
  23. arch/arm/mach-imx/mach-mx27_3ds.c:302: REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"),
  24. arch/arm/mach-imx/mach-mx27_3ds.c:410: .name = "soc-camera-pdrv",
  25. arch/arm/mach-imx/mx31moboard-smartbot.c:91: .name = "soc-camera-pdrv",
  26. arch/arm/mach-imx/mx31moboard-marxbot.c:181: .name = "soc-camera-pdrv",
  27. arch/arm/mach-imx/mach-pcm037.c:329: .name = "soc-camera-pdrv",
  28. arch/arm/mach-imx/mach-pcm037.c:337: .name = "soc-camera-pdrv",

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

  1. * soc-camera OV2640
  2. */
  3. #if defined(CONFIG_SOC_CAMERA_OV2640) || \
  4. defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
  5. static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)
  6. {
  7. /* ISI board for ek using default 8-bits connection */
  8. return SOCAM_DATAWIDTH_8;
  9. }
  10. static int i2c_camera_power(struct device *dev, int on)
  11. {
  12. /* enable or disable the camera */
  13. pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
  14. at91_set_gpio_output(AT91_PIN_PD13, !on);
  15. if (!on)
  16. goto out;
  17. /* If enabled, give a reset impulse */
  18. at91_set_gpio_output(AT91_PIN_PD12, 0);
  19. msleep(20);
  20. at91_set_gpio_output(AT91_PIN_PD12, 1);
  21. msleep(100);
  22. out:
  23. return 0;
  24. }
  25. static struct i2c_board_info i2c_camera = {
  26. I2C_BOARD_INFO("ov2640", 0x30),
  27. };
  28. static struct soc_camera_link iclink_ov2640 = {
  29. .bus_id = 0,
  30. .board_info = &i2c_camera,
  31. .i2c_adapter_id = 0,
  32. .power = i2c_camera_power,
  33. .query_bus_param = isi_camera_query_bus_param,
  34. };
  35. static struct platform_device isi_ov2640 = {
  36. .name = "soc-camera-pdrv",
  37. .id = 0,
  38. .dev = {
  39. .platform_data = &iclink_ov2640,
  40. },
  41. };
  42. #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的实现很短,为了方面说明,也贴出来吧:

  1. static int soc_camera_pdrv_probe(struct platform_device *pdev)
  2. {
  3. struct soc_camera_desc *sdesc = pdev->dev.platform_data;
  4. struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
  5. struct soc_camera_device *icd;
  6. int ret;
  7. if (!sdesc)
  8. return -EINVAL;
  9. icd = devm_kzalloc(&pdev->dev, sizeof(*icd), GFP_KERNEL);
  10. if (!icd)
  11. return -ENOMEM;
  12. /*
  13. * In the asynchronous case ssdd->num_regulators == 0 yet, so, the below
  14. * regulator allocation is a dummy. They are actually requested by the
  15. * subdevice driver, using soc_camera_power_init(). Also note, that in
  16. * that case regulators are attached to the I2C device and not to the
  17. * camera platform device.
  18. */
  19. ret = devm_regulator_bulk_get(&pdev->dev, ssdd->sd_pdata.num_regulators,
  20. ssdd->sd_pdata.regulators);
  21. if (ret < 0)
  22. return ret;
  23. icd->iface = sdesc->host_desc.bus_id;
  24. icd->sdesc = sdesc;
  25. icd->pdev = &pdev->dev;
  26. platform_set_drvdata(pdev, icd);
  27. icd->user_width = DEFAULT_WIDTH;
  28. icd->user_height = DEFAULT_HEIGHT;
  29. return soc_camera_device_register(icd);
  30. }

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

  1. struct soc_camera_desc {
  2. struct soc_camera_subdev_desc subdev_desc;
  3. struct soc_camera_host_desc host_desc;
  4. };

因此,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月

camera驱动框架分析(上)的更多相关文章

  1. camera驱动框架分析(上)【转】

    转自:https://www.cnblogs.com/rongpmcu/p/7662738.html 前言 camera驱动框架涉及到的知识点比较多,特别是camera本身的接口就有很多,有些是直接连 ...

  2. camera驱动框架分析(中)

    camera host的驱动 下面开始分析camera host吧,如果仅仅是想知道camera sensor驱动怎么写,而不想知道内部具体怎么个调用流程,怎么个架构设计,那可以跳过该部分,直接去看i ...

  3. camera驱动框架分析(下)

    sensor的驱动 v4l2_i2c_new_subdev_board先用client = i2c_new_device(adapter, info);创建info对应的i2c_client对象(代表 ...

  4. Linux USB驱动框架分析(2)【转】

    转自:http://blog.chinaunix.net/uid-23046336-id-3243543.html   看了http://blog.chinaunix.net/uid-11848011 ...

  5. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

  6. linux驱动基础系列--linux spi驱动框架分析

    前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...

  7. linux驱动基础系列--linux spi驱动框架分析(续)

    前言 这篇文章是对linux驱动基础系列--linux spi驱动框架分析的补充,主要是添加了最新的linux内核里设备树相关内容. spi设备树相关信息 如之前的文章里所述,控制器的device和s ...

  8. Linux下USB驱动框架分析【转】

    转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...

  9. Linux USB驱动框架分析【转】

    转自:http://blog.csdn.net/jeffade/article/details/7701431 Linux USB驱动框架分析(一) 初次接触和OS相关的设备驱动编写,感觉还挺有意思的 ...

随机推荐

  1. centos 64位 下hadoop-2.7.2 下编译

    centos 64位 下hadoop-2.7.2 下编译 由于机器安装的是centos 6.7 64位 系统  从hadoop中下载是32位  hadoop 依赖的的库是libhadoop.so 是3 ...

  2. 第一个spring,总结!

    陈志棚:界面跳转与框架 李天麟:游戏界面ui 徐侃:算法代码的设计 经过五天的时间,开会时候分配的任务,已经全部完成,在这期间中,我们遇到了一些问题.但是,经过android老师的指导后,app成功的 ...

  3. Kafka与Logstash的数据采集对接

    Logstash工作原理 由于Kafka采用解耦的设计思想,并非原始的发布订阅,生产者负责产生消息,直接推送给消费者.而是在中间加入持久化层--broker,生产者把数据存放在broker中,消费者从 ...

  4. Kivy 中文教程 实例入门 简易画板 (Simple Paint App):0. 项目简介 & 成果展示

    本教程咪博士将带领大家学习创建自己的窗口部件 (widget).最终,我们完成的作品是一个简易的画板程序. 当用 kivy 创建应用时,我们需要仔细思考以下 3 个问题: 我们创建的应用需要处理什么数 ...

  5. hdu 6301 Distinct Values (2018 Multi-University Training Contest 1 1004)

    Distinct Values Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  6. 【刷题】BZOJ 4289 PA2012 Tax

    Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边 ...

  7. 【题解】 [SCOI2011]糖果 (差分约束)

    懒得复制,戳我戳我 Solution: 首先考虑\(X=1\)的情况,我们其实只用用一下并查集把相等的点合为一个点 然后后面的四个式子我们就可以用差分约束了,就拿\(X=2\)的情况来说吧,我们用\( ...

  8. What is SCons?

    SCons: A software construction tool What is SCons? SCons is an Open Source software construction too ...

  9. 【poj3415】 Common Substrings

    http://poj.org/problem?id=3415 (题目链接) 题意 给定两个字符串 A 和 B,求长度不小于 k 的公共子串的个数(可以相同). Solution 后缀数组论文题... ...

  10. 新年的展望,2018 hello world~

    虽然离$2017$到$2018$的跨年已经过去很久了,但还是想写点东西试图拯救一下最近有些颓势的自己~ $2017$对我来说是意义重大的一年,这一年里,我有欢笑也有泪水,有收获也有挫折,有坚强也有脆弱 ...