OrangePi3 LTS 驱动开发-GPIO中断
上一节将到将普通gpio设置为输入,app端可以通过轮询的方式去读取外部设备的状态,但这样消耗的资源比较大。
如果采用中断的方法,当gpio高低电平发生变化的时候,我们再去处理相应的事件,那么会大大降低cpu的负担。
kernel版本:orange-pi-5.10-media
dts配置同上一节gpio输入
pl8连接pw0,
将pw0修改输出1hz的方波,
那么串口会每隔一秒打印一次中断处理函数。
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include "../type.h"
#define DRIVER_NAME "max_input"
#define DEVICE_NAME "input"
typedef struct input_driver
{
struct mutex mutex;
struct device *dev;
struct gpio_desc *gpiod;
unsigned int irq;
int irq_enable;
}max_inputs_driver;
static ssize_t name_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", DRIVER_NAME);
}
static DEVICE_ATTR(name, 0444, name_show,NULL);
static ssize_t gpio_value_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
max_inputs_driver * max_inputs = dev_get_drvdata(dev);
if (!max_inputs)
{
max_error("get max_leds_driver error\n");
return -ENODEV;
}
int value = gpiod_get_value(max_inputs->gpiod);
return sprintf(buf, "%d\n", value);
}
static DEVICE_ATTR(gpio_value, 0444, gpio_value_show,NULL);
static ssize_t irq_enable_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int ret = 0;
max_inputs_driver * max_inputs = dev_get_drvdata(dev);
if (!max_inputs)
{
max_error("get max_inputs_driver error\n");
return -ENODEV;
}
ret = sprintf(buf,"%s",max_inputs->irq_enable == 1 ? "PL8 IRQ On\n" : "PL8 IRQ On Off\n");
return ret;
}
static ssize_t irq_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
uint8_t value;
int ret;
max_inputs_driver * max_inputs = dev_get_drvdata(dev);
if (!max_inputs)
{
max_error("get max_inputs_driver error\n");
return -ENODEV;
}
ret = kstrtou8(buf, 0, &value);// auto data format
if (ret)
{
max_error("kstrtou8 error\n");
return -ENODEV;
}
if (value == 0 )
{
disable_irq_nosync(max_inputs->irq);
max_inputs->irq_enable = 0;
}
else if (value == 1)
{
enable_irq(max_inputs->irq);
max_inputs->irq_enable = 1;
}
else
{
max_info(" value only equal 1 and 0\n");
}
return count;
}
static DEVICE_ATTR(irq_enable, 0664, irq_enable_show,irq_enable_store);
static struct attribute *attrs[] = {
&dev_attr_name.attr,
&dev_attr_gpio_value.attr,
&dev_attr_irq_enable.attr,
NULL, /* need to NULL terminate the list of attributes */
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static irqreturn_t gpio_irq_handler(int irq, void *data)
{
max_inputs_driver * max_inputs = (max_inputs_driver *)data;
//mod_timer(&msa311_driver->timer,jiffies + msecs_to_jiffies(10));
//unsigned long delay = msecs_to_jiffies(2);
//schedule_work(&msa311_driver->work);
max_error("gpio_irq_handler \n");
return IRQ_HANDLED;
}
static int dts_parse(struct platform_device *pdev)
{
int ret = 0;
struct device_node * node;
const char *str;
max_inputs_driver * max_inputs = (max_inputs_driver *)platform_get_drvdata(pdev);
node = pdev->dev.of_node;
if (!node)
{
max_error("failed to find node for %s\n",DEVICE_NAME);
return -ENODEV;
}
if (node)
{
ret = of_property_read_string(node, "gpios", &str);
if (ret)
{
max_error("no define %s in dts\n", "gpios");
return -1;
}
else
{
max_inputs->gpiod = devm_gpiod_get(&pdev->dev,NULL,GPIOD_IN);
if (IS_ERR_OR_NULL(max_inputs->gpiod))
{
max_error("devm_gpiod_get error\n");
}
}
///gpiod_get_value(max_inputs->gpiod);
//申请irq
max_inputs->irq = gpiod_to_irq(max_inputs->gpiod);
// 申请中断
ret = devm_request_irq(&pdev->dev,
max_inputs->irq,
gpio_irq_handler,
IRQF_TRIGGER_FALLING,
"max", max_inputs);
max_inputs->irq_enable = 1;
if (ret)
{
max_error("devm_request_irq error\n");
}
}
return 0;
}
static int max_input_probe(struct platform_device *pdev)
{
int ret = 0;
struct class *inputs_class;
max_inputs_driver *max_inputs;
max_inputs = kzalloc(sizeof(max_inputs_driver), GFP_KERNEL);
if (!max_inputs) {
max_error("kzalloc max_inputs error\n");
return -ENOMEM;
}
mutex_init(&max_inputs->mutex);
platform_set_drvdata(pdev, max_inputs);
ret = dts_parse(pdev);
if (ret){
max_error("dts parse error\n");
goto malloc_error;
}
inputs_class = class_create(THIS_MODULE, DRIVER_NAME);
if (IS_ERR(inputs_class)) {
ret= PTR_ERR(inputs_class);
max_error("inputs_class: class create failed\n");
goto malloc_error;
}
max_inputs->dev = device_create(inputs_class,
&pdev->dev, 0, NULL, DEVICE_NAME);
if (unlikely(IS_ERR(max_inputs->dev))) {
ret = PTR_ERR(max_inputs->dev);
max_inputs->dev = NULL;
goto destory_class;
}
ret = sysfs_create_group(&max_inputs->dev->kobj, &attr_group);
if(ret){
max_error("sysfs_create_group in leds driver\n");
goto destory_device;
}
dev_set_drvdata(max_inputs->dev,max_inputs);
max_info("max_input_probe success \n");
return 0;
destory_device:
device_destroy(inputs_class,0);
destory_class:
class_destroy(inputs_class);
malloc_error:
kfree(max_inputs);
return -ENODEV;
}
static int max_input_remove(struct platform_device *pdev)
{
max_inputs_driver * max_inputs = (max_inputs_driver *)platform_get_drvdata(pdev);
devm_free_irq(&pdev->dev, max_inputs->irq, max_inputs);
platform_set_drvdata(pdev, NULL);
kfree(max_inputs);
return 0;
}
static const struct of_device_id max_input_dt_match[] = {
{
.compatible = "max, input",
},
{},
};
static struct platform_driver input_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
.of_match_table = max_input_dt_match,
},
.probe = max_input_probe,
.remove = max_input_remove,
};
static int __init orange_input_init(void)
{
if (platform_driver_register(&input_driver)) {
max_error("failed to register driver\n");
return -ENODEV;
}
max_info("orange_input_init:module init\n");
return 0;
}
static void __exit orange_input_exit(void)
{
max_info("orange_input_exit module exit\n");
}
module_init(orange_input_init);
module_exit(orange_input_exit);
MODULE_DESCRIPTION("Max GPIO Input Test Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("738270732@qq.com");