I2C 總線驅動, I2C總線驅動就是SOC的 I2C控制器驅動,也叫做 I2C適配器驅動。
I2C 設備驅動, I2C設備驅動就是針對具體的 I2C設備而編寫的驅動。
I2C框架下的幾個重要成員
1. I2C總線
I2C總線結構體在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總線對應著/bus下的一條總線,這個i2c總線結構體管理著i2c設備與I2C驅動的匹配,刪除等操作,I2C總線會調用i2c_device_match函數看I2C設備和I2C驅動是否匹配,如果匹配就調用i2c_device_probe函數,進而調用I2C驅動的probe函數。
形如:
i2c_device_match會管理I2C設備和I2C總線匹配規則,這將和如何編寫I2C驅動程序息息相關。
2. I2C驅動
i2c_driver 類似 platform_driver,是我們編寫 I2C 設備驅動重點要處理的內容, i2c_driver 結構體定義在 include/linux/i2c.h 文件中,內容如下:
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; };
重點成員如下:
int(*probe)(structi2c_client*,conststructi2c_device_id*)
當 I2C設備和驅動匹配成功以后 probe函數就會執行。
structdevice_driverdriverdevice_driver
驅動結構體,如果使用設備樹的話,需要設置device_driver的of_match_table成員變量,也就是驅動的兼容(compatible)屬性。
conststructi2c_device_id*id_table
id_table 是傳統的、未使用設備樹的設備匹配 ID表
3. I2C設備
I2C設備結構體i2c_client 結構體定義在 include/linux/i2c.h 文件中,內容如下:
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 };
重點成員如下:
flags:標志
addr:芯片地址,7 位,存在低 7 位
flagsname[I2C_NAME_SIZE]:名字
adapter:對應的 I2C 適配器
dev:設備結構體
irq:中斷
一個設備對應一個 i2c_client,每檢測到一個 I2C 設備就會給這個 I2C 設備分配一個i2c_client。
4. I2C適配器
經過上面的介紹,知道有I2C驅動和I2C設備,我們需要通過I2C驅動去和I2C設備通訊,這其中就需要一個I2C設配器,I2C設配器對應的就是SOC上的I2C控制器。
Linux 內核將 SOC 的 I2C 適配器(控制器)抽象成 i2c_adapter, i2c_adapter 結構體定義在 include/linux/i2c.h 文件中,結構體內容如下:
/* *i2c_adapteristhestructureusedtoidentifyaphysicali2cbusalong *withtheaccessalgorithmsnecessarytoaccessit. */ structi2c_adapter{ structmodule*owner; unsignedintclass;/*classestoallowprobingfor*/ conststructi2c_algorithm*algo;/*thealgorithmtoaccessthebus*//*總線訪問算法*/ 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; };
重點成員如下:
conststructi2c_algorithm*algo
I2C 適配器與 IIC 設備進行通信的方法。
i2c_algorithm 結構體定義在 include/linux/i2c.h 文件中,內容如下:
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 };
重點成員如下:
master_xfer:I2C 適配器的傳輸函數,可以通過此函數來完成與 IIC 設備之間的通信。
smbus_xfer:SMBUS 總線的傳輸函數
I2C 適配器驅動的主要工作就是初始化 i2c_adapter 結構體變量,然后設置 i2c_algorithm中的master_xfer函數。完成以后通過 i2c_add_numbered_adapter或 i2c_add_adapter這兩個函數向系統注冊設置好的 i2c_adapter。
這兩個函數的區別在于 i2c_add_adapter 使用動態的總線號,而 i2c_add_numbered_adapter使用靜態總線號。
5. 小結
I2C驅動有4個重要的東西:I2C總線、I2C驅動、I2C設備、I2C設備器。
I2C總線:維護著兩個鏈表(I2C驅動、I2C設備),管理I2C設備和I2C驅動的匹配和刪除等。
I2C驅動:對應的就是I2C設備的驅動程序。
I2C設備:是具體硬件設備的一個抽象。
I2C適配器:用于I2C驅動和I2C設備間的通用,是SOC上I2C控制器的一個抽象。
Linux I2C總線的運行機制:
注冊I2C驅動
將I2C驅動添加到I2C總線的驅動鏈表中
遍歷I2C總線上的設備鏈表,根據i2c_device_match函數進行匹配,如果匹配調用i2c_device_probe函數
i2c_device_probe函數會調用I2C驅動的probe函數
I2C驅動簡單編寫流程
一般 SOC 的 I2C總線驅動都是由半導體廠商編寫的,這個不需要用戶去編寫。因此 I2C 總線驅動對于 SOC使用者來說是被屏蔽掉的,我們只要專注于 I2C 設備驅動即可。除非你是在半導體公司上班,工作內容就是寫 I2C 適配器驅動。
i2c_driver類似platform_driver,是我們編寫I2C設備驅動重點要處理的內容,i2c_driver在上面已經介紹了其結構體的具體內容。
對于我們 I2C 設備驅動編寫人來說,重點工作就是構建i2c_driver,構建完成以后需要向Linux內核注冊這個i2c_driver。
那么如何注冊呢?
使用下面的這個函數:
inti2c_register_driver(structmodule*owner,structi2c_driver*driver)函數參數和返回值含義如下:
owner:一般為 THIS_MODULE。
driver:要注冊的 i2c_driver。
返回值:0,成功;負值,失敗。
另外 i2c_add_driver 也常常用于注冊 i2c_driver, i2c_add_driver 是一個宏,定義如下:
#definei2c_add_driver(driver) i2c_register_driver(THIS_MODULE,driver)
i2c_add_driver 就是對 i2c_register_driver 做了一個簡單的封裝,只有一個參數,就是要注冊的 i2c_driver。
設備驅動的時候需要將前面注冊的 i2c_driver 從 Linux 內核中注銷掉,需要用到i2c_del_driver 函數,此函數原型如下:
voidi2c_del_driver(structi2c_driver*driver);函數參數和返回值含義如下:
driver:要注銷的 i2c_driver。
返回值:無。
例程框架:
/*i2c驅動的probe函數*/ staticintxxx_probe(structi2c_client*client, { /*函數具體程序*/ return0; } /*i2c驅動的remove函數*/ staticintxxx_remove(structi2c_client*client) { /*函數具體程序*/ return0; } /*傳統匹配方式ID列表*/ staticconststructi2c_device_idxxx_id[]={ {"xxx",0}, {} }; /*設備樹匹配列表*/ staticconststructof_device_idxxx_of_match[]={ {.compatible="xxx"}, {/*Sentinel*/} }; /*i2c驅動結構體*/ 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, }; /*驅動入口函數*/ staticint__initxxx_init(void) { intret=0; ret=i2c_add_driver(&xxx_driver); returnret; } /*驅動出口函數*/ staticvoid__exitxxx_exit(void) { i2c_del_driver(&xxx_driver); } module_init(xxx_init); module_exit(xxx_exit);
當I2C設備和I2C驅動匹配成功以后probe函數就會執行,這些和platform驅動一樣,probe函數里面基本就是標準的字符設備驅動那一套了。
審核編輯:湯梓紅
-
內核
+關注
關注
3文章
1372瀏覽量
40276 -
Linux
+關注
關注
87文章
11292瀏覽量
209328 -
I2C總線
+關注
關注
8文章
390瀏覽量
60916 -
I2C驅動
+關注
關注
0文章
9瀏覽量
7046
原文標題:Linux I2C 驅動入門,建議收藏!!!
文章出處:【微信號:混說Linux,微信公眾號:混說Linux】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論