一. i2c的结构体
1. i2c适配器
struct i2c_adapter {
struct module *owner; //模块所有者
unsigned int id __deprecated;
unsigned int class; //支持的类别(I2C_CLASS_HWMON,I2C_CLASS_DDC,I2C_CLASS_SPD)
const struct i2c_algorithm *algo; //i2c算法结构体
void *algo_data;
struct rt_mutex bus_lock;
int timeout; //超时值默认是1s
int retries; //通讯重试次数
struct device dev; //设备文件
int nr; //id号,次设备号
char name[48]; //i2c适配器名
struct completion dev_released;
struct mutex userspace_clients_lock;
struct list_head userspace_clients; //挂接的设备链表头
};
2. i2c设备
struct i2c_client {
unsigned short flags; //标志(读/写)
unsigned short addr; //i2c地址
char name[I2C_NAME_SIZE]; //i2c设备名
struct i2c_adapter *adapter; //匹配的i2c适配器
struct i2c_driver *driver; //匹配的i2c驱动
struct device dev; //设备文件
int irq;
struct list_head detected; //"检测到"链表头
};
3. i2c驱动
struct i2c_driver {
unsigned int class;
int (*attach_adapter)(struct i2c_adapter *); //连接i2c适配器
int (*detach_adapter)(struct i2c_adapter *); //分离i2c适配器
int (*probe)(struct i2c_client *, const struct i2c_device_id *); //probe方法
int (*remove)(struct i2c_client *); //remove方法
void (*shutdown)(struct i2c_client *); //关闭
int (*suspend)(struct i2c_client *, pm_message_t mesg); //挂起
int (*resume)(struct i2c_client *); //唤醒
void (*alert)(struct i2c_client *, unsigned int data);
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver; //设备驱动文件
const struct i2c_device_id *id_table; //支持的i2c设备id表
int (*detect)(struct i2c_client *, struct i2c_board_info *); //检测
const unsigned short *address_list;
struct list_head clients; //匹配的设备链表
};
4. i2c板级信息
struct i2c_board_info {
char type[I2C_NAME_SIZE]; //设备名
unsigned short flags; //标志(读/写)
unsigned short addr; //i2c地址
void *platform_data; //平台资源
struct dev_archdata *archdata;
#ifdef CONFIG_OF
struct device_node *of_node;
#endif
int irq;
};
4.1 i2c板级信息辅助宏(一般声明在板级初始化函数中)
#define I2C_BOARD_INFO(dev_type, dev_addr) \
.type = dev_type, .addr = (dev_addr)
5. i2c消息
struct i2c_msg {
__u16 addr; //i2c设备地址
__u16 flags; //标志(读/写)
__u16 len; //消息长度
__u8 *buf; //缓冲区
};
5.1 i2c读写控制数据结构体
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
6. i2c算法
struct i2c_algorithm {
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, //smbus传输方式
char read_write,u8 command, int size, union i2c_smbus_data *data);
u32 (*functionality) (struct i2c_adapter *); //功能检测
};
二. i2c总线,适配器,驱动,设备的初始化
1. i2c总线类型
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match, //i2c设备与驱动匹配
.probe = i2c_device_probe, //i2c设备probe方法
.remove = i2c_device_remove, //移除
.shutdown = i2c_device_shutdown, //关闭
.pm = &i2c_device_pm_ops, //电源管理
};
1.1 i2c设备与驱动的匹配i2c_device_match
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = i2c_verify_client(dev); //根据设备文件获取i2c_client
struct i2c_driver *driver;
if (!client)
return 0;
if (of_driver_match_device(dev, drv)) //设备文件与设备驱动文件的匹配
return 1;
driver = to_i2c_driver(drv); //根据设备驱动文件获取i2c_driver
if (driver->id_table) //i2c_driver的id_table存在
return i2c_match_id(driver->id_table, client) != NULL; //匹配i2c_client和i2c_driver
return 0;
}
1.1.1 i2c_match_id函数
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,const struct i2c_client *client)
{
while (id->name[0]) { //判断i2c_driver->id_table->name数组中有与i2c_client->name相同的项没
if (strcmp(client->name, id->name) == 0)
return id;
id++;
}
return NULL;
}
1.2 i2c探测函数
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
int status;
if (!client)
return 0;
driver = to_i2c_driver(dev->driver); //获得i2c_driver
if (!driver->probe || !driver->id_table)
return -ENODEV;
client->driver = driver; //设置i2c_client->driver成员,i2c设备与驱动捆绑
if (!device_can_wakeup(&client->dev)) //i2c设备支持唤醒
device_init_wakeup(&client->dev,client->flags & I2C_CLIENT_WAKE); //则唤醒
dev_dbg(dev, "probe\n");
status = driver->probe(client, i2c_match_id(driver->id_table, client)); //调用i2c_driver->probe方法
if (status) {
client->driver = NULL;
i2c_set_clientdata(client, NULL);
}
return status;
}
2. i2c总线的注册
static int __init i2c_init(void)
{
int retval;
retval = bus_register(&i2c_bus_type);
if (retval)
return retval;
#ifdef CONFIG_I2C_COMPAT
i2c_adapter_compat_class = class_compat_register("i2c-adapter"); //创建"/sys/class/i2c-adapter"
if (!i2c_adapter_compat_class) {
retval = -ENOMEM;
goto bus_err;
}
#endif
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto clas