CMOS摄像头驱动分析-i2c驱动

news2025/1/12 23:33:50

CMOS摄像头驱动分析-i2c驱动


文章目录

  • CMOS摄像头驱动分析-i2c驱动
  • 设备树内容
  • module_i2c_driver宏分析
  • ov2640_i2c_driver
    • ov2640_probe


在这里插入图片描述

设备树内容

ov2640: camera@0x30 {
       compatible = "ovti,ov2640";
       reg = <0x30>;
       status = "okay";

       pinctrl-names = "default";

       pinctrl-0 = <&pinctrl_csi1
                   &csi_pwn_rst>;
       resetb = <&gpio1 2 GPIO_ACTIVE_LOW>;
       pwdn = <&gpio1 4 GPIO_ACTIVE_HIGH>;
       clocks = <&clks IMX6UL_CLK_CSI>;
       clock-names = "xvclk";

       port {
              camera_ep: endpoint {
                     remote-endpoint = <&csi_ep>;
                     bus-width = <8>;
              };
       };
    };

module_i2c_driver宏分析

// 注册i2c驱动程序

module_i2c_driver(ov2640_i2c_driver);

module_i2c_driver(ov2640_i2c_driver),可以分析出以下信息:
module_i2c_driver是一个宏,它可能是在编程中定义的一个宏,用于简化I2C驱动模块的注册。
ov2640_i2c_driver是一个I2C驱动的结构体或变量名。它可能定义了有关OV2640摄像头的I2C通信设置和功能的信息。
宏module_i2c_driver可能在内部执行一些操作,以便将ov2640_i2c_driver的I2C驱动注册到系统中。这通常涉及使用相关的函数和数据结构将驱动程序添加到I2C驱动程序列表中,并与I2C总线进行关联。
总的来说,module_i2c_driver(ov2640_i2c_driver)宏的作用是将ov2640_i2c_driver所定义的I2C驱动注册到系统中,以便系统能够正确识别和使用与OV2640摄像头相关的I2C通信功能。
module_i2c_driver原型

#define module_i2c_driver(__i2c_driver) \
    module_driver(__i2c_driver, i2c_add_driver, \
            i2c_del_driver)

根据您提供的代码宏定义,module_i2c_driver宏用于简化I2C驱动模块的注册和注销过程,并使用了module_driver宏。
该宏定义的详细分析如下:
module_i2c_driver是宏的名称。
__i2c_driver是一个传入的参数,表示要注册的I2C驱动程序。宏的具体实现包括以下步骤:
使用module_driver宏,传入__i2c_driver作为驱动参数,以及i2c_add_driver和i2c_del_driver作为注册和注销函数。
i2c_add_driver是用于将I2C驱动程序添加到系统中的函数。
i2c_del_driver是用于从系统中注销I2C驱动程序的函数。
通过使用module_i2c_driver宏,可以将注册和注销I2C驱动程序的过程简化为调用module_driver宏,并传入适当的参数。这样可以减少手动编写注册和注销函数的工作量,并提高代码的可读性和可维护性。
总结而言,module_i2c_driver宏的作用是将指定的I2C驱动程序注册到系统中,并在加载模块时调用注册函数,以及在卸载模块时调用注销函数。
module_i2c_driver的原型为module_driver,定义如下

#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
    return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
    __unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

module_driver宏用于简化驱动模块的注册和注销过程,并提供了模块的初始化和退出函数。
该宏定义的详细分析如下:
module_driver是宏的名称。
__driver是一个传入的参数,表示要注册的驱动程序。
__register是一个传入的参数,表示用于注册驱动的函数。
__unregister是一个传入的参数,表示用于注销驱动的函数。
…表示可变参数,用于传递额外的参数给注册和注销函数。
宏的具体实现包括以下步骤:
定义一个静态的初始化函数__driver##_init,该函数在模块初始化时被调用。
在__driver##_init函数中,调用__register函数来注册驱动程序,传递驱动程序结构体和额外的参数。
使用module_init宏将__driver##_init函数指定为模块的初始化函数,确保在加载模块时会调用该函数进行初始化。
定义一个静态的退出函数__driver##_exit,该函数在模块注销时被调用。
在__driver##_exit函数中,调用__unregister函数来注销驱动程序,传递驱动程序结构体和额外的参数。
使用module_exit宏将__driver##_exit函数指定为模块的退出函数,确保在卸载模块时会调用该函数进行注销。
通过使用module_driver宏,可以简化驱动模块的注册和注销过程,减少了手动编写初始化和退出函数的工作量,提高了代码的可读性和可维护性。

ov2640_i2c_driver

ov2640的i2c驱动程序

// 定义ov2640的i2c设备ID
static const struct i2c_device_id ov2640_id[] = {
    { "ov2640", 0 }, // 设备名为ov2640,ID为0
    { } // 结束符
};

MODULE_DEVICE_TABLE(i2c, ov2640_id); // 将ov2640_id注册到i2c设备表中,以便内核能够自动加载驱动程序


// 定义设备树匹配表
static const struct of_device_id ov2640_of_match[] = {
    {.compatible = "ovti,ov2640", }, // 匹配ovti,ov2640
    {}, // 结束符
};

MODULE_DEVICE_TABLE(of, ov2640_of_match); // 将ov2640_of_match注册到设备树匹配表中,以便内核能够自动加载驱动程序


// 定义ov2640的i2c驱动程序
static struct i2c_driver ov2640_i2c_driver = {
    .driver = {
        .name = "ov2640", // 驱动程序名为ov2640
        .of_match_table = of_match_ptr(ov2640_of_match), // 设置设备树匹配表
    },
    .probe    = ov2640_probe, // 设置探测函数
    .remove   = ov2640_remove, // 设置反初始化函数
    .id_table = ov2640_id, // 设置i2c设备ID
};

ov2640_probe

这个函数是用于初始化并探测OV2640摄像头的驱动程序。下面是对该函数的概括总结:
检查所使用的I2C适配器是否支持SMBUS功能,如果不支持则返回错误码。
分配内存并初始化ov2640_priv结构体。
获取摄像头的时钟,如果获取失败则返回延迟探测错误码。
检查是否存在soc_camera_subdev_desc结构体或设备树节点,如果都不存在则返回错误码。
如果不存在soc_camera_subdev_desc结构体,从设备树中获取OV2640的GPIO引脚并进行初始化。
初始化v4l2子设备,使用ov2640_subdev_ops作为操作函数。
初始化v4l2控制器,创建VFLIP和HFLIP控制器。
将控制器绑定到子设备的控制器处理器中。
如果控制器存在错误,则返回错误码。
进行视频探测,初始化摄像头的视频功能。
如果视频探测失败,则释放控制器并释放时钟,并返回错误码。
注册v4l2异步子设备。
如果注册失败,则释放探测的视频,并返回错误码。
打印OV2640已成功探测的消息。
返回0表示探测成功。
如果探测失败,将会在相应的错误标签处释放控制器和时钟,并返回相应的错误码。

static int ov2640_probe(struct i2c_client *client,
            const struct i2c_device_id *did)
{
    struct ov2640_priv    *priv;
    struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); // 获取soc_camera_subdev_desc
    struct i2c_adapter    *adapter = to_i2c_adapter(client->dev.parent); // 获取i2c_adapter
    int            ret;

    if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { // 如果i2c_adapter不支持SMBUS
        dev_err(&adapter->dev,
            "OV2640: I2C-Adapter doesn't support SMBUS\n"); // 打印错误信息
        return -EIO; // 返回-EIO
    }

    priv = devm_kzalloc(&client->dev, sizeof(struct ov2640_priv), GFP_KERNEL); // 分配内存
    if (!priv) { // 如果分配失败
        dev_err(&adapter->dev,
            "Failed to allocate memory for private data!\n"); // 打印错误信息
        return -ENOMEM; // 返回-ENOMEM
    }

    priv->clk = v4l2_clk_get(&client->dev, "xvclk"); // 获取时钟
    if (IS_ERR(priv->clk)) // 如果获取失败
        return -EPROBE_DEFER; // 返回-EPROBE_DEFER

    if (!ssdd && !client->dev.of_node) { // 如果soc_camera_subdev_desc不存在且设备树节点不存在
        dev_err(&client->dev, "Missing platform_data for driver\n"); // 打印错误信息
        ret = -EINVAL; // 返回-EINVAL
        goto err_clk; // 跳转到err_clk
    }

    //if (!ssdd) {
        ret = ov2640_probe_dt(client, priv); // 从设备树中获取ov2640的GPIO引脚并进行初始化
        if (ret) // 如果初始化失败
            goto err_clk; // 跳转到err_clk
    //}


    // 初始化v4l2子设备
    v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);

    // 初始化v4l2控制器
    v4l2_ctrl_handler_init(&priv->hdl, 2);

    // 添加vflip控制器
    v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
            V4L2_CID_VFLIP, 0, 1, 1, 0);

    // 添加hflip控制器
    v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
            V4L2_CID_HFLIP, 0, 1, 1, 0);

    // 设置子设备的控制器
    priv->subdev.ctrl_handler = &priv->hdl;

    // 如果控制器有错误,则返回错误
    if (priv->hdl.error) {
        ret = priv->hdl.error;
        goto err_clk;
    }

    // 进行视频探测
    ret = ov2640_video_probe(client);

    // 如果探测失败,则跳转到err_videoprobe
    if (ret < 0)
        goto err_videoprobe;

    // 注册v4l2异步子设备
    ret = v4l2_async_register_subdev(&priv->subdev);

    // 如果注册失败,则跳转到err_videoprobe
    if (ret < 0)
        goto err_videoprobe;

    // 打印信息
    dev_info(&adapter->dev, "OV2640 Probed\n");

    // 返回0
    return 0;

// 如果探测失败,则释放控制器并释放时钟
err_videoprobe:
    v4l2_ctrl_handler_free(&priv->hdl);
err_clk:
    v4l2_clk_put(priv->clk);

    // 返回错误码
    return ret;
}

ov2640_remove
这个函数是用于从i2c_client中获取ov2640_priv结构体,并进行反初始化操作。下面是对该函数的概括总结:
从i2c_client中获取ov2640_priv结构体。
取消v4l2异步子设备的注册。
释放时钟资源。
取消v4l2子设备的注册。
释放控制器资源。
返回0表示反初始化成功。
该函数主要用于释放与OV2640摄像头驱动程序相关的资源,包括时钟、控制器和子设备的注册。
// 从i2c_client中获取ov2640_priv,并进行反初始化

static int ov2640_remove(struct i2c_client *client)
{
    struct ov2640_priv       *priv = to_ov2640(client); // 获取ov2640_priv

    v4l2_async_unregister_subdev(&priv->subdev); // 取消v4l2异步子设备的注册
    v4l2_clk_put(priv->clk); // 释放时钟
    v4l2_device_unregister_subdev(&priv->subdev); // 取消v4l2子设备的注册
    v4l2_ctrl_handler_free(&priv->hdl); // 释放控制器
    return 0; // 返回0
}

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

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

相关文章

三、Mybatis从入门到入土

一、什么是Mybatis 1&#xff09;MyBatis 是一款优秀的持久层&#xff08;DAO层&#xff09;框架 2&#xff09;MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程 3&#xff09;MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c;将…

程序员做爬虫有哪些痛点

很多网站会设置反爬虫机制&#xff0c;如验证码、IP封禁、请求频率限制等&#xff0c;这些机制会增加爬虫的难度。 程序员做爬虫时&#xff0c;可能会遇到以下难点&#xff1a; 1、反爬虫机制 许多网站会设置反爬虫机制&#xff0c;如验证码、IP封禁、请求频率限制等&#x…

ICV: ADAS SoC市场规模将在2024年迎来较大突破

随着先进驾驶辅助系统&#xff08;ADAS&#xff09;的出现和对于自动驾驶的追求&#xff0c;汽车行业正在经历快速转型。这些技术进步的核心是ADAS SoC&#xff0c;它是实现多个功能集成于单一平台的关键组件。ADAS SoC已经成为智能汽车的重要驱动因素&#xff0c;彻底改变了安…

Linkage Mapper Toolkit中的 Barrier Mapper 功能解析(含实际案例分析)

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: Linkage Mapper解密数字世界链接 文章目录 🎉引言🌟博客介绍🌟Linkage Mapper 工具和 ArcGIS 简介🎉Barrier Mapper 和 ArcGIS 的集成</

python内置模块之logging

文章目录 1 开始使用 logging 1.1 第一个程序1.2 日志级别1.3 输出格式 2 输出日志到文件 2.1 使用 basicConfig 配置文件路径2.2 logging 模块化设计2.3 自动分割日志文件 最近因为一个小需求&#xff0c;需要保存日志到文件中。因为平时调试都只是用print&#xff0c;当不…

Cesium教程(五):加载自定义地形数据

目录 1、准备数据 2、转化数据 3、发布数据 4、加载数据 5、数据下载地址 1、准备数据 可以从NASA网站免费下载30m空间分辨率高程模型数据 在地图上选择区域之后&#xff0c;点击左侧对应区域下载即可&#xff1a; 也可以在地理空间数据云上下载所需要的地区数据地理空间数…

Zeebe系列(1)-- Zeebe官方管理台使用

Zeebe管理台创建 注册zeebe账号&#xff0c;可以获得30天的免费试用期。可以在官方提供的管理台页面进行zeebe集群的创建等操作。 Accounts | Sign Up - Camunda Zeebe管理台是进行流程管理的界面&#xff0c;主要包括5个组件。 Console Console&#xff1a;Zeebe的控制台&…

Java高并发核心编程—内置锁原理篇

注&#xff1a;本笔记是阅读《Java高并发核心编程卷2》整理的笔记&#xff01; 导致并发修改的原因 例如Java中的i等指令并非是原子操作&#xff0c;而是三条指令的集合&#xff1a;“内存取值”、“寄存器增加1”、“存值到内存” 。 因此&#xff0c;如果是多线程并发使用C…

PHP操作宝塔面板Api,宝塔服务器搭建,API接口使用教程

最近两个月都在写Bty项目&#xff0c;所以收集了很多很多宝塔常用到的一些Api接口&#xff0c;官方文档虽然写了一点&#xff0c;但是始终是不怎么全的&#xff0c;下面我们来看看宝塔面板的接口如何抓取 接口抓取 1、登录宝塔面板 2、找到自己想要的功能 3、f12打开审查元素&a…

韵达转债上市价格预测

韵达转债 基本信息 转债名称&#xff1a;韵达转债&#xff0c;评级&#xff1a;AA&#xff0c;发行规模&#xff1a;24.5亿元。 正股名称&#xff1a;韵达股份&#xff0c;今日收盘价&#xff1a;12.23元&#xff0c;转股价格&#xff1a;12.15元。 当前转股价值 转债面值 / 转…

vue关于静态路由和动态路由:

这篇文章写得超详细&#xff01;&#xff01;&#xff01; &#x1f449;vue实现动态路由一步到位_vue动态路由怎么实现_ds_surk的博客-CSDN博客 目录 静态路由的配置&#xff1a; 步骤&#xff1a; 动态路由的配置&#xff1a; 步骤&#xff1a; 代码实现&#xff1a; …

网易云音乐开发--search模块基本功能实现(除历史记录模块)

search头部搭建 老样子搭建一个search搜索页面 还有一块没有实现&#xff0c;那就是让输入框默认的文本变换颜色 微信小程序: input输入框placeholder样式的修改_微信小程序placeholder样式_酷伊奥的博客-CSDN博客 百度搜索了一下&#xff0c;找到了这个大佬的解决方案。很nic…

ICV:中国的数字经济与5G市场研究报告

近日&#xff0c;专注于前沿科技领域的国际咨询机构ICV发布了《中国的数字经济与5G市场研究报告》。报告指出&#xff0c;随着5G商用的发展&#xff0c;5G对经济社会的影响逐步显现&#xff0c;其影响突出体现在对数字产业发展的带动上。随着5G应用的不断创新与扩散&#xff0c…

chrome插件打包之后,显示此扩展程序可能已损坏

每日鸡汤&#xff0c;每个你想要学习的瞬间都是未来的你向自己求救 问题是这样的&#xff0c;我们有一个chrome插件的项目&#xff0c;但是我也没有参与开发&#xff0c;可以说此前对chrome插件一窍不通。但是今天呢&#xff0c;有个bug&#xff0c;要我改&#xff0c;我就拉一…

基于Java+SpringBoot+Vue的校园交友网站的设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架下…

为什么x86架构一个字节是8个bit

探究计算机存储的历史&#xff1a;为什么x86架构下一个字节是8个bit 原文链接&#xff1a;Some possible reasons for 8-bit bytes About author I’m a software developer. I live in Montreal. I sometimes give talks. Most of my income comes from my programming zines…

【博览群书】《实战大数据》——属于我的第一本大数据图书

文章目录 前言简介目录其他 前言 Hello家人们&#xff0c;博主前不久参加了CSDN图书馆和机械工业出版社联合举办的图书类活动&#xff0c;很荣幸在活动中获得了属于自己的第一本大数据图书&#xff0c;《实战大数据—— 分布式大数据分析处理系统开发与应用》。作为大数据专业…

五、数据仓库详细介绍(建模)理论篇

1 前言 大家好&#xff0c;本篇文章是数仓详细介绍系列的第四篇。 第一篇是简单介绍&#xff0c;后三篇属于数仓设计部分&#xff1a; 数仓概述&#xff0c;这一篇我给大家简单介绍了数据仓库的基本概念和大致构建过程&#xff0c;没有过多深入主要是给大家有个基本的了解。 数…

数字孪生应用落地,“未来之城”或成智慧城市新形态

“最近&#xff0c;到北京大学人民医院西直门院区就诊的患者发现&#xff1a;动辄绵延数百米的“车龙”消失了&#xff0c;周边道路也变得畅通起来。高峰期排队进院花费的时间&#xff0c;从过去1个多小时减至现在的10分钟左右。 与之相隔不远的北京市西城区城市管理委员会办公…

Java程序设计入门教程--类的行为

类的成员方法是Java描述类对象行为的途径。成员方法的定义应包含两部分内容&#xff1a;方法声明和方法体。 方法定义常用的格式如下&#xff1a; [public/protected/private][static][final/abstract] returnType methodName([param List]) [throw…