www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀]作者:劉洪濤,華清遠見嵌入式學(xué)院講師。四、在內(nèi)核里寫i2c設(shè)備驅(qū)動的兩種方式前文介紹了利用/dev/i2c-0在應(yīng)用層完成對i2c設(shè)備的操作,但很多時候我們還是習(xí)慣為i2c設(shè)備在內(nèi)

作者:劉洪濤,華清遠見嵌入式學(xué)院講師。

四、在內(nèi)核里寫i2c設(shè)備驅(qū)動的兩種方式

前文介紹了利用/dev/i2c-0在應(yīng)用層完成對i2c設(shè)備的操作,但很多時候我們還是習(xí)慣為i2c設(shè)備在內(nèi)核層編寫驅(qū)動程序。目前內(nèi)核支持兩種編寫i2c驅(qū)動程序的方式。下面分別介紹這兩種方式的實現(xiàn)。這里分別稱這兩種方式為“Adapter方式(LEGACY)”和“Probe方式(new style)”。

(1) Adapter方式(LEGACY)

(下面的實例代碼是在2.6.27內(nèi)核的pca953x.c基礎(chǔ)上修改的,原始代碼采用的是本文將要討論的第2種方式,即Probe方式)

● 構(gòu)建i2c_driver

static struct i2c_driver pca953x_driver = {

.driver = {

.nAME= "pca953x", //名稱

},

.id= ID_PCA9555,//id號

.attach_adapter= pca953x_attach_adapter, //調(diào)用適配器連接設(shè)備

.detach_client= pca953x_detach_client,//讓設(shè)備脫離適配器

};

● 注冊i2c_driver

static int __init pca953x_init(void)

{

return i2c_add_driver(&pca953x_driver);

}

module_init(pca953x_init);

● attach_adapter動作

執(zhí)行i2c_add_driver(&pca953x_driver)后會,如果內(nèi)核中已經(jīng)注冊了i2c適配器,則順序調(diào)用這些適配器來連接我們的i2c設(shè)備。此過程是通過調(diào)用i2c_driver中的attach_adapter方法完成的。具體實現(xiàn)形式如下:

static int pca953x_attach_adapter(struct i2c_adapter *adapter)

{

return i2c_probe(adapter, &addr_data, pca953x_detect);

/*

adapter:適配器

addr_data:地址信息

pca953x_detect:探測到設(shè)備后調(diào)用的函數(shù)

*/

}

地址信息addr_data是由下面代碼指定的。

/* Addresses to scan */

static unsigned short normal_i2c[] = {0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,I2C_CLIENT_END};

I2C_CLIENT_INSMOD;

注意:normal_i2c里的地址必須是你i2c芯片的地址。否則將無法正確探測到設(shè)備。而I2C_ CLIENT_INSMOD是一個宏,它會利用normal_i2c構(gòu)建addr_data。

● 構(gòu)建i2c_client,并注冊字符設(shè)備驅(qū)動

i2c_probe在探測到目標(biāo)設(shè)備后,后調(diào)用pca953x_detect,并把當(dāng)時的探測地址address作為參數(shù)傳入。

static int pca953x_detect(struct i2c_adapter *adapter, int address, int kind)

{

struct i2c_client *new_client;

struct pca953x_chip *chip; //設(shè)備結(jié)構(gòu)體

int err = 0,result;

dev_t pca953x_dev=MKDEV(pca953x_major,0);//構(gòu)建設(shè)備號,根據(jù)具體情況設(shè)定,這里我只考慮了normal_i2c中只有一個地址匹配的情況。

if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA| I2C_FUNC_SMBUS_WORD_DATA))//判定適配器能力

goto exit;

if (!(chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL))) {

err = -ENOMEM;

goto exit;

}

/****構(gòu)建i2c-client****/

chip->client=kzalloc(sizeof(struct i2c_client),GFP_KERNEL);

new_client = chip->client;

i2c_set_clientdata(new_client, chip);

new_client->addr = address;

new_client->adapter = adapter;

new_client->driver = &pca953x_driver;

new_client->flags = 0;

strlcpy(new_client->name, "pca953x", I2C_NAME_SIZE);

if ((err = i2c_attach_client(new_client)))//注冊i2c_client

goto exit_kfree;

if (err)

goto exit_detach;

if(pca953x_major)

{

result=register_chrdev_region(pca953x_dev,1,"pca953x");

}

else{

result=alloc_chrdev_region(&pca953x_dev,0,1,"pca953x");

pca953x_major=MAJOR(pca953x_dev);

}

if (result < 0) {

printk(KERN_NOTICE "Unable to get pca953x region, error %d\n", result);

return result;

}

pca953x_setup_cdev(chip,0); //注冊字符設(shè)備,此處不詳解

return 0;

exit_detach:

i2c_detach_client(new_client);

exit_kfree:

kfree(chip);

exit:

return err;

}

i2c_check_functionality用來判定設(shè)配器的能力,這一點非常重要。你也可以直接查看對應(yīng)設(shè)配器的能力,如

static const struct i2c_algorithm smbus_algorithm = {

.smbus_xfer= i801_access,

.functionality= i801_func,

};

static u32 i801_func(struct i2c_adapter *adapter)

{

return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |

I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |

I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK

| (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);

}

● 字符驅(qū)動的具體實現(xiàn)

struct file_operations pca953x_fops = {

.owner = THIS_MODULE,

.ioctl= pca953x_ioctl,

.open= pca953x_open,

.release =pca953x_release,

};

字符設(shè)備驅(qū)動本身沒有什么好說的,這里主要想說一下,如何在驅(qū)動中調(diào)用i2c設(shè)配器幫我們完成數(shù)據(jù)傳輸。

目前設(shè)配器主要支持兩種傳輸方法:smbus_xfer和master_xfer。一般來說,如果設(shè)配器支持了master_xfer那么它也可以模擬支持smbus的傳輸。但如果只實現(xiàn)smbus_xfer,則不支持一些i2c的傳輸。

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);

master_xfer中的參數(shù)設(shè)置,和前面的用戶空間編程一致?,F(xiàn)在只是要在驅(qū)動中構(gòu)建相關(guān)的參數(shù)然后調(diào)用i2c_transfer來完成傳輸既可。

int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)

smbus_xfer中的參數(shù)設(shè)置及調(diào)用方法如下:

static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)

{

int ret;

ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);

if (ret < 0) {

dev_err(&chip->client->dev, "failed writing register\n");

return -EIO;

}

return 0;

}

上面函數(shù)完成向芯片的地址為reg的寄存器寫一個16bit的數(shù)據(jù)。i2c_smbus_write_word_data的實現(xiàn)如下:

s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)

{

union i2c_smbus_data data;

data.word = value;

return i2c_smbus_xfer(client->adapter,client->addr,client->flags,

I2C_SMBUS_WRITE,command,

I2C_SMBUS_WORD_DATA,&data);

}

從中可以看出smbus傳輸一個16位數(shù)據(jù)的方法。其它操作如:字符寫、字符讀、字讀、塊操作等,可以參考內(nèi)核的i2c-core.c中提供的方法。

● 注銷i2c_driver

static void __exit pca953x_exit(void)

{

i2c_del_driver(&pca953x_driver);

}

module_exit(pca953x_exit);

● detach_client動作

順序調(diào)用內(nèi)核中注冊的適配器來斷開我們注冊過的i2c設(shè)備。此過程通過調(diào)用i2c_driver中的attach_adapter方法完成的。具體實現(xiàn)形式如下:

static int pca953x_detach_client(struct i2c_client *client)

{

int err;

struct pca953x_chip *data;

if ((err = i2c_detach_client(client)))//斷開i2c_client

return err;

data=i2c_get_clientdata(client);

cdev_del(&(data->cdev));

unregister_chrdev_region(MKDEV(pca953x_major, 0), 1);

kfree(data->client);

kfree(data);

return 0;

}

(2) Probe方式(new style)

● 構(gòu)建i2c_driver

和LEGACY方式一樣,也需要構(gòu)建i2c_driver,但是內(nèi)容有所不同。

static struct i2c_driver pca953x_driver = {

.driver = {

.name= "pca953x",

},

.probe= pca953x_probe, //當(dāng)有i2c_client和i2c_driver匹配時調(diào)用

.remove= pca953x_remove,//注銷時調(diào)用

.id_table= pca953x_id,//匹配規(guī)則

};

● 注冊i2c_driver

static int __init pca953x_init(void)

{

return i2c_add_driver(&pca953x_driver);

}

module_init(pca953x_init);

在注冊i2c_driver的過程中,是將driver注冊到了i2c_bus_type的總線上。此總線的匹配規(guī)則是:

static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,

const struct i2c_client *client)

{

while (id->name[0]) {

if (strcmp(client->name, id->name) == 0)

return id;

id++;

}

return NULL;

}

可以看出是利用i2c_client的名稱和id_table中的名稱做匹配的。本驅(qū)動中的id_table為

static const struct i2c_device_id pca953x_id[] = {

{ "pca9534", 8, },

{ "pca9535", 16, },

{ "pca9536", 4, },

{ "pca9537", 4, },

{ "pca9538", 8, },

{ "pca9539", 16, },

{ "pca9554", 8, },

{ "pca9555", 16, },

{ "pca9557", 8, },

{ "max7310", 8, },

{ }

};

看到現(xiàn)在我們應(yīng)該會有這樣的疑問,在Adapter模式中,i2c_client是我們自己構(gòu)造出來的,而現(xiàn)在的i2c_client是從哪來的呢?看看下面的解釋

● 注冊i2c_bOArd_info

對于Probe模式,通常在平臺代碼中要完成i2c_board_info的注冊。方法如下:

static struct i2c_board_info __initdata test_i2c_devices[] = {

{

I2C_BOARD_INFO("pca9555", 0x27),//pca9555為芯片名稱,0x27為芯片地址

.platform_data = &pca9555_data,

}, {

I2C_BOARD_INFO("mt9v022", 0x48),

.platform_data = &iclink[0], /* With extender */

}, {

I2C_BOARD_INFO("mt9m001", 0x5d),

.platform_data = &iclink[0], /* With extender */

},

};

i2c_register_board_info(0, test_i2c_devices,ARRAY_SIZE(test_i2c_devices)); //注冊

i2c_client就是在注冊過程中構(gòu)建的。但有一點需要注意的是i2c_register_board_info并沒有EXPORT_SYMBOL給模塊使用。

● 字符驅(qū)動注冊

在Probe方式下,添加字符驅(qū)動的位置在pca953x_probe中。

static int __devinit pca953x_probe(struct i2c_client *client,const struct i2c_device_id *id)

{

……

/****字符設(shè)備驅(qū)動注冊位置****/

……

return 0;

}

● 注銷i2c_driver

static void __exit pca953x_exit(void)

{

i2c_del_driver(&pca953x_driver);

}

module_exit(pca953x_exit);

● 注銷字符設(shè)備驅(qū)動

在Probe方式下,注銷字符驅(qū)動的位置在pca953x_remove中。

static int __devinit pca953x_remove (struct i2c_client *client)

{

……

/****字符設(shè)備驅(qū)動注銷的位置****/

……

return 0;

}

● I2C設(shè)備的數(shù)據(jù)交互方法(即:調(diào)用適配器操作設(shè)備的方法)和Adapter方式下相同。

“本文由華清遠見http://www.embedu.org/index.htm提供”



華清遠見

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉