1*09c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds #include <linux/input.h>
31da177e4SLinus Torvalds #include <linux/module.h>
41da177e4SLinus Torvalds #include <linux/init.h>
51da177e4SLinus Torvalds #include <linux/interrupt.h>
61da177e4SLinus Torvalds #include <asm/io.h>
71da177e4SLinus Torvalds #include <asm/delay.h>
81da177e4SLinus Torvalds #include <asm/adc.h>
97639a454SPaul Mundt #include <mach/hp6xx.h>
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #define MODNAME "hp680_ts_input"
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds #define HP680_TS_ABS_X_MIN 40
141da177e4SLinus Torvalds #define HP680_TS_ABS_X_MAX 950
151da177e4SLinus Torvalds #define HP680_TS_ABS_Y_MIN 80
161da177e4SLinus Torvalds #define HP680_TS_ABS_Y_MAX 910
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds #define PHDR 0xa400012e
191da177e4SLinus Torvalds #define SCPDR 0xa4000136
201da177e4SLinus Torvalds
21049fa57cSKristoffer Ericson static void do_softint(struct work_struct *work);
221da177e4SLinus Torvalds
23eca1ed19SDmitry Torokhov static struct input_dev *hp680_ts_dev;
24049fa57cSKristoffer Ericson static DECLARE_DELAYED_WORK(work, do_softint);
251da177e4SLinus Torvalds
do_softint(struct work_struct * work)26049fa57cSKristoffer Ericson static void do_softint(struct work_struct *work)
271da177e4SLinus Torvalds {
281da177e4SLinus Torvalds int absx = 0, absy = 0;
291da177e4SLinus Torvalds u8 scpdr;
301da177e4SLinus Torvalds int touched = 0;
311da177e4SLinus Torvalds
32e28abafbSPaul Mundt if (__raw_readb(PHDR) & PHDR_TS_PEN_DOWN) {
33e28abafbSPaul Mundt scpdr = __raw_readb(SCPDR);
341da177e4SLinus Torvalds scpdr |= SCPDR_TS_SCAN_ENABLE;
351da177e4SLinus Torvalds scpdr &= ~SCPDR_TS_SCAN_Y;
36e28abafbSPaul Mundt __raw_writeb(scpdr, SCPDR);
371da177e4SLinus Torvalds udelay(30);
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds absy = adc_single(ADC_CHANNEL_TS_Y);
401da177e4SLinus Torvalds
41e28abafbSPaul Mundt scpdr = __raw_readb(SCPDR);
421da177e4SLinus Torvalds scpdr |= SCPDR_TS_SCAN_Y;
431da177e4SLinus Torvalds scpdr &= ~SCPDR_TS_SCAN_X;
44e28abafbSPaul Mundt __raw_writeb(scpdr, SCPDR);
451da177e4SLinus Torvalds udelay(30);
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds absx = adc_single(ADC_CHANNEL_TS_X);
481da177e4SLinus Torvalds
49e28abafbSPaul Mundt scpdr = __raw_readb(SCPDR);
501da177e4SLinus Torvalds scpdr |= SCPDR_TS_SCAN_X;
511da177e4SLinus Torvalds scpdr &= ~SCPDR_TS_SCAN_ENABLE;
52e28abafbSPaul Mundt __raw_writeb(scpdr, SCPDR);
531da177e4SLinus Torvalds udelay(100);
54e28abafbSPaul Mundt touched = __raw_readb(PHDR) & PHDR_TS_PEN_DOWN;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds if (touched) {
58eca1ed19SDmitry Torokhov input_report_key(hp680_ts_dev, BTN_TOUCH, 1);
59eca1ed19SDmitry Torokhov input_report_abs(hp680_ts_dev, ABS_X, absx);
60eca1ed19SDmitry Torokhov input_report_abs(hp680_ts_dev, ABS_Y, absy);
611da177e4SLinus Torvalds } else {
62eca1ed19SDmitry Torokhov input_report_key(hp680_ts_dev, BTN_TOUCH, 0);
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds
65eca1ed19SDmitry Torokhov input_sync(hp680_ts_dev);
661da177e4SLinus Torvalds enable_irq(HP680_TS_IRQ);
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds
hp680_ts_interrupt(int irq,void * dev)697d12e780SDavid Howells static irqreturn_t hp680_ts_interrupt(int irq, void *dev)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds disable_irq_nosync(irq);
721da177e4SLinus Torvalds schedule_delayed_work(&work, HZ / 20);
731da177e4SLinus Torvalds
741da177e4SLinus Torvalds return IRQ_HANDLED;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds
hp680_ts_init(void)771da177e4SLinus Torvalds static int __init hp680_ts_init(void)
781da177e4SLinus Torvalds {
7952c1f570SDmitry Torokhov int err;
8052c1f570SDmitry Torokhov
81eca1ed19SDmitry Torokhov hp680_ts_dev = input_allocate_device();
82eca1ed19SDmitry Torokhov if (!hp680_ts_dev)
83eca1ed19SDmitry Torokhov return -ENOMEM;
841da177e4SLinus Torvalds
857b19ada2SJiri Slaby hp680_ts_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
867b19ada2SJiri Slaby hp680_ts_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
871da177e4SLinus Torvalds
8852c1f570SDmitry Torokhov input_set_abs_params(hp680_ts_dev, ABS_X,
8952c1f570SDmitry Torokhov HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0);
9052c1f570SDmitry Torokhov input_set_abs_params(hp680_ts_dev, ABS_Y,
9152c1f570SDmitry Torokhov HP680_TS_ABS_Y_MIN, HP680_TS_ABS_Y_MAX, 0, 0);
921da177e4SLinus Torvalds
93eca1ed19SDmitry Torokhov hp680_ts_dev->name = "HP Jornada touchscreen";
94eca1ed19SDmitry Torokhov hp680_ts_dev->phys = "hp680_ts/input0";
951da177e4SLinus Torvalds
96eca1ed19SDmitry Torokhov if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
97b51425beSJulia Lawall 0, MODNAME, NULL) < 0) {
981da177e4SLinus Torvalds printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
991da177e4SLinus Torvalds HP680_TS_IRQ);
10052c1f570SDmitry Torokhov err = -EBUSY;
10152c1f570SDmitry Torokhov goto fail1;
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds
10452c1f570SDmitry Torokhov err = input_register_device(hp680_ts_dev);
10552c1f570SDmitry Torokhov if (err)
10652c1f570SDmitry Torokhov goto fail2;
10752c1f570SDmitry Torokhov
1081da177e4SLinus Torvalds return 0;
10952c1f570SDmitry Torokhov
11052c1f570SDmitry Torokhov fail2: free_irq(HP680_TS_IRQ, NULL);
111790d5c8dSTejun Heo cancel_delayed_work_sync(&work);
11252c1f570SDmitry Torokhov fail1: input_free_device(hp680_ts_dev);
11352c1f570SDmitry Torokhov return err;
1141da177e4SLinus Torvalds }
1151da177e4SLinus Torvalds
hp680_ts_exit(void)1161da177e4SLinus Torvalds static void __exit hp680_ts_exit(void)
1171da177e4SLinus Torvalds {
11852c1f570SDmitry Torokhov free_irq(HP680_TS_IRQ, NULL);
119790d5c8dSTejun Heo cancel_delayed_work_sync(&work);
120eca1ed19SDmitry Torokhov input_unregister_device(hp680_ts_dev);
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds
1231da177e4SLinus Torvalds module_init(hp680_ts_init);
1241da177e4SLinus Torvalds module_exit(hp680_ts_exit);
1251da177e4SLinus Torvalds
1261da177e4SLinus Torvalds MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
1271da177e4SLinus Torvalds MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver");
1281da177e4SLinus Torvalds MODULE_LICENSE("GPL");
129