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>
33 #include <linux/config.h>
35 #include <linux/init.h>
37 #include <linux/cdev.h>
38 #include <linux/interrupt.h>
39 #include <linux/sched.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>
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
;
65 struct input_dev
*input
;
73 static unsigned long poll_sample_time
= 10; /* Sample every 10 milliseconds */
75 static struct touchscreen_data
*ts_data
;
79 module_param(poll_sample_time
, ulong
, 0644);
80 MODULE_PARM_DESC(poll_sample_time
, "Poll sample time");
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
);
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 */) {
102 * Disable the pen interrupt. It's reenabled when the user lifts the
105 disable_irq(ts
->irq
);
107 if (ts
->state
== STATE_WAIT_FOR_TOUCH
) {
108 ts
->state
= STATE_SAMPLING
;
111 /* Shouldn't happen */
112 printk(KERN_ERR
"Unexpected ts interrupt\n");
120 ssp_init(int port
, int clock
)
123 pxa_set_cken(clock
, 1);
125 /* *** Set up the SPI Registers *** */
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) */
136 /* Clear the Status */
137 SSSR_P(port
) = SSSR_P(port
) & 0x00fcfffc;
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) */
150 start_read(struct touchscreen_data
*touch
)
152 unsigned long inc
= (poll_sample_time
* HZ
) / 1000;
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.
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
);
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
;
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
);
218 if(number_of_entries_in_fifo
== TS_SAMPLES
* 2) {
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]) {
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; */
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]) {
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; */
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) {
272 /* Not ready yet. Come back later. */
273 unsigned long inc
= (poll_sample_time
* HZ
) / 1000;
274 mod_timer(&ts
->timer
, jiffies
+ inc
);
279 * Now we check to see if the pen is still down. If it is, then call
282 if( GET_HTCALPINE_GPIO(TOUCHPANEL_IRQ_N
) == 0 ) {
284 if(oldx
!= x
|| oldy
!= y
) {
287 report_touchpanel(ts
, 1, x
, y
);
292 report_touchpanel(ts
, 0, 0, 0);
294 ts
->state
= STATE_WAIT_FOR_TOUCH
;
295 /* Re-enable pen down interrupt */
301 ts_probe (struct platform_device
*dev
)
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
);
311 printk( KERN_NOTICE
"htcuniversal_ts: unable to allocate memory\n" );
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" );
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
);
347 ts
->port
= mach
->port
;
348 ts
->clock
= mach
->clock
;
349 ts
->pwrbit_X
= mach
->pwrbit_X
;
350 ts
->pwrbit_Y
= mach
->pwrbit_Y
;
356 printk("tsc2046: your device is not supported by this driver\n");
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
);
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
);
382 printk("Unable to get interrupt\n");
383 input_unregister_device (ts
->input
);
386 set_irq_type(ts
->irq
, IRQ_TYPE_EDGE_FALLING
);
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);
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");
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
);
425 printk("htcuniversal_ts2_resume: called.\n");
429 static struct platform_driver ts_driver
= {
432 .suspend
= ts_suspend
,
435 .name
= "htcuniversal_ts",
441 ts_module_init (void)
443 printk(KERN_NOTICE
"HTC Universal Touch Screen Driver\n");
445 return platform_driver_register(&ts_driver
);
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");