aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/misc
diff options
context:
space:
mode:
authorXianglong Du <Xianglong.Du@csr.com>2014-02-15 15:30:58 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-02-15 17:09:33 -0500
commita1a7521064428fc1cf8e2942179525a22cde1d49 (patch)
tree565f6585ddc0f403cd2207b9ee8c8ce09480bbfb /drivers/input/misc
parenta5e466451939153cbec4d5446be139ba666ee28d (diff)
Input: sirfsoc-onkey - report release event by detecting pin status
This change adds a delayed_work to detect the release of onkey since HW will not generate interrupt for it. At the same time, we move the KEY event to POWER instead of SUSPEND, which will be suitable for both Android and Linux. Userspace PowerManager Daemon will decide to suspend or shutdown based on how long we have touched onkey. Signed-off-by: Xianglong Du <Xianglong.Du@csr.com> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/misc')
-rw-r--r--drivers/input/misc/sirfsoc-onkey.c43
1 files changed, 32 insertions, 11 deletions
diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
index 81cdf51f8246..a6e76080af5f 100644
--- a/drivers/input/misc/sirfsoc-onkey.c
+++ b/drivers/input/misc/sirfsoc-onkey.c
@@ -13,16 +13,41 @@
13#include <linux/input.h> 13#include <linux/input.h>
14#include <linux/rtc/sirfsoc_rtciobrg.h> 14#include <linux/rtc/sirfsoc_rtciobrg.h>
15#include <linux/of.h> 15#include <linux/of.h>
16#include <linux/workqueue.h>
16 17
17struct sirfsoc_pwrc_drvdata { 18struct sirfsoc_pwrc_drvdata {
18 u32 pwrc_base; 19 u32 pwrc_base;
19 struct input_dev *input; 20 struct input_dev *input;
21 struct delayed_work work;
20}; 22};
21 23
22#define PWRC_ON_KEY_BIT (1 << 0) 24#define PWRC_ON_KEY_BIT (1 << 0)
23 25
24#define PWRC_INT_STATUS 0xc 26#define PWRC_INT_STATUS 0xc
25#define PWRC_INT_MASK 0x10 27#define PWRC_INT_MASK 0x10
28#define PWRC_PIN_STATUS 0x14
29#define PWRC_KEY_DETECT_UP_TIME 20 /* ms*/
30
31static int sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata *pwrcdrv)
32{
33 u32 state = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
34 PWRC_PIN_STATUS);
35 return !(state & PWRC_ON_KEY_BIT); /* ON_KEY is active low */
36}
37
38static void sirfsoc_pwrc_report_event(struct work_struct *work)
39{
40 struct sirfsoc_pwrc_drvdata *pwrcdrv =
41 container_of(work, struct sirfsoc_pwrc_drvdata, work.work);
42
43 if (sirfsoc_pwrc_is_on_key_down(pwrcdrv)) {
44 schedule_delayed_work(&pwrcdrv->work,
45 msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
46 } else {
47 input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 0);
48 input_sync(pwrcdrv->input);
49 }
50}
26 51
27static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id) 52static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
28{ 53{
@@ -34,17 +59,10 @@ static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
34 sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT, 59 sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
35 pwrcdrv->pwrc_base + PWRC_INT_STATUS); 60 pwrcdrv->pwrc_base + PWRC_INT_STATUS);
36 61
37 /* 62 input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 1);
38 * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
39 * to queue a SUSPEND APM event
40 */
41 input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
42 input_sync(pwrcdrv->input); 63 input_sync(pwrcdrv->input);
43 64 schedule_delayed_work(&pwrcdrv->work,
44 /* 65 msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
45 * Todo: report KEY_POWER event for Android platforms, Android PowerManager
46 * will handle the suspend and powerdown/hibernation
47 */
48 66
49 return IRQ_HANDLED; 67 return IRQ_HANDLED;
50} 68}
@@ -76,6 +94,7 @@ static void sirfsoc_pwrc_close(struct input_dev *input)
76 struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input); 94 struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
77 95
78 sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false); 96 sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
97 cancel_delayed_work_sync(&pwrcdrv->work);
79} 98}
80 99
81static const struct of_device_id sirfsoc_pwrc_of_match[] = { 100static const struct of_device_id sirfsoc_pwrc_of_match[] = {
@@ -115,7 +134,9 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
115 134
116 pwrcdrv->input->name = "sirfsoc pwrckey"; 135 pwrcdrv->input->name = "sirfsoc pwrckey";
117 pwrcdrv->input->phys = "pwrc/input0"; 136 pwrcdrv->input->phys = "pwrc/input0";
118 pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR); 137 pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY);
138
139 INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
119 140
120 pwrcdrv->input->open = sirfsoc_pwrc_open; 141 pwrcdrv->input->open = sirfsoc_pwrc_open;
121 pwrcdrv->input->close = sirfsoc_pwrc_close; 142 pwrcdrv->input->close = sirfsoc_pwrc_close;