]> Pileus Git - ~andy/linux/blob - drivers/mfd/ucb1x00-ts.c
52e0699eeb8ba418b524f1f7d11d8b1a5bb88049
[~andy/linux] / drivers / mfd / ucb1x00-ts.c
1 /*
2  *  linux/drivers/mfd/ucb1x00-ts.c
3  *
4  *  Copyright (C) 2001 Russell King, All Rights Reserved.
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 version 2 as
8  * published by the Free Software Foundation.
9  *
10  * 21-Jan-2002 <jco@ict.es> :
11  *
12  * Added support for synchronous A/D mode. This mode is useful to
13  * avoid noise induced in the touchpanel by the LCD, provided that
14  * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin.
15  * It is important to note that the signal connected to the ADCSYNC
16  * pin should provide pulses even when the LCD is blanked, otherwise
17  * a pen touch needed to unblank the LCD will never be read.
18  */
19 #include <linux/config.h>
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/init.h>
23 #include <linux/smp.h>
24 #include <linux/smp_lock.h>
25 #include <linux/sched.h>
26 #include <linux/completion.h>
27 #include <linux/delay.h>
28 #include <linux/string.h>
29 #include <linux/input.h>
30 #include <linux/device.h>
31 #include <linux/suspend.h>
32 #include <linux/slab.h>
33
34 #include <asm/dma.h>
35 #include <asm/semaphore.h>
36
37 #include "ucb1x00.h"
38
39
40 struct ucb1x00_ts {
41         struct input_dev        idev;
42         struct ucb1x00          *ucb;
43
44         wait_queue_head_t       irq_wait;
45         struct semaphore        sem;
46         struct completion       init_exit;
47         struct task_struct      *rtask;
48         int                     use_count;
49         u16                     x_res;
50         u16                     y_res;
51
52         int                     restart:1;
53         int                     adcsync:1;
54 };
55
56 static int adcsync;
57
58 static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
59 {
60         input_report_abs(&ts->idev, ABS_X, x);
61         input_report_abs(&ts->idev, ABS_Y, y);
62         input_report_abs(&ts->idev, ABS_PRESSURE, pressure);
63         input_sync(&ts->idev);
64 }
65
66 static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
67 {
68         input_report_abs(&ts->idev, ABS_PRESSURE, 0);
69         input_sync(&ts->idev);
70 }
71
72 /*
73  * Switch to interrupt mode.
74  */
75 static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
76 {
77         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
78                         UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
79                         UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
80                         UCB_TS_CR_MODE_INT);
81 }
82
83 /*
84  * Switch to pressure mode, and read pressure.  We don't need to wait
85  * here, since both plates are being driven.
86  */
87 static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts)
88 {
89         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
90                         UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
91                         UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
92                         UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
93
94         return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
95 }
96
97 /*
98  * Switch to X position mode and measure Y plate.  We switch the plate
99  * configuration in pressure mode, then switch to position mode.  This
100  * gives a faster response time.  Even so, we need to wait about 55us
101  * for things to stabilise.
102  */
103 static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
104 {
105         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
106                         UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
107                         UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
108         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
109                         UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
110                         UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
111         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
112                         UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
113                         UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
114
115         udelay(55);
116
117         return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
118 }
119
120 /*
121  * Switch to Y position mode and measure X plate.  We switch the plate
122  * configuration in pressure mode, then switch to position mode.  This
123  * gives a faster response time.  Even so, we need to wait about 55us
124  * for things to stabilise.
125  */
126 static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
127 {
128         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
129                         UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
130                         UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
131         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
132                         UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
133                         UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
134         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
135                         UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
136                         UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
137
138         udelay(55);
139
140         return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
141 }
142
143 /*
144  * Switch to X plate resistance mode.  Set MX to ground, PX to
145  * supply.  Measure current.
146  */
147 static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts)
148 {
149         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
150                         UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
151                         UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
152         return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
153 }
154
155 /*
156  * Switch to Y plate resistance mode.  Set MY to ground, PY to
157  * supply.  Measure current.
158  */
159 static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
160 {
161         ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
162                         UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
163                         UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
164         return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
165 }
166
167 /*
168  * This is a RT kernel thread that handles the ADC accesses
169  * (mainly so we can use semaphores in the UCB1200 core code
170  * to serialise accesses to the ADC).
171  */
172 static int ucb1x00_thread(void *_ts)
173 {
174         struct ucb1x00_ts *ts = _ts;
175         struct task_struct *tsk = current;
176         DECLARE_WAITQUEUE(wait, tsk);
177         int valid;
178
179         ts->rtask = tsk;
180
181         daemonize("ktsd");
182         /* only want to receive SIGKILL */
183         allow_signal(SIGKILL);
184
185         /*
186          * We could run as a real-time thread.  However, thus far
187          * this doesn't seem to be necessary.
188          */
189 //      tsk->policy = SCHED_FIFO;
190 //      tsk->rt_priority = 1;
191
192         complete(&ts->init_exit);
193
194         valid = 0;
195
196         add_wait_queue(&ts->irq_wait, &wait);
197         for (;;) {
198                 unsigned int x, y, p, val;
199                 signed long timeout;
200
201                 ts->restart = 0;
202
203                 ucb1x00_adc_enable(ts->ucb);
204
205                 x = ucb1x00_ts_read_xpos(ts);
206                 y = ucb1x00_ts_read_ypos(ts);
207                 p = ucb1x00_ts_read_pressure(ts);
208
209                 /*
210                  * Switch back to interrupt mode.
211                  */
212                 ucb1x00_ts_mode_int(ts);
213                 ucb1x00_adc_disable(ts->ucb);
214
215                 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
216                 schedule_timeout(HZ / 100);
217                 if (signal_pending(tsk))
218                         break;
219
220                 ucb1x00_enable(ts->ucb);
221                 val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
222
223                 if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) {
224                         set_task_state(tsk, TASK_INTERRUPTIBLE);
225
226                         ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
227                         ucb1x00_disable(ts->ucb);
228
229                         /*
230                          * If we spat out a valid sample set last time,
231                          * spit out a "pen off" sample here.
232                          */
233                         if (valid) {
234                                 ucb1x00_ts_event_release(ts);
235                                 valid = 0;
236                         }
237
238                         timeout = MAX_SCHEDULE_TIMEOUT;
239                 } else {
240                         ucb1x00_disable(ts->ucb);
241
242                         /*
243                          * Filtering is policy.  Policy belongs in user
244                          * space.  We therefore leave it to user space
245                          * to do any filtering they please.
246                          */
247                         if (!ts->restart) {
248                                 ucb1x00_ts_evt_add(ts, p, x, y);
249                                 valid = 1;
250                         }
251
252                         set_task_state(tsk, TASK_INTERRUPTIBLE);
253                         timeout = HZ / 100;
254                 }
255
256                 try_to_freeze();
257
258                 schedule_timeout(timeout);
259                 if (signal_pending(tsk))
260                         break;
261         }
262
263         remove_wait_queue(&ts->irq_wait, &wait);
264
265         ts->rtask = NULL;
266         complete_and_exit(&ts->init_exit, 0);
267 }
268
269 /*
270  * We only detect touch screen _touches_ with this interrupt
271  * handler, and even then we just schedule our task.
272  */
273 static void ucb1x00_ts_irq(int idx, void *id)
274 {
275         struct ucb1x00_ts *ts = id;
276         ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
277         wake_up(&ts->irq_wait);
278 }
279
280 static int ucb1x00_ts_open(struct input_dev *idev)
281 {
282         struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
283         int ret = 0;
284
285         if (down_interruptible(&ts->sem))
286                 return -EINTR;
287
288         if (ts->use_count++ != 0)
289                 goto out;
290
291         if (ts->rtask)
292                 panic("ucb1x00: rtask running?");
293
294         init_waitqueue_head(&ts->irq_wait);
295         ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
296         if (ret < 0)
297                 goto out;
298
299         /*
300          * If we do this at all, we should allow the user to
301          * measure and read the X and Y resistance at any time.
302          */
303         ucb1x00_adc_enable(ts->ucb);
304         ts->x_res = ucb1x00_ts_read_xres(ts);
305         ts->y_res = ucb1x00_ts_read_yres(ts);
306         ucb1x00_adc_disable(ts->ucb);
307
308         init_completion(&ts->init_exit);
309         ret = kernel_thread(ucb1x00_thread, ts, CLONE_KERNEL);
310         if (ret >= 0) {
311                 wait_for_completion(&ts->init_exit);
312                 ret = 0;
313         } else {
314                 ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
315         }
316
317  out:
318         if (ret)
319                 ts->use_count--;
320         up(&ts->sem);
321         return ret;
322 }
323
324 /*
325  * Release touchscreen resources.  Disable IRQs.
326  */
327 static void ucb1x00_ts_close(struct input_dev *idev)
328 {
329         struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
330
331         down(&ts->sem);
332         if (--ts->use_count == 0) {
333                 if (ts->rtask) {
334                         send_sig(SIGKILL, ts->rtask, 1);
335                         wait_for_completion(&ts->init_exit);
336                 }
337
338                 ucb1x00_enable(ts->ucb);
339                 ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
340                 ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
341                 ucb1x00_disable(ts->ucb);
342         }
343         up(&ts->sem);
344 }
345
346 #ifdef CONFIG_PM
347 static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
348 {
349         struct ucb1x00_ts *ts = dev->priv;
350
351         if (ts->rtask != NULL) {
352                 /*
353                  * Restart the TS thread to ensure the
354                  * TS interrupt mode is set up again
355                  * after sleep.
356                  */
357                 ts->restart = 1;
358                 wake_up(&ts->irq_wait);
359         }
360         return 0;
361 }
362 #else
363 #define ucb1x00_ts_resume NULL
364 #endif
365
366
367 /*
368  * Initialisation.
369  */
370 static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
371 {
372         struct ucb1x00_ts *ts;
373
374         ts = kmalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
375         if (!ts)
376                 return -ENOMEM;
377
378         memset(ts, 0, sizeof(struct ucb1x00_ts));
379
380         ts->ucb = dev->ucb;
381         ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
382         init_MUTEX(&ts->sem);
383
384         ts->idev.name       = "Touchscreen panel";
385         ts->idev.id.product = ts->ucb->id;
386         ts->idev.open       = ucb1x00_ts_open;
387         ts->idev.close      = ucb1x00_ts_close;
388
389         __set_bit(EV_ABS, ts->idev.evbit);
390         __set_bit(ABS_X, ts->idev.absbit);
391         __set_bit(ABS_Y, ts->idev.absbit);
392         __set_bit(ABS_PRESSURE, ts->idev.absbit);
393
394         input_register_device(&ts->idev);
395
396         dev->priv = ts;
397
398         return 0;
399 }
400
401 static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
402 {
403         struct ucb1x00_ts *ts = dev->priv;
404         input_unregister_device(&ts->idev);
405         kfree(ts);
406 }
407
408 static struct ucb1x00_driver ucb1x00_ts_driver = {
409         .add            = ucb1x00_ts_add,
410         .remove         = ucb1x00_ts_remove,
411         .resume         = ucb1x00_ts_resume,
412 };
413
414 static int __init ucb1x00_ts_init(void)
415 {
416         return ucb1x00_register_driver(&ucb1x00_ts_driver);
417 }
418
419 static void __exit ucb1x00_ts_exit(void)
420 {
421         ucb1x00_unregister_driver(&ucb1x00_ts_driver);
422 }
423
424 module_param(adcsync, int, 0444);
425 module_init(ucb1x00_ts_init);
426 module_exit(ucb1x00_ts_exit);
427
428 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
429 MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
430 MODULE_LICENSE("GPL");