7.【linux驱动】中断

用GPIOB_31模拟按键功能,设置上拉,下降沿触发

寄存器版本

linux驱动几乎不用管硬件中断了,内核已经帮我们管理好了所有硬件中断号,并且定义了相应的内核中断号,我们只需要看一下内核中断号。
arch/arm/mach-s5p4418/include/mach/s5paa18_irq.h
在这里插入图片描述
这里GPIOB_31直接用IRQ_GPIO_B_START + 31就好。
在这里插入图片描述
数据手册中得到下降沿触发值为0b010=2。有关GPIO寄存器的定义和操作可以见这篇文章:【linux驱动】GPIO

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h> //含有request_irq、free_irq函数
#include <linux/irq.h>    //含有IRQ_HANDLED\IRQ_TYPE_EDGE_RISING
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <mach/soc.h>
#include <mach/platform.h>

MODULE_LICENSE("GPL");

#pragma pack(4)
static struct GPIO_B{
	unsigned int out_put;
	unsigned int out_enb;
	unsigned int detect_md_0;
	unsigned int detect_md_1;
	unsigned int int_enb;
	unsigned int event_detect;
	unsigned int pad_state;
	unsigned int resv;
	unsigned int func0;
	unsigned int func1;
	unsigned int DETMODEEX;
	unsigned int DETENB;
	unsigned int SLEW;
	unsigned int SLEW_DISABLE_DEFAULT;
	unsigned int DRV1;
	unsigned int DRV1_DISABLE_DEFAULT;
	unsigned int DRV0;
	unsigned int DRV0_DISABLE_DEFAULT;
	unsigned int pull_sell;
	unsigned int PULLSEL_DISABLE_DEFAULT;
	unsigned int pull_enb;
}* gpio_b;
#pragma pack()

dev_t devid;
unsigned int int_num,gpio_b_31_int_num;

static irqreturn_t hello_irq(int irq,void * dev_id)
{
	printk("gpiob_31 down,MAJOR:%d MINOR:%d\n",MAJOR((dev_t)dev_id),MINOR((dev_t)dev_id));
	return IRQ_HANDLED;
}


static int __init hello_init(void){
	int ret = 0;

    devid = MKDEV(241, 1);								//换算设备号
    ret = register_chrdev_region(devid, 1, "char_test");//注册设备,在/proc/drivers下面可以看到
    if (ret < 0)
        goto err0;

	gpio_b = (struct GPIO_B *)ioremap(0xc001b000,sizeof(struct GPIO_B));//映射地址
	gpio_b->func1 |= (1 << 30);			//设置gpio功能
	gpio_b->out_enb &= ~(1 << 31);		//禁用输出
	gpio_b->pull_enb |= (1 << 31);		//使能上下拉
	gpio_b->pull_sell |= (1 << 31);		//设置为上拉
	gpio_b->int_enb |= (1 << 31);		//中断使能
	gpio_b->detect_md_1 |= (2 << 30);	//中断模式为下降沿触发

	gpio_b_31_int_num = IRQ_GPIO_B_START + 31;
	if (!request_irq(gpio_b_31_int_num,hello_irq,IRQF_DISABLED | IRQF_SHARED,"gpio_irq0",(void *)devid)){
        printk("irq registed:%d\n", gpio_b_31_int_num);
        int_num = gpio_b_31_int_num;
    }else{
    	printk("irq regist fail:%d\n",gpio_b_31_int_num);
    }

	printk("hello init\n");
	return 0;

    err0:
        return ret;
}

static void __exit hello_exit(void){
	if(int_num){
		free_irq(gpio_b_31_int_num,(void *)devid);	//取消中断函数注册
	}
	unregister_chrdev_region(devid, 1);
	gpio_b->int_enb &= ~(1 << 31);					//禁用中断
	printk("hello exit\n");
}

module_init(hello_init);
module_exit(hello_exit);

API版本

api版本需要看一下中断模式的设置,从注释看出来下降沿触发依然是2。
arch/arm/mach-s5p4418/soc/gpio.c
在这里插入图片描述

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h> //含有request_irq、free_irq函数
#include <linux/irq.h>    //含有IRQ_HANDLED\IRQ_TYPE_EDGE_RISING
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <mach/soc.h>
#include <mach/platform.h>

MODULE_LICENSE("GPL");

dev_t devid;
unsigned int int_num,gpio_b_31_int_num;

static irqreturn_t hello_irq(int irq,void * dev_id)
{
	printk("gpiob_31 down,MAJOR:%d MINOR:%d\n",MAJOR((dev_t)dev_id),MINOR((dev_t)dev_id));
	return IRQ_HANDLED;
}


static int __init hello_init(void){
	int ret = 0;

    devid = MKDEV(241, 1);								//换算设备号
    ret = register_chrdev_region(devid, 1, "char_test");//注册设备,在/proc/drivers下面可以看到
    if (ret < 0)
        goto err0;

	nxp_soc_gpio_set_io_func(PAD_GPIO_B + 31, 1);		//设置gpio功能
	nxp_soc_gpio_set_io_pull_enb(PAD_GPIO_B + 31, 1);	//使能上下拉 
	nxp_soc_gpio_set_io_pull_sel(PAD_GPIO_B + 31, 1);	//设置为上拉
	nxp_soc_gpio_set_int_enable(PAD_GPIO_B + 31, 1);	//中断使能
	nxp_soc_gpio_set_int_mode(PAD_GPIO_B + 31, 2);		//中断模式为下降沿触发

	gpio_b_31_int_num = IRQ_GPIO_B_START + 31;
	if (!request_irq(gpio_b_31_int_num,hello_irq,IRQF_DISABLED | IRQF_SHARED,"gpio_irq0",(void *)devid)){
        printk("irq registed:%d\n", gpio_b_31_int_num);
        int_num = gpio_b_31_int_num;
    }else{
    	printk("irq regist fail:%d\n",gpio_b_31_int_num);
    }

	printk("hello init\n");
	return 0;

    err0:
        return ret;
}

static void __exit hello_exit(void){
	if(int_num){
		free_irq(gpio_b_31_int_num,(void *)devid);		//取消中断函数注册
	}
	unregister_chrdev_region(devid, 1);
	nxp_soc_gpio_set_io_pull_enb(PAD_GPIO_B + 31, 0);	//禁用上下拉
	nxp_soc_gpio_set_int_enable(PAD_GPIO_B + 31, 0);	//禁用中断
	printk("hello exit\n");
}

module_init(hello_init);
module_exit(hello_exit);

运行一下

[root@minicoco int_register]# insmod gpiob_31.ko
[  128.636000] irq registed:127
[  128.636000] hello init
[root@minicoco int_register]# [  134.824000] gpiob_31 down,MAJOR:241 MINOR:1
[  135.240000] gpiob_31 down,MAJOR:241 MINOR:1
[  136.444000] gpiob_31 down,MAJOR:241 MINOR:1

猜你喜欢

转载自blog.csdn.net/qq_16054639/article/details/106679148
今日推荐