【驱动】I2C驱动分析(三)-关键数据类型

I2C bus

i2c_bus_type 用于表示 I2C 总线类型。bus_type 是 Linux 内核中用于表示总线类型的结构体,用于管理该类型总线上的设备。

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
};
  • .name: 用于指定总线类型的名称。在这里,总线类型的名称被设置为 "i2c",表示 I2C 总线类型。
  • .match: 匹配设备与总线。
  • .probe: 用于在设备与总线匹配成功后进行设备探测和初始化。
  • .remove: 用于设备从总线上移除时的操作。
  • .shutdown: 用于在系统关机时对设备进行关闭和清理操作。

I2C client

struct i2c_client 结构体用于表示 I2C 设备的客户端,并存储了与该设备相关的各种信息,例如设备的地址、名称、适配器、中断请求等。

struct i2c_client {
	unsigned short flags;		/* div., see below		*/
	unsigned short addr;		/* 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 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
};
  • unsigned short flags: 存储一些标志位。
  • unsigned short addr:表示 I2C 设备的地址。需要注意的是,I2C 设备地址通常只占用 7 个比特,而这里只使用了低 7 个比特来存储地址。
  • char name[I2C_NAME_SIZE]:表示 I2C 设备的名称。I2C_NAME_SIZE 是一个宏定义,表示数组的大小。
  • struct i2c_adapter *adapter: 一个指向 struct i2c_adapter 结构体的指针,表示 I2C 设备所连接的适配器。
  • struct device dev: 一个 struct device 结构体,表示 I2C 设备对应的设备结构。
  • int irq: 设备触发的中断请求(IRQ)。
  • struct list_head detected: 链表头,用于存储已检测到的设备。
  • #if IS_ENABLED(CONFIG_I2C_SLAVE) ... #endif: 这是一个条件编译块,用于在编译时根据是否启用了 I2C 从设备模式来条件地包含代码。在启用了 I2C 从设备模式时,这里会有一个 i2c_slave_cb_t 类型的成员 slave_cb,它是一个用于从设备模式的回调函数。

I2C driver

struct i2c_driver 结构体用于表示 I2C 设备的驱动程序,并存储了与该驱动程序相关的各种函数指针、设备驱动结构、标识符表、设备检测回调函数等。

struct i2c_driver {
	unsigned int class;

	/* Notifies the driver that a new bus has appeared. You should avoid
	 * using this, it will be removed in a near future.
	 */
	int (*attach_adapter)(struct i2c_adapter *) __deprecated;

	/* Standard driver model interfaces */
	int (*probe)(struct i2c_client *, const struct i2c_device_id *);
	int (*remove)(struct i2c_client *);

	/* driver model interfaces that don't relate to enumeration  */
	void (*shutdown)(struct i2c_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").
	 */
	void (*alert)(struct i2c_client *, 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;
	const struct i2c_device_id *id_table;

	/* Device detection callback for automatic device creation */
	int (*detect)(struct i2c_client *, struct i2c_board_info *);
	const unsigned short *address_list;
	struct list_head clients;
};
  • unsigned int class: 表示驱动程序的类别。
  • int (*attach_adapter)(struct i2c_adapter *) __deprecated: 通知驱动程序有新的总线出现。
  • int (*probe)(struct i2c_client *, const struct i2c_device_id *): 指向驱动程序的探测函数。当一个新的 I2C 设备与驱动程序匹配时,将调用该函数进行初始化和配置。
  • int (*remove)(struct i2c_client *): 表示驱动程序的移除函数。当一个已经存在的 I2C 设备与驱动程序不再匹配时,将调用该函数进行清理和释放资源。
  • void (*shutdown)(struct i2c_client *):表示驱动程序的关机函数。用于在系统关机时执行一些清理操作。
  • void (*alert)(struct i2c_client *, unsigned int data): 表示驱动程序的警报回调函数。该函数用于处理警报事件,例如 SMBus 警报协议中的警报。
  • int (*command)(struct i2c_client *client, unsigned int cmd, void *arg):一个类似于 ioctl 的命令函数。用于执行特定的设备功能。
  • struct device_driver driver: 一个 struct device_driver 表示 I2C 设备驱动程序对应的设备驱动结构。
  • const struct i2c_device_id *id_table: 一个指向 struct i2c_device_id 结构体的常量指针,用于存储设备的标识符表。
  • int (*detect)(struct i2c_client *, struct i2c_board_info *): 设备检测回调函数,用于自动创建设备。
  • const unsigned short *address_list: 无符号短整型数组的常量指针,用于存储设备的地址列表。
  • struct list_head clients: 链表头,用于存储与该驱动程序关联的客户端列表。

I2C algorithm

在 Linux 内核中,每个 I2C 适配器通常都会有一个对应的 I2C 算法。struct i2c_algorithm 结构体用于表示 I2C 适配器的算法,并存储了与该适配器相关的各种函数指针,用于执行主设备传输、SMBus 传输和功能性查询。

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);
	int (*smbus_xfer) (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 *);

#if IS_ENABLED(CONFIG_I2C_SLAVE)
	int (*reg_slave)(struct i2c_client *client);
	int (*unreg_slave)(struct i2c_client *client);
#endif
};
  • int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num): I2C 主设备传输函数。该函数用于在总线上执行一系列 I2C 消息传输操作,返回成功处理的消息数量,或者在出错时返回负值。
  • 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 传输函数。该函数用于在总线上执行 SMBus 消息传输操作,根据给定的参数执行读取或写入操作,并返回操作结果。
  • u32 (*functionality)(struct i2c_adapter *): 指向功能性函数。该函数用于确定适配器支持的功能,并返回一个表示适配器功能的位掩码。
  • #if IS_ENABLED(CONFIG_I2C_SLAVE) ... #endif: 条件编译块,用于在编译时根据是否启用了 I2C 从设备模式来条件地包含代码。在启用了 I2C 从设备模式时,这里会有两个函数指针 reg_slaveunreg_slave,分别用于注册和注销从设备。

I2C adapter

struct i2c_adapter 结构体用于表示 I2C 适配器,并存储了与适配器相关的各种属性和状态信息,如适配器的拥有者、算法、超时时间、设备等。这些信息用于控制和管理 I2C 总线上的通信和操作。

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	*/
	struct rt_mutex bus_lock;

	int timeout;			/* in jiffies */
	int retries;
	struct device dev;		/* the adapter device */

	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 module *owner: 指向拥有该 I2C 适配器的内核模块的指针。
  • unsigned int class: 指定可以进行探测的 I2C 设备类别。
  • const struct i2c_algorithm *algo: 用于访问总线的 I2C 算法的指针。
  • void *algo_data: 存储与 I2C 算法相关的数据。
  • struct rt_mutex bus_lock: 用于保护 I2C 总线的互斥锁。
  • int timeout: I2C 传输的超时时间,以 jiffies 为单位。
  • int retries: 在传输期间发生错误时进行的重试次数。
  • struct device dev: 表示适配器设备的结构体。
  • 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: I2C 总线恢复信息的指针。
  • const struct i2c_adapter_quirks *quirks: I2C 适配器的特殊属性的指针。

i2c_msg

struct i2c_msg 提供了在 Linux 内核中定义和组织 I2C 消息的方式,通过 I2C 总线与 I2C 设备进行通信。

struct i2c_msg {
	__u16 addr;	/* slave address			*/
	__u16 flags;
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
	__u16 len;		/* msg length				*/
	__u8 *buf;		/* pointer to msg data			*/
};
  • __u16 addr: I2C 设备的从设备地址。
  • __u16 flags:保存了控制 I2C 消息行为的各种标志。

  • I2C_M_TEN(0x0010):表示从设备地址为十位地址。通常,I2C 设备使用七位地址,但某些设备支持十位地址。

  • I2C_M_RD(0x0001):表示消息是一个读操作,数据从从设备传输到主设备。

  • I2C_M_STOP(0x8000):该标志与 I2C_FUNC_PROTOCOL_MANGLING 特性一起使用。它表示主设备在消息之后应发送停止条件。

  • I2C_M_NOSTART(0x4000):该标志与 I2C_FUNC_NOSTART 特性一起使用。它表示主设备在此消息之前不应生成启动条件。

  • I2C_M_REV_DIR_ADDR(0x2000):该标志与 I2C_FUNC_PROTOCOL_MANGLING 特性一起使用。它表示在传输过程中地址字节应该被反转。

  • I2C_M_IGNORE_NAK(0x1000):该标志与 I2C_FUNC_PROTOCOL_MANGLING 特性一起使用。它表示如果从设备对数据字节发送 NAK(不应答),主设备应忽略它并继续传输。

  • I2C_M_NO_RD_ACK(0x0800):该标志与 I2C_FUNC_PROTOCOL_MANGLING 特性一起使用。它表示如果主设备接收到读传输的最后一个字节,它不应向从设备发送 ACK(应答)位。

  • I2C_M_RECV_LEN(0x0400):该标志表示第一个接收到的字节将包含剩余数据的长度。这通常与 I2C_M_RD 标志结合使用。

  • __u16 len:表示消息的长度,指定主设备和从设备之间要传输的字节数。

  • __u8 *buf:指向存储消息实际数据的数据缓冲区的指针。指针指向存储数据的内存位置。

i2c_board_info

i2c_board_info描述一个I2C设备的板级信息,其中包括设备类型、地址、平台特定数据、体系结构数据、设备树节点、固件节点和中断号等。这些信息可以在设备驱动程序中使用,以便正确地配置和操作I2C设备。

struct i2c_board_info {
	char		type[I2C_NAME_SIZE];
	unsigned short	flags;
	unsigned short	addr;
	void		*platform_data;
	struct dev_archdata	*archdata;
	struct device_node *of_node;
	struct fwnode_handle *fwnode;
	int		irq;
};
  • type:表示I2C设备的类型名称。I2C_NAME_SIZE是一个预定义的常量,表示数组的最大大小。
  • flags:表示与设备相关的标志位。
  • addr:表示I2C设备的地址。
  • platform_data:表示特定于平台的数据。
  • archdata:存储与设备体系结构相关的数据。
  • of_node:表示与设备树相关的节点。这个字段用于与设备树中的节点进行关联。
  • fwnode:表示固件节点(Firmware Node)相关的处理。固件节点是一种用于描述设备和其配置的数据结构,这个字段用于与固件节点进行关联。
  • irq:表示与设备关联的中断号。这个字段用于指示设备在系统中使用的中断。

各结构体的作用与它们之间的关系

i2c_adapter与i2c_algorithm

i2c_adapter对应与物理上的一个适配器,而i2c_algorithm对应一套通信方法,一个i2c适配器需要i2c_algorithm中提供的(i2c_algorithm中的又是更下层与硬件相关的代码提供)通信函数来控制适配器上产生特定的访问周期。缺少i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含其使用i2c_algorithm的指针。

i2c_algorithm中的关键函数master_xfer()用于产生i2c访问周期需要的start stop ack信号,以i2c_msg(即i2c消息)为单位发送和接收通信数据。

i2c_msg也非常关键,调用驱动中的发送接收函数需要填充该结构体

i2c_driver和i2c_client

i2c_driver对应一套驱动方法,其主要函数是attach_adapter()和detach_client()。i2c_client对应真实的i2c物理设备device,每个i2c设备都需要一个i2c_client来描述。i2c_driver与i2c_client的关系是一对多。一个i2c_driver上可以支持多个同等类型的i2c_client.

i2c_adapter和i2c_client

i2c_adapter和i2c_client的关系与i2c硬件体系中适配器和设备的关系一致,即i2c_client依附于i2c_adapter,由于一个适配器上可以连接多个i2c设备,所以i2c_adapter中包含依附于它的i2c_client的链表。

posted @ 2024-01-18 22:55  学习,积累,成长  阅读(120)  评论(0编辑  收藏  举报