I2C對外APIhtml
I2C client的註冊node
i2c_register_board_info具體實現數組
i2c_new_device數據結構
I2C driver框架
關於I2C設備驅動的小總結ide
I2C adapter的註冊函數
使用場景ui
在(一)中簡述了Linux I2C子系統的三個主要成員i2c_adapter、i2c_driver、i2c_client。三者的關係也在上一節進行了描述。應該已經算是對Linux I2C子系統有了初步的瞭解。下面再對他們之間的關係進行代碼層的深刻分析,我認爲對他們的關係瞭解的越好,越有助於I2C設備的驅動開發及調試。this
帶着問題去分析可能會更有幫助吧,經過對(一)的瞭解後,可能會產生如下的幾點疑問:spa
i2c_adapter驅動如何添加?
i2c_client與i2c_board_info到底是什麼關係?
在解答問題前,不妨先縷順一下Linux內核的I2C子系統對驅動模塊的API有哪些。(來自https://www.kernel.org/doc/htmldocs/device-drivers/i2c.html)
// 對外數據結構 struct i2c_driver — 表明一個I2C設備驅動 struct i2c_client — 表明一個I2C從設備 struct i2c_board_info — 從設備建立的模版 I2C_BOARD_INFO — 建立I2C設備的宏,包含名字和地址 struct i2c_algorithm — 表明I2C傳輸方法 struct i2c_bus_recovery_info — I2C總線恢復信息?內核新加入的結構,不是很清楚。 //對外函數操做 module_i2c_driver — 註冊I2C設備驅動的宏定義 i2c_register_board_info — 靜態聲明(註冊)I2C設備,可多個 i2c_verify_client — 若是設備是i2c_client的dev成員則返回其父指針,不然返回NULL。用來校驗設備是否爲I2C設備 i2c_lock_adapter — I2C總線持鎖操做,會找到最根源的那個i2c_adapter。說明你的模塊必須符合GPL協議纔可使用這個接口。後邊以GPL表明。 i2c_unlock_adapter — 上一個的反操做,GPL i2c_new_device — 由i2c_board_info信息聲明一個i2c設備(client),GPL i2c_unregister_device — 上一個的反操做,GPL。 i2c_new_dummy — 聲明一個名爲dummy(指定地址)的I2C設備,GPL i2c_verify_adapter — 驗證是不是i2c_adapter i2c_add_adapter — 聲明I2C適配器,系統動態分配總線號。 i2c_add_numbered_adapter — 一樣是聲明I2C適配器,可是指定了總線號,GPL i2c_del_adapter — 卸載I2C適配器 i2c_del_driver — 卸載I2C設備驅動 i2c_use_client — i2c_client引用數+1 i2c_release_client — i2c_client引用數-1 __i2c_transfer — 沒有自動持鎖(adapter lock)的I2C傳輸接口 i2c_transfer — 自動持鎖的I2C傳輸接口 i2c_master_send — 單條消息發送 i2c_master_recv — 單條消息接收 i2c_smbus_read_byte — SMBus 「receive byte」 protocol i2c_smbus_write_byte — SMBus 「send byte」 protocol i2c_smbus_read_byte_data — SMBus 「read byte」 protocol i2c_smbus_write_byte_data — SMBus 「write byte」 protocol i2c_smbus_read_word_data — SMBus 「read word」 protocol i2c_smbus_write_word_data — SMBus 「write word」 protocol i2c_smbus_read_block_data — SMBus 「block read」 protocol i2c_smbus_write_block_data — SMBus 「block write」 protocol i2c_smbus_xfer — execute SMBus protocol operations
(一)中對幾個基本的結構體和宏定義也有了大概的解釋,相信結合I2C的理論基礎不難理解。對以上一些I2C的API進行分類:
No. | Adapter | Driver | Device(client) | Transfer |
---|---|---|---|---|
1 | i2c_add_adapter | module_i2c_driver | i2c_register_board_info | __i2c_transfer |
2 | i2c_add_numbered_adapter | i2c_del_driver | i2c_new_device | i2c_transfer |
3 | i2c_del_adapter | i2c_new_dummy | i2c_master_send | |
4 | i2c_lock_adapter | i2c_verify_client | i2c_master_recv | |
5 | i2c_unlock_adapter | i2c_unregister_device | i2c_smbus_read_byte | |
6 | i2c_verify_adapter | i2c_use_client | i2c_smbus_write_byte | |
7 | i2c_release_client | i2c_smbus_read_byte_data | ||
8 | i2c_smbus_write_byte_data | |||
9 | i2c_smbus_read_word_data | |||
10 | i2c_smbus_write_word_data | |||
11 | i2c_smbus_read_block_data | |||
12 | i2c_smbus_write_block_data | |||
13 | i2c_smbus_xfer |
通過一個表格的整理,不難發如今Linux I2C子系統中,最重要的要數i2c_client,而最多樣化的就是數據的傳輸。
爲了更好的理解和銜接,我想也許倒着分析會更有幫助,而這裏先暫且不討論I2C傳輸過程當中的細節。下邊的順序是由client到driver,再到adapter。
i2c_client即I2C設備的註冊接口有三個:
i2c_register_board_info i2c_new_device i2c_new_dummy
而i2c_new_dummy在內部其實也就是將client的name指定爲dummy後依舊執行的是i2c_new_device,因此就只分析前兩個就能夠了。首先看這兩個函數的原型:
i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
busnum 經過總線號指定這個(些)設備屬於哪一個總線
info i2c設備的數組集合 i2c_board_info格式
len 數組個數ARRAY_SIZE(info)
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
adap 此設備所依附的I2C適配器指針
info 此設備描述,i2c_board_info格式,bus_num成員是被忽略的
int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { int status; down_write(&__i2c_board_lock); //i2c設備信息讀寫鎖,鎖寫操做,其餘只讀 /* dynamic bus numbers will be assigned after the last static one */ if (busnum >= __i2c_first_dynamic_bus_num) //與動態分配的總線號相關,動態分配的總線號應該是從已經現有最大總線號基礎上+1的,這樣可以保證動態分配出的總線號與板級總線號不會產生衝突 __i2c_first_dynamic_bus_num = busnum + 1; for (status = 0; len; len--, info++) { //處理info數組中每一個成員 struct i2c_devinfo *devinfo; devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); if (!devinfo) { pr_debug("i2c-core: can't register boardinfo!\n"); status = -ENOMEM; break; } devinfo->busnum = busnum; //組裝總線號 devinfo->board_info = *info; //組裝設備信息 list_add_tail(&devinfo->list, &__i2c_board_list); //加入到__i2c_board_list鏈表中(尾部) } up_write(&__i2c_board_lock); //釋放讀鎖,其餘可讀可寫 return status; }
看完後相信都會產生個疑問?怎麼將相關信息放到鏈表中就算完事了嗎?不着急,來看下內核中已經給出的解釋:
* Systems using the Linux I2C driver stack can declare tables of board info * while they initialize. This should be done in board-specific init code * near arch_initcall() time, or equivalent, before any I2C adapter driver is * registered. For example, mainboard init code could define several devices, * as could the init code for each daughtercard in a board stack. * * The I2C devices will be created later, after the adapter for the relevant * bus has been registered. After that moment, standard driver model tools * are used to bind "new style" I2C drivers to the devices. The bus number * for any device declared using this routine is not available for dynamic * allocation.
核心內容就是說關於集成的I2C設備註冊過程應該在板級代碼初始化期間,也就是arch_initcall先後的時間,或者就在這個時候(board-xxx-yyy.c中),切記切記!!!必定要在I2C適配器驅動註冊前完成!!!爲何說是靜態註冊,是由於真實的I2C設備是在適配器成功註冊後才被生成的。若是在I2C適配器註冊完後還想要添加I2C設備的話,就要經過新方式!(即i2c_new_device)
小弟永遠要擋在老大前邊嘛!老大還沒出來前,小弟們趕忙前排列陣好,老大到了可不等你,你列陣也沒用了。而對於遲到的小弟,本身想辦法追上去吧,在原地本身列陣是白費工夫了。
對於__i2c_board_list鏈表中的信息是如何變成實際的i2c設備信息的過程放在以後adapter註冊過程的分析中。記得,重點是i2c_register_board_info方式必定要趕在I2C適配器的註冊前,這樣就沒有問題。
struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) { struct i2c_client *client; int status; client = kzalloc(sizeof *client, GFP_KERNEL); //爲即將註冊的client申請內存 if (!client) return NULL; client->adapter = adap; //綁定指定的adapter適配器 client->dev.platform_data = info->platform_data; //保存設備數據 if (info->archdata) //代碼上看是DMA相關操做數據 client->dev.archdata = *info->archdata; client->flags = info->flags; //類型,(一)中說過,或是10位地址,或是使用SMBus檢錯 client->addr = info->addr; //設備從地址 client->irq = info->irq; //設備終端 strlcpy(client->name, info->type, sizeof(client->name)); //從設備名 //瞧!(一)中說過i2c_board_info中的信息是與i2c_client有對應關係的,靈驗了吧! /* Check for address validity */ status = i2c_check_client_addr_validity(client); //檢測地址是否有效,10位地址是否大於0x3ff,7位地址是否大於0x7f或爲0 if (status) { //非零(實際上爲-22,無效參數Invalid argument dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); goto out_err_silent; } /* Check for address business */ status = i2c_check_addr_busy(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; client->dev.of_node = info->of_node; ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle); /* For 10-bit clients, add an arbitrary offset to avoid collisions */ dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), client->addr | ((client->flags & I2C_CLIENT_TEN) ? 0xa000 : 0)); //若是是10位地址設備,那名字格式與7bit的會有不一樣 status = device_register(&client->dev); //註冊了!註冊了!!! if (status) goto out_err; dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); return client; out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " "(%d)\n", client->name, client->addr, status); out_err_silent: kfree(client); return NULL; }
i2d_new_device沒什麼好多說的,因爲有i2c_register_board_info的鋪墊,相信也很好理解了。而i2c_new_device不但印證了i2c_client與i2c_board_info的對應關係,還順便體現了10bit地址設備與7bit地址設備的略微不一樣。經過二者的對比,能夠再總結出幾點區別,從而更好的理解I2C設備的註冊方法:
i2c_register_board_info的形參須要的是總線號
i2c_new_device的形參須要的直接是適配器的指針
我想這也正好能完美的說明二者的根本區別,對於板級設備更在意適配器的總線號,由於這是固定的,沒有異議的。而對於可插拔設備,由於其適配器可能非板級集成的,因此不能在意其總線號,反而只要尋求其適配器指針進行綁定便可。後邊adapter註冊的分析能更好的證實這一點。
i2c_register_board_info能夠同時註冊多個I2C設備
i2c_new_device只能一次註冊一個I2C設備
這也是其根本區別決定的,板級代碼中常包含有許多I2C設備,因此i2c_register_board_info須要有同時註冊多個I2C設備的能力也能夠說是剛需。而i2c_new_device既然是用來給可插拔設備用的,想必設備數量並很少,而常可能只是一個兩個而已,因此一次一個就夠了,需求量並不大。
I2C設備驅動。Linux內核給出的接口只有兩個,一個是註冊,另外一個就是卸載。在(一)也分析過module_i2c_driver這個宏定義,由於有它的存在,I2C設備驅動的開發能夠不用在乎你的I2C驅動須要如何註冊以及如何卸載的,所有的精力都放在i2c_driver的完善上就能夠了。
經過最開始的表單能明顯察覺到,I2C子系統中I2C driver的開放接口最少,說白了就是須要驅動編寫者完成完了i2c_driver放入module_i2c_driver宏中便可,而正由於如此,也偏偏說明,i2c_driver的靈活性是最高的。一般驅動會首先在乎在用戶空間的打開、關閉、讀寫等接口,可是對於i2c_driver來講,這些工做是I2C子系統已經作好的,關於經常使用的讀寫最終也是經過adapter實現的i2c_algorithm達到目的。好吧,再次說明了I2C子系統的完善程度,對於I2C設備及驅動開發來講是極其方便的。那麼I2C驅動要實現什麼呢?
再次回顧一下i2c_driver結構體,不過如今要剔除一些不經常使用的成員:
struct i2c_driver { int (*probe)(struct i2c_client *, const struct i2c_device_id *); //現行通用的與對應設備進行綁定的接口函數 int (*remove)(struct i2c_client *); //現行通用與對應設備進行解綁的接口函數 void (*shutdown)(struct i2c_client *); //關閉設備 int (*suspend)(struct i2c_client *, pm_message_t mesg); //掛起設備,與電源管理有關,爲省電 int (*resume)(struct i2c_client *); //從掛起狀態恢復 struct device_driver driver; //I2C設備的驅動模型 const struct i2c_device_id *id_table; //匹配設備列表 ... };
若是有可能的話,我還想再精簡一下:
struct i2c_driver { int (*probe)(struct i2c_client *, const struct i2c_device_id *); //現行通用的與對應設備進行綁定的接口函數 int (*remove)(struct i2c_client *); //現行通用與對應設備進行解綁的接口函數 struct device_driver driver; //I2C設備的驅動模型 const struct i2c_device_id *id_table; //匹配設備列表 ... };
好了,精簡到這種程度,爲何把電源管理相關也幹掉了呢?實際上沒有,一般實際的I2C驅動喜歡在drivers中完成這個動做(以mpu3050爲例):
static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL); static const struct i2c_device_id mpu3050_ids[] = { { "mpu3050", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, mpu3050_ids); static const struct of_device_id mpu3050_of_match[] = { { .compatible = "invn,mpu3050", }, { }, }; MODULE_DEVICE_TABLE(of, mpu3050_of_match); static struct i2c_driver mpu3050_i2c_driver = { .driver = { .name = "mpu3050", .owner = THIS_MODULE, .pm = &mpu3050_pm, .of_match_table = mpu3050_of_match, }, .probe = mpu3050_probe, .remove = mpu3050_remove, .id_table = mpu3050_ids, }; module_i2c_driver(mpu3050_i2c_driver);
能夠看到,實際驅動中喜歡將電源管理集成在i2c_driver的driver成員中。
UNIVERSAL_DEV_PM_OPS這個名字很犀利,貌似是「宇宙終極驅動電源管理大法」的樣子:
#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ const struct dev_pm_ops name = { \ SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ } #define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ .suspend = suspend_fn, \ .resume = resume_fn, \ .freeze = suspend_fn, \ .thaw = resume_fn, \ .poweroff = suspend_fn, \ .restore = resume_fn, #define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ .runtime_suspend = suspend_fn, \ .runtime_resume = resume_fn, \ .runtime_idle = idle_fn,
結合MPU3050的驅動將其完整展開能夠獲得:
static const struct dev_pm_ops mpu3050_pm = { .suspend = mpu3050_suspend, .resume = mpu3050_resume, .freeze = mpu3050_suspend, .thaw = mpu3050_resume, .poweroff = mpu3050_suspend, .restore = mpu3050_resume, .runtime_suspend = mpu3050_suspend, .runtime_resume = mpu3050_resume, .runtime_idle = NULL, }
對電源管理有興趣的能夠去查閱pm.h,其中對電源管理有詳盡的說明了,這裏不作分析。能夠看到,在電源管理中,有不少成員其實是同樣的,在現實驅動中這樣的狀況也常常出現,因此會有「終極電源管理大法」宏的出現了。
of_match_table是OpenFirmware相關,在3.0(具體版本本人不清楚)kernel後對arm平臺引入了Device Tree,可經過dts配置文件代替大量板級代碼,有興趣可自行查閱。
上邊說過,i2c_driver的多樣化最多,從mpu3050的驅動註冊中也能夠發現,其注重實現的爲probe與電源管理,其中probe最爲重要(好像是廢話,哪一個驅動這個都是最重要的-。-)。由於主要是從驅動的角度看待I2C子系統,因此這裏不詳盡分析mpu3050的代碼,只以其爲例說明I2C驅動大致框架。在mpu3050的probe主要對此傳感器進行上電、工做模式初始化、註冊INPUT子系統接口、關聯中斷處理程序(在中斷處理線程中上報三軸參數)等工做。
I2C設備驅動一般只是須要掛載在I2C總線(即依附於I2C子系統),I2C子系統對於設備驅動來講只是一個載體、基石。許多設備的主要核心是創建在其餘子系統上,如重力傳感器、三軸傳感器、觸摸屏等一般主要工做集中在INPUT子系統中,而相機模塊、FM模塊、GPS模塊大多主要依附於V4L2子系統。這也能經過I2C設計理念證實,I2C的產生正是爲了節省外圍電路複雜度,讓CPU使用有限的IO口掛載更多的外部模塊。假設CPU的擴展IO口足夠多,我想I2C也沒什麼必要存在了,畢竟直接操做IO口驅動設備比I2C來的更簡單。
如上表所示,對於I2C adapter的註冊有兩種途徑:i2c_add_adapter 或i2c_add_numbered_adapter,二者的區別是後者在註冊時已經指定了此I2C適配器的總線號,而前者的總線號將由系統自動分配。
其各自的聲明格式爲:
int i2c_add_adapter(struct i2c_adapter *adapter) int i2c_add_numbered_adapter(struct i2c_adapter *adap)
在i2c_add_numberd_adapter使用前必須制定adap->nr,若是給-1,說明仍是叫系統去自動生成總線號的。
之因此區分開兩種I2C adapter的註冊方式,是由於他們的使用場景有所不一樣。
i2c_add_adapter的使用常常是用來註冊那些可插拔設備,如USB PCI設備等。主板上的其餘模塊與其沒有直接聯繫,說白了就是現有模塊不在意新加入的I2C適配器的總線號是多少,由於他們不須要。反而這個可插拔設備上的一些模塊會須要其註冊成功的適配器指針。回看一開始就分析的i2c_client,會發現不一樣場景的設備與其匹配的適配器有着這樣的對應關係:
1. i2c_register_board_info須要指定已有的busnum,而i2c_add_numbered_adapter註冊前已經指定總線號; 2. i2c_new_device須要指定adapter指針,而i2c_add_adapter註冊成功後剛好這個指針就有了。
想象這樣一個場景:新設備插入後,對應的驅動程序經過i2c_add_adapter註冊本身的I2C適配器,而後根據與小弟們的協定將其是適配器指針存放在某處,至關於對小弟們(依附在其上的I2C設備)說:「看見沒?大家註冊大家本身的設備的時候就經過這個就能找到我,就能跟我混了!」而後驅動程序繼續,當執行到對本身的I2C設備註冊時候,小弟們去約定地點找老大留下的記號,發現有效信息後,蜂擁而上:「看!老大在那!!!」
i2c_add_numbered_adapter用來註冊CPU自帶的I2C適配器,或是集成在主板上的I2C適配器。主板上的其餘I2C從設備(client)在註冊時候須要這個總線號。
經過簡短的代碼分析看一看他們的區別究竟如何,以及爲何靜態註冊的i2c_client必需要在adapter註冊前(此處會精簡部分代碼,只留重要部分):
int i2c_add_adapter(struct i2c_adapter *adapter) { int id, res = 0; res = idr_get_new_above(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, &id); //動態獲取總線號 adapter->nr = id; return i2c_register_adapter(adapter); //註冊adapter } int i2c_add_numbered_adapter(struct i2c_adapter *adap) { int id; int status; if (adap->nr == -1) /* -1 means dynamically assign bus id */ return i2c_add_adapter(adap); status = i2c_register_adapter(adap); return status; }
可見,最終他們都是經過i2c_register_adapter註冊適配器:
static int i2c_register_adapter(struct i2c_adapter *adap) { int res = 0; /* Can't register until after driver model init */ //時序檢查 if (unlikely(WARN_ON(!i2c_bus_type.p))) { res = -EAGAIN; goto out_list; } /* Sanity checks */ if (unlikely(adap->name[0] == '\0')) { //防護型代碼,檢查適配器名稱 pr_err("i2c-core: Attempt to register an adapter with " "no name!\n"); return -EINVAL; } if (unlikely(!adap->algo)) { //適配器是否已經完成了通訊方法的實現 pr_err("i2c-core: Attempt to register adapter '%s' with " "no algo!\n", adap->name); return -EINVAL; } rt_mutex_init(&adap->bus_lock); mutex_init(&adap->userspace_clients_lock); INIT_LIST_HEAD(&adap->userspace_clients); /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; dev_set_name(&adap->dev, "i2c-%d", adap->nr); adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type; res = device_register(&adap->dev); //註冊設備節點 if (res) goto out_list; /* create pre-declared device nodes */ //建立預-聲明的I2C設備節點 if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); //若是adapter的總線號小於動態分配的總線號的最小那個,說明是板級adapter。 //由於經過i2c_add_adapter加入的適配器所分配的總線號必定是比__i2c_first_dynamic_bus_num大的。 ... }
對於i2c_add_numbered_adapter來講會觸發i2c_scan_static_board_info:
static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo; down_read(&__i2c_board_lock); //持有讀寫鎖的讀,有用戶讀的時候不容許寫入 list_for_each_entry(devinfo, &__i2c_board_list, list) { //又見__i2c_board_list,這不是經過i2c_register_board_info組建起來的那個鏈表嗎! if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info)) //找到總線號與剛註冊的這個adapter相同的並經過i2c_new_device進行註冊 dev_err(&adapter->dev, "Can't create device at 0x%02x\n", devinfo->board_info.addr); } up_read(&__i2c_board_lock); //釋放讀寫鎖 }
而i2c_board_info成員與i2c_client的對應動做也是在i2c_new_device中進行的,這一點在上邊已經分析過了。看到這裏,對adapter與client的微妙關係應該瞭解程度就比較深了,爲何說i2c_register_board_info與i2c_add_numbered_adapter對應而不是i2c_add_adapter也能夠說得通。
那麼,最終回答開篇提出的那兩個問題:
i2c_adapter驅動如何添加?
板級適配器(CPU自帶、主板集成)要經過i2c_add_numbered_adapter註冊,註冊前要指定總線號,從0開始。假如板級I2C適配器註冊了3個,那麼第一個動態總線號必定是3,也就是說可插拔設備所帶有的I2C適配器須要經過i2c_add_adapter進行註冊,其總線號由系統指定。
i2c_client與i2c_board_info到底是什麼關係?
i2c_client與i2c_board_info的對應關係在i2c_new_device中有完總體現。
i2c_client->dev.platform_data = i2c_board_info->platform_data; i2c_client->dev.archdata = i2c_board_info->archdata; i2c_client->flags = i2c_board_info->flags; i2c_client->addr = i2c_board_info->addr; i2c_client->irq = i2c_board_info->irq;