Linux I2C驅(qū)動(dòng)注冊(cè)詳解
注冊(cè)接口
#define i2c_add_driver(driver) \ i2c_register_driver(THIS_MODULE, driver) int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
注冊(cè)的結(jié)構(gòu)體是struct i2c_driver,主要填充name、probe和id_table字段,其中name是驅(qū)動(dòng)名稱,到時(shí)會(huì)在/sys/bus/i2c/drivers顯示這個(gè)驅(qū)動(dòng)名稱,probe會(huì)在I2C設(shè)備匹配后調(diào)用,不是發(fā)現(xiàn)I2C設(shè)備,即便實(shí)際上這個(gè)設(shè)備不在,但是代碼里注冊(cè)了這個(gè)設(shè)備,或者設(shè)備樹(shù)里配置了這個(gè)設(shè)備,就會(huì)被調(diào)用。
driver.of_match_table和 id_table兩個(gè)成員列出的是驅(qū)動(dòng)程序所能支持的所有設(shè)備,其中driver.of_match_table里的設(shè)備,是跟設(shè)備樹(shù)匹配的,id_table是跟靜態(tài)注冊(cè)是調(diào)用的struct i2c_board_info里的name做比較的。
示例代碼
驅(qū)動(dòng)注冊(cè):
static int __devinit zsl_i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct property *pp = NULL; uint8_t buf[4]; struct i2c_msg msgs[2] = {{0}, {0}}; int len = sizeof(msgs) / sizeof(msgs[0]); printk(KERN_INFO "%s: %x\n",__func__,client->addr); pp = of_find_property(client->dev.of_node, "testdata", NULL); if (pp) printk(KERN_INFO "%s: %d:%s \n",__func__,pp->length,(char *)pp->value); dump_stack(); if (client->adapter) { buf[0] = 0; buf[1] = 4; buf[2] = 0; buf[3] = 0; memset(msgs,0,sizeof(struct i2c_msg)*2); msgs[0].addr = client->addr; msgs[0].flags = 0x0; msgs[0].len = 2; msgs[0].buf = buf; msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD; msgs[1].len = 4; msgs[1].buf = buf; if (i2c_transfer(client->adapter, msgs, len) == len) printk(KERN_INFO "zsl i2c_transfer r: %d:%x %x %x %x\n",len,buf[0],buf[1],buf[2],buf[3]); buf[0] = 0; buf[1] = 4; buf[2] = 7; buf[3] = 8; memset(msgs,0,sizeof(struct i2c_msg)*2); msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = 4; msgs[0].buf = buf; if (i2c_transfer(client->adapter, msgs, 1) == 1) printk(KERN_INFO "zsl i2c_transfer w: %d:%x %x %x %x\n",1,buf[0],buf[1],buf[2],buf[3]); buf[0] = 0; buf[1] = 4; buf[2] = 0; buf[3] = 0; memset(msgs,0,sizeof(struct i2c_msg)*2); msgs[0].addr = client->addr; msgs[0].flags = 0x0; msgs[0].len = 2; msgs[0].buf = buf; msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD; msgs[1].len = 4; msgs[1].buf = buf; msleep(100); len = i2c_transfer(client->adapter, msgs, len); if (2 == len) printk(KERN_INFO "zsl i2c_transfer r: %d:%x %x %x %x\n",len,buf[0],buf[1],buf[2],buf[3]); } return 0; } static void __devexit zsl_i2c_drv_remove(struct i2c_client *client) { printk(KERN_INFO "%s: \n",__func__); } static const struct i2c_device_id zsl_dev_id_table[] = { { "zsl_i2c_dev", 0 }, {} };//這里的名字很重要,驅(qū)動(dòng)第一種匹配設(shè)備的方式要用到 static const struct of_device_id zsl_of_match_ids[] = { { .compatible = "i2c_name,zsl", .data = NULL }, { /* END OF LIST */ } //最后一項(xiàng)為空,用于判斷數(shù)組遍歷完成 }; static struct i2c_driver zsl_i2c_driver = { .driver = { .name = "zsl_i2c", .owner = THIS_MODULE, .of_match_table = zsl_of_match_ids,//設(shè)備樹(shù)匹配用 }, .probe = zsl_i2c_drv_probe, .remove = __devexit_p(zsl_i2c_drv_remove), .id_table = zsl_dev_id_table, //設(shè)備樹(shù)不需要,i2c_register_board_info匹配使用 }; void zsl_i2c_drv_init(void) { i2c_add_driver(&zsl_i2c_driver); }
靜態(tài)設(shè)備注冊(cè)
static struct i2c_board_info zsl_i2c_dev = { I2C_BOARD_INFO("zsl_i2c_dev", 0x50),//這個(gè)名字很重要,用于匹配 I2C 驅(qū)動(dòng) }; static struct i2c_client *zsl_i2c_client; void zsl_i2c_dev_init(void) { i2c_register_board_info(4, &zsl_i2c_dev, 1); }
設(shè)備樹(shù)注冊(cè)
&i2c4 { zsli2c0: zsli2c@50 { compatible = "i2c_name,zsl"; status = "okay"; testdata = "asdfg"; reg = <0x50>; }; };
運(yùn)行后probe就會(huì)被調(diào)用,無(wú)論配的是什么地址,0x50設(shè)備存在,0x60設(shè)備不存在,probe都能被調(diào)用,但是0x60的讀不到數(shù)據(jù)。
調(diào)用關(guān)系
probe里的堆棧打印如下:
從芯片廠家的I2C驅(qū)動(dòng)初始化接口rk3x_i2c_driver_init開(kāi)始,使用platform_driver_register接口注冊(cè)rk3x_i2c_driver,當(dāng)設(shè)備樹(shù)里有對(duì)應(yīng)的I2C總線時(shí),就會(huì)注冊(cè)I2C設(shè)備,匹配后調(diào)用這里的probe接口rk3x_i2c_probe。
rk3x_i2c_probe里會(huì)初始化 Rockchip I2C控制器,調(diào)用 i2c_register_adapter將 I2C 適配器注冊(cè)到內(nèi)核,進(jìn)而調(diào)用of_i2c_register_devices 掃描設(shè)備樹(shù),調(diào)用i2c_new_client_device創(chuàng)建配置的I2C設(shè)備。
i2c_new_client_device里會(huì)創(chuàng)建struct i2c_client并調(diào)用device_register注冊(cè)到內(nèi)核,觸發(fā) device_add,內(nèi)核會(huì)嘗試匹配驅(qū)動(dòng)(通過(guò) compatible 字符串或者name)。如果匹配成功,調(diào)用 i2c_device_probe到probe接口的zsl_i2c_drv_probe。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Linux中如何通過(guò)端口號(hào)查找進(jìn)程號(hào)
這篇文章主要介紹了Linux中如何通過(guò)端口號(hào)查找進(jìn)程號(hào)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05Apache 二級(jí)域名實(shí)現(xiàn)方法介紹
首先,你的擁有一個(gè)有泛域名解析的頂級(jí)域名,例如:domain.com2009-05-05CentOS 7.2配置Apache服務(wù)httpd(上)
這篇文章主要為大家詳細(xì)介紹了CentOS 7.2配置Apache服務(wù) httpd上篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11linux查找大文件指定內(nèi)容的實(shí)現(xiàn)方法
今天小編就為大家分享一篇linux查找大文件指定內(nèi)容的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07Centos7升級(jí)glibc導(dǎo)致系統(tǒng)異常(無(wú)法開(kāi)機(jī))解決方法
大家好,本篇文章主要講的是Centos7升級(jí)glibc導(dǎo)致系統(tǒng)異常(無(wú)法開(kāi)機(jī))解決方法,感興趣的同學(xué)趕快來(lái)看看吧,希望對(duì)你有幫助2021-11-11linux線程間的同步與互斥知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理的是關(guān)于linux線程間的同步與互斥的相關(guān)知識(shí)點(diǎn),有興趣的朋友們學(xué)習(xí)下。2019-11-11Linux PXE高效批量網(wǎng)絡(luò)裝機(jī)過(guò)程
PXE(預(yù)啟動(dòng)執(zhí)行環(huán)境)是一種網(wǎng)絡(luò)引導(dǎo)技術(shù),允許從遠(yuǎn)程服務(wù)器通過(guò)網(wǎng)絡(luò)下載引導(dǎo)鏡像來(lái)安裝操作系統(tǒng),本文介紹了PXE的優(yōu)點(diǎn)如規(guī)模化、自動(dòng)化和遠(yuǎn)程實(shí)現(xiàn),以及搭建PXE服務(wù)器的基本步驟,包括安裝和配置TFTP、DHCP服務(wù)2024-09-09吸引發(fā)燒友的視聽(tīng)Linux發(fā)行版
今天小編就為大家分享一篇關(guān)于吸引發(fā)燒友的Linux發(fā)行版,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-09-09