注:文章都是通过阅读各位前辈总结的资料 Android 11.0 && Linux(Kernel 4.19)Rockchip平台源码、加上自己的思考分析总结出来的,其中难免有理解不对的地方,欢迎大家批评指正。文章为个人学习、研究、欣赏之用,图文内容整理自互联网,如有侵权,请联系删除(◕‿◕),转载请注明出处(©Rockchip ©Android @Linux 版权所有),谢谢。
(==文章基于 Kernel-4.19 ==)&&(==文章基于 Android 11.0 ==)
【zhoujinjian.com博客原图链接】
【开发板 RockPi4bPlusV1.6】
[【开发板 RockPi4bPlusV1.6 Android 11.0 && Linux(Kernel 4.19)源码链接】](repo init -u https://github.com/radxa/manifests.git -b Android11_Radxa_rk11.1 -m rockchip-r-release.xml)
正是由于前人(各位大神)的分析和总结,帮助我节约了大量的时间和精力,特别感谢,由于不喜欢图片水印,去除了水印,敬请谅解!!!
【嵌入式Linux全新系列教程之驱动大全(基于IMX6ULL开发板)】
1. Pinctrl作用
Pinctrl:Pin Controller,顾名思义,就是用来控制引脚的:
引脚枚举与命名(Enumerating and naming)
引脚复用(Multiplexing):比如用作GPIO、I2C或其他功能
引脚配置(Configuration):比如上拉、下来、open drain、驱动强度等
Pinctrl驱动由芯片厂家的BSP工程师提供,一般的驱动工程师只需要在设备树里:
在一般的设备驱动程序里,甚至可以没有pinctrl的代码。
对于一般的驱动工程师,只需要知道“怎么使用pinctrl”即可。
2. Pinctrl子系统使用示例
查看原理图确定使用哪些引脚:比如pinA、pinB
生成pincontroller设备树信息
选择功能:比如把pinA配置为I2C_SCL、把pinB配置为I2C_SDA
配置:比如把pinA、pinB配置为open drain
使用pincontroller设备树信息:比如在i2c节点里定义”pinctrl-names”、”pinctrl-0”
2.1 pinctrl信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 pinctrl: pinctrl { compatible = "rockchip,rk3399-pinctrl"; rockchip,grf = <&grf>; rockchip,pmu = <&pmugrf>; # address-cells = <2>; # size-cells = <2>; ranges; ...... i2c0 { i2c0_xfer: i2c0-xfer { rockchip,pins = <1 RK_PB7 RK_FUNC_2 &pcfg_pull_none>, <1 RK_PC0 RK_FUNC_2 &pcfg_pull_none>; }; }; ...... }
2.2. 在client节点使用pinctrl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 i2c0: i2c@ff3c0000 { compatible = "rockchip,rk3399-i2c"; reg = <0x0 0xff3c0000 0x0 0x1000>; assigned-clocks = <&pmucru SCLK_I2C0_PMU>; assigned-clock-rates = <200000000>; clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>; clock-names = "i2c", "pclk"; interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH 0>; pinctrl-names = "default"; pinctrl-0 = <&i2c0_xfer>; # address-cells = <1>; # size-cells = <0>; status = "disabled"; };
2.3. 使用过程 这是透明的,我们的驱动基本不用管。当设备切换状态时,对应的pinctrl就会被调用。
比如在platform_device和platform_driver的枚举过程中,流程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 [2021 /8 /30 14 :49 :52 ] [ 1.021595 ] enable function i2c0 group i2c0-xfer [2021 /8 /30 14 :49 :52 ] [ 1.021615 ] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.19 .111 #20 [2021 /8 /30 14 :49 :52 ] [ 1.021630 ] Hardware name: ROCKPI 4B (DT) [2021 /8 /30 14 :49 :52 ] [ 1.021639 ] Call trace: [2021 /8 /30 14 :49 :52 ] [ 1.021654 ] dump_backtrace+0x0 /0x178 [2021 /8 /30 14 :49 :52 ] [ 1.021669 ] show_stack+0x14 /0x20 [2021 /8 /30 14 :49 :52 ] [ 1.021684 ] dump_stack+0x94 /0xb4 [2021 /8 /30 14 :49 :52 ] [ 1.021702 ] rockchip_pmx_set+0x188 /0x198 [2021 /8 /30 14 :49 :52 ] [ 1.021721 ] pinmux_enable_setting+0x1a8 /0x270 [2021 /8 /30 14 :49 :52 ] [ 1.021737 ] pinctrl_commit_state+0xe4 /0x168 [2021 /8 /30 14 :49 :52 ] [ 1.021750 ] pinctrl_select_state+0x18 /0x28 [2021 /8 /30 14 :49 :52 ] [ 1.021767 ] pinctrl_bind_pins+0x13c /0x150 [2021 /8 /30 14 :49 :52 ] [ 1.021782 ] really_probe+0x6c /0x2b0 [2021 /8 /30 14 :49 :52 ] [ 1.021798 ] driver_probe_device+0x58 /0x100 [2021 /8 /30 14 :49 :52 ] [ 1.021813 ] device_driver_attach+0x6c /0x78 [2021 /8 /30 14 :49 :52 ] [ 1.021828 ] __driver_attach+0xb0 /0xf0 [2021 /8 /30 14 :49 :52 ] [ 1.021843 ] bus_for_each_dev+0x68 /0xc8 [2021 /8 /30 14 :49 :52 ] [ 1.021858 ] driver_attach+0x20 /0x28 [2021 /8 /30 14 :49 :52 ] [ 1.021872 ] bus_add_driver+0xf8 /0x1f0 [2021 /8 /30 14 :49 :52 ] [ 1.021884 ] driver_register+0x60 /0x110 [2021 /8 /30 14 :49 :52 ] [ 1.021895 ] __platform_driver_register+0x40 /0x48 [2021 /8 /30 14 :49 :52 ] [ 1.021912 ] rk3x_i2c_driver_init+0x18 /0x20 [2021 /8 /30 14 :49 :52 ] [ 1.021928 ] do_one_initcall+0x48 /0x240 [2021 /8 /30 14 :49 :52 ] [ 1.021944 ] kernel_init_freeable+0x210 /0x37c [2021 /8 /30 14 :49 :52 ] [ 1.021960 ] kernel_init+0x10 /0x108 [2021 /8 /30 14 :49 :52 ] [ 1.021975 ] ret_from_fork+0x10 /0x18
3.Pinctrl子系统主要数据结构 3.1. 设备树 3.1.1 理想模型
3.1.2 实际的例子
RK3399
3.2. PinController的数据结构 记住pinctrl的三大作用,有助于理解所涉及的数据结构:
引脚枚举与命名(Enumerating and naming)
引脚复用(Multiplexing):比如用作GPIO、I2C或其他功能
引脚配置(Configuration):比如上拉、下来、open drain、驱动强度等
3.2.1 pinctrl_desc和pinctrl_dev 1. 结构体引入 pincontroller虽然是一个软件的概念,但是它背后是有硬件支持的,所以可以使用一个结构体来表示它:pinctrl_dev。
怎么构造出pinctrl_dev?我们只需要描述它:提供一个pinctrl_desc,然后调用pinctrl_register就可以:
1 2 struct pinctrl_dev *pinctrl_register (struct pinctrl_desc *pctldesc, struct device *dev, void *driver_data) ;
怎么使用pinctrl_desc、pinctrl_dev来描述一个pin controller?这两个结构体定义如下:
pinctrl_desc示例如下:
2. 作用1:描述、获得引脚 使用结构体pinctrl_pin_desc来描述一个引脚,一个pin controller有多个引脚:
使用pinctrl_ops来操作引脚,主要功能有二:
来取出某组的引脚:get_groups_count、get_group_pins
处理设备树中pin controller中的某个节点:dt_node_to_map,把device_node转换为一系列的pinctrl_map
3. 作用2:引脚复用
4. 作用3:引脚配置
5. 使用pinctrl_desc注册得到pinctrl_dev 调用devm_pinctrl_register或pinctrl_register,就可以根据pinctrl_desc构造出pinctrl_dev,并且把pinctrl_dev放入链表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 devm_pinctrl_register pinctrl_register pinctrl_init_controller struct pinctrl_dev *pctldev ; pctldev = kzalloc(sizeof (*pctldev), GFP_KERNEL); pctldev->owner = pctldesc->owner; pctldev->desc = pctldesc; pctldev->driver_data = driver_data; ret = pinctrl_check_ops(pctldev); ret = pinmux_check_ops(pctldev); ret = pinconf_check_ops(pctldev); ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); list_add_tail(&pctldev->node, &pinctrldev_list);
3.3 client的数据结构 在设备树中,使用pinctrl时格式如下:
1 2 3 4 5 6 /* For a client device requiring named states */ device { pinctrl-names = "active", "idle"; pinctrl-0 = <&state_0_node_a>; pinctrl-1 = <&state_1_node_a &state_1_node_b>; };
设备节点要么被转换为platform_device,或者其他结构体(比如i2c_client),但是里面都会有一个device结构体,比如:
3.3.1 dev_pin_info 每个device结构体里都有一个dev_pin_info结构体,用来保存设备的pinctrl信息:
3.3.2 pinctrl 假设芯片上有多个pin controller,那么这个设备使用哪个pin controller?
这需要通过设备树来确定:
分析设备树,找到pin controller
对于每个状态,比如default、init,去分析pin controller中的设备树节点
使用pin controller的pinctrl_ops.dt_node_to_map来处理设备树的pinctrl节点信息,得到一系列的pinctrl_map
这些pinctrl_map放在pinctrl.dt_maps链表中
每个pinctrl_map都被转换为pinctrl_setting,放在对应的pinctrl_state.settings链表中
3.3.3 pinctrl_map和pinctrl_setting 设备引用pin controller中的某个节点时,这个节点会被转换为一系列的pinctrl_map:
转换为多少个pinctrl_map,完全由具体的驱动决定
每个pinctrl_map,又被转换为一个pinctrl_setting
举例,设备节点里有:pinctrl-0 = <&state_0_node_a>
pinctrl-0对应一个状态,会得到一个pinctrl_state
state_0_node_a节点被解析为一系列的pinctrl_map
这一系列的pinctrl_map被转换为一系列的pinctrl_setting
这些pinctrl_setting被放入pinctrl_state的settings链表
3.4. 使用pinctrl_setting
调用过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 really_probe pinctrl_bind_pins pinctrl_select_state /* Apply all the settings for the new state */ list_for_each_entry(setting, &state->settings, node) { switch (setting->type) { case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_enable_setting(setting); ret = ops->set_mux(...); break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: ret = pinconf_apply_setting(setting); ret = ops->pin_config_group_set(...); break; default: ret = -EINVAL; break; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 really_probe -->pinctrl_bind_pins ---->devm_pinctrl_get ------>pinctrl_get -------->create_pinctrl(INIT_LIST_HEAD(&p->states)) (INIT_LIST_HEAD(&p->dt_maps)) ---------->pinctrl_dt_to_map ->dt_to_map_one_config ->rockchip_dt_node_to_map ---------->add_setting ------>devres_add ---->pinctrl_select_state ------>pinmux_enable_setting -------->ops->set_mux ->rockchip_pmx_set ------>pinconf_apply_setting -------->ops->pin_config_group_set
4.PinController构造过程情景分析 4.1. 设备树
4.2. 驱动代码执行流程 驱动程序位置:
1 F:\Rock4Plus_Android10\kernel\drivers\pinctrl\pinctrl-rockchip.c
调用过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 rockchip_pinctrl_probe rockchip_pinctrl_register(pdev, info); struct pinctrl_desc *ctrldesc = &info ->pctl ; struct pinctrl_pin_desc *pindesc , *pdesc ; struct rockchip_pin_bank *pin_bank ; int pin, bank, ret; int k; ctrldesc->name = "rockchip-pinctrl" ; ctrldesc->owner = THIS_MODULE; ctrldesc->pctlops = &rockchip_pctrl_ops; ctrldesc->pmxops = &rockchip_pmx_ops; ctrldesc->confops = &rockchip_pinconf_ops; pindesc = devm_kcalloc(&pdev->dev, info->ctrl->nr_pins, sizeof (*pindesc), GFP_KERNEL); ctrldesc->pins = pindesc; ctrldesc->npins = info->ctrl->nr_pins; pdesc = pindesc; for (bank = 0 , k = 0 ; bank < info->ctrl->nr_banks; bank++) { pin_bank = &info->ctrl->pin_banks[bank]; for (pin = 0 ; pin < pin_bank->nr_pins; pin++, k++) { pdesc->number = k; pdesc->name = kasprintf(GFP_KERNEL, "%s-%d" , pin_bank->name, pin); pdesc++; } } ret = rockchip_pinctrl_parse_dt(pdev, info); info->pctl_dev = devm_pinctrl_register(&pdev->dev, ctrldesc, info);
4.3. 作用1:描述、获得引脚:解析设备树 3.1 单个引脚 1 2 3 F:\Rock4Plus_Android10\kernel\drivers\pinctrl\pinctrl-rockchip.c ctrldesc->pins = pindesc; ctrldesc->npins = info->ctrl->nr_pins;
可以在开发板上查看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 rk3399_Android10:/sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl $ cat pins registered pins: 160 pin 0 (gpio0-0) ...... pin 31 (gpio0-31) pin 32 (gpio1-0) ...... pin 63 (gpio1-31) pin 64 (gpio2-0) ...... pin 95 (gpio2-31) pin 96 (gpio3-0) ...... pin 127 (gpio3-31) pin 128 (gpio4-0) ...... pin 159 (gpio4-31)
3.2 某组引脚 1 2 3 4 5 6 7 8 F:\Rock4Plus_Android10\kernel\drivers\pinctrl\pinctrl-rockchip.c static const struct pinctrl_ops rockchip_pctrl_ops = { .get_groups_count = rockchip_get_groups_count, .get_group_name = rockchip_get_group_name, .get_group_pins = rockchip_get_group_pins, .dt_node_to_map = rockchip_dt_node_to_map, .dt_free_map = rockchip_dt_free_map, };
某组引脚中,有哪些引脚?这要分析设备树:imx_pinctrl_probe_dt。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 rk3399_Android10:/sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl $ cat pingroups registered pin groups: group: clk-32k pin 0 (gpio0-0) ...... group: rgmii-pins pin 113 (gpio3-17) pin 110 (gpio3-14) pin 109 (gpio3-13) pin 108 (gpio3-12) pin 107 (gpio3-11) pin 105 (gpio3-9) pin 104 (gpio3-8) pin 103 (gpio3-7) pin 102 (gpio3-6) pin 101 (gpio3-5) pin 100 (gpio3-4) pin 99 (gpio3-3) pin 98 (gpio3-2) pin 97 (gpio3-1) pin 96 (gpio3-0) ...... group: i2c0-xfer pin 47 (gpio1-15) pin 48 (gpio1-16) ...... group: uart4-xfer pin 39 (gpio1-7) pin 40 (gpio1-8) ......
3.3 设备树解析情景分析 分析:rockchip_pinctrl_parse_dt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 F:\Rock4Plus_Android10\kernel\drivers\pinctrl\pinctrl-rockchip.c static int rockchip_pinctrl_parse_dt (struct platform_device *pdev, struct rockchip_pinctrl *info) { struct device *dev = &pdev ->dev ; struct device_node *np = dev ->of_node ; struct device_node *child ; int ret; int i; rockchip_pinctrl_child_count(info, np); dev_dbg(&pdev->dev, "nfunctions = %d\n" , info->nfunctions); dev_dbg(&pdev->dev, "ngroups = %d\n" , info->ngroups); info->functions = devm_kcalloc(dev, info->nfunctions, sizeof (struct rockchip_pmx_func), GFP_KERNEL); ...... info->groups = devm_kcalloc(dev, info->ngroups, sizeof (struct rockchip_pin_group), GFP_KERNEL); ...... i = 0 ; for_each_child_of_node(np, child) { ...... ret = rockchip_pinctrl_parse_functions(child, info, i++); ....... } return 0 ; } static int rockchip_pinctrl_parse_functions (struct device_node *np, struct rockchip_pinctrl *info, u32 index) { struct device_node *child ; struct rockchip_pmx_func *func ; struct rockchip_pin_group *grp ; int ret; static u32 grp_index; u32 i = 0 ; dev_dbg(info->dev, "parse function(%d): %s\n" , index, np->name); func = &info->functions[index]; func->name = np->name; func->ngroups = of_get_child_count(np); ...... func->groups = devm_kcalloc(info->dev, func->ngroups, sizeof (char *), GFP_KERNEL); ...... for_each_child_of_node(np, child) { func->groups[i] = child->name; grp = &info->groups[grp_index++]; ret = rockchip_pinctrl_parse_groups(child, grp, info, i++); ...... } return 0 ; } static int rockchip_pinctrl_parse_groups (struct device_node *np, struct rockchip_pin_group *grp, struct rockchip_pinctrl *info, u32 index) { struct rockchip_pin_bank *bank ; int size; const __be32 *list ; int num; int i, j; int ret; dev_dbg(info->dev, "group(%d): %s\n" , index, np->name); grp->name = np->name; list = of_get_property(np, "rockchip,pins" , &size); size /= sizeof (*list ); ...... grp->npins = size / 4 ; grp->pins = devm_kcalloc(info->dev, grp->npins, sizeof (unsigned int ), GFP_KERNEL); grp->data = devm_kcalloc(info->dev, grp->npins, sizeof (struct rockchip_pin_config), GFP_KERNEL); ...... for (i = 0 , j = 0 ; i < size; i += 4 , j++) { const __be32 *phandle; struct device_node *np_config ; num = be32_to_cpu(*list ++); bank = bank_num_to_bank(info, num); ...... grp->pins[j] = bank->pin_base + be32_to_cpu(*list ++); grp->data[j].func = be32_to_cpu(*list ++); phandle = list ++; ...... np_config = of_find_node_by_phandle(be32_to_cpup(phandle)); ret = pinconf_generic_parse_dt_config(np_config, NULL , &grp->data[j].configs, &grp->data[j].nconfigs); ...... } return 0 ; }
4.4. 作用2:引脚复用 4.5. 作用3:引脚配置 5.client端使用pinctrl过程的情景分析 5.1. 回顾client的数据结构 在设备树中,使用pinctrl时格式如下:
设备节点要么被转换为platform_device,或者其他结构体(比如i2c_client),但是里面都会有一个device结构体,比如:
1.1 dev_pin_info 每个device结构体里都有一个dev_pin_info结构体,用来保存设备的pinctrl信息:
1.2 pinctrl 假设芯片上有多个pin controller,那么这个设备使用哪个pin controller?
这需要通过设备树来确定:
分析设备树,找到pin controller
对于每个状态,比如default、init,去分析pin controller中的设备树节点
使用pin controller的pinctrl_ops.dt_node_to_map来处理设备树的pinctrl节点信息,得到一系列的pinctrl_map
这些pinctrl_map放在pinctrl.dt_maps链表中
每个pinctrl_map都被转换为pinctrl_setting,放在对应的pinctrl_state.settings链表中
1.3 pinctrl_map和pinctrl_setting 设备引用pin controller中的某个节点时,这个节点会被转换为一些列的pinctrl_map:
转换为多少个pinctrl_map,完全由具体的驱动决定
每个pinctrl_map,又被转换为一个pinctrl_setting
举例,设备节点里有:pinctrl-0 = <&state_0_node_a>
pinctrl-0对应一个状态,会得到一个pinctrl_state
state_0_node_a节点被解析为一系列的pinctrl_map
这一系列的pinctrl_map被转换为一系列的pinctrl_setting
这些pinctrl_setting被放入pinctrl_state的settings链表
5.2. client节点的pinctrl构造过程 2.1 函数调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 really_probe pinctrl_bind_pins dev-> pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL); dev-> pins->p = devm_pinctrl_get(dev); pinctrl_get create_pinctrl(dev); ret = pinctrl_dt_to_map(p); for_each_maps(maps_node, i, map) { ret = add_setting(p, map); } dev-> pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT);
2.2 情景分析 1. 设备树转换为pinctrl_map 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 really_probe -->pinctrl_bind_pins(dev) ---->devm_pinctrl_get ------>pinctrl_get -------->create_pinctrl(INIT_LIST_HEAD(&p->states)) (INIT_LIST_HEAD(&p->dt_maps)) ---------->pinctrl_dt_to_map ->dt_to_map_one_config ->rockchip_dt_node_to_map ---------->add_setting ------>devres_add F:\Rock4Plus_Android10\kernel\drivers\pinctrl\core.c static struct pinctrl *create_pinctrl (struct device *dev, struct pinctrl_dev *pctldev) { struct pinctrl *p ; const char *devname; struct pinctrl_maps *maps_node ; int i; const struct pinctrl_map *map ; int ret; p = kzalloc(sizeof (*p), GFP_KERNEL); ...... p->dev = dev; INIT_LIST_HEAD(&p->states); INIT_LIST_HEAD(&p->dt_maps); ret = pinctrl_dt_to_map(p, pctldev); ...... devname = dev_name(dev); mutex_lock(&pinctrl_maps_mutex); for_each_maps(maps_node, i, map ) { ...... ret = add_setting(p, pctldev, map ); ...... } mutex_unlock(&pinctrl_maps_mutex); ...... kref_init(&p->users); mutex_lock(&pinctrl_list_mutex); list_add_tail(&p->node, &pinctrl_list); mutex_unlock(&pinctrl_list_mutex); return p; } F:\Rock4Plus_Android10\kernel\drivers\pinctrl\devicetree.c int pinctrl_dt_to_map (struct pinctrl *p, struct pinctrl_dev *pctldev) { struct device_node *np = p ->dev ->of_node ; int state, ret; char *propname; struct property *prop ; const char *statename; const __be32 *list ; int size, config; phandle phandle; struct device_node *np_config ; ...... of_node_get(np); for (state = 0 ; ; state++) { propname = kasprintf(GFP_KERNEL, "pinctrl-%d" , state); prop = of_find_property(np, propname, &size); ..... for (config = 0 ; config < size; config++) { phandle = be32_to_cpup(list ++); np_config = of_find_node_by_phandle(phandle); ...... ret = dt_to_map_one_config(p, pctldev, statename, np_config); of_node_put(np_config); ...... } ...... } return 0 ; err: pinctrl_dt_free_maps(p); return ret; } dt_to_map_one_config ->rockchip_dt_node_to_map
2. pinctrl_map转换为pinctrl_setting 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 really_probe -->pinctrl_bind_pins(dev) ---->devm_pinctrl_get ------>pinctrl_get -------->create_pinctrl(INIT_LIST_HEAD(&p->states)) (INIT_LIST_HEAD(&p->dt_maps)) ---------->pinctrl_dt_to_map ->dt_to_map_one_config ->rockchip_dt_node_to_map ---------->add_setting ------>devres_add F:\Rock4Plus_Android10\kernel\drivers\pinctrl\core.c static int add_setting (struct pinctrl *p, struct pinctrl_dev *pctldev, const struct pinctrl_map *map ) { struct pinctrl_state *state ; struct pinctrl_setting *setting ; int ret; state = find_state(p, map ->name); ...... setting = kzalloc(sizeof (*setting), GFP_KERNEL); ...... setting->type = map ->type; if (pctldev) setting->pctldev = pctldev; else setting->pctldev = get_pinctrl_dev_from_devname(map ->ctrl_dev_name); ...... setting->dev_name = map ->dev_name; switch (map ->type) { case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_map_to_setting(map , setting); break ; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: ret = pinconf_map_to_setting(map , setting); break ; ...... } ...... list_add_tail(&setting->node, &state->settings); return 0 ; }
5.3. 切换state情景分析 3.1 函数调用过程 涉及pinctrl子系统的其他2个作用:引脚复用、引脚配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 really_probe pinctrl_bind_pins pinctrl_select_state /* Apply all the settings for the new state */ list_for_each_entry(setting, &state->settings, node) { switch (setting->type) { case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_enable_setting(setting); ret = ops->set_mux(...); break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: ret = pinconf_apply_setting(setting); ret = ops->pin_config_group_set(...); break; default: ret = -EINVAL; break; }
3.2 情景分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 [2021/8/30 14:49:52] [ 1.021595] enable function i2c0 group i2c0-xfer [2021/8/30 14:49:52] [ 1.021615] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.19.111 #20 [2021/8/30 14:49:52] [ 1.021630] Hardware name: ROCKPI 4B (DT) [2021/8/30 14:49:52] [ 1.021639] Call trace: [2021/8/30 14:49:52] [ 1.021654] dump_backtrace+0x0/0x178 [2021/8/30 14:49:52] [ 1.021669] show_stack+0x14/0x20 [2021/8/30 14:49:52] [ 1.021684] dump_stack+0x94/0xb4 [2021/8/30 14:49:52] [ 1.021702] rockchip_pmx_set+0x188/0x198 [2021/8/30 14:49:52] [ 1.021721] pinmux_enable_setting+0x1a8/0x270 [2021/8/30 14:49:52] [ 1.021737] pinctrl_commit_state+0xe4/0x168 [2021/8/30 14:49:52] [ 1.021750] pinctrl_select_state+0x18/0x28 [2021/8/30 14:49:52] [ 1.021767] pinctrl_bind_pins+0x13c/0x150 [2021/8/30 14:49:52] [ 1.021782] really_probe+0x6c/0x2b0 [2021/8/30 14:49:52] [ 1.021798] driver_probe_device+0x58/0x100 [2021/8/30 14:49:52] [ 1.021813] device_driver_attach+0x6c/0x78 [2021/8/30 14:49:52] [ 1.021828] __driver_attach+0xb0/0xf0 [2021/8/30 14:49:52] [ 1.021843] bus_for_each_dev+0x68/0xc8 [2021/8/30 14:49:52] [ 1.021858] driver_attach+0x20/0x28 [2021/8/30 14:49:52] [ 1.021872] bus_add_driver+0xf8/0x1f0 [2021/8/30 14:49:52] [ 1.021884] driver_register+0x60/0x110 [2021/8/30 14:49:52] [ 1.021895] __platform_driver_register+0x40/0x48 [2021/8/30 14:49:52] [ 1.021912] rk3x_i2c_driver_init+0x18/0x20 [2021/8/30 14:49:52] [ 1.021928] do_one_initcall+0x48/0x240 [2021/8/30 14:49:52] [ 1.021944] kernel_init_freeable+0x210/0x37c [2021/8/30 14:49:52] [ 1.021960] kernel_init+0x10/0x108 [2021/8/30 14:49:52] [ 1.021975] ret_from_fork+0x10/0x18 [2021/8/30 14:50:19] [ 0.763414] enable function gmac group rgmii-pins [2021/8/30 14:50:19] [ 0.763433] CPU: 4 PID: 1 Comm: swapper/0 Not tainted 4.19.111 #20 [2021/8/30 14:50:19] [ 0.763445] Hardware name: ROCKPI 4B (DT) [2021/8/30 14:50:19] [ 0.763456] Call trace: [2021/8/30 14:50:19] [ 0.763480] dump_backtrace+0x0/0x178 [2021/8/30 14:50:19] [ 0.763492] show_stack+0x14/0x20 [2021/8/30 14:50:19] [ 0.763507] dump_stack+0x94/0xb4 [2021/8/30 14:50:19] [ 0.763522] rockchip_pmx_set+0x188/0x198 [2021/8/30 14:50:19] [ 0.763534] pinmux_enable_setting+0x1a8/0x270 [2021/8/30 14:50:19] [ 0.763544] pinctrl_commit_state+0xe4/0x168 [2021/8/30 14:50:19] [ 0.763554] pinctrl_select_state+0x18/0x28 [2021/8/30 14:50:19] [ 0.763567] pinctrl_bind_pins+0x13c/0x150 [2021/8/30 14:50:19] [ 0.763581] really_probe+0x6c/0x2b0 [2021/8/30 14:50:19] [ 0.763593] driver_probe_device+0x58/0x100 [2021/8/30 14:50:19] [ 0.763605] device_driver_attach+0x6c/0x78 [2021/8/30 14:50:19] [ 0.763618] __driver_attach+0xb0/0xf0 [2021/8/30 14:50:19] [ 0.763629] bus_for_each_dev+0x68/0xc8 [2021/8/30 14:50:19] [ 0.763641] driver_attach+0x20/0x28 [2021/8/30 14:50:19] [ 0.763653] bus_add_driver+0xf8/0x1f0 [2021/8/30 14:50:19] [ 0.763665] driver_register+0x60/0x110 [2021/8/30 14:50:19] [ 0.763679] __platform_driver_register+0x40/0x48 [2021/8/30 14:50:19] [ 0.763693] rk_gmac_dwmac_driver_init+0x18/0x20 [2021/8/30 14:50:19] [ 0.763706] do_one_initcall+0x48/0x240 [2021/8/30 14:50:19] [ 0.763721] kernel_init_freeable+0x210/0x37c [2021/8/30 14:50:19] [ 0.763734] kernel_init+0x10/0x108 [2021/8/30 14:50:19] [ 0.763747] ret_from_fork+0x10/0x18