camera驱动框架分析(上)
前言
camera驅(qū)動(dòng)框架涉及到的知識(shí)點(diǎn)比較多,特別是camera本身的接口就有很多,有些是直接連接到soc的camif口上的,有些是通過usb接口導(dǎo)出的,如usb camera。我這里主要討論前者,也就是與soc直連的。我認(rèn)為凡是涉及到usb的,都不是一兩句話可以說明白的!如有錯(cuò)誤,歡迎指正,謝謝!!!
環(huán)境說明
涉及到的基礎(chǔ)知識(shí)點(diǎn):
字符設(shè)備驅(qū)動(dòng)
設(shè)備模型
平臺(tái)設(shè)備驅(qū)動(dòng)
v4l2框架
i2c驅(qū)動(dòng)框架
涉及到的術(shù)語:
camera : 指的是整個(gè)camera,包括它本身的硬件連接方式及支持i2c控制的i2c設(shè)備
sensor : 指的是支持i2c控制的i2c設(shè)備,它屬于camera的一部分,在內(nèi)核實(shí)現(xiàn)里也能體現(xiàn)出來
camera host: 指的是與camera相連接的,一般內(nèi)嵌在soc里面的控制器
涉及到的文件夾:
drivers/media/platform/soc_camera/ 主要存放camera host驅(qū)動(dòng),通用的camera驅(qū)動(dòng)也存放在此
drivers/media/i2c/soc_camera/ 主要存放sensor驅(qū)動(dòng)
分析所采用的內(nèi)核版本:
VERSION = 3 PATCHLEVEL = 15 SUBLEVEL = 0 EXTRAVERSION = NAME = Shuffling Zombie Jurorcamera的驅(qū)動(dòng)包括通用camera的驅(qū)動(dòng)、camera host的驅(qū)動(dòng)以及sensor的驅(qū)動(dòng),下面一個(gè)個(gè)來分析
這里先插一張圖,來自:http://blog.csdn.net/kickxxx/article/details/8484498(該圖片及圖片后的文字是在我寫完這篇博文后發(fā)現(xiàn)的,我認(rèn)為對(duì)理解camera驅(qū)動(dòng)會(huì)有幫助,所以就摘抄了^_^)
Soc camera sub-system對(duì)應(yīng)著drivers/media/video/下的soc_camera.c soc_camera_platform.c
Soc camera host 是host端實(shí)現(xiàn),是由平臺(tái)廠商實(shí)現(xiàn)的,向上實(shí)現(xiàn)soc_camera_host_ops接口,向下操作Camera host硬件以及通過平臺(tái)特定的接口操作Soc camera device
Soc camera device 是平臺(tái)的camera device(同時(shí)也是subdev),由驅(qū)動(dòng)開發(fā)者來實(shí)現(xiàn)v4l2_subdev_call調(diào)用的subdev 接口,同時(shí)還要為soc camera host實(shí)現(xiàn)平臺(tái)特定的操作接口;向下操作camera sensor或者video AD芯片。
Camera host hardware是平臺(tái)硬件相關(guān)的,不同的平臺(tái)有不同的host硬件,比如imx51的ipu,三星s5pv210的fimc控制器等。
soc_camera_host,soc_camera_device,v4l2_device,v4l2_subdev關(guān)系如下:理論上系統(tǒng)內(nèi)可以有多個(gè)soc_camera_host,物理上soc_camera_host就是系統(tǒng)的camera處理模塊驅(qū)動(dòng)一個(gè)soc_camera_host可以對(duì)應(yīng)多個(gè)soc_camera_device,物理上soc_camera_device是一個(gè)camera接口,每個(gè)soc_camera_host對(duì)應(yīng)一個(gè)v4l2_dev每個(gè)soc_camera_device,系統(tǒng)會(huì)為他們創(chuàng)建設(shè)備節(jié)點(diǎn)/dev/videoX。每個(gè)soc_camera_device有多個(gè)v4l2_subdev,物理上v4l2_subdev可以是sensor,video AD芯片v4l2_subdev可以通過i2c掛接到v4l2_device,也可以通過soc_camera_link提供的add_device來增加,這依賴于sensor和video AD芯片掛接到MCU camera接口的方式。通用camera驅(qū)動(dòng)
對(duì)應(yīng)文件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);從這里可以看出,我們要使該驅(qū)動(dòng)probe得到調(diào)用,先得注冊(cè)一個(gè)平臺(tái)設(shè)備,且名字為soc-camera-pdrv。通用camera的驅(qū)動(dòng)就是定義了一套數(shù)據(jù)結(jié)構(gòu),然后告訴大家,你如果想用通用的camera驅(qū)動(dòng),那就照著數(shù)據(jù)結(jié)構(gòu)填好,然后用soc-camera-pdrv的名字通過平臺(tái)總線注冊(cè)上來就可以了。平臺(tái)設(shè)備的注冊(cè)可以通過兩種方式來實(shí)現(xiàn),一種是通過設(shè)備樹,它是最新的一種機(jī)制,通過dts文件來描述硬件信息,使得內(nèi)核里面不會(huì)再硬編碼一堆和用于描述硬件信息的代碼。對(duì)應(yīng)到這里的硬件信息就是camera sensor硬件信息以及camera硬件布線信息。另一種就是以前采用的方式,直接用代碼在板子相關(guān)的啟動(dòng)文件里來描述那些信息并通過平臺(tái)設(shè)備的注冊(cè)。soc_camera_pdrv里面沒有設(shè)備樹的相關(guān)支持,說明這類設(shè)備的添加還是采用后面那種方式,通過下面的命令輸出也可以證實(shí)這一點(diǎn):
我用命令(grep -rns soc-camera-pdrv arch/arm*/)搜索一下,就可以得到以下結(jié)果:
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",我選一個(gè)稍微簡(jiǎn)單的mach來進(jìn)行后面的分析,at91平臺(tái)(arch/arm/mach-at91/board-sam9m10g45ek.c),我把相關(guān)的代碼截取出來:
* 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最重要的結(jié)構(gòu)就是soc_camera_link,它是所有camera這類設(shè)備都需要用到的結(jié)構(gòu)體。bus_id用來描述它是連接到哪條soc camera host總線上,后面會(huì)再講這個(gè)。board_info用來描述i2c設(shè)備的信息,比如它的型號(hào)名稱,它的i2c地址,相信研究過i2c驅(qū)動(dòng)的人都比較熟悉。i2c_adapter_id用來描述i2c設(shè)備掛載哪條i2c總線上。sensor的控制一般通過i2c來實(shí)現(xiàn),所以這里才會(huì)有i2c設(shè)備的描述,因?yàn)樾枰獙?duì)應(yīng)的i2c驅(qū)動(dòng)來驅(qū)動(dòng)它啊。power一般指sensor的電源模塊的開啟和關(guān)閉,一般是單獨(dú)通過一個(gè)gpio來控制的。query_bus_param這個(gè)成員先不看吧,用到的時(shí)候再看。
總之,通過上面的信息以及后面的平臺(tái)設(shè)備注冊(cè)后,就將soc-camera-pdrv平臺(tái)設(shè)備添加到平臺(tái)總線了。也就是說只要這段代碼編譯進(jìn)入了內(nèi)核并調(diào)用了這段代碼,那么soc_camera_pdrv_probe就一定會(huì)執(zhí)行了。下面繼續(xù)分析前面列出來的soc_camera_pdrv_probe吧!
soc_camera_pdrv_probe的實(shí)現(xiàn)很短,為了方面說明,也貼出來吧:
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); }這里我們會(huì)開始接觸第二個(gè)重要的數(shù)據(jù)結(jié)構(gòu)soc_camera_device,它在內(nèi)核里代表的就是一個(gè)camera sensor設(shè)備。有一點(diǎn)需要提前說明下,我們之前談到數(shù)據(jù)結(jié)構(gòu)soc_camera_link,對(duì)應(yīng)到驅(qū)動(dòng)使用的時(shí)候,將其拆分成兩個(gè)結(jié)構(gòu)體了,我想也是為了代碼更清晰吧!對(duì)應(yīng)的結(jié)構(gòu)如下:
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其實(shí)就是上面我說過的bus_id,用來描述它是連接到哪條soc camera host線上。soc_camera_pdrv_probe主要是創(chuàng)建對(duì)象 soc_camera_device,它代表著一個(gè)camera sensor設(shè)備。當(dāng)然可以有多個(gè)這樣的設(shè)備同時(shí)存在,且都由該驅(qū)動(dòng)負(fù)責(zé)創(chuàng)建。并將platform設(shè)備傳過來的各種數(shù)據(jù)放到soc_camera_device里面,最終調(diào)用soc_camera_device_register將該camera sensor注冊(cè)。
soc_camera_device_register的代碼就不貼了,它其實(shí)主要就做了一件事情,將代表著camera sensor的對(duì)象soc_camera_device放到了全局鏈表devices中,其他的就是做參數(shù)檢查等等。
好了,到這里,我們的系統(tǒng)里的devices全局鏈表里已經(jīng)有一個(gè)用于代表camera sensor的設(shè)備了,它就在這里靜靜的等待著負(fù)責(zé)它的驅(qū)動(dòng)的到來,我們應(yīng)該可以想象到,負(fù)責(zé)它的就是camera host咯。順便說一下,如果我們僅僅需要寫一個(gè)sensor驅(qū)動(dòng),那么到這里,就算完成了一小半了,剩下的就是完成我們camera sensor里對(duì)應(yīng)的i2c設(shè)備的驅(qū)動(dòng)(參考drivers/media/i2c/soc_camera/,里面有一些已經(jīng)實(shí)現(xiàn)了的i2c sensor驅(qū)動(dòng)),至于camera host驅(qū)動(dòng),一般對(duì)應(yīng)的soc的sdk都會(huì)實(shí)現(xiàn)啦。
未完,待續(xù)!
2015年6月
轉(zhuǎn)載于:https://www.cnblogs.com/rongpmcu/p/7662738.html
總結(jié)
以上是生活随笔為你收集整理的camera驱动框架分析(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bzoj 4552: [Tjoi2016
- 下一篇: 网页自动刷新