aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r--drivers/input/touchscreen/Kconfig32
-rw-r--r--drivers/input/touchscreen/Makefile3
-rw-r--r--drivers/input/touchscreen/ads7846.c23
-rw-r--r--drivers/input/touchscreen/atmel-wm97xx.c446
-rw-r--r--drivers/input/touchscreen/eeti_ts.c286
-rw-r--r--drivers/input/touchscreen/tsc2007.c2
-rw-r--r--drivers/input/touchscreen/w90p910_ts.c350
7 files changed, 1137 insertions, 5 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index b01fd61dadcc..72e2712c7e2a 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -111,6 +111,15 @@ config TOUCHSCREEN_DA9034
111 Say Y here to enable the support for the touchscreen found 111 Say Y here to enable the support for the touchscreen found
112 on Dialog Semiconductor DA9034 PMIC. 112 on Dialog Semiconductor DA9034 PMIC.
113 113
114config TOUCHSCREEN_EETI
115 tristate "EETI touchscreen panel support"
116 depends on I2C
117 help
118 Say Y here to enable support for I2C connected EETI touch panels.
119
120 To compile this driver as a module, choose M here: the
121 module will be called eeti_ts.
122
114config TOUCHSCREEN_FUJITSU 123config TOUCHSCREEN_FUJITSU
115 tristate "Fujitsu serial touchscreen" 124 tristate "Fujitsu serial touchscreen"
116 select SERIO 125 select SERIO
@@ -341,6 +350,21 @@ config TOUCHSCREEN_WM9713
341 Say Y here to enable support for the Wolfson Microelectronics 350 Say Y here to enable support for the Wolfson Microelectronics
342 WM9713 touchscreen controller. 351 WM9713 touchscreen controller.
343 352
353config TOUCHSCREEN_WM97XX_ATMEL
354 tristate "WM97xx Atmel accelerated touch"
355 depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91)
356 help
357 Say Y here for support for streaming mode with WM97xx touchscreens
358 on Atmel AT91 or AVR32 systems with an AC97C module.
359
360 Be aware that this will use channel B in the controller for
361 streaming data, this must not conflict with other AC97C drivers.
362
363 If unsure, say N.
364
365 To compile this driver as a module, choose M here: the module will
366 be called atmel-wm97xx.
367
344config TOUCHSCREEN_WM97XX_MAINSTONE 368config TOUCHSCREEN_WM97XX_MAINSTONE
345 tristate "WM97xx Mainstone accelerated touch" 369 tristate "WM97xx Mainstone accelerated touch"
346 depends on TOUCHSCREEN_WM97XX && ARCH_PXA 370 depends on TOUCHSCREEN_WM97XX && ARCH_PXA
@@ -466,4 +490,12 @@ config TOUCHSCREEN_TSC2007
466 To compile this driver as a module, choose M here: the 490 To compile this driver as a module, choose M here: the
467 module will be called tsc2007. 491 module will be called tsc2007.
468 492
493config TOUCHSCREEN_W90X900
494 tristate "W90P910 touchscreen driver"
495 help
496 Say Y here if you have a W90P910 based touchscreen.
497
498 To compile this driver as a module, choose M here: the
499 module will be called w90p910_ts.
500
469endif 501endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 6700f7b9d165..3e1c5e0b952f 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
13obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o 13obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
14obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o 14obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
15obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o 15obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
16obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
16obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o 17obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
17obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o 18obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
18obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o 19obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
@@ -35,5 +36,7 @@ obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
35wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o 36wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
36wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o 37wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
37wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o 38wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
39obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
38obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o 40obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
39obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o 41obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
42obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 2b01e56568f8..ba9d38c3f412 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -83,6 +83,7 @@ struct ads7846_packet {
83struct ads7846 { 83struct ads7846 {
84 struct input_dev *input; 84 struct input_dev *input;
85 char phys[32]; 85 char phys[32];
86 char name[32];
86 87
87 struct spi_device *spi; 88 struct spi_device *spi;
88 89
@@ -97,6 +98,8 @@ struct ads7846 {
97 u16 x_plate_ohms; 98 u16 x_plate_ohms;
98 u16 pressure_max; 99 u16 pressure_max;
99 100
101 bool swap_xy;
102
100 struct ads7846_packet *packet; 103 struct ads7846_packet *packet;
101 104
102 struct spi_transfer xfer[18]; 105 struct spi_transfer xfer[18];
@@ -599,6 +602,10 @@ static void ads7846_rx(void *ads)
599 dev_dbg(&ts->spi->dev, "DOWN\n"); 602 dev_dbg(&ts->spi->dev, "DOWN\n");
600#endif 603#endif
601 } 604 }
605
606 if (ts->swap_xy)
607 swap(x, y);
608
602 input_report_abs(input, ABS_X, x); 609 input_report_abs(input, ABS_X, x);
603 input_report_abs(input, ABS_Y, y); 610 input_report_abs(input, ABS_Y, y);
604 input_report_abs(input, ABS_PRESSURE, Rt); 611 input_report_abs(input, ABS_PRESSURE, Rt);
@@ -917,6 +924,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
917 ts->spi = spi; 924 ts->spi = spi;
918 ts->input = input_dev; 925 ts->input = input_dev;
919 ts->vref_mv = pdata->vref_mv; 926 ts->vref_mv = pdata->vref_mv;
927 ts->swap_xy = pdata->swap_xy;
920 928
921 hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 929 hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
922 ts->timer.function = ads7846_timer; 930 ts->timer.function = ads7846_timer;
@@ -958,8 +966,9 @@ static int __devinit ads7846_probe(struct spi_device *spi)
958 ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync; 966 ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
959 967
960 snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); 968 snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
969 snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
961 970
962 input_dev->name = "ADS784x Touchscreen"; 971 input_dev->name = ts->name;
963 input_dev->phys = ts->phys; 972 input_dev->phys = ts->phys;
964 input_dev->dev.parent = &spi->dev; 973 input_dev->dev.parent = &spi->dev;
965 974
@@ -1141,9 +1150,15 @@ static int __devinit ads7846_probe(struct spi_device *spi)
1141 1150
1142 if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING, 1151 if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
1143 spi->dev.driver->name, ts)) { 1152 spi->dev.driver->name, ts)) {
1144 dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); 1153 dev_info(&spi->dev,
1145 err = -EBUSY; 1154 "trying pin change workaround on irq %d\n", spi->irq);
1146 goto err_free_gpio; 1155 err = request_irq(spi->irq, ads7846_irq,
1156 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
1157 spi->dev.driver->name, ts);
1158 if (err) {
1159 dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
1160 goto err_free_gpio;
1161 }
1147 } 1162 }
1148 1163
1149 err = ads784x_hwmon_register(spi, ts); 1164 err = ads784x_hwmon_register(spi, ts);
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c
new file mode 100644
index 000000000000..35377f583e28
--- /dev/null
+++ b/drivers/input/touchscreen/atmel-wm97xx.c
@@ -0,0 +1,446 @@
1/*
2 * Atmel AT91 and AVR32 continuous touch screen driver for Wolfson WM97xx AC97
3 * codecs.
4 *
5 * Copyright (C) 2008 - 2009 Atmel Corporation
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 */
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/delay.h>
16#include <linux/irq.h>
17#include <linux/interrupt.h>
18#include <linux/wm97xx.h>
19#include <linux/timer.h>
20#include <linux/gpio.h>
21#include <linux/io.h>
22
23#define AC97C_ICA 0x10
24#define AC97C_CBRHR 0x30
25#define AC97C_CBSR 0x38
26#define AC97C_CBMR 0x3c
27#define AC97C_IER 0x54
28#define AC97C_IDR 0x58
29
30#define AC97C_RXRDY (1 << 4)
31#define AC97C_OVRUN (1 << 5)
32
33#define AC97C_CMR_SIZE_20 (0 << 16)
34#define AC97C_CMR_SIZE_18 (1 << 16)
35#define AC97C_CMR_SIZE_16 (2 << 16)
36#define AC97C_CMR_SIZE_10 (3 << 16)
37#define AC97C_CMR_CEM_LITTLE (1 << 18)
38#define AC97C_CMR_CEM_BIG (0 << 18)
39#define AC97C_CMR_CENA (1 << 21)
40
41#define AC97C_INT_CBEVT (1 << 4)
42
43#define AC97C_SR_CAEVT (1 << 3)
44
45#define AC97C_CH_MASK(slot) \
46 (0x7 << (3 * (slot - 3)))
47#define AC97C_CH_ASSIGN(slot, channel) \
48 (AC97C_CHANNEL_##channel << (3 * (slot - 3)))
49#define AC97C_CHANNEL_NONE 0x0
50#define AC97C_CHANNEL_B 0x2
51
52#define ac97c_writel(chip, reg, val) \
53 __raw_writel((val), (chip)->regs + AC97C_##reg)
54#define ac97c_readl(chip, reg) \
55 __raw_readl((chip)->regs + AC97C_##reg)
56
57#ifdef CONFIG_CPU_AT32AP700X
58#define ATMEL_WM97XX_AC97C_IOMEM (0xfff02800)
59#define ATMEL_WM97XX_AC97C_IRQ (29)
60#define ATMEL_WM97XX_GPIO_DEFAULT (32+16) /* Pin 16 on port B. */
61#else
62#error Unkown CPU, this driver only supports AT32AP700X CPUs.
63#endif
64
65struct continuous {
66 u16 id; /* codec id */
67 u8 code; /* continuous code */
68 u8 reads; /* number of coord reads per read cycle */
69 u32 speed; /* number of coords per second */
70};
71
72#define WM_READS(sp) ((sp / HZ) + 1)
73
74static const struct continuous cinfo[] = {
75 {WM9705_ID2, 0, WM_READS(94), 94},
76 {WM9705_ID2, 1, WM_READS(188), 188},
77 {WM9705_ID2, 2, WM_READS(375), 375},
78 {WM9705_ID2, 3, WM_READS(750), 750},
79 {WM9712_ID2, 0, WM_READS(94), 94},
80 {WM9712_ID2, 1, WM_READS(188), 188},
81 {WM9712_ID2, 2, WM_READS(375), 375},
82 {WM9712_ID2, 3, WM_READS(750), 750},
83 {WM9713_ID2, 0, WM_READS(94), 94},
84 {WM9713_ID2, 1, WM_READS(120), 120},
85 {WM9713_ID2, 2, WM_READS(154), 154},
86 {WM9713_ID2, 3, WM_READS(188), 188},
87};
88
89/* Continuous speed index. */
90static int sp_idx;
91
92/*
93 * Pen sampling frequency (Hz) in continuous mode.
94 */
95static int cont_rate = 188;
96module_param(cont_rate, int, 0);
97MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
98
99/*
100 * Pen down detection.
101 *
102 * This driver can either poll or use an interrupt to indicate a pen down
103 * event. If the irq request fails then it will fall back to polling mode.
104 */
105static int pen_int = 1;
106module_param(pen_int, int, 0);
107MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
108
109/*
110 * Pressure readback.
111 *
112 * Set to 1 to read back pen down pressure.
113 */
114static int pressure;
115module_param(pressure, int, 0);
116MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
117
118/*
119 * AC97 touch data slot.
120 *
121 * Touch screen readback data ac97 slot.
122 */
123static int ac97_touch_slot = 5;
124module_param(ac97_touch_slot, int, 0);
125MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
126
127/*
128 * GPIO line number.
129 *
130 * Set to GPIO number where the signal from the WM97xx device is hooked up.
131 */
132static int atmel_gpio_line = ATMEL_WM97XX_GPIO_DEFAULT;
133module_param(atmel_gpio_line, int, 0);
134MODULE_PARM_DESC(atmel_gpio_line, "GPIO line number connected to WM97xx");
135
136struct atmel_wm97xx {
137 struct wm97xx *wm;
138 struct timer_list pen_timer;
139 void __iomem *regs;
140 unsigned long ac97c_irq;
141 unsigned long gpio_pen;
142 unsigned long gpio_irq;
143 unsigned short x;
144 unsigned short y;
145};
146
147static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id)
148{
149 struct atmel_wm97xx *atmel_wm97xx = dev_id;
150 struct wm97xx *wm = atmel_wm97xx->wm;
151 int status = ac97c_readl(atmel_wm97xx, CBSR);
152 irqreturn_t retval = IRQ_NONE;
153
154 if (status & AC97C_OVRUN) {
155 dev_dbg(&wm->touch_dev->dev, "AC97C overrun\n");
156 ac97c_readl(atmel_wm97xx, CBRHR);
157 retval = IRQ_HANDLED;
158 } else if (status & AC97C_RXRDY) {
159 u16 data;
160 u16 value;
161 u16 source;
162 u16 pen_down;
163
164 data = ac97c_readl(atmel_wm97xx, CBRHR);
165 value = data & 0x0fff;
166 source = data & WM97XX_ADCSRC_MASK;
167 pen_down = (data & WM97XX_PEN_DOWN) >> 8;
168
169 if (source == WM97XX_ADCSEL_X)
170 atmel_wm97xx->x = value;
171 if (source == WM97XX_ADCSEL_Y)
172 atmel_wm97xx->y = value;
173
174 if (!pressure && source == WM97XX_ADCSEL_Y) {
175 input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
176 input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
177 input_report_key(wm->input_dev, BTN_TOUCH, pen_down);
178 input_sync(wm->input_dev);
179 } else if (pressure && source == WM97XX_ADCSEL_PRES) {
180 input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
181 input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
182 input_report_abs(wm->input_dev, ABS_PRESSURE, value);
183 input_report_key(wm->input_dev, BTN_TOUCH, value);
184 input_sync(wm->input_dev);
185 }
186
187 retval = IRQ_HANDLED;
188 }
189
190 return retval;
191}
192
193static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm)
194{
195 struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
196 struct input_dev *input_dev = wm->input_dev;
197 int pen_down = gpio_get_value(atmel_wm97xx->gpio_pen);
198
199 if (pen_down != 0) {
200 mod_timer(&atmel_wm97xx->pen_timer,
201 jiffies + msecs_to_jiffies(1));
202 } else {
203 if (pressure)
204 input_report_abs(input_dev, ABS_PRESSURE, 0);
205 input_report_key(input_dev, BTN_TOUCH, 0);
206 input_sync(input_dev);
207 }
208}
209
210static void atmel_wm97xx_pen_timer(unsigned long data)
211{
212 atmel_wm97xx_acc_pen_up((struct wm97xx *)data);
213}
214
215static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
216{
217 struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
218 int idx = 0;
219
220 if (wm->ac97 == NULL)
221 return -ENODEV;
222
223 for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
224 if (wm->id != cinfo[idx].id)
225 continue;
226
227 sp_idx = idx;
228
229 if (cont_rate <= cinfo[idx].speed)
230 break;
231 }
232
233 wm->acc_rate = cinfo[sp_idx].code;
234 wm->acc_slot = ac97_touch_slot;
235 dev_info(&wm->touch_dev->dev, "atmel accelerated touchscreen driver, "
236 "%d samples/sec\n", cinfo[sp_idx].speed);
237
238 if (pen_int) {
239 unsigned long reg;
240
241 wm->pen_irq = atmel_wm97xx->gpio_irq;
242
243 switch (wm->id) {
244 case WM9712_ID2: /* Fall through. */
245 case WM9713_ID2:
246 /*
247 * Use GPIO 13 (PEN_DOWN) to assert GPIO line 3
248 * (PENDOWN).
249 */
250 wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
251 WM97XX_GPIO_POL_HIGH,
252 WM97XX_GPIO_STICKY,
253 WM97XX_GPIO_WAKE);
254 wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT,
255 WM97XX_GPIO_POL_HIGH,
256 WM97XX_GPIO_NOTSTICKY,
257 WM97XX_GPIO_NOWAKE);
258 case WM9705_ID2: /* Fall through. */
259 /*
260 * Enable touch data slot in AC97 controller channel B.
261 */
262 reg = ac97c_readl(atmel_wm97xx, ICA);
263 reg &= ~AC97C_CH_MASK(wm->acc_slot);
264 reg |= AC97C_CH_ASSIGN(wm->acc_slot, B);
265 ac97c_writel(atmel_wm97xx, ICA, reg);
266
267 /*
268 * Enable channel and interrupt for RXRDY and OVERRUN.
269 */
270 ac97c_writel(atmel_wm97xx, CBMR, AC97C_CMR_CENA
271 | AC97C_CMR_CEM_BIG
272 | AC97C_CMR_SIZE_16
273 | AC97C_OVRUN
274 | AC97C_RXRDY);
275 /* Dummy read to empty RXRHR. */
276 ac97c_readl(atmel_wm97xx, CBRHR);
277 /*
278 * Enable interrupt for channel B in the AC97
279 * controller.
280 */
281 ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
282 break;
283 default:
284 dev_err(&wm->touch_dev->dev, "pen down irq not "
285 "supported on this device\n");
286 pen_int = 0;
287 break;
288 }
289 }
290
291 return 0;
292}
293
294static void atmel_wm97xx_acc_shutdown(struct wm97xx *wm)
295{
296 if (pen_int) {
297 struct atmel_wm97xx *atmel_wm97xx =
298 platform_get_drvdata(wm->touch_dev);
299 unsigned long ica;
300
301 switch (wm->id & 0xffff) {
302 case WM9705_ID2: /* Fall through. */
303 case WM9712_ID2: /* Fall through. */
304 case WM9713_ID2:
305 /* Disable slot and turn off channel B interrupts. */
306 ica = ac97c_readl(atmel_wm97xx, ICA);
307 ica &= ~AC97C_CH_MASK(wm->acc_slot);
308 ac97c_writel(atmel_wm97xx, ICA, ica);
309 ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
310 ac97c_writel(atmel_wm97xx, CBMR, 0);
311 wm->pen_irq = 0;
312 break;
313 default:
314 dev_err(&wm->touch_dev->dev, "unknown codec\n");
315 break;
316 }
317 }
318}
319
320static void atmel_wm97xx_irq_enable(struct wm97xx *wm, int enable)
321{
322 /* Intentionally left empty. */
323}
324
325static struct wm97xx_mach_ops atmel_mach_ops = {
326 .acc_enabled = 1,
327 .acc_pen_up = atmel_wm97xx_acc_pen_up,
328 .acc_startup = atmel_wm97xx_acc_startup,
329 .acc_shutdown = atmel_wm97xx_acc_shutdown,
330 .irq_enable = atmel_wm97xx_irq_enable,
331 .irq_gpio = WM97XX_GPIO_3,
332};
333
334static int __init atmel_wm97xx_probe(struct platform_device *pdev)
335{
336 struct wm97xx *wm = platform_get_drvdata(pdev);
337 struct atmel_wm97xx *atmel_wm97xx;
338 int ret;
339
340 atmel_wm97xx = kzalloc(sizeof(struct atmel_wm97xx), GFP_KERNEL);
341 if (!atmel_wm97xx) {
342 dev_dbg(&pdev->dev, "out of memory\n");
343 return -ENOMEM;
344 }
345
346 atmel_wm97xx->wm = wm;
347 atmel_wm97xx->regs = (void *)ATMEL_WM97XX_AC97C_IOMEM;
348 atmel_wm97xx->ac97c_irq = ATMEL_WM97XX_AC97C_IRQ;
349 atmel_wm97xx->gpio_pen = atmel_gpio_line;
350 atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen);
351
352 setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer,
353 (unsigned long)wm);
354
355 ret = request_irq(atmel_wm97xx->ac97c_irq,
356 atmel_wm97xx_channel_b_interrupt,
357 IRQF_SHARED, "atmel-wm97xx-ch-b", atmel_wm97xx);
358 if (ret) {
359 dev_dbg(&pdev->dev, "could not request ac97c irq\n");
360 goto err;
361 }
362
363 platform_set_drvdata(pdev, atmel_wm97xx);
364
365 ret = wm97xx_register_mach_ops(wm, &atmel_mach_ops);
366 if (ret)
367 goto err_irq;
368
369 return ret;
370
371err_irq:
372 free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
373err:
374 platform_set_drvdata(pdev, NULL);
375 kfree(atmel_wm97xx);
376 return ret;
377}
378
379static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
380{
381 struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
382 struct wm97xx *wm = atmel_wm97xx->wm;
383
384 ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
385 free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
386 del_timer_sync(&atmel_wm97xx->pen_timer);
387 wm97xx_unregister_mach_ops(wm);
388 platform_set_drvdata(pdev, NULL);
389 kfree(atmel_wm97xx);
390
391 return 0;
392}
393
394#ifdef CONFIG_PM
395static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg)
396{
397 struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
398
399 ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
400 disable_irq(atmel_wm97xx->gpio_irq);
401 del_timer_sync(&atmel_wm97xx->pen_timer);
402
403 return 0;
404}
405
406static int atmel_wm97xx_resume(struct platform_device *pdev)
407{
408 struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
409 struct wm97xx *wm = atmel_wm97xx->wm;
410
411 if (wm->input_dev->users) {
412 enable_irq(atmel_wm97xx->gpio_irq);
413 ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
414 }
415
416 return 0;
417}
418#else
419#define atmel_wm97xx_suspend NULL
420#define atmel_wm97xx_resume NULL
421#endif
422
423static struct platform_driver atmel_wm97xx_driver = {
424 .remove = __exit_p(atmel_wm97xx_remove),
425 .driver = {
426 .name = "wm97xx-touch",
427 },
428 .suspend = atmel_wm97xx_suspend,
429 .resume = atmel_wm97xx_resume,
430};
431
432static int __init atmel_wm97xx_init(void)
433{
434 return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe);
435}
436module_init(atmel_wm97xx_init);
437
438static void __exit atmel_wm97xx_exit(void)
439{
440 platform_driver_unregister(&atmel_wm97xx_driver);
441}
442module_exit(atmel_wm97xx_exit);
443
444MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
445MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
446MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
new file mode 100644
index 000000000000..3ab92222a525
--- /dev/null
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -0,0 +1,286 @@
1/*
2 * Touch Screen driver for EETI's I2C connected touch screen panels
3 * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
4 *
5 * See EETI's software guide for the protocol specification:
6 * http://home.eeti.com.tw/web20/eg/guide.htm
7 *
8 * Based on migor_ts.c
9 * Copyright (c) 2008 Magnus Damm
10 * Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>
11 *
12 * This file is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This file is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#include <linux/module.h>
28#include <linux/moduleparam.h>
29#include <linux/kernel.h>
30#include <linux/input.h>
31#include <linux/interrupt.h>
32#include <linux/i2c.h>
33#include <linux/timer.h>
34#include <linux/gpio.h>
35
36static int flip_x;
37module_param(flip_x, bool, 0644);
38MODULE_PARM_DESC(flip_x, "flip x coordinate");
39
40static int flip_y;
41module_param(flip_y, bool, 0644);
42MODULE_PARM_DESC(flip_y, "flip y coordinate");
43
44struct eeti_ts_priv {
45 struct i2c_client *client;
46 struct input_dev *input;
47 struct work_struct work;
48 struct mutex mutex;
49 int irq;
50};
51
52#define EETI_TS_BITDEPTH (11)
53#define EETI_MAXVAL ((1 << (EETI_TS_BITDEPTH + 1)) - 1)
54
55#define REPORT_BIT_PRESSED (1 << 0)
56#define REPORT_BIT_AD0 (1 << 1)
57#define REPORT_BIT_AD1 (1 << 2)
58#define REPORT_BIT_HAS_PRESSURE (1 << 6)
59#define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH)
60
61static void eeti_ts_read(struct work_struct *work)
62{
63 char buf[6];
64 unsigned int x, y, res, pressed, to = 100;
65 struct eeti_ts_priv *priv =
66 container_of(work, struct eeti_ts_priv, work);
67
68 mutex_lock(&priv->mutex);
69
70 while (!gpio_get_value(irq_to_gpio(priv->irq)) && --to)
71 i2c_master_recv(priv->client, buf, sizeof(buf));
72
73 if (!to) {
74 dev_err(&priv->client->dev,
75 "unable to clear IRQ - line stuck?\n");
76 goto out;
77 }
78
79 /* drop non-report packets */
80 if (!(buf[0] & 0x80))
81 goto out;
82
83 pressed = buf[0] & REPORT_BIT_PRESSED;
84 res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1));
85 x = buf[2] | (buf[1] << 8);
86 y = buf[4] | (buf[3] << 8);
87
88 /* fix the range to 11 bits */
89 x >>= res - EETI_TS_BITDEPTH;
90 y >>= res - EETI_TS_BITDEPTH;
91
92 if (flip_x)
93 x = EETI_MAXVAL - x;
94
95 if (flip_y)
96 y = EETI_MAXVAL - y;
97
98 if (buf[0] & REPORT_BIT_HAS_PRESSURE)
99 input_report_abs(priv->input, ABS_PRESSURE, buf[5]);
100
101 input_report_abs(priv->input, ABS_X, x);
102 input_report_abs(priv->input, ABS_Y, y);
103 input_report_key(priv->input, BTN_TOUCH, !!pressed);
104 input_sync(priv->input);
105
106out:
107 mutex_unlock(&priv->mutex);
108}
109
110static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
111{
112 struct eeti_ts_priv *priv = dev_id;
113
114 /* postpone I2C transactions as we are atomic */
115 schedule_work(&priv->work);
116
117 return IRQ_HANDLED;
118}
119
120static int eeti_ts_open(struct input_dev *dev)
121{
122 struct eeti_ts_priv *priv = input_get_drvdata(dev);
123
124 enable_irq(priv->irq);
125
126 /* Read the events once to arm the IRQ */
127 eeti_ts_read(&priv->work);
128
129 return 0;
130}
131
132static void eeti_ts_close(struct input_dev *dev)
133{
134 struct eeti_ts_priv *priv = input_get_drvdata(dev);
135
136 disable_irq(priv->irq);
137 cancel_work_sync(&priv->work);
138}
139
140static int __devinit eeti_ts_probe(struct i2c_client *client,
141 const struct i2c_device_id *idp)
142{
143 struct eeti_ts_priv *priv;
144 struct input_dev *input;
145 int err = -ENOMEM;
146
147 /* In contrast to what's described in the datasheet, there seems
148 * to be no way of probing the presence of that device using I2C
149 * commands. So we need to blindly believe it is there, and wait
150 * for interrupts to occur. */
151
152 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
153 if (!priv) {
154 dev_err(&client->dev, "failed to allocate driver data\n");
155 goto err0;
156 }
157
158 mutex_init(&priv->mutex);
159 input = input_allocate_device();
160
161 if (!input) {
162 dev_err(&client->dev, "Failed to allocate input device.\n");
163 goto err1;
164 }
165
166 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
167 input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
168
169 input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0);
170 input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0);
171 input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0);
172
173 input->name = client->name;
174 input->id.bustype = BUS_I2C;
175 input->dev.parent = &client->dev;
176 input->open = eeti_ts_open;
177 input->close = eeti_ts_close;
178
179 priv->client = client;
180 priv->input = input;
181 priv->irq = client->irq;
182
183 INIT_WORK(&priv->work, eeti_ts_read);
184 i2c_set_clientdata(client, priv);
185 input_set_drvdata(input, priv);
186
187 err = input_register_device(input);
188 if (err)
189 goto err1;
190
191 err = request_irq(priv->irq, eeti_ts_isr, IRQF_TRIGGER_FALLING,
192 client->name, priv);
193 if (err) {
194 dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
195 goto err2;
196 }
197
198 /* Disable the irq for now. It will be enabled once the input device
199 * is opened. */
200 disable_irq(priv->irq);
201
202 device_init_wakeup(&client->dev, 0);
203 return 0;
204
205err2:
206 input_unregister_device(input);
207 input = NULL; /* so we dont try to free it below */
208err1:
209 input_free_device(input);
210 i2c_set_clientdata(client, NULL);
211 kfree(priv);
212err0:
213 return err;
214}
215
216static int __devexit eeti_ts_remove(struct i2c_client *client)
217{
218 struct eeti_ts_priv *priv = i2c_get_clientdata(client);
219
220 free_irq(priv->irq, priv);
221 input_unregister_device(priv->input);
222 i2c_set_clientdata(client, NULL);
223 kfree(priv);
224
225 return 0;
226}
227
228#ifdef CONFIG_PM
229static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
230{
231 struct eeti_ts_priv *priv = i2c_get_clientdata(client);
232
233 if (device_may_wakeup(&client->dev))
234 enable_irq_wake(priv->irq);
235
236 return 0;
237}
238
239static int eeti_ts_resume(struct i2c_client *client)
240{
241 struct eeti_ts_priv *priv = i2c_get_clientdata(client);
242
243 if (device_may_wakeup(&client->dev))
244 disable_irq_wake(priv->irq);
245
246 return 0;
247}
248#else
249#define eeti_ts_suspend NULL
250#define eeti_ts_resume NULL
251#endif
252
253static const struct i2c_device_id eeti_ts_id[] = {
254 { "eeti_ts", 0 },
255 { }
256};
257MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
258
259static struct i2c_driver eeti_ts_driver = {
260 .driver = {
261 .name = "eeti_ts",
262 },
263 .probe = eeti_ts_probe,
264 .remove = __devexit_p(eeti_ts_remove),
265 .suspend = eeti_ts_suspend,
266 .resume = eeti_ts_resume,
267 .id_table = eeti_ts_id,
268};
269
270static int __init eeti_ts_init(void)
271{
272 return i2c_add_driver(&eeti_ts_driver);
273}
274
275static void __exit eeti_ts_exit(void)
276{
277 i2c_del_driver(&eeti_ts_driver);
278}
279
280MODULE_DESCRIPTION("EETI Touchscreen driver");
281MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
282MODULE_LICENSE("GPL");
283
284module_init(eeti_ts_init);
285module_exit(eeti_ts_exit);
286
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 948e167557f1..880f58c6a7c4 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -257,7 +257,7 @@ static int tsc2007_probe(struct i2c_client *client,
257 struct input_dev *input_dev; 257 struct input_dev *input_dev;
258 int err; 258 int err;
259 259
260 if (!pdata) { 260 if (!pdata || !pdata->get_pendown_state) {
261 dev_err(&client->dev, "platform data is required!\n"); 261 dev_err(&client->dev, "platform data is required!\n");
262 return -EINVAL; 262 return -EINVAL;
263 } 263 }
diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c
new file mode 100644
index 000000000000..6071f5882572
--- /dev/null
+++ b/drivers/input/touchscreen/w90p910_ts.c
@@ -0,0 +1,350 @@
1/*
2 * Copyright (c) 2008 Nuvoton technology corporation.
3 *
4 * Wan ZongShun <mcuos.com@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation;version 2 of the License.
9 *
10 */
11
12#include <linux/delay.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/io.h>
16#include <linux/input.h>
17#include <linux/interrupt.h>
18
19/* ADC controller bit defines */
20#define ADC_DELAY 0xf00
21#define ADC_DOWN 0x01
22#define ADC_TSC_Y (0x01 << 8)
23#define ADC_TSC_X (0x00 << 8)
24#define TSC_FOURWIRE (~(0x03 << 1))
25#define ADC_CLK_EN (0x01 << 28) /* ADC clock enable */
26#define ADC_READ_CON (0x01 << 12)
27#define ADC_CONV (0x01 << 13)
28#define ADC_SEMIAUTO (0x01 << 14)
29#define ADC_WAITTRIG (0x03 << 14)
30#define ADC_RST1 (0x01 << 16)
31#define ADC_RST0 (0x00 << 16)
32#define ADC_EN (0x01 << 17)
33#define ADC_INT (0x01 << 18)
34#define WT_INT (0x01 << 20)
35#define ADC_INT_EN (0x01 << 21)
36#define LVD_INT_EN (0x01 << 22)
37#define WT_INT_EN (0x01 << 23)
38#define ADC_DIV (0x04 << 1) /* div = 6 */
39
40enum ts_state {
41 TS_WAIT_NEW_PACKET, /* We are waiting next touch report */
42 TS_WAIT_X_COORD, /* We are waiting for ADC to report X coord */
43 TS_WAIT_Y_COORD, /* We are waiting for ADC to report Y coord */
44 TS_IDLE, /* Input device is closed, don't do anything */
45};
46
47struct w90p910_ts {
48 struct input_dev *input;
49 struct timer_list timer;
50 int irq_num;
51 void __iomem *clocken;
52 void __iomem *ts_reg;
53 spinlock_t lock;
54 enum ts_state state;
55};
56
57static void w90p910_report_event(struct w90p910_ts *w90p910_ts, bool down)
58{
59 struct input_dev *dev = w90p910_ts->input;
60
61 if (down) {
62 input_report_abs(dev, ABS_X,
63 __raw_readl(w90p910_ts->ts_reg + 0x0c));
64 input_report_abs(dev, ABS_Y,
65 __raw_readl(w90p910_ts->ts_reg + 0x10));
66 }
67
68 input_report_key(dev, BTN_TOUCH, down);
69 input_sync(dev);
70}
71
72static void w90p910_prepare_x_reading(struct w90p910_ts *w90p910_ts)
73{
74 unsigned long ctlreg;
75
76 __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg + 0x04);
77 ctlreg = __raw_readl(w90p910_ts->ts_reg);
78 ctlreg &= ~(ADC_WAITTRIG | WT_INT | WT_INT_EN);
79 ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV;
80 __raw_writel(ctlreg, w90p910_ts->ts_reg);
81
82 w90p910_ts->state = TS_WAIT_X_COORD;
83}
84
85static void w90p910_prepare_y_reading(struct w90p910_ts *w90p910_ts)
86{
87 unsigned long ctlreg;
88
89 __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg + 0x04);
90 ctlreg = __raw_readl(w90p910_ts->ts_reg);
91 ctlreg &= ~(ADC_WAITTRIG | ADC_INT | WT_INT_EN);
92 ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV;
93 __raw_writel(ctlreg, w90p910_ts->ts_reg);
94
95 w90p910_ts->state = TS_WAIT_Y_COORD;
96}
97
98static void w90p910_prepare_next_packet(struct w90p910_ts *w90p910_ts)
99{
100 unsigned long ctlreg;
101
102 ctlreg = __raw_readl(w90p910_ts->ts_reg);
103 ctlreg &= ~(ADC_INT | ADC_INT_EN | ADC_SEMIAUTO | ADC_CONV);
104 ctlreg |= ADC_WAITTRIG | WT_INT_EN;
105 __raw_writel(ctlreg, w90p910_ts->ts_reg);
106
107 w90p910_ts->state = TS_WAIT_NEW_PACKET;
108}
109
110static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id)
111{
112 struct w90p910_ts *w90p910_ts = dev_id;
113 unsigned long flags;
114
115 spin_lock_irqsave(&w90p910_ts->lock, flags);
116
117 switch (w90p910_ts->state) {
118 case TS_WAIT_NEW_PACKET:
119 /*
120 * The controller only generates interrupts when pen
121 * is down.
122 */
123 del_timer(&w90p910_ts->timer);
124 w90p910_prepare_x_reading(w90p910_ts);
125 break;
126
127
128 case TS_WAIT_X_COORD:
129 w90p910_prepare_y_reading(w90p910_ts);
130 break;
131
132 case TS_WAIT_Y_COORD:
133 w90p910_report_event(w90p910_ts, true);
134 w90p910_prepare_next_packet(w90p910_ts);
135 mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(100));
136 break;
137
138 case TS_IDLE:
139 break;
140 }
141
142 spin_unlock_irqrestore(&w90p910_ts->lock, flags);
143
144 return IRQ_HANDLED;
145}
146
147static void w90p910_check_pen_up(unsigned long data)
148{
149 struct w90p910_ts *w90p910_ts = (struct w90p910_ts *) data;
150 unsigned long flags;
151
152 spin_lock_irqsave(&w90p910_ts->lock, flags);
153
154 if (w90p910_ts->state == TS_WAIT_NEW_PACKET &&
155 !(__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN)) {
156
157 w90p910_report_event(w90p910_ts, false);
158 }
159
160 spin_unlock_irqrestore(&w90p910_ts->lock, flags);
161}
162
163static int w90p910_open(struct input_dev *dev)
164{
165 struct w90p910_ts *w90p910_ts = input_get_drvdata(dev);
166 unsigned long val;
167
168 /* enable the ADC clock */
169 val = __raw_readl(w90p910_ts->clocken);
170 __raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken);
171
172 __raw_writel(ADC_RST1, w90p910_ts->ts_reg);
173 msleep(1);
174 __raw_writel(ADC_RST0, w90p910_ts->ts_reg);
175 msleep(1);
176
177 /* set delay and screen type */
178 val = __raw_readl(w90p910_ts->ts_reg + 0x04);
179 __raw_writel(val & TSC_FOURWIRE, w90p910_ts->ts_reg + 0x04);
180 __raw_writel(ADC_DELAY, w90p910_ts->ts_reg + 0x08);
181
182 w90p910_ts->state = TS_WAIT_NEW_PACKET;
183 wmb();
184
185 /* set trigger mode */
186 val = __raw_readl(w90p910_ts->ts_reg);
187 val |= ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN;
188 __raw_writel(val, w90p910_ts->ts_reg);
189
190 return 0;
191}
192
193static void w90p910_close(struct input_dev *dev)
194{
195 struct w90p910_ts *w90p910_ts = input_get_drvdata(dev);
196 unsigned long val;
197
198 /* disable trigger mode */
199
200 spin_lock_irq(&w90p910_ts->lock);
201
202 w90p910_ts->state = TS_IDLE;
203
204 val = __raw_readl(w90p910_ts->ts_reg);
205 val &= ~(ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN | ADC_INT_EN);
206 __raw_writel(val, w90p910_ts->ts_reg);
207
208 spin_unlock_irq(&w90p910_ts->lock);
209
210 /* Now that interrupts are shut off we can safely delete timer */
211 del_timer_sync(&w90p910_ts->timer);
212
213 /* stop the ADC clock */
214 val = __raw_readl(w90p910_ts->clocken);
215 __raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken);
216}
217
218static int __devinit w90x900ts_probe(struct platform_device *pdev)
219{
220 struct w90p910_ts *w90p910_ts;
221 struct input_dev *input_dev;
222 struct resource *res;
223 int err;
224
225 w90p910_ts = kzalloc(sizeof(struct w90p910_ts), GFP_KERNEL);
226 input_dev = input_allocate_device();
227 if (!w90p910_ts || !input_dev) {
228 err = -ENOMEM;
229 goto fail1;
230 }
231
232 w90p910_ts->input = input_dev;
233 w90p910_ts->state = TS_IDLE;
234 spin_lock_init(&w90p910_ts->lock);
235 setup_timer(&w90p910_ts->timer, w90p910_check_pen_up,
236 (unsigned long)&w90p910_ts);
237
238 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
239 if (!res) {
240 err = -ENXIO;
241 goto fail1;
242 }
243
244 if (!request_mem_region(res->start, res->end - res->start + 1,
245 pdev->name)) {
246 err = -EBUSY;
247 goto fail1;
248 }
249
250 w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1);
251 if (!w90p910_ts->ts_reg) {
252 err = -ENOMEM;
253 goto fail2;
254 }
255
256 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
257 if (!res) {
258 err = -ENXIO;
259 goto fail3;
260 }
261
262 w90p910_ts->clocken = (void __iomem *)res->start;
263
264 input_dev->name = "W90P910 TouchScreen";
265 input_dev->phys = "w90p910ts/event0";
266 input_dev->id.bustype = BUS_HOST;
267 input_dev->id.vendor = 0x0005;
268 input_dev->id.product = 0x0001;
269 input_dev->id.version = 0x0100;
270 input_dev->dev.parent = &pdev->dev;
271 input_dev->open = w90p910_open;
272 input_dev->close = w90p910_close;
273
274 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
275 input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
276
277 input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0);
278 input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0);
279
280 input_set_drvdata(input_dev, w90p910_ts);
281
282 w90p910_ts->irq_num = platform_get_irq(pdev, 0);
283 if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
284 IRQF_DISABLED, "w90p910ts", w90p910_ts)) {
285 err = -EBUSY;
286 goto fail3;
287 }
288
289 err = input_register_device(w90p910_ts->input);
290 if (err)
291 goto fail4;
292
293 platform_set_drvdata(pdev, w90p910_ts);
294
295 return 0;
296
297fail4: free_irq(w90p910_ts->irq_num, w90p910_ts);
298fail3: iounmap(w90p910_ts->ts_reg);
299fail2: release_mem_region(res->start, res->end - res->start + 1);
300fail1: input_free_device(input_dev);
301 kfree(w90p910_ts);
302 return err;
303}
304
305static int __devexit w90x900ts_remove(struct platform_device *pdev)
306{
307 struct w90p910_ts *w90p910_ts = platform_get_drvdata(pdev);
308 struct resource *res;
309
310 free_irq(w90p910_ts->irq_num, w90p910_ts);
311 del_timer_sync(&w90p910_ts->timer);
312 iounmap(w90p910_ts->ts_reg);
313
314 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
315 release_mem_region(res->start, res->end - res->start + 1);
316
317 input_unregister_device(w90p910_ts->input);
318 kfree(w90p910_ts);
319
320 platform_set_drvdata(pdev, NULL);
321
322 return 0;
323}
324
325static struct platform_driver w90x900ts_driver = {
326 .probe = w90x900ts_probe,
327 .remove = __devexit_p(w90x900ts_remove),
328 .driver = {
329 .name = "w90x900-ts",
330 .owner = THIS_MODULE,
331 },
332};
333
334static int __init w90x900ts_init(void)
335{
336 return platform_driver_register(&w90x900ts_driver);
337}
338
339static void __exit w90x900ts_exit(void)
340{
341 platform_driver_unregister(&w90x900ts_driver);
342}
343
344module_init(w90x900ts_init);
345module_exit(w90x900ts_exit);
346
347MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
348MODULE_DESCRIPTION("w90p910 touch screen driver!");
349MODULE_LICENSE("GPL");
350MODULE_ALIAS("platform:w90p910-ts");