LV09-01-pinctrl和gpio子系统-02-虚拟pinctrl驱动实例

来写一个虚拟的pinctrl子系统的驱动程序?。若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
PC端开发环境 Windows Windows11
Ubuntu Ubuntu20.04.2的64位版本
VMware® Workstation 17 Pro 17.6.0 build-24238078
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
Win32DiskImager Win32DiskImager v1.0
Linux开发板环境 Linux开发板 正点原子 i.MX6ULL Linux 阿尔法开发板
uboot NXP官方提供的uboot,使用的uboot版本为U-Boot 2019.04
linux内核 linux-4.19.71(NXP官方提供)
点击查看本文参考资料
分类 网址 说明
官方网站 https://www.arm.com/ ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.nxp.com.cn/ NXP官方网站
https://www.nxpic.org.cn/NXP 官方社区
https://u-boot.readthedocs.io/en/latest/u-boot官网
https://www.kernel.org/linux内核官网
点击查看相关文件下载
分类 网址 说明
NXP https://github.com/nxp-imx NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库
nxp-imx/linux-imx/releases/tag/v4.19.71 NXP linux内核仓库tags中的v4.19.71
nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0 NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0
I.MX6ULL i.MX 6ULL Applications Processors for Industrial Products I.MX6ULL 芯片手册(datasheet,可以在线查看)
i.MX 6ULL Applications ProcessorReference Manual I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网)
Source Code https://elixir.bootlin.com/linux/latest/source linux kernel源码
kernel/git/stable/linux.git - Linux kernel stable tree linux kernel源码(官网,tag 4.19.71)
https://elixir.bootlin.com/u-boot/latest/source uboot源码

一、编写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个引脚:

image-20250401162348111
  • pin0,1,2,3都可以配置为GPIO功能。
  • pin0,1还可以配置为I2C功能。
  • pin2,3还可以配置为UART功能。

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
/ {
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>;
};
};
};

编译完设备树,就更新到开发板上去。更新成功可以看到如下节点:

image-20250402194357273

3. 驱动程序

3.1 pinctrl驱动

核心是pinctrl_desc:分配、设置和注册pinctrl_desc结构体。这里是一个platform_driver。

3.2 client驱动

编写、注册一个platform_driver即可。

三、调试虚拟的pinctrl

1. 开发板准备

1.1 设备树

前面更新了设备树,注意更新。

1.2 加载驱动

这个需要加载两个驱动:

1
insmod ./virtual_pinctrl_driver.ko
image-20250402194752814
1
insmod ./virtual_pinctrl_client.ko
image-20250402194819910

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 单个引脚信息

1
2
3
4
5
6
# 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

以刚才我们的设备树为例就是:

1
cat /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pins
image-20250402194952302

2.2 引脚的组信息

1
2
3
4
5
6
7
8
9
10
11
12
13
# 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)

以刚才我们的设备树为例就是:

1
cat /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pingroups
image-20250402195210757

2.3 单个引脚的复用信息

1
2
3
4
5
6
7
# 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)

以刚才我们的设备树为例就是:

1
cat /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pinmux-pins
image-20250402195237959

2.4 function下的group(支持该function的group)

1
2
3
4
#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 ]

以刚才我们的设备树为例就是:

1
cat /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pinmux-functions
image-20250402195311931

2.5 单个引脚的配置

1
2
3
4
5
6
7
# 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

以刚才我们的设备树为例就是:

1
cat /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pinconf-pins
image-20250402195338812

2.6 引脚组的配置

1
2
3
4
5
6
7
# 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

以刚才我们的设备树为例就是:

1
cat /sys/kernel/debug/pinctrl/alpha:virtual_pincontroller/pinconf-groups
image-20250402195414515

3. 修改配置值

在内核源码中为我们提供了下面的函数来修改配置值

1
2
// drivers/pinctrl/pinconf.c
pinconf_dbg_config_write()

如果pin controller驱动程序中的pinconf_ops提供了pin_config_dbg_parse_modify函数,就可以通过pinconf-config文件修改某个pin或某个group的配置值。

1
2
3
4
# 格式: 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

以上面的设备树为例就是:

1
2
3
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
image-20250402200113056

不过上面失败了,没太搞明白为啥,不过这里主要是了解虚拟pinctrl子系统的实例,这里先不管了,后面有需要再说。