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 WM9712_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 = 3;
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 wm9712_phy_init(struct wm97xx *wm)
157{
158 u16 dig1 = 0;
159 u16 dig2 = WM97XX_RPR | WM9712_RPU(1);
160
161
162 if (rpu) {
163 dig2 &= 0xffc0;
164 dig2 |= WM9712_RPU(rpu);
165 dev_dbg(wm->dev, "setting pen detect pull-up to %d Ohms",
166 64000 / rpu);
167 }
168
169
170 if (five_wire) {
171 dig2 |= WM9712_45W;
172 dev_dbg(wm->dev, "setting 5-wire touchscreen mode.");
173
174 if (pil) {
175 dev_warn(wm->dev, "pressure measurement is not "
176 "supported in 5-wire mode\n");
177 pil = 0;
178 }
179 }
180
181
182 if (pil == 2) {
183 dig2 |= WM9712_PIL;
184 dev_dbg(wm->dev,
185 "setting pressure measurement current to 400uA.");
186 } else if (pil)
187 dev_dbg(wm->dev,
188 "setting pressure measurement current to 200uA.");
189 if (!pil)
190 pressure = 0;
191
192
193 if (delay < 0 || delay > 15) {
194 dev_dbg(wm->dev, "supplied delay out of range.");
195 delay = 4;
196 }
197 dig1 &= 0xff0f;
198 dig1 |= WM97XX_DELAY(delay);
199 dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
200 delay_table[delay]);
201
202
203 dig2 |= ((mask & 0x3) << 6);
204 if (mask) {
205 u16 reg;
206
207 reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
208 wm97xx_reg_write(wm, AC97_MISC_AFE, reg | WM97XX_GPIO_4);
209 reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
210 wm97xx_reg_write(wm, AC97_GPIO_CFG, reg | WM97XX_GPIO_4);
211 }
212
213
214 if (coord)
215 dig2 |= WM9712_WAIT;
216
217 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
218 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
219}
220
221static void wm9712_dig_enable(struct wm97xx *wm, int enable)
222{
223 u16 dig2 = wm->dig[2];
224
225 if (enable) {
226 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
227 dig2 | WM97XX_PRP_DET_DIG);
228 wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
229 } else
230 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
231 dig2 & ~WM97XX_PRP_DET_DIG);
232}
233
234static void wm9712_aux_prepare(struct wm97xx *wm)
235{
236 memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
237 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
238 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
239}
240
241static void wm9712_dig_restore(struct wm97xx *wm)
242{
243 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
244 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
245}
246
247static inline int is_pden(struct wm97xx *wm)
248{
249 return wm->dig[2] & WM9712_PDEN;
250}
251
252
253
254
255static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
256{
257 int timeout = 5 * delay;
258
259 if (!wm->pen_probably_down) {
260 u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
261 if (!(data & WM97XX_PEN_DOWN))
262 return RC_PENUP;
263 wm->pen_probably_down = 1;
264 }
265
266
267 if (adcsel & 0x8000)
268 adcsel = ((adcsel & 0x7fff) + 3) << 12;
269
270 if (wm->mach_ops && wm->mach_ops->pre_sample)
271 wm->mach_ops->pre_sample(adcsel);
272 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
273 adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
274
275
276 poll_delay(delay);
277
278
279 while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
280 && timeout) {
281 udelay(AC97_LINK_FRAME);
282 timeout--;
283 }
284
285 if (timeout <= 0) {
286
287 if (is_pden(wm))
288 wm->pen_probably_down = 0;
289 else
290 dev_dbg(wm->dev, "adc sample timeout");
291 return RC_PENUP;
292 }
293
294 *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
295 if (wm->mach_ops && wm->mach_ops->post_sample)
296 wm->mach_ops->post_sample(adcsel);
297
298
299 if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
300 dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
301 *sample & WM97XX_ADCSEL_MASK);
302 return RC_PENUP;
303 }
304
305 if (!(*sample & WM97XX_PEN_DOWN)) {
306 wm->pen_probably_down = 0;
307 return RC_PENUP;
308 }
309
310 return RC_VALID;
311}
312
313
314
315
316static int wm9712_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
317{
318 int timeout = 5 * delay;
319
320 if (!wm->pen_probably_down) {
321 u16 data_rd = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
322 if (!(data_rd & WM97XX_PEN_DOWN))
323 return RC_PENUP;
324 wm->pen_probably_down = 1;
325 }
326
327
328 if (wm->mach_ops && wm->mach_ops->pre_sample)
329 wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
330
331 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
332 WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay));
333
334
335 poll_delay(delay);
336 data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
337
338 while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
339 && timeout) {
340 udelay(AC97_LINK_FRAME);
341 timeout--;
342 }
343
344 if (timeout <= 0) {
345
346 if (is_pden(wm))
347 wm->pen_probably_down = 0;
348 else
349 dev_dbg(wm->dev, "adc sample timeout");
350 return RC_PENUP;
351 }
352
353
354 data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
355 if (pil)
356 data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
357 else
358 data->p = DEFAULT_PRESSURE;
359
360 if (wm->mach_ops && wm->mach_ops->post_sample)
361 wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
362
363
364 if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
365 goto err;
366 if (pil && !(data->p & WM97XX_ADCSEL_PRES))
367 goto err;
368
369 if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) {
370 wm->pen_probably_down = 0;
371 return RC_PENUP;
372 }
373 return RC_VALID;
374err:
375 return 0;
376}
377
378
379
380
381static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
382{
383 int rc;
384
385 if (coord) {
386 rc = wm9712_poll_coord(wm, data);
387 if (rc != RC_VALID)
388 return rc;
389 } else {
390 rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
391 if (rc != RC_VALID)
392 return rc;
393
394 rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
395 if (rc != RC_VALID)
396 return rc;
397
398 if (pil && !five_wire) {
399 rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES,
400 &data->p);
401 if (rc != RC_VALID)
402 return rc;
403 } else
404 data->p = DEFAULT_PRESSURE;
405 }
406 return RC_VALID;
407}
408
409
410
411
412
413static int wm9712_acc_enable(struct wm97xx *wm, int enable)
414{
415 u16 dig1, dig2;
416 int ret = 0;
417
418 dig1 = wm->dig[1];
419 dig2 = wm->dig[2];
420
421 if (enable) {
422
423 if (wm->mach_ops->acc_startup) {
424 ret = wm->mach_ops->acc_startup(wm);
425 if (ret < 0)
426 return ret;
427 }
428 dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
429 WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
430 dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
431 WM97XX_DELAY(delay) |
432 WM97XX_SLT(wm->acc_slot) |
433 WM97XX_RATE(wm->acc_rate);
434 if (pil)
435 dig1 |= WM97XX_ADCSEL_PRES;
436 dig2 |= WM9712_PDEN;
437 } else {
438 dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
439 dig2 &= ~WM9712_PDEN;
440 if (wm->mach_ops->acc_shutdown)
441 wm->mach_ops->acc_shutdown(wm);
442 }
443
444 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
445 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
446
447 return 0;
448}
449
450struct wm97xx_codec_drv wm9712_codec = {
451 .id = WM9712_ID2,
452 .name = "wm9712",
453 .poll_sample = wm9712_poll_sample,
454 .poll_touch = wm9712_poll_touch,
455 .acc_enable = wm9712_acc_enable,
456 .phy_init = wm9712_phy_init,
457 .dig_enable = wm9712_dig_enable,
458 .dig_restore = wm9712_dig_restore,
459 .aux_prepare = wm9712_aux_prepare,
460};
461EXPORT_SYMBOL_GPL(wm9712_codec);
462
463
464MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
465MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
466MODULE_LICENSE("GPL");
467