博主寫的 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()函數。
-
嵌入式
+關注
關注
5082文章
19111瀏覽量
304856 -
Linux
+關注
關注
87文章
11296瀏覽量
209358 -
系統
+關注
關注
1文章
1015瀏覽量
21332
發布評論請先 登錄
相關推薦
評論