歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

基於linux 3.10.49內核的pinctrl流程分析

基於linux 3.10.49內核的pinctrl流程分析

linux kernel 3.10.49+pinctrl驅動的platform注冊就不說了,

無非就是platform_driver_register這個入口,

最後匹配到合適的設備後調用struct platform_driver 的probe函數.

這裡說說, pinctl io復用關系(pinmux)的是怎麼通過device tree source(dts)設置的.

1. 首先,當然是看pinctrl驅動的probe函數(這相當於驅動初始化的入口):

drivers/pinctrl/pinctrl-xxxxxx.c : xxxxxx_pinctrl_probe(...)

xxxxxx_pinctrl_probe(...) --> pinctrl_register(...)

2. drivers/pinctrl/core.c : pinctrl_register(...)

pinctrl_register(...) --> pinctrl_get(...)

3. drivers/pinctrl/core.c : pinctrl_get(...)

pinctrl_get(...) --> create_pinctrl(...)

4. drivers/pinctrl/core.c : create_pinctrl(...)

create_pinctrl(...) --> pinctrl_dt_to_map(...)

5. drivers/pinctrl/devicetree.c : pinctrl_dt_to_map(...)

pinctrl_dt_to_map(...) --> dt_to_map_one_config(...)

6. drivers/pinctrl/devicetree.c : dt_to_map_one_config(...)

dt_to_map_one_config(...) --> ops->dt_node_to_map(...) // 回調函數. 第7~10步是進入到回調後的一系列初始化.

7. ops->dt_node_to_map 就是 drivers/pinctrl/pinctrl-xxxxxx.c 中 struct pinctrl_ops 的 dt_node_to_map成員函數指針,

也就是struct pinctrl_ops xxxxxx_pinctrl_ops->dt_node_to_map = xxxxxx_pinctrl_dt_node_to_map;

8. drivers/pinctrl/pinctrl-xxxxxx.c : xxxxxx_pinctrl_dt_node_to_map(...)

xxxxxx_pinctrl_dt_node_to_map(...) --> 輪詢調用 xxxxxx_pinctrl_dt_subnode_to_map(...)

輪詢的內容: struct device_node *np 其中一個就是 dts文件裡pinmuxing node設備, 而pinmuxing node設備有7個子node(看例子):

如: arm926u, i2c0, i2c1等.

state_default: pinmuxing {

arm926u {

xxx,function = "arm926u";

xxx,group = "arm926u";

};

i2c0 {

xxx,function = "i2c";

xxx,group = "i2c0_pos_0";

};

i2c1 {

xxx,function = "i2c";

xxx,group = "i2c1";

};

i2c2 {

xxx,function = "i2c";

xxx,group = "i2c2";

};

uart0 {

xxx,function = "uart";

xxx,group = "uart0_pos_0";

};

uart1 {

xxx,function = "uart";

xxx,group = "uart1_pos_0";

};

wdt {

xxx,function = "wdt";

xxx,group = "wdt";

};

};

9. drivers/pinctrl/pinctrl-xxxxxx.c : xxxxxx_pinctrl_dt_subnode_to_map(...)

在這裡有:

ret = of_property_read_string(np, "xxx,function", &function); // 哈哈, 解析dts node設備屬性

ret = of_property_read_string(np, "xxx,group", &group);

reserve_map(...) // allocate map內存

最後調用 add_map_mux(...);

10. drivers/pinctrl/pinctrl-xxxxxx.c : add_map_mux(...)

(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; //特別注意這個type, 後續用到

(*map)[*num_maps].data.mux.group = group; // group只是個字符串, 如:i2c0_pos_0

(*map)[*num_maps].data.mux.function = function; // function只是個字符串, 如:i2c

(*num_maps)++;

11. 回調ops->dt_node_to_map完成, 回到第6步繼續運行.

drivers/pinctrl/devicetree.c : 運行dt_remember_or_free_map(...);

12. drivers/pinctrl/devicetree.c : dt_remember_or_free_map(...)

dt_remember_or_free_map(...) --> pinctrl_register_map(...)

13. drivers/pinctrl/core.c : pinctrl_register_map(...)

判斷一下PIN_MAP_TYPE_MUX_GROUP

pinctrl_register_map(...) --> list_add_tail(&maps_node->node, &pinctrl_maps) // pinctrl_maps 是全局變量: LIST_HEAD(pinctrl_maps);

######### 到這裡, create_pinctrl(...) 的 pinctrl_dt_to_map(...) 函數已運行完成. #########

14. 回調pinctrl_dt_to_map完成, 回到第4步繼續運行. 還是在create_pinctrl(...)函數裡.

create_pinctrl(...) --> add_setting(...)

15. drivers/pinctrl/core.c : add_setting(...)

switch (map->type) {

case PIN_MAP_TYPE_MUX_GROUP:

ret = pinmux_map_to_setting(map, setting);

break;

}

add_setting(...) --> pinmux_map_to_setting(...)

16. drivers/pinctrl/pinmux.c : pinmux_map_to_setting(...)

pinmux_map_to_setting(...) --> pmxops->get_function_groups(...)

17. pmxops->get_function_groups(...) 就是 drivers/pinctrl/pinctrl-xxxxxx.c 中 struct pinmux_ops 的 get_function_groups成員函數指針,

也就是struct pinmux_ops xxxxxx_pinmux_ops->get_function_groups = xxxxxx_get_groups;

在xxxxxx_get_groups(...)函數裡:可以取到 xxxxx_groups[] = {...};的字符串數值.

ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);

// pinmux_func_name_to_selector(...) { // 函數實現

// ...

// while (selector < nfuncs) {

// const char *fname = ops->get_function_name(pctldev,

// selector); // ops->get_function_name 就是struct pinmux_ops的get_function_name 取到 i2c

// if (!strcmp(function, fname)) // function: map->data.mux.function這個就是dts的 xxx,function = "i2c";

// return selector; // fname:得到const struct xxxxxx_function xxxxxx_functions[] 第幾個是i2c,

// 所以, 代碼裡的 function 與 group 必須是一一對應的.

// selector++;

// }

// }

// ...

setting->data.mux.func = ret;

ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,

&groups, &num_groups);

// groups 等於 fname##_groups 如:const char * const i2c_groups[] = { "i2c0_pos_0", "i2c0_pos_1", "i2c1", "i2c2"}

group = map->data.mux.group; // xxx,group = "i2c0_pos_0"; //注意: 凡是map相關的, 很可能是dts的內容

for (i = 0; i < num_groups; i++) {

if (!strcmp(group, groups[i])) {

found = true;

break;

}

}

// dts的 類似於xxx,group = "i2c0_pos_0" 與通過get_function_groups獲取到代碼的 const struct xxxxxx_function xxxxxx_functions[]全局變量.

// 兩個作對比, 得到setting->data.mux.group;

ret = pinctrl_get_group_selector(pctldev, group);

// pinctrl_get_group_selector(struct pinctrl_dev *pctldev,

const char *pin_group) { // 函數實現

// ...

// while (group_selector < ngroups) {

// const char *gname = pctlops->get_group_name(pctldev,

// group_selector); // pctlops->get_group_name 就是 struct pinctrl_ops的get_group_name

// if (!strcmp(gname, pin_group)) { // pin_group: 是 xxx,group = "i2c0_pos_0";

// gname: 是 代碼裡的全局變量 const struct xxxxxx_group xxxxxx_groups[];

// dev_dbg(pctldev->dev,

// "found group selector %u for %s\n",

// group_selector,

// pin_group);

// return group_selector;

// }

// group_selector++;

// }

// ...

setting->data.mux.group = ret; // 得到setting->data.mux.group,後面給xxxxxx_enable使用(設置控制寄存器)

// 相當於, 我只要在dts中設置xxx,group = "i2c0_pos_0", pinctrl子系統就會找到對應的寄存器設置.

######### 到這裡, create_pinctrl(...) 的 add_setting(...) 函數已運行完成. #########

######### 到這裡, pinctrl_register(...) 的 pinctrl_get(...) 函數已運行完成. #########

18. 回調pinctrl_get完成, 回到第2步繼續運行. 還是在pinctrl_register(...)函數裡.

pinctrl_register(...) --> pinctrl_select_state(...)

switch (setting->type) {

case PIN_MAP_TYPE_MUX_GROUP: // 用到了.

ret = pinmux_enable_setting(setting);

break;

...

}

19. drivers/pinctrl/pinmux.c : pinmux_enable_setting(...)

pinmux_enable_setting(...) --> ops->enable(...) // 哈哈, 又是ops,回調函數,第19~20步是進入到回調後的一系列初始化.

ret = ops->enable(pctldev, setting->data.mux.func,

setting->data.mux.group);

20. ops->enable 就是 drivers/pinctrl/pinctrl-xxxxxx.c 中 struct pinmux_ops 的 enable成員函數指針,

也就是struct pinmux_ops xxxxxx_pinmux_ops->enable = xxxxxx_enable;

在xxxxxx_enable(...)函數裡:可以設置控制寄存器的值, 作為IO復用設置(這函數是內核運行完成後,應用程序修改時用到的.), 用作gpio, 還是i2c等.

######### 到這裡, pinctrl_register(...) 的 pinctrl_select_state(...) 函數已運行完成. #########

##############################################################################################

重要結構體:

1). struct pinctrl_desc: struct platform_driver的probe函數的pinctrl_register需要使用到

struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,

struct device *dev, void *driver_data);

2). struct pinctrl_ops: struct pinctrl_desc結構體需要使用到.

.get_groups_count = 需賦函數指針, --|

.get_group_name = 需賦函數指針, | 這三個函數, 需要生成一個全局變量的結構體, 指定gpio引腳控制寄存器的位移和組需要用到的引腳號.

.get_group_pins = 需賦函數指針, --|

.dt_node_to_map = 需賦函數指針, ------|

.dt_free_map = 需賦函數指針, ------| 這兩個是解析dts文件的復用信息pinmuxing到內存map 和 析構map

3). struct pinmux_ops: struct pinctrl_desc結構體需要使用到.

.gpio_request_enable = 需賦函數指針,

.gpio_disable_free = 需賦函數指針,

.request = 需賦函數指針,

.free = 需賦函數指針,

.get_functions_count = 需賦函數指針, --|

.get_function_name = 需賦函數指針, --| 這三個函數, 是直接解析dts, 用到的function 和 group, 通過function名字, 找到 group的名字(可能有多個)

.get_function_groups = 需賦函數指針, --| 再通過 group 的名字去找到gpio引腳控制寄存器的信息, 最後通過enable回調函數設置.

.enable = 需賦函數指針,

.disable = 需賦函數指針,

4). struct pinctrl_pin_desc 所有引腳號.

5). 自定義group結構體:

5-1). group的名字(也就是io復用的名字)(dts編寫時, 需要在這裡找得到),

5-2). 復用io數(如i2c, 需要使用兩個io).

5-3). 控制寄存器地址, 和使用哪幾位.

6). 自定義function結構體:

6-1). function的名字(dts編寫時, 需要在這裡找得到),

6-2). group的名字(可以有很多個, 如i2c1, i2c2等, 但也必須在自定義group結構體裡找得到)

##############################################################################################

pinctrl 運行原理:

1) 讀取dts: 先讀入dts的pinmuxing節點的信息到map;

2) dts的子節點的function 和 自定義function結構體的function的名字匹配, 得到自定義function結構體的下標, 放入Setting變量的func:

3) 由自定義function結構體的下標, 得到自定義function結構體的group的名字和數量;

4) 判斷 dts的子節點的group 是否在自定義function結構體的group的名字裡面, 如果是, 運行第5步, 否就運行第二步匹配dts下一個子節點的function;

5) dts的子節點的group 和 自定義group結構體的group的名字匹配, 得到自定義group結構體的下標, 放入Setting變量的group;

6) 通過Setting變量的func和group這兩個下標調用struct pinmux_ops的enable回調函數. 哈哈, 絡於可以設置寄存器了.

Copyright © Linux教程網 All Rights Reserved