Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | #include <linux/input.h> |
2 | #include <linux/module.h> | |
3 | #include <linux/init.h> | |
1da177e4 LT |
4 | #include <linux/interrupt.h> |
5 | #include <asm/io.h> | |
6 | #include <asm/delay.h> | |
7 | #include <asm/adc.h> | |
7639a454 | 8 | #include <mach/hp6xx.h> |
1da177e4 LT |
9 | |
10 | #define MODNAME "hp680_ts_input" | |
11 | ||
12 | #define HP680_TS_ABS_X_MIN 40 | |
13 | #define HP680_TS_ABS_X_MAX 950 | |
14 | #define HP680_TS_ABS_Y_MIN 80 | |
15 | #define HP680_TS_ABS_Y_MAX 910 | |
16 | ||
1da177e4 LT |
17 | #define PHDR 0xa400012e |
18 | #define SCPDR 0xa4000136 | |
19 | ||
049fa57c | 20 | static void do_softint(struct work_struct *work); |
1da177e4 | 21 | |
eca1ed19 | 22 | static struct input_dev *hp680_ts_dev; |
049fa57c | 23 | static DECLARE_DELAYED_WORK(work, do_softint); |
1da177e4 | 24 | |
049fa57c | 25 | static void do_softint(struct work_struct *work) |
1da177e4 LT |
26 | { |
27 | int absx = 0, absy = 0; | |
28 | u8 scpdr; | |
29 | int touched = 0; | |
30 | ||
e28abafb PM |
31 | if (__raw_readb(PHDR) & PHDR_TS_PEN_DOWN) { |
32 | scpdr = __raw_readb(SCPDR); | |
1da177e4 LT |
33 | scpdr |= SCPDR_TS_SCAN_ENABLE; |
34 | scpdr &= ~SCPDR_TS_SCAN_Y; | |
e28abafb | 35 | __raw_writeb(scpdr, SCPDR); |
1da177e4 LT |
36 | udelay(30); |
37 | ||
38 | absy = adc_single(ADC_CHANNEL_TS_Y); | |
39 | ||
e28abafb | 40 | scpdr = __raw_readb(SCPDR); |
1da177e4 LT |
41 | scpdr |= SCPDR_TS_SCAN_Y; |
42 | scpdr &= ~SCPDR_TS_SCAN_X; | |
e28abafb | 43 | __raw_writeb(scpdr, SCPDR); |
1da177e4 LT |
44 | udelay(30); |
45 | ||
46 | absx = adc_single(ADC_CHANNEL_TS_X); | |
47 | ||
e28abafb | 48 | scpdr = __raw_readb(SCPDR); |
1da177e4 LT |
49 | scpdr |= SCPDR_TS_SCAN_X; |
50 | scpdr &= ~SCPDR_TS_SCAN_ENABLE; | |
e28abafb | 51 | __raw_writeb(scpdr, SCPDR); |
1da177e4 | 52 | udelay(100); |
e28abafb | 53 | touched = __raw_readb(PHDR) & PHDR_TS_PEN_DOWN; |
1da177e4 LT |
54 | } |
55 | ||
56 | if (touched) { | |
eca1ed19 DT |
57 | input_report_key(hp680_ts_dev, BTN_TOUCH, 1); |
58 | input_report_abs(hp680_ts_dev, ABS_X, absx); | |
59 | input_report_abs(hp680_ts_dev, ABS_Y, absy); | |
1da177e4 | 60 | } else { |
eca1ed19 | 61 | input_report_key(hp680_ts_dev, BTN_TOUCH, 0); |
1da177e4 LT |
62 | } |
63 | ||
eca1ed19 | 64 | input_sync(hp680_ts_dev); |
1da177e4 LT |
65 | enable_irq(HP680_TS_IRQ); |
66 | } | |
67 | ||
7d12e780 | 68 | static irqreturn_t hp680_ts_interrupt(int irq, void *dev) |
1da177e4 LT |
69 | { |
70 | disable_irq_nosync(irq); | |
71 | schedule_delayed_work(&work, HZ / 20); | |
72 | ||
73 | return IRQ_HANDLED; | |
74 | } | |
75 | ||
76 | static int __init hp680_ts_init(void) | |
77 | { | |
52c1f570 DT |
78 | int err; |
79 | ||
eca1ed19 DT |
80 | hp680_ts_dev = input_allocate_device(); |
81 | if (!hp680_ts_dev) | |
82 | return -ENOMEM; | |
1da177e4 | 83 | |
7b19ada2 JS |
84 | hp680_ts_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); |
85 | hp680_ts_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | |
1da177e4 | 86 | |
52c1f570 DT |
87 | input_set_abs_params(hp680_ts_dev, ABS_X, |
88 | HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0); | |
89 | input_set_abs_params(hp680_ts_dev, ABS_Y, | |
90 | HP680_TS_ABS_Y_MIN, HP680_TS_ABS_Y_MAX, 0, 0); | |
1da177e4 | 91 | |
eca1ed19 DT |
92 | hp680_ts_dev->name = "HP Jornada touchscreen"; |
93 | hp680_ts_dev->phys = "hp680_ts/input0"; | |
1da177e4 | 94 | |
eca1ed19 | 95 | if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt, |
b51425be | 96 | 0, MODNAME, NULL) < 0) { |
eca1ed19 | 97 | printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n", |
1da177e4 | 98 | HP680_TS_IRQ); |
52c1f570 DT |
99 | err = -EBUSY; |
100 | goto fail1; | |
1da177e4 LT |
101 | } |
102 | ||
52c1f570 DT |
103 | err = input_register_device(hp680_ts_dev); |
104 | if (err) | |
105 | goto fail2; | |
106 | ||
1da177e4 | 107 | return 0; |
52c1f570 DT |
108 | |
109 | fail2: free_irq(HP680_TS_IRQ, NULL); | |
790d5c8d | 110 | cancel_delayed_work_sync(&work); |
52c1f570 DT |
111 | fail1: input_free_device(hp680_ts_dev); |
112 | return err; | |
1da177e4 LT |
113 | } |
114 | ||
115 | static void __exit hp680_ts_exit(void) | |
116 | { | |
52c1f570 | 117 | free_irq(HP680_TS_IRQ, NULL); |
790d5c8d | 118 | cancel_delayed_work_sync(&work); |
eca1ed19 | 119 | input_unregister_device(hp680_ts_dev); |
1da177e4 LT |
120 | } |
121 | ||
122 | module_init(hp680_ts_init); | |
123 | module_exit(hp680_ts_exit); | |
124 | ||
125 | MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua"); | |
126 | MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver"); | |
127 | MODULE_LICENSE("GPL"); |