文章目录
- 前言
- 一、I2C硬件框架
- 二、i2c_adapter
- 三、i2c_client
- 四、i2c_msg
- 总结
前言
本篇文章来讲解I2C系统的重要结构体,了解这些结构体对于编写I2C驱动来说是至关重要的,所以要想编写好一个I2C驱动程序那么就必须先了解这些结构体。
一、I2C硬件框架
这里使用百问网的一张图片来讲解:
一个芯片中可以有多个I2C控制器,并且一个I2C控制器可以控制多个设备。那么在对应的驱动中I2C控制器和这些设备还有传输的消息都是用什么来表示的呢?
在Linux内核中:
使用i2c_adapter这个结构体来代表一个I2C控制器。
传输的消息使用i2c_msg结构体表示。
设备使用i2c_client结构体表示。
二、i2c_adapter
i2c_adapter结构体:
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];
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;
};
在Linux内核中我们能找到这个结构体,下面我们来讲解一下其中比较重要的成员。
nr成员:
这个成员变量代表的是第几个I2C控制器,因为在一个芯片中I2C控制器的数量肯定是不止一个的,所以需要有一个变量来标识具体是第几个I2C控制器。
const struct i2c_algorithm *algo
const struct i2c_algorithm *algo 是指向 I2C 访问算法的结构体指针,该指针指向一个常量类型的 struct i2c_algorithm 结构体,其中定义了 I2C 总线上的访问操作函数指针,包括了 master_xfer、smbus_xfer 以及 functionality 等。通过这些访问函数,可以实现对 I2C 总线上的传感器、EEPROM 和其他设备的读写操作。
在实现 I2C 设备驱动程序时,通常需要根据具体的 I2C 总线访问算法进行编程。而在适配器结构体 struct i2c_adapter 中,通过 algo 指针可以方便地获取到对应的 I2C 总线访问算法信息,从而实现 I2C 设备的访问。
algo结构体:
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
};
三、i2c_client
i2c_client结构体:
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
};
在 Linux 内核中,i2c_client 是 I2C 从设备的设备结构体,表示连接到 I2C 总线上的一个 I2C 从设备。它包含了该从设备的一些信息,例如设备地址、从设备驱动程序、从设备所在的 I2C 适配器等。
重要的成员:
unsigned short addr:I2C 从设备的地址,存储在 7 位中。注意,这个地址不包括 I2C 地址的读写位,即 7 位地址用于标识从设备的身份。
struct i2c_adapter *adapter:指向从设备所连接的 I2C 适配器的指针。有了适配器信息,可以通过适配器的接口访问连接的从设备。
四、i2c_msg
i2c_msg结构体:
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 */
};
struct i2c_msg 是 Linux 内核中 I2C/SMBus 消息的结构体,用于描述 I2C 总线上的一条消息。
重要的成员:
__u16 addr:I2C 从设备的地址,用于指定消息要发送到哪个从设备上。
__u16 flags:消息的标志参数,包括多种不同的位掩码:
通过这些参数,struct i2c_msg 结构体可以描述出 I2C 总线上的一条具体的消息,并通过设备驱动程序对该消息进行操作。
总结
有了这些重要结构体的知识我们就可以开始编写驱动程序了。