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