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

来源:互联网 发布:java客户端服务端通信 编辑:程序博客网 时间:2024/06/15 18:02

开发板: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,待调试。。


原创粉丝点击