LV030-虚拟pinctrl驱动实例
来写一个虚拟的 pinctrl 子系统的驱动程序?。若笔记中有错误或者不合适的地方,欢迎批评指正 😃。
一、编写 pinctrl 驱动程序要做什么?
1. pinctrl 三大作用
- (1)引脚枚举与命名(Enumerating and naming):包括单个引脚和各组引脚。
- (2)引脚复用(Multiplexing):比如用作 GPIO、I2C 或其他功能。
- (3)引脚配置(Configuration):比如上拉、下拉、open drain、驱动强度等。
2. 做哪些事?
- pin controller:
(1)创建设备树节点

(2)编写驱动程序
- 开发板测试
(1)创建 client 设备树节点
(2)编写驱动程序
二、编写虚拟 pinctrl 程序实例
1. 硬件功能
假设这个虚拟的 pin controller 有 4 个引脚:
- pin0,1,2,3 都可以配置为 GPIO 功能。
- pin0,1 还可以配置为 I2C 功能。
- pin2,3 还可以配置为 UART 功能。
2. 编写设备树文件
/ {
model = "Freescale i.MX6 UlltraLite ALPHA EMMC Board";
compatible = "fsl,imx6ull-alpha-emmc", "fsl,imx6ull";
alpha {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
//......
virtual_pincontroller {
compatible = "alpha,virtual_pinctrl";
i2cgrp: i2cgrp {
functions = "i2c", "i2c";
groups = "pin0", "pin1";
configs = <0x11223344 0x55667788>;
};
};
virtual_i2c {
compatible = "alpha,virtual_i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2cgrp>;
};
};
};编译完设备树,就更新到开发板上去。更新成功可以看到如下节点:

3. 驱动程序
3.1 pinctrl 驱动
核心是 pinctrl_desc:分配、设置和注册 pinctrl_desc 结构体。这里是一个 platform_driver。可以看这里:31_pinctrl_gpio_subsystem/03_virtual_pinctrl/drivers_demo/virtual_pinctrl_driver.c
3.2 client 驱动
编写、注册一个 platform_driver 即可。可以看这里:31_pinctrl_gpio_subsystem/03_virtual_pinctrl/drivers_demo/virtual_pinctrl_client.c
三、调试虚拟的 pinctrl
1. 开发板准备
1.1 设备树
前面更新了设备树,注意更新。
1.2 加载驱动
这个需要加载两个驱动:
insmod ./virtual_pinctrl_driver.ko
insmod ./virtual_pinctrl_client.ko
2. 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 值 |
2.1 单个引脚信息
# 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/alpha:virtual_pincontroller/pins
2.2 引脚的组信息
# 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/alpha:virtual_pincontroller/pingroups
2.3 单个引脚的复用信息
# 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)以刚才我们的设备树为例就是:
cat /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pinmux-pins
2.4 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/alpha:virtual_pincontroller/pinmux-functions
2.5 单个引脚的配置
# 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/alpha:virtual_pincontroller/pinconf-pins
2.6 引脚组的配置
# 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以刚才我们的设备树为例就是:
cat /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pinconf-groups
3. 修改配置值
在内核源码中为我们提供了下面的函数来修改配置值
// 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以上面的设备树为例就是:
echo "modify config_pin virtual_i2c default pin0 0xaabb" > /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pinconf-config
cat /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pinconf-config
不过上面失败了,没太搞明白为啥,不过这里主要是了解虚拟 pinctrl 子系统的实例,这里先不管了,后面有需要再说。
参考资料: