侧边栏壁纸
博主头像
Into The Abyss 博主等级

My Life is a Death Race

  • 累计撰写 34 篇文章
  • 累计创建 7 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Linux设备驱动:pinctrl 子系统 与 GPIO 子系统

Administrator
2024-03-27 / 1 评论 / 0 点赞 / 1137 阅读 / 0 字

pinctrl 子系统

pinctrl 子系统是 Linux 内核中的一个框架,用于管理处理器的引脚功能和属性。它的主要任务是允许用户空间和内核驱动程序对处理器引脚进行配置、控制和监视。pinctrl 子系统通常包含以下主要组件:

pinctrl 核心:pinctrl 核心是 pinctl 子系统的核心部分,负责处理与处理器引脚相关的请求,包括引脚配置、引脚状态查询等。

pinctrl 驱动程序:pinctrl 驱动程序是特定于硬件的驱动程序,负责与硬件交互以配置和控制处理器引脚的功能和属性。

pinctrl 设备树绑定:pinctrl 子系统通常通过设备树 (Device Tree) 进行配置,设备树描述了处理器的引脚和与之相关的属性。pinctrl 设备树绑定描述了硬件与 pinctrl 驱动程序之间的关系。

总而言之,pinctrl是用来设置一个pin的复用和电器属性的,对于使用者来说,只需要掌握如何在设备书中设置好某个pin的相关属性即可。
在树莓派4B中,一个使用例子如下:

pin4: pin4{
	brcm,pins = <4>;
	brcm,function = <1>;
	brcm,pull = <0>;
};
// brcm,pins是引脚号;brcm,function是引脚功能;brcm,pull是引脚上下拉设定。可以参考“linux/include/dt-bindings/pinctrl/bcm2835.h”中的定义,具体引脚功能可以查看数据手册。
//上面的例子是配置gpio4为输出,不使用上下拉,状态由外部电路确定。

GPIO 子系统

GPIO 子系统允许 Linux 内核控制处理器的通用输入/输出引脚,这些引脚通常用于连接外部设备。GPIO 子系统包括以下主要组件:

GPIO 核心:GPIO 核心是 GPIO 子系统的核心部分,负责处理与 GPIO 引脚相关的请求,包括配置引脚方向、设置引脚值、监视引脚状态等。

GPIO 控制器驱动程序:GPIO 控制器驱动程序是特定于硬件的驱动程序,负责与硬件交互以控制 GPIO 引脚的功能和状态。

GPIO 设备节点:GPIO 设备节点通常通过设备树描述,设备树描述了 GPIO 控制器与系统中的 GPIO 引脚之间的关系。

GPIO 子系统允许用户空间程序和内核驱动程序通过标准的 GPIO API 控制 GPIO 引脚。这种通用的 GPIO API 提供了一致的接口,使得开发者可以在不同的硬件平台上轻松地编写和移植 GPIO 相关的驱动程序和应用程序。

驱动中对GPIO的操作过程主要为:
1、获取到gpio的设备节点,比如使用struct device_node *of_find_node_by_path(const char *path);
2、获取gpio编号,使用int of_get_named_gpio(const struct device_node *np, const char *propname, int index);
3、请求此编号的gpio,使用int gpio_request(unsigned gpio, const char *label);
4、设置gpio,输入或输出,使用int gpio_direction_input(unsigned gpio);int gpio_direction_output(unsigned gpio, int value);
5、输入使用int gpio_get_value(unsigned gpio);读取gpio的值;输出使用void gpio_set_value(unsigned gpio, int value);写gpio的值。
6、使用完毕后释放此gpio,使用`void gpio_free(unsigned gpio);

设备树中添加节点:

my_led: my_led{
	compatible = "pjw6,led";
	pinctrl-names = "default";
	pinctrl-0 = <&pin4>; //使用上面定义的pinctrl子系统
	gpio = <&gpio 4 GPIO_ACTIVE_LOW>;
	status = "okay";
};

在驱动程序中使用:

//首先需要在设备结构体中添加设备节点和gpio对应的数据结构
struct my_dev
{
	//...
	struct device_node *nd;
	int led_gpio;
};

//对gpio进行获取并操作
mydev.nd = of_find_node_by_path("/my_led");
if(mydev.nd == NULL ){
	printk("of_find_node_by_path();\n");
	return -EINVAL;
}
mydev.led_gpio = of_get_named_gpio(mydev.nd,"gpios",0);
if(mydev.led_gpio == NULL){
	printk("of_get_named_gpio\n");
	return -EINVAL;
}
ret = gpio_request(mydev.led_gpio,"my_led_gpio");
if (ret < 0)
{
	printk("gpio_request\n");
	return ret;
}
ret = gpio_direction_output(mydev.led_gpio,0);
if (ret < 0)
{
	printk("gpio_direction_output\n");
	return ret;
 }
gpio_set_value(mydev.led_gpio,1);
printk("succeed gpio_set_value\n");

//卸载驱动时释放gpio
static void __exit gpioled_exit(void)
{
	gpio_set_value(mydev.led_gpio,0);
	gpio_free(mydev.led_gpio);
	cdev_del(&mydev.cdev);
	// ...
}
0

评论区