介绍
参考资料:
- 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 等功能。