介绍

参考资料:

  • 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 中比较重要的:

  • pins npins 这两个都是用来描述单个引脚的。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 等功能。

发表评论