hh.org updates
[hh.org.git] / arch / arm / mach-pxa / htcuniversal / htcuniversal_ts2.c
blob0de522cbc2954c1832c31d0fff0e5a2a062f1061
1 /* Touch screen driver for the TI something-or-other
3 * Copyright © 2005 SDG Systems, LLC
5 * Based on code that was based on the SAMCOP driver.
6 * Copyright © 2003, 2004 Compaq Computer Corporation.
8 * Use consistent with the GNU GPL is permitted,
9 * provided that this copyright notice is
10 * preserved in its entirety in all copies and derived works.
12 * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
13 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
14 * FITNESS FOR ANY PARTICULAR PURPOSE.
16 * Author: Keith Packard <keith.packard@hp.com>
17 * May 2003
19 * Updates:
21 * 2004-02-11 Michael Opdenacker Renamed names from samcop to shamcop,
22 * Goal:support HAMCOP and SAMCOP.
23 * 2004-02-14 Michael Opdenacker Temporary fix for device id handling
25 * 2005-02-18 Aric Blumer Converted basic structure to support hx4700
27 * 2005-06-07 Aric Blumer Added tssim device handling so we can
28 * hook in the fbvncserver.
31 #include <linux/module.h>
32 #include <linux/version.h>
34 #include <linux/init.h>
35 #include <linux/fs.h>
36 #include <linux/cdev.h>
37 #include <linux/interrupt.h>
38 #include <linux/sched.h>
39 #include <linux/pm.h>
40 #include <linux/delay.h>
41 #include <linux/input.h>
42 #include <linux/platform_device.h>
43 #include <linux/irq.h>
45 #include <asm/arch/hardware.h>
46 #include <asm/mach/irq.h>
47 #include <asm/io.h>
49 /* remove me */
50 #include <asm/arch/pxa-regs.h>
51 #include <asm/arch/htcuniversal-gpio.h>
52 #include <asm/arch/htcuniversal-asic.h>
53 #include <asm/mach-types.h>
55 #include <asm/hardware/ipaq-asic3.h>
56 #include <linux/soc/asic3_base.h>
59 #include "tsc2046_ts.h"
61 enum touchscreen_state {
62 STATE_WAIT_FOR_TOUCH, /* Waiting for a PEN interrupt */
63 STATE_SAMPLING /* Actively sampling ADC */
66 struct touchscreen_data {
67 enum touchscreen_state state;
68 struct timer_list timer;
69 int irq;
70 struct input_dev *input;
71 /* */
72 int port;
73 int clock;
74 int pwrbit_X;
75 int pwrbit_Y;
78 static unsigned long poll_sample_time = 10; /* Sample every 10 milliseconds */
80 static struct touchscreen_data *ts_data;
82 static int irqblock;
84 module_param(poll_sample_time, ulong, 0644);
85 MODULE_PARM_DESC(poll_sample_time, "Poll sample time");
87 static inline void
88 report_touchpanel(struct touchscreen_data *ts, int pressure, int x, int y)
90 input_report_abs(ts->input, ABS_PRESSURE, pressure);
91 input_report_abs(ts->input, ABS_X, x);
92 input_report_abs(ts->input, ABS_Y, y);
93 input_sync(ts->input);
96 static void start_read(struct touchscreen_data *touch);
98 static irqreturn_t
99 pen_isr(int irq, void *irq_desc)
101 struct touchscreen_data *ts = ts_data;
103 if(irq == ts->irq /* && !irqblock */) {
104 irqblock = 1;
107 * Disable the pen interrupt. It's reenabled when the user lifts the
108 * pen.
110 disable_irq(ts->irq);
112 if (ts->state == STATE_WAIT_FOR_TOUCH) {
113 ts->state = STATE_SAMPLING;
114 start_read(ts);
115 } else {
116 /* Shouldn't happen */
117 printk(KERN_ERR "Unexpected ts interrupt\n");
121 return IRQ_HANDLED;
124 static void
125 ssp_init(int port, int clock)
128 pxa_set_cken(clock, 1);
130 /* *** Set up the SPI Registers *** */
131 SSCR0_P(port) =
132 (1 << 20) /* Extended Data Size Select */
133 | (6 << 8) /* Serial Clock Rate */
134 | (0 << 7) /* Synchronous Serial Enable (Disable for now) */
135 | (0 << 4) /* Motorola SPI Interface */
136 | (7 << 0) /* Data Size Select (24-bit) */
138 SSCR1_P(port) = 0;
139 SSPSP_P(port) = 0;
141 /* Clear the Status */
142 SSSR_P(port) = SSSR_P(port) & 0x00fcfffc;
144 /* Now enable it */
145 SSCR0_P(port) =
146 (1 << 20) /* Extended Data Size Select */
147 | (6 << 8) /* Serial Clock Rate */
148 | (1 << 7) /* Synchronous Serial Enable */
149 | (0 << 4) /* Motorola SPI Interface */
150 | (7 << 0) /* Data Size Select (24-bit) */
154 static void
155 start_read(struct touchscreen_data *touch)
157 unsigned long inc = (poll_sample_time * HZ) / 1000;
158 int i;
160 /* Write here to the serial port. We request X and Y only for now.
161 * Then we have to wait for poll_sample_time before we read out the serial
162 * port. Then, when we read it out, we check to see if the pen is still
163 * down. If so, then we issue another request here.
165 #define TS_SAMPLES 7
168 * We do four samples for each, and throw out the highest and lowest, then
169 * average the other two.
172 for(i = 0; i < TS_SAMPLES; i++) {
173 while(!(SSSR_P(touch->port) & (1 << 2)))
175 /* It's not full. Write the command for X */
176 SSDR_P(touch->port) = (TSC2046_SAMPLE_X|(touch->pwrbit_X))<<16;
179 for(i = 0; i < TS_SAMPLES; i++) {
180 while(!(SSSR_P(touch->port) & (1 << 2)))
182 /* It's not full. Write the command for Y */
183 SSDR_P(touch->port) = (TSC2046_SAMPLE_Y|(touch->pwrbit_Y))<<16;
187 * Enable the timer. We should get an interrupt, but we want keep a timer
188 * to ensure that we can detect missing data
190 mod_timer(&touch->timer, jiffies + inc);
193 static void
194 ts_timer_callback(unsigned long data)
196 struct touchscreen_data *ts = (struct touchscreen_data *)data;
197 int x, a[TS_SAMPLES], y;
198 static int oldx, oldy;
199 int ssrval;
200 int statusa;
203 * Check here to see if there is anything in the SPI FIFO. If so,
204 * return it if there has been a change. If not, then we have a
205 * timeout. Generate an erro somehow.
207 ssrval = SSSR_P(ts->port);
209 if(ssrval & (1 << 3)) { /* Look at Rx Not Empty bit */
210 int number_of_entries_in_fifo;
212 /* The FIFO is not emtpy. Good! Now make sure there are at least two
213 * entries. (Should be two exactly.) */
215 number_of_entries_in_fifo = ((ssrval >> 12) & 0xf) + 1;
217 if(number_of_entries_in_fifo < TS_SAMPLES * 2) {
218 /* Not ready yet. Come back later. */
219 unsigned long inc = (poll_sample_time * HZ) / 1000;
220 mod_timer(&ts->timer, jiffies + inc);
221 return;
224 if(number_of_entries_in_fifo == TS_SAMPLES * 2) {
225 int i, j;
227 for(i = 0; i < TS_SAMPLES; i++) {
228 a[i] = SSDR_P(ts->port);
230 /* Sort them (bubble) */
231 for(j = TS_SAMPLES - 1; j > 0; j--) {
232 for(i = 0; i < j; i++) {
233 if(a[i] > a[i + 1]) {
234 int tmp;
235 tmp = a[i+1];
236 a[i+1] = a[i];
237 a[i] = tmp;
242 /* Take the average of the middle two */
243 /* x = (a[TS_SAMPLES/2 - 1] + a[TS_SAMPLES/2] + a[TS_SAMPLES/2+1] + a[TS_SAMPLES/2+2]) >> 2; */
244 x = a[TS_SAMPLES/2];
246 for(i = 0; i < TS_SAMPLES; i++) {
247 a[i] = SSDR_P(ts->port);
249 /* Sort them (bubble) */
250 for(j = TS_SAMPLES - 1; j > 0; j--) {
251 for(i = 0; i < j; i++) {
252 if(a[i] > a[i + 1]) {
253 int tmp;
254 tmp = a[i+1];
255 a[i+1] = a[i];
256 a[i] = tmp;
262 /* Take the average of the middle two */
263 /* y = (a[TS_SAMPLES/2 - 1] + a[TS_SAMPLES/2] + a[TS_SAMPLES/2+1] + a[TS_SAMPLES/2+2]) >> 2; */
264 y = a[TS_SAMPLES/2];
265 } else {
266 /* We have an error! Too many entries. */
267 printk(KERN_ERR "TS: Expected %d entries. Got %d\n", TS_SAMPLES*2, number_of_entries_in_fifo);
268 /* Try to clear the FIFO */
269 while(number_of_entries_in_fifo--) {
270 (void)SSDR_P(ts->port);
272 if( ((statusa = asic3_get_gpio_status_a( &htcuniversal_asic3.dev )) & (1<<GPIOA_TOUCHSCREEN_N)) == 0) {
273 start_read(ts);
275 return;
277 } else {
278 /* Not ready yet. Come back later. */
279 unsigned long inc = (poll_sample_time * HZ) / 1000;
280 mod_timer(&ts->timer, jiffies + inc);
281 return;
285 * Now we check to see if the pen is still down. If it is, then call
286 * start_read().
288 statusa = asic3_get_gpio_status_a( &htcuniversal_asic3.dev );
290 if( (statusa & (1<<GPIOA_TOUCHSCREEN_N)) == 0) {
291 /* Still down */
292 if(oldx != x || oldy != y) {
293 oldx = x;
294 oldy = y;
295 report_touchpanel(ts, 1, x, y);
297 start_read(ts);
298 } else {
299 /* Up */
300 report_touchpanel(ts, 0, 0, 0);
301 irqblock = 0;
302 ts->state = STATE_WAIT_FOR_TOUCH;
303 /* Re-enable pen down interrupt */
304 enable_irq(ts->irq);
308 static int
309 ts_probe (struct platform_device *dev)
311 int retval;
312 struct touchscreen_data *ts;
313 struct tsc2046_mach_info *mach = dev->dev.platform_data;
315 printk("htcuniversal: ts_probe\n");
317 ts = ts_data = kmalloc (sizeof (*ts), GFP_KERNEL);
318 if (ts == NULL) {
319 printk( KERN_NOTICE "htcuniversal_ts: unable to allocate memory\n" );
320 return -ENOMEM;
322 memset (ts, 0, sizeof (*ts));
324 ts->input = input_allocate_device();
325 if (ts->input == NULL) {
326 printk( KERN_NOTICE "htcuniversal_ts: unable to allocation touchscreen input\n" );
327 kfree(ts);
328 return -ENOMEM;
330 ts->input->evbit[0] = BIT(EV_ABS);
331 ts->input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
332 ts->input->absmin[ABS_X] = 0;
333 ts->input->absmax[ABS_X] = 32767;
334 ts->input->absmin[ABS_Y] = 0;
335 ts->input->absmax[ABS_Y] = 32767;
336 ts->input->absmin[ABS_PRESSURE] = 0;
337 ts->input->absmax[ABS_PRESSURE] = 1;
339 ts->input->name = "htcuniversal_ts";
340 ts->input->phys = "touchscreen/htcuniversal_ts";
341 ts->input->private = ts;
343 input_register_device(ts->input);
345 ts->timer.function = ts_timer_callback;
346 ts->timer.data = (unsigned long)ts;
347 ts->state = STATE_WAIT_FOR_TOUCH;
348 init_timer (&ts->timer);
350 platform_set_drvdata(dev, ts);
352 ts->port=-1;
354 if (mach) {
355 ts->port = mach->port;
356 ts->clock = mach->clock;
357 ts->pwrbit_X = mach->pwrbit_X;
358 ts->pwrbit_Y = mach->pwrbit_Y;
360 /* static irq */
361 if (mach->irq)
362 ts->irq = mach->irq;
365 if (ts->port == -1)
367 printk("tsc2046: your device is not supported by this driver\n");
368 return -ENODEV;
371 /* *** Initialize the SSP interface *** */
372 ssp_init(ts->port, ts->clock);
374 while(!(SSSR_P(ts->port) & (1 << 2)))
376 SSDR_P(ts->port) = (TSC2046_SAMPLE_X|(ts->pwrbit_X))<<16;
378 for(retval = 0; retval < 100; retval++) {
379 if(SSSR_P(ts->port) & (1 << 3)) {
380 while(SSSR_P(ts->port) & (1 << 3)) {
381 (void)SSDR_P(ts->port);
383 break;
385 mdelay(1);
388 if (machine_is_htcuniversal() )
389 ts->irq = asic3_irq_base( &htcuniversal_asic3.dev ) + ASIC3_GPIOA_IRQ_BASE + GPIOA_TOUCHSCREEN_N;
391 retval = request_irq(ts->irq, pen_isr, SA_INTERRUPT, "tsc2046_ts", ts);
392 if(retval) {
393 printk("Unable to get interrupt\n");
394 input_unregister_device (ts->input);
395 return -ENODEV;
397 set_irq_type(ts->irq, IRQ_TYPE_EDGE_FALLING);
399 return 0;
402 static int
403 ts_remove (struct platform_device *dev)
405 struct touchscreen_data *ts = platform_get_drvdata(dev);
407 input_unregister_device (ts->input);
408 del_timer_sync (&ts->timer);
409 free_irq (ts->irq, ts);
410 pxa_set_cken(ts->clock, 0);
412 kfree(ts);
413 return 0;
416 static int
417 ts_suspend (struct platform_device *dev, pm_message_t state)
419 struct touchscreen_data *ts = platform_get_drvdata(dev);
421 disable_irq(ts->irq);
423 printk("htcuniversal_ts2_suspend: called.\n");
424 return 0;
427 static int
428 ts_resume (struct platform_device *dev)
430 struct touchscreen_data *ts = platform_get_drvdata(dev);
432 ts->state = STATE_WAIT_FOR_TOUCH;
433 ssp_init(ts->port, ts->clock);
434 enable_irq(ts->irq);
436 printk("htcuniversal_ts2_resume: called.\n");
437 return 0;
440 static struct platform_driver ts_driver = {
441 .probe = ts_probe,
442 .remove = ts_remove,
443 .suspend = ts_suspend,
444 .resume = ts_resume,
445 .driver = {
446 .name = "htcuniversal_ts",
451 static int
452 ts_module_init (void)
454 printk(KERN_NOTICE "HTC Universal Touch Screen Driver\n");
456 return platform_driver_register(&ts_driver);
459 static void
460 ts_module_cleanup (void)
462 platform_driver_unregister (&ts_driver);
465 module_init(ts_module_init);
466 module_exit(ts_module_cleanup);
468 MODULE_LICENSE("GPL");
469 MODULE_AUTHOR("Aric Blumer, SDG Systems, LLC");
470 MODULE_DESCRIPTION("HTC Universal Touch Screen Driver");