Linux I2C设备驱动编写(一)
在Linux驱动中I2C系统中主要包含以下几个成员:
I2C adapter 即I2C适配器
I2C driver 某个I2C设备的设备驱动,可以以driver理解。
I2C client 某个I2C设备的设备声明,可以以device理解。
I2C adapter
是CPU集成或外接的I2C适配器,用来控制各种I2C从设备,其驱动需要完成对适配器的完整描述,最主要的工作是需要完成i2c_algorithm结构体。这个结构体包含了此I2C控制器的数据传输具体实现,以及对外上报此设备所支持的功能类型。i2c_algorithm结构体如下:
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 *);
};
如果一个I2C适配器不支持I2C通道,那么就将master_xfer成员设为NULL。如果适配器支持SMBUS协议,那么需要去实现smbus_xfer,如果smbus_xfer指针被设为NULL,那么当使用SMBUS协议的时候将会通过I2C通道进行仿真。master_xfer指向的函数的返回值应该是已经成功处理的消息数,或者返回负数表示出错了。functionality指针很简单,告诉询问着这个I2C主控器都支持什么功能。
在内核的drivers/i2c/i2c-stub.c中实现了一个i2c adapter的例子,其中实现的是更为复杂的SMBUS。
SMBus 与 I2C的区别
通常情况下,I2C和SMBus是兼容的,但是还是有些微妙的区别的。
时钟速度对比:
I2C | SMBus | |
---|---|---|
最小 | 无 | 10kHz |
最大 | 100kHZ(标准)400kHz(快速模式)2MHz(高速模式) | 100kHz |
超时 | 无 | 35ms |
在电气特性上他们也有所不同,SMBus要求的电压范围更低。
I2C driver
具体的I2C设备驱动,如相机、传感器、触摸屏、背光控制器常见硬件设备大多都有或都是通过I2C协议与主机进行数据传输、控制。结构体如下:
struct i2c_driver {
unsigned int class;
/* Notifies the driver that a new bus has appeared or is about to be
* removed. You should avoid using this, it will be removed in a
* near future.
*/
int (*attach_adapter)(struct i2c_adapter *) __deprecated; //旧的与设备进行绑定的接口函数
int (*detach_adapter)(struct i2c_adapter *) __deprecated; //旧的与设备进行解绑的接口函数
/* Standard driver model interfaces */
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 *); //从挂起状态恢复
/* 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").
*/
void (*alert)(struct i2c_client *, 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);
struct device_driver driver; //I2C设备的驱动模型
const struct i2c_device_id *id_table; //匹配设备列表
/* Device detection callback for automatic device creation */
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_head clients;
};
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) //一般编写驱动过程中对象常是driver类型,可以通过to_i2c_driver找到其父类型i2c_driver
如同普通设备的驱动能够驱动多个设备一样,一个I2C driver也可以对应多个I2C client。
以重力传感器AXLL34X为例,其实现的I2C驱动为:
static const struct i2c_device_id adxl34x_id[] = {
{ "adxl34x", 0 }, //匹配i2c client名为adxl34x的设备
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl34x_id);
static struct i2c_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
.owner = THIS_MODULE,
.pm = &adxl34x_i2c_pm, //指定设备驱动的电源管理接口,包含suspend、resume
},
.probe = adxl34x_i2c_probe, //组装设备匹配时候的匹配动作
.remove = adxl34x_i2c_remove, //组装设备移除接口
.id_table = adxl34x_id, //制定匹配设备列表
};
module_i2c_driver(adxl34x_driver);
这里要说明一下module_i2c_driver宏定义(i2c.h):
#define module_i2c_driver(__i2c_driver) \
module_driver(__i2c_driver, i2c_add_driver, \
i2c_del_driver)
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)
module_driver():
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
理解上述宏定义后,将module_i2c_driver(adxl34x_driver)展开就可以得到:
static int __int adxl34x_driver_init(void)
{
return i2c_register_driver(&adxl34x_driver);
}
module_init(adxl34x_driver_init);
static void __exit adxl34x_driver_exit(void)
{
return i2c_del_driver(&adxl34x_driver);
}
module_exit(adxl34x_driver_exit);
这一句宏就解决了模块module安装卸载的复杂代码。这样驱动开发者在实现I2C驱动时只要将i2c_driver结构体填充进来就可以了,无需关心设备的注册与反注册过程。
I2C client
即I2C设备。I2C设备的注册一般在板级代码中,在解析实例前还是先熟悉几个定义:
struct i2c_client {
unsigned short flags; //I2C_CLIENT_TEN表示设备使用10bit从地址,I2C_CLIENT_PEC表示设备使用SMBus检错
unsigned short addr; //设备从地址,7bit。这里说一下为什么是7位,因为最后以为0表示写,1表示读,通过对这个7bit地址移位处理即可。addr<<1 & 0x0即写,addr<<1 | 0x01即读。
char name[I2C_NAME_SIZE]; //从设备名称
struct i2c_adapter *adapter; //此从设备依附于哪个adapter上
struct i2c_driver *driver; // 此设备对应的I2C驱动指针
struct device dev; // 设备模型
int irq; // 设备使用的中断号
struct list_head detected; //用于链表操作
};
#define to_i2c_client(d) container_of(d, struct i2c_client, dev) //通常使用device设备模型进行操作,可以通过to_i2c_client找到对应client指针
struct i2c_board_info {
char type[I2C_NAME_SIZE]; //设备名,最长20个字符,最终安装到client的name上
unsigned short flags; //最终安装到client.flags
unsigned short addr; //设备从地址slave address,最终安装到client.addr上
void *platform_data; //设备数据,最终存储到i2c_client.dev.platform_data上
struct dev_archdata *archdata;
struct device_node *of_node; //OpenFirmware设备节点指针
struct acpi_dev_node acpi_node;
int irq; //设备采用的中断号,最终存储到i2c_client.irq上
};
//可以看到,i2c_board_info基本是与i2c_client对应的。
#define I2C_BOARD_INFO(dev_type, dev_addr) \
.type = dev_type, .addr = (dev_addr)
//通过这个宏定义可以方便的定义I2C设备的名称和从地址(别忘了是7bit的)
下面还是以adxl34x为例:
static struct i2c_board_info i2c0_devices[] = {
{
I2C_BOARD_INFO("ak4648", 0x12),
},
{
I2C_BOARD_INFO("r2025sd", 0x32),
},
{
I2C_BOARD_INFO("ak8975", 0x0c),
.irq = intcs_evt2irq(0x3380), /* IRQ28 */
},
{
I2C_BOARD_INFO("adxl34x", 0x1d),
.irq = intcs_evt2irq(0x3340), /* IRQ26 */
},
};
...
i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices));
这样ADXL34X的i2c设备就被注册到了系统中,当名字与i2c_driver中的id_table中的成员匹配时就能够出发probe匹配函数了。
Linux I2C设备驱动编写(一)的更多相关文章
- 【转】Linux I2C设备驱动编写(一)
原文网址:http://www.cnblogs.com/biglucky/p/4059576.html 在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即I2C适配器 I ...
- Linux I2C设备驱动编写(一)【转】
本文转载自:http://blog.csdn.net/airk000/article/details/21345457 在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即 ...
- Linux I2C设备驱动编写(二)
在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_driver.i2c_client.三者的关系也在上一节进行了描述.应该已经算是对Linux I2C子系统有了初步 ...
- 【转】Linux I2C设备驱动编写(二)
原文网址:http://www.cnblogs.com/biglucky/p/4059582.html 在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_drive ...
- Linux I2C设备驱动编写(三)-实例分析AM3359
TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1版本规格 支持标准模式(100K bits/s)和快速模式(400K bits/s) 多路接收.发送模式 ...
- 【转】Linux I2C设备驱动编写(三)-实例分析AM3359
原文网址:http://www.cnblogs.com/biglucky/p/4059586.html TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1 ...
- Linux I2C设备驱动
i2c设备:ts.camera.audio.gsensor.e2prom I2C基本协议: 写:开始 -> 设备地址 -> 写标志 -> 应答 -> 内部地址 -> 应答 ...
- i2c设备驱动注册
Linux I2C设备驱动编写(二) 原创 2014年03月16日 23:26:50 在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_driver.i2c ...
- Linux i2c子系统(一) _动手写一个i2c设备驱动
i2c总线是一种十分常见的板级总线,本文以linux3.14.0为参考, 讨论Linux中的i2c驱动模型并利用这个模型写一个mpu6050的驱动, 最后在应用层将mpu6050中的原始数据读取出来 ...
随机推荐
- nodejs 实现机制
最近在学习nodejs,作为一个从未学过javascript的程序员,把自己学习的过程贴出来,当做记录和总结吧. 1. nodejs的原理: nodejs完全是基于事件轮询机制的一个javascrip ...
- Java编写的C语言词法分析器
Java编写的C语言词法分析器 这是java编写的C语言词法分析器,我也是参考很多代码,然后核心代码整理起来,放在QQ空间和博客上,目的是互相学习借鉴,希望可以得到高手改进.这个词法分析器实现的功能有 ...
- linux shell 逻辑运算符
一.逻辑卷标 逻辑卷标 表示意思 1. 关于档案与目录的侦测逻辑卷标! -f 常用!侦测『档案』是否存在 eg: if [ -f filename ] -d 常用!侦测『目录』是否存在 -b 侦测是否 ...
- HTML5 File API
1.File API 一直以来,不能直接访问用户计算机中的文件都是web应用开发当中的一大障碍.File API的宗旨是为web开发人员提供一种安全的方式,以便在客户端访问用户计算机中的文件,并更好的 ...
- 玩转HTML5移动页面(优化篇)
原文:http://www.grycheng.com/?p=472 承接上文<玩转HTML5移动页面(动效篇)>,上次说的是让页面动起来的一些小技巧.而页面动起来的根基是功能可用的页面,因 ...
- 操作系统和Python的发展历程
一:操作系统的发展历史: 操作系统:什么是操作系统?我们首先想到的是电脑,,也就是所谓的Windows8,Windows7,或者XP系统和Windows10,当然也包括我们手机的安卓系统或者IPhon ...
- C# RichTextBox 获取当前显示部分的文字
int start = richTextBox1.GetCharIndexFromPosition(new Point(0, 0)); int end = richTextBox1.GetCharIn ...
- ubuntu 安装mysql及修改编码
643 netstat -tap | grep mysql 645 apt-get install mysql-server mysql-client 646 netstat -tap | ...
- [原博客] POJ 2484 A Funny Game
题目链接题意:有n个硬币排成一圈,两个人轮流操作,每次可以取走一个或者相邻的连个硬币(只算最开始相邻的,取之后才相邻的不算),问先手必胜还是必败. 这个题可以证明若n>=3,则先手必败.对称博弈 ...
- Table嵌套去掉子table的外边框
Table表格去掉子表格的边框 1. 父表格 <table align="center" style="border:none;cell-padding:0; ce ...