本文转载自:http://blog.csdn.net/airk000/article/details/21345457

在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设备驱动编写(一)【转】的更多相关文章

  1. Linux I2C设备驱动编写(一)

    在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即I2C适配器 I2C driver 某个I2C设备的设备驱动,可以以driver理解. I2C client 某个I2C ...

  2. 【转】Linux I2C设备驱动编写(一)

    原文网址:http://www.cnblogs.com/biglucky/p/4059576.html 在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即I2C适配器 I ...

  3. Linux I2C设备驱动编写(二)

    在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_driver.i2c_client.三者的关系也在上一节进行了描述.应该已经算是对Linux I2C子系统有了初步 ...

  4. 【转】Linux I2C设备驱动编写(二)

    原文网址:http://www.cnblogs.com/biglucky/p/4059582.html 在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_drive ...

  5. Linux I2C设备驱动编写(三)-实例分析AM3359

    TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1版本规格 支持标准模式(100K bits/s)和快速模式(400K bits/s) 多路接收.发送模式 ...

  6. 【转】Linux I2C设备驱动编写(三)-实例分析AM3359

    原文网址:http://www.cnblogs.com/biglucky/p/4059586.html TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1 ...

  7. Linux I2C设备驱动

    i2c设备:ts.camera.audio.gsensor.e2prom I2C基本协议: 写:开始 -> 设备地址 -> 写标志 -> 应答 -> 内部地址 -> 应答 ...

  8. i2c设备驱动注册

      Linux I2C设备驱动编写(二) 原创 2014年03月16日 23:26:50   在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_driver.i2c ...

  9. Linux i2c子系统(一) _动手写一个i2c设备驱动

    i2c总线是一种十分常见的板级总线,本文以linux3.14.0为参考, 讨论Linux中的i2c驱动模型并利用这个模型写一个mpu6050的驱动, 最后在应用层将mpu6050中的原始数据读取出来 ...

随机推荐

  1. Python自学-2-python解释器

    写python源文件,以.py为后缀名 用python解释器去执行.py文件 python解释器 CPython:官方版本,由C语言开发的,下载默认就是这个,使用最广的解释器.   用>> ...

  2. 'dict' object is not callable

    今天学py的map函数时,由于在上面定义了一个dict类型的变量(取的名是map),所以编译后报了这么一个错,哎,以后学py命名要小心了

  3. Vue.js 计算属性(computed)

    Vue.js 计算属性(computed) 如果在模板中使用一些复杂的表达式,会让模板显得过于繁重,且后期难以维护.对此,vue.js 提供了计算属性(computed),你可以把这些复杂的表达式写到 ...

  4. 省市区json结构

    [ { "label": "北京市", "value": "北京市", "children": [ ...

  5. 常用的HTTP测试工具谷歌浏览器插件汇总

    网页的开发和测试时最常见的测试就是HTTP测试,作为曾经的测试人员在这方面还是略知一二的.其实做网页测试工作是非常繁琐的时期,有时候甚至是无聊重复的,如果没有网页测试工具的帮助的话,测试人员会越做越怀 ...

  6. PAT 1141 PAT Ranking of Institutions

    After each PAT, the PAT Center will announce the ranking of institutions based on their students' pe ...

  7. PAT 1122 Hamiltonian Cycle

    The "Hamilton cycle problem" is to find a simple cycle that contains every vertex in a gra ...

  8. 初次使用Let's encrypt

    wget --no-check-certificate -O shadowsocks.sh https://raw.githubusercontent.com/teddysun/shadowsocks ...

  9. 生成随机数验证码的工具类(from韩顺平)

    生成随机数验证码的工具类 package com.cx; //生成随机数的图片 import java.awt.Color; import java.awt.Font; import java.awt ...

  10. [bzoj1572][Usaco2009 Open]工作安排Job_贪心_堆

    工作安排 Job bzoj-1572 Usaco-2009 Open 题目大意:题目链接. 注释:略. 想法: 我们将任务按照截止时间排序,枚举任务的同时顺便记录出已经做了多少任务(当前时间). 对于 ...