imx6ull-驱动开发篇10——pinctrl 子系统

目录

前言

[pinctrl 子系统](#pinctrl 子系统)

pinctrl简介

[PIN 配置信息详解](#PIN 配置信息详解)

引脚标识

寄存器值

[电气属性值 0x17059](#电气属性值 0x17059)

[PIN 驱动程序讲解](#PIN 驱动程序讲解)

[PIN 配置](#PIN 配置)

of_device_id

驱动探测函数

注册驱动

获取PIN配置

注册PIN控制器

[设备树中添加 pinctrl 节点模板](#设备树中添加 pinctrl 节点模板)

创建对应的节点

添加"fsl,pins"属性

[添加 PIN 配置信息](#添加 PIN 配置信息)


前言

在上一讲内容里,设备树下的 LED 驱动实验,我们配置 LED 灯所使用的 GPIO 寄存器,驱动开发方式和裸机基本没啥区别。

Linux 内核提供了 pinctrl 和 gpio 子系统用于GPIO 驱动,借助 pinctrl 和 gpio 子系统来简化 GPIO 驱动开发。本讲实验,我们主要学习pinctrl子系统的配置信息、理解驱动代码、学会添加pinctrl节点模板。

以控制一个 LED为例:

pinctrl 子系统

Linux 驱动讲究驱动分离与分层, pinctrl 和 gpio 子系统就是驱动分离与分层思想下的产物。

  • ​分离​​:将硬件相关的代码(如寄存器操作)与业务逻辑(如设备功能)解耦。

  • ​分层​​:通过子系统抽象硬件共性,提供统一接口,避免重复造轮子。

pinctrl简介

pinctrl 子系统:引脚复用与电气属性管理​

​功能​

  • 控制引脚的 ​​复用功能​​(如 GPIO、UART、I2C 等)

  • 配置引脚的 ​​电气属性​​(上下拉、驱动强度、斜率等)

对于我们使用者来讲,只需要在设备树里面设置好某个 pin 的相关属性即可,其他的初始化工作均由 pinctrl 子系统来完成。

pinctrl 子系统源码目录为 drivers/pinctrl。

接下来我们学习以下I.MX6ULL 的 pinctrl 子系统驱动。

PIN 配置信息详解

要使用 pinctrl 子系统,一般会在设备树里面创建一个节点来描述 PIN 的配置信息。

打开 imx6ull.dtsi 文件,找到一个叫做 iomuxc 的节点,如下所示:

cpp 复制代码
iomuxc: iomuxc@020e0000 {
    compatible = "fsl,imx6ul-iomuxc";  // 兼容性字符串,匹配i.MX6ULL的IOMUXC驱动
    reg = <0x020e0000 0x4000>;         // 寄存器基地址0x020e0000,地址空间长度16KB
};

iomuxc 节点就是 I.MX6ULL 的 IOMUXC 外设对应的节点。

再打开 imx6ull-alientek-emmc.dts,找到**iomuxc 节点,**如下所示内容:

cpp 复制代码
&iomuxc {
    pinctrl-names = "default";            // 默认引脚状态名称
    pinctrl-0 = <&pinctrl_hog_1>;        // 默认使用的引脚配置组

    /* 开发板特定引脚配置 */
    imx6ul-evk {
        /* GPIO默认配置组 */
        pinctrl_hog_1: hoggrp-1 {
            fsl,pins = <
                /* GPIO1_IO19配置:复用为GPIO,电气属性0x17059 */
                MX6UL_PAD_UART1_RTS_B__GPIO1_IO19     0x17059
                /* GPIO1_IO05配置:复用为USDHC1_VSELECT */
                MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT  0x17059
                /* GPIO1_IO09配置:复用为GPIO */
                MX6UL_PAD_GPIO1_IO09__GPIO1_IO09     0x17059
                /* GPIO1_IO00配置:复用为OTG ID检测,电气属性0x13058 */
                MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x13058
            >;
        };
......

        /* FlexCAN1控制器引脚配置 */
        pinctrl_flexcan1: flexcan1grp {
            fsl,pins = <
                /* CAN_RX信号:复用为FLEXCAN1_RX,电气属性0x1b020 */
                MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX   0x1b020
                /* CAN_TX信号:复用为FLEXCAN1_TX,电气属性0x1b020 */
                MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX   0x1b020
            >;
        };
......

        /* 看门狗引脚配置 */
        pinctrl_wdog: wdoggrp {
            fsl,pins = <
                /* 看门狗信号:复用为WDOG1_WDOG_ANY,电气属性0x30b0 */
                MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY   0x30b0
            >;
        };
    };
};

这段代码向 iomuxc 节点追加数据,不同的外设使用的 PIN 不同、其配置也不同,将某个外设所使用的所有 PIN 都组织在一个子节点里面。

以GPIO1_IO19为例:

cpp 复制代码
/* GPIO1_IO19配置:复用为GPIO,电气属性0x17059 */
  MX6UL_PAD_UART1_RTS_B__GPIO1_IO19     0x17059
cpp 复制代码
#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0

引脚标识

MX6UL_PAD_UART1_RTS_B__GPIO1_IO19

  • 前半部分:物理引脚名称,MX6UL_PAD_UART1_RTS_B物理引脚名称,对应芯片手册中的 UART1_RTS_B 引脚
  • 后半部分:配置该引脚,复用功能(GPIO1_IO19)

寄存器值

宏定义后面跟着一串数字:

cpp 复制代码
#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0

对应参数顺序:

<mux_reg,conf_reg,input_reg,mux_mode,input_val>

参数​ ​值​ ​说明​
mux_reg 0x0090 ​复用功能寄存器偏移地址​ ​(相对于IOMUXC基地址0x020E0000
conf_reg 0x031C ​电气属性寄存器偏移地址​​(相对于IOMUXC基地址)
input_reg 0x0000 ​输入寄存器偏移地址​​(此引脚无输入功能,故为0)
mux_mode 0x5 ​复用模式值​​(ALT5模式对应GPIO1_IO19功能)
input_val 0x0 ​输入功能选择值​​(未使用)

以mux_reg来看寄存器偏移,如图:

其它寄存器的具体细节,可以参考芯片手册来分析。

电气属性值 0x17059

cpp 复制代码
/* GPIO1_IO19配置:复用为GPIO,电气属性0x17059 */
  MX6UL_PAD_UART1_RTS_B__GPIO1_IO19     0x17059

i.MX6UL 的引脚控制寄存器(IOMUXC_SW_PAD_CTL_PAD_*)按以下位域定义:

​位域​ ​名称​ ​值​ ​功能说明​
16:13 HYS 0x1 输入滞后使能(抗抖动)
12 PUS 0x7 上拉/下拉选择(0=无, 1=下拉, 2=上拉)
11:10 PUE 0x0 上下拉使能(0=关闭, 3=保持器模式)
9:6 PKE 0x1 输入保持器使能
5:3 ODE 0x0 开漏输出禁用(推挽模式)
2:1 SPEED 0x2 驱动强度(00=低, 11=高)
0 SRE 0x1 压摆率(0=慢, 1=快)

0x17059的二进制展开​​:0001_0111_0000_0101_1001

对应配置:

  • HYS=1:启用输入滞后
  • PUS=7 (0111):47KΩ 上拉
  • PUE=0:关闭上下拉(PUS 优先)
  • PKE=1:启用输入保持器
  • ODE=0:推挽输出
  • SPEED=2:中速驱动
  • SRE=1:快速压摆率

PIN 驱动程序讲解

PIN 配置

在文件drivers/pinctrl/freescale/pinctrl-imx6ul.c中,有如下内容:

cpp 复制代码
/**
 * imx6ul_pinctrl_of_match - 设备树兼容性匹配表
 * 
 * 用于匹配设备树中的iomuxc节点与对应的驱动数据
 */
static struct of_device_id imx6ul_pinctrl_of_match[] = {
    { 
        .compatible = "fsl,imx6ul-iomuxc",          // 标准IOMUX控制器
        .data = &imx6ul_pinctrl_info,               // 关联i.MX6UL的引脚控制信息
    },
    { 
        .compatible = "fsl,imx6ull-iomuxc-snvs",     // SNVS域IOMUX控制器
        .data = &imx6ull_snvs_pinctrl_info,          // 关联i.MX6ULL SNVS引脚信息
    },
    { /* sentinel */ }                               // 结束标记
};

/**
 * imx6ul_pinctrl_probe - 驱动探测函数
 * @pdev: 平台设备结构体指针
 * 
 * 1. 匹配设备树节点
 * 2. 获取SoC特定引脚信息
 * 3. 调用通用pinctrl初始化
 */
static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
    const struct of_device_id *match;
    struct imx_pinctrl_soc_info *pinctrl_info;

    // 通过设备树匹配表查找对应设备
    match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);
    if (!match)
        return -ENODEV;  // 未找到匹配项

    // 获取匹配项中存储的SoC特定数据
    pinctrl_info = (struct imx_pinctrl_soc_info *)match->data;

    // 调用i.MX系列通用pinctrl初始化函数
    return imx_pinctrl_probe(pdev, pinctrl_info);
}

/**
 * imx6ul_pinctrl_driver - pinctrl平台驱动结构
 * 
 * 注册驱动到内核平台驱动框架
 */
static struct platform_driver imx6ul_pinctrl_driver = {
    .driver = {
        .name = "imx6ul-pinctrl",       // 驱动名称
        .owner = THIS_MODULE,           // 模块所有者
        .of_match_table = of_match_ptr(imx6ul_pinctrl_of_match), // 设备树匹配表
    },
    .probe = imx6ul_pinctrl_probe,      // 设备探测回调
    .remove = imx_pinctrl_remove,       // 设备移除回调
};

让我们分析这段代码:

of_device_id

of_device_id结构体数组,保存着这个驱动文件的兼容性值,设备树中的 compatible 属性值会和 of_device_id 中的所有兼容性字符串比较,查看是否可以使用此驱动。

cpp 复制代码
static struct of_device_id imx6ul_pinctrl_of_match[] = {
    { 
        .compatible = "fsl,imx6ul-iomuxc",          // 标准IOMUX控制器
        .data = &imx6ul_pinctrl_info,               // 关联i.MX6UL的引脚控制信息
    },
    { 
        .compatible = "fsl,imx6ull-iomuxc-snvs",     // SNVS域IOMUX控制器
        .data = &imx6ull_snvs_pinctrl_info,          // 关联i.MX6ULL SNVS引脚信息
    },
    { /* sentinel */ }                               // 结束标记
};

imx6ul_pinctrl_of_match 结构体数组一共有两个兼容性字符串, 分别为"fsl,imx6ul-iomuxc"和"fsl,imx6ull-iomuxc-snvs",因此 iomuxc 节点与此驱动匹配,所以 pinctrl-imx6ul.c 会完成 I.MX6ULL 的 PIN 配置工作。

驱动探测函数

imx6ul_pinctrl_probe 函数就是 I.MX6ULL 这个 SOC 的 PIN 配置入口函数:

cpp 复制代码
static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
    const struct of_device_id *match;
    struct imx_pinctrl_soc_info *pinctrl_info;

    // 通过设备树匹配表查找对应设备
    match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);
    if (!match)
        return -ENODEV;  // 未找到匹配项

    // 获取匹配项中存储的SoC特定数据
    pinctrl_info = (struct imx_pinctrl_soc_info *)match->data;

    // 调用i.MX系列通用pinctrl初始化函数
    return imx_pinctrl_probe(pdev, pinctrl_info);
}

imx6ul_pinctrl_probe 函数调用路径如下:

注册驱动

platform_driver结构体 是平台设备驱动,有个 probe 成员变量。当设备和驱动匹配成功以后, platform_driver 的 probe 成员变量所代表的函数就会执行。

cpp 复制代码
static struct platform_driver imx6ul_pinctrl_driver = {
    .driver = {
        .name = "imx6ul-pinctrl",       // 驱动名称
        .owner = THIS_MODULE,           // 模块所有者
        .of_match_table = of_match_ptr(imx6ul_pinctrl_of_match), // 设备树匹配表
    },
    .probe = imx6ul_pinctrl_probe,      // 设备探测回调
    .remove = imx_pinctrl_remove,       // 设备移除回调
};

获取PIN配置

函数 imx_pinctrl_parse_groups 负责获取设备树中关于 PIN 的配置信息:

cpp 复制代码
/*
 * fsl,pins 属性中每个引脚由5个u32(PIN_FUNC_ID)和1个u32(CONFIG)组成,
 * 因此每个引脚总共占用24字节。
 */
#define FSL_PIN_SIZE 24          // 标准引脚描述符的字节大小
#define SHARE_FSL_PIN_SIZE 20    // 共享引脚描述符的字节大小(无input_reg时)

/**
 * imx_pinctrl_parse_groups - 解析设备树中的引脚组配置
 * @np: 设备树节点指针
 * @grp: 存储解析结果的引脚组结构
 * @info: SoC特定的引脚控制器信息
 * @index: 引脚组索引
 *
 * 从设备树的fsl,pins属性中提取引脚复用和配置信息,
 * 填充到imx_pin_group结构中。
 */
static int imx_pinctrl_parse_groups(struct device_node *np,
                  struct imx_pin_group *grp,
                  struct imx_pinctrl_soc_info *info,
                  u32 index)
{
    int size, pin_size;
    const __be32 *list;  // 指向设备树属性数据的指针
    int i;
    u32 config;
......

    /* 遍历组内所有引脚 */
    for (i = 0; i < grp->npins; i++) {
        u32 mux_reg = be32_to_cpu(*list++);  // 复用寄存器地址
        u32 conf_reg;                        // 配置寄存器地址
        unsigned int pin_id;                 // 计算得到的引脚ID
        struct imx_pin_reg *pin_reg;         // 引脚寄存器信息指针
        struct imx_pin *pin = &grp->pins[i]; // 当前引脚结构
......

        /* 计算引脚ID(根据复用或配置寄存器地址) */
        pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;

        /* 存储寄存器映射信息 */
        pin_reg = &info->pin_regs[pin_id];
        pin->pin = pin_id;                   // 记录引脚ID
        grp->pin_ids[i] = pin_id;            // 存储到组ID数组
        pin_reg->mux_reg = mux_reg;          // 复用寄存器地址
        pin_reg->conf_reg = conf_reg;        // 配置寄存器地址

        /* 提取引脚功能配置 */
        pin->input_reg = be32_to_cpu(*list++);  // 输入选择寄存器
        pin->mux_mode = be32_to_cpu(*list++);   // 复用模式(ALTx)
        pin->input_val = be32_to_cpu(*list++);  // 输入功能值
......

        /* 处理SION位(特殊功能位,位于复用寄存器中) */
        config = be32_to_cpu(*list++);          // 原始配置值
        if (config & IMX_PAD_SION)
            pin->mux_mode |= IOMUXC_CONFIG_SION; // 设置SION标志位
        pin->config = config & ~IMX_PAD_SION;   // 存储清理后的配置值
    }

    return 0;
}

设备树中的 mux_reg 和 conf_reg 值会保存在 info 参数中, input_reg、mux_mode、 input_val 和 config 值会保存在 grp 参数中。

cpp 复制代码
static int imx_pinctrl_parse_groups(struct device_node *np,
                  struct imx_pin_group *grp,
                  struct imx_pinctrl_soc_info *info,
                  u32 index)

获取 mux_reg、 conf_reg、 input_reg、 mux_mode 和 input_val 值。

cpp 复制代码
        pin_reg->mux_reg = mux_reg;          // 复用寄存器地址
        pin_reg->conf_reg = conf_reg;        // 配置寄存器地址
        /* 提取引脚功能配置 */
        pin->input_reg = be32_to_cpu(*list++);  // 输入选择寄存器
        pin->mux_mode = be32_to_cpu(*list++);   // 复用模式(ALTx)
        pin->input_val = be32_to_cpu(*list++);  // 输入功能值

获取 config 值。

cpp 复制代码
pin->config = config & ~IMX_PAD_SION;   // 存储清理后的配置值

注册PIN控制器

函数 pinctrl_register,用于向 Linux 内核注册一个 PIN 控制器,原型如下:

cpp 复制代码
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,  // 描述引脚控制器的结构
                                     struct device *dev,               // 关联的硬件设备
                                     void *driver_data                 // 驱动私有数据
);
参数​ ​类型​ ​说明​
pctldesc struct pinctrl_desc* 描述引脚控制器的结构体,包含操作函数集、引脚范围等关键信息
dev struct device* 关联的硬件设备(通常为platform_device
driver_data void* 驱动私有数据,可通过pinctrl_dev_get_drvdata()获取

参数 pctldesc ,就是要注册的 PIN 控制器, PIN 控制器用于配置 SOC的 PIN 复用功能和电气特性。参数 pctldesc 是 pinctrl_desc 结构体类型指针。

pinctrl_desc结构体如下所示:

cpp 复制代码
/*
 * pinctrl_desc - 引脚控制器描述符
 * 该结构体描述一个引脚控制器及其功能,用于向pinctrl子系统注册引脚控制器
 */
struct pinctrl_desc {
    const char *name;                                  /* 引脚控制器设备名称 */
    struct pinctrl_pin_desc const *pins;               /* 描述每个引脚的引脚描述符数组 */
    unsigned int npins;                                /* pins数组中的引脚数量 */
    const struct pinctrl_ops *pctlops;                 /* 引脚控制操作(引脚控制核心操作) */
    const struct pinmux_ops *pmxops;                   /* 引脚复用操作(多路复用功能配置) */
    const struct pinconf_ops *confops;                 /* 引脚配置操作(电气特性配置) */
    struct module *owner;                              /* 该引脚控制器的模块所有者 */
    
#ifdef CONFIG_GENERIC_PINCONF
    unsigned int num_custom_params;                    /* 自定义配置参数的数量 */
    const struct pinconf_generic_params *custom_params; /* 自定义配置参数数组 */
    const struct pin_config_item *custom_conf_items;    /* 自定义参数的配置项 */
#endif
};

其中,有三个重要的结构体指针:

cpp 复制代码
const struct pinctrl_ops *pctlops;                 /* 引脚控制操作(引脚控制核心操作) */
const struct pinmux_ops *pmxops;                   /* 引脚复用操作(多路复用功能配置) */
const struct pinconf_ops *confops;                 /* 引脚配置操作(电气特性配置) */

这三个结构体就是 PIN 控制器的"工具",这三个结构体里面包含了很多操作函数,通过这些操作函数就可以完成对某一个PIN 的配置。

pinctrl_desc 结构体需要由用户提供,结构体里面的成员变量也是用户提供的。但是这个用户并不是我们这些使用芯片的程序员,而是半导体厂商,半导体厂商发布的 Linux 内核源码中已经把这些工作做完了。

比如在 imx_pinctrl_probe 函数中,有以下代码:

cpp 复制代码
int imx_pinctrl_probe(struct platform_device *pdev,
                     struct imx_pinctrl_soc_info *info)
{
    struct device_node *dev_np = pdev->dev.of_node;  // 获取设备树节点
    struct device_node *np;                          // 临时设备树节点指针
    struct imx_pinctrl *ipctl;                      // i.MX引脚控制器数据结构
    struct resource *res;                           // 资源指针
    struct pinctrl_desc *imx_pinctrl_desc;          // 引脚控制器描述符
......

    // 为引脚控制器描述符分配内存
    imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),
                                   GFP_KERNEL);
    if (!imx_pinctrl_desc)
        return -ENOMEM;  // 内存分配失败返回错误
......

    // 初始化引脚控制器描述符
    imx_pinctrl_desc->name = dev_name(&pdev->dev);  // 设置控制器名称
    imx_pinctrl_desc->pins = info->pins;           // 设置引脚描述数组
    imx_pinctrl_desc->npins = info->npins;         // 设置引脚数量
    imx_pinctrl_desc->pctlops = &imx_pctrl_ops;    // 设置控制操作函数集
    imx_pinctrl_desc->pmxops = &imx_pmx_ops;       // 设置复用操作函数集
    imx_pinctrl_desc->confops = &imx_pinconf_ops;  // 设置配置操作函数集
    imx_pinctrl_desc->owner = THIS_MODULE;         // 设置所属模块
......

    // 注册引脚控制器
    ipctl->pctl = pinctrl_register(imx_pinctrl_desc, &pdev->dev, ipctl);
    
    // ...其他代码...
}
  • 定义结构体指针变量 imx_pinctrl_desc。
  • 向指针变量 imx_pinctrl_desc 分配内存。
  • 初始化 imx_pinctrl_desc 结构体指针变量,重点是 pctlops、 pmxops 和 confops这三个成员变量,分别对应 imx_pctrl_ops、 imx_pmx_ops 和 imx_pinconf_ops 这三个结构体。
  • 调用函数 pinctrl_register 向 Linux 内核注册 imx_pinctrl_desc,注册以后 Linux 内核就有了对 I.MX6ULL 的 PIN 进行配置的工具。

imx_pctrl_ops、 imx_pmx_ops 和 imx_pinconf_ops 这三个结构体定义如下:

cpp 复制代码
/* i.MX 引脚控制操作集合 */
static const struct pinctrl_ops imx_pctrl_ops = {
    .get_groups_count = imx_get_groups_count,      /* 获取引脚组数量 */
    .get_group_name = imx_get_group_name,          /* 获取引脚组名称 */ 
    .get_group_pins = imx_get_group_pins,          /* 获取引脚组中的引脚列表 */
    .pin_dbg_show = imx_pin_dbg_show,              /* 调试接口:显示引脚信息 */
    .dt_node_to_map = imx_dt_node_to_map,          /* 从设备树节点生成引脚映射 */
    .dt_free_map = imx_dt_free_map,                /* 释放引脚映射资源 */
};
......

/* i.MX 引脚复用操作集合 */  
static const struct pinmux_ops imx_pmx_ops = {
    .get_functions_count = imx_pmx_get_funcs_count, /* 获取复用功能数量 */
    .get_function_name = imx_pmx_get_func_name,    /* 获取复用功能名称 */
    .get_function_groups = imx_pmx_get_groups,     /* 获取支持某功能的引脚组 */
    .set_mux = imx_pmx_set,                        /* 设置引脚复用功能 */
    .gpio_request_enable = imx_pmx_gpio_request_enable, /* GPIO请求使能 */
    .gpio_set_direction = imx_pmx_gpio_set_direction,   /* 设置GPIO方向 */
};
......

/* i.MX 引脚配置操作集合 */
static const struct pinconf_ops imx_pinconf_ops = {
    .pin_config_get = imx_pinconf_get,             /* 获取引脚配置参数 */
    .pin_config_set = imx_pinconf_set,             /* 设置引脚配置参数 */
    .pin_config_dbg_show = imx_pinconf_dbg_show,   /* 调试接口:显示引脚配置 */
    .pin_config_group_dbg_show = imx_pinconf_group_dbg_show, /* 调试接口:显示引脚组配置 */
};
......

这三个结构体下的所有函数就是 I.MX6ULL 的 PIN 配置函数。

设备树中添加 pinctrl 节点模板

我们学习一下如何在设备树中添加某个外设的PIN信息 。

关 于 I.MX 系 列 SOC 的 pinctrl 设 备 树 绑 定 信 息 可 以 参 考 文 档Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt。

这里我们虚拟一个名为"test"的设备, test 使用了GPIO1_IO00这个 PIN的GPIO 功能,

pinctrl 节点添加过程如下:

创建对应的节点

同一个外设的 PIN 都放到一个节点里面,打开 imx6ull-alientek-emmc.dts,在 iomuxc 节点中的"imx6ul-evk"子节点下添加"pinctrl_test"节点。

添加完成以后如下所示:

cpp 复制代码
pinctrl_test: testgrp {
        /* 具体的 PIN 信息 */
};

添加"fsl,pins"属性

设备树是通过属性来保存信息的,因此我们需要添加一个属性,属性名字一定要为"fsl,pins"。

因为对于 I.MX 系列 SOC 而言, pinctrl 驱动程序是通过读取"fsl,pins"属性值来获取 PIN 的配置信息。

完成以后如下所示:

cpp 复制代码
pinctrl_test: testgrp {
            fsl,pins = <
            /* 设备所使用的 PIN 配置信息 */
            >;
};

添加 PIN 配置信息

最后在"fsl,pins"属性中添加具体的 PIN 配置信息,完成以后如下所示:

cpp 复制代码
pinctrl_test: testgrp {
        fsl,pins = <
        MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 config /*config 是具体设置值*/
        >;
};

至此,我们已经在 imx6ull-alientek-emmc.dts 文件中,添加好了 test 设备所使用的 PIN 配置信息。

相关推荐
朱包林8 分钟前
数据库服务-日志管理-备份与恢复-主从同步
linux·运维·服务器·数据库·mysql·云计算
李法师_19 分钟前
lwIP MQTT 心跳 Bug 分析与修复
linux·c语言·stm32·单片机·lwip
超级大坏蛋20182 小时前
QT .pro文件的常见用法
java·linux·qt
我好饿13 小时前
Linux入门教程 第十五章 Linux 系统调优工具
linux·运维·网络
萌虎爱分享4 小时前
Linux 防火墙 (firewalld) 管理完整指南
linux·运维·防火墙·firewalld
祈祷苍天赐我java之术8 小时前
Linux 进阶之性能调优,文件管理,网络安全
java·linux·运维
ajassi20009 小时前
开源 C++ QT Widget 开发(七)线程--多线程及通讯
linux·c++·qt·开源
孤雪心殇9 小时前
如何安全,高效,优雅的提升linux的glibc版本
linux·后端·golang·glibc
潇凝子潇9 小时前
获取服务器指标的信息
linux·运维·服务器
FreeBuf_9 小时前
Chrome高危零日漏洞PoC公开,已被用于野外攻击
linux·运维·服务器·安全·web安全