博主写的 demo
博主下面给的是简化版,并且自测OK,分享给大家,以后如果需要可以copy xxx.c
#include < linux/module.h >
#include < linux/i2c.h >
#include < linux/interrupt.h >
#include < linux/delay.h >
#include < linux/uaccess.h >
#include < linux/pm.h >
#include < linux/slab.h >
#include < linux/sysctl.h >
#include < linux/proc_fs.h >
#include < linux/delay.h >
#include < linux/platform_device.h >
#include < linux/input.h >
#include < linux/gpio_keys.h >
#include < linux/workqueue.h >
#include < linux/gpio.h >
#include < linux/of.h >
#include < linux/of_platform.h >
#include < linux/of_gpio.h >
#include < linux/of_irq.h >
#include < linux/spinlock.h >
#include < linux/cdev.h >
static int gpionum = 0;
static int irqnum = 0;
static irqreturn_t my_handler(int irq, void *dev_id)
{
printk("%srn",__FUNCTION__);
return IRQ_HANDLED;
}
static int gpio_keys_probe(struct platform_device *pdev)
{
int ret = 0;
struct device_node *node = NULL;; /* 设备节点*/
node = of_find_compatible_node(NULL,NULL,"atkalpha-key");
if (node == NULL){
printk("%s:atkalpha-key node not find!rn",__FUNCTION__);
return -EINVAL;
}
/* 提取 GPIO */
gpionum = of_get_named_gpio(node,"key-gpio", 0);
if (gpionum < 0) {
printk("of_get_named_gpio can't get keyrn");
}
/* 初始化 key 所使用的 IO,并且设置成中断模式 */
gpio_request(gpionum, "key-gpio");
gpio_direction_input(gpionum);
irqnum = gpio_to_irq(gpionum);
ret = request_irq(irqnum,my_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "my-key", NULL);
if(ret < 0){
printk("irq %d request failed!rn", irqnum);
return -EFAULT;
}
return 0;
}
static const struct of_device_id gpio_keys_of_match[] = {
{ .compatible = "atkalpha-key", },
{ },
};
MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
static int gpio_keys_remove(struct platform_device *pdev)
{
return 0;
}
static int gpio_keys_suspend(struct device *dev)
{
printk("%srn",__FUNCTION__);
enable_irq_wake(irqnum);
return 0;
}
static int gpio_keys_resume(struct device *dev)
{
printk("%srn",__FUNCTION__);
disable_irq_wake(irqnum);
return 0;
}
static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = gpio_keys_remove,
.driver = {
.name = "my-key",
.pm = &gpio_keys_pm_ops,
.of_match_table = of_match_ptr(gpio_keys_of_match),
}
};
static int __init gpio_keys_init(void)
{
return platform_driver_register(&gpio_keys_device_driver);
}
static void __exit gpio_keys_exit(void)
{
platform_driver_unregister(&gpio_keys_device_driver);
}
module_init(gpio_keys_init);
module_exit(gpio_keys_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jason");
MODULE_DESCRIPTION("Keyboard driver for GPIOs");
MODULE_ALIAS("platform:gpio-keys");
xxx.dts
key {
#address-cells = < 1 >;
#size-cells = < 1 >;
compatible = "atkalpha-key";
key-gpio = < &gpio1 18 GPIO_ACTIVE_LOW >; /* KEY0 */
interrupt-parent = < &gpio1 >;
interrupts = < 18 IRQ_TYPE_EDGE_BOTH >; /* FALLING RISING */
gpio-key,wakeup;
status = "okay";
};
最后再总结一下:中断唤醒系统和普通的驱动区别在于,多了两个函数:suspend 和 resume,在suspend 函数中,调用 enable_irq_wake,表示该中断号在系统休眠时也是 enable 状态,可以触发中断。在 resume 函数中,调用 disable_irq_wake ,恢复原始的中断触发路径。
然后使用 SIMPLE_DEV_PM_OPS 宏将 suspend 和 resume 函数注册到 gpio_keys_pm_ops 操作集,最终由 platform 注册到系统中。这样完成后,系统休眠过程中就会调用到设备注册的 suspend,系统唤醒过程中就会调用设备注册的 resume 函数。
note:该 demo 只用来唤醒系统,如果你的中断是在 I2C 等设备驱动中,唤醒系统后要立刻在中断处理函数中进行 I2C 通信,写法不太一样,但是框架相同。
另外,该驱动的中断处理函数中没做什么东西,因此唤醒后执行完中断处理函数后又会睡过去。如果你想要该中断唤醒系统后让系统一直处于唤醒状态,请在中断处理函数中使用 __pm_stay_awake() 和__pm_relax()函数。
-
嵌入式
+关注
关注
5083文章
19133浏览量
305608 -
Linux
+关注
关注
87文章
11310浏览量
209658 -
系统
+关注
关注
1文章
1017浏览量
21362
发布评论请先 登录
相关推荐
评论