xref: /linux/drivers/input/touchscreen/hp680_ts_input.c (revision 7639a4541f7e7abb1295ff8ab39cc2f5842239ae)
11da177e4SLinus Torvalds #include <linux/input.h>
21da177e4SLinus Torvalds #include <linux/module.h>
31da177e4SLinus Torvalds #include <linux/init.h>
41da177e4SLinus Torvalds #include <linux/interrupt.h>
51da177e4SLinus Torvalds #include <asm/io.h>
61da177e4SLinus Torvalds #include <asm/delay.h>
71da177e4SLinus Torvalds #include <asm/adc.h>
8*7639a454SPaul Mundt #include <mach/hp6xx.h>
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #define MODNAME "hp680_ts_input"
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #define HP680_TS_ABS_X_MIN	40
131da177e4SLinus Torvalds #define HP680_TS_ABS_X_MAX	950
141da177e4SLinus Torvalds #define HP680_TS_ABS_Y_MIN	80
151da177e4SLinus Torvalds #define HP680_TS_ABS_Y_MAX	910
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds #define	PHDR	0xa400012e
181da177e4SLinus Torvalds #define SCPDR	0xa4000136
191da177e4SLinus Torvalds 
20049fa57cSKristoffer Ericson static void do_softint(struct work_struct *work);
211da177e4SLinus Torvalds 
22eca1ed19SDmitry Torokhov static struct input_dev *hp680_ts_dev;
23049fa57cSKristoffer Ericson static DECLARE_DELAYED_WORK(work, do_softint);
241da177e4SLinus Torvalds 
25049fa57cSKristoffer Ericson static void do_softint(struct work_struct *work)
261da177e4SLinus Torvalds {
271da177e4SLinus Torvalds 	int absx = 0, absy = 0;
281da177e4SLinus Torvalds 	u8 scpdr;
291da177e4SLinus Torvalds 	int touched = 0;
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds 	if (ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN) {
321da177e4SLinus Torvalds 		scpdr = ctrl_inb(SCPDR);
331da177e4SLinus Torvalds 		scpdr |= SCPDR_TS_SCAN_ENABLE;
341da177e4SLinus Torvalds 		scpdr &= ~SCPDR_TS_SCAN_Y;
351da177e4SLinus Torvalds 		ctrl_outb(scpdr, SCPDR);
361da177e4SLinus Torvalds 		udelay(30);
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 		absy = adc_single(ADC_CHANNEL_TS_Y);
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds 		scpdr = ctrl_inb(SCPDR);
411da177e4SLinus Torvalds 		scpdr |= SCPDR_TS_SCAN_Y;
421da177e4SLinus Torvalds 		scpdr &= ~SCPDR_TS_SCAN_X;
431da177e4SLinus Torvalds 		ctrl_outb(scpdr, SCPDR);
441da177e4SLinus Torvalds 		udelay(30);
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds 		absx = adc_single(ADC_CHANNEL_TS_X);
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 		scpdr = ctrl_inb(SCPDR);
491da177e4SLinus Torvalds 		scpdr |= SCPDR_TS_SCAN_X;
501da177e4SLinus Torvalds 		scpdr &= ~SCPDR_TS_SCAN_ENABLE;
511da177e4SLinus Torvalds 		ctrl_outb(scpdr, SCPDR);
521da177e4SLinus Torvalds 		udelay(100);
531da177e4SLinus Torvalds 		touched = ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN;
541da177e4SLinus Torvalds 	}
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds 	if (touched) {
57eca1ed19SDmitry Torokhov 		input_report_key(hp680_ts_dev, BTN_TOUCH, 1);
58eca1ed19SDmitry Torokhov 		input_report_abs(hp680_ts_dev, ABS_X, absx);
59eca1ed19SDmitry Torokhov 		input_report_abs(hp680_ts_dev, ABS_Y, absy);
601da177e4SLinus Torvalds 	} else {
61eca1ed19SDmitry Torokhov 		input_report_key(hp680_ts_dev, BTN_TOUCH, 0);
621da177e4SLinus Torvalds 	}
631da177e4SLinus Torvalds 
64eca1ed19SDmitry Torokhov 	input_sync(hp680_ts_dev);
651da177e4SLinus Torvalds 	enable_irq(HP680_TS_IRQ);
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
687d12e780SDavid Howells static irqreturn_t hp680_ts_interrupt(int irq, void *dev)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	disable_irq_nosync(irq);
711da177e4SLinus Torvalds 	schedule_delayed_work(&work, HZ / 20);
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	return IRQ_HANDLED;
741da177e4SLinus Torvalds }
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds static int __init hp680_ts_init(void)
771da177e4SLinus Torvalds {
7852c1f570SDmitry Torokhov 	int err;
7952c1f570SDmitry Torokhov 
80eca1ed19SDmitry Torokhov 	hp680_ts_dev = input_allocate_device();
81eca1ed19SDmitry Torokhov 	if (!hp680_ts_dev)
82eca1ed19SDmitry Torokhov 		return -ENOMEM;
831da177e4SLinus Torvalds 
847b19ada2SJiri Slaby 	hp680_ts_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
857b19ada2SJiri Slaby 	hp680_ts_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
861da177e4SLinus Torvalds 
8752c1f570SDmitry Torokhov 	input_set_abs_params(hp680_ts_dev, ABS_X,
8852c1f570SDmitry Torokhov 		HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0);
8952c1f570SDmitry Torokhov 	input_set_abs_params(hp680_ts_dev, ABS_Y,
9052c1f570SDmitry Torokhov 		HP680_TS_ABS_Y_MIN, HP680_TS_ABS_Y_MAX, 0, 0);
911da177e4SLinus Torvalds 
92eca1ed19SDmitry Torokhov 	hp680_ts_dev->name = "HP Jornada touchscreen";
93eca1ed19SDmitry Torokhov 	hp680_ts_dev->phys = "hp680_ts/input0";
941da177e4SLinus Torvalds 
95eca1ed19SDmitry Torokhov 	if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
96dace1453SThomas Gleixner 			IRQF_DISABLED, MODNAME, 0) < 0) {
971da177e4SLinus Torvalds 		printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
981da177e4SLinus Torvalds 		       HP680_TS_IRQ);
9952c1f570SDmitry Torokhov 		err = -EBUSY;
10052c1f570SDmitry Torokhov 		goto fail1;
1011da177e4SLinus Torvalds 	}
1021da177e4SLinus Torvalds 
10352c1f570SDmitry Torokhov 	err = input_register_device(hp680_ts_dev);
10452c1f570SDmitry Torokhov 	if (err)
10552c1f570SDmitry Torokhov 		goto fail2;
10652c1f570SDmitry Torokhov 
1071da177e4SLinus Torvalds 	return 0;
10852c1f570SDmitry Torokhov 
10952c1f570SDmitry Torokhov  fail2:	free_irq(HP680_TS_IRQ, NULL);
11052c1f570SDmitry Torokhov 	cancel_delayed_work(&work);
11152c1f570SDmitry Torokhov 	flush_scheduled_work();
11252c1f570SDmitry Torokhov  fail1:	input_free_device(hp680_ts_dev);
11352c1f570SDmitry Torokhov 	return err;
1141da177e4SLinus Torvalds }
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds static void __exit hp680_ts_exit(void)
1171da177e4SLinus Torvalds {
11852c1f570SDmitry Torokhov 	free_irq(HP680_TS_IRQ, NULL);
1191da177e4SLinus Torvalds 	cancel_delayed_work(&work);
1201da177e4SLinus Torvalds 	flush_scheduled_work();
121eca1ed19SDmitry Torokhov 	input_unregister_device(hp680_ts_dev);
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds module_init(hp680_ts_init);
1251da177e4SLinus Torvalds module_exit(hp680_ts_exit);
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
1281da177e4SLinus Torvalds MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver");
1291da177e4SLinus Torvalds MODULE_LICENSE("GPL");
130