aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBinghua Duan <Binghua.Duan@csr.com>2013-06-03 02:38:46 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2013-06-03 02:49:12 -0400
commit9b5f953ddc3247dd0c3d0cafa4247be10d5c05db (patch)
tree8a3b629f57456c62202d2ca22498e97c80efe1a1
parentf6e63f8032571bb58d054071edfd35d88f9dd07a (diff)
Input: sirfsoc_pwrc - add onkey input driver for CSR SiRFprimaII PWRC
There is an embedded PWRC(power controller) in SiRFprimaII and SiRFatlasVI, we have an ONKEY button which can generate interrupt to IRQ controller. In a typical user scenarios, at the runtime, if users touch the key, we put system to s2ram status. Signed-off-by: Binghua Duan <Binghua.Duan@csr.com> Signed-off-by: Xianglong Du <Xianglong.Du@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/sirfsoc-onkey.c165
3 files changed, 176 insertions, 0 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index af80928a46b4..f6002a76c29f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -637,4 +637,14 @@ config INPUT_XEN_KBDDEV_FRONTEND
637 To compile this driver as a module, choose M here: the 637 To compile this driver as a module, choose M here: the
638 module will be called xen-kbdfront. 638 module will be called xen-kbdfront.
639 639
640config INPUT_SIRFSOC_ONKEY
641 bool "CSR SiRFSoC power on/off/suspend key support"
642 depends on ARCH_SIRF && OF
643 default y
644 help
645 Say Y here if you want to support for the SiRFSoC power on/off/suspend key
646 in Linux, after you press the onkey, system will suspend.
647
648 If unsure, say N.
649
640endif 650endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index d7fc17f11d77..829de43a2427 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
51obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o 51obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
52obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o 52obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
53obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o 53obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
54obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
54obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o 55obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
55obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o 56obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
56obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o 57obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
new file mode 100644
index 000000000000..0621c367049a
--- /dev/null
+++ b/drivers/input/misc/sirfsoc-onkey.c
@@ -0,0 +1,165 @@
1/*
2 * Power key driver for SiRF PrimaII
3 *
4 * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/module.h>
10#include <linux/init.h>
11#include <linux/interrupt.h>
12#include <linux/delay.h>
13#include <linux/platform_device.h>
14#include <linux/input.h>
15#include <linux/rtc/sirfsoc_rtciobrg.h>
16#include <linux/of.h>
17
18struct sirfsoc_pwrc_drvdata {
19 u32 pwrc_base;
20 struct input_dev *input;
21};
22
23#define PWRC_ON_KEY_BIT (1 << 0)
24
25#define PWRC_INT_STATUS 0xc
26#define PWRC_INT_MASK 0x10
27
28static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
29{
30 struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
31 u32 int_status;
32
33 int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
34 PWRC_INT_STATUS);
35 sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
36 pwrcdrv->pwrc_base + PWRC_INT_STATUS);
37
38 /*
39 * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
40 * to queue a SUSPEND APM event
41 */
42 input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
43 input_sync(pwrcdrv->input);
44
45 /*
46 * Todo: report KEY_POWER event for Android platforms, Android PowerManager
47 * will handle the suspend and powerdown/hibernation
48 */
49
50 return IRQ_HANDLED;
51}
52
53static const struct of_device_id sirfsoc_pwrc_of_match[] = {
54 { .compatible = "sirf,prima2-pwrc" },
55 {},
56}
57MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
58
59static int sirfsoc_pwrc_probe(struct platform_device *pdev)
60{
61 struct device_node *np = pdev->dev.of_node;
62 struct sirfsoc_pwrc_drvdata *pwrcdrv;
63 int irq;
64 int error;
65
66 pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata),
67 GFP_KERNEL);
68 if (!pwrcdrv) {
69 dev_info(&pdev->dev, "Not enough memory for the device data\n");
70 return -ENOMEM;
71 }
72
73 /*
74 * we can't use of_iomap because pwrc is not mapped in memory,
75 * the so-called base address is only offset in rtciobrg
76 */
77 error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
78 if (error) {
79 dev_err(&pdev->dev,
80 "unable to find base address of pwrc node in dtb\n");
81 return error;
82 }
83
84 pwrcdrv->input = devm_input_allocate_device(&pdev->dev);
85 if (!pwrcdrv->input)
86 return -ENOMEM;
87
88 pwrcdrv->input->name = "sirfsoc pwrckey";
89 pwrcdrv->input->phys = "pwrc/input0";
90 pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
91
92 irq = platform_get_irq(pdev, 0);
93 error = devm_request_irq(&pdev->dev, irq,
94 sirfsoc_pwrc_isr, IRQF_SHARED,
95 "sirfsoc_pwrc_int", pwrcdrv);
96 if (error) {
97 dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
98 irq, error);
99 return error;
100 }
101
102 sirfsoc_rtc_iobrg_writel(
103 sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) |
104 PWRC_ON_KEY_BIT,
105 pwrcdrv->pwrc_base + PWRC_INT_MASK);
106
107 error = input_register_device(pwrcdrv->input);
108 if (error) {
109 dev_err(&pdev->dev,
110 "unable to register input device, error: %d\n",
111 error);
112 return error;
113 }
114
115 platform_set_drvdata(pdev, pwrcdrv);
116 device_init_wakeup(&pdev->dev, 1);
117
118 return 0;
119}
120
121static int sirfsoc_pwrc_remove(struct platform_device *pdev)
122{
123 device_init_wakeup(&pdev->dev, 0);
124
125 return 0;
126}
127
128#ifdef CONFIG_PM_SLEEP
129static int pwrc_resume(struct device *dev)
130{
131 struct platform_device *pdev = to_platform_device(dev);
132 struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev);
133
134 /*
135 * Do not mask pwrc interrupt as we want pwrc work as a wakeup source
136 * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
137 */
138 sirfsoc_rtc_iobrg_writel(
139 sirfsoc_rtc_iobrg_readl(
140 pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT,
141 pwrcdrv->pwrc_base + PWRC_INT_MASK);
142
143 return 0;
144}
145#endif
146
147static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume);
148
149static struct platform_driver sirfsoc_pwrc_driver = {
150 .probe = sirfsoc_pwrc_probe,
151 .remove = sirfsoc_pwrc_remove,
152 .driver = {
153 .name = "sirfsoc-pwrc",
154 .owner = THIS_MODULE,
155 .pm = &sirfsoc_pwrc_pm_ops,
156 .of_match_table = of_match_ptr(sirfsoc_pwrc_of_match),
157 }
158};
159
160module_platform_driver(sirfsoc_pwrc_driver);
161
162MODULE_LICENSE("GPLv2");
163MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
164MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");
165MODULE_ALIAS("platform:sirfsoc-pwrc");