最近在研究linux的i2c驱动,从最底层i2c控制器初始化到应用层与i2c设备交互基本打通了。
一、linux的i2c架构可以用下图表示:
IIC适配器对应一条i2c总线,linux里面用i2c_adapter结构表示。总线下的i2c设备用i2c_client结构表示。algorithm是i2c的通信协议,IIC核心层负责注册/注销i2c_adapter、注册/注销i2c_client、注册i2c总线等操作。i2c-dev对应的是i2c-dev.c,它负责将总线实例化为一个i2c_client,应用层可以通过操作对应设备节点来与总线下的任意设备进行通信。IIC设备驱动是i2c总线下的具体设备的驱动方法。
其中具体的IIC控制器操作与algorithm由IIC控制器驱动实现,常见的不同处理器的i2c总线驱动在内核源码/driver/i2c/buses/目录下。具体的i2c设备驱动内核源码并没有实现,需要自己提供。
以下摘抄宋宝华老师写的书《linux设备驱动开发详解》中说作为一个工程师要实现的主要工作:
I2C总线驱动:
(1)提供I2C适配器的硬件驱动,探测、初始化I2C适配器(如申请I2C的I/O地址和中断号)、驱动CPU控制的I2C适配器从硬件上产生各种信号以及处理I2C中断等。
(2)提供I2C适配器的Algorithm,用具体适配器的xxx_xfer()函数填充i2c_algorithm的master_xfer指针,并把i2c_algorithm指针赋值给i2c_adapter的algo指针。
I2C设备驱动:
(1):实现I2C设备驱动中的i2c_driver接口,用具体设备yyy的yyy_probe()、yyy_remove()、yyy_suspend()、yyy_resume()函数指针和i2c_device_id设备ID表赋值给i2c_driver的probe、remove、suspend、和id_table指针。
(2):实现I2C设备所对应类型的具体驱动,i2c_driver只是实现设备与总线的挂接,而挂接在总线上的设备千差万别。例如,如果是字符设备,就实现文件操作接口,即实现设备yyy的yyy_read()、yyy_write()和yyy_ioctl()函数等;如果是声卡,就实现ALSA驱动。
二、I2C核心
(1)增加/删除i2c_adapter
int i2c_add_adapter(struct i2c_adapter *adapter);
int i2c_del_adapter(struct i2c_adapter *adap);
(2)增加/删除i2c_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
void i2c_del_driver(struct i2c_driver *driver);
static inline int i2c_add_driver(struct i2c_driver *driver)
{
return i2c_register_driver(THIS_MODULE, driver);
}
(3)I2C传输、发送和接收
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
int i2c_master_send(const struct i2c_client *client, const char *buf, int count);
int i2c_master_recv(const struct i2c_client *client, char *buf, int count);