aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-09-15 06:07:12 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2009-09-17 03:47:02 -0400
commit0c73b992dd4c645f050344cb13142c0fd3496824 (patch)
tree64dc9705ea0efadb86e142e7f0cb1fbe36a9cf1c /drivers/input
parent08bad5a821371548942aa13565831f18fe1875f3 (diff)
input: Add support for the WM831x ON pin
The WM831x series of PMICs support control of initial power on through the ON pin on the device with soft control of the pin at other times. Represent this to userspace as KEY_POWER. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/wm831x-on.c163
3 files changed, 174 insertions, 0 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index cbe21bc96b52..852941d108ff 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -279,4 +279,14 @@ config INPUT_BFIN_ROTARY
279 To compile this driver as a module, choose M here: the 279 To compile this driver as a module, choose M here: the
280 module will be called bfin-rotary. 280 module will be called bfin-rotary.
281 281
282config INPUT_WM831X_ON
283 tristate "WM831X ON pin"
284 depends on MFD_WM831X
285 help
286 Support the ON pin of WM831X PMICs as an input device
287 reporting power button status.
288
289 To compile this driver as a module, choose M here: the module
290 will be called wm831x_on.
291
282endif 292endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 79c1e9a5ea31..c97533fb83c8 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -26,4 +26,5 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
26obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o 26obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
27obj-$(CONFIG_INPUT_UINPUT) += uinput.o 27obj-$(CONFIG_INPUT_UINPUT) += uinput.o
28obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o 28obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
29obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
29obj-$(CONFIG_INPUT_YEALINK) += yealink.o 30obj-$(CONFIG_INPUT_YEALINK) += yealink.o
diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c
new file mode 100644
index 000000000000..ba4f5dd7c60e
--- /dev/null
+++ b/drivers/input/misc/wm831x-on.c
@@ -0,0 +1,163 @@
1/**
2 * wm831x-on.c - WM831X ON pin driver
3 *
4 * Copyright (C) 2009 Wolfson Microelectronics plc
5 *
6 * This file is subject to the terms and conditions of the GNU General
7 * Public License. See the file "COPYING" in the main directory of this
8 * archive for more details.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/errno.h>
24#include <linux/input.h>
25#include <linux/interrupt.h>
26#include <linux/platform_device.h>
27#include <linux/workqueue.h>
28#include <linux/mfd/wm831x/core.h>
29
30struct wm831x_on {
31 struct input_dev *dev;
32 struct delayed_work work;
33 struct wm831x *wm831x;
34};
35
36/*
37 * The chip gives us an interrupt when the ON pin is asserted but we
38 * then need to poll to see when the pin is deasserted.
39 */
40static void wm831x_poll_on(struct work_struct *work)
41{
42 struct wm831x_on *wm831x_on = container_of(work, struct wm831x_on,
43 work.work);
44 struct wm831x *wm831x = wm831x_on->wm831x;
45 int poll, ret;
46
47 ret = wm831x_reg_read(wm831x, WM831X_ON_PIN_CONTROL);
48 if (ret >= 0) {
49 poll = !(ret & WM831X_ON_PIN_STS);
50
51 input_report_key(wm831x_on->dev, KEY_POWER, poll);
52 input_sync(wm831x_on->dev);
53 } else {
54 dev_err(wm831x->dev, "Failed to read ON status: %d\n", ret);
55 poll = 1;
56 }
57
58 if (poll)
59 schedule_delayed_work(&wm831x_on->work, 100);
60}
61
62static irqreturn_t wm831x_on_irq(int irq, void *data)
63{
64 struct wm831x_on *wm831x_on = data;
65
66 schedule_delayed_work(&wm831x_on->work, 0);
67
68 return IRQ_HANDLED;
69}
70
71static int __devinit wm831x_on_probe(struct platform_device *pdev)
72{
73 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
74 struct wm831x_on *wm831x_on;
75 int irq = platform_get_irq(pdev, 0);
76 int ret;
77
78 wm831x_on = kzalloc(sizeof(struct wm831x_on), GFP_KERNEL);
79 if (!wm831x_on) {
80 dev_err(&pdev->dev, "Can't allocate data\n");
81 return -ENOMEM;
82 }
83
84 wm831x_on->wm831x = wm831x;
85 INIT_DELAYED_WORK(&wm831x_on->work, wm831x_poll_on);
86
87 wm831x_on->dev = input_allocate_device();
88 if (!wm831x_on->dev) {
89 dev_err(&pdev->dev, "Can't allocate input dev\n");
90 ret = -ENOMEM;
91 goto err;
92 }
93
94 wm831x_on->dev->evbit[0] = BIT_MASK(EV_KEY);
95 wm831x_on->dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
96 wm831x_on->dev->name = "wm831x_on";
97 wm831x_on->dev->phys = "wm831x_on/input0";
98 wm831x_on->dev->dev.parent = &pdev->dev;
99
100 ret = wm831x_request_irq(wm831x, irq, wm831x_on_irq,
101 IRQF_TRIGGER_RISING, "wm831x_on", wm831x_on);
102 if (ret < 0) {
103 dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret);
104 goto err_input_dev;
105 }
106 ret = input_register_device(wm831x_on->dev);
107 if (ret) {
108 dev_dbg(&pdev->dev, "Can't register input device: %d\n", ret);
109 goto err_irq;
110 }
111
112 platform_set_drvdata(pdev, wm831x_on);
113
114 return 0;
115
116err_irq:
117 wm831x_free_irq(wm831x, irq, NULL);
118err_input_dev:
119 input_free_device(wm831x_on->dev);
120err:
121 kfree(wm831x_on);
122 return ret;
123}
124
125static int __devexit wm831x_on_remove(struct platform_device *pdev)
126{
127 struct wm831x_on *wm831x_on = platform_get_drvdata(pdev);
128 int irq = platform_get_irq(pdev, 0);
129
130 wm831x_free_irq(wm831x_on->wm831x, irq, wm831x_on);
131 cancel_delayed_work_sync(&wm831x_on->work);
132 input_unregister_device(wm831x_on->dev);
133 kfree(wm831x_on);
134
135 return 0;
136}
137
138static struct platform_driver wm831x_on_driver = {
139 .probe = wm831x_on_probe,
140 .remove = __devexit_p(wm831x_on_remove),
141 .driver = {
142 .name = "wm831x-on",
143 .owner = THIS_MODULE,
144 },
145};
146
147static int __init wm831x_on_init(void)
148{
149 return platform_driver_register(&wm831x_on_driver);
150}
151module_init(wm831x_on_init);
152
153static void __exit wm831x_on_exit(void)
154{
155 platform_driver_unregister(&wm831x_on_driver);
156}
157module_exit(wm831x_on_exit);
158
159MODULE_ALIAS("platform:wm831x-on");
160MODULE_DESCRIPTION("WM831x ON pin");
161MODULE_LICENSE("GPL");
162MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
163