Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/touchscreen/mk712.c
15111 views
1
/*
2
* ICS MK712 touchscreen controller driver
3
*
4
* Copyright (c) 1999-2002 Transmeta Corporation
5
* Copyright (c) 2005 Rick Koch <[email protected]>
6
* Copyright (c) 2005 Vojtech Pavlik <[email protected]>
7
*/
8
9
/*
10
* This program is free software; you can redistribute it and/or modify it
11
* under the terms of the GNU General Public License version 2 as published by
12
* the Free Software Foundation.
13
*/
14
15
/*
16
* This driver supports the ICS MicroClock MK712 TouchScreen controller,
17
* found in Gateway AOL Connected Touchpad computers.
18
*
19
* Documentation for ICS MK712 can be found at:
20
* http://www.idt.com/products/getDoc.cfm?docID=18713923
21
*/
22
23
/*
24
* 1999-12-18: original version, Daniel Quinlan
25
* 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
26
* to use queue_empty, Nathan Laredo
27
* 1999-12-20: improved random point rejection, Nathan Laredo
28
* 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
29
* queue code, added module options, other fixes, Daniel Quinlan
30
* 2002-03-15: Clean up for kernel merge <[email protected]>
31
* Fixed multi open race, fixed memory checks, fixed resource
32
* allocation, fixed close/powerdown bug, switched to new init
33
* 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch
34
* 2005-02-05: Rewritten for the input layer, Vojtech Pavlik
35
*
36
*/
37
38
#include <linux/module.h>
39
#include <linux/kernel.h>
40
#include <linux/init.h>
41
#include <linux/errno.h>
42
#include <linux/delay.h>
43
#include <linux/ioport.h>
44
#include <linux/interrupt.h>
45
#include <linux/input.h>
46
#include <asm/io.h>
47
48
MODULE_AUTHOR("Daniel Quinlan <[email protected]>, Vojtech Pavlik <[email protected]>");
49
MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
50
MODULE_LICENSE("GPL");
51
52
static unsigned int mk712_io = 0x260; /* Also 0x200, 0x208, 0x300 */
53
module_param_named(io, mk712_io, uint, 0);
54
MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
55
56
static unsigned int mk712_irq = 10; /* Also 12, 14, 15 */
57
module_param_named(irq, mk712_irq, uint, 0);
58
MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
59
60
/* eight 8-bit registers */
61
#define MK712_STATUS 0
62
#define MK712_X 2
63
#define MK712_Y 4
64
#define MK712_CONTROL 6
65
#define MK712_RATE 7
66
67
/* status */
68
#define MK712_STATUS_TOUCH 0x10
69
#define MK712_CONVERSION_COMPLETE 0x80
70
71
/* control */
72
#define MK712_ENABLE_INT 0x01
73
#define MK712_INT_ON_CONVERSION_COMPLETE 0x02
74
#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS 0x04
75
#define MK712_ENABLE_PERIODIC_CONVERSIONS 0x10
76
#define MK712_READ_ONE_POINT 0x20
77
#define MK712_POWERUP 0x40
78
79
static struct input_dev *mk712_dev;
80
static DEFINE_SPINLOCK(mk712_lock);
81
82
static irqreturn_t mk712_interrupt(int irq, void *dev_id)
83
{
84
unsigned char status;
85
static int debounce = 1;
86
static unsigned short last_x;
87
static unsigned short last_y;
88
89
spin_lock(&mk712_lock);
90
91
status = inb(mk712_io + MK712_STATUS);
92
93
if (~status & MK712_CONVERSION_COMPLETE) {
94
debounce = 1;
95
goto end;
96
}
97
98
if (~status & MK712_STATUS_TOUCH) {
99
debounce = 1;
100
input_report_key(mk712_dev, BTN_TOUCH, 0);
101
goto end;
102
}
103
104
if (debounce) {
105
debounce = 0;
106
goto end;
107
}
108
109
input_report_key(mk712_dev, BTN_TOUCH, 1);
110
input_report_abs(mk712_dev, ABS_X, last_x);
111
input_report_abs(mk712_dev, ABS_Y, last_y);
112
113
end:
114
last_x = inw(mk712_io + MK712_X) & 0x0fff;
115
last_y = inw(mk712_io + MK712_Y) & 0x0fff;
116
input_sync(mk712_dev);
117
spin_unlock(&mk712_lock);
118
return IRQ_HANDLED;
119
}
120
121
static int mk712_open(struct input_dev *dev)
122
{
123
unsigned long flags;
124
125
spin_lock_irqsave(&mk712_lock, flags);
126
127
outb(0, mk712_io + MK712_CONTROL); /* Reset */
128
129
outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
130
MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
131
MK712_ENABLE_PERIODIC_CONVERSIONS |
132
MK712_POWERUP, mk712_io + MK712_CONTROL);
133
134
outb(10, mk712_io + MK712_RATE); /* 187 points per second */
135
136
spin_unlock_irqrestore(&mk712_lock, flags);
137
138
return 0;
139
}
140
141
static void mk712_close(struct input_dev *dev)
142
{
143
unsigned long flags;
144
145
spin_lock_irqsave(&mk712_lock, flags);
146
147
outb(0, mk712_io + MK712_CONTROL);
148
149
spin_unlock_irqrestore(&mk712_lock, flags);
150
}
151
152
static int __init mk712_init(void)
153
{
154
int err;
155
156
if (!request_region(mk712_io, 8, "mk712")) {
157
printk(KERN_WARNING "mk712: unable to get IO region\n");
158
return -ENODEV;
159
}
160
161
outb(0, mk712_io + MK712_CONTROL);
162
163
if ((inw(mk712_io + MK712_X) & 0xf000) || /* Sanity check */
164
(inw(mk712_io + MK712_Y) & 0xf000) ||
165
(inw(mk712_io + MK712_STATUS) & 0xf333)) {
166
printk(KERN_WARNING "mk712: device not present\n");
167
err = -ENODEV;
168
goto fail1;
169
}
170
171
mk712_dev = input_allocate_device();
172
if (!mk712_dev) {
173
printk(KERN_ERR "mk712: not enough memory\n");
174
err = -ENOMEM;
175
goto fail1;
176
}
177
178
mk712_dev->name = "ICS MicroClock MK712 TouchScreen";
179
mk712_dev->phys = "isa0260/input0";
180
mk712_dev->id.bustype = BUS_ISA;
181
mk712_dev->id.vendor = 0x0005;
182
mk712_dev->id.product = 0x0001;
183
mk712_dev->id.version = 0x0100;
184
185
mk712_dev->open = mk712_open;
186
mk712_dev->close = mk712_close;
187
188
mk712_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
189
mk712_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
190
input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0);
191
input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0);
192
193
if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) {
194
printk(KERN_WARNING "mk712: unable to get IRQ\n");
195
err = -EBUSY;
196
goto fail1;
197
}
198
199
err = input_register_device(mk712_dev);
200
if (err)
201
goto fail2;
202
203
return 0;
204
205
fail2: free_irq(mk712_irq, mk712_dev);
206
fail1: input_free_device(mk712_dev);
207
release_region(mk712_io, 8);
208
return err;
209
}
210
211
static void __exit mk712_exit(void)
212
{
213
input_unregister_device(mk712_dev);
214
free_irq(mk712_irq, mk712_dev);
215
release_region(mk712_io, 8);
216
}
217
218
module_init(mk712_init);
219
module_exit(mk712_exit);
220
221