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 resistor 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 bool wants_pen = adcsel & WM97XX_PEN_DOWN;
265
266 if (wants_pen && !wm->pen_probably_down) {
267 u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
268 if (!(data & WM97XX_PEN_DOWN))
269 return RC_PENUP;
270 wm->pen_probably_down = 1;
271 }
272
273
274 dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
275 dig1 &= ~WM9713_ADCSEL_MASK;
276
277 dig1 |= 1 << ((adcsel & WM97XX_ADCSEL_MASK) >> 12);
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 | 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 ^ adcsel) & WM97XX_ADCSEL_MASK) {
308 dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
309 adcsel & WM97XX_ADCSEL_MASK,
310 *sample & WM97XX_ADCSEL_MASK);
311 return RC_PENUP;
312 }
313
314 if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
315 wm->pen_probably_down = 0;
316 return RC_PENUP;
317 }
318
319 return RC_VALID;
320}
321
322
323
324
325static int wm9713_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
326{
327 u16 dig1;
328 int timeout = 5 * delay;
329
330 if (!wm->pen_probably_down) {
331 u16 val = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
332 if (!(val & WM97XX_PEN_DOWN))
333 return RC_PENUP;
334 wm->pen_probably_down = 1;
335 }
336
337
338 dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
339 dig1 &= ~WM9713_ADCSEL_MASK;
340 if (pil)
341 dig1 |= WM9713_ADCSEL_PRES;
342
343 if (wm->mach_ops && wm->mach_ops->pre_sample)
344 wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
345 wm97xx_reg_write(wm, AC97_WM9713_DIG1,
346 dig1 | WM9713_POLL | WM9713_COO);
347
348
349 poll_delay(delay);
350 data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
351
352 while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL)
353 && timeout) {
354 udelay(AC97_LINK_FRAME);
355 timeout--;
356 }
357
358 if (timeout <= 0) {
359
360 if (is_pden(wm))
361 wm->pen_probably_down = 0;
362 else
363 dev_dbg(wm->dev, "adc sample timeout");
364 return RC_PENUP;
365 }
366
367
368 data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
369 if (pil)
370 data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
371 else
372 data->p = DEFAULT_PRESSURE;
373
374 if (wm->mach_ops && wm->mach_ops->post_sample)
375 wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
376
377
378 if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
379 goto err;
380 if (pil && !(data->p & WM97XX_ADCSEL_PRES))
381 goto err;
382
383 if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) {
384 wm->pen_probably_down = 0;
385 return RC_PENUP;
386 }
387 return RC_VALID;
388err:
389 return 0;
390}
391
392
393
394
395static int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
396{
397 int rc;
398
399 if (coord) {
400 rc = wm9713_poll_coord(wm, data);
401 if (rc != RC_VALID)
402 return rc;
403 } else {
404 rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
405 if (rc != RC_VALID)
406 return rc;
407 rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
408 if (rc != RC_VALID)
409 return rc;
410 if (pil) {
411 rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN,
412 &data->p);
413 if (rc != RC_VALID)
414 return rc;
415 } else
416 data->p = DEFAULT_PRESSURE;
417 }
418 return RC_VALID;
419}
420
421
422
423
424
425static int wm9713_acc_enable(struct wm97xx *wm, int enable)
426{
427 u16 dig1, dig2, dig3;
428 int ret = 0;
429
430 dig1 = wm->dig[0];
431 dig2 = wm->dig[1];
432 dig3 = wm->dig[2];
433
434 if (enable) {
435
436 if (wm->mach_ops->acc_startup &&
437 (ret = wm->mach_ops->acc_startup(wm)) < 0)
438 return ret;
439
440 dig1 &= ~WM9713_ADCSEL_MASK;
441 dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X |
442 WM9713_ADCSEL_Y;
443 if (pil)
444 dig1 |= WM9713_ADCSEL_PRES;
445 dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK |
446 WM97XX_CM_RATE_MASK);
447 dig2 |= WM97XX_SLEN | WM97XX_DELAY(delay) |
448 WM97XX_SLT(wm->acc_slot) | WM97XX_RATE(wm->acc_rate);
449 dig3 |= WM9713_PDEN;
450 } else {
451 dig1 &= ~(WM9713_CTC | WM9713_COO);
452 dig2 &= ~WM97XX_SLEN;
453 dig3 &= ~WM9713_PDEN;
454 if (wm->mach_ops->acc_shutdown)
455 wm->mach_ops->acc_shutdown(wm);
456 }
457
458 wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
459 wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
460 wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
461
462 return ret;
463}
464
465struct wm97xx_codec_drv wm9713_codec = {
466 .id = WM9713_ID2,
467 .name = "wm9713",
468 .poll_sample = wm9713_poll_sample,
469 .poll_touch = wm9713_poll_touch,
470 .acc_enable = wm9713_acc_enable,
471 .phy_init = wm9713_phy_init,
472 .dig_enable = wm9713_dig_enable,
473 .dig_restore = wm9713_dig_restore,
474 .aux_prepare = wm9713_aux_prepare,
475};
476EXPORT_SYMBOL_GPL(wm9713_codec);
477
478
479MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
480MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
481MODULE_LICENSE("GPL");
482