小米手机linux驱动,Linux设备驱动子系统 - I2C

1. Overview

2. Data Structure

3. Adapter

4. I2C-core

5. Slave Device

1. Overview

1.1 Definition

I2C           Inter-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 speed      100 kbps

1.4 Topology

uid-31356549-id-5746176.html

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从设备驱动

3Adapter

内核目录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, structi2c_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, struct i2c_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();

... ...

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值