往期内容
I2C子系统专栏:
总线和设备树专栏:
1.框图
建议右击图片在新标签页打开预览
i2c_transfer函数就是读取i2c设备的信息或者输出信息给i2c设备的函数
比如发送app发送数据给i2c设备,i2c设备的驱动程序会调用到i2c_transfer函数,将信息发送给i2c控制器,I2C控制器就能根据协议调用内部i2c_adapter定义的传输函数(比如master_xfer和smbus_xfer)向设备发送数据
又比如想要读取i2c设备的数据,通过i2c_transfer来读取,会告诉i2c控制器调用相关的读函数来读取到i2c设备的数据(比如读取到Buf中,将buf传送回app)
结构体刚开始的话,看到这其实已经差不多了,当然,有兴趣深究的可以继续往下看:
2. struct i2c_adapter
代表着一个I2C 控制器,同时也标识着物理的I2C总线,并且有着一套访问I2C设备的算法,其实也就是协议类型:I2C/SMbus协议等
\Linux-4.9.88\include\linux\i2c.h:
/*
* i2c_adapter is the structure used to identify a physical i2c bus along
* with the access algorithms necessary to access it.
*/
struct i2c_adapter {
struct module *owner;
unsigned int class; /* classes to allow probing for */
const struct i2c_algorithm *algo; /* 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 */
int nr;
char name[48]; // 表示 I2C 适配器的名字
struct completion dev_released; //用于同步释放控制器资源的完成机制
struct mutex userspace_clients_lock; //用于保护用户空间 I2C 客户端的并发访问
struct list_head userspace_clients; //维护一个用户空间 I2C 客户端的链表。通过这个链表,适配器可以跟踪注册到它的用户空间客户端
struct i2c_bus_recovery_info *bus_recovery_info;//当 I2C 总线发生错误或死锁时,可以尝试通过 bus_recovery_info 中定义的方法进行总线恢复,例如通过 GPIO 拉低总线或者其他恢复手段
const struct i2c_adapter_quirks *quirks;//定义适配器的某些特殊行为或限制
};
struct module *owner
: 用于指向当前拥有这个 I2C 控制器的模块。这个成员确保了模块在其设备未完全释放时不会被卸载。典型情况下会使用 THIS_MODULE
来指向当前模块。
unsigned int class
: 用于表示该 I2C 适配器支持的设备类型(类)。 class 字段用于限制能够自动挂载到这个适配器上的设备类型 :
I2C_CLASS_HWMON
:支持硬件监控设备。I2C_CLASS_DDC
:用于显示设备的 DDC 通道。I2C_CLASS_SPD
:支持 SPD 存储设备。I2C_CLASS_DEPRECATED
:表示不再支持的设备类型。
const struct i2c_algorithm *algo
**:**下一点中再细讲
void *algo_data
: 用于存储算法(algo
)相关的私有数据。 允许驱动在适配器与其使用的算法之间共享特定于适配器的上下文数据。
const struct i2c_lock_operations *lock_ops
: 如果某些适配器需要特殊的锁定行为,可以在这里定义自定义的锁操作,以确保在并发访问总线时保持正确的同步。
struct rt_mutex bus_lock
: 多设备可能同时尝试访问 I2C 总线,这里用 rt_mutex
互斥锁来保护总线,确保不会发生并发访问问题。
struct rt_mutex mux_lock
: 与 bus_lock
类似,保护 I2C 总线多路复用器(mux)的同步访问。 在某些情况下,一个 I2C 控制器可能连接多个 I2C 总线,通过一个多路复用器进行选择,mux_lock
保护对该复用器的访问。
int timeout
和 int retries
: 定义 I2C 传输的超时时间,单位是 jiffies; 定义 I2C 传输失败后的重试次数。
struct device dev
:I2C framework将I2C adapter当做了I2C bus中的一类特殊的设备,因此dev变量是它在设备模型中的体现。
int nr
: 控制器的编号(ID),在 /sys/bus/i2c/devices/i2c-n
中表示该总线。
剩下的就直接注释在代码中了。
3. struct i2c_algorithm
用于定义一个 I2C 控制器器(i2c_adapter
)的传输方法(I2C 或 SMBus)。它主要用于描述控制器器的操作方式,并为设备驱动提供传输功能接口
\Linux-4.9.88\include\uapi\linux\i2c.h
/**
* struct i2c_algorithm - represent I2C transfer method
* @master_xfer: Issue a set of i2c transactions to the given I2C adapter
* defined by the msgs array, with num messages available to transfer via
* the adapter specified by adap.
* @smbus_xfer: Issue smbus transactions to the given I2C adapter. If this
* is not present, then the bus layer will try and convert the SMBus calls
* into I2C transfers instead.
* @functionality: Return the flags that this algorithm/adapter pair supports
* from the I2C_FUNC_* flags.
* @reg_slave: Register given client to I2C slave mode of this adapter
* @unreg_slave: Unregister given client from I2C slave mode of this adapter
*
* The following structs are for those who like to implement new bus drivers:
* i2c_algorithm is the interface to a class of hardware solutions which can
* be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
* to name two of the most common.
*
* The return codes from the @master_xfer field should indicate the type of
* error code that occurred during the transfer, as documented in the kernel
* Documentation file Documentation/i2c/fault-codes.
*/
struct i2c_algorithm {
/* 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);
//---------------(A)
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);
//---------------(B)
/* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *);
//---------------(C)
#if IS_ENABLED(CONFIG_I2C_SLAVE)
int (*reg_slave)(struct i2c_client *client);
int (*unreg_slave)(struct i2c_client *client);
#endif
};
(A)master_xfer
是控制器执行 I2C 传输的核心函数,里面有一个关键的参数就是 struct i2c_msg *msgs, 驱动程序会通过该函数与 I2C 设备通信,具体的讲解下文会单独讲;参三num是指该msgs数据的长度。
(B)smbus_xfer
SMBUS有关的数据传输接口,如果为NULL,I2C core会尝试使用master_xfer模拟
(C)functionality
该函数返回适配器支持的功能标志,用于描述适配器能够支持哪些类型的 I2C 或 SMBus 操作:
I2C_FUNC_I2C
: 适配器支持基本的 I2C 功能。I2C_FUNC_10BIT_ADDR
: 支持 10 位地址的 I2C 设备。I2C_FUNC_PROTOCOL_MANGLING
: 支持非标准协议行为(如时序微调等)。I2C_FUNC_NOSTART
: 支持不需要发送 START 信号的 I2C 传输。I2C_FUNC_SMBUS_*
: 支持 SMBus 协议的各种操作,如字节传输、块传输等。
4.struct i2c_msg
用于描述 I2C 传输过程中一次消息(msg
)的内容。I2C 通信通常以消息为单位进行操作,一个 i2c_msg
结构体对应 I2C 总线上的一次传输,无论是主机向从机发送数据,还是主机从从机读取数据
\Linux-4.9.88\include\uapi\linux\i2c.h
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 /* this is a ten bit chip address */
#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 */
};
(1)addr,I2C slave device的地址。
(2)flags,数据传输可携带的flag,下面讲解
(3)len,数据传输的长度,单位为byte。
(4)buf,数据buf。
正常写:
S Addr Wr [A] Data [A] Data [A] ... [A] Data [A] P
- 主设备发送 START 信号,接着发送从设备地址(写操作标志位
Wr
),等待应答A
,然后发送数据,直到发送完成并收到应答A
,最后发送 STOP 信号。
正常读:
S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
- 主设备发送 START 信号,接着发送从设备地址(读操作标志位
Rd
),等待应答A
,然后从从设备读取数据,直到读取完成并返回 NACK(表示没有更多数据可读),然后发送 STOP 信号。
读写混合操作:
- 读写混合操作通常出现在需要连续传输的场景中。比如先从设备读取数据,再发送某些写入命令:
S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P
flag:
I2C_M_RD
(0x0001):表示这是一个读操作,数据流向是从从设备到主设备。默认情况下,没有这个标志时,消息是写操作(主设备向从设备发送数据)。I2C_M_TEN
(0x0010):表示从设备使用的是 10 位地址。默认情况下,I2C 使用 7 位地址。I2C_M_RECV_LEN
(0x0400): 表示读取的数据长度将由从设备通过第一个接收到的字节来指定。I2C_M_NO_RD_ACK
(0x0800):表示在读取过程中不需要确认(ACK)忽略所有的NACK/ACK信号。这个标志位常见于 SMBus(System Management Bus)设备。某些设备在 I2C 读操作的开始,会首先发送一个字节作为接下来的数据长度,然后再传输实际的数据。I2C_M_IGNORE_NAK
(0x1000):表示即使在收到非应答(NAK,No Acknowledgement)信号后,也要继续执行传输操作。 某些从设备设计不规范,在正常情况下可能会返回 NACK,即使仍然有数据可以读取。使用此标志时,主设备会继续读取数据,而不会因为 NACK 停止传输。例如,读取电视的 EDID 信息时,可能会遇到这样的设备。I2C_M_REV_DIR_ADDR
(0x2000): 反转读写方向,即在读操作时发送写信号,写操作时发送读信号。I2C_M_NOSTART
(0x4000): 如果消息的标志位中包含I2C_M_NOSTART
,则会跳过 START 信号的发送,直接传输数据。这种场景比较少见,可能在一些特定硬件或者协议优化中用到。例如, 有两个连续的消息:- 正常情况下:
S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P
S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P
- 使用 `I2C_M_NOSTART` 后:
S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P
S Addr Rd [A] [Data] NA Data [A] P
I2C_M_STOP
(0x8000):表示在本次传输结束时,需要发送一个停止信号(STOP 信号)。如果不设置此标志,可能会继续传输后续消息。仅支持I2C_FUNC_PROTOCOL_MANGLING
的适配器能使用此标志。
标签:i2c,struct,algorithm,adapter,I2C,Data,设备 From: https://blog.csdn.net/caiji0169/article/details/142907145至于i2c client结构体留到 consumer 角度讲一下i2c外设 专节再细讲,只需看框架图中的介绍就行了