[转载]Linux的I2C驱动架构

最近因为工作需要涉及到了I2C 总线。虽然我过去用过I2c ,但看了 Linux kernel 后才发现,一个 layer 能被做到这样完善。

1.     Linux I2C 驱动 架构

Linux I2C 总线的驱动 分为两个部分,总线驱动 BUS )和设备驱动 DEVICE )。其中总线驱动 的职责,是为系统中每个I2C 总线增加相应的读写方法。但是总线驱动 本身并不会进行任何的通讯,它只是存在在那里,等待设备驱动 调用其函数。

 

设备驱动 则是与挂在I2C 总线上的具体的设备通讯的驱动 。通过I2C 总线驱动 提供的函数,设备驱动 可以忽略不同总线控制器的差异,不考虑其实现细节地与硬件设备通讯。

 

1.1 总线驱动

在系统开机时,首先装载的是I2C 总线驱动 。一个总线驱动 用于支持一条特定的I2C 总线的读写。一个总线驱动 通常需要两个模块,一个struct i2c _adapter 和一个struct i2c _algorithm 来描述:

static struct i2c

_adapter pb1550_board_adapter = {


  name:              "pb1550 adapter",


  id:                I2C

_HW_AU1550_PSC,


  algo:              NULL,


  algo_data:         &pb1550_i2c

_info,


  inc_use:           pb1550_inc_use,


  dec_use:           pb1550_dec_use,


  client_register:   pb1550_reg,


  client_unregister: pb1550_unreg,


  client_count:      0,


};


 

这个样例挂接了一个叫做“pb1550 adapter ”的驱动 。但这个模块并未提供读写函数,具体的读写方法由第二个模块,struct i2c _algorithm供。

 

static struct i2c _algorithm au1550_algo = {

.name         = "Au1550 algorithm",

.id      = I2C _ALGO_AU1550,

.master_xfer  = au1550_xfer,

.functionality     = au1550_func,

};

 

i2c _adap->algo = &au1550_algo;

   

这个样例给上述总线驱动 增加了读写“算法”。通常情况下每个I2C 总线驱动 都定义一个自己的读写算法,但鉴于有些总线使用相同的算法,因而可以共用同一套读写函数。本例中的驱动 定义了自己的读写算法模块,起名叫“Au1550 algorithm ”。

 

全部填妥后,通过调用:

i2c _add_adapter(i2c _adap);

 

将这两个模块注册到操作系统里,总线驱动 就算装上了。对于AMD au1550 ,这部分已经由AMD 提供了。

1.2 设备驱动

如前所述,总线驱动 只是提供了对一条总线的读写机制,本身并不会去做通信。通信是由I2C 设备驱动 来做的,设备驱动 透过I2C 总线同具体的设备进行通讯。一个设备驱动 有两个模块来描述,struct i2c _driverstruct i2c _client

 

当系统开机、I2C 总线驱动 装入完成后,就可以装入设备驱动 了。首先装入如下结构:

 

static struct i2c _driver driver = {

        .name           = "i2c TV tuner driver",

        .id             = I2C _DRIVERID_TUNER,

        .flags          = I2C _DF_NOTIFY,

        .attach_adapter = tuner_probe,

        .detach_client  = tuner_detach,

        .command        = tuner_command,

};

 

i2c _add_driver(&driver);

 

这个i2c _driver 一旦装入完成,其中的attach_adapter 函数就会被调用。在其中可以遍历系统中的每个i2c 总线驱动 ,探测想要访问的设备:

 

static int tuner_probe(struct i2c _adapter *adap)

{

return i2c _probe(adap, &addr_data, tuner_attach);

}

 

注意探测可能会找到多个设备,因而不仅一个I2C 总线可以挂多个不同类型的设备,一个设备驱动 也可以同时为挂在多个不同I2C 总线上的设备服务。

 

每当设备驱动 探测到了一个它能支持的设备,它就创建一个struct i2c _client 来标识这个设备:

new_client->addr = address;

new_client->adapter = adapter;

new_client->driver = &driver;

 

/* Tell the I2C layer a new client has arrived */

err = i2c _attach_client(new_client);

if (err)

    goto error;

 

可见,一个i2c _client 代表着位于adapter 总线上,地址为address ,使用driver驱动 的一个设备。它将总线驱动 与设备驱动 ,以及设备地址绑定在了一起。一个i2c _client 就代表着一个I2C 设备。

 

当得到I2C 设备后,就可以直接对此设备进行读写:

/*

 * The master routines are the ones normally used to transmit data to devices

 * on a bus (or read from them). Apart from two basic transfer functions to

 * transmit one message at a time, a more complex version can be used to

 * transmit an arbitrary number of messages without interruption.

 */

extern int i2c _master_send(struct i2c _client *,const char* ,int);

extern int i2c _master_recv(struct i2c _client *,char* ,int);

 

与通常意义上的读写函数一样,这两个函数对i2c _client 指针指定的设备,读写intchar 。返回值为读写的字节数。对于我们现有的SLIC驱动 ,只要将最后要往总线上进行读写的数据引出传输到这两个函数中,移植工作就算完成了,我们将得到一个Linux 版的I2C 设备驱动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值