红联Linux门户
Linux帮助

Linux I2C总线框架学习笔记

发布时间:2016-12-17 15:18:07来源:blog.csdn.net/qidi_huang作者:Qidi_Huang
【I2C框架结构】
Linux 内核中的 I2C 框架分为 3 部分,分别是 Core、Bus Driver、DeviceDriver 。其中 Core 部分是框架中的框架,会调用 Bus Driver 和 Device Driver 中的函数和结构体进行 I2C 注册、数据读写。我将其整理成为下面这张框图(按下 ctrl+鼠标滚轴 可放大图片):
Linux I2C总线框架学习笔记
 
【驱动编写的主要工作】
I2C 框架里需要我们完善的内容存在于 Bus Driver 和 Device Driver 中,我将其分为 2 部分——接口结构体、接口函数。
先来看结构体。根据设备的不同我们需要定义包含不同内容的 adapter 结构体、client结构体、driver 结构体、algorithm 结构体。一个adapter结构体可以用于注册多个 client结构体,这些 client结构体都存储在 adapter结构体的 clients链表中。adapter结构体的定义如下:
struct i2c_adapter {  
struct module *owner;   
unsigned int id;  
unsigned int class;    
const struct i2c_algorithm *algo;    // i2c 时序实现算法  
void *algo_data;    // 私有数据,包含要收发的消息 *msg  
int(*client_register)(struct i2c_client *);   // 用于注册 client  
int (*client_unregister)(struct i2c_client *);  
/* data fields that are valid for all devices */  
u8 level;  
struct mutex bus_lock;  
struct mutex clist_lock;  
int timeout;    /* in jiffies*/  
int retries;    
struct device dev;    /* the adapter device */  
int nr;     // 适配器的个数  
struct list_head clients;    //client链表头  
char name[48];    // 适配器名称  
struct completion dev_released;    // 用于同步  
};
client结构体定义如下:
struct i2c_client {  
unsigned int flags;   /* 标志 */  
unsigned short addr;    /* 低 7 位为芯片地址 */  
struct i2c_adapter *adapter;   /*依附的 i2c_adapter*/  
struct i2c_driver *driver;    /*依附的 i2c_driver*/  
struct device dev;    /* 设备结构体 */  
char name[I2C_NAME_SIZE];     /* 设备名称 */  
struct completion released;     /* 用于同步 */  
};
i2c_msg结构体定义如下:
struct i2c_msg {  
__u16 addr;    // 设备地址  
__u16 flags;   // 读/写标志  
__u16 len;     // 消息长度  
__u8 *buf;     // 消息数据  
};
再来看在上述的接口结构体中存在的众多接口函数,她们也需要我们根据具体情况实现。这些待实现的接口函数有 (*master_xfer)、(*probe)、(*remove) 等。如下:
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,  
char read_write,  
u8 command,  
int size,  
union i2c_smbus_data * data);  
u32 (*functionality) (struct i2c_adapter *);/*返回适配器支持的功能*/  
};  
struct i2c_driver {  
int id;  
unsigned int class;  
int (*attach_adapter)(struct i2c_adapter *);    /* 依附i2c_adapter函数指针 */  
int (*detach_adapter)(struct i2c_adapter *);    /* 脱离i2c_adapter函数指针 */  
int (*detach_client)(struct i2c_client *);        /* i2c client脱离函数指针 */  
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 *);  
int (*suspend)(struct i2c_client *, pm_message_t mesg);  
int (*resume)(struct i2c_client *);  
int (*command)(struct i2c_client *client,unsigned int cmd, void*arg);     /* 类似ioctl */  
struct device_driver driver;    /* 设备驱动结构体 */  
struct list_headlist;         /* 链表头 */  
};
以上就是需要我们在自己的驱动里主要编写的内容。按照 Linux I2C 的框架,我们将这些内容分别写到 2 个驱动模块中,即 Bus Driver 模块和 Device Driver 模块。
 
【I2C驱动调用流程】
驱动加载时,从模块入口函数开始执行。2 个模块的加载/卸载函数与其余各部分的关系如上文框图所示,其形式类似下方代码:
static int __init i2c_adapter_xxx_init()  
{  
xxx_adapter_hw_init();    // 硬件相关初始化,如申请I/O地址、中断号等  
i2c_add_adapter(&xxx_adapter);    // 添加实际情况需要的 xxx_adapter  
…  
}  
static void __exit i2c_adapter_xxx_exit()  
{  
xxx_adapter_hw_free();  
i2c_del_adapter(&xxx_adapter);  
}  
static struct i2c_driver device_xxx_driver= {  
.driver = {  
.name = “device_xxx”,    // 为各设备填充 driver 结构体  
}  
.probe =device_xxx_probe,  
.remove =device_xxx_remove,  
.id_table =device_xxx_id,  
};  
static int __init device_xxx_init()  
{  
return i2c_add_driver(&device_xxx_driver);   // 为设备添加 driver 结构体,有几个设备就要添加几个 driver  
}  
static void __exit device_xxx_exit()  
{  
i2c_del_driver(&device_xxx_driver);  
}
之后的 I2C 操作,如设备注册、数据读写等,将按照以上各结构体中关联的函数相应进行。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/26991.html