1. GPIO子系统:Linux硬件控制的利器
GPIO子系统是Linux内核中管理GPIO资源的框架,它提供了一套标准化的API接口,让驱动开发者可以轻松操作硬件引脚。想象一下,如果没有GPIO子系统,每次控制一个LED灯都需要直接操作寄存器,那将是多么繁琐的事情!GPIO子系统就像是一个硬件管家,帮我们处理了底层的复杂操作,让我们可以专注于业务逻辑的实现。
我在实际项目中第一次使用GPIO子系统时,真的被它的便捷性惊艳到了。以前需要查阅几百页的芯片手册,现在只需要几行设备树配置和API调用就能完成同样的功能。这种抽象层次的变化,大大降低了嵌入式开发的入门门槛。
GPIO子系统的核心价值在于它提供了硬件无关的编程接口。无论你使用的是哪家芯片厂商的处理器,无论是ARM、MIPS还是RISC-V架构,GPIO子系统的API都是相同的。这意味着你的驱动代码可以在不同平台间移植,只需要修改设备树配置即可。
2. 设备树配置:硬件描述的现代化方式
设备树是现代Linux内核中描述硬件资源的标准方式,它取代了传统的板级文件(board file)。通过设备树,我们可以用结构化的文本文件来定义硬件连接关系,内核在启动时会解析这些信息并初始化相应的硬件资源。
2.1 基础设备树节点配置
让我们从一个最简单的LED设备树配置开始:
/ {
compatible = "myboard,model";
led {
compatible = "myboard,led";
status = "okay";
default-state = "on";
led-gpio = <&gpio0 7 GPIO_ACTIVE_HIGH>;
};
};
这个配置定义了一个LED设备,使用GPIO0组的第7个引脚,高电平有效。compatible属性非常重要,它是驱动和设备匹配的关键。内核会根据这个字符串来找到对应的驱动程序。
我在实际项目中遇到过很多设备树配置的问题,最常见的就是compatible字符串不匹配。有一次调试了整整一天,最后发现只是多了一个空格字符。所以建议大家复制粘贴时要特别小心,最好使用专门的设备树语法检查工具。
2.2 添加pinctrl绑定
在现代嵌入式系统中,引脚复用(Pin Multiplexing)是非常普遍的功能。同一个物理引脚可能有多种功能选择,比如GPIO、UART、I2C等。pinctrl子系统就是用来管理引脚复用配置的。
&pio {
led_pin: led_pin {
pins = "PF6";
function = "gpio_out";
drive-strength = <10>;
bias-pull-up;
};
};
led {
compatible = "myboard,led";
status = "okay";
gpios = <&pio 6 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&led_pin>;
};
这里我们定义了一个pinctrl节点led_pin,将PF6引脚配置为GPIO输出模式,驱动强度为10mA,启用上拉电阻。然后在LED节点中通过pinctrl-0引用这个配置。
pinctrl的配置格式因芯片厂商而异,需要参考具体的芯片文档。我在适配不同平台时,发现每家厂商的实现都有细微差别,这也是移植工作中比较繁琐的部分。
3. GPIO驱动开发实战
现在让我们进入实际的驱动开发环节。GPIO驱动通常基于字符设备框架,我们需要实现open、read、write、release等标准文件操作接口。
3.1 设备结构体定义
首先定义设备结构体,包含所有需要管理的资源:
#define GPIOLED_CNT 1
#define GPIOLED_NAME "gpioled"
struct gpioled_dev {
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
int major;
int minor;
struct device_node *nd;
int led_gpio;
};
static struct gpioled_dev gpioled;
这个结构体包含了字符设备需要的所有信息:设备号、cdev结构、类、设备实例,以及GPIO编号和设备节点指针。我习惯把这种结构体称为"设备上下文",它包含了设备生命周期中需要的所有状态信息。
3.2 文件操作实现
实现标准的文件操作接口:
static


1525

被折叠的 条评论
为什么被折叠?



