merge of '0b604857bbf871639fdb43ee8380222e8ef64bb7'
[vuplus_openembedded] / packages / linux / linux-rp-2.6.24 / tosa / 0032-Add-chip-driver-for-WM9712-touchscreen.patch
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
5
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>
18 ---
19  drivers/input/touchscreen/wm9712.c |  461 ++++++++++++++++++++++++++++++++++++
20  1 files changed, 461 insertions(+), 0 deletions(-)
21  create mode 100644 drivers/input/touchscreen/wm9712.c
22
23 diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
24 new file mode 100644
25 index 0000000..eaab326
26 --- /dev/null
27 +++ b/drivers/input/touchscreen/wm9712.c
28 @@ -0,0 +1,461 @@
29 +/*
30 + * wm9712.c  --  Codec driver for Wolfson WM9712 AC97 Codecs.
31 + *
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>
38 + *
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.
43 + *
44 + */
45 +
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>
54 +
55 +#define TS_NAME                        "wm97xx"
56 +#define WM9712_VERSION         "0.61"
57 +#define DEFAULT_PRESSURE       0xb0c0
58 +
59 +/*
60 + * Module parameters
61 + */
62 +
63 +/*
64 + * Set internal pull up for pen detect.
65 + *
66 + * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
67 + * i.e. pull up resistance = 64k Ohms / rpu.
68 + *
69 + * Adjust this value if you are having problems with pen detect not
70 + * detecting any down event.
71 + */
72 +static int rpu = 8;
73 +module_param(rpu, int, 0);
74 +MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
75 +
76 +/*
77 + * Set current used for pressure measurement.
78 + *
79 + * Set pil = 2 to use 400uA
80 + *     pil = 1 to use 200uA and
81 + *     pil = 0 to disable pressure measurement.
82 + *
83 + * This is used to increase the range of values returned by the adc
84 + * when measureing touchpanel pressure.
85 + */
86 +static int pil;
87 +module_param(pil, int, 0);
88 +MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
89 +
90 +/*
91 + * Set threshold for pressure measurement.
92 + *
93 + * Pen down pressure below threshold is ignored.
94 + */
95 +static int pressure = DEFAULT_PRESSURE & 0xfff;
96 +module_param(pressure, int, 0);
97 +MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
98 +
99 +/*
100 + * Set adc sample delay.
101 + *
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.
105 + *
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
109 + * recommended.
110 + */
111 +static int delay = 3;
112 +module_param(delay, int, 0);
113 +MODULE_PARM_DESC(delay, "Set adc sample delay.");
114 +
115 +/*
116 + * Set five_wire = 1 to use a 5 wire touchscreen.
117 + *
118 + * NOTE: Five wire mode does not allow for readback of pressure.
119 + */
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.");
123 +
124 +/*
125 + * Set adc mask function.
126 + *
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.
131 + *
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
136 + */
137 +static int mask;
138 +module_param(mask, int, 0);
139 +MODULE_PARM_DESC(mask, "Set adc mask function.");
140 +
141 +/*
142 + * Coordinate Polling Enable.
143 + *
144 + * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
145 + * for every poll.
146 + */
147 +static int coord;
148 +module_param(coord, int, 0);
149 +MODULE_PARM_DESC(coord, "Polling coordinate mode");
150 +
151 +/*
152 + * ADC sample delay times in uS
153 + */
154 +static const int delay_table[] = {
155 +       21,    /* 1 AC97 Link frames */
156 +       42,    /* 2 */
157 +       84,    /* 4 */
158 +       167,   /* 8 */
159 +       333,   /* 16 */
160 +       667,   /* 32 */
161 +       1000,  /* 48 */
162 +       1333,  /* 64 */
163 +       2000,  /* 96 */
164 +       2667,  /* 128 */
165 +       3333,  /* 160 */
166 +       4000,  /* 192 */
167 +       4667,  /* 224 */
168 +       5333,  /* 256 */
169 +       6000,  /* 288 */
170 +       0      /* No delay, switch matrix always on */
171 +};
172 +
173 +/*
174 + * Delay after issuing a POLL command.
175 + *
176 + * The delay is 3 AC97 link frames + the touchpanel settling delay
177 + */
178 +static inline void poll_delay(int d)
179 +{
180 +       udelay(3 * AC97_LINK_FRAME + delay_table[d]);
181 +}
182 +
183 +/*
184 + * set up the physical settings of the WM9712
185 + */
186 +static void wm9712_phy_init(struct wm97xx *wm)
187 +{
188 +       u16 dig1 = 0;
189 +       u16 dig2 = WM97XX_RPR | WM9712_RPU(1);
190 +
191 +       /* WM9712 rpu */
192 +       if (rpu) {
193 +               dig2 &= 0xffc0;
194 +               dig2 |= WM9712_RPU(rpu);
195 +               dev_dbg(wm->dev, "setting pen detect pull-up to %d Ohms",
196 +                       64000 / rpu);
197 +       }
198 +
199 +       /* touchpanel pressure current*/
200 +       if (pil == 2) {
201 +               dig2 |= WM9712_PIL;
202 +               dev_dbg(wm->dev,
203 +                       "setting pressure measurement current to 400uA.");
204 +       } else if (pil)
205 +               dev_dbg(wm->dev,
206 +                       "setting pressure measurement current to 200uA.");
207 +       if (!pil)
208 +               pressure = 0;
209 +
210 +       /* WM9712 five wire */
211 +       if (five_wire) {
212 +               dig2 |= WM9712_45W;
213 +               dev_dbg(wm->dev, "setting 5-wire touchscreen mode.");
214 +       }
215 +
216 +       /* polling mode sample settling delay */
217 +       if (delay < 0 || delay > 15) {
218 +               dev_dbg(wm->dev, "supplied delay out of range.");
219 +               delay = 4;
220 +       }
221 +       dig1 &= 0xff0f;
222 +       dig1 |= WM97XX_DELAY(delay);
223 +       dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
224 +               delay_table[delay]);
225 +
226 +       /* mask */
227 +       dig2 |= ((mask & 0x3) << 6);
228 +       if (mask) {
229 +               u16 reg;
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);
235 +       }
236 +
237 +       /* wait - coord mode */
238 +       if (coord)
239 +               dig2 |= WM9712_WAIT;
240 +
241 +       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
242 +       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
243 +}
244 +
245 +static void wm9712_dig_enable(struct wm97xx *wm, int enable)
246 +{
247 +       u16 dig2 = wm->dig[2];
248 +
249 +       if (enable) {
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 */
253 +       } else
254 +               wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
255 +                                dig2 & ~WM97XX_PRP_DET_DIG);
256 +}
257 +
258 +static void wm9712_aux_prepare(struct wm97xx *wm)
259 +{
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);
263 +}
264 +
265 +static void wm9712_dig_restore(struct wm97xx *wm)
266 +{
267 +       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
268 +       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
269 +}
270 +
271 +static inline int is_pden(struct wm97xx *wm)
272 +{
273 +       return wm->dig[2] & WM9712_PDEN;
274 +}
275 +
276 +/*
277 + * Read a sample from the WM9712 adc in polling mode.
278 + */
279 +static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
280 +{
281 +       int timeout = 5 * delay;
282 +
283 +       if (!wm->pen_probably_down) {
284 +               u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
285 +               if (!(data & WM97XX_PEN_DOWN))
286 +                       return RC_PENUP;
287 +               wm->pen_probably_down = 1;
288 +       }
289 +
290 +       /* set up digitiser */
291 +       if (adcsel & 0x8000)
292 +               adcsel = ((adcsel & 0x7fff) + 3) << 12;
293 +
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));
298 +
299 +       /* wait 3 AC97 time slots + delay for conversion */
300 +       poll_delay(delay);
301 +
302 +       /* wait for POLL to go low */
303 +       while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
304 +              && timeout) {
305 +               udelay(AC97_LINK_FRAME);
306 +               timeout--;
307 +       }
308 +
309 +       if (timeout <= 0) {
310 +               /* If PDEN is set, we can get a timeout when pen goes up */
311 +               if (is_pden(wm))
312 +                       wm->pen_probably_down = 0;
313 +               else
314 +                       dev_dbg(wm->dev, "adc sample timeout");
315 +               return RC_PENUP;
316 +       }
317 +
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);
321 +
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);
326 +               return RC_PENUP;
327 +       }
328 +
329 +       if (!(*sample & WM97XX_PEN_DOWN)) {
330 +               wm->pen_probably_down = 0;
331 +               return RC_PENUP;
332 +       }
333 +
334 +       return RC_VALID;
335 +}
336 +
337 +/*
338 + * Read a coord from the WM9712 adc in polling mode.
339 + */
340 +static int wm9712_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
341 +{
342 +       int timeout = 5 * delay;
343 +
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))
347 +                       return RC_PENUP;
348 +               wm->pen_probably_down = 1;
349 +       }
350 +
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);
354 +
355 +       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
356 +               WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay));
357 +
358 +       /* wait 3 AC97 time slots + delay for conversion and read x */
359 +       poll_delay(delay);
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)
363 +              && timeout) {
364 +               udelay(AC97_LINK_FRAME);
365 +               timeout--;
366 +       }
367 +
368 +       if (timeout <= 0) {
369 +               /* If PDEN is set, we can get a timeout when pen goes up */
370 +               if (is_pden(wm))
371 +                       wm->pen_probably_down = 0;
372 +               else
373 +                       dev_dbg(wm->dev, "adc sample timeout");
374 +               return RC_PENUP;
375 +       }
376 +
377 +       /* read back y data */
378 +       data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
379 +       if (pil)
380 +               data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
381 +       else
382 +               data->p = DEFAULT_PRESSURE;
383 +
384 +       if (wm->mach_ops && wm->mach_ops->post_sample)
385 +               wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
386 +
387 +       /* check we have correct sample */
388 +       if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
389 +               goto err;
390 +       if (pil && !(data->p & WM97XX_ADCSEL_PRES))
391 +               goto err;
392 +
393 +       if (!(data->x & WM97XX_PEN_DOWN)) {
394 +               wm->pen_probably_down = 0;
395 +               return RC_PENUP;
396 +       }
397 +       return RC_VALID;
398 +err:
399 +       return RC_PENUP;
400 +}
401 +
402 +/*
403 + * Sample the WM9712 touchscreen in polling mode
404 + */
405 +static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
406 +{
407 +       int rc;
408 +
409 +       if (coord) {
410 +               rc = wm9712_poll_coord(wm, data);
411 +               if (rc != RC_VALID)
412 +                       return rc;
413 +       } else {
414 +               rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
415 +               if (rc != RC_VALID)
416 +                       return rc;
417 +
418 +               rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
419 +               if (rc != RC_VALID)
420 +                       return rc;
421 +
422 +               if (pil && !five_wire) {
423 +                       rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES,
424 +                                               &data->p);
425 +                       if (rc != RC_VALID)
426 +                               return rc;
427 +               } else
428 +                       data->p = DEFAULT_PRESSURE;
429 +       }
430 +       return RC_VALID;
431 +}
432 +
433 +/*
434 + * Enable WM9712 continuous mode, i.e. touch data is streamed across
435 + * an AC97 slot
436 + */
437 +static int wm9712_acc_enable(struct wm97xx *wm, int enable)
438 +{
439 +       u16 dig1, dig2;
440 +       int ret = 0;
441 +
442 +       dig1 = wm->dig[1];
443 +       dig2 = wm->dig[2];
444 +
445 +       if (enable) {
446 +               /* continous mode */
447 +               if (wm->mach_ops->acc_startup) {
448 +                       ret = wm->mach_ops->acc_startup(wm);
449 +                       if (ret < 0)
450 +                               return ret;
451 +               }
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);
458 +               if (pil)
459 +                       dig1 |= WM97XX_ADCSEL_PRES;
460 +               dig2 |= WM9712_PDEN;
461 +       } else {
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);
466 +       }
467 +
468 +       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
469 +       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
470 +       return 0;
471 +}
472 +
473 +struct wm97xx_codec_drv wm9712_codec = {
474 +       .id =   WM9712_ID2,
475 +       .name = "wm9712",
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,
483 +};
484 +EXPORT_SYMBOL_GPL(wm9712_codec);
485 +
486 +/* Module information */
487 +MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
488 +MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
489 +MODULE_LICENSE("GPL");
490 -- 
491 1.5.3.8
492