一:总体步骤
涉及文件:
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 <linux/delay.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/suspend.h>
#include <linux/poll.h>
/*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");