1 From b2640063b8321bdfb324c00d5f0c3366ac31696b Mon Sep 17 00:00:00 2001
2 From: Mark Brown <broonie@opensource.wolfsonmicro.com>
3 Date: Sat, 26 Jan 2008 21:14:19 +0300
4 Subject: [PATCH 32/64] Add chip driver for WM9712 touchscreen
6 Signed-off-by: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
7 Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com>
8 Signed-off-by: Mike Arthur <mike.arthur@wolfsonmicro.com>
9 Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
10 Cc: Dmitry Baryshkov <dbaryshkov@gmail.com>
11 Cc: Stanley Cai <stanley.cai@intel.com>
12 Cc: Rodolfo Giometti <giometti@enneenne.com>
13 Cc: Russell King <rmk@arm.linux.org.uk>
14 Cc: Marc Kleine-Budde <mkl@pengutronix.de>
15 Cc: Ian Molton <spyro@f2s.com>
16 Cc: Vince Sanders <vince@kyllikki.org>
17 Cc: Andrew Zabolotny <zap@homelink.ru>
19 drivers/input/touchscreen/wm9712.c | 461 ++++++++++++++++++++++++++++++++++++
20 1 files changed, 461 insertions(+), 0 deletions(-)
21 create mode 100644 drivers/input/touchscreen/wm9712.c
23 diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
25 index 0000000..eaab326
27 +++ b/drivers/input/touchscreen/wm9712.c
30 + * wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs.
32 + * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
33 + * Author: Liam Girdwood
34 + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
35 + * Parts Copyright : Ian Molton <spyro@f2s.com>
36 + * Andrew Zabolotny <zap@homelink.ru>
37 + * Russell King <rmk@arm.linux.org.uk>
39 + * This program is free software; you can redistribute it and/or modify it
40 + * under the terms of the GNU General Public License as published by the
41 + * Free Software Foundation; either version 2 of the License, or (at your
42 + * option) any later version.
46 +#include <linux/module.h>
47 +#include <linux/moduleparam.h>
48 +#include <linux/version.h>
49 +#include <linux/kernel.h>
50 +#include <linux/input.h>
51 +#include <linux/delay.h>
52 +#include <linux/bitops.h>
53 +#include <linux/wm97xx.h>
55 +#define TS_NAME "wm97xx"
56 +#define WM9712_VERSION "0.61"
57 +#define DEFAULT_PRESSURE 0xb0c0
64 + * Set internal pull up for pen detect.
66 + * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
67 + * i.e. pull up resistance = 64k Ohms / rpu.
69 + * Adjust this value if you are having problems with pen detect not
70 + * detecting any down event.
73 +module_param(rpu, int, 0);
74 +MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
77 + * Set current used for pressure measurement.
79 + * Set pil = 2 to use 400uA
80 + * pil = 1 to use 200uA and
81 + * pil = 0 to disable pressure measurement.
83 + * This is used to increase the range of values returned by the adc
84 + * when measureing touchpanel pressure.
87 +module_param(pil, int, 0);
88 +MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
91 + * Set threshold for pressure measurement.
93 + * Pen down pressure below threshold is ignored.
95 +static int pressure = DEFAULT_PRESSURE & 0xfff;
96 +module_param(pressure, int, 0);
97 +MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
100 + * Set adc sample delay.
102 + * For accurate touchpanel measurements, some settling time may be
103 + * required between the switch matrix applying a voltage across the
104 + * touchpanel plate and the ADC sampling the signal.
106 + * This delay can be set by setting delay = n, where n is the array
107 + * position of the delay in the array delay_table below.
108 + * Long delays > 1ms are supported for completeness, but are not
111 +static int delay = 3;
112 +module_param(delay, int, 0);
113 +MODULE_PARM_DESC(delay, "Set adc sample delay.");
116 + * Set five_wire = 1 to use a 5 wire touchscreen.
118 + * NOTE: Five wire mode does not allow for readback of pressure.
120 +static int five_wire;
121 +module_param(five_wire, int, 0);
122 +MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
125 + * Set adc mask function.
127 + * Sources of glitch noise, such as signals driving an LCD display, may feed
128 + * through to the touch screen plates and affect measurement accuracy. In
129 + * order to minimise this, a signal may be applied to the MASK pin to delay or
130 + * synchronise the sampling.
132 + * 0 = No delay or sync
133 + * 1 = High on pin stops conversions
134 + * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
135 + * 3 = Edge triggered, edge on pin starts conversion after delay param
138 +module_param(mask, int, 0);
139 +MODULE_PARM_DESC(mask, "Set adc mask function.");
142 + * Coordinate Polling Enable.
144 + * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
148 +module_param(coord, int, 0);
149 +MODULE_PARM_DESC(coord, "Polling coordinate mode");
152 + * ADC sample delay times in uS
154 +static const int delay_table[] = {
155 + 21, /* 1 AC97 Link frames */
170 + 0 /* No delay, switch matrix always on */
174 + * Delay after issuing a POLL command.
176 + * The delay is 3 AC97 link frames + the touchpanel settling delay
178 +static inline void poll_delay(int d)
180 + udelay(3 * AC97_LINK_FRAME + delay_table[d]);
184 + * set up the physical settings of the WM9712
186 +static void wm9712_phy_init(struct wm97xx *wm)
189 + u16 dig2 = WM97XX_RPR | WM9712_RPU(1);
194 + dig2 |= WM9712_RPU(rpu);
195 + dev_dbg(wm->dev, "setting pen detect pull-up to %d Ohms",
199 + /* touchpanel pressure current*/
201 + dig2 |= WM9712_PIL;
203 + "setting pressure measurement current to 400uA.");
206 + "setting pressure measurement current to 200uA.");
210 + /* WM9712 five wire */
212 + dig2 |= WM9712_45W;
213 + dev_dbg(wm->dev, "setting 5-wire touchscreen mode.");
216 + /* polling mode sample settling delay */
217 + if (delay < 0 || delay > 15) {
218 + dev_dbg(wm->dev, "supplied delay out of range.");
222 + dig1 |= WM97XX_DELAY(delay);
223 + dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
224 + delay_table[delay]);
227 + dig2 |= ((mask & 0x3) << 6);
230 + /* Set GPIO4 as Mask Pin*/
231 + reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
232 + wm97xx_reg_write(wm, AC97_MISC_AFE, reg | WM97XX_GPIO_4);
233 + reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
234 + wm97xx_reg_write(wm, AC97_GPIO_CFG, reg | WM97XX_GPIO_4);
237 + /* wait - coord mode */
239 + dig2 |= WM9712_WAIT;
241 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
242 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
245 +static void wm9712_dig_enable(struct wm97xx *wm, int enable)
247 + u16 dig2 = wm->dig[2];
250 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
251 + dig2 | WM97XX_PRP_DET_DIG);
252 + wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
254 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
255 + dig2 & ~WM97XX_PRP_DET_DIG);
258 +static void wm9712_aux_prepare(struct wm97xx *wm)
260 + memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
261 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
262 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
265 +static void wm9712_dig_restore(struct wm97xx *wm)
267 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
268 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
271 +static inline int is_pden(struct wm97xx *wm)
273 + return wm->dig[2] & WM9712_PDEN;
277 + * Read a sample from the WM9712 adc in polling mode.
279 +static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
281 + int timeout = 5 * delay;
283 + if (!wm->pen_probably_down) {
284 + u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
285 + if (!(data & WM97XX_PEN_DOWN))
287 + wm->pen_probably_down = 1;
290 + /* set up digitiser */
291 + if (adcsel & 0x8000)
292 + adcsel = ((adcsel & 0x7fff) + 3) << 12;
294 + if (wm->mach_ops && wm->mach_ops->pre_sample)
295 + wm->mach_ops->pre_sample(adcsel);
296 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
297 + adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
299 + /* wait 3 AC97 time slots + delay for conversion */
302 + /* wait for POLL to go low */
303 + while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
305 + udelay(AC97_LINK_FRAME);
309 + if (timeout <= 0) {
310 + /* If PDEN is set, we can get a timeout when pen goes up */
312 + wm->pen_probably_down = 0;
314 + dev_dbg(wm->dev, "adc sample timeout");
318 + *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
319 + if (wm->mach_ops && wm->mach_ops->post_sample)
320 + wm->mach_ops->post_sample(adcsel);
322 + /* check we have correct sample */
323 + if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
324 + dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
325 + *sample & WM97XX_ADCSEL_MASK);
329 + if (!(*sample & WM97XX_PEN_DOWN)) {
330 + wm->pen_probably_down = 0;
338 + * Read a coord from the WM9712 adc in polling mode.
340 +static int wm9712_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
342 + int timeout = 5 * delay;
344 + if (!wm->pen_probably_down) {
345 + u16 data_rd = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
346 + if (!(data_rd & WM97XX_PEN_DOWN))
348 + wm->pen_probably_down = 1;
351 + /* set up digitiser */
352 + if (wm->mach_ops && wm->mach_ops->pre_sample)
353 + wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
355 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
356 + WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay));
358 + /* wait 3 AC97 time slots + delay for conversion and read x */
360 + data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
361 + /* wait for POLL to go low */
362 + while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
364 + udelay(AC97_LINK_FRAME);
368 + if (timeout <= 0) {
369 + /* If PDEN is set, we can get a timeout when pen goes up */
371 + wm->pen_probably_down = 0;
373 + dev_dbg(wm->dev, "adc sample timeout");
377 + /* read back y data */
378 + data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
380 + data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
382 + data->p = DEFAULT_PRESSURE;
384 + if (wm->mach_ops && wm->mach_ops->post_sample)
385 + wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
387 + /* check we have correct sample */
388 + if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
390 + if (pil && !(data->p & WM97XX_ADCSEL_PRES))
393 + if (!(data->x & WM97XX_PEN_DOWN)) {
394 + wm->pen_probably_down = 0;
403 + * Sample the WM9712 touchscreen in polling mode
405 +static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
410 + rc = wm9712_poll_coord(wm, data);
411 + if (rc != RC_VALID)
414 + rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
415 + if (rc != RC_VALID)
418 + rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
419 + if (rc != RC_VALID)
422 + if (pil && !five_wire) {
423 + rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES,
425 + if (rc != RC_VALID)
428 + data->p = DEFAULT_PRESSURE;
434 + * Enable WM9712 continuous mode, i.e. touch data is streamed across
437 +static int wm9712_acc_enable(struct wm97xx *wm, int enable)
446 + /* continous mode */
447 + if (wm->mach_ops->acc_startup) {
448 + ret = wm->mach_ops->acc_startup(wm);
452 + dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
453 + WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
454 + dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
455 + WM97XX_DELAY(delay) |
456 + WM97XX_SLT(wm->acc_slot) |
457 + WM97XX_RATE(wm->acc_rate);
459 + dig1 |= WM97XX_ADCSEL_PRES;
460 + dig2 |= WM9712_PDEN;
462 + dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
463 + dig2 &= ~WM9712_PDEN;
464 + if (wm->mach_ops->acc_shutdown)
465 + wm->mach_ops->acc_shutdown(wm);
468 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
469 + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
473 +struct wm97xx_codec_drv wm9712_codec = {
476 + .poll_sample = wm9712_poll_sample,
477 + .poll_touch = wm9712_poll_touch,
478 + .acc_enable = wm9712_acc_enable,
479 + .phy_init = wm9712_phy_init,
480 + .dig_enable = wm9712_dig_enable,
481 + .dig_restore = wm9712_dig_restore,
482 + .aux_prepare = wm9712_aux_prepare,
484 +EXPORT_SYMBOL_GPL(wm9712_codec);
486 +/* Module information */
487 +MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
488 +MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
489 +MODULE_LICENSE("GPL");