Linux_I2C總線分析(主要是probe的方式)1_第1頁
Linux_I2C總線分析(主要是probe的方式)1_第2頁
Linux_I2C總線分析(主要是probe的方式)1_第3頁
Linux_I2C總線分析(主要是probe的方式)1_第4頁
Linux_I2C總線分析(主要是probe的方式)1_第5頁
已閱讀5頁,還剩6頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、Linux I2C 總線淺析 Overview內(nèi)核空間層次!i2c adapter 是一個(gè)struct, 用來抽象一個(gè)物理i2c bus ,而且還和linux 設(shè)備驅(qū)動(dòng)架構(gòu)柔和在一起.如果只說硬件的話,就是在CPU內(nèi)部集成的一個(gè)I2C控制器(提供給用戶的就是那幾個(gè)register),硬件上并沒的所謂的adapter,client這些東東,adapter和client都是linux驅(qū)動(dòng)軟件抽象出來的東西 資料帖子:struct i2c_algorithm /* If an adapter algorithm can't do I2C-level access, set master_xf

2、er to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages */* master_xfer should return the number of messages successfully processed, or a negative value on error */int (*master_xfer)(struct i2c_adapter *adap,

3、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);/* To determine what the adapter supports */u32 (*functionality) (struct i2c_adapter *);/* * i2c_adapter is the structure use

4、d to identify a physical i2c bus along * with the access algorithms necessary to access it. */struct i2c_adapter struct module *owner;unsigned int id;unsigned int class; /* classes to allow probing for */const struct i2c_algorithm *algo; /* the algorithm to access the bus */void *algo_data;/* data f

5、ields that are valid for all devices*/u8 level; /* nesting level for lockdep */struct mutex bus_lock;int timeout;/* in jiffies */int retries;struct device dev;/* the adapter device */int nr;char name48;struct completion dev_released;Linux的I2C體系結(jié)構(gòu)分為3個(gè)組成部分:1·I2C核心:I2C核心提供了I2C總線驅(qū)動(dòng)和設(shè)備驅(qū)動(dòng)的注冊(cè)、注銷方法,I2C

6、通信方法(即“algorithm”)上層的、與具體適配器無關(guān)的代碼以及探測(cè)設(shè)備、檢測(cè)設(shè)備地址的上層代碼等。這部分是與平臺(tái)無關(guān)的。2·I2C總線驅(qū)動(dòng):I2C總線驅(qū)動(dòng)是對(duì)I2C硬件體系結(jié)構(gòu)中適配器端的實(shí)現(xiàn)。I2C總線驅(qū)動(dòng)主要包含了I2C適配器數(shù)據(jù)結(jié)構(gòu)i2c_adapter、I2C適配器的algorithm數(shù)據(jù)結(jié)構(gòu)i2c_algorithm和控制I2C適配器產(chǎn)生通信信號(hào)的函數(shù)。經(jīng)由I2C總線驅(qū)動(dòng)的代碼,我們可以控制I2C適配器以主控方式產(chǎn)生開始位、停止位、讀寫周期,以及以從設(shè)備方式被讀寫、產(chǎn)生ACK等。不同的CPU平臺(tái)對(duì)應(yīng)著不同的I2C總線驅(qū)動(dòng)。 總線驅(qū)動(dòng)的職責(zé),是為系統(tǒng)中每個(gè)I2C總線增

7、加相應(yīng)的讀寫方法。但是總線驅(qū)動(dòng)本身并不會(huì)進(jìn)行任何的通訊,它只是存在在那里,等待設(shè)備驅(qū)動(dòng)調(diào)用其函數(shù)。這部分在MTK 6516中是由MTK已經(jīng)幫我們實(shí)現(xiàn)了的,不需要我們更改。3· I2C設(shè)備驅(qū)動(dòng):I2C設(shè)備驅(qū)動(dòng)是對(duì)I2C硬件體系結(jié)構(gòu)中設(shè)備端的實(shí)現(xiàn)。設(shè)備一般掛接在受CPU控制的I2C適配器上,通過I2C適配器與CPU交換數(shù)據(jù)。I2C設(shè)備驅(qū)動(dòng)主要包含了數(shù)據(jù)結(jié)構(gòu)i2c_driver和i2c_client,我們需要根據(jù)具體設(shè)備實(shí)現(xiàn)其中的成員函數(shù)。在Linux內(nèi)核源代碼中的drivers目錄下的i2c_dev.c文件,實(shí)現(xiàn)了I2C適配器設(shè)備文件的功能,應(yīng)用程序通過“i2c-%d”文件名并使用文件操

8、作接口open()、write()、read()、ioctl()和close()等來訪問這個(gè)設(shè)備。應(yīng)用層可以借用這些接口訪問掛接在適配器上的I2C設(shè)備的存儲(chǔ)空間或寄存器并控制I2C設(shè)備的工作方式。設(shè)備驅(qū)動(dòng)則是與掛在I2C總線上的具體的設(shè)備通訊的驅(qū)動(dòng)。通過I2C總線驅(qū)動(dòng)提供的函數(shù),設(shè)備驅(qū)動(dòng)可以忽略不同總線控制器的差異,不考慮其實(shí)現(xiàn)細(xì)節(jié)地與硬件設(shè)備通訊。這部分在MTK 6516中是由具體的設(shè)備實(shí)現(xiàn)的。(比如camera)struct i2c_client:代表一個(gè)掛載到i2c總線上的i2c從設(shè)備,該設(shè)備所需要的數(shù)據(jù)結(jié)構(gòu),其中包括該i2c從設(shè)備所依附的i2c主設(shè)備 struct i2c_adapte

9、r *adapter 該i2c從設(shè)備的驅(qū)動(dòng)程序struct i2c_driver *driver 作為i2c從設(shè)備所通用的成員變量,比如addr, name等 該i2c從設(shè)備驅(qū)動(dòng)所特有的數(shù)據(jù),依附于dev->driver_data下struct i2c_adapter:代表主芯片所支持的一個(gè)i2c主設(shè)備。struct i2c_algorithm *algo:是該i2c主設(shè)備傳輸數(shù)據(jù)的一種算法,或者說是在i2c總線上完成主從設(shè)備間數(shù)據(jù)通信的一種能力。Linux的i2c子系統(tǒng)新、舊架構(gòu)并存。主要分為舊架構(gòu)(Legacy)也有人稱之為adapter方式,和新的架構(gòu)new-style的方式。這倆

10、者的區(qū)別主要在于設(shè)備注冊(cè)和驅(qū)動(dòng)注冊(cè)的不同。對(duì)于Legacy的設(shè)備注冊(cè)是在驅(qū)動(dòng)運(yùn)行的時(shí)候動(dòng)態(tài)的創(chuàng)建,而新式的new-style則是采用靜態(tài)定義的方式。注:MTK在Android2.1版上用的是Legacy的架構(gòu),而在Android2.2版上用的是new-style的架構(gòu)。(在這里我就只說明Android2.2的new-style的實(shí)現(xiàn)方法)要完成I2C設(shè)備的驅(qū)動(dòng),我們可以分三步走:第一步:完成適配器的注冊(cè)(總線);第二步:完成I2C client的設(shè)備注冊(cè)(設(shè)備);第三步:完成I2C client驅(qū)動(dòng)的注冊(cè)(驅(qū)動(dòng));我們分別給予介紹:(I2C-mt6516.c)就總線而言,其本質(zhì)只需要我們填充倆

11、個(gè)結(jié)構(gòu)體就可以了:i2c_adapter;i2c_algorithm;i2c_add_adapter(i2c->adap); 往總線上添加對(duì)應(yīng)的適配器;struct i2c_adapter     struct module *owner;    unsigned int id;    unsigned int class;    /* classes to allow probing for */   const struct i2c_algori

12、thm *algo; /* the algorithm to access the bus */   void *algo_data;    /* - administration stuff. */   int (*client_register)(struct i2c_client *);    int (*client_unregister)(struct i2c_client *);      /* data fields that are val

13、id for all devices */   u8 level;    /* nesting level for lockdep */   struct mutex bus_lock;    struct mutex clist_lock;      int timeout;   /* in jiffies */   int retries;    struct device dev;

14、  /* the adapter device */     int nr; /*該成員描述了總線號(hào)*/   struct list_head clients; /* i2c_client結(jié)構(gòu)鏈表,該結(jié)構(gòu)包含device,driver和  adapter結(jié)構(gòu)*/   char name48;    struct completion dev_released;   ; static struct i2c_algorithm mt6516_i2c_

15、algorithm = .master_xfer = mt6516_i2c_transfer,.smbus_xfer = NULL,.functionality = mt6516_i2c_functionality,;2、設(shè)備注冊(cè)第一步:記得以前的i2c設(shè)備驅(qū)動(dòng),設(shè)備部分喜歡驅(qū)動(dòng)運(yùn)行的時(shí)候動(dòng)態(tài)創(chuàng)建,新式的驅(qū)動(dòng)傾向于向傳統(tǒng)的linux下設(shè)備驅(qū)動(dòng)看齊,采用靜態(tài)定義的方式來注冊(cè)設(shè)備,使用接口為:int _init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) int statu

16、s; mutex_lock(&_i2c_board_lock); /* dynamic bus numbers will be assigned after the last static one */ if (busnum >= _i2c_first_dynamic_bus_num) _i2c_first_dynamic_bus_num = busnum + 1; for (status = 0; len; len-, info+) struct i2c_devinfo *devinfo; devinfo = kzalloc(sizeof(*devinfo), GFP_KERN

17、EL);/申請(qǐng)表示i2c設(shè)備的結(jié)構(gòu)體空間 if (!devinfo) pr_debug("i2c-core: can't register boardinfo!n"); status = -ENOMEM; break; /* 填寫i2c設(shè)備描述結(jié)構(gòu) */ devinfo->busnum = busnum; devinfo->board_info = *info; list_add_tail(&devinfo->list, &_i2c_board_list);/添加到全局鏈表_i2c_board_list中 mutex_unlock(

18、&_i2c_board_lock); return status;在系統(tǒng)初始化的過程中,我們可以通過 i2c_register_board_info,將所需要的I2C從設(shè)備加入一個(gè)名為_i2c_board_list雙向循環(huán)鏈表,系統(tǒng)在成功加載I2C主設(shè)備adapt后,就會(huì)對(duì)這張鏈表里所有I2C從設(shè)備逐一地完成 i2c_client的注冊(cè)。第二步: 系統(tǒng)初始化的時(shí)候,會(huì)根據(jù)板級(jí)i2c設(shè)備配置信息,創(chuàng)建i2c客戶端設(shè)備(i2c_client),添加到i2c子系統(tǒng)中:static void i2c_scan_static_board_info (struct i2c_adapter *ada

19、pter) struct i2c_devinfo *devinfo; mutex_lock(&_i2c_board_lock); list_for_each_entry(devinfo, &_i2c_board_list, list) /遍歷全局鏈表_i2c_board_list if (devinfo->busnum = adapter->nr && !i2c_new_device(adapter, &devinfo->board_info) printk(KERN_ERR "i2c-core: can't crea

20、te i2c%d-%04xn", i2c_adapter_id(adapter), devinfo->board_info.addr); mutex_unlock(&_i2c_board_lock);struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)struct i2c_client*client;intstatus;client = kzalloc(sizeof *client, GFP_KERNEL);if (!client)re

21、turn NULL;client->adapter = adap;client->dev.platform_data = info->platform_data;if (info->archdata)client->dev.archdata = *info->archdata;client->flags = info->flags;client->addr = info->addr;client->irq = info->irq;strlcpy(client->name, info->type, sizeof(

22、client->name);/* Check for address business */status = i2c_check_addr(adap, client->addr);if (status)goto out_err;client->dev.parent = &client->adapter->dev;client->dev.bus = &i2c_bus_type;client->dev.type = &i2c_client_type;dev_set_name(&client->dev, "%d

23、-%04x", i2c_adapter_id(adap), client->addr);status = device_register(&client->dev);if (status)goto out_err;dev_dbg(&adap->dev, "client %s registered with bus id %sn",client->name, dev_name(&client->dev);return client;out_err:dev_err(&adap->dev, "

24、Failed to register i2c client %s at 0x%02x ""(%d)n", client->name, client->addr, status);kfree(client);return NULL;IDR機(jī)制:完成的是設(shè)備ID和結(jié)構(gòu)體的關(guān)聯(lián)。_i2c_first_dynamic_bus_num:當(dāng)前系統(tǒng)允許的動(dòng)態(tài)總線的最大值。i2c_scan_static_board_info(adap);/*完成新類型i2c設(shè)備的注冊(cè),一般只在主板初始化時(shí)*/ 此函數(shù)為整個(gè)I2C子系統(tǒng)的核心,它會(huì)去遍歷一個(gè)由I2C從設(shè)備組成

25、的雙向循環(huán)鏈表,并完成所有I2C從設(shè)備的i2c_client的注冊(cè)。struct i2c_devinfo *devinfo;     /已經(jīng)建立好了的I2C從設(shè)備鏈表status = i2c_check_addr(adap, client->addr);注: 特別要提一下的是這個(gè)“i2c_check_addr”,引用<<i2c 源代碼情景分析>>里的話:“i2c 設(shè)備的7 位地址是就當(dāng)前i2c 總線而言的,是“相對(duì)地址”。不同的i2c 總線上的設(shè)備可以使用相同的7 位地址,但是它們所在的i2c 總線不同。所以在系統(tǒng)中一個(gè)i2

26、c 設(shè)備的“絕對(duì)地址”由二元組(i2c 適配器的ID 和設(shè)備在該總線上的7 位地址)表示?!?,所以這個(gè)函數(shù)的作用主要是排除同一i2c總線上出現(xiàn)多個(gè)地址相同的設(shè)備。3、I2C驅(qū)動(dòng)注冊(cè):第一步:static inline int i2c_add_driver(struct i2c_driver *driver) return i2c_register_driver(THIS_MODULE, driver);int i2c_register_driver(struct module *owner, struct i2c_driver *driver)int res;/* Can't regi

27、ster until after driver model init */if (unlikely(WARN_ON(!i2c_bus_type.p)return -EAGAIN;/* add the driver to the list of i2c drivers in the driver core */driver->driver.owner = owner;driver->driver.bus = &i2c_bus_type;/* When registration returns, the driver core * will have called probe(

28、) for all matching-but-unbound devices. */res = driver_register(&driver->driver);if (res)return res;pr_debug("i2c-core: driver %s registeredn", driver->);INIT_LIST_HEAD(&driver->clients);/* Walk the adapters that are already present */mutex_lock(&core_lock);

29、bus_for_each_dev(&i2c_bus_type, NULL, driver, _attach_adapter);mutex_unlock(&core_lock);return 0;設(shè)備和驅(qū)動(dòng)的關(guān)聯(lián)過程:首先當(dāng)I2C從設(shè)備和I2C驅(qū)動(dòng)如果處于同一條總線上,那么其在設(shè)備和驅(qū)動(dòng)注冊(cè)之后,將會(huì)促使I2C_bus_type中的match獲得調(diào)用;()如下:struct bus_type i2c_bus_type = .name= "i2c",.match= i2c_device_match,.probe= i2c_device_probe,.remove

30、= i2c_device_remove,.shutdown= i2c_device_shutdown,.suspend= i2c_device_suspend,.resume= i2c_device_resume,;繼續(xù)跟進(jìn)i2c_device_match;i2c_match_id(driver->id_table, client) != NULL;我們回到i2c_device_probe;這個(gè)函數(shù)的關(guān)鍵是:status = driver->probe(client, i2c_match_id(driver->id_table, client);它將函數(shù)的流程交回到了driv

31、er->probe的手中;流程圖:過程分享:1、設(shè)備和驅(qū)動(dòng)的關(guān)聯(lián)大家知道,對(duì)于一個(gè)驅(qū)動(dòng)程序有兩個(gè)元素不可或缺,即設(shè)備和驅(qū)動(dòng),一般驅(qū)動(dòng)都是通過設(shè)備名和驅(qū)動(dòng)名的匹配建立關(guān)系的,最開始我從代碼中只能發(fā)現(xiàn)驅(qū)動(dòng)的注冊(cè),卻不見設(shè)備注冊(cè)的蹤影,令人疑惑,跟蹤發(fā)現(xiàn),在i2c adapter注冊(cè)時(shí)會(huì)遍歷i2c_board_info這樣一個(gè)結(jié)構(gòu),而這個(gè)結(jié)構(gòu)在29以前或更早的內(nèi)核里是不存在的,它會(huì)完成驅(qū)動(dòng)與設(shè)備的匹配問題, 2、名字匹配一個(gè)i2c驅(qū)動(dòng)是可以有多個(gè)名字的,即一個(gè)驅(qū)動(dòng)程序可以支持多個(gè)設(shè)備,該機(jī)制是通過 struct i2c_device_id實(shí)現(xiàn)的,驅(qū)動(dòng)中建立這么一個(gè)結(jié)構(gòu)體數(shù)組,i2c架構(gòu)層便會(huì)掃

32、描該數(shù)組,與設(shè)備名去匹配,匹配成功的都會(huì)進(jìn)入相應(yīng)probe函數(shù)。3、進(jìn)入probe該過程困惑了我一段時(shí)間,其實(shí)要進(jìn)入自己驅(qū)動(dòng)的probe首先需要進(jìn)入總線的probe,而進(jìn)入總線probe的前提是與總線的match成功。待解決的困惑:1、I2C從設(shè)備名; Legacy 的相關(guān)知識(shí):(一) Linux的I2C驅(qū)動(dòng)框架中的主要數(shù)據(jù)結(jié)構(gòu)及其關(guān)系 Linux的I2C驅(qū)動(dòng)框架中的主要數(shù)據(jù)結(jié)構(gòu)包括:i2c_driver、i2c_client、i2c_adapter和i2c_algorithm。i2c_adapter對(duì)應(yīng)于物理上的一個(gè)適配器,這個(gè)適配器是基于不同的平臺(tái)的,一個(gè)I2C適配器需要i2c_algor

33、ithm中提供的通信函數(shù)來控制適配器,因此i2c_adapter中包含其使用的i2c_algorithm的指針。i2c_algorithm中的關(guān)鍵函數(shù)master_xfer()以i2c_msg為單位產(chǎn)生I2C訪問需要的信號(hào)。不同的平臺(tái)所對(duì)應(yīng)的master_xfer()是不同的,開發(fā)人員需要根據(jù)所用平臺(tái)的硬件特性實(shí)現(xiàn)自己的XXX_xfer()方法以填充i2c_algorithm的master_xfer指針。i2c_ driver對(duì)應(yīng)一套驅(qū)動(dòng)方法,不對(duì)應(yīng)于任何的物理實(shí)體。i2c_client對(duì)應(yīng)于真實(shí)的物理設(shè)備,每個(gè)I2C設(shè)備都需要一個(gè)i2c_client來描述。i2c_client依附于i2c_adpater,這與I2C硬件體系中適配器和設(shè)備的關(guān)系一致。i2c_driver提供了i2c-client與i2c-adapter產(chǎn)生聯(lián)系的函數(shù)。當(dāng)attach a_dapter()函數(shù)探測(cè)物理設(shè)備時(shí),如果確定存在一個(gè)client,則把該client使用的i2c_client數(shù)據(jù)結(jié)構(gòu)的

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論