查看: 253|回复: 0
打印 上一主题 下一主题

【Seeed开发板试用体验】内核篇(3)实现BBG的GPIO中断驱动

[复制链接] qrcode

17

主题

23

帖子

68

积分

注册会员

Rank: 2

积分
68
楼主
跳转到指定楼层
发表于 2015-12-5 08:15 PM | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

    废话不说了,直接说实现,想必用的人应该能看懂。

    以下代码均为控制P8.15引脚,即当该引脚的电平变化时,会触发中断响应函数。在Linux设备驱动程序中,对中断响应函数的实现,主要介绍了3种:直接响应,tasklet机制和workqueue机制。有兴趣的可查看Linux设备驱动第3版的第10章,下面是驱动代码和实现效果,makefile文件可参考上一节(主要修改下名字)。

一、直接响应中断函数

1 驱动代码


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)

#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE       0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0

#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C

#define GPIO_PIN_FLAGS GPIOF_IN
#define DEV_NAME "gpiop815"
#define GPIO_PIN_ADDRESS 47 // P8 pin 15
#define GPIO_PIN_LABEL "P815"


static irqreturn_t my_irq_handler (int irq, void *dev_id)
{
    printk(KERN_ALERT"From Kernel P815n");
    printk(KERN_ALERT"my_irq_handler workingn");
    return IRQ_HANDLED;
}


static int __init mydev_init()
{
    int retval, irq, regval;
    void __iomem *mem;
    void __iomem *cm_per;

    printk(KERN_ALERT"p8.15 dirver initn");
    /**
    * Request the GPIO lines for the IRQ channels.
    */
    retval = gpio_request_one(GPIO_PIN_ADDRESS, GPIO_PIN_FLAGS, GPIO_PIN_LABEL);
    irq = gpio_to_irq (GPIO_PIN_ADDRESS);
    retval = request_irq (irq, my_irq_handler, 0 , GPIO_PIN_LABEL, NULL);//
    irq_set_irq_type (irq, IRQF_TRIGGER_RISING);


    /*    Enable GPIO2 clock    */
    cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
    iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
    iounmap(cm_per);
    /**
    * Setup the IRQ registers with the appropriate values.
    */
    mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);

    // Enable the IRQ ability for GPIO.
    regval = ioread32 (mem + GPIO_IRQSTATUS_0);
    regval |= (1 << 2);
    iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
    regval = ioread32 (mem + GPIO_IRQSTATUS_1);
    regval |= (1 << 2);
    iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
    // Set GPIO for rising and falling edge detection.
    regval = ioread32 (mem + GPIO_RISINGDETECT);
    regval |= (1 << 2);
    iowrite32(regval, mem + GPIO_RISINGDETECT);
    regval = ioread32 (mem + GPIO_RISINGDETECT);
    regval |= (1 << 2);
    iowrite32 (regval, mem + GPIO_RISINGDETECT);

    // Release the mapped memory.
    iounmap (mem);
    return 0;
}

static void __exit mydev_exit()
{
    printk(KERN_ALERT"p8.15 dirver exitn");

    free_irq (gpio_to_irq (GPIO_PIN_ADDRESS), NULL);
    gpio_free (GPIO_PIN_ADDRESS);

 }

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("gjianw217");


2 示例效果

二、tasklet机制


1 驱动代码


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)

#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE       0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0

#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C

#define GPIO_PIN_FLAGS GPIOF_IN
#define DEV_NAME "gpiop815"
#define GPIO_PIN_ADDRESS 47 // P8 pin 15
#define GPIO_PIN_LABEL "P815"

struct tasklet_struct dlp_tasklet;	//定义tasklet结构体

void dlp_func(struct work_struct *work)
{
    printk(KERN_ALERT"dlp_tasklet working!n");

}


static irqreturn_t my_irq_handler (int irq, void *dev_id)
{
    printk(KERN_ALERT"From Kernel P815n");
    tasklet_schedule(&dlp_tasklet);

    return IRQ_HANDLED;
}


static int __init mydev_init()
{
    int retval, irq, regval;
    void __iomem *mem;
    void __iomem *cm_per;

    printk (KERN_ALERT "p8.15 dirver initn");

    /*tasklet*/
    tasklet_init(&dlp_tasklet, dlp_func, (unsigned long)123);


    /**
    * Request the GPIO lines for the IRQ channels.
    */
    retval = gpio_request_one(GPIO_PIN_ADDRESS, GPIO_PIN_FLAGS, GPIO_PIN_LABEL);
    irq = gpio_to_irq (GPIO_PIN_ADDRESS);
    retval = request_irq (irq, my_irq_handler, 0 , GPIO_PIN_LABEL, NULL);//
    irq_set_irq_type (irq, IRQF_TRIGGER_RISING);


    /*    Enable GPIO2 clock    */
    cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
    iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
    iounmap(cm_per);
    /**
    * Setup the IRQ registers with the appropriate values.
    */
    mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);

    // Enable the IRQ ability for GPIO.
    regval = ioread32 (mem + GPIO_IRQSTATUS_0);
    regval |= (1 << 2);
    iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
    regval = ioread32 (mem + GPIO_IRQSTATUS_1);
    regval |= (1 << 2);
    iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
    // Set GPIO for rising and falling edge detection.
    regval = ioread32 (mem + GPIO_RISINGDETECT);
    regval |= (1 << 2);
    iowrite32(regval, mem + GPIO_RISINGDETECT);
    regval = ioread32 (mem + GPIO_RISINGDETECT);
    regval |= (1 << 2);
    iowrite32 (regval, mem + GPIO_RISINGDETECT);

    // Release the mapped memory.
    iounmap (mem);
    return 0;
}

static void __exit mydev_exit()
{
    printk(KERN_ALERT"p8.15 dirver exitn");
    tasklet_kill(&dlp_tasklet);

    free_irq (gpio_to_irq (GPIO_PIN_ADDRESS), NULL);
    gpio_free (GPIO_PIN_ADDRESS);

 }

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("gjianw217");


2 示例效果



三、workqueue机制


1 驱动代码


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)

#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE       0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0

#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C

#define GPIO_PIN_FLAGS GPIOF_IN
#define DEV_NAME "gpiop815"
#define GPIO_PIN_ADDRESS 47 // P8 pin 15
#define GPIO_PIN_LABEL "P815"

struct workqueue_struct *dlp_wq;	 //定义工作队列
struct work_struct dlp_work;		 //定义work结构体

void dlp_func(struct work_struct *work)
{
	printk(KERN_ALERT"dlp_work working!n");

}


static irqreturn_t my_irq_handler (int irq, void *dev_id)
{
	printk(KERN_ALERT"From Kernel P815n");
    queue_work(dlp_wq ,&dlp_work);

    return IRQ_HANDLED;
}


static int __init mydev_init()
{
    int retval, irq, regval;
    void __iomem *mem;
    void __iomem *cm_per;

    printk (KERN_ALERT "p8.15 dirver initn");

    /*work*/
	dlp_wq = create_workqueue("dlp");
	INIT_WORK(&dlp_work, dlp_func);

    /**
    * Request the GPIO lines for the IRQ channels.
    */
    retval = gpio_request_one(GPIO_PIN_ADDRESS, GPIO_PIN_FLAGS, GPIO_PIN_LABEL);
    irq = gpio_to_irq (GPIO_PIN_ADDRESS);
    retval = request_irq (irq, my_irq_handler, 0 , GPIO_PIN_LABEL, NULL);
    irq_set_irq_type (irq, IRQF_TRIGGER_RISING);

    /**
    *    Enable GPIO2 clock
    */
    cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
    iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
    iounmap(cm_per);

    /**
    * Setup the IRQ registers with the appropriate values.
    */
    mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
    regval = ioread32 (mem + GPIO_IRQSTATUS_0);
    regval |= (1 << 2);
    iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
    regval = ioread32 (mem + GPIO_IRQSTATUS_1);
    regval |= (1 << 2);
    iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
    // Set GPIO for rising and falling edge detection.
    regval = ioread32 (mem + GPIO_RISINGDETECT);
    regval |= (1 << 2);
    iowrite32(regval, mem + GPIO_RISINGDETECT);
    regval = ioread32 (mem + GPIO_RISINGDETECT);
    regval |= (1 << 2);
    iowrite32 (regval, mem + GPIO_RISINGDETECT);

    iounmap (mem);
    return 0;
}

static void __exit mydev_exit()
{
    printk(KERN_ALERT"p8.15 dirver exitn");

	flush_workqueue(dlp_wq);
	destroy_workqueue(dlp_wq);

    free_irq (gpio_to_irq (GPIO_PIN_ADDRESS), NULL);
    gpio_free (GPIO_PIN_ADDRESS);

 }

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("gjianw217");


2 示例效果




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表