当前位置: 首页 > 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.dtcms.com/a/317268.html

相关文章:

  • django permission_classes = [AllowAny] 如何限制到具体接口
  • 得物向量数据库落地实践
  • 智慧二次供水管理系统解决方案:城市供水“最后一公里”
  • 【面试场景题】电商秒杀系统的库存管理设计实战
  • Docker swarm 常用的命令集合
  • 线轨矫平机:让“钢轨”变直的幕后物理课
  • 移动端网页调试实战,跨设备兼容与触控交互问题排查全流程
  • SassSCSS:让CSS拥有超能力的预处理器
  • `<dependencyManagement>`内部的`<dependencies>`和外部的`<dependencies>`的区别:
  • Spring Boot全局异常处理与日志监控实战指南
  • 浙江大学PTA程序设计C语言基础编程练习题6-10
  • Python爬虫实战:研究Photon工具,构建企业信息收集系统
  • 【Java】HashMap的key可以为null吗?如何存储的?
  • 线性代数中矩阵的基本运算运算
  • 【图像处理基石】浅谈3D城市生成中的数据融合技术
  • 分布式微服务--GateWay(1)
  • 【注意】HCIE-Datacom华为数通考试,第四季度将变题!
  • 基于Hadoop的木鸟民宿数据分析与可视化、民宿价格预测模型系统的设计与实现
  • OpenKruise
  • Linux《进程间通信(上)》
  • Git 乱码文件处理全流程指南
  • 记一次ORACLE ORA-00600 [19004] 错误的分析与解决方法
  • HarmonyOS 5 入门系列-鸿蒙HarmonyOS示例项目讲解
  • 铁路通信信号基础知识点(2)轨旁与车载ATP关系
  • 《动手学深度学习》读书笔记—9.5机器翻译与数据集
  • 虚拟机磁盘扩容
  • centos KVM
  • Java技术栈/面试题合集(19)-架构设计篇
  • Vue2中实现数据复制到 Excel
  • 【普通地质学】地球的物质组成