Linux第103步_了解I2C总线框架

了解Linux中的I2C总线框架为后面做I2C实验做准备,学驱动,就是学习框架,了解是必须的。

1、了解Linux下的I2C子系统中的相关数据结构

struct i2c_adapter {

struct module *owner;

unsigned int class;   /* classes to allow probing for */

const struct i2c_algorithm *algo;

/*i2c_algorithmI2C适配器与IIC设备进行通信的方法the algorithm to access the bus*/

void *algo_data;

/*对所有设备都有效的数据字段data fields that are valid for all devices*/

const struct i2c_lock_operations *lock_ops;

struct rt_mutex bus_lock;

struct rt_mutex mux_lock;

int timeout; /* in jiffies */

int retries;

struct device dev; /*适配器设备the adapter device */

unsigned long locked_flags; /* owned by the I2C core */

#define I2C_ALF_IS_SUSPENDED 0

#define I2C_ALF_SUSPEND_REPORTED 1

int nr;

char name[48];

struct completion dev_released;

struct mutex userspace_clients_lock;

struct list_head userspace_clients;

struct i2c_bus_recovery_info *bus_recovery_info;

const struct i2c_adapter_quirks *quirks;

struct irq_domain *host_notify_domain;

};

struct i2c_algorithm {

/*如果适配器算法不能进行i2c级访问,则将master_xfer设置为NULL。如果适配器算法可以进行SMBus访问,则设置smbus_xfer。如果设置为NULL,则使用普通I2C消息模拟SMBus协议。

Master_xfer应该返回成功处理的消息数,如果出错则返回负值。

If an adapter algorithm can't do I2C-level access, set master_xfer to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages.

master_xfer should return the number of messages successfully processed, or a negative value on error.

*/

int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);

/*master_xfer是I2C适配器的传输函数,可以通过此函数来完成与IIC设备之间的通信*/

int (*master_xfer_atomic)(struct i2c_adapter *adap,struct i2c_msg *msgs, int num);

int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr,

  unsigned short flags, char read_write,

  u8 command, int size, union i2c_smbus_data *data);

/*smbus_xfer是SMBUS总线的传输函数*/

int (*smbus_xfer_atomic)(struct i2c_adapter *adap, u16 addr,

 unsigned short flags, char read_write,

 u8 command, int size, union i2c_smbus_data *data);

/*确定适配器支持什么,To determine what the adapter supports */

u32 (*functionality)(struct i2c_adapter *adap);

#if IS_ENABLED(CONFIG_I2C_SLAVE)

int (*reg_slave)(struct i2c_client *client);

int (*unreg_slave)(struct i2c_client *client);

#endif

};

一个I2C设备对应一个i2c_client结构体变量,系统每检测到一个“I2C从设备就会给这个设备分配一个i2c_client。

struct i2c_client {

unsigned short flags; /* div., see below*/

#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */

#define I2C_CLIENT_TEN 0x10

/*我们有一个10位的芯片地址;we have a ten bit chip address */

/* Must equal I2C_M_TEN below */

#define I2C_CLIENT_SLAVE 0x20 /*我们是从机;we are the slave */

#define I2C_CLIENT_HOST_NOTIFY 0x40

/*我们想使用I2C主机通知;We want to use I2C host notify */

#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */

#define I2C_CLIENT_SCCB 0x9000

/* Use Omnivision SCCB protocol */

/* Must match I2C_M_STOP|IGNORE_NAK */

unsigned short addr;

/*芯片的7位地址, chip address - NOTE: 7bit*/

/* addresses are stored in the _LOWER_ 7 bits*/

char name[I2C_NAME_SIZE];

struct i2c_adapter *adapter; /*我们安装的适配器;the adapter we sit on */

struct device dev; /* the device structure*/

int init_irq; /* irq set at initialization */

int irq; /* irq issued by device */

struct list_head detected;

#if IS_ENABLED(CONFIG_I2C_SLAVE)

i2c_slave_cb_t slave_cb; /*从模式回调;callback for slave mode */

#endif

};

struct i2c_driver {

unsigned int class;

/*标准驱动模型接口; Standard driver model interfaces */

int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);

int (*remove)(struct i2c_client *client);

/* New driver model interface to aid the seamless removal of the current probe()'s, more commonly unused than used second parameter.*/

int (*probe_new)(struct i2c_client *client);

/* driver model interfaces that don't relate to enumeration  */

void (*shutdown)(struct i2c_client *client);

/* Alert callback, for example for the SMBus alert protocol.

 * The format and meaning of the data value depends on the protocol.

 * For the SMBus alert protocol, there is a single bit of data passed

 * as the alert response's low bit ("event flag").

 * For the SMBus Host Notify protocol, the data corresponds to the

 * 16-bit payload data reported by the slave device acting as master.

 */

void (*alert)(struct i2c_client *client, enum i2c_alert_protocol protocol,

      unsigned int data);

/* a ioctl like command that can be used to perform specific functions with the device.*/

int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

struct device_driver driver;

/*如果使用设备树的话,需要设置device_driver的of_match_table成员变量,

也就是驱动的兼容(compatible)属性*/

const struct i2c_device_id *id_table;

/*id_table是传统的、未使用设备树的设备匹配ID表*/

/* Device detection callback for automatic device creation */

int (*detect)(struct i2c_client *client, struct i2c_board_info *info);

const unsigned short *address_list;

struct list_head clients;

bool disable_i2c_core_irq_mapping;

};

struct i2c_board_info {

char type[I2C_NAME_SIZE];/*I2C设备的名字*/

unsigned short flags;

unsigned short addr;/*I2C器件地址*/

const char *dev_name;

void *platform_data;

struct device_node *of_node;

struct fwnode_handle *fwnode;

const struct property_entry *properties;

const struct resource *resources;

unsigned int num_resources;

int irq;

};

#define I2C_BOARD_INFO(dev_type, dev_addr)  .type = dev_type, .addr = (dev_addr)

static struct i2c_board_info armadillo5x0_i2c_rtc = {

I2C_BOARD_INFO("s35390a", 0x30),

/*type[]="s35390a"表示I2C设备的名字,addr=0x30表示I2C器件地址*/

};

struct i2c_msg {

__u16 addr; /*从机地址,slave address*/

__u16 flags;  /*标志*/

#define I2C_M_RD 0x0001 /* read data, from slave to master */

/* I2C_M_RD is guaranteed to be 0x0001! */

#define I2C_M_TEN 0x0010

/*0x0010表示10位的芯片地址, this is a ten bit chip address */

#define I2C_M_DMA_SAFE 0x0200

/* the buffer of this message is DMA safe */

/* makes only sense in kernelspace */

/* userspace buffers are copied anyway */

#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */

#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */

#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */

__u16 len; /*消息长度;msg length*/

__u8 *buf; /*指向消息数据;pointer to msg data*/

};

2、了解Linux下的I2C子系统中的相关函数

int i2c_add_adapter(struct i2c_adapter *adapter);

//动态分配一个总线编号;adapter是I2C适配器;

//返回值:0表示成功;负值表示失败;

int i2c_add_numbered_adapter(struct i2c_adapter *adap);

//指定一个静态的总线编号;adap是I2C适配器;

//返回值:0表示成功;负值表示失败;

void i2c_del_adapter(struct i2c_adapter *adap);

//删除I2C适配器,adap是要删除的I2C适配器;

int i2c_register_driver(struct module *owner, struct i2c_driver *driver);

//owner: 一般为THIS_MODULE.

//driver:要注册的i2c_driver;

//返回值:0表示成功;负值表示失败;

#define i2c_add_driver(driver)  i2c_register_driver(THIS_MODULE, driver)

void i2c_del_driver(struct i2c_driver *driver);

//注销I2C设备驱动;driver:要注销的i2c_driver;

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

//adap是I2C适配器;msgs表示I2C要发送的消息;num表示消息的数量;

//返回值:非幅值表示发送的msgs的数量;负值表示失败;

static inline int i2c_master_send(const struct i2c_client *client,const char *buf, int count);

//client表示I2C设备对应的i2c_client;

//buf指向要发送的数据;count表示要发送的数据字节数量

//注意:count要小于64Kb,因为i2c_msg结构中的len成员是u16型的;

//返回值:非幅值表示发送的字节的数量;负值表示失败;

static inline int i2c_master_recv(const struct i2c_client *client,char *buf, int count);

//client表示I2C设备对应的i2c_client;

//buf指向要接收的数据;count表示要接收的数据字节数量

//注意:count要小于64Kb,因为i2c_msg结构中的len成员是u16型的;

//返回值:非幅值表示接收到的字节的数量;负值表示失败;

3、i2c_driver注册流程:

/* i2c驱动的probe函数 */

static int xxx_probe(struct i2c_client *client, const struct i2c_device_id *id)

{

/* 函数具体程序 */

return 0;

}

/* i2c驱动的remove函数 */

static int ap3216c_remove(struct i2c_client *client)

 {

/* 函数具体程序 */

return 0;

}

 /*传统匹配方式ID列表,无设备树的时候匹配ID表*/

static const struct i2c_device_id xxx_id[] = {

  {"xxx", 0},

{}

};

/*设备树匹配列表,设备树所使用的匹配表*/

static const struct of_device_id xxx_of_match[] = {

{ .compatible = "xxx" },

/*在stm32mp157d-atk.dts设备树文件中,定义“compatible = "xxx";”*/

{ /*这是一个空元素,在编写of_device_id时最后一个元素一定要为空*/

/* Sentinel */

}

};

/* i2c驱动结构体*/

static struct i2c_driver xxx_driver = {

.probe = xxx_probe,/*i2c驱动的probe函数xxx_probe()*/

.remove = xxx_remove,/*i2c驱动的remove函数xxx_remove()*/

.driver = {

.owner = THIS_MODULE,

.name = "xxx",

.of_match_table = xxx_of_match,

},

.id_table = xxx_id,

};

/*驱动入口函数*/

static int __init xxx_init(void)

{

int ret = 0;

ret = i2c_add_driver(&xxx_driver);

return ret;

}

/*驱动出口函数*/

static void __exit xxx_exit(void)

{

i2c_del_driver(&xxx_driver);

}

module_init(xxx_init);//声明xxx_init()为驱动入口函数

module_exit(xxx_exit);//声明xxx_exit()为驱动出口函数

4、I2C总线的数据结构:

struct bus_type i2c_bus_type = {

.name = "i2c",

.match = i2c_device_match,/*I2C总线的设备和驱动匹配函数*/

.probe = i2c_device_probe,

.remove = i2c_device_remove,

.shutdown = i2c_device_shutdown,

};

static int i2c_device_match(struct device *dev, struct device_driver *drv)

{

struct i2c_client *client = i2c_verify_client(dev);

struct i2c_driver *driver;

/* Attempt an OF style match */

if (i2c_of_match_device(drv->of_match_table, client)) return 1;

/*比较I2C设备节点的compatible属性和of_device_id中的compatible属性是否相等,如果相当的话就表示I2C设备和驱动匹配。*/

/*用于ACPI形式的匹配;Then ACPI style match */

if (acpi_driver_match_device(dev, drv)) return 1;

driver = to_i2c_driver(drv);

/* Finally an I2C match */

if (i2c_match_id(driver->id_table, client)) return 1;

/*用于传统的、无设备树的I2C设备和驱动匹配过程。比较I2C设备名字和i2c_device_id的 name字段是否相等,相等的话就说明I2C设备和驱动匹配成功。*/

return 0;

}

5、I2C设备多寄存器数据读写:

/* 设备结构体 */

struct xxx_dev {

 ......

void *private_data; /* 私有数据,一般会设置为i2c_client */ 

};

/*

* @description : 读取I2C设备多个寄存器数据

* @param – dev : I2C设备

* @param – reg : 要读取的寄存器首地址

* @param – val : 读取到的数据

* @param – len : 要读取的数据长度

* @return : 操作结果

*/

static int xxx_read_regs(struct xxx_dev *dev, u8 reg, void *val, int len)

{

int ret;

struct i2c_msg msg[2];

struct i2c_client *client = (struct i2c_client *) dev->private_data;

/* msg[0],第一条写消息,发送要读取的寄存器首地址 */

msg[0].addr = client->addr; /* I2C器件地址 */

msg[0].flags = 0; /* 标记为发送数据 */

msg[0].buf = ® /* 读取的首地址 */

msg[0].len = 1; /* reg长度 */

/* msg[1],第二条读消息,读取寄存器数据 */

msg[1].addr = client->addr; /* I2C器件地址 */

msg[1].flags = I2C_M_RD; /* 标记为读取数据 */

msg[1].buf = val; /* 读取数据缓冲区 */

msg[1].len = len; /* 要读取的数据长度 */

ret = i2c_transfer(client->adapter, msg, 2);

if(ret == 2) {ret = 0;}

else {  ret = -EREMOTEIO;}

return ret;

}

/*

* @description : 向I2C设备多个寄存器写入数据

* @param – dev : 要写入的设备结构体

* @param – reg : 要写入的寄存器首地址

* @param – val : 要写入的数据缓冲区

* @param – len : 要写入的数据长度

* @return : 操作结果

*/

static s32 xxx_write_regs(struct xxx_dev *dev, u8 reg, u8 *buf, u8 len)

{

u8 b[256];

struct i2c_msg msg;

struct i2c_client *client = (struct i2c_client *) dev->private_data;

b[0] = reg; /* 寄存器首地址*/

memcpy(&b[1],buf,len); /* 将要发送的数据拷贝到数组b里面 */

msg.addr = client->addr; /* I2C器件地址 */

msg.flags = 0; /* 标记为写数据 */

msg.buf = b; /* 要发送的数据缓冲区,发送的数据是数组b[] */

msg.len = len + 1; /* 要发送的数据长度,加1是因为要加上一个字节的寄存器地址 */

return i2c_transfer(client->adapter, &msg, 1);

}

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

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

相关文章

AAAI2024论文合集解读|Physics-Informed Representation and Learning Control and Risk

论文标题 Physics-Informed Representation and Learning: Control and Risk Quantification 物理信息表征与学习:控制与风险量化 论文链接 Physics-Informed Representation and Learning: Control and Risk Quantification论文下载 论文作者 Zhuoyuan Wang, …

Vue3组件重构实战:从Geeker-Admin拆解DataTable的最佳实践

一、前言 背景与动机 在当前的开发实践中,我们选择了开源项目 Geeker-Admin 作为前端框架的二次开发基础。其内置的 ProTable.vue 组件虽然提供了一定程度的开箱即用性,但在实际业务场景中逐渐暴露出设计上的局限性,尤其是其将 搜索条件表单…

【JavaEE进阶】Spring留言板实现

目录 🎍预期结果 🍀前端代码 🎄约定前后端交互接口 🚩需求分析 🚩接口定义 🌳实现服务器端代码 🚩lombok介绍 🚩代码实现 🌴运行测试 🎄前端代码实…

HackTheBox靶机:Sightless;NodeJS模板注入漏洞,盲XSS跨站脚本攻击漏洞实战

HackTheBox靶机:Sightless 渗透过程1. 信息收集常规探测深入分析 2. 漏洞利用(CVE-2022-0944)3. 从Docker中提权4. 信息收集(michael用户)5. 漏洞利用 Froxlor6. 解密Keepass文件 漏洞分析SQLPad CVE-2022-0944 靶机介…

Ansible入门学习之基础元素介绍

一、Ansible目录结构介绍 1.通过rpm -ql ansible获取ansible所有文件存放的目录 有配置文件目录 /etc/ansible/ 执行文件目录 /usr/bin/ 其中 /etc/ansible/ 该文件目录的主要功能是 inventory主机信息配置,ansible工具功能配置。 ansible自身的配置文件…

【pytorch 】miniconda python3.11 环境安装pytorch

ubuntu24.04 miniconda python3.11 环境安装pytorch 组件:langgraph本身不需要有一些模型是需要的:python3.11环境:报错ModuleNotFoundError: No module named ‘torchaudio’ ModuleNotFoundError: No module named ‘torchaudio’File "/root/miniconda3/envs/05_ep_…

Antd React Form使用Radio嵌套多个Select和Input的处理

使用Antd React Form使用Radio会遇到嵌套多个Select和Input的处理&#xff0c;需要多层嵌套和处理默认事件和冒泡&#xff0c;具体实现过程直接上代码。 实现效果布局如下图 代码 <Formname"basic"form{form}labelWrap{...formItemLayoutSpan(5, 19)}onFinish{on…

11 蚂蚁链技术特性

概览 蚂蚁链通过引入P2P网络、共识算法、虚拟机、智能合约、密码学、数据存储等技术特性&#xff0c;构建一个稳定、高效、安全的图灵完备智能合约执行环境&#xff0c;提供账户的基本操作以及面向智能合约的功能调用。 区块结构 一个区块包含区块头和区块体&#xff0c;区块…

如何使用 pytest-html 创建自定义 HTML 测试报告

关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理&#xff0c;构建成功的基石 在自动化测试工作之前&#xff0c;你应该知道的10条建议 在自动化测试中&#xff0c;重要的不是工具 测试 Python 代码对于提高代码质量、检测漏洞或意外行为至关重要。 但测试结果又该…

【华为OD-E卷 - VLAN资源池 100分(python、java、c++、js、c)】

【华为OD-E卷 - VLAN资源池 100分&#xff08;python、java、c、js、c&#xff09;】 题目 VLAN是一种对局域网设备进行逻辑划分的技术&#xff0c;为了标识不同的VLAN&#xff0c;引入VLAN ID(1-4094之间的整数)的概念。 定义一个VLAN ID的资源池(下称VLAN资源池)&#xff0…

【C++高并发服务器WebServer】-5:内存映射与进程通信

本文目录 一、内存映射与进程通信二、匿名映射与进程通信 一、内存映射与进程通信 内存映射Memory-mapped I/O指的是将磁盘文件的数据映射到内存&#xff0c;用户通过修改内存就能够修改磁盘文件&#xff0c;如下图所示&#xff08;进程地址空间指的是虚拟地址空间&#xff09…

使用vscode + Roo Code (prev. Roo Cline)+DeepSeek-R1使用一句话需求做了个实验

摘要 使用vscode、Roo Code和deepseek-reasoner进行了一个实验&#xff0c;尝试使用一句话需求来生成小红书封面图片。工具根据需求提供了详细的架构方案&#xff0c;包括技术栈选择、核心模块划分、目录结构建议等。然后&#xff0c;工具自动化地完成了开发和测试&#xff0c;…

C语言初阶牛客网刷题—— JZ11 旋转数组的最小数字【难度:简单】

1. 题目描述 牛客网在线OJ链接 有一个长度为 n 的非降序数组&#xff0c;比如 [1,2,3,4,5] &#xff0c;将它进行旋转&#xff0c;即把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;变成一个旋转数组&#xff0c;比如变成了 [3,4,5,1,2] &#xff0c;或者 [4,5,1,2,3…

Coze,Dify,FastGPT,对比

在当今 AI 技术迅速发展的背景下&#xff0c;AI Agent 智能体成为了关键领域&#xff0c;Coze、Dify 和 FastGPT 作为其中的佼佼者&#xff0c;各有千秋。 平台介绍 - FastGPT&#xff1a;由环界云计算公司发起&#xff0c;是基于大语言模型&#xff08;LLM&#xff09;的开源…

如何解压7z文件?8种方法(Win/Mac/手机/网页端)

7z 文件是一种高效的压缩文件格式&#xff0c;由 7 - Zip 软件开发者所采用。它运用独特的压缩算法&#xff0c;能显著缩小文件体积&#xff0c;便于存储与传输各类数据&#xff0c;像软件安装包、大型资料集等。但要使用其中内容&#xff0c;就必须解压&#xff0c;因为处于压…

【Docker】ubuntu中 Docker的使用

之前记录了 docker的安装 【环境配置】ubuntu中 Docker的安装&#xff1b; 本篇博客记录Dockerfile的示例&#xff0c;docker 的使用&#xff0c;包括镜像的构建、容器的启动、docker compose的使用等。   当安装好后&#xff0c;可查看docker的基本信息 docker info ## 查…

豆包MarsCode 蛇年编程大作战 | 高效开发“蛇年运势预测系统”

&#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 豆包MarsCode 蛇年编程大作战 | &#x1f40d; 蛇年运势预测 在线体验地址&#xff1a;蛇年…

【转帖】eclipse-24-09版本后,怎么还原原来版本的搜索功能

【1】原贴地址&#xff1a;eclipse - 怎么还原原来版本的搜索功能_eclipse打开类型搜索类功能失效-CSDN博客 https://blog.csdn.net/sinat_32238399/article/details/145113105 【2】原文如下&#xff1a; 更新eclipse-24-09版本后之后&#xff0c;新的搜索功能&#xff08;CT…

求平均年龄(信息学奥赛一本通-1059)

【题目描述】 班上有学生若干名&#xff0c;给出每名学生的年龄&#xff08;整数&#xff09;&#xff0c;求班上所有学生的平均年龄&#xff0c;保留到小数点后两位。 【输入】 第一行有一个整数n&#xff08;1≤n≤100&#xff09;&#xff0c;表示学生的人数。其后n行每行有…

macos的图标过大,这是因为有自己的设计规范

苹果官方链接&#xff1a;App 图标 | Apple Developer Documentation 这个在官方文档里有说明&#xff0c;并且提供了sketch 和 ps 的模板。 figma还提供了模板&#xff1a; Figma