日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux i2c子系统驱动probe

發布時間:2023/12/20 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。