diff options
Diffstat (limited to 'drivers/input/misc')
-rw-r--r-- | drivers/input/misc/Kconfig | 20 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 3 | ||||
-rw-r--r-- | drivers/input/misc/pcap_keys.c | 144 | ||||
-rw-r--r-- | drivers/input/misc/wm831x-on.c | 163 |
4 files changed, 330 insertions, 0 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index cbe21bc96b52..1a50be379cbc 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -279,4 +279,24 @@ 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 | ||
282 | config 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 | |||
292 | config INPUT_PCAP | ||
293 | tristate "Motorola EZX PCAP misc input events" | ||
294 | depends on EZX_PCAP | ||
295 | help | ||
296 | Say Y here if you want to use Power key and Headphone button | ||
297 | on Motorola EZX phones. | ||
298 | |||
299 | To compile this driver as a module, choose M here: the | ||
300 | module will be called pcap_keys. | ||
301 | |||
282 | endif | 302 | endif |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 79c1e9a5ea31..bf4db626c313 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -16,6 +16,7 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o | |||
16 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | 16 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o |
17 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | 17 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o |
18 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | 18 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o |
19 | obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o | ||
19 | obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o | 20 | obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o |
20 | obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o | 21 | obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o |
21 | obj-$(CONFIG_INPUT_POWERMATE) += powermate.o | 22 | obj-$(CONFIG_INPUT_POWERMATE) += powermate.o |
@@ -26,4 +27,6 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o | |||
26 | obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o | 27 | obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o |
27 | obj-$(CONFIG_INPUT_UINPUT) += uinput.o | 28 | obj-$(CONFIG_INPUT_UINPUT) += uinput.o |
28 | obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o | 29 | obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o |
30 | obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o | ||
29 | obj-$(CONFIG_INPUT_YEALINK) += yealink.o | 31 | obj-$(CONFIG_INPUT_YEALINK) += yealink.o |
32 | |||
diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c new file mode 100644 index 000000000000..7ea969347ca9 --- /dev/null +++ b/drivers/input/misc/pcap_keys.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Input driver for PCAP events: | ||
3 | * * Power key | ||
4 | * * Headphone button | ||
5 | * | ||
6 | * Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <linux/mfd/ezx-pcap.h> | ||
20 | |||
21 | struct pcap_keys { | ||
22 | struct pcap_chip *pcap; | ||
23 | struct input_dev *input; | ||
24 | }; | ||
25 | |||
26 | /* PCAP2 interrupts us on keypress */ | ||
27 | static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys) | ||
28 | { | ||
29 | struct pcap_keys *pcap_keys = _pcap_keys; | ||
30 | int pirq = irq_to_pcap(pcap_keys->pcap, irq); | ||
31 | u32 pstat; | ||
32 | |||
33 | ezx_pcap_read(pcap_keys->pcap, PCAP_REG_PSTAT, &pstat); | ||
34 | pstat &= 1 << pirq; | ||
35 | |||
36 | switch (pirq) { | ||
37 | case PCAP_IRQ_ONOFF: | ||
38 | input_report_key(pcap_keys->input, KEY_POWER, !pstat); | ||
39 | break; | ||
40 | case PCAP_IRQ_MIC: | ||
41 | input_report_key(pcap_keys->input, KEY_HP, !pstat); | ||
42 | break; | ||
43 | } | ||
44 | |||
45 | input_sync(pcap_keys->input); | ||
46 | |||
47 | return IRQ_HANDLED; | ||
48 | } | ||
49 | |||
50 | static int __devinit pcap_keys_probe(struct platform_device *pdev) | ||
51 | { | ||
52 | int err = -ENOMEM; | ||
53 | struct pcap_keys *pcap_keys; | ||
54 | struct input_dev *input_dev; | ||
55 | |||
56 | pcap_keys = kmalloc(sizeof(struct pcap_keys), GFP_KERNEL); | ||
57 | if (!pcap_keys) | ||
58 | return err; | ||
59 | |||
60 | pcap_keys->pcap = dev_get_drvdata(pdev->dev.parent); | ||
61 | |||
62 | input_dev = input_allocate_device(); | ||
63 | if (!input_dev) | ||
64 | goto fail; | ||
65 | |||
66 | pcap_keys->input = input_dev; | ||
67 | |||
68 | platform_set_drvdata(pdev, pcap_keys); | ||
69 | input_dev->name = pdev->name; | ||
70 | input_dev->phys = "pcap-keys/input0"; | ||
71 | input_dev->id.bustype = BUS_HOST; | ||
72 | input_dev->dev.parent = &pdev->dev; | ||
73 | |||
74 | __set_bit(EV_KEY, input_dev->evbit); | ||
75 | __set_bit(KEY_POWER, input_dev->keybit); | ||
76 | __set_bit(KEY_HP, input_dev->keybit); | ||
77 | |||
78 | err = input_register_device(input_dev); | ||
79 | if (err) | ||
80 | goto fail_allocate; | ||
81 | |||
82 | err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), | ||
83 | pcap_keys_handler, 0, "Power key", pcap_keys); | ||
84 | if (err) | ||
85 | goto fail_register; | ||
86 | |||
87 | err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), | ||
88 | pcap_keys_handler, 0, "Headphone button", pcap_keys); | ||
89 | if (err) | ||
90 | goto fail_pwrkey; | ||
91 | |||
92 | return 0; | ||
93 | |||
94 | fail_pwrkey: | ||
95 | free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); | ||
96 | fail_register: | ||
97 | input_unregister_device(input_dev); | ||
98 | goto fail; | ||
99 | fail_allocate: | ||
100 | input_free_device(input_dev); | ||
101 | fail: | ||
102 | kfree(pcap_keys); | ||
103 | return err; | ||
104 | } | ||
105 | |||
106 | static int __devexit pcap_keys_remove(struct platform_device *pdev) | ||
107 | { | ||
108 | struct pcap_keys *pcap_keys = platform_get_drvdata(pdev); | ||
109 | |||
110 | free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); | ||
111 | free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), pcap_keys); | ||
112 | |||
113 | input_unregister_device(pcap_keys->input); | ||
114 | kfree(pcap_keys); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static struct platform_driver pcap_keys_device_driver = { | ||
120 | .probe = pcap_keys_probe, | ||
121 | .remove = __devexit_p(pcap_keys_remove), | ||
122 | .driver = { | ||
123 | .name = "pcap-keys", | ||
124 | .owner = THIS_MODULE, | ||
125 | } | ||
126 | }; | ||
127 | |||
128 | static int __init pcap_keys_init(void) | ||
129 | { | ||
130 | return platform_driver_register(&pcap_keys_device_driver); | ||
131 | }; | ||
132 | |||
133 | static void __exit pcap_keys_exit(void) | ||
134 | { | ||
135 | platform_driver_unregister(&pcap_keys_device_driver); | ||
136 | }; | ||
137 | |||
138 | module_init(pcap_keys_init); | ||
139 | module_exit(pcap_keys_exit); | ||
140 | |||
141 | MODULE_DESCRIPTION("Motorola PCAP2 input events driver"); | ||
142 | MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>"); | ||
143 | MODULE_LICENSE("GPL"); | ||
144 | MODULE_ALIAS("platform:pcap_keys"); | ||
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 | |||
30 | struct 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 | */ | ||
40 | static 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 | |||
62 | static 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 | |||
71 | static 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 | |||
116 | err_irq: | ||
117 | wm831x_free_irq(wm831x, irq, NULL); | ||
118 | err_input_dev: | ||
119 | input_free_device(wm831x_on->dev); | ||
120 | err: | ||
121 | kfree(wm831x_on); | ||
122 | return ret; | ||
123 | } | ||
124 | |||
125 | static 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 | |||
138 | static 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 | |||
147 | static int __init wm831x_on_init(void) | ||
148 | { | ||
149 | return platform_driver_register(&wm831x_on_driver); | ||
150 | } | ||
151 | module_init(wm831x_on_init); | ||
152 | |||
153 | static void __exit wm831x_on_exit(void) | ||
154 | { | ||
155 | platform_driver_unregister(&wm831x_on_driver); | ||
156 | } | ||
157 | module_exit(wm831x_on_exit); | ||
158 | |||
159 | MODULE_ALIAS("platform:wm831x-on"); | ||
160 | MODULE_DESCRIPTION("WM831x ON pin"); | ||
161 | MODULE_LICENSE("GPL"); | ||
162 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
163 | |||