当前位置: 首页 > news >正文

imx6ull-驱动开发篇11——gpio子系统

目录

前言

gpio 子系统简介

I.MX6ULL 的 gpio 子系统驱动

设备树中的 gpio 信息

GPIO 驱动程序简介

of_device_id 匹配表

gpio-mxc.c文件

mxc_gpio_probe函数

mxc_gpio_port 结构体

mxc_gpio_get_hw 函数

imx35_gpio_hwdata结构体

bgpio_init函数

gpio_chip 结构体

gpiochip_add函数

gpio 子系统 API 函数

设备树中添加 gpio 节点模板

创建 test 设备节点

添加 pinctrl 信息

添加 GPIO 属性信息


前言

在上一讲内容里,驱动开发篇10——pinctrl 子系统,我们已经详细地讲解了pinctrl子系统。

这一讲,我们继续学习gpio子系统,熟悉原理、掌握常用的API函数。

gpio 子系统简介

GPIO子系统架构GPIO子系统采用分层设计,主要包含以下组件:

  • GPIO芯片驱动层:直接操作硬件寄存器
  • GPIO核心层:提供通用接口和框架
  • GPIO用户接口层:向用户空间和内核其他模块提供API

gpio 子系统,用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO为输入输出,读取 GPIO 的值等。

// 申请GPIO
int gpio_request(unsigned gpio, const char *label);// 设置方向
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);// 读写操作
int gpio_get_value(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);// 释放GPIO
void gpio_free(unsigned gpio);

gpio 子系统的主要目的就是方便驱动开发者使用 gpio,驱动开发者在设备树中添加 gpio 相关信息,然后就可以在驱动程序中使用 gpio 子系统提供的 API函数来操作 GPIO,。

Linux 内核向驱动开发者屏蔽掉了 GPIO 的设置过程,极大地方便了驱动开发者使用 GPIO。

I.MX6ULL 的 gpio 子系统驱动

设备树中的 gpio 信息

我们使用正点原子的I.MX6ULL-ALPHA 开发板,以SD 卡的检测引脚为例:

打开 imx6ull-alientek-emmc.dts,有如下代码:

pinctrl_hog_1: hoggrp-1 {fsl,pins = <MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
......>;
};

将 UART1_RTS_B 这个 PIN 复用为 GPIO1_IO19,并且设置电气属性。

SD 卡连接在I.MX6ULL 的 usdhc1 接口上,在 imx6ull-alientek-emmc.dts 中找到名为“usdhc1”的节点,这个节点就是 SD 卡设备节点,如下所示:

&usdhc1 {/* 引脚控制状态名称,对应不同时钟频率下的配置 */pinctrl-names = "default", "state_100mhz", "state_200mhz";/* 各状态对应的具体引脚配置组 */pinctrl-0 = <&pinctrl_usdhc1>;        // 默认状态引脚配置pinctrl-1 = <&pinctrl_usdhc1_100mhz>; // 100MHz时钟下的引脚配置pinctrl-2 = <&pinctrl_usdhc1_200mhz>; // 200MHz时钟下的引脚配置// pinctrl-3 = <&pinctrl_hog_1>;      // 注释掉的备用配置/* SD卡检测信号配置 */cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; // 使用GPIO1_IO19作为卡检测引脚,低电平有效/* 电源管理相关配置 */keep-power-in-suspend;                 // 在挂起状态保持电源enable-sdio-wakeup;                    // 允许SDIO唤醒系统/* 电源供应配置 */vmmc-supply = <&reg_sd1_vmmc>;        // 指定3.3V电源调节器/* 设备状态 */status = "okay";                      // 启用该设备
};

其中,属性“cd-gpios”描述了 SD 卡的 CD 引脚使用的哪个 IO。

  /* SD卡检测信号配置 */cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; // 使用GPIO1_IO19作为卡检测引脚,低电平有效
  • &gpio1”表示 CD 引脚所使用的 IO 属于 GPIO1 组,
  • 19” 表示 GPIO1 组的第 19 号 IO,通过这两个值 SD 卡驱动程序就知道 CD 引脚使用了 GPIO1_IO19这 GPIO。
  • GPIO_ACTIVE_LOW”表示低电平有效,如果改为“GPIO_ACTIVE_HIGH”就表示高电平有效。

根据上面这些信息, SD 卡驱动程序就可以使用 GPIO1_IO19 来检测 SD 卡的 CD 信号。

打开 imx6ull.dtsi,关于GPIO1节点有如下所示内容:

gpio1: gpio@0209c000 {compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";  // 设备兼容性标识,支持i.MX6UL和i.MX35的GPIO驱动reg = <0x0209c000 0x4000>;                        // 寄存器物理地址范围:基地址0x0209c000,长度16KB// 中断配置:两个中断号,均采用高电平触发interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,    // 第一个中断,SPI中断号66<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;    // 第二个中断,SPI中断号67gpio-controller;                                  // 声明为GPIO控制器#gpio-cells = <2>;                                // 使用GPIO时需要2个参数:引脚号和标志位interrupt-controller;                             // 同时作为中断控制器#interrupt-cells = <2>;                           // 中断说明符需要2个参数:GPIO号和中断类型
};

gpio1 节点信息描述了 GPIO1 控制器的所有信息,重点就是 GPIO1 外设寄存器基地址以及兼容 属性 。

关 于 I.MX 系 列 SOC 的 GPIO 控 制 器 绑 定 信 息 请 查 看 文档: Documentation/devicetree/bindings/gpio/ fsl-imx-gpio.txt

reg 属性设置了 GPIO1 控制器的寄存器基地址为 0X0209C000:

reg = <0x0209c000 0x4000>; 

“#gpio-cells”属性:有两个 cell:

#gpio-cells = <2>;  
  • 第一个 cell 为 GPIO 编号,比如“&gpio1 3”就表示 GPIO1_IO03。
  • 第二个 cell 表示GPIO 极 性 , 如 果 为 0(GPIO_ACTIVE_HIGH) 的 话 表 示 高 电 平 有 效 , 如 果 为1(GPIO_ACTIVE_LOW)的话表示低电平有效。

GPIO 驱动程序简介

of_device_id 匹配表

I.MX6ULL的 GPIO 驱动文件drivers/gpio/gpio-mxc.c,有如下所示 of_device_id 匹配表:

/* * i.MX系列GPIO控制器兼容性匹配表* 用于设备树匹配和驱动初始化*/
static const struct of_device_id mxc_gpio_dt_ids[] = {/* i.MX1系列GPIO兼容性定义 */{ .compatible = "fsl,imx1-gpio",                     // 设备树兼容性字符串.data = &mxc_gpio_devtype[IMX1_GPIO],              // 指向IMX1的GPIO设备类型数据},/* i.MX21系列GPIO兼容性定义 */  {.compatible = "fsl,imx21-gpio",                    // i.MX21兼容字符串.data = &mxc_gpio_devtype[IMX21_GPIO],             // IMX21设备类型数据指针},/* i.MX31系列GPIO兼容性定义 */{.compatible = "fsl,imx31-gpio",                    // i.MX31兼容字符串.data = &mxc_gpio_devtype[IMX31_GPIO],             // IMX31设备类型数据指针},/* i.MX35系列GPIO兼容性定义 */{.compatible = "fsl,imx35-gpio",                    // i.MX35兼容字符串.data = &mxc_gpio_devtype[IMX35_GPIO],             // IMX35设备类型数据指针},/* 结束标记 */{ /* sentinel */ }
};

其中,compatible 值为“fsl,imx35-gpio”的代码,和 gpio1 的 compatible 属性匹配,因此 gpio-mxc.c 就是 I.MX6ULL 的 GPIO 控制器驱动文件。

gpio-mxc.c文件

gpio-mxc.c 文件中有如下所示内容:

/** i.MX GPIO平台驱动注册结构体* 用于向内核注册GPIO控制器驱动*/
static struct platform_driver mxc_gpio_driver = {.driver = {.name = "gpio-mxc",                    /* 驱动名称,用于/sys/bus/platform/drivers/目录 */.of_match_table = mxc_gpio_dt_ids,     /* 设备树匹配表,指向之前定义的兼容性表 */},.probe = mxc_gpio_probe,                   /* 设备探测函数,匹配成功后调用 */.id_table = mxc_gpio_devtype,              /* 设备ID表,用于非设备树的平台设备匹配 */
};

GPIO 驱动也是个平台设备驱动,因此当设备树中的设备节点与驱动的of_device_id 匹配以后 probe 函数就会执行,在这里就是 mxc_gpio_probe 函数。

mxc_gpio_probe函数

mxc_gpio_probe函数就是I.MX6ULL 的 GPIO 驱动入口函数。

/** i.MX GPIO控制器探测函数* 完成GPIO控制器的硬件初始化和驱动注册*/
static int mxc_gpio_probe(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node;  // 获取设备树节点struct mxc_gpio_port *port;                 // GPIO端口数据结构struct resource *iores;                     // IO资源指针int irq_base;                               // 中断号基址int err;                                    // 错误码// 获取硬件类型信息mxc_gpio_get_hw(pdev);// 分配端口内存空间port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);if (!port)return -ENOMEM;/*----- 硬件资源初始化 -----*/// 获取并映射寄存器资源iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);port->base = devm_ioremap_resource(&pdev->dev, iores);if (IS_ERR(port->base))return PTR_ERR(port->base);// 获取中断资源port->irq_high = platform_get_irq(pdev, 1);  // 高16位GPIO中断port->irq = platform_get_irq(pdev, 0);       // 基础中断if (port->irq < 0)return port->irq;/*----- 硬件初始化 -----*/// 禁用中断并清除状态writel(0, port->base + GPIO_IMR);    // 中断屏蔽寄存器writel(~0, port->base + GPIO_ISR);   // 中断状态寄存器/*----- 中断处理配置 -----*/if (mxc_gpio_hwtype == IMX21_GPIO) {// i.MX21系列的特殊处理irq_set_chained_handler(port->irq, mx2_gpio_irq_handler);} else {// i.MX3及后续系列的通用处理irq_set_chained_handler(port->irq, mx3_gpio_irq_handler);irq_set_handler_data(port->irq, port);// 高16位GPIO中断配置if (port->irq_high > 0) {irq_set_chained_handler(port->irq_high, mx3_gpio_irq_handler);irq_set_handler_data(port->irq_high, port);}}/*----- GPIO控制器初始化 -----*/// 使用gpiolib的通用后端初始化err = bgpio_init(&port->bgc, &pdev->dev, 4,port->base + GPIO_PSR,    // 引脚状态寄存器port->base + GPIO_DR,     // 数据寄存器NULL,port->base + GPIO_GDIR,   // 方向寄存器NULL, 0);if (err)goto out_bgio;// 设置GPIO芯片特性port->bgc.gc.to_irq = mxc_gpio_to_irq;    // 转换GPIO到IRQ的函数port->bgc.gc.base = (pdev->id < 0) ?      // GPIO编号基址of_alias_get_id(np, "gpio") * 32 : pdev->id * 32;// 注册GPIO控制器err = gpiochip_add(&port->bgc.gc);if (err)goto out_bgpio_remove;/*----- 中断域配置 -----*/// 分配中断描述符irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());if (irq_base < 0) {err = irq_base;goto out_gpiochip_remove;}// 创建IRQ域port->domain = irq_domain_add_legacy(np, 32, irq_base, 0,&irq_domain_simple_ops, NULL);if (!port->domain) {err = -ENODEV;goto out_irqdesc_free;}// 初始化通用中断芯片mxc_gpio_init_gc(port, irq_base);// 将端口添加到全局列表list_add_tail(&port->node, &mxc_gpio_ports);return 0;/*----- 错误处理路径 -----*/... 
}

让我们来详细分析一下这段代码:

mxc_gpio_port 结构体

定义一个结构体指针 port,结构体类型为 mxc_gpio_port

struct mxc_gpio_port *port;                 // GPIO端口数据结构

gpio-mxc.c 的重点工作就是维护 mxc_gpio_port, mxc_gpio_port 就是对 I.MX6ULL GPIO 的抽象。

mxc_gpio_port 结构体定义如下:

/** i.MX GPIO端口数据结构* 描述一个GPIO控制器的所有硬件和软件状态*/
struct mxc_gpio_port {struct list_head node;        // 链表节点,用于将多个GPIO端口串联到全局列表void __iomem *base;           // GPIO寄存器基地址指针(I/O映射后的虚拟地址)int irq;                      // 主中断号(处理GPIO0-15中断)int irq_high;                 // 高16位中断号(处理GPIO16-31中断,可选)struct irq_domain *domain;    // IRQ域,用于GPIO中断号映射管理struct bgpio_chip bgc;        // 通用GPIO控制器数据结构,包含:// - gpio_chip 基础结构// - 寄存器访问方法// - 状态缓存等u32 both_edges;              // 双边沿触发状态标志位,用于:// - 记录配置为双边沿触发的GPIO位// - 实现模拟双边沿触发功能
};/* * 结构体功能详解:* 1. 硬件资源管理:*    - base: 提供对GPIO控制寄存器的访问*    - irq/irq_high: 管理两组GPIO中断线** 2. 中断系统集成:*    - domain: 将GPIO引脚映射到Linux中断号*    - both_edges: 特殊处理双边沿触发模式** 3. GPIO核心框架:*    - bgpio_chip: 集成到Linux GPIO子系统*      * 包含gpio_chip基本操作*      * 实现方向控制/数值读写等标准接口** 4. 系统管理:*    - node: 允许系统遍历所有已注册的GPIO控制器** 典型使用场景:* - 每个i.MX处理器的GPIO bank对应一个port实例* - 通过base+偏移访问具体寄存器* - 通过bgc提供标准GPIO操作接口*/
mxc_gpio_get_hw 函数

调用 mxc_gpio_get_hw 函数获取 gpio 的硬件相关数据,其实就是 gpio 的寄存器组。

    // 获取硬件类型信息mxc_gpio_get_hw(pdev);

函数 mxc_gpio_get_hw 里面有如下代码:

/** mxc_gpio_get_hw - 获取i.MX GPIO控制器硬件类型和配置数据* @pdev: 平台设备指针** 根据设备树匹配结果确定具体的GPIO硬件类型,并设置对应的硬件配置数据。* 该函数在probe阶段被调用,用于初始化硬件相关参数。*/
static void mxc_gpio_get_hw(struct platform_device *pdev)
{// 通过设备树兼容性字符串匹配硬件类型const struct of_device_id *of_id = of_match_device(mxc_gpio_dt_ids, &pdev->dev);enum mxc_gpio_hwtype hwtype;/* * 硬件类型判断逻辑:* 根据of_match_table中设置的.data指针确定具体型号*/if (of_id && of_id->data) {hwtype = (enum mxc_gpio_hwtype)of_id->data;} else {/* 默认回退到最基础的类型 */hwtype = IMX1_GPIO;}// 根据硬件类型选择对应的配置数据结构if (hwtype == IMX35_GPIO)mxc_gpio_hwdata = &imx35_gpio_hwdata;      // i.MX35系列专用配置else if (hwtype == IMX31_GPIO)mxc_gpio_hwdata = &imx31_gpio_hwdata;     // i.MX31系列专用配置elsemxc_gpio_hwdata = &imx1_imx21_gpio_hwdata; // i.MX1/i.MX21通用配置// 设置全局硬件类型标识mxc_gpio_hwtype = hwtype;
}

mxc_gpio_hwdata 是个全局变量,如果硬件类型是 IMX35_GPIO 的话,设置mxc_gpio_hwdat 为 imx35_gpio_hwdata

对于 I.MX6ULL 而言,硬件类型就是 IMX35_GPIO。

imx35_gpio_hwdata结构体

imx35_gpio_hwdata 是个结构体变量,描述了 GPIO 寄存器组,内容如下:

/** i.MX35系列GPIO硬件配置数据结构* 定义i.MX35处理器的GPIO控制器寄存器布局和中断触发类型配置*/
static struct mxc_gpio_hwdata imx35_gpio_hwdata = {/* GPIO寄存器偏移地址定义 */.dr_reg        = 0x00,   // 数据寄存器:存储GPIO输入/输出值.gdir_reg      = 0x04,   // 方向寄存器:配置GPIO输入/输出模式.psr_reg       = 0x08,   // 引脚状态寄存器:读取GPIO当前电平状态.icr1_reg      = 0x0c,   // 中断配置寄存器1:配置GPIO0-15中断触发方式.icr2_reg      = 0x10,   // 中断配置寄存器2:配置GPIO16-31中断触发方式.imr_reg       = 0x14,   // 中断屏蔽寄存器:使能/禁用GPIO中断.isr_reg       = 0x18,   // 中断状态寄存器:查看触发的中断源.edge_sel_reg  = 0x1c,   // 边沿选择寄存器:用于双边沿触发配置/* 中断触发类型配置值 */.low_level     = 0x00,   // 低电平触发配置值.high_level    = 0x01,   // 高电平触发配置值.rise_edge     = 0x02,   // 上升沿触发配置值.fall_edge     = 0x03,   // 下降沿触发配置值
};

imx35_gpio_hwdata 结构体就是 GPIO 寄存器组结构。

这样我们后面就可以通过mxc_gpio_hwdata 这个全局变量来访问 GPIO 的相应寄存器了。

bgpio_init函数

bgpio_init 函数主要任务就是初始化 bgc->gc 。 bgpio_init 里 面 有 三 个 setup 函 数 : bgpio_setup_io 、bgpio_setup_accessors 和 bgpio_setup_direction。

这三个函数就是初始化 bgc->gc 中的各种有关GPIO 的操作,比如输出,输入等等。

    /*----- GPIO控制器初始化 -----*/// 使用gpiolib的通用后端初始化err = bgpio_init(&port->bgc, &pdev->dev, 4,port->base + GPIO_PSR,    // 引脚状态寄存器port->base + GPIO_DR,     // 数据寄存器NULL,port->base + GPIO_GDIR,   // 方向寄存器NULL, 0);

bgpio_init 函数第一个参数为 bgc,是 bgpio_chip 结构体指针。

bgc 既有对 GPIO 的操作函数,又有 I.MX6ULL 有关 GPIO的寄存器,那么只要得到 bgc 就可以对 I.MX6ULL 的 GPIO 进行操作。

gpio_chip 结构体

bgpio_chip结构体有个 gc 成员变量, gc 是个 gpio_chip 结构体类型的变量。 gpio_chip 结构体是抽象出来的GPIO 控制器。

gpio_chip 结构体如下所示(有缩减):

/** GPIO控制器抽象接口* 定义GPIO控制器的标准操作方法和属性*/
struct gpio_chip {const char *label;          /* 控制器标签/名称,用于标识 */struct device *dev;         /* 关联的设备结构体 */struct module *owner;       /* 所属模块(用于引用计数) */struct list_head list;      /* 全局GPIO控制器链表节点 *//*----- 核心操作函数集 -----*/int (*request)(struct gpio_chip *chip, unsigned offset);      /* GPIO引脚申请 */void (*free)(struct gpio_chip *chip,  unsigned offset);        /* GPIO引脚释放 *//* 方向控制 */int (*get_direction)(struct gpio_chip *chip,  unsigned offset); /* 获取方向 */int (*direction_input)(struct gpio_chip *chip,  unsigned offset); /* 设为输入 */int (*direction_output)(struct gpio_chip *chip,unsigned offset, int value); /* 设为输出 *//* 数值操作 */                        int (*get)(struct gpio_chip *chip,  unsigned offset);          /* 获取引脚值 */void (*set)(struct gpio_chip *chip,  unsigned offset, int value); /* 设置引脚值 */......
};

可以看出, gpio_chip 大量的成员都是函数,这些函数就是 GPIO 操作函数。

gpiochip_add函数

调用函数gpiochip_add向Linux内核注册gpio_chip,也就是 port->bgc.gc。

    // 注册GPIO控制器err = gpiochip_add(&port->bgc.gc);

注册完成以后我们就可以在驱动中使用 gpiolib 提供的各个 API 函数。

gpio 子系统 API 函数

对于驱动开发人员,设置好设备树以后就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO, gpio 子系统向驱动开发人员屏蔽了具体的读写寄存器过程。

gpio 子系统提供的常用的 API 函数有下面几个:

函数名

功能描述

​gpio_request​

申请GPIO引脚使用权(使用前必须调用)

​gpio_free​

释放已申请的GPIO资源

​gpio_direction_input​

将GPIO配置为输入模式

​gpio_direction_output​

将GPIO配置为输出模式(可设置初始输出值)

​gpio_get_value​

读取GPIO当前输入电平值

​gpio_set_value​

设置GPIO输出电平值

// 1. GPIO申请(必须首先调用)
int gpio_request(unsigned int gpio, const char *label);
/* 功能:申请GPIO引脚使用权* 参数:*   gpio  - 要申请的GPIO编号(通过of_get_named_gpio()从设备树获取)*   label - 自定义标识字符串(出现在/sys/kernel/debug/gpio中)* 返回:*   0成功,非零失败(-EBUSY表示已被占用)*/// 2. GPIO释放
void gpio_free(unsigned int gpio);
/* 功能:释放GPIO资源* 参数:*   gpio - 要释放的GPIO编号*/// 3. 设置为输入模式
int gpio_direction_input(unsigned int gpio);
/* 功能:配置GPIO为输入方向* 参数:*   gpio - 要配置的GPIO编号* 返回:*   0成功,负值表示错误*/// 4. 设置为输出模式(带初始值)
int gpio_direction_output(unsigned int gpio, int value);
/* 功能:配置GPIO为输出方向并设置初始电平* 参数:*   gpio  - 要配置的GPIO编号*   value - 初始输出值(0/1)* 返回:*   0成功,负值表示错误*/// 5. 读取GPIO值(输入模式使用)
#define gpio_get_value __gpio_get_value
int __gpio_get_value(unsigned int gpio);
/* 功能:读取GPIO当前电平值* 参数:*   gpio - 要读取的GPIO编号* 返回:*   0/1  - 实际读取的电平*   负值  - 读取失败*/// 6. 设置GPIO值(输出模式使用)
#define gpio_set_value __gpio_set_value
void __gpio_set_value(unsigned int gpio, int value);
/* 功能:设置GPIO输出电平* 参数:*   gpio  - 要设置的GPIO编号*   value - 要设置的值(0/1)*/

使用举例:

#include <linux/gpio.h>// 假设从设备树获取的GPIO编号
#define LED_GPIO    123  // 输出用GPIO
#define KEY_GPIO    456  // 输入用GPIO// GPIO初始化
void gpio_init(void)
{// 1. 申请GPIOgpio_request(LED_GPIO, "my_led");gpio_request(KEY_GPIO, "my_key");// 2. 设置方向gpio_direction_output(LED_GPIO, 0); // LED初始低电平gpio_direction_input(KEY_GPIO);     // 按键输入模式
}// GPIO使用示例
void gpio_usage(void) 
{// 3. 输出控制(LED闪烁)gpio_set_value(LED_GPIO, 1); // LED亮gpio_set_value(LED_GPIO, 0); // LED灭// 4. 输入读取(按键检测)if (gpio_get_value(KEY_GPIO)) {printk("Key pressed!\n"); }
}// GPIO释放
void gpio_release(void)
{gpio_free(LED_GPIO);gpio_free(KEY_GPIO);
}

设备树中添加 gpio 节点模板

我们来学习一下如何创建 test 设备的 GPIO 节点。

创建 test 设备节点

在根节点“/”下创建 test 设备子节点,如下所示:

test {/* 节点内容 */
};

添加 pinctrl 信息

在之前的文章里,pinctrl 子系统,我们创建了 pinctrl_test 节点,此节点描述了 test 设备所使用的 GPIO1_IO00 这个 PIN 的信息。

我们要将这节点添加到 test 设备节点中,如下所示:

test {pinctrl-names = "default";pinctrl-0 = <&pinctrl_test>;/* 其他节点内容 */
};

添加 GPIO 属性信息

在 test 节点中添加 GPIO 属性信息,表明 test 所使用的 GPIO 是哪个引脚。

添加完成以后如下所示:

test {pinctrl-names = "default";pinctrl-0 = <&pinctrl_test>;gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
};

关于 pinctrl 子系统和 gpio 子系统就讲解到这里。

下一讲内容我们使用 pinctrl 和 gpio 子系统,来驱动 I.MX6ULL-ALPHA 开发板上的 LED 灯。

http://www.lryc.cn/news/612400.html

相关文章:

  • 常用排序方法
  • 排序算法归并排序
  • 单变量单步时序预测:CNN-BiGRU卷积神经网络结合双向门控循环单元
  • 202506 电子学会青少年等级考试机器人六级实际操作真题
  • 基于RPR模型的机械臂手写器simulink建模与仿真
  • Qt Frameless Widget跨平台无边框窗口
  • 机器学习-KNN​​
  • 云平台托管集群:EKS、GKE、AKS 深度解析与选型指南-第四章
  • iT 运维: WindoWs CMD 命令表
  • Flutter开发 Image组件使用示例
  • <form> + <iframe> 方式下载大文件的机制
  • 基于Github Pages搭建个人博客站点:hexo环境搭建、本地预览与发布
  • 当前就业形势下,软件测试工程师职业发展与自我提升的必要性
  • AI 软件工程开发 AI 算法 架构与业务
  • [FBCTF2019]RCEService
  • Kafka-exporter采集参数调整方案
  • android NDK 报错日志解读和还原报错方法名
  • 数语科技登陆华为云商店,助力企业释放数据潜能
  • FPGA学习笔记——VGA彩条显示
  • 【软考系统架构设计师备考笔记4】 - 英语语法一篇通
  • 机器人定位装配的精度革命:迁移科技如何重塑工业生产价值
  • Spring Boot 参数校验全指南
  • 应急响应linux
  • vue3+element-plus,el-popover实现筛选弹窗的方法
  • ACL 2025 Oral|Evaluation Agent:面向视觉生成模型的高效可提示的评估框架
  • 【关于Java的对象】
  • C++、STL面试题总结(二)
  • Android14的QS面板的加载解析
  • 【android bluetooth 协议分析 03】【蓝牙扫描详解 4】【BR/EDR扫描到设备后如何上报给app侧】
  • 力扣137:只出现一次的数字Ⅱ