diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/input.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/omap-keypad.c | 22 | ||||
-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 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 9 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/pcap_ts.c | 271 |
9 files changed, 623 insertions, 12 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index 7c237e6ac711..851791d955f3 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -1144,7 +1144,7 @@ static struct attribute_group input_dev_caps_attr_group = { | |||
1144 | .attrs = input_dev_caps_attrs, | 1144 | .attrs = input_dev_caps_attrs, |
1145 | }; | 1145 | }; |
1146 | 1146 | ||
1147 | static struct attribute_group *input_dev_attr_groups[] = { | 1147 | static const struct attribute_group *input_dev_attr_groups[] = { |
1148 | &input_dev_attr_group, | 1148 | &input_dev_attr_group, |
1149 | &input_dev_id_attr_group, | 1149 | &input_dev_id_attr_group, |
1150 | &input_dev_caps_attr_group, | 1150 | &input_dev_caps_attr_group, |
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 87ec7b18ac69..bba85add35a3 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c | |||
@@ -116,7 +116,7 @@ static irqreturn_t omap_kp_interrupt(int irq, void *dev_id) | |||
116 | } | 116 | } |
117 | } else | 117 | } else |
118 | /* disable keyboard interrupt and schedule for handling */ | 118 | /* disable keyboard interrupt and schedule for handling */ |
119 | omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); | 119 | omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); |
120 | 120 | ||
121 | tasklet_schedule(&kp_tasklet); | 121 | tasklet_schedule(&kp_tasklet); |
122 | 122 | ||
@@ -143,20 +143,20 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state) | |||
143 | 143 | ||
144 | } else { | 144 | } else { |
145 | /* disable keyboard interrupt and schedule for handling */ | 145 | /* disable keyboard interrupt and schedule for handling */ |
146 | omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); | 146 | omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); |
147 | 147 | ||
148 | /* read the keypad status */ | 148 | /* read the keypad status */ |
149 | omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); | 149 | omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); |
150 | for (col = 0; col < omap_kp->cols; col++) { | 150 | for (col = 0; col < omap_kp->cols; col++) { |
151 | omap_writew(~(1 << col) & 0xff, | 151 | omap_writew(~(1 << col) & 0xff, |
152 | OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); | 152 | OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); |
153 | 153 | ||
154 | udelay(omap_kp->delay); | 154 | udelay(omap_kp->delay); |
155 | 155 | ||
156 | state[col] = ~omap_readw(OMAP_MPUIO_BASE + | 156 | state[col] = ~omap_readw(OMAP1_MPUIO_BASE + |
157 | OMAP_MPUIO_KBR_LATCH) & 0xff; | 157 | OMAP_MPUIO_KBR_LATCH) & 0xff; |
158 | } | 158 | } |
159 | omap_writew(0x00, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); | 159 | omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); |
160 | udelay(2); | 160 | udelay(2); |
161 | } | 161 | } |
162 | } | 162 | } |
@@ -234,7 +234,7 @@ static void omap_kp_tasklet(unsigned long data) | |||
234 | for (i = 0; i < omap_kp_data->rows; i++) | 234 | for (i = 0; i < omap_kp_data->rows; i++) |
235 | enable_irq(gpio_to_irq(row_gpios[i])); | 235 | enable_irq(gpio_to_irq(row_gpios[i])); |
236 | } else { | 236 | } else { |
237 | omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); | 237 | omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); |
238 | kp_cur_group = -1; | 238 | kp_cur_group = -1; |
239 | } | 239 | } |
240 | } | 240 | } |
@@ -317,7 +317,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) | |||
317 | 317 | ||
318 | /* Disable the interrupt for the MPUIO keyboard */ | 318 | /* Disable the interrupt for the MPUIO keyboard */ |
319 | if (!cpu_is_omap24xx()) | 319 | if (!cpu_is_omap24xx()) |
320 | omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); | 320 | omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); |
321 | 321 | ||
322 | keymap = pdata->keymap; | 322 | keymap = pdata->keymap; |
323 | 323 | ||
@@ -391,7 +391,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) | |||
391 | } | 391 | } |
392 | 392 | ||
393 | if (pdata->dbounce) | 393 | if (pdata->dbounce) |
394 | omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING); | 394 | omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING); |
395 | 395 | ||
396 | /* scan current status and enable interrupt */ | 396 | /* scan current status and enable interrupt */ |
397 | omap_kp_scan_keypad(omap_kp, keypad_state); | 397 | omap_kp_scan_keypad(omap_kp, keypad_state); |
@@ -402,7 +402,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) | |||
402 | "omap-keypad", omap_kp) < 0) | 402 | "omap-keypad", omap_kp) < 0) |
403 | goto err4; | 403 | goto err4; |
404 | } | 404 | } |
405 | omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); | 405 | omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); |
406 | } else { | 406 | } else { |
407 | for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) { | 407 | for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) { |
408 | if (request_irq(gpio_to_irq(row_gpios[irq_idx]), | 408 | if (request_irq(gpio_to_irq(row_gpios[irq_idx]), |
@@ -449,7 +449,7 @@ static int __devexit omap_kp_remove(struct platform_device *pdev) | |||
449 | free_irq(gpio_to_irq(row_gpios[i]), 0); | 449 | free_irq(gpio_to_irq(row_gpios[i]), 0); |
450 | } | 450 | } |
451 | } else { | 451 | } else { |
452 | omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); | 452 | omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); |
453 | free_irq(omap_kp->irq, 0); | 453 | free_irq(omap_kp->irq, 0); |
454 | } | 454 | } |
455 | 455 | ||
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 | |||
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 87a1ae63bcc4..ab02d72afbf3 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -510,4 +510,13 @@ config TOUCHSCREEN_W90X900 | |||
510 | To compile this driver as a module, choose M here: the | 510 | To compile this driver as a module, choose M here: the |
511 | module will be called w90p910_ts. | 511 | module will be called w90p910_ts. |
512 | 512 | ||
513 | config TOUCHSCREEN_PCAP | ||
514 | tristate "Motorola PCAP touchscreen" | ||
515 | depends on EZX_PCAP | ||
516 | help | ||
517 | Say Y here if you have a Motorola EZX telephone and | ||
518 | want to enable support for the built-in touchscreen. | ||
519 | |||
520 | To compile this driver as a module, choose M here: the | ||
521 | module will be called pcap_ts. | ||
513 | endif | 522 | endif |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 3e1c5e0b952f..4599bf7ad819 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -40,3 +40,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o | |||
40 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o | 40 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o |
41 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o | 41 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o |
42 | obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o | 42 | obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o |
43 | obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o | ||
diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c new file mode 100644 index 000000000000..67fcd33595de --- /dev/null +++ b/drivers/input/touchscreen/pcap_ts.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform. | ||
3 | * | ||
4 | * Copyright (C) 2006 Harald Welte <laforge@openezx.org> | ||
5 | * Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/timer.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/mfd/ezx-pcap.h> | ||
23 | |||
24 | struct pcap_ts { | ||
25 | struct pcap_chip *pcap; | ||
26 | struct input_dev *input; | ||
27 | struct delayed_work work; | ||
28 | u16 x, y; | ||
29 | u16 pressure; | ||
30 | u8 read_state; | ||
31 | }; | ||
32 | |||
33 | #define SAMPLE_DELAY 20 /* msecs */ | ||
34 | |||
35 | #define X_AXIS_MIN 0 | ||
36 | #define X_AXIS_MAX 1023 | ||
37 | #define Y_AXIS_MAX X_AXIS_MAX | ||
38 | #define Y_AXIS_MIN X_AXIS_MIN | ||
39 | #define PRESSURE_MAX X_AXIS_MAX | ||
40 | #define PRESSURE_MIN X_AXIS_MIN | ||
41 | |||
42 | static void pcap_ts_read_xy(void *data, u16 res[2]) | ||
43 | { | ||
44 | struct pcap_ts *pcap_ts = data; | ||
45 | |||
46 | switch (pcap_ts->read_state) { | ||
47 | case PCAP_ADC_TS_M_PRESSURE: | ||
48 | /* pressure reading is unreliable */ | ||
49 | if (res[0] > PRESSURE_MIN && res[0] < PRESSURE_MAX) | ||
50 | pcap_ts->pressure = res[0]; | ||
51 | pcap_ts->read_state = PCAP_ADC_TS_M_XY; | ||
52 | schedule_delayed_work(&pcap_ts->work, 0); | ||
53 | break; | ||
54 | case PCAP_ADC_TS_M_XY: | ||
55 | pcap_ts->y = res[0]; | ||
56 | pcap_ts->x = res[1]; | ||
57 | if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX || | ||
58 | pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) { | ||
59 | /* pen has been released */ | ||
60 | input_report_abs(pcap_ts->input, ABS_PRESSURE, 0); | ||
61 | input_report_key(pcap_ts->input, BTN_TOUCH, 0); | ||
62 | |||
63 | pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY; | ||
64 | schedule_delayed_work(&pcap_ts->work, 0); | ||
65 | } else { | ||
66 | /* pen is touching the screen */ | ||
67 | input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x); | ||
68 | input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y); | ||
69 | input_report_key(pcap_ts->input, BTN_TOUCH, 1); | ||
70 | input_report_abs(pcap_ts->input, ABS_PRESSURE, | ||
71 | pcap_ts->pressure); | ||
72 | |||
73 | /* switch back to pressure read mode */ | ||
74 | pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE; | ||
75 | schedule_delayed_work(&pcap_ts->work, | ||
76 | msecs_to_jiffies(SAMPLE_DELAY)); | ||
77 | } | ||
78 | input_sync(pcap_ts->input); | ||
79 | break; | ||
80 | default: | ||
81 | dev_warn(&pcap_ts->input->dev, | ||
82 | "pcap_ts: Warning, unhandled read_state %d\n", | ||
83 | pcap_ts->read_state); | ||
84 | break; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static void pcap_ts_work(struct work_struct *work) | ||
89 | { | ||
90 | struct delayed_work *dw = container_of(work, struct delayed_work, work); | ||
91 | struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work); | ||
92 | u8 ch[2]; | ||
93 | |||
94 | pcap_set_ts_bits(pcap_ts->pcap, | ||
95 | pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); | ||
96 | |||
97 | if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) | ||
98 | return; | ||
99 | |||
100 | /* start adc conversion */ | ||
101 | ch[0] = PCAP_ADC_CH_TS_X1; | ||
102 | ch[1] = PCAP_ADC_CH_TS_Y1; | ||
103 | pcap_adc_async(pcap_ts->pcap, PCAP_ADC_BANK_1, 0, ch, | ||
104 | pcap_ts_read_xy, pcap_ts); | ||
105 | } | ||
106 | |||
107 | static irqreturn_t pcap_ts_event_touch(int pirq, void *data) | ||
108 | { | ||
109 | struct pcap_ts *pcap_ts = data; | ||
110 | |||
111 | if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) { | ||
112 | pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE; | ||
113 | schedule_delayed_work(&pcap_ts->work, 0); | ||
114 | } | ||
115 | return IRQ_HANDLED; | ||
116 | } | ||
117 | |||
118 | static int pcap_ts_open(struct input_dev *dev) | ||
119 | { | ||
120 | struct pcap_ts *pcap_ts = input_get_drvdata(dev); | ||
121 | |||
122 | pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY; | ||
123 | schedule_delayed_work(&pcap_ts->work, 0); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static void pcap_ts_close(struct input_dev *dev) | ||
129 | { | ||
130 | struct pcap_ts *pcap_ts = input_get_drvdata(dev); | ||
131 | |||
132 | cancel_delayed_work_sync(&pcap_ts->work); | ||
133 | |||
134 | pcap_ts->read_state = PCAP_ADC_TS_M_NONTS; | ||
135 | pcap_set_ts_bits(pcap_ts->pcap, | ||
136 | pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); | ||
137 | } | ||
138 | |||
139 | static int __devinit pcap_ts_probe(struct platform_device *pdev) | ||
140 | { | ||
141 | struct input_dev *input_dev; | ||
142 | struct pcap_ts *pcap_ts; | ||
143 | int err = -ENOMEM; | ||
144 | |||
145 | pcap_ts = kzalloc(sizeof(*pcap_ts), GFP_KERNEL); | ||
146 | if (!pcap_ts) | ||
147 | return err; | ||
148 | |||
149 | pcap_ts->pcap = dev_get_drvdata(pdev->dev.parent); | ||
150 | platform_set_drvdata(pdev, pcap_ts); | ||
151 | |||
152 | input_dev = input_allocate_device(); | ||
153 | if (!input_dev) | ||
154 | goto fail; | ||
155 | |||
156 | INIT_DELAYED_WORK(&pcap_ts->work, pcap_ts_work); | ||
157 | |||
158 | pcap_ts->read_state = PCAP_ADC_TS_M_NONTS; | ||
159 | pcap_set_ts_bits(pcap_ts->pcap, | ||
160 | pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); | ||
161 | |||
162 | pcap_ts->input = input_dev; | ||
163 | input_set_drvdata(input_dev, pcap_ts); | ||
164 | |||
165 | input_dev->name = "pcap-touchscreen"; | ||
166 | input_dev->phys = "pcap_ts/input0"; | ||
167 | input_dev->id.bustype = BUS_HOST; | ||
168 | input_dev->id.vendor = 0x0001; | ||
169 | input_dev->id.product = 0x0002; | ||
170 | input_dev->id.version = 0x0100; | ||
171 | input_dev->dev.parent = &pdev->dev; | ||
172 | input_dev->open = pcap_ts_open; | ||
173 | input_dev->close = pcap_ts_close; | ||
174 | |||
175 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
176 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
177 | input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); | ||
178 | input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); | ||
179 | input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, | ||
180 | PRESSURE_MAX, 0, 0); | ||
181 | |||
182 | err = input_register_device(pcap_ts->input); | ||
183 | if (err) | ||
184 | goto fail_allocate; | ||
185 | |||
186 | err = request_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), | ||
187 | pcap_ts_event_touch, 0, "Touch Screen", pcap_ts); | ||
188 | if (err) | ||
189 | goto fail_register; | ||
190 | |||
191 | return 0; | ||
192 | |||
193 | fail_register: | ||
194 | input_unregister_device(input_dev); | ||
195 | goto fail; | ||
196 | fail_allocate: | ||
197 | input_free_device(input_dev); | ||
198 | fail: | ||
199 | kfree(pcap_ts); | ||
200 | |||
201 | return err; | ||
202 | } | ||
203 | |||
204 | static int __devexit pcap_ts_remove(struct platform_device *pdev) | ||
205 | { | ||
206 | struct pcap_ts *pcap_ts = platform_get_drvdata(pdev); | ||
207 | |||
208 | free_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), pcap_ts); | ||
209 | cancel_delayed_work_sync(&pcap_ts->work); | ||
210 | |||
211 | input_unregister_device(pcap_ts->input); | ||
212 | |||
213 | kfree(pcap_ts); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | #ifdef CONFIG_PM | ||
219 | static int pcap_ts_suspend(struct device *dev) | ||
220 | { | ||
221 | struct pcap_ts *pcap_ts = dev_get_drvdata(dev); | ||
222 | |||
223 | pcap_set_ts_bits(pcap_ts->pcap, PCAP_ADC_TS_REF_LOWPWR); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int pcap_ts_resume(struct device *dev) | ||
228 | { | ||
229 | struct pcap_ts *pcap_ts = dev_get_drvdata(dev); | ||
230 | |||
231 | pcap_set_ts_bits(pcap_ts->pcap, | ||
232 | pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static struct dev_pm_ops pcap_ts_pm_ops = { | ||
237 | .suspend = pcap_ts_suspend, | ||
238 | .resume = pcap_ts_resume, | ||
239 | }; | ||
240 | #define PCAP_TS_PM_OPS (&pcap_ts_pm_ops) | ||
241 | #else | ||
242 | #define PCAP_TS_PM_OPS NULL | ||
243 | #endif | ||
244 | |||
245 | static struct platform_driver pcap_ts_driver = { | ||
246 | .probe = pcap_ts_probe, | ||
247 | .remove = __devexit_p(pcap_ts_remove), | ||
248 | .driver = { | ||
249 | .name = "pcap-ts", | ||
250 | .owner = THIS_MODULE, | ||
251 | .pm = PCAP_TS_PM_OPS, | ||
252 | }, | ||
253 | }; | ||
254 | |||
255 | static int __init pcap_ts_init(void) | ||
256 | { | ||
257 | return platform_driver_register(&pcap_ts_driver); | ||
258 | } | ||
259 | |||
260 | static void __exit pcap_ts_exit(void) | ||
261 | { | ||
262 | platform_driver_unregister(&pcap_ts_driver); | ||
263 | } | ||
264 | |||
265 | module_init(pcap_ts_init); | ||
266 | module_exit(pcap_ts_exit); | ||
267 | |||
268 | MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver"); | ||
269 | MODULE_AUTHOR("Daniel Ribeiro / Harald Welte"); | ||
270 | MODULE_LICENSE("GPL"); | ||
271 | MODULE_ALIAS("platform:pcap_ts"); | ||