资讯中心

Linux内核学习4--Pinctrl子系统

📅 2026/8/6 17:53:55
Linux内核学习4--Pinctrl子系统
1 前言这一篇2月就TODO了因为之前一直没怎么用到所以拖到现在。因为我之前一直用树莓派或者esp32这些感觉GPIO这些就是直接用就完了所以Pinctrl的概念一直不明白最近因为主动请缨申请了点屏幕要用到这个所以再看看。这里不写原理了只写用法。26年重写这一篇是24年写的那个时候刚接触底层不久所以很多内容写的不好现在26年整体重写一下。2 Pinctrl基础2.1 Pinctrl原理首先还是简单看看硬件吧在现代硬件中处理I2CSPI这些都是一个单独的硬件核如下是一个I2C的处理核。一个总线处理核心会对应几个输出引脚但是如果每个引脚都固定成某个用途就太浪费管脚了。所以在MU/SOC中内部有一个引脚复用矩阵Pinmux可以动态配置这个管脚连接哪个控制器UART/I2C/SPI...。下面这个是STM32 F407的例子可以看到很多个控制器。有GPIOTIMSDIOUARTSPII2C。暴露的引脚可以通过配置寄存器连接需要的控制器。通过修改寄存器来完成配置。Pinctrl其实就是封装了上面这些操作将修改寄存器的操作对一般内核开发不可见驱动直接操作API接口就行了。此外还有一些需要配置的内容。比如这个引脚是用推挽Push-Pull还是开漏Open-Drain驱动电流要开到4\mA还是12mA需不需要打开上拉电阻抵消噪声它的复用通道是AF7还是AF0这些现在也都是Pinctrl子系统来配置。2.2 Pinctrl组成pinctrl 子系统在系统中大概是这个位置GPIO/I2C/SPI的底层。pinctrl 子系统的代码主要位于 Linux 内核源码树的以下目录中核心代码drivers/pinctrl/设备树支持Documentation/devicetree/bindings/pinctrl/头文件include/linux/pinctrl/其实内容真的不算很多。核心就是几个文件。大部分内容都是各家的适配。比较奇怪华子米子蓝绿这些牛比哄哄的厂商没看到。3 Pinctrl源码这里只是简单看看。3.1 基本流程Pinctrl向下接口/* include/linux/pinctrl/pinctrl.h */ struct pinctrl_desc { const char *name; /* 控制器名称如 msm-tlmm */ const struct pinctrl_pin_desc *pins; /* 芯片所有的引脚列表数组 */ unsigned int npins; /* 引脚总数 */ /* 三大核心操作集回调 */ const struct pinctrl_ops *pctlops; /* 1. 管脚组 (Pin Group) 查询与管理 */ const struct pinmux_ops *pmxops; /* 2. 管脚复用 (Pin Muxing) 控制 */ const struct pinconf_ops *confops; /* 3. 管脚配置 (Pin Configuration) 控制 */ struct module *owner; };提供的核心状态切换函数/* drivers/pinctrl/core.c */ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) { struct pinctrl_setting *setting; /* 如果当前已经是该状态避免重复配置 */ if (p-state state) return 0; /* 遍历这个 state 里的所有 setting 项复用配置 电气配置 */ list_for_each_entry(setting, state-settings, node) { switch (setting-type) { case PINCTRL_SETTING_TYPE_MUX: /* 1. 触发复用切换回调底层驱动去写 MUX 寄存器 */ setting-pctldev-desc-pmxops-set_mux( setting-pctldev, setting-data.mux.func, setting-data.mux.group ); break; case PINCTRL_SETTING_TYPE_CONFIG_GROUP: /* 2. 触发电气属性回调底层驱动去写 CONFIG 寄存器 */ setting-pctldev-desc-confops-pin_config_group_set( setting-pctldev, setting-data.configs.group_or_pin, setting-data.configs.configs, setting-data.configs.num_configs ); break; default: break; } } /* 更新设备当前的引脚状态 */ p-state state; return 0; } EXPORTS_SYMBOL_GPL(pinctrl_select_state);3.2 子节点很多时候SPI都是子节点的形式。比如qupv3_se3_spi { status okay; pinctrl-names default, sleep; pinctrl-0 qupv3_se3_spi_active, qupv3_se3_spi_cs1_active; pinctrl-1 qupv3_se3_spi_sleep, qupv3_se3_spi_cs1_sleep; goodix_fp1 { compatible xxx,xxxxxxx; reg 1; interrupt-parent tlmm; interrupts 149 IRQ_TYPE_EDGE_FALLING; spi-max-frequency 50000000; gf,gpio_rst tlmm 58 0x0; gf,gpio_irq tlmm 149 0x0; gf,gpio_vdd pmar2230_gpios 9 GPIO_ACTIVE_HIGH; pinctrl-names gf_vdd_high, gf_vdd_low, gf_reset_high, gf_reset_low; pinctrl-0 gf_vdd_high_default; pinctrl-1 gf_vdd_low_default; pinctrl-2 gf_reset_high; pinctrl-3 gf_reset_low; status okay; }; };这种是怎么实现的呢首先还是调用的父节点的SPI这里也就是平台的SPI控制器的驱动。控制器驱动完成后内核SPI系统会去扫描下面的SPI节点然后去调用子节点的驱动。父节点调用of_register_spi_devices去扫描子节点创建spi device。static void of_register_spi_devices(struct spi_controller *ctlr) { struct device_node *nc; if (!ctlr-dev.of_node) return; /* 遍历 SPI 控制器 DTS 节点下的所有子节点 */ for_each_available_child_of_node(ctlr-dev.of_node, nc) { if (of_node_test_and_set_flag(nc, OF_POPULATED)) continue; /* 为每个 available 的子节点创建并注册 spi_device */ of_register_spi_device(ctlr, nc); } }读取SPI子节点信息。static struct spi_device *of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc) { struct spi_device *spi; int rc; u32 value; /* 分配 spi_device 结构体关联父控制器 */ spi spi_alloc_device(ctlr); if (!spi) return ERR_PTR(-ENOMEM); /* 1. 解析片选号 reg 1 */ rc of_property_read_u32(nc, reg, value); if (rc) { dev_err(ctlr-dev, %pOF has no valid reg property (%d)\n, nc, rc); goto err_of_node_put; } spi-chip_select[0] value; /* 2. 解析最大频率 spi-max-frequency 50000000 */ rc of_property_read_u32(nc, spi-max-frequency, value); if (rc) { dev_err(ctlr-dev, %pOF has no valid spi-max-frequency property (%d)\n, nc, rc); goto err_of_node_put; } spi-max_speed_hz value; /* 3. 解析并绑定 DTS 节点信息 */ of_node_get(nc); spi-dev.of_node nc; /* 4. 将设备注册到 SPI 总线 */ rc spi_add_device(spi); if (rc) { goto err_of_node_put; } return spi; err_of_node_put: spi_dev_put(spi); return ERR_PTR(rc); }最后注册设备并加载驱动。int spi_add_device(struct spi_device *spi) { struct device *dev spi-dev; int status; /* 关联 SPI 总线类型 (spi_bus_type) */ dev-bus spi_bus_type; /* 初始化设备名称例如: spi3.1 (控制器编号.片选号) */ dev_set_name(dev, %s.%u, dev_name(spi-controller-dev), spi_get_chipselect(spi, 0)); /* 将设备注册进内核总线 */ status device_add(dev); if (status 0) { dev_err(dev, cant add %s, status %d\n, dev_name(dev), status); return status; } /* 注册成功后Linux 设备驱动模型bus_probe_device * 会自动寻找 compatible 匹配的驱动匹配成功即触发指纹驱动的 probe() */ return 0; }4 Pinctrl使用Pintrl内部有啥我不想去看了估计也不会去改。主要还是看看怎么去改大致方法有以下这些方法修改位置生效时间典型场景Device TreeDTS/DTSI开机现代 Linux BSPPinctrl API驱动代码运行时Active/Sleep切换BootloaderU-BootLinux启动前调试串口、DDR寄存器直写驱动或应用运行时调试验证pinctrl命令用户空间运行时树莓派devmem用户空间运行时临时调试4.1 设备树Linux 设备驱动模型driver_probe_device()在调用设备的 probe() 之前会自动检查设备的 DTS 中是否有 pinctrl-names default。举个UART配置的例子pinctrl { /* 在源码中节点本身的名字就是天然的指针Label不需要指定 0x20 */ uart1_pins: uart1-pins-node { /* 用官方头文件里的宏取代难懂的 0x18 0x1C */ pinmux RK_GPIO1_D0 RK_FUNC_UART1, /* 假设是瑞芯微GPIO1_D0 作为 UART1 */ RK_GPIO1_D1 RK_FUNC_UART1; bias-disable; }; }; /* 2. 租户外设直接引用上面的 Label */ uart1 { pinctrl-names default; /* 直接用 符号去引用上面的标签编译器在编译时会自动帮你把这里换算成 0x20 这样的十六进制 */ pinctrl-0 uart1_pins; status okay; };在这个示例中uart1_pins 定义了UART1的引脚配置指定了 PINMUX_UART1_TX 和 PINMUX_UART1_RX 的引脚复用同时禁用了引脚的上拉或下拉偏置。uart1 节点引用了这些引脚配置并将其应用到 UART1 设备。DTS里面的pinmux 属性指定了引脚的复用设置如 UART1 TX 和 RX引脚具体值由 SoC 数据手册定义。bias-disable 和 bias-pull-up 是引脚配置属性用于配置引脚的上拉/下拉电阻。drive-strength 属性配置了引脚驱动强度。再给一个配置成SPI的例子引脚控制器节点/* 树莓派原厂基础设备树里spi0*/ spi0: spi400000 { compatible brcm,bcm2712-spi; reg 0x400000 0x100; #address-cells 1; #size-cells 0; /* 原厂默认把 Pinctrl 配置绑在 spi0 上了 */ pinctrl-names default; pinctrl-0 spi0_pins; /* 这里的 spi0_pins 定义在原厂的 pinctrl 节点下 */ status disabled; /* 默认是关闭的 */ };compatible 属性指定了SPI控制器的驱动。reg 属性指定了引脚控制器的寄存器地址和大小。这里的0x100表示0x00到0xff一个寄存器占4个字节所以一共差不多64个寄存器。#address-cells 和 #size-cells 属性定义了子节点的地址和大小单元。pinctrl-single,register-width 和 pinctrl-single,function-mask 是特定引脚控制器的属性用于配置引脚复用寄存器的宽度和功能掩码。所以可以看出这里的pinctrl支持的是一大组寄存器。这部分的配置不同厂商可能差别很大。4.2 驱动代码修改目前在驱动中修改pinctrl也基本上要基于设备树来实现。设备树pinctrl { /* 菜单一正常工作时的引脚状态 */ my_uart_working: uart-working-node { pinmux RK_GPIO1_D0 RK_FUNC_UART1, RK_GPIO1_D1 RK_FUNC_UART1; bias-disable; /* 正常工作不加内部电阻 */ }; /* 菜单二低功耗休眠时的引脚状态 */ my_uart_sleep: uart-sleep-node { pinmux RK_GPIO1_D0 RK_FUNC_GPIO, /* 强行降级为普通 GPIO 模式 */ RK_GPIO1_D1 RK_FUNC_GPIO; bias-pull-down; /* 强行内部下拉接地防止悬空漏电 */ }; }; my_hardware_device { compatible my-vendor,low-power-device; status okay; /* 关键起名字告诉内核这属于不同的状态 */ pinctrl-names active, sleep; pinctrl-0 my_uart_working; /* 对应第 0 个名字 active */ pinctrl-1 my_uart_sleep; /* 对应第 1 个名字 sleep */ };代码#include linux/module.h #include linux/platform_device.h #include linux/pinctrl/consumer.h /* 必须包含这个核心头文件 */ #include linux/slab.h // 自定义设备私有结构体 struct my_device_private { struct pinctrl *pinctrl; // 总管句柄 struct pinctrl_state *state_active; // 工作状态菜单 struct pinctrl_state *state_sleep; // 休眠状态菜单 }; static int my_driver_probe(struct platform_device *pdev) { struct device *dev pdev-dev; struct my_device_private *priv; int ret; dev_info(dev, Driver probing...\n); priv devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; platform_set_drvdata(pdev, priv); /* ---------------------------------------------------- * 第一步获取该设备的 pinctrl 总管句柄 * ---------------------------------------------------- */ priv-pinctrl devm_pinctrl_get(dev); if (IS_ERR(priv-pinctrl)) { dev_err(dev, Failed to get pinctrl handle\n); return PTR_ERR(priv-pinctrl); } /* ---------------------------------------------------- * 第二步顺着设备树里的 pinctrl-names把状态菜单抠出来 * ---------------------------------------------------- */ priv-state_active pinctrl_lookup_state(priv-pinctrl, active); if (IS_ERR(priv-state_active)) { dev_err(dev, Cannot find active pinctrl state\n); return PTR_ERR(priv-state_active); } priv-state_sleep pinctrl_lookup_state(priv-pinctrl, sleep); if (IS_ERR(priv-state_sleep)) { dev_err(dev, Cannot find sleep pinctrl state\n); return PTR_ERR(priv-state_sleep); } /* ---------------------------------------------------- * 第三步默认初始化让引脚进入 active 状态工作 * ---------------------------------------------------- */ ret pinctrl_select_state(priv-pinctrl, priv-state_active); if (ret) { dev_err(dev, Failed to select active state\n); return ret; } dev_info(dev, Pinctrl initialized to ACTIVE mode.\n); return 0; } /* ---------------------------------------------------- * 第四步在需要切换状态的业务函数中比如电源管理 PM 接口动态切换 * ---------------------------------------------------- */ static int my_driver_suspend(struct device *dev) { struct my_device_private *priv dev_get_drvdata(dev); int ret; dev_info(dev, Device going to sleep, switching pinctrl...\n); /* 一句话物理芯片引脚瞬间断开 UART 复用全部拉低接地 */ ret pinctrl_select_state(priv-pinctrl, priv-state_sleep); if (ret) { dev_err(dev, Failed to switch to sleep pinctrl state\n); return ret; } return 0; } static int my_driver_resume(struct device *dev) { struct my_device_private *priv dev_get_drvdata(dev); int ret; dev_info(dev, Device waking up, restoring pinctrl...\n); /* 一句话物理铁轨瞬间拨回串口重新接通 */ ret pinctrl_select_state(priv-pinctrl, priv-state_active); if (ret) { dev_err(dev, Failed to restore active pinctrl state\n); return ret; } return 0; } // 绑定 PM 休眠唤醒的回调函数 static const struct dev_pm_ops my_driver_pm_ops { .suspend my_driver_suspend, .resume my_driver_resume, }; static const struct of_device_id my_driver_dt_ids[] { { .compatible my-vendor,low-power-device }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, my_driver_dt_ids); static struct platform_driver my_platform_driver { .probe my_driver_probe, .driver { .name my_low_power_driver, .of_match_table my_driver_dt_ids, .pm my_driver_pm_ops, // 挂载电源管理支持 }, }; module_platform_driver(my_platform_driver); MODULE_LICENSE(GPL); MODULE_AUTHOR(Senior Embedded Engineer);在这个示例中驱动程序在 probe 函数中获取 pinctrl 句柄查找 default 状态并将其应用到设备。这样设备的引脚配置将在设备初始化时自动设置。4.3 直接改寄存器writel( 0x02, TLMM_BASE 0x1000);或者使用命令devmem这部分要查一下收据手册怎么用了。。。4.4 内核接口可以使用/sys/kernel/debug/pinctrl/下面的接口mount -t debugfs none /sys/kernel/debug ls /sys/kernel/debug/pinctrl/ tomraspberrypi:~/dttest$ cat /sys/kernel/debug/pinctrl/1f000d0000.gpio-pinctrl-rp1/ gpio-ranges pinconf-groups pinconf-pins pingroups pinmux-functions pinmux-pins pinmux-select pins文件作用类比pinsSoC所有管脚的静态信息硬件手册pinmux-pins当前管脚被谁占用、配置成什么功能运行状态查看pinmux-pinstomraspberrypi:~/dttest$ cat /sys/kernel/debug/pinctrl/1f000d0000.gpio-pinctrl-rp1/pinmux-pins Pinmux settings per pin Format: pin (name): mux_owner gpio_owner hog? pin 0 (gpio0): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 1 (gpio1): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 2 (gpio2): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 3 (gpio3): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 4 (gpio4): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 5 (gpio5): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 6 (gpio6): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 7 (gpio7): 1f00050000.spi pinctrl-rp1:578 function spi0 group gpio7 pin 8 (gpio8): 1f00050000.spi pinctrl-rp1:579 function spi0 group gpio8 pin 9 (gpio9): 1f00050000.spi (GPIO UNCLAIMED) function spi0 group gpio9 pin 10 (gpio10): 1f00050000.spi (GPIO UNCLAIMED) function spi0 group gpio10 pin 11 (gpio11): 1f00050000.spi (GPIO UNCLAIMED) function spi0 group gpio11 pin 12 (gpio12): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 13 (gpio13): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 14 (gpio14): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 15 (gpio15): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 16 (gpio16): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 17 (gpio17): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 18 (gpio18): 1f00054000.spi pinctrl-rp1:589 function gpio group gpio18 pin 19 (gpio19): 1f00054000.spi (GPIO UNCLAIMED) function spi1 group gpio19 pin 20 (gpio20): 1f00054000.spi (GPIO UNCLAIMED) function spi1 group gpio20 pin 21 (gpio21): 1f00054000.spi (GPIO UNCLAIMED) function spi1 group gpio21 pin 22 (gpio22): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 23 (gpio23): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 24 (gpio24): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 25 (gpio25): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 26 (gpio26): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 27 (gpio27): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 28 (gpio28): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 29 (gpio29): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 30 (gpio30): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 31 (gpio31): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 32 (gpio32): (MUX UNCLAIMED) pinctrl-rp1:603 pin 33 (gpio33): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 34 (gpio34): (MUX UNCLAIMED) pinctrl-rp1:605 pin 35 (gpio35): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 36 (gpio36): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 37 (gpio37): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 38 (gpio38): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 39 (gpio39): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 40 (gpio40): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 41 (gpio41): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 42 (gpio42): 1f00200000.usb (GPIO UNCLAIMED) function vbus1 group gpio42 pin 43 (gpio43): 1f00200000.usb (GPIO UNCLAIMED) function vbus1 group gpio43 pin 44 (gpio44): (MUX UNCLAIMED) pinctrl-rp1:615 pin 45 (gpio45): 1f0009c000.pwm (GPIO UNCLAIMED) function pwm1 group gpio45 pin 46 (gpio46): (MUX UNCLAIMED) pinctrl-rp1:617 pin 47 (gpio47): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 48 (gpio48): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 49 (gpio49): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 50 (gpio50): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 51 (gpio51): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 52 (gpio52): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 53 (gpio53): (MUX UNCLAIMED) (GPIO UNCLAIMED)查看pinstomraspberrypi:~/dttest$ cat /sys/kernel/debug/pinctrl/1f000d0000.gpio-pinctrl-rp1/pins registered pins: 54 pin 0 (gpio0) 0:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 1 (gpio1) 1:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 2 (gpio2) 2:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 3 (gpio3) 3:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 4 (gpio4) 4:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 5 (gpio5) 5:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 6 (gpio6) 6:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 7 (gpio7) 7:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 8 (gpio8) 8:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 9 (gpio9) 9:pinctrl-rp1 function alt0 (spi0) in lo; irq 0 (none) pin 10 (gpio10) 10:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 11 (gpio11) 11:pinctrl-rp1 function gpio (gpio) in lo; irq 0 (none) pin 12 (gpio12) 12:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 13 (gpio13) 13:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 14 (gpio14) 14:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 15 (gpio15) 15:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 16 (gpio16) 16:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 17 (gpio17) 17:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 18 (gpio18) 18:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 19 (gpio19) 19:pinctrl-rp1 function alt0 (spi1) in lo; irq 0 (none) pin 20 (gpio20) 20:pinctrl-rp1 function alt0 (spi1) in lo; irq 0 (none) pin 21 (gpio21) 21:pinctrl-rp1 function alt0 (spi1) in lo; irq 0 (none) pin 22 (gpio22) 22:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 23 (gpio23) 23:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 24 (gpio24) 24:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 25 (gpio25) 25:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 26 (gpio26) 26:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 27 (gpio27) 27:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 28 (gpio28) 28:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 29 (gpio29) 29:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 30 (gpio30) 30:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 31 (gpio31) 31:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 32 (gpio32) 32:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 33 (gpio33) 33:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 34 (gpio34) 34:pinctrl-rp1 function gpio (gpio) in lo; irq 0 (none) pin 35 (gpio35) 35:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 36 (gpio36) 36:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 37 (gpio37) 37:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 38 (gpio38) 38:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 39 (gpio39) 39:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 40 (gpio40) 40:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 41 (gpio41) 41:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 42 (gpio42) 42:pinctrl-rp1 function alt2 (vbus1) in hi; irq 0 (none) pin 43 (gpio43) 43:pinctrl-rp1 function alt2 (vbus1) in hi; irq 0 (none) pin 44 (gpio44) 44:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 45 (gpio45) 45:pinctrl-rp1 function alt0 (pwm1) in hi; irq 0 (none) pin 46 (gpio46) 46:pinctrl-rp1 function gpio (gpio) in lo; irq 0 (none) pin 47 (gpio47) 47:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 48 (gpio48) 48:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 49 (gpio49) 49:pinctrl-rp1 function gpio (gpio) in hi; irq 0 (none) pin 50 (gpio50) 50:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 51 (gpio51) 51:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 52 (gpio52) 52:pinctrl-rp1 function none (none) in lo; irq 0 (none) pin 53 (gpio53) 53:pinctrl-rp1 function none (none) in hi; irq 0 (none)还可以用pinconf-pins这个可以查看pull-uppull-downdrive strengthinput enableoutput enable。4.5 命令修改在树莓派提供了工具pinctrl 修改这个具体用法看帮助吧。tomraspberrypi:~/dttest$ pinctrl -hWARNING! pinctrl set writes directly to the GPIO control registersignoring whatever else may be using them (such as Linux drivers) -it is designed as a debug tool, only use it if you know what youare doing and at your own risk!Running pinctrl with the help argument prints this help.pinctrl can get and print the state of a GPIO (or all GPIOs)and can be used to set the function, pulls and value of a GPIO.pinctrl must be run as root (or as a member of group gpioon RPiOS).Use:pinctrl [-p] [-v] get [GPIO]ORpinctrl [-p] [-v] [-e] set GPIO [options]ORpinctrl [-p] [-v] poll GPIOORpinctrl [-p] [-v] funcs [GPIO]ORpinctrl [-p] [-v] lev [GPIO]ORpinctrl -c chip [funcs] [GPIO]ORpinctrl -lGPIO is a comma-separated list of GPIO names, numbers or ranges (withoutspaces), e.g. 4 or 18-21 or BT_ON,9-11Note that omitting [GPIO] from pinctrl get prints all GPIOs.If the -p option is given, GPIO numbers are replaced by pin numbers on the40-way header. If the -v option is given, the output is more verbose. Includingthe -e option in a set causes pinctrl to echo back the new pin states.pinctrl funcs will dump all the possible GPIO alt functions in CSV formator if [GPIO] is specified the alternate funcs just for that specific GPIO.The -c option allows the alt functions (and only the alt function) for a namedchip to be displayed, even if that chip is not present in the current system.The -l option lists the discovered chips.Valid [options] for pinctrl set are:ip set GPIO as inputop set GPIO as outputa0-a8 set GPIO to alt function in the range 0 to 8 (range varies by model)no set GPIO to no function (NONE)pu set GPIO in-pad pull uppd set GPIO in-pad pull downpn set GPIO pull none (no pull)dh set GPIO to drive high (1) level (only valid if set to be an output)dl set GPIO to drive low (0) level (only valid if set to be an output)Examples:pinctrl get Prints state of all GPIOs one per linepinctrl get 10 Prints state of GPIO10pinctrl get 10,11 Prints state of GPIO10 and GPIO11pinctrl set 10 a2 Set GPIO10 to fsel 2 function (nand_wen_clk)pinctrl -e set 10 pu Enable GPIO10 ~50k in-pad pull up, echoing the resultpinctrl set 10 pd Enable GPIO10 ~50k in-pad pull downpinctrl set 10 op Set GPIO10 to be an outputpinctrl set 10 dl Set GPIO10 to output low/zero (must already be set as an output)pinctrl set 10 ip pd Set GPIO10 to input with pull downpinctrl set 35 a1 pu Set GPIO35 to fsel 1 (jtag_2_clk) with pull uppinctrl set 20 op pn dh Set GPIO20 to output with no pull and driving highpinctrl lev 4 Prints the level (1 or 0) of GPIO4pinctrl -c bcm2835 9-11 Display the alt functions for GPIOs 9-11 on bcm2835pinctrl -l List the compatible detected GPIO chips不过这个工具只在树莓派上有高通或者其它平台还是用/sys/kernel/debug/pinctrl/吧。5 小结Pinctrl主要就是配置了引脚用了哪些管脚这些管脚复用为什么功能这些管脚的初始状态是什么。其实就是为了简化移植而来的如果整个功能从A板移植到B板那么驱动代码不用动使用代码不用动设备树要动但是不多就一点点。日常中遇到引脚配置错误那么一般排查流程如下# 看GPIO是否被占用cat /sys/kernel/debug/gpio# 看当前复用cat /sys/kernel/debug/pinctrl/*/pinmux-pins# 看可选功能cat /sys/kernel/debug/pinctrl/*/pins# 看设备树是否生效dmesg | grep pinctrl修改的方法一般是/sys/kernel/debug/pinctrl 查看当前Pinctrl状态Device Tree 永久修改pinctrl_select_state() 驱动动态修改devmem 临时强制修改参考https://blog.csdn.net/qq_33141353/category_11633447.html