hh.org updates
[hh.org.git] / arch / arm / mach-pxa / htcalpine / tsc2046-ts.c
blobd58c04090646c16ed8fe6ce92e4ac984d8315fad
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>
33 #include <linux/config.h>
35 #include <linux/init.h>
36 #include <linux/fs.h>
37 #include <linux/cdev.h>
38 #include <linux/interrupt.h>
39 #include <linux/sched.h>
40 #include <linux/pm.h>
41 #include <linux/delay.h>
42 #include <linux/input.h>
43 #include <linux/platform_device.h>
44 #include <linux/irq.h>
46 #include <asm/arch/hardware.h>
47 #include <asm/mach/irq.h>
48 #include <asm/io.h>
50 /* remove me */
51 #include <asm/arch/pxa-regs.h>
52 #include <asm/arch/htcalpine-gpio.h>
54 #include "tsc2046_ts.h"
56 enum touchscreen_state {
57 STATE_WAIT_FOR_TOUCH, /* Waiting for a PEN interrupt */
58 STATE_SAMPLING /* Actively sampling ADC */
61 struct touchscreen_data {
62 enum touchscreen_state state;
63 struct timer_list timer;
64 int irq;
65 struct input_dev *input;
66 /* */
67 int port;
68 int clock;
69 int pwrbit_X;
70 int pwrbit_Y;
73 static unsigned long poll_sample_time = 10; /* Sample every 10 milliseconds */
75 static struct touchscreen_data *ts_data;
77 static int irqblock;
79 module_param(poll_sample_time, ulong, 0644);
80 MODULE_PARM_DESC(poll_sample_time, "Poll sample time");
82 static inline void
83 report_touchpanel(struct touchscreen_data *ts, int pressure, int x, int y)
85 input_report_abs(ts->input, ABS_PRESSURE, pressure);
86 input_report_abs(ts->input, ABS_X, x);
87 input_report_abs(ts->input, ABS_Y, y);
88 input_sync(ts->input);
91 static void start_read(struct touchscreen_data *touch);
93 static irqreturn_t
94 pen_isr(int irq, void *irq_desc, struct pt_regs *regs)
96 struct touchscreen_data *ts = ts_data;
98 if(irq == ts->irq /* && !irqblock */) {
99 irqblock = 1;
102 * Disable the pen interrupt. It's reenabled when the user lifts the
103 * pen.
105 disable_irq(ts->irq);
107 if (ts->state == STATE_WAIT_FOR_TOUCH) {
108 ts->state = STATE_SAMPLING;
109 start_read(ts);
110 } else {
111 /* Shouldn't happen */
112 printk(KERN_ERR "Unexpected ts interrupt\n");
116 return IRQ_HANDLED;
119 static void
120 ssp_init(int port, int clock)
123 pxa_set_cken(clock, 1);
125 /* *** Set up the SPI Registers *** */
126 SSCR0_P(port) =
127 (1 << 20) /* Extended Data Size Select */
128 | (6 << 8) /* Serial Clock Rate */
129 | (0 << 7) /* Synchronous Serial Enable (Disable for now) */
130 | (0 << 4) /* Motorola SPI Interface */
131 | (7 << 0) /* Data Size Select (24-bit) */
133 SSCR1_P(port) = 0;
134 SSPSP_P(port) = 0;
136 /* Clear the Status */
137 SSSR_P(port) = SSSR_P(port) & 0x00fcfffc;
139 /* Now enable it */
140 SSCR0_P(port) =
141 (1 << 20) /* Extended Data Size Select */
142 | (6 << 8) /* Serial Clock Rate */
143 | (1 << 7) /* Synchronous Serial Enable */
144 | (0 << 4) /* Motorola SPI Interface */
145 | (7 << 0) /* Data Size Select (24-bit) */
149 static void
150 start_read(struct touchscreen_data *touch)
152 unsigned long inc = (poll_sample_time * HZ) / 1000;
153 int i;
155 /* Write here to the serial port. We request X and Y only for now.
156 * Then we have to wait for poll_sample_time before we read out the serial
157 * port. Then, when we read it out, we check to see if the pen is still
158 * down. If so, then we issue another request here.
160 #define TS_SAMPLES 7
163 * We do four samples for each, and throw out the highest and lowest, then
164 * average the other two.
167 for(i = 0; i < TS_SAMPLES; i++) {
168 while(!(SSSR_P(touch->port) & (1 << 2)))
170 /* It's not full. Write the command for X */
171 SSDR_P(touch->port) = (TSC2046_SAMPLE_X|(touch->pwrbit_X))<<16;
174 for(i = 0; i < TS_SAMPLES; i++) {
175 while(!(SSSR_P(touch->port) & (1 << 2)))
177 /* It's not full. Write the command for Y */
178 SSDR_P(touch->port) = (TSC2046_SAMPLE_Y|(touch->pwrbit_Y))<<16;
182 * Enable the timer. We should get an interrupt, but we want keep a timer
183 * to ensure that we can detect missing data
185 mod_timer(&touch->timer, jiffies + inc);
188 static void
189 ts_timer_callback(unsigned long data)
191 struct touchscreen_data *ts = (struct touchscreen_data *)data;
192 int x, a[TS_SAMPLES], y;
193 static int oldx, oldy;
194 int ssrval;
197 * Check here to see if there is anything in the SPI FIFO. If so,
198 * return it if there has been a change. If not, then we have a
199 * timeout. Generate an erro somehow.
201 ssrval = SSSR_P(ts->port);
203 if(ssrval & (1 << 3)) { /* Look at Rx Not Empty bit */
204 int number_of_entries_in_fifo;
206 /* The FIFO is not emtpy. Good! Now make sure there are at least two
207 * entries. (Should be two exactly.) */
209 number_of_entries_in_fifo = ((ssrval >> 12) & 0xf) + 1;
211 if(number_of_entries_in_fifo < TS_SAMPLES * 2) {
212 /* Not ready yet. Come back later. */
213 unsigned long inc = (poll_sample_time * HZ) / 1000;
214 mod_timer(&ts->timer, jiffies + inc);
215 return;
218 if(number_of_entries_in_fifo == TS_SAMPLES * 2) {
219 int i, j;
221 for(i = 0; i < TS_SAMPLES; i++) {
222 a[i] = SSDR_P(ts->port);
224 /* Sort them (bubble) */
225 for(j = TS_SAMPLES - 1; j > 0; j--) {
226 for(i = 0; i < j; i++) {
227 if(a[i] > a[i + 1]) {
228 int tmp;
229 tmp = a[i+1];
230 a[i+1] = a[i];
231 a[i] = tmp;
236 /* Take the average of the middle two */
237 /* x = (a[TS_SAMPLES/2 - 1] + a[TS_SAMPLES/2] + a[TS_SAMPLES/2+1] + a[TS_SAMPLES/2+2]) >> 2; */
238 x = a[TS_SAMPLES/2];
240 for(i = 0; i < TS_SAMPLES; i++) {
241 a[i] = SSDR_P(ts->port);
243 /* Sort them (bubble) */
244 for(j = TS_SAMPLES - 1; j > 0; j--) {
245 for(i = 0; i < j; i++) {
246 if(a[i] > a[i + 1]) {
247 int tmp;
248 tmp = a[i+1];
249 a[i+1] = a[i];
250 a[i] = tmp;
256 /* Take the average of the middle two */
257 /* y = (a[TS_SAMPLES/2 - 1] + a[TS_SAMPLES/2] + a[TS_SAMPLES/2+1] + a[TS_SAMPLES/2+2]) >> 2; */
258 y = a[TS_SAMPLES/2];
259 } else {
260 /* We have an error! Too many entries. */
261 printk(KERN_ERR "TS: Expected %d entries. Got %d\n", TS_SAMPLES*2, number_of_entries_in_fifo);
262 /* Try to clear the FIFO */
263 while(number_of_entries_in_fifo--) {
264 (void)SSDR_P(ts->port);
266 if( GET_HTCALPINE_GPIO(TOUCHPANEL_IRQ_N) == 0) {
267 start_read(ts);
269 return;
271 } else {
272 /* Not ready yet. Come back later. */
273 unsigned long inc = (poll_sample_time * HZ) / 1000;
274 mod_timer(&ts->timer, jiffies + inc);
275 return;
279 * Now we check to see if the pen is still down. If it is, then call
280 * start_read().
282 if( GET_HTCALPINE_GPIO(TOUCHPANEL_IRQ_N) == 0 ) {
283 /* Still down */
284 if(oldx != x || oldy != y) {
285 oldx = x;
286 oldy = y;
287 report_touchpanel(ts, 1, x, y);
289 start_read(ts);
290 } else {
291 /* Up */
292 report_touchpanel(ts, 0, 0, 0);
293 irqblock = 0;
294 ts->state = STATE_WAIT_FOR_TOUCH;
295 /* Re-enable pen down interrupt */
296 enable_irq(ts->irq);
300 static int
301 ts_probe (struct platform_device *dev)
303 int retval;
304 struct touchscreen_data *ts;
305 struct tsc2046_mach_info *mach = dev->dev.platform_data;
307 printk("htcuniversal: ts_probe\n");
309 ts = ts_data = kmalloc (sizeof (*ts), GFP_KERNEL);
310 if (ts == NULL) {
311 printk( KERN_NOTICE "htcuniversal_ts: unable to allocate memory\n" );
312 return -ENOMEM;
314 memset (ts, 0, sizeof (*ts));
316 ts->input = input_allocate_device();
317 if (ts->input == NULL) {
318 printk( KERN_NOTICE "htcuniversal_ts: unable to allocation touchscreen input\n" );
319 kfree(ts);
320 return -ENOMEM;
322 ts->input->evbit[0] = BIT(EV_ABS);
323 ts->input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
324 ts->input->absmin[ABS_X] = 0;
325 ts->input->absmax[ABS_X] = 32767;
326 ts->input->absmin[ABS_Y] = 0;
327 ts->input->absmax[ABS_Y] = 32767;
328 ts->input->absmin[ABS_PRESSURE] = 0;
329 ts->input->absmax[ABS_PRESSURE] = 1;
331 ts->input->name = "htcuniversal_ts";
332 ts->input->phys = "touchscreen/htcuniversal_ts";
333 ts->input->private = ts;
335 input_register_device(ts->input);
337 ts->timer.function = ts_timer_callback;
338 ts->timer.data = (unsigned long)ts;
339 ts->state = STATE_WAIT_FOR_TOUCH;
340 init_timer (&ts->timer);
342 platform_set_drvdata(dev, ts);
344 ts->port=-1;
346 if (mach) {
347 ts->port = mach->port;
348 ts->clock = mach->clock;
349 ts->pwrbit_X = mach->pwrbit_X;
350 ts->pwrbit_Y = mach->pwrbit_Y;
351 ts->irq = mach->irq;
354 if (ts->port == -1)
356 printk("tsc2046: your device is not supported by this driver\n");
357 return -ENODEV;
360 /* *** Initialize the SSP interface *** */
361 ssp_init(ts->port, ts->clock);
363 while(!(SSSR_P(ts->port) & (1 << 2)))
365 SSDR_P(ts->port) = (TSC2046_SAMPLE_X|(ts->pwrbit_X))<<16;
367 for(retval = 0; retval < 100; retval++) {
368 if(SSSR_P(ts->port) & (1 << 3)) {
369 while(SSSR_P(ts->port) & (1 << 3)) {
370 (void)SSDR_P(ts->port);
372 break;
374 mdelay(1);
377 // if (machine_is_htcuniversal() )
378 // ts->irq = asic3_irq_base( &htcuniversal_asic3.dev ) + ASIC3_GPIOA_IRQ_BASE + GPIOA_TOUCHSCREEN_N;
380 retval = request_irq(ts->irq, pen_isr, SA_INTERRUPT, "tsc2046_ts", ts);
381 if(retval) {
382 printk("Unable to get interrupt\n");
383 input_unregister_device (ts->input);
384 return -ENODEV;
386 set_irq_type(ts->irq, IRQ_TYPE_EDGE_FALLING);
388 return 0;
391 static int
392 ts_remove (struct platform_device *dev)
394 struct touchscreen_data *ts = platform_get_drvdata(dev);
396 input_unregister_device (ts->input);
397 del_timer_sync (&ts->timer);
398 free_irq (ts->irq, ts);
399 pxa_set_cken(ts->clock, 0);
401 kfree(ts);
402 return 0;
405 static int
406 ts_suspend (struct platform_device *dev, pm_message_t state)
408 struct touchscreen_data *ts = platform_get_drvdata(dev);
410 disable_irq(ts->irq);
412 printk("htcuniversal_ts2_suspend: called.\n");
413 return 0;
416 static int
417 ts_resume (struct platform_device *dev)
419 struct touchscreen_data *ts = platform_get_drvdata(dev);
421 ts->state = STATE_WAIT_FOR_TOUCH;
422 ssp_init(ts->port, ts->clock);
423 enable_irq(ts->irq);
425 printk("htcuniversal_ts2_resume: called.\n");
426 return 0;
429 static struct platform_driver ts_driver = {
430 .probe = ts_probe,
431 .remove = ts_remove,
432 .suspend = ts_suspend,
433 .resume = ts_resume,
434 .driver = {
435 .name = "htcuniversal_ts",
440 static int
441 ts_module_init (void)
443 printk(KERN_NOTICE "HTC Universal Touch Screen Driver\n");
445 return platform_driver_register(&ts_driver);
448 static void
449 ts_module_cleanup (void)
451 platform_driver_unregister (&ts_driver);
454 module_init(ts_module_init);
455 module_exit(ts_module_cleanup);
457 MODULE_LICENSE("GPL");
458 MODULE_AUTHOR("Aric Blumer, SDG Systems, LLC");
459 MODULE_DESCRIPTION("HTC Universal Touch Screen Driver");