hh.org updates
[hh.org.git] / arch / arm / mach-pxa / htcapache / htcapache-ad7877.c
blob8fa13da85d166249df174ed32f2f99c71829e86f
1 /* Support for the ad7877 touchscreen chip attached to the htcapache
2 * phone.
4 * (c) Copyright 2006 Kevin O'Connor <kevin@koconnor.net>
6 * This file may be distributed under the terms of the GNU GPL license.
7 */
9 #include <linux/interrupt.h>
10 #include <linux/input.h>
11 #include <linux/platform_device.h>
13 #include <asm/mach-types.h>
14 #include <asm/arch/ssp.h>
15 #include <asm/arch/hardware.h>
16 #include <asm/arch/pxa-regs.h>
17 #include <asm/arch/htcapache-gpio.h>
19 /****************************************************************
20 * AD7877 specific functions
21 ****************************************************************/
23 enum {
24 AD7877_SEQ_YPOS = 0,
25 AD7877_SEQ_XPOS = 1,
26 AD7877_SEQ_Z2 = 2,
27 AD7877_SEQ_AUX1 = 3,
28 AD7877_SEQ_AUX2 = 4,
29 AD7877_SEQ_AUX3 = 5,
30 AD7877_SEQ_BAT1 = 6,
31 AD7877_SEQ_BAT2 = 7,
32 AD7877_SEQ_TEMP1 = 8,
33 AD7877_SEQ_TEMP2 = 9,
34 AD7877_SEQ_Z1 = 10,
36 AD7877_NR_SENSE = 11,
39 struct ad7877 {
40 struct input_dev *input;
41 struct ssp_dev ssp;
42 int (*ispendown)(void);
43 int sent_pen_down;
44 int x_plate_ohms;
45 int min_pressure;
46 u16 read_results_data[AD7877_NR_SENSE];
48 spinlock_t lock;
49 struct timer_list timer;
52 enum {
53 REG_CR1 = 0x01,
54 REG_CR2 = 0x02,
55 REG_SENSORS = 0x10,
57 CR1_OFF_READADDR = 2,
58 CR1_SLAVEMODE = 0x02,
61 #define TS_POLL_PERIOD msecs_to_jiffies(10)
63 // Build a command that writes to an ad7877 register
64 static inline int WRITE_REG(int reg, int val)
66 return (reg << 12) | val;
69 // Send a command and drain the receive buffer.
70 static u32
71 ssp_putget(struct ad7877 *ts, u32 data)
73 u32 ret;
74 ssp_write_word(&ts->ssp, data);
75 ssp_read_word(&ts->ssp, &ret);
76 return ret;
79 // Send an event to the input layer.
80 static inline void
81 report_event(struct ad7877 *ts, int pressure, int x, int y)
83 input_report_abs(ts->input, ABS_PRESSURE, pressure);
84 input_report_abs(ts->input, ABS_X, x);
85 input_report_abs(ts->input, ABS_Y, y);
86 input_sync(ts->input);
89 // Read the most recently reported values from the chip.
90 static void ad7877_readvals(void *data)
92 struct ad7877 *ts = data;
93 u16 *regs = ts->read_results_data;
94 u16 x, y, z1, z2, pendown;
95 uint Rt = 0;
96 int i;
97 unsigned long flag;
99 // Read sensed values from ad7877.
100 spin_lock_irqsave(&ts->lock, flag);
101 ssp_putget(ts, WRITE_REG(REG_CR1, REG_SENSORS << CR1_OFF_READADDR));
102 for (i=0; i<AD7877_NR_SENSE; i++)
103 ts->read_results_data[i] = ssp_putget(ts, 0);
105 // Calculate x, y, and pressure.
106 x = regs[AD7877_SEQ_XPOS];
107 y = regs[AD7877_SEQ_YPOS];
108 z1 = regs[AD7877_SEQ_Z1];
109 z2 = regs[AD7877_SEQ_Z2];
111 // RTOUCH = (RXPlate) x (XPOSITION /4096) x [(Z2/Z1) - 1]
112 if (likely(z1)) {
113 Rt = z2;
114 Rt -= z1;
115 Rt *= x;
116 Rt *= ts->x_plate_ohms;
117 Rt /= z1;
118 Rt /= 4096;
121 pendown = ts->ispendown();
123 // printk(KERN_NOTICE "TS: pen=%d x=%d y=%d Rt=%d (z1=%d z2=%d)\n"
124 // , pendown, x, y, Rt, z1, z2);
126 if (!pendown || Rt < ts->min_pressure) {
127 // Pen no longer down.
128 if (ts->sent_pen_down) {
129 // Send pen up event.
130 report_event(ts, 0, 0, 0);
131 ts->sent_pen_down = 0;
133 } else {
134 // Pen down - arrange for events until pen up again.
135 ts->sent_pen_down = 1;
136 mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
137 report_event(ts, Rt, x, y);
140 spin_unlock_irqrestore(&ts->lock, flag);
143 // Instruct the ad7877 to sense new values.
144 static void
145 startSense(struct ad7877 *ts)
147 ssp_putget(ts, WRITE_REG(REG_CR1, CR1_SLAVEMODE));
150 // Periodic callback while pen is down.
151 static void ad7877_timer(unsigned long handle)
153 struct ad7877 *ts = (void *)handle;
154 spin_lock(&ts->lock);
155 startSense(ts);
156 spin_unlock(&ts->lock);
159 // Interrupt handler for when pen is first depressed.
160 static irqreturn_t ad7877_penirq(int irq, void *handle, struct pt_regs *regs)
162 struct ad7877 *ts = handle;
163 spin_lock(&ts->lock);
164 if (! ts->sent_pen_down)
165 startSense(ts);
166 spin_unlock(&ts->lock);
167 return IRQ_HANDLED;
170 // Interrupt handler for when sensing is complete.
171 static irqreturn_t ad7877_davirq(int irq, void *handle, struct pt_regs *regs)
173 struct ad7877 *ts = handle;
175 ad7877_readvals(ts);
177 return IRQ_HANDLED;
180 // XXX
181 static irqreturn_t ad7877_alertirq(int irq, void *handle, struct pt_regs *regs)
183 struct ad7877 *ts = handle;
185 spin_lock(&ts->lock);
186 spin_unlock(&ts->lock);
188 return IRQ_HANDLED;
192 /****************************************************************
193 * HTCApache specific functions
194 ****************************************************************/
196 #define GPLR_BIT(n) (GPLR((n)) & GPIO_bit((n)))
198 // Return true if the pen is currently down.
199 static int
200 checkPenDown(void)
202 return !GPLR_BIT(GPIO_NR_HTCAPACHE_TS_PENDOWN);
205 #define MAX_12BIT ((1<<12)-1)
207 static int
208 ts_initirq(void *d)
210 int err;
211 err = request_irq(IRQ_GPIO(GPIO_NR_HTCAPACHE_TS_PENDOWN)
212 , ad7877_penirq, SA_TRIGGER_FALLING
213 , "ad7877-pendown", d);
214 if (err)
215 return err;
216 err = request_irq(IRQ_GPIO(GPIO_NR_HTCAPACHE_TS_DAV)
217 , ad7877_davirq, SA_TRIGGER_FALLING
218 , "ad7877-dav", d);
219 if (err) {
220 free_irq(IRQ_GPIO(GPIO_NR_HTCAPACHE_TS_PENDOWN), d);
221 return err;
224 return 0; // XXX
226 err = request_irq(IRQ_GPIO(GPIO_NR_HTCAPACHE_TS_ALERT)
227 , ad7877_alertirq, SA_TRIGGER_FALLING
228 , "ad7877-alert", d);
229 if (err) {
230 free_irq(IRQ_GPIO(GPIO_NR_HTCAPACHE_TS_PENDOWN), d);
231 free_irq(IRQ_GPIO(GPIO_NR_HTCAPACHE_TS_DAV), d);
232 return err;
234 return 0;
237 static void
238 ts_freeirq(void *d)
240 free_irq(IRQ_GPIO(GPIO_NR_HTCAPACHE_TS_PENDOWN), d);
241 free_irq(IRQ_GPIO(GPIO_NR_HTCAPACHE_TS_DAV), d);
242 return; // XXX
243 free_irq(IRQ_GPIO(GPIO_NR_HTCAPACHE_TS_ALERT), d);
246 static int __init ts_ssp_probe(struct device *dev)
248 struct ad7877 *ts;
249 struct input_dev *input_dev;
250 int ret;
252 // Initialize ts data structure.
253 ts = kzalloc(sizeof(*ts), GFP_KERNEL);
254 if (!ts)
255 return -ENOMEM;
257 ret = ts_initirq(ts);
258 if (ret) {
259 kfree(ts);
260 return ret;
263 ret = ssp_init(&ts->ssp, 1, 0);
264 if (ret) {
265 printk(KERN_ERR "Unable to register SSP handler!\n");
266 ts_freeirq(ts);
267 kfree(ts);
268 return ret;
270 dev->driver_data = ts;
272 ts->ispendown = checkPenDown;
273 ts->x_plate_ohms = 400; // XXX - don't know real value.
274 ts->min_pressure = 1; // XXX - don't know real value.
276 init_timer(&ts->timer);
277 ts->timer.data = (unsigned long) ts;
278 ts->timer.function = ad7877_timer;
280 spin_lock_init(&ts->lock);
282 // Initialize input device.
283 input_dev = input_allocate_device();
284 input_dev->name = "AD7877 Touchscreen";
285 set_bit(EV_KEY, input_dev->evbit);
286 set_bit(EV_ABS, input_dev->evbit);
287 set_bit(ABS_X, input_dev->absbit);
288 set_bit(ABS_Y, input_dev->absbit);
289 set_bit(ABS_PRESSURE, input_dev->absbit);
290 input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
291 input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
292 input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
293 ts->input = input_dev;
294 input_register_device(input_dev);
296 return 0;
299 static int ts_ssp_remove(struct device *dev)
301 struct ad7877 *ts = dev->driver_data;
303 del_timer_sync(&ts->timer);
305 ts_freeirq(ts);
306 ssp_exit(&ts->ssp);
308 input_unregister_device(ts->input);
309 kfree(ts);
311 return 0;
314 static struct device_driver ts_ssp_driver = {
315 .name = "htcapache-ad7877",
316 .bus = &platform_bus_type,
317 .probe = ts_ssp_probe,
318 .remove = ts_ssp_remove,
321 static int __init ts_ssp_init(void)
323 if (!machine_is_htcapache())
324 return -ENODEV;
326 return driver_register(&ts_ssp_driver);
329 static void __exit ts_ssp_exit(void)
331 driver_unregister(&ts_ssp_driver);
334 module_init(ts_ssp_init)
335 module_exit(ts_ssp_exit)
337 MODULE_LICENSE("GPL");