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