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>
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>
36 #include <linux/cdev.h>
37 #include <linux/interrupt.h>
38 #include <linux/sched.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>
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
;
70 struct input_dev
*input
;
78 static unsigned long poll_sample_time
= 10; /* Sample every 10 milliseconds */
80 static struct touchscreen_data
*ts_data
;
84 module_param(poll_sample_time
, ulong
, 0644);
85 MODULE_PARM_DESC(poll_sample_time
, "Poll sample time");
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
);
99 pen_isr(int irq
, void *irq_desc
)
101 struct touchscreen_data
*ts
= ts_data
;
103 if(irq
== ts
->irq
/* && !irqblock */) {
107 * Disable the pen interrupt. It's reenabled when the user lifts the
110 disable_irq(ts
->irq
);
112 if (ts
->state
== STATE_WAIT_FOR_TOUCH
) {
113 ts
->state
= STATE_SAMPLING
;
116 /* Shouldn't happen */
117 printk(KERN_ERR
"Unexpected ts interrupt\n");
125 ssp_init(int port
, int clock
)
128 pxa_set_cken(clock
, 1);
130 /* *** Set up the SPI Registers *** */
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) */
141 /* Clear the Status */
142 SSSR_P(port
) = SSSR_P(port
) & 0x00fcfffc;
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) */
155 start_read(struct touchscreen_data
*touch
)
157 unsigned long inc
= (poll_sample_time
* HZ
) / 1000;
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.
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
);
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
;
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
);
224 if(number_of_entries_in_fifo
== TS_SAMPLES
* 2) {
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]) {
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; */
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]) {
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; */
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) {
278 /* Not ready yet. Come back later. */
279 unsigned long inc
= (poll_sample_time
* HZ
) / 1000;
280 mod_timer(&ts
->timer
, jiffies
+ inc
);
285 * Now we check to see if the pen is still down. If it is, then call
288 statusa
= asic3_get_gpio_status_a( &htcuniversal_asic3
.dev
);
290 if( (statusa
& (1<<GPIOA_TOUCHSCREEN_N
)) == 0) {
292 if(oldx
!= x
|| oldy
!= y
) {
295 report_touchpanel(ts
, 1, x
, y
);
300 report_touchpanel(ts
, 0, 0, 0);
302 ts
->state
= STATE_WAIT_FOR_TOUCH
;
303 /* Re-enable pen down interrupt */
309 ts_probe (struct platform_device
*dev
)
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
);
319 printk( KERN_NOTICE
"htcuniversal_ts: unable to allocate memory\n" );
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" );
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
);
355 ts
->port
= mach
->port
;
356 ts
->clock
= mach
->clock
;
357 ts
->pwrbit_X
= mach
->pwrbit_X
;
358 ts
->pwrbit_Y
= mach
->pwrbit_Y
;
367 printk("tsc2046: your device is not supported by this driver\n");
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
);
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
);
393 printk("Unable to get interrupt\n");
394 input_unregister_device (ts
->input
);
397 set_irq_type(ts
->irq
, IRQ_TYPE_EDGE_FALLING
);
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);
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");
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
);
436 printk("htcuniversal_ts2_resume: called.\n");
440 static struct platform_driver ts_driver
= {
443 .suspend
= ts_suspend
,
446 .name
= "htcuniversal_ts",
452 ts_module_init (void)
454 printk(KERN_NOTICE
"HTC Universal Touch Screen Driver\n");
456 return platform_driver_register(&ts_driver
);
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");