内核中展示gpio接口的驱动

250 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天。

本文记录一种内核中对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