Linux內(nèi)核將 I2C 驅(qū)動(dòng)分為兩部分:
I2C 總線(xiàn)驅(qū)動(dòng), I2C總線(xiàn)驅(qū)動(dòng)就是SOC的 I2C控制器驅(qū)動(dòng),也叫做 I2C適配器驅(qū)動(dòng)。
I2C 設(shè)備驅(qū)動(dòng), I2C設(shè)備驅(qū)動(dòng)就是針對(duì)具體的 I2C設(shè)備而編寫(xiě)的驅(qū)動(dòng)。
I2C框架下的幾個(gè)重要成員
1. I2C總線(xiàn)
I2C總線(xiàn)結(jié)構(gòu)體在driversi2ci2c-core.c中定義如下:
structbus_typei2c_bus_type={ .name="i2c", .match=i2c_device_match, .probe=i2c_device_probe, .remove=i2c_device_remove, .shutdown=i2c_device_shutdown, };
I2C總線(xiàn)對(duì)應(yīng)著/bus下的一條總線(xiàn),這個(gè)i2c總線(xiàn)結(jié)構(gòu)體管理著i2c設(shè)備與I2C驅(qū)動(dòng)的匹配,刪除等操作,I2C總線(xiàn)會(huì)調(diào)用i2c_device_match函數(shù)看I2C設(shè)備和I2C驅(qū)動(dòng)是否匹配,如果匹配就調(diào)用i2c_device_probe函數(shù),進(jìn)而調(diào)用I2C驅(qū)動(dòng)的probe函數(shù)。
形如:
i2c_device_match會(huì)管理I2C設(shè)備和I2C總線(xiàn)匹配規(guī)則,這將和如何編寫(xiě)I2C驅(qū)動(dòng)程序息息相關(guān)。
2. I2C驅(qū)動(dòng)
i2c_driver 類(lèi)似 platform_driver,是我們編寫(xiě) I2C 設(shè)備驅(qū)動(dòng)重點(diǎn)要處理的內(nèi)容, i2c_driver 結(jié)構(gòu)體定義在 include/linux/i2c.h 文件中,內(nèi)容如下:
structi2c_driver{ unsignedintclass; /*Notifiesthedriverthatanewbushasappeared.Youshouldavoid *usingthis,itwillberemovedinanearfuture. */ int(*attach_adapter)(structi2c_adapter*)__deprecated; /*Standarddrivermodelinterfaces*/ int(*probe)(structi2c_client*,conststructi2c_device_id*); int(*remove)(structi2c_client*); /*drivermodelinterfacesthatdon'trelatetoenumeration*/ void(*shutdown)(structi2c_client*); /*Alertcallback,forexamplefortheSMBusalertprotocol. *Theformatandmeaningofthedatavaluedependsontheprotocol. *FortheSMBusalertprotocol,thereisasinglebitofdatapassed *asthealertresponse'slowbit("eventflag"). */ void(*alert)(structi2c_client*,unsignedintdata); /*aioctllikecommandthatcanbeusedtoperformspecificfunctions *withthedevice. */ int(*command)(structi2c_client*client,unsignedintcmd,void*arg); structdevice_driverdriver; conststructi2c_device_id*id_table; /*Devicedetectioncallbackforautomaticdevicecreation*/ int(*detect)(structi2c_client*,structi2c_board_info*); constunsignedshort*address_list; structlist_headclients; };
重點(diǎn)成員如下:
int(*probe)(structi2c_client*,conststructi2c_device_id*)
當(dāng) I2C設(shè)備和驅(qū)動(dòng)匹配成功以后 probe函數(shù)就會(huì)執(zhí)行。
structdevice_driverdriverdevice_driver
驅(qū)動(dòng)結(jié)構(gòu)體,如果使用設(shè)備樹(shù)的話(huà),需要設(shè)置device_driver的of_match_table成員變量,也就是驅(qū)動(dòng)的兼容(compatible)屬性。
conststructi2c_device_id*id_table
id_table 是傳統(tǒng)的、未使用設(shè)備樹(shù)的設(shè)備匹配 ID表
3. I2C設(shè)備
I2C設(shè)備結(jié)構(gòu)體i2c_client 結(jié)構(gòu)體定義在 include/linux/i2c.h 文件中,內(nèi)容如下:
structi2c_client{ unsignedshortflags;/*div.,seebelow*/ unsignedshortaddr;/*chipaddress-NOTE:7bit*/ /*addressesarestoredinthe_LOWER_7bits*/ charname[I2C_NAME_SIZE]; structi2c_adapter*adapter;/*theadapterwesiton*/ structdevicedev;/*thedevicestructure*/ intirq;/*irqissuedbydevice*/ structlist_headdetected; #ifIS_ENABLED(CONFIG_I2C_SLAVE) i2c_slave_cb_tslave_cb;/*callbackforslavemode*/ #endif };
重點(diǎn)成員如下:
flags:標(biāo)志
addr:芯片地址,7 位,存在低 7 位
flagsname[I2C_NAME_SIZE]:名字
adapter:對(duì)應(yīng)的 I2C 適配器
dev:設(shè)備結(jié)構(gòu)體
irq:中斷
一個(gè)設(shè)備對(duì)應(yīng)一個(gè) i2c_client,每檢測(cè)到一個(gè) I2C 設(shè)備就會(huì)給這個(gè) I2C 設(shè)備分配一個(gè)i2c_client。
4. I2C適配器
經(jīng)過(guò)上面的介紹,知道有I2C驅(qū)動(dòng)和I2C設(shè)備,我們需要通過(guò)I2C驅(qū)動(dòng)去和I2C設(shè)備通訊,這其中就需要一個(gè)I2C設(shè)配器,I2C設(shè)配器對(duì)應(yīng)的就是SOC上的I2C控制器。
Linux 內(nèi)核將 SOC 的 I2C 適配器(控制器)抽象成 i2c_adapter, i2c_adapter 結(jié)構(gòu)體定義在 include/linux/i2c.h 文件中,結(jié)構(gòu)體內(nèi)容如下:
/* *i2c_adapteristhestructureusedtoidentifyaphysicali2cbusalong *withtheaccessalgorithmsnecessarytoaccessit. */ structi2c_adapter{ structmodule*owner; unsignedintclass;/*classestoallowprobingfor*/ conststructi2c_algorithm*algo;/*thealgorithmtoaccessthebus*//*總線(xiàn)訪問(wèn)算法*/ void*algo_data; /*datafieldsthatarevalidforalldevices*/ structrt_mutexbus_lock; inttimeout;/*injiffies*/ intretries; structdevicedev;/*theadapterdevice*/ intnr; charname[48]; structcompletiondev_released; structmutexuserspace_clients_lock; structlist_headuserspace_clients; structi2c_bus_recovery_info*bus_recovery_info; conststructi2c_adapter_quirks*quirks; };
重點(diǎn)成員如下:
conststructi2c_algorithm*algo
I2C 適配器與 IIC 設(shè)備進(jìn)行通信的方法。
i2c_algorithm 結(jié)構(gòu)體定義在 include/linux/i2c.h 文件中,內(nèi)容如下:
structi2c_algorithm{ /*Ifanadapteralgorithmcan'tdoI2C-levelaccess,setmaster_xfer toNULL.IfanadapteralgorithmcandoSMBusaccess,set smbus_xfer.IfsettoNULL,theSMBusprotocolissimulated usingcommonI2Cmessages*/ /*master_xfershouldreturnthenumberofmessagessuccessfully processed,oranegativevalueonerror*/ int(*master_xfer)(structi2c_adapter*adap,structi2c_msg*msgs, intnum); int(*smbus_xfer)(structi2c_adapter*adap,u16addr, unsignedshortflags,charread_write, u8command,intsize,unioni2c_smbus_data*data); /*Todeterminewhattheadaptersupports*/ u32(*functionality)(structi2c_adapter*); #ifIS_ENABLED(CONFIG_I2C_SLAVE) int(*reg_slave)(structi2c_client*client); int(*unreg_slave)(structi2c_client*client); #endif };
重點(diǎn)成員如下:
master_xfer:I2C 適配器的傳輸函數(shù),可以通過(guò)此函數(shù)來(lái)完成與 IIC 設(shè)備之間的通信。
smbus_xfer:SMBUS 總線(xiàn)的傳輸函數(shù)
I2C 適配器驅(qū)動(dòng)的主要工作就是初始化 i2c_adapter 結(jié)構(gòu)體變量,然后設(shè)置 i2c_algorithm中的master_xfer函數(shù)。完成以后通過(guò) i2c_add_numbered_adapter或 i2c_add_adapter這兩個(gè)函數(shù)向系統(tǒng)注冊(cè)設(shè)置好的 i2c_adapter。
這兩個(gè)函數(shù)的區(qū)別在于 i2c_add_adapter 使用動(dòng)態(tài)的總線(xiàn)號(hào),而 i2c_add_numbered_adapter使用靜態(tài)總線(xiàn)號(hào)。
5. 小結(jié)
I2C驅(qū)動(dòng)有4個(gè)重要的東西:I2C總線(xiàn)、I2C驅(qū)動(dòng)、I2C設(shè)備、I2C設(shè)備器。
I2C總線(xiàn):維護(hù)著兩個(gè)鏈表(I2C驅(qū)動(dòng)、I2C設(shè)備),管理I2C設(shè)備和I2C驅(qū)動(dòng)的匹配和刪除等。
I2C驅(qū)動(dòng):對(duì)應(yīng)的就是I2C設(shè)備的驅(qū)動(dòng)程序。
I2C設(shè)備:是具體硬件設(shè)備的一個(gè)抽象。
I2C適配器:用于I2C驅(qū)動(dòng)和I2C設(shè)備間的通用,是SOC上I2C控制器的一個(gè)抽象。
Linux I2C總線(xiàn)的運(yùn)行機(jī)制:
注冊(cè)I2C驅(qū)動(dòng)
將I2C驅(qū)動(dòng)添加到I2C總線(xiàn)的驅(qū)動(dòng)鏈表中
遍歷I2C總線(xiàn)上的設(shè)備鏈表,根據(jù)i2c_device_match函數(shù)進(jìn)行匹配,如果匹配調(diào)用i2c_device_probe函數(shù)
i2c_device_probe函數(shù)會(huì)調(diào)用I2C驅(qū)動(dòng)的probe函數(shù)
I2C驅(qū)動(dòng)簡(jiǎn)單編寫(xiě)流程
一般 SOC 的 I2C總線(xiàn)驅(qū)動(dòng)都是由半導(dǎo)體廠商編寫(xiě)的,這個(gè)不需要用戶(hù)去編寫(xiě)。因此 I2C 總線(xiàn)驅(qū)動(dòng)對(duì)于 SOC使用者來(lái)說(shuō)是被屏蔽掉的,我們只要專(zhuān)注于 I2C 設(shè)備驅(qū)動(dòng)即可。除非你是在半導(dǎo)體公司上班,工作內(nèi)容就是寫(xiě) I2C 適配器驅(qū)動(dòng)。
i2c_driver類(lèi)似platform_driver,是我們編寫(xiě)I2C設(shè)備驅(qū)動(dòng)重點(diǎn)要處理的內(nèi)容,i2c_driver在上面已經(jīng)介紹了其結(jié)構(gòu)體的具體內(nèi)容。
對(duì)于我們 I2C 設(shè)備驅(qū)動(dòng)編寫(xiě)人來(lái)說(shuō),重點(diǎn)工作就是構(gòu)建i2c_driver,構(gòu)建完成以后需要向Linux內(nèi)核注冊(cè)這個(gè)i2c_driver。
那么如何注冊(cè)呢?
使用下面的這個(gè)函數(shù):
inti2c_register_driver(structmodule*owner,structi2c_driver*driver)函數(shù)參數(shù)和返回值含義如下:
owner:一般為 THIS_MODULE。
driver:要注冊(cè)的 i2c_driver。
返回值:0,成功;負(fù)值,失敗。
另外 i2c_add_driver 也常常用于注冊(cè) i2c_driver, i2c_add_driver 是一個(gè)宏,定義如下:
#definei2c_add_driver(driver) i2c_register_driver(THIS_MODULE,driver)
i2c_add_driver 就是對(duì) i2c_register_driver 做了一個(gè)簡(jiǎn)單的封裝,只有一個(gè)參數(shù),就是要注冊(cè)的 i2c_driver。
設(shè)備驅(qū)動(dòng)的時(shí)候需要將前面注冊(cè)的 i2c_driver 從 Linux 內(nèi)核中注銷(xiāo)掉,需要用到i2c_del_driver 函數(shù),此函數(shù)原型如下:
voidi2c_del_driver(structi2c_driver*driver);函數(shù)參數(shù)和返回值含義如下:
driver:要注銷(xiāo)的 i2c_driver。
返回值:無(wú)。
例程框架:
/*i2c驅(qū)動(dòng)的probe函數(shù)*/ staticintxxx_probe(structi2c_client*client, { /*函數(shù)具體程序*/ return0; } /*i2c驅(qū)動(dòng)的remove函數(shù)*/ staticintxxx_remove(structi2c_client*client) { /*函數(shù)具體程序*/ return0; } /*傳統(tǒng)匹配方式ID列表*/ staticconststructi2c_device_idxxx_id[]={ {"xxx",0}, {} }; /*設(shè)備樹(shù)匹配列表*/ staticconststructof_device_idxxx_of_match[]={ {.compatible="xxx"}, {/*Sentinel*/} }; /*i2c驅(qū)動(dòng)結(jié)構(gòu)體*/ staticstructi2c_driverxxx_driver={ .probe=xxx_probe, .remove=xxx_remove, .driver={ .owner=THIS_MODULE, .name="xxx", .of_match_table=xxx_of_match, }, .id_table=xxx_id, }; /*驅(qū)動(dòng)入口函數(shù)*/ staticint__initxxx_init(void) { intret=0; ret=i2c_add_driver(&xxx_driver); returnret; } /*驅(qū)動(dòng)出口函數(shù)*/ staticvoid__exitxxx_exit(void) { i2c_del_driver(&xxx_driver); } module_init(xxx_init); module_exit(xxx_exit);
當(dāng)I2C設(shè)備和I2C驅(qū)動(dòng)匹配成功以后probe函數(shù)就會(huì)執(zhí)行,這些和platform驅(qū)動(dòng)一樣,probe函數(shù)里面基本就是標(biāo)準(zhǔn)的字符設(shè)備驅(qū)動(dòng)那一套了。
審核編輯:湯梓紅
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1372瀏覽量
40275 -
Linux
+關(guān)注
關(guān)注
87文章
11292瀏覽量
209322 -
I2C總線(xiàn)
+關(guān)注
關(guān)注
8文章
390瀏覽量
60916 -
I2C驅(qū)動(dòng)
+關(guān)注
關(guān)注
0文章
9瀏覽量
7046
原文標(biāo)題:Linux I2C 驅(qū)動(dòng)入門(mén),建議收藏!??!
文章出處:【微信號(hào):混說(shuō)Linux,微信公眾號(hào):混說(shuō)Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論