diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/input/touchscreen/hp680_ts_input.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/input/touchscreen/hp680_ts_input.c')
-rw-r--r-- | drivers/input/touchscreen/hp680_ts_input.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c new file mode 100644 index 000000000000..7e1404441eca --- /dev/null +++ b/drivers/input/touchscreen/hp680_ts_input.c | |||
@@ -0,0 +1,135 @@ | |||
1 | #include <linux/input.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/init.h> | ||
4 | |||
5 | #include <linux/interrupt.h> | ||
6 | #include <asm/io.h> | ||
7 | #include <asm/delay.h> | ||
8 | #include <asm/adc.h> | ||
9 | #include <asm/hp6xx/hp6xx.h> | ||
10 | |||
11 | #define MODNAME "hp680_ts_input" | ||
12 | |||
13 | #define HP680_TS_ABS_X_MIN 40 | ||
14 | #define HP680_TS_ABS_X_MAX 950 | ||
15 | #define HP680_TS_ABS_Y_MIN 80 | ||
16 | #define HP680_TS_ABS_Y_MAX 910 | ||
17 | |||
18 | #define SCPCR 0xa4000116 | ||
19 | #define PHDR 0xa400012e | ||
20 | #define SCPDR 0xa4000136 | ||
21 | |||
22 | static void do_softint(void *data); | ||
23 | |||
24 | static struct input_dev hp680_ts_dev; | ||
25 | static DECLARE_WORK(work, do_softint, 0); | ||
26 | static char *hp680_ts_name = "HP Jornada touchscreen"; | ||
27 | static char *hp680_ts_phys = "input0"; | ||
28 | |||
29 | static void do_softint(void *data) | ||
30 | { | ||
31 | int absx = 0, absy = 0; | ||
32 | u8 scpdr; | ||
33 | int touched = 0; | ||
34 | |||
35 | if (ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN) { | ||
36 | scpdr = ctrl_inb(SCPDR); | ||
37 | scpdr |= SCPDR_TS_SCAN_ENABLE; | ||
38 | scpdr &= ~SCPDR_TS_SCAN_Y; | ||
39 | ctrl_outb(scpdr, SCPDR); | ||
40 | udelay(30); | ||
41 | |||
42 | absy = adc_single(ADC_CHANNEL_TS_Y); | ||
43 | |||
44 | scpdr = ctrl_inb(SCPDR); | ||
45 | scpdr |= SCPDR_TS_SCAN_Y; | ||
46 | scpdr &= ~SCPDR_TS_SCAN_X; | ||
47 | ctrl_outb(scpdr, SCPDR); | ||
48 | udelay(30); | ||
49 | |||
50 | absx = adc_single(ADC_CHANNEL_TS_X); | ||
51 | |||
52 | scpdr = ctrl_inb(SCPDR); | ||
53 | scpdr |= SCPDR_TS_SCAN_X; | ||
54 | scpdr &= ~SCPDR_TS_SCAN_ENABLE; | ||
55 | ctrl_outb(scpdr, SCPDR); | ||
56 | udelay(100); | ||
57 | touched = ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN; | ||
58 | } | ||
59 | |||
60 | if (touched) { | ||
61 | input_report_key(&hp680_ts_dev, BTN_TOUCH, 1); | ||
62 | input_report_abs(&hp680_ts_dev, ABS_X, absx); | ||
63 | input_report_abs(&hp680_ts_dev, ABS_Y, absy); | ||
64 | } else { | ||
65 | input_report_key(&hp680_ts_dev, BTN_TOUCH, 0); | ||
66 | } | ||
67 | |||
68 | input_sync(&hp680_ts_dev); | ||
69 | enable_irq(HP680_TS_IRQ); | ||
70 | } | ||
71 | |||
72 | static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
73 | { | ||
74 | disable_irq_nosync(irq); | ||
75 | schedule_delayed_work(&work, HZ / 20); | ||
76 | |||
77 | return IRQ_HANDLED; | ||
78 | } | ||
79 | |||
80 | static int __init hp680_ts_init(void) | ||
81 | { | ||
82 | u8 scpdr; | ||
83 | u16 scpcr; | ||
84 | |||
85 | scpdr = ctrl_inb(SCPDR); | ||
86 | scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y; | ||
87 | scpdr &= ~SCPDR_TS_SCAN_ENABLE; | ||
88 | ctrl_outb(scpdr, SCPDR); | ||
89 | |||
90 | scpcr = ctrl_inw(SCPCR); | ||
91 | scpcr &= ~SCPCR_TS_MASK; | ||
92 | scpcr |= SCPCR_TS_ENABLE; | ||
93 | ctrl_outw(scpcr, SCPCR); | ||
94 | |||
95 | memset(&hp680_ts_dev, 0, sizeof(hp680_ts_dev)); | ||
96 | init_input_dev(&hp680_ts_dev); | ||
97 | |||
98 | hp680_ts_dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); | ||
99 | hp680_ts_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); | ||
100 | hp680_ts_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
101 | |||
102 | hp680_ts_dev.absmin[ABS_X] = HP680_TS_ABS_X_MIN; | ||
103 | hp680_ts_dev.absmin[ABS_Y] = HP680_TS_ABS_Y_MIN; | ||
104 | hp680_ts_dev.absmax[ABS_X] = HP680_TS_ABS_X_MAX; | ||
105 | hp680_ts_dev.absmax[ABS_Y] = HP680_TS_ABS_Y_MAX; | ||
106 | |||
107 | hp680_ts_dev.name = hp680_ts_name; | ||
108 | hp680_ts_dev.phys = hp680_ts_phys; | ||
109 | input_register_device(&hp680_ts_dev); | ||
110 | |||
111 | if (request_irq | ||
112 | (HP680_TS_IRQ, hp680_ts_interrupt, SA_INTERRUPT, MODNAME, 0) < 0) { | ||
113 | printk(KERN_ERR "hp680_touchscreen.c : Can't allocate irq %d\n", | ||
114 | HP680_TS_IRQ); | ||
115 | input_unregister_device(&hp680_ts_dev); | ||
116 | return -EBUSY; | ||
117 | } | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static void __exit hp680_ts_exit(void) | ||
123 | { | ||
124 | free_irq(HP680_TS_IRQ, 0); | ||
125 | cancel_delayed_work(&work); | ||
126 | flush_scheduled_work(); | ||
127 | input_unregister_device(&hp680_ts_dev); | ||
128 | } | ||
129 | |||
130 | module_init(hp680_ts_init); | ||
131 | module_exit(hp680_ts_exit); | ||
132 | |||
133 | MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua"); | ||
134 | MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver"); | ||
135 | MODULE_LICENSE("GPL"); | ||