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

开发板: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 
#include 
#include 
#include 
#include 
#include 
#include 
#include  
#include  
#include 
#include 
#include 

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 
#include 

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,待调试。。


你可能感兴趣的:(Tiny4412,Linux,Device,Tree,Tiny4412之旅)