27 IIC(五)i2c体系结构
1. I2C体系结构组成
在linux中i2c驱动由三部分组成:i2c-core(i2c核心)、i2c总线驱动、i2c设备驱动
结合上图描述可知
-
应用态访问内核态可以使用特定的I2C driver,也可以使用通用的i2c_dev
i2c_dev.c文件内部实现的是基本的通用的i2c驱动程序。它对外只提供基本的i2c操作,相当于把部分驱动操作放到了应用层去实现
-
i2c设备驱动通过i2c-core与i2c总线驱动建立连接
-
i2c总线驱动包含:algorithum、i2c adapter、特定的硬件相关的代码
-
driver并不一定需要访问i2c adapter,还可以走gpio模拟的i2c
-
I2C设备驱动是设备端的实现,主要为i2c_driver和i2c_client
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
2. I2C文件
在内核中
linux-5.10.150/drivers/i2c$ tree
.
├── algos
│ ├── i2c-algo-bit.c
│ ├── i2c-algo-pca.c
│ ├── i2c-algo-pcf.c
│ ├── i2c-algo-pcf.h
│ ├── Kconfig
│ └── Makefile
├── busses
│ ├── i2c-acorn.c
│ ├── i2c-ali1535.c
│ ├── i2c-ali1563.c
│ ├── i2c-ali15x3.c
│ ├── i2c-altera.c
│ ├── i2c-amd756.c
...
│ ├── Kconfig
│ ├── Makefile
│ └── scx200_acb.c
├── i2c-boardinfo.c
├── i2c-core-acpi.c
├── i2c-core-base.c
├── i2c-core.h
├── i2c-core-of.c
├── i2c-core-slave.c
├── i2c-core-smbus.c
├── i2c-dev.c
├── i2c-mux.c
├── i2c-slave-eeprom.c
├── i2c-slave-testunit.c
├── i2c-smbus.c
├── i2c-stub.c
├── Kconfig
├── Makefile
└── muxes
├── i2c-arb-gpio-challenge.c
├── i2c-demux-pinctrl.c
├── i2c-mux-gpio.c
├── i2c-mux-gpmux.c
├── i2c-mux-ltc4306.c
├── i2c-mux-mlxcpld.c
-
algos
iic总线驱动的通信方法
-
busses
iic主控芯片的驱动
-
i2c-core.c
iic-core的核心功能
-
i2c-dev.c
通用iic adapter驱动,主设备号都为89,此设备号为0~255。注册类型为/dev/i2c-%d
linux-5.10.150/include/linux/i2c.h
-
i2c.h
此文件包含i2c_adapter、i2c_algorithm、i2c_driver、i2c_client等重要结构体
linux-5.10.150/include/uapi/linux/i2c.h
-
i2c_msg
iic消息,包含iic的传输地址、方向、缓冲区、缓冲长度。
位于uapi,意味着可供用户空间使用
3. 主要数据结构
3.1 i2c_adapter
/*
* 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 */
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;
};
3.2 i2c_client
client中指定了client的地址、name和adapter
struct i2c_client {
unsigned short flags; /* div., see below */
#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
#define I2C_CLIENT_TEN 0x10 /* 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 /* 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; /* 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
};
3.3 i2c_driver
i2c_driver成员中包含of_match_type和id_table
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);
/* driver中含有of_match_type */
struct device_driver driver;
const struct i2c_device_id *id_table;
/* 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;
};
3.4 i2c_algorithm
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 (*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);
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
};
3.5 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_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 */
};
3.6 数据结构之间的关系
3.6.1 i2c_adapter、i2c_algorithm
一个i2c_adapter对应一个物理上的适配器;一个i2c_algorithm对应一套通信算法
一个i2c_adapter应该包含一个i2c_algorithm。即一个i2c适配器,需要对应的algorithm来实现
3.6.2 i2c_adapter、i2c_client
i2c_adapter与i2c_client为一对多关系
3.6.3 i2c_driver、i2c_client
i2c_driver与i2c_client为一对多关系
4 i2c bus匹配机制
i2c设备的driver与client的匹配机制是由i2c_device_match去实现的了。整体实现机制与platform类似
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
if (!client)
return 0;
/* Attempt an OF style match */
/* 设备树中指定信息匹配
* devicetree compatible与driver中of_match_type中的compatible进行比较
*/
if (of_driver_match_device(dev, drv))
return 1;
/* Then ACPI style match */
/* 使用较少略过 */
if (acpi_driver_match_device(dev, drv))
return 1;
/* 比较client的name与id_table进行比较 */
driver = to_i2c_driver(drv);
/* match on an id table if there is one */
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
return 0;
}