aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;