Merge branch 'org.openembedded.dev' of git@git.openembedded.net:openembedded into...
[vuplus_openembedded] / packages / linux / linux-2.6.28 / collie / 0012-move-ucb1200-ts-driver.patch
1 From 9e0d71c4a6247d88d3b772f6b05bcaa39711a937 Mon Sep 17 00:00:00 2001
2 From: Thomas Kunze <thommycheck@gmx.de>
3 Date: Tue, 10 Feb 2009 19:31:25 +0100
4 Subject: [PATCH 12/23] move ucb1200-ts driver
5
6 Move the touchscreen driver to drivers/input/touchscreen
7 where touchscreen drivers belong.
8
9 Conflicts:
10
11         drivers/input/touchscreen/Makefile
12         drivers/mfd/Kconfig
13         drivers/mfd/Makefile
14
15 Conflicts:
16
17         drivers/mfd/Kconfig
18         drivers/mfd/Makefile
19 ---
20  drivers/input/touchscreen/Kconfig      |    7 +
21  drivers/input/touchscreen/Makefile     |    1 +
22  drivers/input/touchscreen/ucb1x00-ts.c |  438 ++++++++++++++++++++++++++++++++
23  drivers/mfd/Kconfig                    |    3 -
24  drivers/mfd/Makefile                   |    3 +-
25  drivers/mfd/ucb1x00-ts.c               |  438 --------------------------------
26  6 files changed, 447 insertions(+), 443 deletions(-)
27  create mode 100644 drivers/input/touchscreen/ucb1x00-ts.c
28  delete mode 100644 drivers/mfd/ucb1x00-ts.c
29
30 diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
31 index 3d1ab8f..3ac8cd6 100644
32 --- a/drivers/input/touchscreen/Kconfig
33 +++ b/drivers/input/touchscreen/Kconfig
34 @@ -221,6 +221,13 @@ config TOUCHSCREEN_ATMEL_TSADCC
35           To compile this driver as a module, choose M here: the
36           module will be called atmel_tsadcc.
37  
38 +config TOUCHSCREEN_UCB1200_TS
39 +       tristate "Philips UCB1200 touchscreen"
40 +       depends on MCP_UCB1200
41 +       help
42 +         This enabled support for the Pilips UCB1200 touchscreen interface
43 +         and compatible.
44 +
45  config TOUCHSCREEN_UCB1400
46         tristate "Philips UCB1400 touchscreen"
47         depends on AC97_BUS
48 diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
49 index 15cf290..77ba930 100644
50 --- a/drivers/input/touchscreen/Makefile
51 +++ b/drivers/input/touchscreen/Makefile
52 @@ -25,6 +25,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)    += penmount.o
53  obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)   += touchit213.o
54  obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)   += touchright.o
55  obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)     += touchwin.o
56 +obj-$(CONFIG_TOUCHSCREEN_UCB1200_TS)   += ucb1x00-ts.o
57  obj-$(CONFIG_TOUCHSCREEN_UCB1400)      += ucb1400_ts.o
58  obj-$(CONFIG_TOUCHSCREEN_WM97XX)       += wm97xx-ts.o
59  wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
60 diff --git a/drivers/input/touchscreen/ucb1x00-ts.c b/drivers/input/touchscreen/ucb1x00-ts.c
61 new file mode 100644
62 index 0000000..b5feae9
63 --- /dev/null
64 +++ b/drivers/input/touchscreen/ucb1x00-ts.c
65 @@ -0,0 +1,438 @@
66 +/*
67 + *  Touchscreen driver for UCB1x00-based touchscreens
68 + *
69 + *  Copyright (C) 2001 Russell King, All Rights Reserved.
70 + *  Copyright (C) 2005 Pavel Machek
71 + *
72 + * This program is free software; you can redistribute it and/or modify
73 + * it under the terms of the GNU General Public License version 2 as
74 + * published by the Free Software Foundation.
75 + *
76 + * 21-Jan-2002 <jco@ict.es> :
77 + *
78 + * Added support for synchronous A/D mode. This mode is useful to
79 + * avoid noise induced in the touchpanel by the LCD, provided that
80 + * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin.
81 + * It is important to note that the signal connected to the ADCSYNC
82 + * pin should provide pulses even when the LCD is blanked, otherwise
83 + * a pen touch needed to unblank the LCD will never be read.
84 + */
85 +#include <linux/module.h>
86 +#include <linux/moduleparam.h>
87 +#include <linux/init.h>
88 +#include <linux/smp.h>
89 +#include <linux/sched.h>
90 +#include <linux/completion.h>
91 +#include <linux/delay.h>
92 +#include <linux/string.h>
93 +#include <linux/input.h>
94 +#include <linux/device.h>
95 +#include <linux/freezer.h>
96 +#include <linux/slab.h>
97 +#include <linux/kthread.h>
98 +#include <linux/mfd/ucb1x00.h>
99 +
100 +#include <asm/dma.h>
101 +#include <mach/collie.h>
102 +#include <asm/mach-types.h>
103 +
104 +
105 +
106 +struct ucb1x00_ts {
107 +       struct input_dev        *idev;
108 +       struct ucb1x00          *ucb;
109 +
110 +       wait_queue_head_t       irq_wait;
111 +       struct task_struct      *rtask;
112 +       u16                     x_res;
113 +       u16                     y_res;
114 +
115 +       unsigned int            restart:1;
116 +       unsigned int            adcsync:1;
117 +};
118 +
119 +static int adcsync;
120 +
121 +static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
122 +{
123 +       struct input_dev *idev = ts->idev;
124 +
125 +       input_report_abs(idev, ABS_X, x);
126 +       input_report_abs(idev, ABS_Y, y);
127 +       input_report_abs(idev, ABS_PRESSURE, pressure);
128 +       input_sync(idev);
129 +}
130 +
131 +static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
132 +{
133 +       struct input_dev *idev = ts->idev;
134 +
135 +       input_report_abs(idev, ABS_PRESSURE, 0);
136 +       input_sync(idev);
137 +}
138 +
139 +/*
140 + * Switch to interrupt mode.
141 + */
142 +static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
143 +{
144 +       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
145 +                       UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
146 +                       UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
147 +                       UCB_TS_CR_MODE_INT);
148 +}
149 +
150 +/*
151 + * Switch to pressure mode, and read pressure.  We don't need to wait
152 + * here, since both plates are being driven.
153 + */
154 +static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts)
155 +{
156 +       if (machine_is_collie()) {
157 +               ucb1x00_io_write(ts->ucb, COLLIE_TC35143_GPIO_TBL_CHK, 0);
158 +               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
159 +                                 UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMX_POW |
160 +                                 UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
161 +
162 +               udelay(55);
163 +
164 +               return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_AD2, ts->adcsync);
165 +       } else {
166 +               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
167 +                                 UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
168 +                                 UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
169 +                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
170 +
171 +               return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
172 +       }
173 +}
174 +
175 +/*
176 + * Switch to X position mode and measure Y plate.  We switch the plate
177 + * configuration in pressure mode, then switch to position mode.  This
178 + * gives a faster response time.  Even so, we need to wait about 55us
179 + * for things to stabilise.
180 + */
181 +static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
182 +{
183 +       if (machine_is_collie())
184 +               ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
185 +       else {
186 +               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
187 +                                 UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
188 +                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
189 +               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
190 +                                 UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
191 +                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
192 +       }
193 +       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
194 +                       UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
195 +                       UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
196 +
197 +       udelay(55);
198 +
199 +       return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
200 +}
201 +
202 +/*
203 + * Switch to Y position mode and measure X plate.  We switch the plate
204 + * configuration in pressure mode, then switch to position mode.  This
205 + * gives a faster response time.  Even so, we need to wait about 55us
206 + * for things to stabilise.
207 + */
208 +static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
209 +{
210 +       if (machine_is_collie())
211 +               ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
212 +       else {
213 +               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
214 +                                 UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
215 +                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
216 +               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
217 +                                 UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
218 +                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
219 +       }
220 +
221 +       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
222 +                       UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
223 +                       UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
224 +
225 +       udelay(55);
226 +
227 +       return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
228 +}
229 +
230 +/*
231 + * Switch to X plate resistance mode.  Set MX to ground, PX to
232 + * supply.  Measure current.
233 + */
234 +static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts)
235 +{
236 +       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
237 +                       UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
238 +                       UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
239 +       return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
240 +}
241 +
242 +/*
243 + * Switch to Y plate resistance mode.  Set MY to ground, PY to
244 + * supply.  Measure current.
245 + */
246 +static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
247 +{
248 +       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
249 +                       UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
250 +                       UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
251 +       return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
252 +}
253 +
254 +static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts)
255 +{
256 +       unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
257 +
258 +       if (machine_is_collie())
259 +               return (!(val & (UCB_TS_CR_TSPX_LOW)));
260 +       else
261 +               return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW));
262 +}
263 +
264 +/*
265 + * This is a RT kernel thread that handles the ADC accesses
266 + * (mainly so we can use semaphores in the UCB1200 core code
267 + * to serialise accesses to the ADC).
268 + */
269 +static int ucb1x00_thread(void *_ts)
270 +{
271 +       struct ucb1x00_ts *ts = _ts;
272 +       DECLARE_WAITQUEUE(wait, current);
273 +       int valid = 0;
274 +
275 +       set_freezable();
276 +       add_wait_queue(&ts->irq_wait, &wait);
277 +       while (!kthread_should_stop()) {
278 +               unsigned int x, y, p;
279 +               signed long timeout;
280 +
281 +               ts->restart = 0;
282 +
283 +               ucb1x00_adc_enable(ts->ucb);
284 +
285 +               x = ucb1x00_ts_read_xpos(ts);
286 +               y = ucb1x00_ts_read_ypos(ts);
287 +               p = ucb1x00_ts_read_pressure(ts);
288 +
289 +               /*
290 +                * Switch back to interrupt mode.
291 +                */
292 +               ucb1x00_ts_mode_int(ts);
293 +               ucb1x00_adc_disable(ts->ucb);
294 +
295 +               msleep(10);
296 +
297 +               ucb1x00_enable(ts->ucb);
298 +
299 +
300 +               if (ucb1x00_ts_pen_down(ts)) {
301 +                       set_current_state(TASK_INTERRUPTIBLE);
302 +
303 +                       ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
304 +                       ucb1x00_disable(ts->ucb);
305 +
306 +                       /*
307 +                        * If we spat out a valid sample set last time,
308 +                        * spit out a "pen off" sample here.
309 +                        */
310 +                       if (valid) {
311 +                               ucb1x00_ts_event_release(ts);
312 +                               valid = 0;
313 +                       }
314 +
315 +                       timeout = MAX_SCHEDULE_TIMEOUT;
316 +               } else {
317 +                       ucb1x00_disable(ts->ucb);
318 +
319 +                       /*
320 +                        * Filtering is policy.  Policy belongs in user
321 +                        * space.  We therefore leave it to user space
322 +                        * to do any filtering they please.
323 +                        */
324 +                       if (!ts->restart) {
325 +                               ucb1x00_ts_evt_add(ts, p, x, y);
326 +                               valid = 1;
327 +                       }
328 +
329 +                       set_current_state(TASK_INTERRUPTIBLE);
330 +                       timeout = HZ / 100;
331 +               }
332 +
333 +               try_to_freeze();
334 +
335 +               schedule_timeout(timeout);
336 +       }
337 +
338 +       remove_wait_queue(&ts->irq_wait, &wait);
339 +
340 +       ts->rtask = NULL;
341 +       return 0;
342 +}
343 +
344 +/*
345 + * We only detect touch screen _touches_ with this interrupt
346 + * handler, and even then we just schedule our task.
347 + */
348 +static void ucb1x00_ts_irq(int idx, void *id)
349 +{
350 +       struct ucb1x00_ts *ts = id;
351 +
352 +       ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
353 +       wake_up(&ts->irq_wait);
354 +}
355 +
356 +static int ucb1x00_ts_open(struct input_dev *idev)
357 +{
358 +       struct ucb1x00_ts *ts = input_get_drvdata(idev);
359 +       int ret = 0;
360 +
361 +       BUG_ON(ts->rtask);
362 +
363 +       init_waitqueue_head(&ts->irq_wait);
364 +       ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
365 +       if (ret < 0)
366 +               goto out;
367 +
368 +       /*
369 +        * If we do this at all, we should allow the user to
370 +        * measure and read the X and Y resistance at any time.
371 +        */
372 +       ucb1x00_adc_enable(ts->ucb);
373 +       ts->x_res = ucb1x00_ts_read_xres(ts);
374 +       ts->y_res = ucb1x00_ts_read_yres(ts);
375 +       ucb1x00_adc_disable(ts->ucb);
376 +
377 +       ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd");
378 +       if (!IS_ERR(ts->rtask)) {
379 +               ret = 0;
380 +       } else {
381 +               ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
382 +               ts->rtask = NULL;
383 +               ret = -EFAULT;
384 +       }
385 +
386 + out:
387 +       return ret;
388 +}
389 +
390 +/*
391 + * Release touchscreen resources.  Disable IRQs.
392 + */
393 +static void ucb1x00_ts_close(struct input_dev *idev)
394 +{
395 +       struct ucb1x00_ts *ts = input_get_drvdata(idev);
396 +
397 +       if (ts->rtask)
398 +               kthread_stop(ts->rtask);
399 +
400 +       ucb1x00_enable(ts->ucb);
401 +       ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
402 +       ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
403 +       ucb1x00_disable(ts->ucb);
404 +}
405 +
406 +#ifdef CONFIG_PM
407 +static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
408 +{
409 +       struct ucb1x00_ts *ts = dev->priv;
410 +
411 +       if (ts->rtask != NULL) {
412 +               /*
413 +                * Restart the TS thread to ensure the
414 +                * TS interrupt mode is set up again
415 +                * after sleep.
416 +                */
417 +               ts->restart = 1;
418 +               wake_up(&ts->irq_wait);
419 +       }
420 +       return 0;
421 +}
422 +#else
423 +#define ucb1x00_ts_resume NULL
424 +#endif
425 +
426 +
427 +/*
428 + * Initialisation.
429 + */
430 +static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
431 +{
432 +       struct ucb1x00_ts *ts;
433 +       struct input_dev *idev;
434 +       int err;
435 +
436 +       ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
437 +       idev = input_allocate_device();
438 +       if (!ts || !idev) {
439 +               err = -ENOMEM;
440 +               goto fail;
441 +       }
442 +
443 +       ts->ucb = dev->ucb;
444 +       ts->idev = idev;
445 +       ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
446 +
447 +       idev->name       = "Touchscreen panel";
448 +       idev->id.product = ts->ucb->id;
449 +       idev->open       = ucb1x00_ts_open;
450 +       idev->close      = ucb1x00_ts_close;
451 +
452 +       __set_bit(EV_ABS, idev->evbit);
453 +       __set_bit(ABS_X, idev->absbit);
454 +       __set_bit(ABS_Y, idev->absbit);
455 +       __set_bit(ABS_PRESSURE, idev->absbit);
456 +
457 +       input_set_drvdata(idev, ts);
458 +
459 +       err = input_register_device(idev);
460 +       if (err)
461 +               goto fail;
462 +
463 +       dev->priv = ts;
464 +
465 +       return 0;
466 +
467 + fail:
468 +       input_free_device(idev);
469 +       kfree(ts);
470 +       return err;
471 +}
472 +
473 +static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
474 +{
475 +       struct ucb1x00_ts *ts = dev->priv;
476 +
477 +       input_unregister_device(ts->idev);
478 +       kfree(ts);
479 +}
480 +
481 +static struct ucb1x00_driver ucb1x00_ts_driver = {
482 +       .add            = ucb1x00_ts_add,
483 +       .remove         = ucb1x00_ts_remove,
484 +       .resume         = ucb1x00_ts_resume,
485 +};
486 +
487 +static int __init ucb1x00_ts_init(void)
488 +{
489 +       return ucb1x00_register_driver(&ucb1x00_ts_driver);
490 +}
491 +
492 +static void __exit ucb1x00_ts_exit(void)
493 +{
494 +       ucb1x00_unregister_driver(&ucb1x00_ts_driver);
495 +}
496 +
497 +module_param(adcsync, int, 0444);
498 +module_init(ucb1x00_ts_init);
499 +module_exit(ucb1x00_ts_exit);
500 +
501 +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
502 +MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
503 +MODULE_LICENSE("GPL");
504 diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
505 index 2572773..bbc137d 100644
506 --- a/drivers/mfd/Kconfig
507 +++ b/drivers/mfd/Kconfig
508 @@ -172,8 +172,5 @@ config MCP_UCB1200
509         tristate "Support for UCB1200 / UCB1300"
510         depends on MCP
511  
512 -config MCP_UCB1200_TS
513 -       tristate "Touchscreen interface support"
514 -       depends on MCP_UCB1200 && INPUT
515  
516  endmenu
517 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
518 index 9a5ad8a..4981aff 100644
519 --- a/drivers/mfd/Makefile
520 +++ b/drivers/mfd/Makefile
521 @@ -24,11 +24,10 @@ obj-$(CONFIG_MFD_CORE)              += mfd-core.o
522  obj-$(CONFIG_MCP)              += mcp-core.o
523  obj-$(CONFIG_MCP_SA11X0)       += mcp-sa11x0.o
524  obj-$(CONFIG_MCP_UCB1200)      += ucb1x00-core.o
525 -obj-$(CONFIG_MCP_UCB1200_TS)   += ucb1x00-ts.o
526  
527  ifeq ($(CONFIG_SA1100_ASSABET),y)
528  obj-$(CONFIG_MCP_UCB1200)      += ucb1x00-assabet.o
529  endif
530  obj-$(CONFIG_UCB1400_CORE)     += ucb1400_core.o
531  
532 -obj-$(CONFIG_PMIC_DA903X)      += da903x.o
533 \ No newline at end of file
534 +obj-$(CONFIG_PMIC_DA903X)      += da903x.o
535 diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
536 deleted file mode 100644
537 index b5feae9..0000000
538 --- a/drivers/mfd/ucb1x00-ts.c
539 +++ /dev/null
540 @@ -1,438 +0,0 @@
541 -/*
542 - *  Touchscreen driver for UCB1x00-based touchscreens
543 - *
544 - *  Copyright (C) 2001 Russell King, All Rights Reserved.
545 - *  Copyright (C) 2005 Pavel Machek
546 - *
547 - * This program is free software; you can redistribute it and/or modify
548 - * it under the terms of the GNU General Public License version 2 as
549 - * published by the Free Software Foundation.
550 - *
551 - * 21-Jan-2002 <jco@ict.es> :
552 - *
553 - * Added support for synchronous A/D mode. This mode is useful to
554 - * avoid noise induced in the touchpanel by the LCD, provided that
555 - * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin.
556 - * It is important to note that the signal connected to the ADCSYNC
557 - * pin should provide pulses even when the LCD is blanked, otherwise
558 - * a pen touch needed to unblank the LCD will never be read.
559 - */
560 -#include <linux/module.h>
561 -#include <linux/moduleparam.h>
562 -#include <linux/init.h>
563 -#include <linux/smp.h>
564 -#include <linux/sched.h>
565 -#include <linux/completion.h>
566 -#include <linux/delay.h>
567 -#include <linux/string.h>
568 -#include <linux/input.h>
569 -#include <linux/device.h>
570 -#include <linux/freezer.h>
571 -#include <linux/slab.h>
572 -#include <linux/kthread.h>
573 -#include <linux/mfd/ucb1x00.h>
574 -
575 -#include <asm/dma.h>
576 -#include <mach/collie.h>
577 -#include <asm/mach-types.h>
578 -
579 -
580 -
581 -struct ucb1x00_ts {
582 -       struct input_dev        *idev;
583 -       struct ucb1x00          *ucb;
584 -
585 -       wait_queue_head_t       irq_wait;
586 -       struct task_struct      *rtask;
587 -       u16                     x_res;
588 -       u16                     y_res;
589 -
590 -       unsigned int            restart:1;
591 -       unsigned int            adcsync:1;
592 -};
593 -
594 -static int adcsync;
595 -
596 -static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
597 -{
598 -       struct input_dev *idev = ts->idev;
599 -
600 -       input_report_abs(idev, ABS_X, x);
601 -       input_report_abs(idev, ABS_Y, y);
602 -       input_report_abs(idev, ABS_PRESSURE, pressure);
603 -       input_sync(idev);
604 -}
605 -
606 -static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
607 -{
608 -       struct input_dev *idev = ts->idev;
609 -
610 -       input_report_abs(idev, ABS_PRESSURE, 0);
611 -       input_sync(idev);
612 -}
613 -
614 -/*
615 - * Switch to interrupt mode.
616 - */
617 -static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
618 -{
619 -       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
620 -                       UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
621 -                       UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
622 -                       UCB_TS_CR_MODE_INT);
623 -}
624 -
625 -/*
626 - * Switch to pressure mode, and read pressure.  We don't need to wait
627 - * here, since both plates are being driven.
628 - */
629 -static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts)
630 -{
631 -       if (machine_is_collie()) {
632 -               ucb1x00_io_write(ts->ucb, COLLIE_TC35143_GPIO_TBL_CHK, 0);
633 -               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
634 -                                 UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMX_POW |
635 -                                 UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
636 -
637 -               udelay(55);
638 -
639 -               return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_AD2, ts->adcsync);
640 -       } else {
641 -               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
642 -                                 UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
643 -                                 UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
644 -                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
645 -
646 -               return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
647 -       }
648 -}
649 -
650 -/*
651 - * Switch to X position mode and measure Y plate.  We switch the plate
652 - * configuration in pressure mode, then switch to position mode.  This
653 - * gives a faster response time.  Even so, we need to wait about 55us
654 - * for things to stabilise.
655 - */
656 -static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
657 -{
658 -       if (machine_is_collie())
659 -               ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
660 -       else {
661 -               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
662 -                                 UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
663 -                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
664 -               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
665 -                                 UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
666 -                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
667 -       }
668 -       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
669 -                       UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
670 -                       UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
671 -
672 -       udelay(55);
673 -
674 -       return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
675 -}
676 -
677 -/*
678 - * Switch to Y position mode and measure X plate.  We switch the plate
679 - * configuration in pressure mode, then switch to position mode.  This
680 - * gives a faster response time.  Even so, we need to wait about 55us
681 - * for things to stabilise.
682 - */
683 -static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
684 -{
685 -       if (machine_is_collie())
686 -               ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
687 -       else {
688 -               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
689 -                                 UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
690 -                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
691 -               ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
692 -                                 UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
693 -                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
694 -       }
695 -
696 -       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
697 -                       UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
698 -                       UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
699 -
700 -       udelay(55);
701 -
702 -       return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
703 -}
704 -
705 -/*
706 - * Switch to X plate resistance mode.  Set MX to ground, PX to
707 - * supply.  Measure current.
708 - */
709 -static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts)
710 -{
711 -       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
712 -                       UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
713 -                       UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
714 -       return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
715 -}
716 -
717 -/*
718 - * Switch to Y plate resistance mode.  Set MY to ground, PY to
719 - * supply.  Measure current.
720 - */
721 -static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
722 -{
723 -       ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
724 -                       UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
725 -                       UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
726 -       return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
727 -}
728 -
729 -static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts)
730 -{
731 -       unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
732 -
733 -       if (machine_is_collie())
734 -               return (!(val & (UCB_TS_CR_TSPX_LOW)));
735 -       else
736 -               return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW));
737 -}
738 -
739 -/*
740 - * This is a RT kernel thread that handles the ADC accesses
741 - * (mainly so we can use semaphores in the UCB1200 core code
742 - * to serialise accesses to the ADC).
743 - */
744 -static int ucb1x00_thread(void *_ts)
745 -{
746 -       struct ucb1x00_ts *ts = _ts;
747 -       DECLARE_WAITQUEUE(wait, current);
748 -       int valid = 0;
749 -
750 -       set_freezable();
751 -       add_wait_queue(&ts->irq_wait, &wait);
752 -       while (!kthread_should_stop()) {
753 -               unsigned int x, y, p;
754 -               signed long timeout;
755 -
756 -               ts->restart = 0;
757 -
758 -               ucb1x00_adc_enable(ts->ucb);
759 -
760 -               x = ucb1x00_ts_read_xpos(ts);
761 -               y = ucb1x00_ts_read_ypos(ts);
762 -               p = ucb1x00_ts_read_pressure(ts);
763 -
764 -               /*
765 -                * Switch back to interrupt mode.
766 -                */
767 -               ucb1x00_ts_mode_int(ts);
768 -               ucb1x00_adc_disable(ts->ucb);
769 -
770 -               msleep(10);
771 -
772 -               ucb1x00_enable(ts->ucb);
773 -
774 -
775 -               if (ucb1x00_ts_pen_down(ts)) {
776 -                       set_current_state(TASK_INTERRUPTIBLE);
777 -
778 -                       ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
779 -                       ucb1x00_disable(ts->ucb);
780 -
781 -                       /*
782 -                        * If we spat out a valid sample set last time,
783 -                        * spit out a "pen off" sample here.
784 -                        */
785 -                       if (valid) {
786 -                               ucb1x00_ts_event_release(ts);
787 -                               valid = 0;
788 -                       }
789 -
790 -                       timeout = MAX_SCHEDULE_TIMEOUT;
791 -               } else {
792 -                       ucb1x00_disable(ts->ucb);
793 -
794 -                       /*
795 -                        * Filtering is policy.  Policy belongs in user
796 -                        * space.  We therefore leave it to user space
797 -                        * to do any filtering they please.
798 -                        */
799 -                       if (!ts->restart) {
800 -                               ucb1x00_ts_evt_add(ts, p, x, y);
801 -                               valid = 1;
802 -                       }
803 -
804 -                       set_current_state(TASK_INTERRUPTIBLE);
805 -                       timeout = HZ / 100;
806 -               }
807 -
808 -               try_to_freeze();
809 -
810 -               schedule_timeout(timeout);
811 -       }
812 -
813 -       remove_wait_queue(&ts->irq_wait, &wait);
814 -
815 -       ts->rtask = NULL;
816 -       return 0;
817 -}
818 -
819 -/*
820 - * We only detect touch screen _touches_ with this interrupt
821 - * handler, and even then we just schedule our task.
822 - */
823 -static void ucb1x00_ts_irq(int idx, void *id)
824 -{
825 -       struct ucb1x00_ts *ts = id;
826 -
827 -       ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
828 -       wake_up(&ts->irq_wait);
829 -}
830 -
831 -static int ucb1x00_ts_open(struct input_dev *idev)
832 -{
833 -       struct ucb1x00_ts *ts = input_get_drvdata(idev);
834 -       int ret = 0;
835 -
836 -       BUG_ON(ts->rtask);
837 -
838 -       init_waitqueue_head(&ts->irq_wait);
839 -       ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
840 -       if (ret < 0)
841 -               goto out;
842 -
843 -       /*
844 -        * If we do this at all, we should allow the user to
845 -        * measure and read the X and Y resistance at any time.
846 -        */
847 -       ucb1x00_adc_enable(ts->ucb);
848 -       ts->x_res = ucb1x00_ts_read_xres(ts);
849 -       ts->y_res = ucb1x00_ts_read_yres(ts);
850 -       ucb1x00_adc_disable(ts->ucb);
851 -
852 -       ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd");
853 -       if (!IS_ERR(ts->rtask)) {
854 -               ret = 0;
855 -       } else {
856 -               ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
857 -               ts->rtask = NULL;
858 -               ret = -EFAULT;
859 -       }
860 -
861 - out:
862 -       return ret;
863 -}
864 -
865 -/*
866 - * Release touchscreen resources.  Disable IRQs.
867 - */
868 -static void ucb1x00_ts_close(struct input_dev *idev)
869 -{
870 -       struct ucb1x00_ts *ts = input_get_drvdata(idev);
871 -
872 -       if (ts->rtask)
873 -               kthread_stop(ts->rtask);
874 -
875 -       ucb1x00_enable(ts->ucb);
876 -       ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
877 -       ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
878 -       ucb1x00_disable(ts->ucb);
879 -}
880 -
881 -#ifdef CONFIG_PM
882 -static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
883 -{
884 -       struct ucb1x00_ts *ts = dev->priv;
885 -
886 -       if (ts->rtask != NULL) {
887 -               /*
888 -                * Restart the TS thread to ensure the
889 -                * TS interrupt mode is set up again
890 -                * after sleep.
891 -                */
892 -               ts->restart = 1;
893 -               wake_up(&ts->irq_wait);
894 -       }
895 -       return 0;
896 -}
897 -#else
898 -#define ucb1x00_ts_resume NULL
899 -#endif
900 -
901 -
902 -/*
903 - * Initialisation.
904 - */
905 -static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
906 -{
907 -       struct ucb1x00_ts *ts;
908 -       struct input_dev *idev;
909 -       int err;
910 -
911 -       ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
912 -       idev = input_allocate_device();
913 -       if (!ts || !idev) {
914 -               err = -ENOMEM;
915 -               goto fail;
916 -       }
917 -
918 -       ts->ucb = dev->ucb;
919 -       ts->idev = idev;
920 -       ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
921 -
922 -       idev->name       = "Touchscreen panel";
923 -       idev->id.product = ts->ucb->id;
924 -       idev->open       = ucb1x00_ts_open;
925 -       idev->close      = ucb1x00_ts_close;
926 -
927 -       __set_bit(EV_ABS, idev->evbit);
928 -       __set_bit(ABS_X, idev->absbit);
929 -       __set_bit(ABS_Y, idev->absbit);
930 -       __set_bit(ABS_PRESSURE, idev->absbit);
931 -
932 -       input_set_drvdata(idev, ts);
933 -
934 -       err = input_register_device(idev);
935 -       if (err)
936 -               goto fail;
937 -
938 -       dev->priv = ts;
939 -
940 -       return 0;
941 -
942 - fail:
943 -       input_free_device(idev);
944 -       kfree(ts);
945 -       return err;
946 -}
947 -
948 -static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
949 -{
950 -       struct ucb1x00_ts *ts = dev->priv;
951 -
952 -       input_unregister_device(ts->idev);
953 -       kfree(ts);
954 -}
955 -
956 -static struct ucb1x00_driver ucb1x00_ts_driver = {
957 -       .add            = ucb1x00_ts_add,
958 -       .remove         = ucb1x00_ts_remove,
959 -       .resume         = ucb1x00_ts_resume,
960 -};
961 -
962 -static int __init ucb1x00_ts_init(void)
963 -{
964 -       return ucb1x00_register_driver(&ucb1x00_ts_driver);
965 -}
966 -
967 -static void __exit ucb1x00_ts_exit(void)
968 -{
969 -       ucb1x00_unregister_driver(&ucb1x00_ts_driver);
970 -}
971 -
972 -module_param(adcsync, int, 0444);
973 -module_init(ucb1x00_ts_init);
974 -module_exit(ucb1x00_ts_exit);
975 -
976 -MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
977 -MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
978 -MODULE_LICENSE("GPL");
979 -- 
980 1.5.6.5
981