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 配置信息。

相关推荐
猫猫的小茶馆2 小时前
【STM32】HAL库中的实现(二):串口(USART)/看门狗(IWDG/WWDG)/定时器(TIM)
arm开发·驱动开发·stm32·单片机·嵌入式硬件·mcu·智能硬件
橘颂TA3 小时前
【Linux】特效爆满的Vim的配置方法 and make/Makefile原理
linux·运维·服务器·vim
AI大法师4 小时前
企业级Linux服务器安全:防火墙规则配置与Web/SSH服务优化指南
linux·服务器·安全
sukalot5 小时前
window显示驱动开发—覆盖 DDI
驱动开发
Hat_man_5 小时前
如何在虚拟机(Linux)安装Qt5.15.2
linux·运维·服务器
LLLLYYYRRRRRTT5 小时前
12. SELinux 加固 Linux 安全
linux·运维·安全
爱学习的小熊猫_6 小时前
在Linux上部署RabbitMQ、Redis、ElasticSearch
linux·redis·elasticsearch·中间件·rabbitmq
拾心216 小时前
【运维进阶】DHCP服务配置和DNS域名解析
linux·运维·服务器
陈陈爱java7 小时前
实习文档背诵
linux·服务器·windows