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

news/2024/11/29 12:52:56/

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_descstruct i2c_adapter    *adapter = to_i2c_adapter(client->dev.parent); // 获取i2c_adapterint            ret;if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { // 如果i2c_adapter不支持SMBUSdev_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_DEFERif (!ssdd && !client->dev.of_node) { // 如果soc_camera_subdev_desc不存在且设备树节点不存在dev_err(&client->dev, "Missing platform_data for driver\n"); // 打印错误信息ret = -EINVAL; // 返回-EINVALgoto 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_videoprobeif (ret < 0)goto err_videoprobe;// 注册v4l2异步子设备ret = v4l2_async_register_subdev(&priv->subdev);// 如果注册失败,则跳转到err_videoprobeif (ret < 0)goto err_videoprobe;// 打印信息dev_info(&adapter->dev, "OV2640 Probed\n");// 返回0return 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_privv4l2_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.ppmy.cn/news/88987.html

相关文章

PLUS模型教程

详情点击链接&#xff1a;基于”PLUS模型“生态系统服务多情景模拟预测 一&#xff1a;理论与软件 1、概念界定与理论 1.1土地利用 1.2多情景模拟 1.3生态系统服务 2、地理数据 2.1地理数据库: 2.2 文件地理数据库:保存在文件系统文件夹中的多种类型的 GIS 数据集的集合…

阿里开源!集成了 AIGC 的免费数据库工具:Chat2DB

今天推荐的这个项目是「Chat2DB」&#xff0c;一款开源免费的数据库客户端工具&#xff0c;支持 Windows、Mac 本地安装&#xff0c;也支持服务器端部署&#xff0c;Web 网页访问。 和传统的数据库客户端软件 Navicat、DBeaver 相比 Chat2DB 集成了 AIGC 的能力&#xff0c;能…

【OS】Python模拟简单的操作系统

【OS】Python模拟简单的操作系统 Background 学习操作系统的时候&#xff0c;关注的对象是&#xff1a; 应用程序系统调用操作系统的内部实现 通常的学习思路&#xff1a; 真实的操作系统编译内核环境qemu模拟 但是&#xff0c;换个角度想一下&#xff0c;把上述的思路抽…

Axure教程—垂直方向多色图(中继器)

本文将教大家如何用AXURE制作动态垂直方向多色图 一、效果介绍 如图&#xff1a; 预览地址&#xff1a;https://9fxtte.axshare.com 下载地址&#xff1a;https://download.csdn.net/download/weixin_43516258/87822547?spm1001.2014.3001.5503 二、功能介绍 简单填写中继…

Linux网络基础-5

在上一篇博客中我们对网络层的典型协议--IP进行了介绍&#xff0c;那么本篇博客作为网络方面的最后一片博客&#xff0c;我们对网络中最后内容--链路层协议进行讲解。 目录 1.链路层协议 1.1MAC地址 1.1.1类型 1.1.2作用 1.2以太网协议 1.2.1协议格式 1.2.2ARP协议 1.…

SolVES模型应用(基于多源环境QGIS\PostgreSQL\ARCGIS\MAXENT\R语言支持下模型应用)

生态系统服务是人类从自然界中获得的直接或间接惠益&#xff0c;可分为供给服务、文化服务、调节服务和支持服务4类&#xff0c;对提升人类福祉具有重大意义&#xff0c;且被视为连接社会与生态系统的桥梁。自从启动千年生态系统评估项目&#xff08;Millennium Ecosystem Asse…

【09】Nginx之缓存集成

Nginx缓存集成 缓存的概念 缓存就是数据交换的缓冲区(称作:Cache),当用户要获取数据的时候&#xff0c;会先从缓存中去查询获取数据&#xff0c;如果缓存中有就会直接返回给用户&#xff0c;如果缓存中没有&#xff0c;则会发请求从服务器重新查询数据&#xff0c;将数据返回给…

使用压缩包安装jdk多版本并能灵活切换

使用压缩包安装jdk多版本并能领过切换 1.下载2.解压包到指定位置3.使用pdate-alternatives 进行版本切换管理3.1. jdk173.2. jdk1.8 3.切换版本4.解决JAVA_HOME环境变量识别的问题 1.下载 官网的下载地址&#xff1a; 下载地址&#xff1a; jdk17: jdk1.8在当前页面的下面: …