歡迎您光臨本站 註冊首頁

Linux的操作系統I2C驅動架構解說

←手機掃碼閱讀     火星人 @ 2014-03-26 , reply:0

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_driver和struct 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指針指定的設備,讀寫int個char。返回值為讀寫的位元組數。對於我們現有的SLIC的驅動,只要將最後要往匯流排上進行讀寫的數據引出傳輸到這兩個函數中,移植工作就算完成了,我們將得到一個Linux版的I2C設備驅動。

[火星人 ] Linux的操作系統I2C驅動架構解說已經有572次圍觀

http://coctec.com/docs/linux/show-post-188066.html