Pinctrl 与 GPIO 子系统

一、Pinctrl 子系统

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"

五、嵌入式建议