From 93c63d759f33238a77f2c1efefa5b8deeecca8ce Mon Sep 17 00:00:00 2001 From: Ajay Dudani Date: Wed, 5 Sep 2012 17:07:13 +0530 Subject: [PATCH] input: pwrkey: Handle out-of-order press and release interrupts There is a possibility of receiving a release interrupt before press when both these actions (press and release) of the power-key are very close-by (~1-2ms) to the debounce time of the key. Handle this case by maintaining a state variable. Also mark the release interrupt as a wakeup source to wakeup the system when the above mentioned abnormal case occurs. CRs-Fixed: 394289 Change-Id: I74475c1e5159dd30e52aca91243eec7e2fac4d57 Signed-off-by: Anirudh Ghayal --- drivers/input/misc/pmic8xxx-pwrkey.c | 29 +++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index 65791cbadf90..4f21adceac05 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,6 +35,8 @@ struct pmic8xxx_pwrkey { struct input_dev *pwr; int key_press_irq; + int key_release_irq; + bool press; const struct pm8xxx_pwrkey_platform_data *pdata; }; @@ -42,6 +44,13 @@ static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey) { struct pmic8xxx_pwrkey *pwrkey = _pwrkey; + if (pwrkey->press == true) { + pwrkey->press = false; + return IRQ_HANDLED; + } else { + pwrkey->press = true; + } + input_report_key(pwrkey->pwr, KEY_POWER, 1); input_sync(pwrkey->pwr); @@ -52,6 +61,14 @@ static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey) { struct pmic8xxx_pwrkey *pwrkey = _pwrkey; + if (pwrkey->press == false) { + input_report_key(pwrkey->pwr, KEY_POWER, 1); + input_sync(pwrkey->pwr); + pwrkey->press = true; + } else { + pwrkey->press = false; + } + input_report_key(pwrkey->pwr, KEY_POWER, 0); input_sync(pwrkey->pwr); @@ -63,8 +80,10 @@ static int pmic8xxx_pwrkey_suspend(struct device *dev) { struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev); - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev)) { enable_irq_wake(pwrkey->key_press_irq); + enable_irq_wake(pwrkey->key_release_irq); + } return 0; } @@ -73,8 +92,10 @@ static int pmic8xxx_pwrkey_resume(struct device *dev) { struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev); - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev)) { disable_irq_wake(pwrkey->key_press_irq); + disable_irq_wake(pwrkey->key_release_irq); + } return 0; } @@ -155,7 +176,9 @@ static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev) } pwrkey->key_press_irq = key_press_irq; + pwrkey->key_release_irq = key_release_irq; pwrkey->pwr = pwr; + pwrkey->press = false; platform_set_drvdata(pdev, pwrkey);