imx6系列--将一个gpio设置为可唤醒系统的外部中断流程

一:总体步骤
涉及文件:
a. 设备树文件:正确配置gpio复用及引脚属性。
b. 驱动模块文件:设置gpio中断相关操作。

二:实际操作
1.修改设备树
参考方法:
http://blog.csdn.net/vertor11/article/details/67633652
例如:将imx6ul的下图两个gpio设置为外部中断
这里写图片描述
设备树配置示例:

   fsl,pins = <
                MX6UL_PAD_LCD_HSYNC__GPIO3_IO02            0x000010B0
                MX6UL_PAD_LCD_VSYNC__GPIO3_IO03            0x000010B0
            >;

2.驱动修改
参考方法:
http://blog.csdn.net/jiangbo_wei/article/details/9852659
http://www.wowotech.net/linux_kenrel/request_threaded_irq.html
http://blog.csdn.net/njuitjf/article/details/21475405
示例代码:

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

/*GPIO3_2: (3-1)*32 + 2*/
#define MCU_WAKEUP_PIN  66
static int wakeup_mcu_irq = 0;

/*中断服务函数*/
static irqreturn_t mcu_irq_handler(int irq, void *dev)
{
    printk ("## mcu wake up! \n");
    /*其他模块的导出符号*/
    set_bit(8, &tbox_wakesoure);
    return IRQ_HANDLED;
}

static int wakesource_open(struct inode *inode, struct file *file)
{
    return 0;
}

static int wakesource_release(struct inode *inode, struct file *file)
{
    /*note: releasing the wdt in NOWAYOUT-mode does not stop it */
    return 0;
}

static int wakesource_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    if (!buf || count < 1)
        return 0;

    if (count > 4)
        count = 4;
    if (copy_to_user(buf, (void*)&tbox_wakesoure, count)) {
        printk(KERN_ERR"wakesource_read copy_to_user failed.");
        return -EFAULT;
    }
    return count;
}

static int wakesource_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
    tbox_wakesoure = 0;
    return count;
}

static const struct file_operations wakesource_fops = {
    .owner = THIS_MODULE,   
    .open = wakesource_open,
    .release = wakesource_release,
    .read = wakesource_read,
    .write = wakesource_write,
};

static struct miscdevice wakesource_device = {
    .minor = MISC_DYNAMIC_MINOR,    
    .name = "wakesource",
    .fops = &wakesource_fops,
};

static int __init gpio_init(void)
{
    int ret;

    /*注册misc设备驱动*/
    ret = misc_register(&wakesource_device);
    if (ret != 0) {
        printk(KERN_ERR "register wakesource_device miscdevice ret");
        return ret;
    }

    /*判断该gpio号码是否有效*/
    if (0 == gpio_is_valid(MCU_WAKEUP_PIN)) {
        printk(KERN_ERR "mcu  gpio is invalid!\n");
        goto error;
    } 


    /*请求申请单个GPIO,并且配置其输入,输出*/
    ret = gpio_request_one(MCU_WAKEUP_PIN, GPIOF_IN, "mcupin");
    if (ret < 0) {
        printk(KERN_ERR "Failed to request GPIO %d, ret %d\n",
            MCU_WAKEUP_PIN, ret);
        goto error;
    }

    /*GPIO映射到中断*/
    wakeup_mcu_irq = gpio_to_irq(MCU_WAKEUP_PIN);
    if (wakeup_mcu_irq < 0) {
        ret = wakeup_mcu_irq;
        printk("Unable to get irq number for GPIO %d, ret %d\n", MCU_WAKEUP_PIN, ret);
        goto error;
    }

    /*设置中断属性*/
    ret = request_threaded_irq(wakeup_mcu_irq, mcu_irq_handler, NULL,
                     IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING|IRQF_NO_SUSPEND | IRQF_ONESHOT,
                     "mcu", NULL);
    if (ret < 0) {
        printk(KERN_ERR "failed to register mcu irq %d!\n", wakeup_mcu_irq);
        goto freeirq;
    }

    /*将irq具有唤醒系统的功能*/
    ret = enable_irq_wake(wakeup_mcu_irq);
    if(ret) {
        printk(KERN_ERR "failed to set mcu gpio irq %d wake up!\n",
            wakeup_mcu_irq);
        goto freeirq;
    }
    printk("4g  mcu wakeup driver probe sucsecc!\n");
    return 0;

freeirq:
    free_irq(wakeup_mcu_irq, NULL);
error:
    misc_deregister(&wakesource_device);

    return ret;
}
module_init(gpio_init);

static void __exit gpio_exit(void)
{
    disable_irq_wake(wakeup_mcu_irq);
    free_irq(wakeup_mcu_irq, NULL);

    if (gpio_is_valid(MCU_WAKEUP_PIN))
        gpio_free(MCU_WAKEUP_PIN);

    misc_deregister(&wakesource_device);
}
module_exit(gpio_exit);

MODULE_AUTHOR("");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("4g wakeup driver");

你可能感兴趣的:(linux系统开发)