class="hide-preCode-box">

许多芯片并不需要在设备树中显式地将引脚配置为GPIO功能。这是因为某些芯片(例如STM32MP157)在内部实现上已经将GPIO功能与引脚复用整合在一起。因此,Pinctrl的使用在某些情况下是虚拟的,它与GPIO密切相关。

2.2 GPIO和Pinctrl的映射关系

2.2.1 示例

img

2.2.2 数据结构

gpio_pin_range 结构体定义了 GPIO 控制器控制的引脚范围和对应的 pinctrl 设备,允许 GPIO 控制器管理一个 pinctrl 设备的引脚范围。

/** 
 * struct gpio_pin_range - GPIO 控制器所控制的引脚范围
 * @node: 连接到范围列表的链表节点,用于内部维护 pin range 的集合。
 * @pctldev: 指向管理相应引脚的 pinctrl 设备(pinctrl_dev)的指针,
 *           该设备将处理引脚复用、方向控制等功能。
 * @range: 由 GPIO 控制器控制的引脚的实际范围,包含引脚的起始位置、数量等信息。
 */
struct gpio_pin_range {
    struct list_head node;            // 列表头,维护 GPIO 范围的链表结构
    struct pinctrl_dev *pctldev;      // 与 GPIO 控制器关联的 pinctrl 设备
    struct pinctrl_gpio_range range;  // 由 GPIO 控制器控制的引脚范围信息
};
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

pinctrl_gpio_range 结构体描述了由 GPIO 控制器所处理的 GPIO 引脚范围,为每个 GPIO 控制器提供一个编号空间的子范围。

/**
 * struct pinctrl_gpio_range - 每个 GPIO 控制器提供的 GPIO 编号范围
 * @node: 用于内部使用的链表节点,连接到范围列表中
 * @name: 此 GPIO 控制器范围的名称,用于标识 GPIO 控制器
 * @id: 该范围的芯片 ID,用于在范围内区分 GPIO 控制器
 * @base: GPIO 范围的基地址偏移,用于计算 GPIO 引脚编号
 * @pin_base: 如果 pins 数组为 NULL,此字段表示 GPIO 引脚范围的基引脚编号
 * @pins: 指向引脚枚举数组的指针,该数组列出 GPIO 范围中的所有引脚
 * @npins: GPIO 范围内的引脚数量,包含基引脚编号
 * @gc: 可选指针,指向 gpio_chip 结构体,该结构体用于 GPIO 控制器的基本信息
 */
struct pinctrl_gpio_range {
    struct list_head node;       // 内部链表节点,连接到 GPIO 范围列表
    const char *name;            // 范围名称,标识 GPIO 控制器
    unsigned int id;             // GPIO 范围 ID,唯一标识该范围
    unsigned int base;           // GPIO 编号范围的基地址偏移,用于计算引脚编号
    unsigned int pin_base;       // 引脚范围的基引脚编号,如果 pins 数组为 NULL 使用此基数
    unsigned const *pins;        // 引脚数组的指针,列出该 GPIO 范围内的所有引脚
    unsigned int npins;          // GPIO 范围中的引脚数量,包括基引脚编号
    struct gpio_chip *gc;        // 可选的 gpio_chip 指针,用于指向 GPIO 控制器信息
};
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

2.3 GPIO调用Pinctrl的过程

GPIO子系统中的request函数,用来申请某个GPIO引脚,

它会导致Pinctrl子系统中的这2个函数之一被调用:pmxops->gpio_request_enablepmxops->request

调用关系如下:

gpiod_get //获取GPIO描述符的主函数,通常用于申请和配置GPIO引脚。
    gpiod_get_index 
        desc = of_find_gpio(dev, con_id, idx, &lookupflags);//查找设备树中指定的GPIO。
        ret = gpiod_request(desc, con_id ? con_id : devname); //用于确认请求并进行最终设置。
                    ret = gpiod_request_commit(desc, label); //如果GPIO芯片结构体中的request指针非空,它会调用芯片的request函数。
                                if (chip->request) {
                                    ret = chip->request(chip, offset);
                                }
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

编写GPIO驱动程序时,所设置chip->request函数,一般直接调用gpiochip_generic_request,它导致Pinctrl把引脚复用为GPIO功能。

gpiochip_generic_request(struct gpio_chip *chip, unsigned offset)
    pinctrl_request_gpio(chip->gpiodev->base + offset) //该函数负责将引脚配置为GPIO功能
        ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); // gpio是引脚的全局编号

        /* Convert to the pin controllers number space */
        pin = gpio_to_pin(range, gpio);
        
        ret = pinmux_request_gpio(pctldev, range, pin, gpio);
                    ret = pin_request(pctldev, pin, owner, range);
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

Pinctrl子系统中的pin_request函数就会把引脚配置为GPIO功能:

static int pin_request(struct pinctrl_dev *pctldev,
                       int pin, const char *owner,
                       struct pinctrl_gpio_range *gpio_range) {
    const struct pinmux_ops *ops = pctldev->desc->pmxops;

    // 检查是否有用于请求引脚的操作
    if (gpio_range && ops->gpio_request_enable) {
        // 请求并启用单个GPIO引脚
        status = ops->gpio_request_enable(pctldev, gpio_range, pin);
    } else if (ops->request) {
        // 如果有通用请求函数,则调用
        status = ops->request(pctldev, pin);
    } else {
        // 默认情况下,不做任何操作
        status = 0;
    }

    return status; // 返回请求状态
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

2.4 编程_GPIO使用Pinctrl

2.4.1 做什么

如果不想在使用GPIO引脚时,在设备树中设置Pinctrl信息,

如果想让GPIO和Pinctrl之间建立联系,

需要做这些事情:

  1. 表明GPIO和Pinctrl间的联系

在GPIO设备树中使用gpio-ranges来描述它们之间的联系:

// 当前GPIO控制器的0号引脚, 对应pinctrlA中的128号引脚, 数量为12
gpio-ranges = <&pinctrlA 0 128 12>; 
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
  1. 解析这些联系

在GPIO驱动程序中,解析跟Pinctrl之间的联系:处理gpio-ranges:

int gpiochip_add_data(struct gpio_chip *chip, void *data)
    status = of_gpiochip_add(chip);
                status = of_gpiochip_add_pin_range(chip);

of_gpiochip_add_pin_range
    for (;; index++) {
        ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
                index, &pinspec);

        pctldev = of_pinctrl_get(pinspec.np); // 根据gpio-ranges的第1个参数找到pctldev

        // 增加映射关系	
        /* npins != 0: linear range */
        ret = gpiochip_add_pin_range(chip,
                                     pinctrl_dev_get_devname(pctldev),
                                     pinspec.args[0],
                                     pinspec.args[1],
                                     pinspec.args[2]);
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">
  1. 编程

2.4.2 编程

  1. GPIO控制器编程

在编写GPIO驱动程序时,需要关注以下几个方面:

  1. 设置请求函数

    • 确保在GPIO芯片结构体中正确设置chip->request指针,通常指向gpiochip_generic_request。这样可以确保引脚被正确复用为GPIO功能。
  2. 理解设备树

    • 如果GPIO引脚来自设备树,确保在设备树中正确描述GPIO的相关属性和配置,以便gpiod_get和相关函数能够正确查找和请求GPIO。
  3. 错误处理

    • 在每个调用中检查返回值,确保处理潜在的错误,避免因引脚请求失败而导致驱动不稳定。
  4. 功能分离

    • 在实现请求和释放引脚时,确保保持代码的清晰和可读,尽量将复杂逻辑分离到辅助函数中,以便于维护。

gpio_chip中提供request函数:

c chip->request = gpiochip_generic_request;

📎virtual_gpio_driver.c
(参考)>>
📎virtual_gpio_driver0.c

  1. Pinctrl编程
static const struct pinmux_ops virtual_pmx_ops = {
    .get_functions_count = virtual_pmx_get_funcs_count,
    .get_function_name = virtual_pmx_get_func_name,
    .get_function_groups = virtual_pmx_get_groups,
    .set_mux = virtual_pmx_set,
    .gpio_request_enable = virtual_pmx_gpio_request_enable,
};
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

📎virtual_pinctrl_driver.c📎core.h

  1. led:

📎virtual_pinctrl_client.c(参考) 》 📎leddrv.c

📎ledtest.c

2.4.3 注意

IMX6ULL使用GPIO时必须设置Pinctrl,如果不设置,只有那些默认就是GPIO功能的引脚可以正常使用。

原因:

3.GPIO子系统的sysfs接口

3.1 驱动程序

📎gpiolib-sysfs.c

3.2 常用的sysfs文件

3.2.1 有哪些GPIO控制器

/sys/bus/gpio/devices目录下,列出了所有的GPIO控制器,如下表示有11个GPIO控制器:

/sys/bus/gpio/devices/gpiochip0
/sys/bus/gpio/devices/gpiochip1
/sys/bus/gpio/devices/gpiochip2
/sys/bus/gpio/devices/gpiochip3
/sys/bus/gpio/devices/gpiochip4
/sys/bus/gpio/devices/gpiochip5
/sys/bus/gpio/devices/gpiochip6
/sys/bus/gpio/devices/gpiochip7
/sys/bus/gpio/devices/gpiochip8
/sys/bus/gpio/devices/gpiochip9
/sys/bus/gpio/devices/gpiochip10
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

3.2.2 每个GPIO控制器的详细信息

/sys/class/gpio/gpiochipXXX下,有这些信息:

/sys/class/gpio/gpiochip508]# ls -1
base     // 这个GPIO控制器的GPIO编号
device
label    // 名字
ngpio    // 引脚个数
power
subsystem
uevent
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

3.2.3 查看GPIO使用情况

cat /sys/kernel/debug/gpio
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

3.2.4 通过sysfs使用GPIO

如果只是简单的引脚控制(比如输出、查询输入值),可以不编写驱动程序。

但是涉及中断的话,就需要编写驱动程序了。

1. 确定GPIO编号

查看每个/sys/class/gpio/gpiochipXXX目录下的label,确定是你要用的GPIO控制器,也称为GPIO Bank。

根据它名字gpiochipXXX,就可以知道基值是XXX。

基值加上引脚offset,就是这个引脚的编号。

2. 导出/设置方向/读写值

举例:

echo 509 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio509/direction
echo 1 > /sys/class/gpio/gpio509/value
echo 509 > /sys/class/gpio/unexport

echo 509 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio509/direction
cat /sys/class/gpio/gpio509/value
echo 509 > /sys/class/gpio/unexport
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/caiji0169/article/details/143582529","extend1":"pc","ab":"new"}">>
注:本文转载自juejin.cn的OpenTiny社区的文章"https://juejin.cn/post/7287473826061189181"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!