`
yidongkaifa
  • 浏览: 4059589 次
文章分类
社区版块
存档分类
最新评论

Linux设备驱动子系统第一弹 - I2C

 
阅读更多

1. Overview

2. Data Structure

3. Adapter

4. I2C-core

5.Slave Device


1. Overview

1.1 Definition

  • I2CInter-Integrated Circuit
  • SMBUS System Management Bus, the I2C subset

1.2 Characteristics

  • The amount of data exchanged is small.
  • The required data transfer rate is low.

1.3 Speed

  • Fast speed 400 kbps
  • Full speed100 kbps

1.4 Topology

2 Data Structure

理解数据结构对理解整个驱动程序子系统是很重要的。I2C的主要有两大数据结构,struct i2c_client 和 struct i2c_adapter。

2.1 i2c_client

struct i2c_client {
unsigned short flags;/* div., see below*/
unsigned short addr;/* chip address */
char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter;/* the adapter we sit on*/
struct i2c_driver *driver;/* and our access routines*/
struct device dev;/* the device structure*/
int irq;/* irq issued by device (or -1) */
char driver_name[KOBJ_NAME_LEN];
struct list_head list;/* DEPRECATED */
struct completion released;
};

struct i2c_client代表一个挂载到i2c总线上的i2c从设备,该设备所需要的数据结构,其中包括

  • 该i2c从设备所依附的i2c主设备 struct i2c_adapter *adapter
  • 该i2c从设备的驱动程序struct i2c_driver *driver
  • 作为i2c从设备所通用的成员变量,比如addr, name等
  • 该i2c从设备驱动所特有的数据,依附于dev->driver_data下

2.2 i2c_adapter

struct i2c_adapter {
struct module *owner;
unsigned int id;
unsigned int class;
const struct i2c_algorithm *algo; /* the algorithm to access the bus */
void *algo_data;

... ...

};
struct i2c_adapter代表主芯片所支持的一个i2c主设备,该设备所需要的数据结构,

其中,struct i2c_algorithm *algo是该i2c主设备传输数据的一种算法,或者说是在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, char read_write,
u8 command, int size, union i2c_smbus_data * data);

u32 (*functionality) (struct i2c_adapter *);
};

接下来,要实现整个i2c子系统的驱动,便围绕这两个数据结构展开,其主要步骤可总结为以下三步,

  • 实现i2c主设备驱动 (drivers/i2c/bus/*)
  • 注册i2c从设备的i2c_client(drivers/i2c/i2c-core)
  • 实现i2c从设备驱动

3 Adapter

内核目录drivers/i2c下有两个文件夹,algorithm和bus,其中bus存放i2c主设备的驱动,主设备驱动完成两大任务,

  • 提供该i2c主设备与从设备间完成数据通信的能力
  • 完成该i2c_adapter和所有已知的i2c_client的注册

以i2c-pxa.c为例,

/* drivers/i2c/bus/i2c-pxa.c */

static int __init i2c_adap_pxa_init(void)
{
return platform_driver_register(&i2c_pxa_driver);
}

static struct platform_driver i2c_pxa_driver = {
.probe= i2c_pxa_probe,
... ...
.id_table= i2c_pxa_id_table,
};

static int i2c_pxa_probe(struct platform_device *dev)
{
struct pxa_i2c *i2c;
i2c->adap.algo = i2c_pxa_algorithm; // 提供该i2c主设备与从设备间完成数据通信的能力

i2c_add_numbered_adapter(&i2c->adap); // 调用i2c-core.c中的接口函数,完成该i2c_adapter和i2c_client的注册

... ...
}

static const struct i2c_algorithm i2c_pxa_algorithm = {
.master_xfer= i2c_pxa_xfer, //根据pxa具体芯片的要求,完成i2c数据传输
.functionality= i2c_pxa_functionality,
};

4 I2C-core

内核目录drivers/i2c下的i2c-core.c,顾名思义,是内核为I2C提供的统一系统接口。

看看i2c_add_numbered_adapter做了些什么,

int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
... ...
status = i2c_register_adapter(adap);
return status;
}

static int i2c_register_adapter(struct i2c_adapter *adap)
{
... ...

device_register(&adap->dev); //完成I2C主设备adapter的注册,即注册object和发送uevent等

i2c_scan_static_board_info(adap);

... ...
}
i2c_scan_static_board_info(adap),此函数为整个I2C子系统的核心,它会去遍历一个由I2C从设备组成的双向循环链表,并完成所有I2C从设备的i2c_client的注册,具体过程如下,

static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
struct i2c_devinfo*devinfo; //已经建立好了的I2C从设备链表


list_for_each_entry(devinfo, &__i2c_board_list, list) {
i2c_new_device(adapter,&devinfo->board_info);
... ...
}
}

struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_infoconst *info)
{
... ...
i2c_attach_client(client);
... ...

}
int i2c_attach_client(struct i2c_client *client)
{
... ...
device_register(&client->dev); //完成I2C从设备client的注册
... ...
}

那么,这个I2C从设备组成的双向循环链表,是什么时候通过什么方式建立起来的呢?

以某重力感应设备为例,

/* /arch/arm/mach-pxa/starwood_p1.c */

static void __init saar_init(void)

{

... ...

i2c_register_board_info(0, ARRAY_AND_SIZE(saar_i2c_bma220_info));

... ...

}

static struct i2c_board_info saar_i2c_bma220_info[] = {
{
.driver_name= "bma220",
.addr= 0x0B,
.irq= IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO15)),
},
};

/* drivers/i2c/i2c-boardinfo.c */

int __init i2c_register_board_info(int busnum, structi2c_board_info const *info, unsigned len)
{

... ...

struct i2c_devinfo*devinfo;
devinfo->board_info = *info;
list_add_tail(&devinfo->list, &__i2c_board_list); //将I2C从设备加入该链表中
... ...
}

所以,在系统初始化的过程中,我们可以通过 i2c_register_board_info,将所需要的I2C从设备加入一个名为__i2c_board_list双向循环链表,系统在成功加载I2C主设备adapt后,就会对这张链表里所有I2C从设备逐一地完成i2c_client的注册。

5 Slave Driver

如果说硬件方面,I2C主设备已经集成在主芯片内,软件方面,linux也为我们提供了相应的驱动程序,位于drivers/i2c/bus下,那么接下来I2C从设备驱动就变得容易得多。既然系统加载I2C主设备驱动时已经注册了i2c_adapter和i2c_client,那么I2C从设备主要完成三大任务,

  • 系统初始化时添加以i2c_board_info为结构的I2C从设备的信息
  • 在I2C从设备驱动程序里使用i2c_adapter里所提供的算法,即实现I2C通信。
  • 将I2C从设备的特有数据结构挂在到i2c_client.dev->driver_data下。

以重力感应装置为例,

static int __init BMA220_init(void)
{
return i2c_add_driver(&bma220_driver);
}

static struct i2c_driver bma220_driver = {
.driver = {
.owner= THIS_MODULE,
.name= "bma220",
},
.class= I2C_CLASS_HWMON,
.probe= bma220_probe,
.remove= bma220_remove,
};

static int bma220_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct bma220_data *data;
i2c_check_functionality(client->adapter, I2C_FUNC_I2C)

i2c_smbus_read_word_data(client, 0x00); // i2c-core提供的接口,利用i2c_adapter的算法实现I2C通信
i2c_set_clientdata(bma220_client, data); // 将设备的数据结构挂到i2c_client.dev->driver_data下
misc_register(&bma_device);
request_irq(client->irq, bma220_irq_handler, IRQF_TRIGGER_RISING, "bma220", &data->bma220);
bma220_set_en_tt_xyz(0);
bma220_reset_int();

... ...
}

转载自:http://blog.csdn.net/qianjin0703/article/details/5894869


分享到:
评论

相关推荐

    Linux操作系统基础教程

    第一讲 Linux基础...........................................................................................................................2 一.什么是Linux?............................................

    入门学习Linux常用必会60个命令实例详解doc/txt

    举例而言,如要挂载下列5个设备,其执行指令可能如下 (假设都是Linux的ext2系统,如果是Windows XX请将ext2改成vfat): 软盘 ===>mount -t ext2 /dev/fd0 /mnt/floppy cdrom ===>mount -t iso9660 /dev/hdc /mnt/...

    vc++ 开发实例源码包

    请求的长度在第一个INT中指定. 2) 每个服务器通常会向多种客户提供服务, 例如, TS要同时向CP, NP提供服务, CP要向NP和其他CP提供服务, 同时还是其他CP, TS, SP的客户. 3) 每个服务器为客户服务时, 通常是长期的, 会...

    网管教程 从入门到精通软件篇.txt

    如果不指定 device_name,新的主引导记录将被写入引导设备,即装载主系统的驱动器。 如果系统检测到无效或非标准分区表标记,将提示用户是否继续执行该命令。除非您访问驱动器有问题,否则不要继续进行。向系统分区...

    JAVA上百实例源码以及开源项目

     当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。  QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...

    JAVA上百实例源码以及开源项目源代码

    Java编写的山寨QQ,多人聊天+用户在线 21个目标文件 摘要:JAVA源码,媒体网络,山寨QQ,Java聊天程序 Java编写的山寨QQ,多人聊天+用户在线,程序分服务端和客户端,典型C/S结构, 当用户发送第一次请求的时候,验证...

    java开源包1

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包10

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包2

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包11

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包3

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包6

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包5

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包4

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包8

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包7

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包9

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    java开源包101

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

    Java资源包01

    LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的...

Global site tag (gtag.js) - Google Analytics