Pinctrl 与 GPIO 子系统
一、Pinctrl 子系统
- pinctrl(Pin Controller):管理 SoC 的引脚复用(mux)、配置(bias、drive strength、speed)
- 设备树中描述 + 驱动在 probe 时应用
1. 设备树
&iomuxc {
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
>;
};
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6UL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1
MX6UL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1
>;
};
};
mydevice {
pinctrl-0 = <&pinctrl_uart1>;
pinctrl-names = "default";
};
格式:PAD_NAME__ALT_FUNCTION PAD_CONFIG
- PAD_CONFIG 是上拉、下拉、驱动强度等参数
2. 驱动中获取
// 通常 pinctrl 在 probe 时由 core 自动应用(基于 pinctrl-0/1/...)
// 手动控制(少见)
struct pinctrl *p = devm_pinctrl_get(dev);
struct pinctrl_state *s1 = pinctrl_lookup_state(p, "default");
pinctrl_select_state(p, s1);
二、GPIO 子系统
1. 设备树
leds {
compatible = "gpio-leds";
led-status {
label = "status";
gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
default-state = "off";
linux,default-trigger = "heartbeat";
};
};
keys {
compatible = "gpio-keys";
key-power {
label = "Power";
gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
linux,code = <KEY_POWER>;
debounce-interval = <20>;
wakeup-source;
};
};
2. 老 API(<linux/gpio.h> / sysfs)
#include <linux/gpio.h>
int gpio = 17;
gpio_request(gpio, "led");
gpio_direction_output(gpio, 1);
gpio_set_value(gpio, 0);
gpio_direction_input(gpio);
gpio_get_value(gpio);
gpio_free(gpio);
注意:此 API 已废弃,新代码用 gpiochip + desc
3. 新 API(descriptor,<linux/gpio/consumer.h>)
#include <linux/gpio/consumer.h>
struct gpio_desc *desc = devm_gpiod_get(dev, "led", GPIOD_OUT_LOW);
// "led" 对应设备树 "led-gpios" 属性
// GPIOD_OUT_LOW / GPIOD_OUT_HIGH / GPIOD_IN
gpiod_set_value(desc, 1);
gpiod_set_value(desc, 0);
int v = gpiod_get_value(desc);
// 调试
gpiod_direction_output(desc, 1);
gpiod_export(desc, false); // 导出到 /sys/class/gpio(调试)
// 中断
struct gpio_desc *btn = devm_gpiod_get(dev, "btn", GPIOD_IN);
int irq = gpiod_to_irq(btn);
request_irq(irq, btn_handler, IRQF_TRIGGER_FALLING, "btn", dev);
设备树对应:
mydevice {
led-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; // led-gpios → "led"
btn-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; // btn-gpios → "btn"
};
4. GPIO chip 驱动(SoC 层)
struct gpio_chip chip = {
.label = "mygpio",
.request = my_request,
.free = my_free,
.direction_input = my_dir_in,
.direction_output = my_dir_out,
.get = my_get,
.set = my_set,
.base = 0,
.ngpio = 32,
.parent = &pdev->dev,
};
gpiochip_add_data(&chip, priv);
// 旧
gpiochip_add(&chip);
5. 用户态 API
# sysfs(老)
echo 17 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio17/direction
echo 1 > /sys/class/gpio/gpio17/value
# 新
ls /dev/gpiochip0
gpiodetect
gpioinfo
gpioset 0 17=1
gpioget 0 17
三、IRQ 子系统
// 设备树
mydriver {
interrupt-parent = <&gpio2>;
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
// 或 interrupt-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
};
// 驱动
int irq = of_irq_get(np, 0);
request_threaded_irq(irq, ...);
四、Pinctrl / GPIO 调试
# 内核
cat /sys/kernel/debug/pinctrl/<chip>/pinmux-pins
cat /sys/kernel/debug/gpio
# 用户态
gpiodetect
gpioinfo gpiochip0
gpiofind "myvendor,mybutton"
五、嵌入式建议
- 用设备树 + 新 GPIO API
- 不要直接写寄存器(用 pinctrl + GPIO chip)
- 设备树中定义全部 pin group
- 探针检查 pin 是否被占用