基于 GPIO 子系统的 LED 驱动程序
GPIO
的地位跟其他模块,比如 I2C、 UART 的地方是一样的,要使用某个引脚,需要先把引脚配置为 GPIO 功能,这要使用 Pinctrl 子系统,只需要在设备树里指定就可以。在驱动代码上不需要我们做任何事情。
GPIO
本身需要确定引脚,这也需要在设备树里指定。设备树节点会被内核转换为 platform_device
,对应的,驱动代码中要注册一个 platform_driver
,在 probe
函数中:获取引脚、注册 file_operations
。
在 file_operations 中:设置方向、读值/写值。 下图就是一个设备树的例子:
在设备树中添加Pinctrl 信息
有些芯片提供了设备树生成工具,在GUI 界面中选择引脚功能和配置信息,就可以自动生成 Pinctrl
子节点。把它复制到你的设备树文件中,然后在 client device
节点中引用就可以了。
有些芯片只提供文档,那就去阅读文档,一般在内核源码目录 Documentation\devicetree\bindings\pinctrl
下面,保存该厂家的文档,如果连文档都没有,那只能参考内核源码中的设备树文件,在内核源码目录 arch/arm/boot/dts
目录下。
最后一步,网络搜索。
在设备树中添加 GPIO 信息
先查看电路原理图确定所用引脚,再在设备树中指定:添加 ”[name]-gpios”
属性,指定使用的是哪一个 GPIO Controller
里的哪一个引脚,还有其他 Flag 信息,比如 GPIO_ACTIVE_LOW
等。具体需要多少个 cell
来描述一个引脚,需要查看设备树中这个 GPIO Controller
节点里的 “ #gpio-cells”
属性值,也可以查看内核文档。示例如下:
代码操作如下
在实际操作过程中也许会碰到意外的问题,现场演示如何解决。
-
第1步 定义、注册一个
platform_driver
-
第2步 在它的
probe
函数里:- 根据
platform_device
的设备树信息确定GPIO: gpiod_get
- 定义、注册一个
file_operations
结构体 - 在
file_operarions
中使用GPIO
子系统的函数操作GPIO:
- 根据
好处在于这些代码对所有的板子都是完全一样的。
注册 platform_driver
// 资源
static const struct of_device_id winter_leds[] = {
{
.compatible = "winter, led_drv"},
{
},
};
// 定义platform_driver
static struct platform_driver chip_demo_gpio_driver = {
.probe = chip_demo_gpio_probe,
.remove = chip_demo_gpio_remove,
.driver = {
.name = "winter_led",
.of_match_table = winter_leds,
},
};
// 入口函数中注册platform_driver
static int __init led_init(void)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
// 注册platform_driver结构体
err = platform_driver_register(&chip_demo_gpio_driver);
return err;
}
// 出口函数
static void __exit led_exit(void)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
platform_driver_unregister(&chip_demo_gpio_driver);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
在 probe 函数中获得 GPIO
核心代码是如下,它从该设备(对应设备树中的设备节点)获取名为“ led”
的引脚。在设备树中,必定有一属性名为 “ led-gpios”
或 “ ledgpio”
/* 从platform_device获得GPIO
* 把file_operations结构体告诉内核:注册驱动程序
*/
int chip_demo_gpio_probe (struct platform_device* pdev)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__)