tiny4412 设备树之按键中断(一)

xiaoxiao2021-02-28  77

开发板:tiny4412(1611)

内核:linux4.4

编译器: arm-none-linux-gnueabi-gcc (gcc version 4.8.3 20140320

中断背后的知识:http://www.cnblogs.com/pengdonglin137/p/6349209.html

使用到的引脚是XEINT26,即GPX3_2

在设备树下添加节点:

interrupt_int26 { compatible = "tiny4412,interrupt_int26"; tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>; };

interrupt_int26是节点名,compatible属性用来匹配platform驱动

tiny4412,int_gpio1是我们自定义的一个属性,后面三个值分别是中断域(中断控制器) gpio引脚 flags

这里的flags即高电平有效

装载新的设备树后可以在sys/firmware/devicetree/base下看到interrupt_int26节点

驱动:

#include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/cdev.h> #include <asm/uaccess.h> #include <linux/kdev_t.h> #include <linux/fs.h> typedef struct { int gpio; int irq; char name[20]; }int_demo_data_t; #define INT_NUM 1 static struct class *int26_class= NULL; struct device *class_dev= NULL; static int_demo_data_t *data = NULL; static int major; static struct cdev int26_cdev; static const char* devname = "int26"; static dev_t int_dev; static const struct file_operations int26_fops; static unsigned char key_val=1; static volatile int ev_press = 0; static DECLARE_WAIT_QUEUE_HEAD(int26_waitq); static irqreturn_t int26_irq(int irq, void *data) { ev_press = 1; wake_up_interruptible(&int26_waitq); return IRQ_HANDLED; } static int int26_open(struct inode * inode, struct file * filp) { printk("%s enter.\n", __func__); devm_request_any_context_irq(class_dev, data->irq,int26_irq, IRQF_TRIGGER_FALLING, data->name, data); return 0; } static ssize_t int26_read(struct file *filp, char __user *buffer,size_t length, loff_t *offset) { if (length != 1) return -EINVAL; wait_event_interruptible(int26_waitq, ev_press); copy_to_user(buffer, &key_val, sizeof(key_val)); ev_press = 0; return 1; } static int int26_release(struct inode *inode, struct file *file) { devm_free_irq(class_dev,data->irq,data); return 0; } static int int_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int irq_gpio = -1; int irq = -1; printk("%s enter.\n", __func__); if (!dev->of_node) { dev_err(dev, "no platform data.\n"); goto err1; } data = devm_kmalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) { dev_err(dev, "no memory.\n"); goto err0; } sprintf(data->name, "tiny4412,int_gpio1"); irq_gpio = of_get_named_gpio(dev->of_node,data->name, 0); if (irq_gpio < 0) { dev_err(dev, "Looking up %s property in node %s failed %d\n",data->name, dev->of_node->full_name, irq_gpio); goto err1; } data->gpio = irq_gpio; irq = gpio_to_irq(irq_gpio); if (irq < 0) { dev_err(dev,"Unable to get irq number for GPIO %d, error %d\n",irq_gpio, irq); goto err1; } data->irq = irq; printk("%s: gpio: %d ---> irq (%d)\n", __func__, irq_gpio, irq); alloc_chrdev_region(&int_dev, 0, INT_NUM, "int26"); major = MAJOR(int_dev); cdev_init(&int26_cdev, &int26_fops); cdev_add(&int26_cdev, MKDEV(major, 0), INT_NUM); int26_class=class_create(THIS_MODULE,"int26"); class_dev=device_create(int26_class, NULL, int_dev, NULL, "%s", devname); return 0; err1: devm_kfree(dev, data); err0: return -EINVAL; } static int int_remove(struct platform_device *pdev) { printk("%s enter.\n", __func__); unregister_chrdev_region(int_dev,INT_NUM); cdev_del(&int26_cdev); device_destroy(int26_class,MKDEV(major, 0)); class_destroy(int26_class); return 0; } static const struct of_device_id dt_ids[] = { { .compatible = "tiny4412,interrupt_int26", }, {}, }; MODULE_DEVICE_TABLE(of, dt_ids); static struct platform_driver int26_driver = { .driver = { .name = "int26", .of_match_table = of_match_ptr(dt_ids), }, .probe = int_probe, .remove = int_remove, }; static const struct file_operations int26_fops={ .owner = THIS_MODULE, .open = int26_open, .read = int26_read, .release= int26_release, }; static int __init int26_init(void) { int ret; ret = platform_driver_register(&int26_driver); if (ret) printk(KERN_ERR "int demo: probe failed: %d\n", ret); return ret; } module_init(int26_init); static void __exit int26_exit(void) { platform_driver_unregister(&int26_driver); } module_exit(int26_exit); MODULE_LICENSE("GPL");

驱动中platform_driver中of_match_table匹配设备树的compatible属性,利用节点的tiny4412,int_gpio1属性来获得中断号,gpio_to_irq把引脚配置成中断模式,devm_request_any_context_irq向内核申请。

测试程序:

#include <stdio.h> #include <fcntl.h> int main(int argc,char *argv[]){ int fd; char buf; int num; fd=open("/dev/int26",O_RDONLY); if(fd<0){ printf("can not open /dev/int26\n"); return -1; } while(1){ num=read(fd,&buf,sizeof(char)); if(num!=sizeof(char)){ printf("read error\n"); return -1; } printf("read:%d\n",buf); } }

执行程序后,按下按键即可看到输出信息。目前驱动存在无法卸载的bug,待调试。。

转载请注明原文地址: https://www.6miu.com/read-58060.html

最新回复(0)