1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/kernel.h>
20#include <linux/input.h>
21#include <linux/delay.h>
22#include <linux/bitops.h>
23#include <linux/wm97xx.h>
24
25#define TS_NAME "wm97xx"
26#define WM9713_VERSION "1.00"
27#define DEFAULT_PRESSURE 0xb0c0
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42static int rpu = 8;
43module_param(rpu, int, 0);
44MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
45
46
47
48
49
50
51
52
53
54
55
56static int pil;
57module_param(pil, int, 0);
58MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
59
60
61
62
63
64
65static int pressure = DEFAULT_PRESSURE & 0xfff;
66module_param(pressure, int, 0);
67MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
68
69
70
71
72
73
74
75
76
77
78
79
80
81static int delay = 4;
82module_param(delay, int, 0);
83MODULE_PARM_DESC(delay, "Set adc sample delay.");
84
85
86
87
88
89
90static int five_wire;
91module_param(five_wire, int, 0);
92MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107static int mask;
108module_param(mask, int, 0);
109MODULE_PARM_DESC(mask, "Set adc mask function.");
110
111
112
113
114
115
116
117static int coord;
118module_param(coord, int, 0);
119MODULE_PARM_DESC(coord, "Polling coordinate mode");
120
121
122
123
124static const int delay_table[] = {
125 21,
126 42,
127 84,
128 167,
129 333,
130 667,
131 1000,
132 1333,
133 2000,
134 2667,
135 3333,
136 4000,
137 4667,
138 5333,
139 6000,
140 0
141};
142
143
144
145
146
147
148static inline void poll_delay(int d)
149{
150 udelay(3 * AC97_LINK_FRAME + delay_table[d]);
151}
152
153
154
155
156static void wm9713_phy_init(struct wm97xx *wm)
157{
158 u16 dig1 = 0, dig2, dig3;
159
160
161 dig2 = WM97XX_DELAY(4) | WM97XX_SLT(5);
162 dig3 = WM9712_RPU(1);
163
164
165 if (rpu) {
166 dig3 &= 0xffc0;
167 dig3 |= WM9712_RPU(rpu);
168 dev_info(wm->dev, "setting pen detect pull-up to %d Ohms\n",
169 64000 / rpu);
170 }
171
172
173 if (five_wire) {
174 dig3 |= WM9713_45W;
175 dev_info(wm->dev, "setting 5-wire touchscreen mode.");
176
177 if (pil) {
178 dev_warn(wm->dev,
179 "Pressure measurement not supported in 5 "
180 "wire mode, disabling\n");
181 pil = 0;
182 }
183 }
184
185
186 if (pil == 2) {
187 dig3 |= WM9712_PIL;
188 dev_info(wm->dev,
189 "setting pressure measurement current to 400uA.");
190 } else if (pil)
191 dev_info(wm->dev,
192 "setting pressure measurement current to 200uA.");
193 if (!pil)
194 pressure = 0;
195
196
197 if (delay < 0 || delay > 15) {
198 dev_info(wm->dev, "supplied delay out of range.");
199 delay = 4;
200 dev_info(wm->dev, "setting adc sample delay to %d u Secs.",
201 delay_table[delay]);
202 }
203 dig2 &= 0xff0f;
204 dig2 |= WM97XX_DELAY(delay);
205
206
207 dig3 |= ((mask & 0x3) << 4);
208 if (coord)
209 dig3 |= WM9713_WAIT;
210
211 wm->misc = wm97xx_reg_read(wm, 0x5a);
212
213 wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
214 wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
215 wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
216 wm97xx_reg_write(wm, AC97_GPIO_STICKY, 0x0);
217}
218
219static void wm9713_dig_enable(struct wm97xx *wm, int enable)
220{
221 u16 val;
222
223 if (enable) {
224 val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
225 wm97xx_reg_write(wm, AC97_EXTENDED_MID, val & 0x7fff);
226 wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] |
227 WM97XX_PRP_DET_DIG);
228 wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
229 } else {
230 wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] &
231 ~WM97XX_PRP_DET_DIG);
232 val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
233 wm97xx_reg_write(wm, AC97_EXTENDED_MID, val | 0x8000);
234 }
235}
236
237static void wm9713_dig_restore(struct wm97xx *wm)
238{
239 wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig_save[0]);
240 wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig_save[1]);
241 wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig_save[2]);
242}
243
244static void wm9713_aux_prepare(struct wm97xx *wm)
245{
246 memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
247 wm97xx_reg_write(wm, AC97_WM9713_DIG1, 0);
248 wm97xx_reg_write(wm, AC97_WM9713_DIG2, 0);
249 wm97xx_reg_write(wm, AC97_WM9713_DIG3, WM97XX_PRP_DET_DIG);
250}
251
252static inline int is_pden(struct wm97xx *wm)
253{
254 return wm->dig[2] & WM9713_PDEN;
255}
256
257
258
259
260static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
261{
262 u16 dig1;
263 int timeout = 5 * delay;
264
265 if (!wm->pen_probably_down) {
266 u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
267 if (!(data & WM97XX_PEN_DOWN))
268 return RC_PENUP;
269 wm->pen_probably_down = 1;
270 }
271
272
273 if (adcsel & 0x8000)
274 adcsel = 1 << ((adcsel & 0x7fff) + 3);
275
276 dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
277 dig1 &= ~WM9713_ADCSEL_MASK;
278
279 if (wm->mach_ops && wm->mach_ops->pre_sample)
280 wm->mach_ops->pre_sample(adcsel);
281 wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | adcsel | WM9713_POLL);
282
283
284 poll_delay(delay);
285
286
287 while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) &&
288 timeout) {
289 udelay(AC97_LINK_FRAME);
290 timeout--;
291 }
292
293 if (timeout <= 0) {
294
295 if (is_pden(wm))
296 wm->pen_probably_down = 0;
297 else
298 dev_dbg(wm->dev, "adc sample timeout");
299 return RC_PENUP;
300 }
301
302 *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
303 if (wm->mach_ops && wm->mach_ops->post_sample)
304 wm->mach_ops->post_sample(adcsel);
305
306
307 if ((*sample & WM97XX_ADCSRC_MASK) != ffs(adcsel >> 1) << 12) {
308 dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
309 *sample & WM97XX_ADCSRC_MASK);
310 return RC_PENUP;
311 }
312
313 if (!(*sample & WM97XX_PEN_DOWN)) {
314 wm->pen_probably_down = 0;
315 return RC_PENUP;
316 }
317
318 return RC_VALID;
319}
320
321
322
323
324static int wm9713_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
325{
326 u16 dig1;
327 int timeout = 5 * delay;
328
329 if (!wm->pen_probably_down) {
330 u16 val = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
331 if (!(val & WM97XX_PEN_DOWN))
332 return RC_PENUP;
333 wm->pen_probably_down = 1;
334 }
335
336
337 dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
338 dig1 &= ~WM9713_ADCSEL_MASK;
339 if (pil)
340 dig1 |= WM9713_ADCSEL_PRES;
341
342 if (wm->mach_ops && wm->mach_ops->pre_sample)
343 wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
344 wm97xx_reg_write(wm, AC97_WM9713_DIG1,
345 dig1 | WM9713_POLL | WM9713_COO);
346
347
348 poll_delay(delay);
349 data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
350
351 while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL)
352 && timeout) {
353 udelay(AC97_LINK_FRAME);
354 timeout--;
355 }
356
357 if (timeout <= 0) {
358
359 if (is_pden(wm))
360 wm->pen_probably_down = 0;
361 else
362 dev_dbg(wm->dev, "adc sample timeout");
363 return RC_PENUP;
364 }
365
366
367 data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
368 if (pil)
369 data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
370 else
371 data->p = DEFAULT_PRESSURE;
372
373 if (wm->mach_ops && wm->mach_ops->post_sample)
374 wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
375
376
377 if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
378 goto err;
379 if (pil && !(data->p & WM97XX_ADCSEL_PRES))
380 goto err;
381
382 if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) {
383 wm->pen_probably_down = 0;
384 return RC_PENUP;
385 }
386 return RC_VALID;
387err:
388 return 0;
389}
390
391
392
393
394static int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
395{
396 int rc;
397
398 if (coord) {
399 rc = wm9713_poll_coord(wm, data);
400 if (rc != RC_VALID)
401 return rc;
402 } else {
403 rc = wm9713_poll_sample(wm, WM9713_ADCSEL_X, &data->x);
404 if (rc != RC_VALID)
405 return rc;
406 rc = wm9713_poll_sample(wm, WM9713_ADCSEL_Y, &data->y);
407 if (rc != RC_VALID)
408 return rc;
409 if (pil) {
410 rc = wm9713_poll_sample(wm, WM9713_ADCSEL_PRES,
411 &data->p);
412 if (rc != RC_VALID)
413 return rc;
414 } else
415 data->p = DEFAULT_PRESSURE;
416 }
417 return RC_VALID;
418}
419
420
421
422
423
424static int wm9713_acc_enable(struct wm97xx *wm, int enable)
425{
426 u16 dig1, dig2, dig3;
427 int ret = 0;
428
429 dig1 = wm->dig[0];
430 dig2 = wm->dig[1];
431 dig3 = wm->dig[2];
432
433 if (enable) {
434
435 if (wm->mach_ops->acc_startup &&
436 (ret = wm->mach_ops->acc_startup(wm)) < 0)
437 return ret;
438
439 dig1 &= ~WM9713_ADCSEL_MASK;
440 dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X |
441 WM9713_ADCSEL_Y;
442 if (pil)
443 dig1 |= WM9713_ADCSEL_PRES;
444 dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK |
445 WM97XX_CM_RATE_MASK);
446 dig2 |= WM97XX_SLEN | WM97XX_DELAY(delay) |
447 WM97XX_SLT(wm->acc_slot) | WM97XX_RATE(wm->acc_rate);
448 dig3 |= WM9713_PDEN;
449 } else {
450 dig1 &= ~(WM9713_CTC | WM9713_COO);
451 dig2 &= ~WM97XX_SLEN;
452 dig3 &= ~WM9713_PDEN;
453 if (wm->mach_ops->acc_shutdown)
454 wm->mach_ops->acc_shutdown(wm);
455 }
456
457 wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
458 wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
459 wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
460
461 return ret;
462}
463
464struct wm97xx_codec_drv wm9713_codec = {
465 .id = WM9713_ID2,
466 .name = "wm9713",
467 .poll_sample = wm9713_poll_sample,
468 .poll_touch = wm9713_poll_touch,
469 .acc_enable = wm9713_acc_enable,
470 .phy_init = wm9713_phy_init,
471 .dig_enable = wm9713_dig_enable,
472 .dig_restore = wm9713_dig_restore,
473 .aux_prepare = wm9713_aux_prepare,
474};
475EXPORT_SYMBOL_GPL(wm9713_codec);
476
477
478MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
479MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
480MODULE_LICENSE("GPL");
481