介绍
参考资料:
- Linux 5.x内核文档
- Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
 
 - Linux 4.x内核文档
- Documentation\pinctrl.txt
 - Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
 
 
真正去写驱动的是 bsp 工程师; 驱动工程师,只要了解,然后会用即可。
Pinctrl子系统重要概念
主要参考文档是:内核 Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
这会涉及2个对象:pin controller、client device。
- 前者提供服务:可以用它来复用引脚、配置引脚。 在芯片手册里你找不到pin controller,它是一个软件上的概念,你可以认为它对应IOMUX──用来复用引脚,还可以配置引脚(比如上下拉电阻等)。
 - 后者使用服务:声明自己要使用哪些引脚的哪些功能,怎么配置它们。 Pinctrl系统的客户,那就是使用Pinctrl系统的设备,使用引脚的设备。它在设备树里会被定义为一个节点,在节点里声明要用哪些引脚。
 
示例
上图中,左边是pin controller节点,右边是client device节点:
pin state:
上图中,pinctrl-names里定义了2种状态:default、sleep。
- 第0种状态用到的引脚在pinctrl-0中定义,它是state_0_node_a,位于pincontroller节点中。
 - 第1种状态用到的引脚在pinctrl-1中定义,它是state_1_node_a,位于pincontroller节点中。
 - 当这个设备处于default状态时,pinctrl子系统会自动根据上述信息把所用引脚复用为uart0功能。
 - 当这这个设备处于sleep状态时,pinctrl子系统会自动根据上述信息把所用引脚配置为高电平。
 
groups和function
一个设备会用到一个或多个引脚,这些引脚就可以归为一组(group);这些引脚可以复用为某个功能:function。 当然:一个设备可以用到多组引脚,比如A1、A2两组引脚,A1组复用为F1功能,A2组复用为F2功能。
Generic pin multiplexing node和Generic pin configuration node
在上图左边的pin controller节点中,有子节点或孙节点,它们是给client device使用的。
- 可以用来描述复用信息:哪组(group)引脚复用为哪个功能(function);
 - 可以用来描述配置信息:哪组(group)引脚配置为哪个设置功能(setting),比如上拉、下拉等。
 
注意:pin controller节点的格式,没有统一的标准!!!!每家芯片都不一样。 甚至上面的group、function关键字也不一定有,但是概念是有的。
代码中怎么引用pinctrl
这是透明的,我们的驱动基本不用管。当设备切换状态时,对应的pinctrl就会被调用。
比如在platform_device和platform_driver的枚举过程中,流程如下:
当系统休眠时,也会去设置该设备sleep状态对应的引脚,不需要我们自己去调用代码。
非要自己调用,也有函数:
devm_pinctrl_get_select_default(struct device *dev);      // 使用"default"状态的引脚
pinctrl_get_select(struct device *dev, const char *name); // 根据name选择某种状态的引脚
pinctrl_put(struct pinctrl *p);   // 不再使用, 退出时调用
pinctrl 使用示例
正常需要做三步:
- 哪个引脚?
 - iomux 引脚功能? i2c 还是什么?
 - 引脚配置? 开漏还是什么
 
设备树
引脚功能和引脚配置,会在设备树中体现, 可以参考 Linux-4.9.88\Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
- pinctrl 节点描述
pincontroller { ... /* Standard DT properties for the device itself elided */ state_0_node_a { ... }; state_1_node_a { ... }; state_1_node_b { ... }; } - 设备节点描述
device { pinctrl-names = "active", "idle"; pinctrl-0 = <&state_0_node_a>; pinctrl-1 = <&state_1_node_a &state_1_node_b>; }; 
pinctrl 节点
生成pincontroller设备树信息,有3中方法:
- 有些芯片有图形化的工具,可以点点鼠标就可以配置引脚信息,得到pincontroller中的信息
 - 有些芯片,只能看厂家给的设备树文档或者参考设备树的例子
 - 最差的就是需要阅读驱动代码才能构造设备树信息。
 
设备树示例
pinctrl
MX6UL_PAD_UART4_RX_DATA__I2C1_SDA          0x000018B0 左边是引脚功能,右边是引脚配置
&iomuxc {
    pinctrl-names = "default";
    pinctrl-0 = <&BOARD_InitPins>;
    imx6ull-board {
        i2c1_pins: i2c1_grp {                /*!< Function assigned for the core: Cortex-A7[ca7] */
            fsl,pins = <
                MX6UL_PAD_UART4_RX_DATA__I2C1_SDA          0x000018B0
                MX6UL_PAD_UART4_TX_DATA__I2C1_SCL          0x000018B0
            >;
        };
    };
};
设备
pinctrl-0 = <&i2c1_pins>; 使用的是 i2c1_pins: i2c1_grp 左边的标签。
&i2c1 {
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&i2c1_pins>;
    status = "okay";
};
pinctrl 主要数据结构
参考资料:
- Linux 5.x内核
- Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
 - arch/arm/boot/dts/stm32mp151.dtsi
 - arch/arm/boot/dts/stm32mp157-100ask-pinctrl.dtsi
 - arch/arm/boot/dts/stm32mp15xx-100ask.dtsi
 - drivers\pinctrl\stm32\pinctrl-stm32mp157.c
 - drivers\pinctrl\stm32\pinctrl-stm32.c
 
 - Linux 4.x内核文档
- Documentation\pinctrl.txt
 - Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
 - arch/arm/boot/dts/imx6ull-14x14-evk.dts
 - arch/arm/boot/dts/100ask_imx6ull-14x14.dts
 - drivers\pinctrl\freescale\pinctrl-imx6ul.c
 - drivers\pinctrl\freescale\pinctrl-imx.c
 
 
匹配关系
                        iomuxc: iomuxc@020e0000 {
                                compatible = "fsl,imx6ul-iomuxc";
                                reg = <0x020e0000 0x4000>;
                        };
// drivers\pinctrl\freescale\pinctrl-imx6ul.c
static struct of_device_id imx6ul_pinctrl_of_match[] = {
    { .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },
    { .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },
    { /* sentinel */ }
};
static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
    ...
    return imx_pinctrl_probe(pdev, pinctrl_info);
}
static struct platform_driver imx6ul_pinctrl_driver = {
    .driver = {
        .name = "imx6ul-pinctrl",
        .of_match_table = of_match_ptr(imx6ul_pinctrl_of_match),
    },
    .probe = imx6ul_pinctrl_probe,
};
// drivers\pinctrl\freescale\pinctrl-imx.c
int imx_pinctrl_probe(struct platform_device *pdev, struct imx_pinctrl_soc_info *info)
最终调用了 imx_pinctrl_probe 这个函数。
pinctrl_desc和pinctrl_dev
int imx_pinctrl_probe(struct platform_device *pdev, struct imx_pinctrl_soc_info *info) 中会配置 struct pinctrl_desc 这个结构体.
int imx_pinctrl_probe(struct platform_device *pdev,
              struct imx_pinctrl_soc_info *info)
{
    ...
    struct pinctrl_desc *imx_pinctrl_desc;
    ...
    imx_pinctrl_desc->name = dev_name(&pdev->dev);
    imx_pinctrl_desc->pins = info->pins;
    imx_pinctrl_desc->npins = info->npins;
    imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
    imx_pinctrl_desc->pmxops = &imx_pmx_ops;
    imx_pinctrl_desc->confops = &imx_pinconf_ops;
    imx_pinctrl_desc->owner = THIS_MODULE;
    ...
pinctrl_desc
struct pinctrl_desc {
    const char *name;
    const struct pinctrl_pin_desc *pins;
    unsigned int npins;
    const struct pinctrl_ops *pctlops;
    const struct pinmux_ops *pmxops;
    const struct pinconf_ops *confops;
    struct module *owner;
    ...
};
pinctrl_desc 中比较重要的:
pinsnpins这两个都是用来描述单个引脚的。pinctrl_pin_desc来描述一个引脚,一个pin controller有多个引脚。struct pinctrl_pin_desc { unsigned number; const char *name; void *drv_data; };pctlops操作引脚,- 来取出某组的引脚:get_groups_count、get_group_pins
 - 处理设备树中pin controller中的某个节点:dt_node_to_map,把device_node转换为一系列的pinctrl_map
struct pinctrl_ops { int (*get_groups_count) (struct pinctrl_dev *pctldev); const char *(*get_group_name) (struct pinctrl_dev *pctldev, unsigned selector); int (*get_group_pins) (struct pinctrl_dev *pctldev, unsigned selector, const unsigned **pins, unsigned *num_pins); ... int (*dt_node_to_map) (struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps); ... }; 
pmxops引脚复用struct pinmux_ops { ... int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector, unsigned group_selector); ... };confops引脚配置struct pinconf_ops { ... int (*pin_config_get) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config); int (*pin_config_set) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs); int (*pin_config_group_get) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *config); int (*pin_config_group_set) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *configs, unsigned num_configs); ...
devm_pinctrl_register
注册 pinctrl 流程:
imx_pinctrl_probe -> ipctl->pctl = devm_pinctrl_register(&pdev->dev, imx_pinctrl_desc, ipctl); -> pctldev = pinctrl_register(pctldesc, dev, driver_data);
struct pinctrl_dev *devm_pinctrl_register(struct device *dev, struct pinctrl_desc *pctldesc, void *driver_data) 输入 struct pinctrl_desc 返回的是 struct pinctrl_dev .
pinctrl_dev
struct pinctrl_dev {
    struct list_head node;
    struct pinctrl_desc *desc;
    struct radix_tree_root pin_desc_tree;
    struct list_head gpio_ranges;
    struct device *dev;
    struct module *owner;
    void *driver_data;
    struct pinctrl *p;
    struct pinctrl_state *hog_default;
    struct pinctrl_state *hog_sleep;
    struct mutex mutex;
#ifdef CONFIG_DEBUG_FS
    struct dentry *device_root;
#endif
};
- desc 指向前面构造好的 
pinctrl_desc - dev 指向 
struct device 
struct device {
    ...
    struct dev_pin_info *pins;
    ...
};
struct device中 pins 对应的struct dev_pin_info包含了 pin 的一些信息struct dev_pin_info { struct pinctrl *p; struct pinctrl_state *default_state; struct pinctrl_state *init_state; #ifdef CONFIG_PM struct pinctrl_state *sleep_state; struct pinctrl_state *idle_state; #endif };
client
设备节点设备树 对应于 client. 转化到代码中也会包含 struct device, 通过 struct dev_pin_info 来对应引脚状态。
    device { pinctrl-names = "default", "sleep";
        pinctrl-0 = <&state_0_node_a>;
        pinctrl-1 = <&state_1_node_a &state_1_node_b>; };
这个设备树中,pinctrl-names = "default", "sleep"; 对应两种状态,default 和 sleep。 对应到 struct dev_pin_info 中的 struct pinctrl_state *default_state; 和 struct pinctrl_state *sleep_state;
正常情况下,pinctrl-names 是和 dev_pin_info 中的 default, init, sleep, idle 对应起来。 如果在 pinctrl-names 中增加一个自定义的状态,比如 plane,在 dev_pin_info 中没有直接对应,那么会在 struct pinctrl *p; 的链表中。
dev_pin_info
struct dev_pin_info {
    struct pinctrl *p;
    struct pinctrl_state *default_state;
    struct pinctrl_state *init_state;
#ifdef CONFIG_PM
    struct pinctrl_state *sleep_state;
    struct pinctrl_state *idle_state;
#endif
};
struct pinctrl {
    struct list_head node;
    struct device *dev;
    struct list_head states;
    struct pinctrl_state *state;
    struct list_head dt_maps;
    struct kref users;
};
struct pinctrl_state {
    struct list_head node;
    const char *name;
    struct list_head settings;
};
struct pinctrl *p; 使用链表,链接 default, init, sleep, idle, 以及自定义的状态。
struct pinctrl_state *default_state;指向链表中的 default,其他以此类推。- default, init, sleep, idle 这几种可以通过 
dev_pin_info下面对应的指针直接访问 - 自定义状态,只能从 
struct pinctrl *p;来获取。 
设备树关联到 pinctrl_state
struct pinctrl_desc 中的 const struct pinctrl_ops *pctlops; 中的函数 int (*dt_node_to_map) (struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps);  对应到 imx_pctrl_ops.dt_node_to_map
static const struct pinctrl_ops imx_pctrl_ops = {
    .get_groups_count = imx_get_groups_count,
    .get_group_name = imx_get_group_name,
    .get_group_pins = imx_get_group_pins,
    .pin_dbg_show = imx_pin_dbg_show,
    .dt_node_to_map = imx_dt_node_to_map,
    .dt_free_map = imx_dt_free_map,
};
总体的流程: 设备树中的节点 => imx_pctrl_ops.dt_node_to_map => pinctrl_map => pinctrl_setting => pinctrl_state.settings.

pinctrl
设备使用哪个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链表中
 
 

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链表
 
 

使用pinctrl_setting
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;
            }        

Pincontroller构造过程情景分析
参考资料:
- Linux 4.x内核文档
- Documentation\pinctrl.txt
 - Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
 - arch/arm/boot/dts/imx6ull-14x14-evk.dts
 - arch/arm/boot/dts/100ask_imx6ull-14x14.dts
 - drivers\pinctrl\freescale\pinctrl-imx6ul.c
 - drivers\pinctrl\freescale\pinctrl-imx.c
 
 
源码
drivers\pinctrl\freescale\pinctrl-imx6ul.c
drivers\pinctrl\freescale\pinctrl-imx.c
调用过程:
imx6ul_pinctrl_probe
    imx_pinctrl_probe(pdev, pinctrl_info);
        imx_pinctrl_desc->name = dev_name(&pdev->dev);
        imx_pinctrl_desc->pins = info->pins;
        imx_pinctrl_desc->npins = info->npins;
        imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
        imx_pinctrl_desc->pmxops = &imx_pmx_ops;
        imx_pinctrl_desc->confops = &imx_pinconf_ops;
        imx_pinctrl_desc->owner = THIS_MODULE;
        ret = imx_pinctrl_probe_dt(pdev, info);
        ipctl->pctl = devm_pinctrl_register(&pdev->dev,
                            imx_pinctrl_desc, ipctl);
解析引脚
单个引脚
    imx_pinctrl_desc->pins = info->pins;
    imx_pinctrl_desc->npins = info->npins;
开发板查看:
# 查看 pinctrl 下面的 iomux, pinctrl-devices, pinctrl-maps 等
cd /sys/kernel/debug/pinctrl
ls
# 查看 iomuxc 下面的 pins, pinmux-pins, pinmux-functions, gpio-ranges, pinconf-config, pinconf-pins 等
cd 20e0000.iomuxc
ls
# 查看 pins
cat pins
某组引脚
比如说 i2c 引脚可能用到一组引脚(p1.1, p1.2),也可能用到另外一组引脚 (p2.2, p2.3) 等。 从设备树中,注明使用那组引脚。
static const struct pinctrl_ops imx_pctrl_ops = {
    .get_groups_count = imx_get_groups_count,
    .get_group_name = imx_get_group_name,
    .get_group_pins = imx_get_group_pins,
    .pin_dbg_show = imx_pin_dbg_show,
    .dt_node_to_map = imx_dt_node_to_map,
    .dt_free_map = imx_dt_free_map,
};
开发板查看:
# /sys/kernel/debug/pinctrl/20e0000.iomuxc
cat pingroups
dtb 反汇编 dts
dtc -I dtb -O dts 100ask_imx6ull-14x14.dtb > 1.dts
反汇编的 dts 中的 iomuxc 与 /sys/kernel/debug/pinctrl/20e0000.iomuxc 里面的 pingroups 是可以对应的上的。
分析
struct imx_pinctrl_soc_info 这个结构体会保存设备树中的很多信息:
struct imx_pinctrl_soc_info {
    struct device *dev;
    const struct pinctrl_pin_desc *pins;
    unsigned int npins;
    struct imx_pin_reg *pin_regs;
    struct imx_pin_group *groups;
    unsigned int ngroups;
    unsigned int group_index;
    struct imx_pmx_func *functions;
    unsigned int nfunctions;
    unsigned int flags;
    const char *gpr_compatible;
    /* MUX_MODE shift and mask in case SHARE_MUX_CONF_REG */
    unsigned int mux_mask;
    u8 mux_shift;
    u32 ibe_bit;
    u32 obe_bit;
};
使用 cat pinmux-functions 可以获得结果: function: imx6ul-evk, groups = [hoggrp-1 hdmigrp ... 这些可以对应到内核结构体 struct imx_pinctrl_soc_info 中, 即 nfunctions 为 1 只有imx6ul-evk, groups 就是一个数组,ngroups 就是这个数组的元素个数。
在设备树中,&iomuxc中的子节点个数,就是 nfunctions, 在这个子节点下面的子节点个数,就是 groups. 比如,imx6ull 中, pinctrl 的 function 对应的是 imx6ul-evk, groups 对应的是 pinctrl_hog_1、pinctrl_sii902x 等等。 fsl,pins 中就是对应具体的多个 pin, 每个pin 占用 24 字节。
如下面的设备树:
&iomuxc {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_hog_1>;
    imx6ul-evk {
        pinctrl_hog_1: hoggrp-1 {
            fsl,pins = <
                MX6UL_PAD_UART1_RTS_B__GPIO1_IO19   0x17059 /* SD1 CD */
                MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID    0x17059 /* USB OTG1 ID */
                // MX6UL_PAD_CSI_DATA07__GPIO4_IO28           0x000010B0
                MX6ULL_PAD_SNVS_TAMPER5__GPIO5_IO05        0x000110A0
            >;
        };
                pinctrl_sii902x: hdmigrp {
                fsl,pins = <
                        MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x59
                            >;
            };
                pinctrl_touchscreen_int: lcdif_tsc_int {
                fsl,pins = <
                        MX6UL_PAD_GPIO1_IO05__GPIO1_IO05 0x000010B0
                            >;
                        };
        pinctrl_enet1: enet1grp {
            fsl,pins = <
            >;
        };
        ...

client端使用pinctrl过程的情景分析
参考资料:
- Linux 5.x内核
- Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
 - arch/arm/boot/dts/stm32mp151.dtsi
 - arch/arm/boot/dts/stm32mp157-100ask-pinctrl.dtsi
 - arch/arm/boot/dts/stm32mp15xx-100ask.dtsi
 - drivers\pinctrl\stm32\pinctrl-stm32mp157.c
 - drivers\pinctrl\stm32\pinctrl-stm32.c
 
 - Linux 4.x内核
- Documentation\pinctrl.txt
 - Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
 - arch/arm/boot/dts/imx6ull-14x14-evk.dts
 - arch/arm/boot/dts/100ask_imx6ull-14x14.dts
 - drivers\pinctrl\freescale\pinctrl-imx6ul.c
 - drivers\pinctrl\freescale\pinctrl-imx.c
 
 
对应关系
上图中标签后面的 i2c1grp 对应的是 struct imx_pmx_func 中的 const char **groups; 这个 groups 是字符串数组,保存的就是这些 group 的名字。
struct imx_pmx_func {
    const char *name;
    const char **groups;
    unsigned num_groups;
};
数据结构

函数调用
client节点的pinctrl构造过程
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);            
state情景分析
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;
            }        
关联

编写虚拟的Pinctrl驱动程序 框架
除了 pinctrl 驱动框架,还有对应的 client 驱动框架。
编写虚拟的Pinctrl驱动程序 设置
完善除了设备树解析以外的内容。
pin_dbg_show 和 dbg 相关的,应该是作用与 /sys/kernel/debug/pinctrl 目录。
编写虚拟的Pinctrl驱动程序 设备树
解析设备树相关
调试虚拟的Pinctrl驱动程序
Pinctrl调试信息
/sys/kernel/debug/pinctrl/目录下,每一个pin controller都有一个目录,比如virtual_pincontroller。
里面有很多文件,作用如下:
| Pinctrl的虚拟文件 | 作用 | 解释 | 
|---|---|---|
| pins | 单个引脚信息 | |
| pingroups | 引脚的组信息 | |
| pinmux-pins | 单个引脚的复用信息 | |
| pinmux-functions | function下的group(支持该function的group) | |
| pinconf-pins | 单个引脚的配置 | |
| pinconf-groups | 引脚组的配置 | |
| pinconf-config | 可以通过写它修改指定设备、指定状态下、指定(组)引脚的config值 | 
单个引脚信息
cat /sys/kernel/debug/pinctrl/virtual_pincontroller/pins
registered pins: 4
pin 0 (pin0) virtual_pincontroller
pin 1 (pin1) virtual_pincontroller
pin 2 (pin2) virtual_pincontroller
pin 3 (pin3) virtual_pincontroller
引脚的组信息
cat /sys/kernel/debug/pinctrl/virtual_pincontroller/pingroups
registered pin groups:
group: pin0
pin 0 (pin0)
group: pin1
pin 1 (pin1)
group: pin2
pin 2 (pin2)
group: pin3
pin 3 (pin3)
单个引脚的复用信息
cat /sys/kernel/debug/pinctrl/virtual_pincontroller/pinmux-pins
Pinmux settings per pin
Format: pin (name): mux_owner gpio_owner hog?
pin 0 (pin0): virtual_i2c (GPIO UNCLAIMED) function i2c group pin0
pin 1 (pin1): virtual_i2c (GPIO UNCLAIMED) function i2c group pin1
pin 2 (pin2): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 3 (pin3): (MUX UNCLAIMED) (GPIO UNCLAIMED)
function下的group(支持该function的group)
cat /sys/kernel/debug/pinctrl/virtual_pincontroller/pinmux-functions
function: gpio, groups = [ pin0 pin1 pin2 pin3 ]
function: i2c, groups = [ pin0 pin1 ]
function: uart, groups = [ pin2 pin3 ]
单个引脚的配置
cat /sys/kernel/debug/pinctrl/virtual_pincontroller/pinconf-pins
Pin config settings per pin
Format: pin (name): configs
pin 0 (pin0): 0x11223344
pin 1 (pin1): 0x55667788
pin 2 (pin2): 0x0
pin 3 (pin3): 0x0
引脚组的配置
cat /sys/kernel/debug/pinctrl/virtual_pincontroller/pinconf-groups
Pin config settings per pin group
Format: group (name): configs
0 (pin0): 0x11223344
1 (pin1): 0x55667788
2 (pin2): 0x0
3 (pin3): 0x0
修改配置值
内核源码:
drivers\pinctrl\pinconf.c
    pinconf_dbg_config_write
pin controller 驱动程序中的pinconf_ops提供了pin_config_dbg_parse_modify函数,就可以通过pinconf-config文件修改某个pin或某个group的配置值。
// 格式: modify <config> <devicename> <state> <pin_name|group_name> <newvalue>
echo "modify config_pin virtual_i2c default pin0 0xaabb" > /sys/kernel/debug/pinctrl/virtual_pincontroller/pinconf-config
cat /sys/kernel/debug/pinctrl/virtual_pincontroller/pinconf-config
总结
pinctrl 驱动加载起来之后,引脚正常会被甚至为默认的 gpio 状态。 client 驱动加载起来之后,引脚才会被配置为 i2c 等功能。