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 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 = 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\n",
166 64000 / rpu);
167 }
168
169
170 if (five_wire) {
171 dig2 |= WM9712_45W;
172 dev_dbg(wm->dev, "setting 5-wire touchscreen mode.\n");
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.\n");
186 } else if (pil)
187 dev_dbg(wm->dev,
188 "setting pressure measurement current to 200uA.\n");
189 if (!pil)
190 pressure = 0;
191
192
193 if (delay < 0 || delay > 15) {
194 dev_dbg(wm->dev, "supplied delay out of range.\n");
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.\n",
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 bool wants_pen = adcsel & WM97XX_PEN_DOWN;
259
260 if (wants_pen && !wm->pen_probably_down) {
261 u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
262 if (!(data & WM97XX_PEN_DOWN))
263 return RC_PENUP;
264 wm->pen_probably_down = 1;
265 }
266
267
268 if (wm->mach_ops && wm->mach_ops->pre_sample)
269 wm->mach_ops->pre_sample(adcsel);
270 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK)
271 | WM97XX_POLL | WM97XX_DELAY(delay));
272
273
274 poll_delay(delay);
275
276
277 while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
278 && timeout) {
279 udelay(AC97_LINK_FRAME);
280 timeout--;
281 }
282
283 if (timeout <= 0) {
284
285 if (is_pden(wm))
286 wm->pen_probably_down = 0;
287 else
288 dev_dbg(wm->dev, "adc sample timeout\n");
289 return RC_PENUP;
290 }
291
292 *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
293 if (wm->mach_ops && wm->mach_ops->post_sample)
294 wm->mach_ops->post_sample(adcsel);
295
296
297 if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
298 dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x\n",
299 adcsel & WM97XX_ADCSEL_MASK,
300 *sample & WM97XX_ADCSEL_MASK);
301 return RC_AGAIN;
302 }
303
304 if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
305
306 *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
307 if (!(*sample & WM97XX_PEN_DOWN)) {
308 wm->pen_probably_down = 0;
309 return RC_PENUP;
310 }
311 }
312
313 return RC_VALID;
314}
315
316
317
318
319static int wm9712_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
320{
321 int timeout = 5 * delay;
322
323 if (!wm->pen_probably_down) {
324 u16 data_rd = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
325 if (!(data_rd & WM97XX_PEN_DOWN))
326 return RC_PENUP;
327 wm->pen_probably_down = 1;
328 }
329
330
331 if (wm->mach_ops && wm->mach_ops->pre_sample)
332 wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
333
334 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
335 WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay));
336
337
338 poll_delay(delay);
339 data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
340
341 while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
342 && timeout) {
343 udelay(AC97_LINK_FRAME);
344 timeout--;
345 }
346
347 if (timeout <= 0) {
348
349 if (is_pden(wm))
350 wm->pen_probably_down = 0;
351 else
352 dev_dbg(wm->dev, "adc sample timeout\n");
353 return RC_PENUP;
354 }
355
356
357 data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
358 if (pil)
359 data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
360 else
361 data->p = DEFAULT_PRESSURE;
362
363 if (wm->mach_ops && wm->mach_ops->post_sample)
364 wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
365
366
367 if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
368 goto err;
369 if (pil && !(data->p & WM97XX_ADCSEL_PRES))
370 goto err;
371
372 if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) {
373 wm->pen_probably_down = 0;
374 return RC_PENUP;
375 }
376 return RC_VALID;
377err:
378 return 0;
379}
380
381
382
383
384static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
385{
386 int rc;
387
388 if (coord) {
389 rc = wm9712_poll_coord(wm, data);
390 if (rc != RC_VALID)
391 return rc;
392 } else {
393 rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN,
394 &data->x);
395 if (rc != RC_VALID)
396 return rc;
397
398 rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN,
399 &data->y);
400 if (rc != RC_VALID)
401 return rc;
402
403 if (pil && !five_wire) {
404 rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN,
405 &data->p);
406 if (rc != RC_VALID)
407 return rc;
408 } else
409 data->p = DEFAULT_PRESSURE;
410 }
411 return RC_VALID;
412}
413
414
415
416
417
418static int wm9712_acc_enable(struct wm97xx *wm, int enable)
419{
420 u16 dig1, dig2;
421 int ret = 0;
422
423 dig1 = wm->dig[1];
424 dig2 = wm->dig[2];
425
426 if (enable) {
427
428 if (wm->mach_ops->acc_startup) {
429 ret = wm->mach_ops->acc_startup(wm);
430 if (ret < 0)
431 return ret;
432 }
433 dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
434 WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
435 dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
436 WM97XX_DELAY(delay) |
437 WM97XX_SLT(wm->acc_slot) |
438 WM97XX_RATE(wm->acc_rate);
439 if (pil)
440 dig1 |= WM97XX_ADCSEL_PRES;
441 dig2 |= WM9712_PDEN;
442 } else {
443 dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
444 dig2 &= ~WM9712_PDEN;
445 if (wm->mach_ops->acc_shutdown)
446 wm->mach_ops->acc_shutdown(wm);
447 }
448
449 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
450 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
451
452 return 0;
453}
454
455struct wm97xx_codec_drv wm9712_codec = {
456 .id = WM9712_ID2,
457 .name = "wm9712",
458 .poll_sample = wm9712_poll_sample,
459 .poll_touch = wm9712_poll_touch,
460 .acc_enable = wm9712_acc_enable,
461 .phy_init = wm9712_phy_init,
462 .dig_enable = wm9712_dig_enable,
463 .dig_restore = wm9712_dig_restore,
464 .aux_prepare = wm9712_aux_prepare,
465};
466EXPORT_SYMBOL_GPL(wm9712_codec);
467
468
469MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
470MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
471MODULE_LICENSE("GPL");
472