内核中展示gpio接口的驱动


本文记录一种内核中对gpio进行操作的方法。

一、获取gpio

我们要对gpio进行操作,那么首先我们要获取到对应的资源。在dts中,我们需要进行一种gpio的配置,方便我们在驱动中对gpio进行操作。

	/*用于匹配驱动的节点*/
    misc_control {
        compatible="m08_a,misc";
        pinctrl-names = "default";
        eeprom-wp = <&lsio_gpio3 14 GPIO_ACTIVE_HIGH>; 
        status = "okay";

    pinctrl_hog: hoggrp {
        fsl,pins = <
            /*eeprom WP*/
            IMX8QXP_QSPI0A_SS0_B_LSIO_GPIO3_IO14        0x06000021
        >;
    };

这个是在imx8qxp的平台上进行的接口调用的dts配置,因为Imx需要将gpio初始化为gpio功能,避免其余功能复用。

二、对GPIO进行操作

驱动获取这个gpio:

	struct device_node *np = NULL;
	/*通过节点名字进行匹配*/
	np = of_find_node_by_name(NULL, "misc_control");
	if (!np) {
		printk("%s[%d] can not find node: misc_control\n", 
		       __func__, __LINE__);
		return -ENODEV;
	}
	/*判断gpio是否可控*/
	eeprom_wp = of_get_named_gpio(np,"eeprom-wp", 0);
	if (!gpio_is_valid(eeprom_wp))
	{
		printk("%s can't get gpio_is_valid\n", __func__);
		return -ENODEV;
	}
	/*如果前面都没报错,后面就可以对gpio进行操作了*/
	/*gpio注册*/
	gpio_request(eeprom_wp, "eeprom-wp");
	/*gpio设置为输出模式,输出为高*/
	gpio_direction_output(eeprom_wp, 1 / 0);
	/*将设置为输出模式的gpio重新拉高拉底,为了保证设置有效,我们都会在这里重新设置一次*/
	gpio_set_value(eeprom_wp, 0 / 1); 

可以将这段添加到对应的驱动里面。

三、在开发板上添加节点,通过命令拉高拉底gpio,以及完整代码


#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <asm/irq.h>

static unsigned int eeprom_wp,eeprom_wp_set;
/*设置节点,通过节点去操作*/
static ssize_t eeprom_wp_store(struct kobject *kobj,
						struct kobj_attribute *attr,
						const char *buf, size_t n)
{
	int value;

	if (sscanf(buf, "%u", &value) != 1 ||
	    (value != 0 && value != 1))
		return -EINVAL;

	eeprom_wp_set = value;
	gpio_set_value(eeprom_wp, eeprom_wp_set);
	
	return n;
}

static ssize_t eeprom_wp_show(struct kobject *kobj,
					       struct kobj_attribute *attr,
					       char *buf)
{
	int value;

	value = gpio_get_value(eeprom_wp);
	return sprintf(buf, "%d\n", value);
}

struct van_attribute {
	struct attribute attr;
	ssize_t (*show) (struct kobject *kobj, struct kobj_attribute *attr,
			 char *buf);
	ssize_t (*store) (struct kobject *kobj, struct kobj_attribute *attr,
			  const char *buf, size_t n);
};

/*添加权限为这个节点*/
static struct van_attribute van_attrs[] =
{
	/*node_name permission show_func store_func */
	__ATTR(eeprom_wp, 0664,eeprom_wp_show,eeprom_wp_store),

};

static struct kobject *van_kobj;

/*在sys的目录下创造van-misc节点*/
static int __init init_bsp_sysfs(void)
{
	int i, j, error = 0;

	van_kobj = kobject_create_and_add("van-misc", NULL);
	if (!van_kobj)
		return -ENOMEM;

	for (i = 0; i < ARRAY_SIZE(van_attrs); i++) {
		error =
			sysfs_create_file(van_kobj,
					  &van_attrs[i].attr);
		if (error) {
			printk("failed to register misc %d : error= %d\n",
				i, error);
			for (j = 0; j < i; j++)
				sysfs_remove_file(van_kobj,
						  &van_attrs[j].attr);

			return -ENOMEM;
		}
	}
	printk("cluo--> create van-misc ok\n");
	return 0;
}

/*驱动注册函数*/
static int  m08_a_misc_probe(struct platform_device *pdev)
{
	struct device_node *np = NULL;
	int i;
	np = of_find_node_by_name(NULL, "misc_control");
	if (!np) {
		printk("%s[%d] can not find node: misc_control\n", 
		       __func__, __LINE__);
		return -ENODEV;
	}

	eeprom_wp = of_get_named_gpio(np,"eeprom-wp", 0);
        //gpio不可控制基本都在这里报错,可以在if里面添加打印进行判断
	if (!gpio_is_valid(eeprom_wp))
	{
		return -ENODEV;
	}

	gpio_request(eeprom_wp, "eeprom-wp");
	gpio_direction_output(eeprom_wp, 1);
        msleep(1);
	gpio_set_value(eeprom_wp, 0);
        msleep(1);

	init_bsp_sysfs();//进行初始化节点操作
	return 0;
}	

static int m08_a_misc_remove(struct platform_device *pdev)
{      
		return 0;
}

#ifdef CONFIG_OF
static struct of_device_id m08_a_platdata_of_match[] = {
    { .compatible = "m08_a,misc" },
    { }
};
MODULE_DEVICE_TABLE(of, m08_a_platdata_of_match);
#endif //CONFIG_OF

static struct platform_driver m08_a_misc_driver = {
		.probe = m08_a_misc_probe,
		.remove = m08_a_misc_remove,
		.driver = {
			.name = "m08_a_misc",
			.owner = THIS_MODULE,
			.of_match_table = of_match_ptr(m08_a_platdata_of_match),
		},
};

static int __init m08_a_misc_init(void)
{
	return platform_driver_register(&m08_a_misc_driver);
}

static void __exit m08_a_misc_exit(void)
{
	platform_driver_unregister(&m08_a_misc_driver);
}

late_initcall(m08_a_misc_init);
module_exit(m08_a_misc_exit);

MODULE_AUTHOR("cluo");
MODULE_DESCRIPTION("misc bsp module for m08_a");
MODULE_LICENSE("GPL");

四、如何操作节点

mek_8q:/ # cd sys/van-misc/                                                    
mek_8q:/sys/van-misc # ls
eeprom_wp
mek_8q:/sys/van-misc # cat eeprom_wp                                           
0
mek_8q:/sys/van-misc # 
mek_8q:/sys/van-misc # echo 1 > eeprom_wp                                      
mek_8q:/sys/van-misc # 
mek_8q:/sys/van-misc # echo 0 > eeprom_wp

这样我们就可以拉高拉底对应的gpio

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
PWM-GPIO驱动程序是Linux内核的一个驱动模块,用于控制嵌入式系统GPIO引脚产生PWM信号。该驱动程序允许开发人员通过编程的方式来控制GPIO引脚的电平变化,从而产生不同占空比的PWM信号。 在Linux内核,PWM-GPIO驱动程序通过向用户空间提供了相应的接口来实现PWM信号的控制。开发人员可以通过打开相应的设备节点,并使用相应的系统调用函数来设置PWM的频率、占空比等参数,从而实现对GPIO引脚的PWM信号的控制。 驱动程序的核心部分是一个PWM子系统,它与GPIO子系统紧密集成。PWM子系统负责管理PWM信号的生成和控制,而GPIO子系统负责管理GPIO引脚的配置和操作。PWM-GPIO驱动程序在这两个子系统之间起着桥梁的作用。 PWM-GPIO驱动程序的实现方式与硬件平台相关,每个平台可能有不同的具体实现。在驱动程序的初始化过程,必须先配置GPIO引脚的功能为PWM模式,并将相应的寄存器映射到内核,以便能够通过对寄存器的操作来控制GPIO引脚。驱动程序还需要初始化PWM子系统,为每个GPIO引脚分配相应的PWM通道,并根据需求设置PWM的频率、占空比等参数。 通过PWM-GPIO驱动程序,开发人员可以方便地利用Linux内核的功能来实现对嵌入式系统GPIO引脚产生PWM信号的控制。这为开发PWM驱动、控制舵机、LED等应用提供了便捷的方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永不秃头的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值