Linux i2c子系统驱动probe
I2C 子系統
I2C 子系統使用的概率非常大,我之前有做過手機的經驗, 手機跑的安卓系統,內核是Linux,手機的很多器件都是用I2C通信的,我經歷過從板級設備到dts設備樹的階段,知道I2C在整個系統的舉足輕重,正常的TP,Camera,sonser等等都是使用I2C進行控制的。
吹牛逼這么多,就是讓大家知道理解I2C子系統的重要性,不過這篇文章就寫一個小細節,I2C驅動的probe是如何被觸發的,如果你不知道其中的原理,可能在寫驅動的時候不能成功執行probe也是有可能的。
static const struct i2c_device_id goodix_ts_id[] = { { GTP_I2C_NAME, 0 }, { } }; static struct of_device_id goodix_ts_dt_ids[] = { { .compatible = "goodix,gt9xx" }, { } }; static struct i2c_driver goodix_ts_driver = { .probe = goodix_ts_probe, .remove = goodix_ts_remove, .id_table = goodix_ts_id, .driver = { .name = GTP_I2C_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(goodix_ts_dt_ids), }, }; /******************************************************* Function: Driver Install function. Input: None. Output: Executive Outcomes. 0---succeed. ********************************************************/ static int goodix_ts_init(void) { s32 ret; /* ...... */ ret = i2c_add_driver(&goodix_ts_driver); return ret; }i2c_add_driver 驅動和設備匹配
i2c_add_driver()
i2c_register_driver?
driver_register?
driver_find?
bus_add_driver?
driver_attach?
bus_for_each_dev?
next_device
__driver_attach
driver_match_device
i2c_device_match?
acpi_driver_match_device
i2c_match_id?
of_driver_match_device?
of_match_device of_match_node
__of_match_node
__of_device_is_compatible
這個要說明的一個點是,我提出來一下,可能大家看代碼的時候就不會那么困惑了,Linux 下的指針那么多,你每次如果調用都要追根溯源,那可能需要花費非常多的時間。
總線上的device和driver進行匹配的時候會調用 bus 對應的 match函數,對于i2c bus而言就是i2c_match,如果是platform_bus 那么就會回調到platform_match里面去執行。
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, const struct i2c_client *client) { while (id->name[0]) { if (strcmp(client->name, id->name) == 0) return id; id++; } return NULL; } static int i2c_device_match(struct device *dev, struct device_driver *drv) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; if (!client) return 0; /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) return 1; /* Then ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; driver = to_i2c_driver(drv); /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; return 0; }里面有三種 match 的函數,最后才會調用 i2c_match_id 這個函數,這個也是低版本內核還沒有使用dts的時候使用的方式,也就是匹配dev和driver的name。
看下面新的?compatible 匹配方式
/** * __of_device_is_compatible() - Check if the node matches given constraints * @device: pointer to node * @compat: required compatible string, NULL or "" for any match * @type: required device_type value, NULL or "" for any match * @name: required node name, NULL or "" for any match * * Checks if the given @compat, @type and @name strings match the * properties of the given @device. A constraints can be skipped by * passing NULL or an empty string as the constraint. * * Returns 0 for no match, and a positive integer on match. The return * value is a relative score with larger values indicating better * matches. The score is weighted for the most specific compatible value * to get the highest score. Matching type is next, followed by matching * name. Practically speaking, this results in the following priority * order for matches: * * 1. specific compatible && type && name * 2. specific compatible && type * 3. specific compatible && name * 4. specific compatible * 5. general compatible && type && name * 6. general compatible && type * 7. general compatible && name * 8. general compatible * 9. type && name * 10. type * 11. name */ static int __of_device_is_compatible(const struct device_node *device, const char *compat, const char *type, const char *name) { struct property *prop; const char *cp; int index = 0, score = 0; /* Compatible match has highest priority */ if (compat && compat[0]) { /*獲取dts里面該節點的值*/ prop = __of_find_property(device, "compatible", NULL); for (cp = of_prop_next_string(prop, NULL); cp; cp = of_prop_next_string(prop, cp), index++) { /*字符串比較*/ if (of_compat_cmp(cp, compat, strlen(compat)) == 0) { score = INT_MAX/2 - (index << 2); break; } } /*返回成功*/ if (!score) return 0; } /* Matching type is better than matching name */ if (type && type[0]) { if (!device->type || of_node_cmp(type, device->type)) return 0; score += 2; } /* Matching name is a bit better than not */ if (name && name[0]) { if (!device->name || of_node_cmp(name, device->name)) return 0; score++; } return score; }代碼里面我們看到是同時比較 name ,type,compatible 這三個屬性的,但是我們使用dts進行設置的時候,name和type的屬性很多時候都是空的。
&i2c1 { status = "okay"; /* ...... */ gt9xx: gt9xx@14 { compatible = "goodix,gt9xx"; reg = <0x14>; touch-gpio = <&gpio1 0 IRQ_TYPE_EDGE_RISING>; reset-gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>; max-x = <800>; max-y = <1280>; tp-size = <89>; configfile-num = <1>; status = "okay"; tp-supply = <&vcc3v0_tp>; }; };i2c probe被探測 執行的流程
i2c_add_driver()
i2c_register_driver?
driver_register driver_find?
kset_find_obj?
kobject_put?
to_driver
bus_add_driver
driver_attach?
bus_for_each_dev?
next_device
__driver_attach
driver_match_device?
driver_probe_device?
really_probe
i2c_device_probe
i2c_match_id
你以為上面設置就好了嗎?我們看到
static struct i2c_driver goodix_ts_driver = { .probe = goodix_ts_probe, .remove = goodix_ts_remove, .id_table = goodix_ts_id, .driver = { .name = GTP_I2C_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(goodix_ts_dt_ids), }, };里面有一個 id_tabel和一個 of_match_table 兩個東西,既然probe探測只需要 of_match_tabel就可以了,是不是可以去掉id_tabel了呢?
這感覺是一個遺留問題,在i2c_probe函數里面有一個判斷,不知道歷史原因還是為何,不能做到完全兼容,看代碼如下
static int i2c_device_probe(struct device *dev) { /* ...... */ driver = to_i2c_driver(dev->driver); /* 判斷id_table為空就退出 */ if (!driver->probe || !driver->id_table) return -ENODEV; /* ...... */ }掃碼或長按關注
回復「?加群?」進入技術群聊
總結
以上是生活随笔為你收集整理的Linux i2c子系统驱动probe的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 乐谱五线谱排版软件种类与介绍
- 下一篇: 创建AD9361的vivado工程并导入