您现在的位置是:首页 >其他 >pinctrl 子系统网站首页其他
pinctrl 子系统
什么是 pinctrl 子系统?
pinctrl(Pin Control)子系统是 Linux 内核中的一个子系统,它用于管理系统上的引脚并为设备驱动程序提供通用的引脚控制 API。该子系统允许设备驱动程序配置和控制其所需的引脚,而不必关心底层硬件的具体实现。
pinctrl 子系统的框架
pinctrl 子系统的框架主要由以下几个部分组成:
pinctrl core
pinctrl core 是 pinctrl 子系统的核心部分,它提供了以下功能:
管理和维护系统上的引脚和 pinctrl 配置;
提供通用的 pinctrl 接口供设备驱动程序使用;
管理设备驱动程序之间的引脚冲突和资源共享。
pinctrl 驱动程序
-
pinctrl 驱动程序是一个用于管理芯片引脚的 Linux 内核驱动程序。它通过实现 pinctrl 核心提供的接口来向 pinctrl 核心注册自己,并提供芯片引脚的配置和控制功能。
pinctrl 映射器* -
pinctrl 映射器是一个将 pinctrl 配置映射到具体芯片引脚的模块。它负责解析 pinctrl 配置,映射到具体的引脚,并将映射结果传递给 pinctrl 驱动程序。pinctrl 映射器可以根据不同的芯片架构和芯片引脚布局进行定制。
pinctrl 核心 API -
pinctrl 核心 API 是 pinctrl 子系统提供给设备驱动程序的通用接口,它包括以下主要函数:
pinctrl_register_mappings(): 用于向 pinctrl 子系统注册 pinctrl 映射器;
pinctrl_register(): 用于向 pinctrl 子系统注册 pinctrl 驱动程序;
pinctrl_lookup_state(): 用于查找并返回指定名称的 pinctrl 配置状态;
pinctrl_select_state(): 用于选择指定的 pinctrl 配置状态;
pinctrl_force_sleep_state(): 用于将指定的引脚强制置于休眠状态;
pinctrl_request(): 用于请求一个或多个引脚的使用权;
pinctrl_free(): 用于释放一个或多个引脚的使用权。
pinctrl 子系统的应用
pinctrl 子系统广泛应用于嵌入式设备和嵌入式系统中,例如:
-
在嵌入式系统中,pinctrl 子系统通常用于为各种外设(如 GPIO、SPI、I2C 等)配置引脚。
例如,在 Raspberry Pi 上,pinctrl 子系统用于配置引脚用于控制各种外设,如 I2C、SPI、UART 和 GPIO 等。 -
在开发板上,pinctrl 子系统也被广泛使用。例如,很多 SoC 厂商都提供了适用于其芯片的 pinctrl 驱动程序和映射器,供开发者使用。这使得开发者可以轻松地配置和控制引脚,以实现各种应用。
-
在内核开发中,pinctrl 子系统也是一个非常重要的子系统。许多设备驱动程序都需要使用 pinctrl 接口来配置和控制引脚。因此,了解 pinctrl 子系统的原理和使用方法对于内核开发者来说是非常有用的。
总结
pinctrl 子系统是 Linux 内核中用于管理系统上的引脚的子系统。它通过提供通用的引脚控制 API,允许设备驱动程序独立于底层硬件的具体实现。pinctrl 子系统由 pinctrl core、pinctrl 驱动程序、pinctrl 映射器和 pinctrl 核心 API 等部分组成。pinctrl 子系统广泛应用于嵌入式设备和嵌入式系统中,并在内核开发中扮演着重要的角色。
例程
下面是一个简单的 pinctrl 驱动程序,用于配置 GPIO 引脚。在 probe() 函数中,首先获取 pinctrl 设备,然后查找并应用 GPIO 配置状态。最后,申请 GPIO 引脚并应用 pinctrl 配置。在 remove() 函数中,释放 GPIO 引脚。
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/gpio.h>
static struct pinctrl *pinctrl;
static struct pinctrl_state *pinctrl_state;
static int gpio_pin = 4;
static int pinctrl_gpio_probe(struct platform_device *pdev)
{
int ret;
// 获取 pinctrl 设备
pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(pinctrl)) {
dev_err(&pdev->dev, "failed to get pinctrl
");
return PTR_ERR(pinctrl);
}
// 配置引脚用于控制 GPIO
pinctrl_state = pinctrl_lookup_state(pinctrl, "gpio");
if (IS_ERR(pinctrl_state)) {
dev_err(&pdev->dev, "failed to lookup gpio state
");
return PTR_ERR(pinctrl_state);
}
// 配置 GPIO 引脚
ret = gpio_request(gpio_pin, "example");
if (ret < 0) {
dev_err(&pdev->dev, "failed to request gpio pin
");
return ret;
}
// 应用 pinctrl 配置
ret = pinctrl_select_state(pinctrl, pinctrl_state);
if (ret < 0) {
dev_err(&pdev->dev, "failed to select pinctrl state
");
return ret;
}
return 0;
}
static int pinctrl_gpio_remove(struct platform_device *pdev)
{
// 释放 GPIO 引脚
gpio_free(gpio_pin);
return 0;
}
static const struct of_device_id pinctrl_gpio_match[] = {
{ .compatible = "example,pinctrl-gpio" },
{},
};
MODULE_DEVICE_TABLE(of, pinctrl_gpio_match);
static struct platform_driver pinctrl_gpio_driver = {
.probe = pinctrl_gpio_probe,
.remove = pinctrl_gpio_remove,
.driver = {
.name = "pinctrl-gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pinctrl_gpio_match),
},
};
module_platform_driver(pinctrl_gpio_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Example");
MODULE_DESCRIPTION("Example pinctrl gpio driver");
以下是该 pinctrl 子系统的设备树代码示例:
pinctrl-gpio {
compatible = "example,pinctrl-gpio";
gpio = <&gpio4 0>;
pinctrl-0 = <&gpio_pinmux>;
};
gpio_pinmux: gpio_pinmux {
pinctrl-single,pins = <
0x10 0x7 /* GPIO4_IO00 */
>;
};
在设备树中,pinctrl-gpio 节点定义了 pinctrl 子系统,并指定了 GPIO 引脚的配置状态(在 pinctrl-0 属性中引用)。gpio_pinmux 节点定义了引脚的映射(在 pinctrl-single,pins 属性中定义),此处指定了 GPIO4_IO00 引脚。
需要注意的是,设备树中的 pinctrl 配置状态和 pinctrl 驱动程序中的 pinctrl 配置状态必须匹配。在这个例子中,pinctrl-gpio 节点中指定的配置状态名称为 “gpio”,而在 pinctrl_gpio_probe() 函数中查找并应用的状态也是 “gpio”。
以下是该 pinctrl 子系统的 Makefile 示例:
obj-m += pinctrl-gpio.o
KDIR ?= /lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
在 Makefile 中,我们定义了要编译的内核模块 pinctrl-gpio.o,并定义了内核源码的位置。在 all 目标中,我们使用 make 命令编译模块。在 clean 目标中,我们使用 make 命令清除编译生成的文件。