[Linux Device Driver] 通过设备节点的方式控制GPIO

本文介绍了一个用于控制 Logo LED 的 Linux 驱动模块实现细节。该模块通过 GPIO 接口控制 Logo LED 的亮灭,并提供了 sysfs 接口供上层应用控制。文中给出了 dtsi 配置文件及 C 语言驱动代码示例。

直接上代码了,Kconfig、defconfig、makefile那些请自己配置。

0. vendor/qcom/proprietary/devicetree-4.19/qcom/lagoon-mtp.dtsi

&soc {
  
   ......
	logo_led {
		compatible = "qcom,logo-led-v2";
		qcom,msm-logo-enable-gpio =   <&tlmm 87 0x00>;
	};

};

1. kernel/msm-4.19/drivers/logoled/logo.c

#include <linux/init.h>
#include <linux/kernel.h>  
#include <linux/module.h> 
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/power_supply.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
#include <linux/leds-qpnp-flash.h>
#include <linux/leds-qpnp-flash-v2.h>
#include <linux/qpnp/qpnp-revid.h>
#include <linux/log2.h>

static int logo_gpio = 0;

static ssize_t pm6150l_wled_enable_show(struct device *dev,
                                 struct device_attribute *attr, char *buf)
{
	int val;
	val =  gpio_get_value(logo_gpio);
	return sprintf(buf, "%d\n", val);
}

static ssize_t pm6150l_wled_enable_store(struct device *dev,
                                      struct device_attribute *attr,
                                      const char *buf, size_t size)
{
	ssize_t ret;

	unsigned int state;
	pr_err("#nigulasi-logo#,debug1,fun=%s,logo_gpio=%d\n",__func__,logo_gpio);

	ret = kstrtouint(buf, 10, &state);
	if (state) {
		gpio_direction_output(logo_gpio, 1);
		pr_err("#nigulasi-logo#,debug2,fun=%s,logo_gpio=%d\n",__func__,logo_gpio);
	}else{
		gpio_direction_output(logo_gpio, 0);
		pr_err("#nigulasi-logo#,debug3,fun=%s,logo_gpio=%d\n",__func__,logo_gpio);
	}

	return size;
}

static DEVICE_ATTR(wled_enable, S_IRUGO | S_IWUSR, pm6150l_wled_enable_show, pm6150l_wled_enable_store);

static int qpnp_logo_led_probe(struct platform_device *pdev)
{
	int rc = 0;
	const char *logo_enable_gpio = "qcom,msm-logo-enable-gpio";
	logo_gpio = of_get_named_gpio(pdev->dev.of_node, logo_enable_gpio, 0);
	rc = gpio_request(logo_gpio, "msm-logo-enable-gpio");
	pr_err("#nigulasi-logo#,debug,fun=%s,logo_gpio=%d\n",__func__,logo_gpio);

	rc = device_create_file(&pdev->dev, &dev_attr_wled_enable);
	if (rc < 0) {
		dev_err(&pdev->dev, "failed to create WLED enable sysfs node rc:%d\n",
			rc);
		return rc;
	}
	gpio_direction_output(logo_gpio, 0);
	return rc;

}

static int qpnp_logo_led_remove(struct platform_device *pdev)
{

	return 0;
}

const struct of_device_id qpnp_logo_led_match_table[] = {
	{ .compatible = "qcom,logo-led-v2",},
	{ },
};

static struct platform_driver logo_led_driver = {
	.driver		= {
		.name = "qcom,logo-led-v2",
		.of_match_table = qpnp_logo_led_match_table,
	},
	.probe		= qpnp_logo_led_probe,
	.remove		= qpnp_logo_led_remove,
};

static int logo_init(void)
{ 
	printk("enter the fun=%s!\n",__func__);
	return platform_driver_register(&logo_led_driver);
} 
static void logo_exit(void)
{
	printk("enter the fun=%s!\n",__func__);
	platform_driver_unregister(&logo_led_driver);
	return;
} 
module_init(logo_init);
module_exit(logo_exit);
MODULE_LICENSE("GPL");

之后就可以通过设备节点操控这个GPIO87了。用echo和cat操控gpio拉高拉低,然后cat /d/gpio会看到对应的gpio被配置为输出,high和low。

/sys/bus/platform/devices/soc:logo_led # cat wled_enable
Linux 内核通过设备树(Device Tree)描述硬件配置,对于 GPIO 的获取也是基于这种机制完成初始化和引用的。下面将为你介绍如何从 Linux 设备树中获取 GPIO 节点信息。 ### 获取设备节点GPIO #### 主要API: 1. **`of_get_named_gpio()`** 这是一个常用的辅助宏,在驱动程序需要访问特定命名属性所指向的 GPIO 引脚时非常有用。它可以从给定的 device_node 中找到指定名字对应的 gpio,并将其转换为平台本地编号形式返回。 - 宏原型:`#define of_get_named_gpio(np, propname, index) ...` - `np`: 指向目标设备的 struct device_node * 类型指针; - `propname`: 字符串类型的属性名称,在 dts 文件里通常是 "gpios" 或者其他自定义的名字; - `index`: 当有多个同名项存在时用于索引的具体位置;如果只有一个则通常传入0即可。 2. **`devm_gpiod_get_from_of_node()`** 推荐使用的现代方法之一,能够帮助管理生命周期并且支持 devres 自动释放资源特性。此 API 可以直接接收 OF node 参数并解析出相应的 gpiod 描述符供后续操作使用。 - 函数原型: `struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, struct device_node *node, const char *con_id, unsigned long flags, const char *label)` 3. **`of_property_read_u32_index()` + 手工映射** 对于一些较为简单的场景或是旧版兼容性考虑下可以选择这种方式读取原始数值再做额外处理得到实际可用的结果。 4. 示例代码片段: ```c #include <linux/of.h> #include <linux/gpio/consumer.h> static int my_driver_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; // 使用新推荐的方式 struct gpio_desc *desc; desc = devm_gpiod_get_from_of_node(dev, pdev->dev.of_node, NULL, 0 /* index */, GPIOD_IN, "my-gpio"); if (IS_ERR(desc)) { return PTR_ERR(desc); } } ``` 以上就是几种常见的 Linux 下根据 DeviceTree 来定位和控制 GPIO 的手段概述了。希望对您有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值