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/battery.h>
46 #include <asm/arch/hardware.h>
48 #include <asm/mach/irq.h>
50 #include <asm/semaphore.h>
52 #include <asm/arch/pxa-regs.h>
53 #include <asm/arch/htcbeetles-gpio.h>
54 #include <asm/arch/htcbeetles-asic.h>
56 #include <asm/hardware/ipaq-asic3.h>
57 #include <linux/soc/asic3_base.h>
59 extern struct platform_device htcbeetles_asic3
;
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
;
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 struct work_struct serial_work
;
94 pen_isr(int irq
, void *irq_desc
, struct pt_regs
*regs
)
96 /* struct touchscreen_data *ts = dev_id->data; */
97 struct touchscreen_data
*ts
= ts_data
;
100 if(irq
== HTCBEETLES_IRQ(TOUCHPANEL_IRQ_N
)) {
102 if (ts
->state
== STATE_WAIT_FOR_TOUCH
) {
104 * There is ground bounce or noise or something going on here:
105 * when you write to the SSP port to get the X and Y values, it
106 * causes a TOUCHPANEL_IRQ_N interrupt to occur. So if that
107 * happens, we can check to make sure the pen is actually down and
108 * disregard the interrupt if it's not.
110 if(GET_HTCBEETLES_GPIO(TOUCHPANEL_IRQ_N
) == 0) {
112 * Disable the pen interrupt. It's reenabled when the user lifts the
115 disable_irq(HTCBEETLES_IRQ(TOUCHPANEL_IRQ_N
));
117 ts
->state
= STATE_SAMPLING
;
118 schedule_work(&serial_work
);
121 /* Shouldn't happen */
122 printk(KERN_ERR
"Unexpected ts interrupt\n");
133 pxa_set_cken(CKEN3_SSP2
, 1);
135 /* *** Set up the SPI Registers *** */
137 (1 << 20) /* Extended Data Size Select */
138 | (6 << 8) /* Serial Clock Rate */
139 | (0 << 7) /* Synchronous Serial Enable (Disable for now) */
140 | (0 << 4) /* Motorola SPI Interface */
141 | (7 << 0) /* Data Size Select (24-bit) */
146 /* Clear the Status */
147 SSSR_P2
= SSSR_P2
& 0x00fcfffc;
151 (1 << 20) /* Extended Data Size Select */
152 | (6 << 8) /* Serial Clock Rate */
153 | (1 << 7) /* Synchronous Serial Enable */
154 | (0 << 4) /* Motorola SPI Interface */
155 | (7 << 0) /* Data Size Select (24-bit) */
157 /* enable_irq(HTCBEETLES_IRQ(TOUCHPANEL_IRQ_N)); */
160 DECLARE_MUTEX(serial_mutex
);
165 struct touchscreen_data
*touch
= in
;
166 unsigned long inc
= (poll_sample_time
* HZ
) / 1000;
171 /* Write here to the serial port.
172 * Then we have to wait for poll_sample_time before we read out the serial
173 * port. Then, when we read it out, we check to see if the pen is still
174 * down. If so, then we issue another request here.
177 for(i
= 0; i
< TS_SAMPLES
; i
++) {
178 while(!(SSSR_P2
& (1 << 2)))
180 /* It's not full. Write the command for X */
182 while(!(SSSR_P2
& (1 << 2)))
184 /* It's not full. Write the command for Y */
189 * Enable the timer. We should get an interrupt, but we want keep a timer
190 * to ensure that we can detect missing data
192 mod_timer(&touch
->timer
, jiffies
+ inc
);
196 do_delta_calc(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
)
198 /* This is based on Jamey Hicks' description on IRC. */
199 int dx2_a
, dy2_a
, dx2_b
, dy2_b
;
202 dx2_a
= dx2_a
* dx2_a
; /* If dx2_a was negative, it's not now */
204 dy2_a
= dy2_a
* dy2_a
; /* If dy2_a was negative, it's not now */
207 dx2_b
= dx2_b
* dx2_b
; /* If dx2_b was negative, it's not now */
209 dy2_b
= dy2_b
* dy2_b
; /* If dy2_b was negative, it's not now */
212 /* This was described in the algorithm by Jamey, but it doesn't do much
215 if(dx2_a
+ dy2_a
< dx2_b
+ dy2_b
) return 0;
218 /* dx2_a + dy2_a is the distance squared */
220 ((dx2_a
+ dy2_a
) > 8000)
221 || ((dx2_b
+ dy2_b
) > 8000)
228 if((dx2_b
+ dy2_b
) > 5000) {
236 ts_timer_callback(unsigned long data
)
238 struct touchscreen_data
*ts
= (struct touchscreen_data
*)data
;
243 * Check here to see if there is anything in the SPI FIFO. If so,
244 * return it if there has been a change. If not, then we have a
245 * timeout. Generate an erro somehow.
248 if(ssrval
& (1 << 3)) { /* Look at Rx Not Empty bit */
249 int number_of_entries_in_fifo
;
251 /* The FIFO is not emtpy. Good! Now make sure there are at least two
254 number_of_entries_in_fifo
= ((ssrval
>> 12) & 0xf) + 1;
256 if(number_of_entries_in_fifo
< (TS_SAMPLES
* 2)) {
257 /* Not ready yet. Come back later. */
258 unsigned long inc
= (poll_sample_time
* HZ
) / 1000;
259 mod_timer(&ts
->timer
, jiffies
+ inc
);
263 if(number_of_entries_in_fifo
== TS_SAMPLES
* 2) {
265 int X
[TS_SAMPLES
], Y
[TS_SAMPLES
];
267 for(i
= 0; i
< TS_SAMPLES
; i
++) {
278 if(do_delta_calc(X
[0], Y
[0], X
[1], Y
[1], X
[2], Y
[2])) {
281 if(do_delta_calc(X
[1], Y
[1], X
[2], Y
[2], X
[3], Y
[3])) {
284 if(do_delta_calc(X
[2], Y
[2], X
[3], Y
[3], X
[4], Y
[4])) {
289 /* Take average of point 0 and point 3 */
290 X
[2] = (X
[1] + X
[3]) / 2;
291 Y
[2] = (Y
[1] + Y
[3]) / 2;
295 /* Just ignore this one */
300 /* keep this sample */
301 x
= (X
[1] + (2 * X
[2]) + X
[3]) / 4;
302 y
= (Y
[1] + (2 * Y
[2]) + Y
[3]) / 4;
306 X
[1] = (X
[0] + X
[2]) / 2;
307 Y
[1] = (Y
[0] + Y
[2]) / 2;
312 x
= (X
[0] + (4 * X
[1]) + (6 * X
[2]) + (4 * X
[3]) + X
[4]) >> 4;
313 y
= (Y
[0] + (4 * Y
[1]) + (6 * Y
[2]) + (4 * Y
[3]) + Y
[4]) >> 4;
318 if(GET_HTCBEETLES_GPIO(TOUCHPANEL_IRQ_N
) == 0) {
321 report_touchpanel(ts
, 1, x
, y
);
326 report_touchpanel(ts
, 0, 0, 0);
327 ts
->state
= STATE_WAIT_FOR_TOUCH
;
328 /* Re-enable pen down interrupt */
329 enable_irq(HTCBEETLES_IRQ(TOUCHPANEL_IRQ_N
));
333 /* We have an error! Too many entries. */
334 printk(KERN_ERR
"TS: Expected %d entries. Got %d\n", 2, number_of_entries_in_fifo
);
335 /* Try to clear the FIFO */
336 while(number_of_entries_in_fifo
--) {
340 if(GET_HTCBEETLES_GPIO(TOUCHPANEL_IRQ_N
) == 0) {
346 /* Not ready yet. Come back later. */
347 unsigned long inc
= (poll_sample_time
* HZ
) / 1000;
348 mod_timer(&ts
->timer
, jiffies
+ inc
);
354 ts_probe (struct device
*dev
)
357 struct touchscreen_data
*ts
;
359 ts
= ts_data
= kmalloc (sizeof (*ts
), GFP_KERNEL
);
361 printk( KERN_NOTICE
"htcbeetles_ts: unable to allocate memory\n" );
364 memset (ts
, 0, sizeof (*ts
));
367 /* *** Set up the input subsystem stuff *** */
368 // memset(ts->input, 0, sizeof(struct input_dev));
369 ts
->input
= input_allocate_device();
370 if (ts
->input
== NULL
) {
371 printk( KERN_NOTICE
"htcbeetles_ts: unable to allocation touchscreen input\n" );
375 ts
->input
->evbit
[0] = BIT(EV_ABS
);
376 ts
->input
->absbit
[0] = BIT(ABS_X
) | BIT(ABS_Y
) | BIT(ABS_PRESSURE
);
377 ts
->input
->absmin
[ABS_X
] = 0;
378 ts
->input
->absmax
[ABS_X
] = 32767;
379 ts
->input
->absmin
[ABS_Y
] = 0;
380 ts
->input
->absmax
[ABS_Y
] = 32767;
381 ts
->input
->absmin
[ABS_PRESSURE
] = 0;
382 ts
->input
->absmax
[ABS_PRESSURE
] = 1;
384 ts
->input
->name
= "htcbeetles_ts";
385 ts
->input
->private = ts
;
387 input_register_device(ts
->input
);
389 ts
->timer
.function
= ts_timer_callback
;
390 ts
->timer
.data
= (unsigned long)ts
;
391 ts
->state
= STATE_WAIT_FOR_TOUCH
;
392 init_timer (&ts
->timer
);
394 INIT_WORK(&serial_work
, start_read
, ts
);
396 dev_set_drvdata(dev
, ts
);
398 /* *** Initialize the SSP interface *** */
402 /* Make sure the device is in such a state that it can give pen
404 while(!(SSSR_P2
& (1 << 2)))
408 for(retval
= 0; retval
< 100; retval
++) {
409 if(SSSR_P2
& (1 << 3)) {
410 while(SSSR_P2
& (1 << 3)) {
420 ts
->irq
= HTCBEETLES_IRQ( TOUCHPANEL_IRQ_N
);
421 retval
= request_irq(ts
->irq
, pen_isr
, SA_INTERRUPT
, "htcbeetles_ts", ts
);
423 printk("Unable to get interrupt\n");
424 input_unregister_device (ts
->input
);
427 set_irq_type(ts
->irq
, IRQT_FALLING
);
433 ts_remove (struct device
*dev
)
435 struct touchscreen_data
*ts
= dev_get_drvdata(dev
);
437 input_unregister_device (ts
->input
);
438 del_timer_sync (&ts
->timer
);
439 free_irq (ts
->irq
, ts
);
442 pxa_set_cken(CKEN3_SSP2
, 0);
447 ts_suspend (struct device
*dev
, pm_message_t state
)
449 disable_irq(HTCBEETLES_IRQ(TOUCHPANEL_IRQ_N
));
454 ts_resume (struct device
*dev
)
456 struct touchscreen_data
*ts
= dev_get_drvdata(dev
);
458 ts
->state
= STATE_WAIT_FOR_TOUCH
;
460 enable_irq(HTCBEETLES_IRQ(TOUCHPANEL_IRQ_N
));
465 static struct device_driver ts_driver
= {
466 .name
= "htcbeetles-ts",
467 .bus
= &platform_bus_type
,
470 .suspend
= ts_suspend
,
474 static int tssim_init(void);
477 ts_module_init (void)
479 printk(KERN_NOTICE
"htcbeetles Touch Screen Driver\n");
481 printk(KERN_NOTICE
" TS Simulator Not Installed\n");
483 printk(KERN_NOTICE
" TS Simulator Installed\n");
485 return driver_register(&ts_driver
);
488 static void tssim_exit(void);
491 ts_module_cleanup (void)
494 driver_unregister (&ts_driver
);
497 /************* Code for Touch Screen Simulation for FBVNC Server **********/
499 static struct cdev
*cdev
;
501 static long a0
= -1122, a2
= 33588528, a4
= 1452, a5
= -2970720, a6
= 65536;
503 /* The input into the input subsystem is prior to correction from calibration.
504 * So we have to undo the effects of the calibration. It's actually a
505 * complicated equation where the calibrated value of X depends on the
506 * uncalibrated values of X and Y. Fortunately, at least on the hx4700, the
507 * multiplier for the Y value is zero, so I assume that here. It is a shame
508 * that the tslib does not allow multiple inputs. Then we could do another
509 * driver for this (as it was originally) that give input that does not
510 * require calibration.
513 tssim_ioctl(struct inode
*inode
, struct file
*fp
, unsigned int ioctlnum
, unsigned long parm
)
516 case 0: a0
= parm
; break;
518 case 2: a2
= parm
; break;
520 case 4: a4
= parm
; break;
521 case 5: a5
= parm
; break;
524 printk(KERN_DEBUG
"a0 = %ld, a2 = %ld, a4 = %ld, a5 = %ld, a6 = %ld\n",
527 default: return -ENOTTY
;
533 tssim_open(struct inode
*inode
, struct file
*fp
)
535 /* Nothing to do here */
540 tssim_write(struct file
*fp
, const char __user
*data
, size_t bytes
, loff_t
*offset
)
542 unsigned long pressure
;
546 x
= data
[0] | (data
[1] << 8) | (data
[2] << 16) | (data
[3] << 24); data
+= 4;
547 y
= data
[0] | (data
[1] << 8) | (data
[2] << 16) | (data
[3] << 24); data
+= 4;
548 pressure
= data
[0] | (data
[1] << 8) | (data
[2] << 16) | (data
[3] << 24); data
+= 4;
550 input_report_abs(ts_data
->input
, ABS_PRESSURE
, pressure
?1:0);
551 input_report_abs(ts_data
->input
, ABS_X
, ((x
* a6
) - a2
)/a0
);
552 input_report_abs(ts_data
->input
, ABS_Y
, ((y
* a6
) - a5
)/a4
);
553 input_sync(ts_data
->input
);
558 int tssim_close(struct inode
*inode
, struct file
*fp
)
563 struct file_operations fops
= {
565 .write
= tssim_write
,
567 .release
= tssim_close
,
568 .ioctl
= tssim_ioctl
,
571 static int battery_class
;
573 static int get_min_voltage(struct battery
*b
)
577 static int get_max_voltage(struct battery
*b
)
579 return 1400; /* mV */
581 static int get_max_charge(struct battery
*b
)
585 static int get_voltage(struct battery
*b
)
587 static int battery_sample
;
589 if(!down_interruptible(&serial_mutex
)) {
593 while(!(SSSR_P2
& (1 << 2)))
596 while(!(SSSR_P2
& (1 << 2)))
599 while(!(SSSR_P2
& (1 << 2)))
601 SSDR_P2
= 0xd30000; /* Dummy command to allow pen interrupts again */
603 for(i
= 0; i
< 10; i
++) {
605 if(ssrval
& (1 << 3)) { /* Look at Rx Not Empty bit */
606 int number_of_entries_in_fifo
;
608 number_of_entries_in_fifo
= ((ssrval
>> 12) & 0xf) + 1;
609 if(number_of_entries_in_fifo
== 3) {
618 battery_sample
= SSDR_P2
& 0xfff;
621 /* Make sure the FIFO is empty */
622 while(SSSR_P2
& (1 << 3)) {
630 return battery_sample
;
632 static int get_charge(struct battery
*b
)
636 static int get_status(struct battery
*b
)
641 static struct battery htcbeetles_power
= {
642 .name
= "htcbeetles_backup",
644 .get_min_voltage
= get_min_voltage
,
645 .get_min_current
= 0,
647 .get_max_voltage
= get_max_voltage
,
648 .get_max_current
= 0,
649 .get_max_charge
= get_max_charge
,
651 .get_voltage
= get_voltage
,
653 .get_charge
= get_charge
,
654 .get_status
= get_status
,
658 battery_class_uevent(struct class_device
*dev
, char **envp
, int num_envp
,
659 char *buffer
, int buffer_size
)
665 battery_class_release(struct class_device
*dev
)
670 battery_class_class_release(struct class *class)
679 retval
= alloc_chrdev_region(&dev
, 0, 1, "tssim");
681 printk(KERN_ERR
"TSSIM Unable to allocate device numbers\n");
686 cdev
->owner
= THIS_MODULE
;
688 retval
= cdev_add(cdev
, dev
, 1);
690 printk(KERN_ERR
"Unable to add cdev\n");
691 unregister_chrdev_region(dev
, 1);
696 if(battery_class_register(&htcbeetles_power
)) {
697 printk(KERN_ERR
"htcbeetles_ts: Could not register battery class\n");
700 htcbeetles_power
.class_dev
.class->uevent
= battery_class_uevent
;
701 htcbeetles_power
.class_dev
.class->release
= battery_class_release
;
702 htcbeetles_power
.class_dev
.class->class_release
= battery_class_class_release
;
712 unregister_chrdev_region(dev
, 1);
714 battery_class_unregister(&htcbeetles_power
);
719 module_init(ts_module_init
);
720 module_exit(ts_module_cleanup
);
722 MODULE_LICENSE("GPL");
723 MODULE_AUTHOR("Aric Blumer, SDG Systems, LLC");
724 MODULE_DESCRIPTION("htcbeetles Touch Screen Driver");