wzero3_tp.c revision 1.3 1 /* $NetBSD: wzero3_tp.c,v 1.3 2010/05/15 03:54:35 nonaka Exp $ */
2
3 /*
4 * Copyright (c) 2010 NONAKA Kimihiro <nonaka (at) netbsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: wzero3_tp.c,v 1.3 2010/05/15 03:54:35 nonaka Exp $");
31
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/malloc.h>
37 #include <sys/kernel.h>
38 #include <sys/callout.h>
39
40 #include <machine/bootinfo.h>
41 #include <machine/platid.h>
42 #include <machine/platid_mask.h>
43
44 #include <dev/wscons/wsconsio.h>
45 #include <dev/wscons/wsmousevar.h>
46 #include <dev/wscons/wsdisplayvar.h>
47
48 #include <dev/hpc/hpcfbio.h>
49 #include <dev/hpc/hpctpanelvar.h>
50
51 #include <arm/xscale/pxa2x0cpu.h>
52 #include <arm/xscale/pxa2x0reg.h>
53 #include <arm/xscale/pxa2x0var.h>
54 #include <arm/xscale/xscalereg.h>
55 #include <arm/xscale/pxa2x0_lcd.h>
56 #include <arm/xscale/pxa2x0_gpio.h>
57
58 #include <hpcarm/dev/wzero3_reg.h>
59 #include <hpcarm/dev/wzero3_sspvar.h>
60
61 #ifdef WZERO3TP_DEBUG
62 #define DPRINTF(s) printf s
63 #else
64 #define DPRINTF(s)
65 #endif
66
67 #define POLL_TIMEOUT_RATE0 ((hz * 150) / 1000)
68 #define POLL_TIMEOUT_RATE1 ((hz + 99) / 100) /* XXX every tick */
69
70 /* Settable via sysctl. */
71 int wzero3tp_rawmode;
72
73 static const struct wsmouse_calibcoords ws003sh_default_calib = {
74 0, 0, 479, 639, /* minx, miny, maxx, maxy */
75 5, /* samplelen */
76 {
77 { 2028, 2004, 240, 320 }, /* rawx, rawy, x, y */
78 { 3312, 705, 48, 64 },
79 { 3316, 3371, 48, 576 },
80 { 739, 3392, 432, 576 },
81 { 749, 673, 432, 64 },
82 }
83 };
84
85 static const struct wsmouse_calibcoords ws007sh_default_calib = {
86 0, 0, 479, 639, /* minx, miny, maxx, maxy */
87 5, /* samplelen */
88 {
89 { 2050, 2024, 240, 320 }, /* rawx, rawy, x, y */
90 { 578, 3471, 48, 64 },
91 { 578, 582, 48, 576 },
92 { 3432, 582, 432, 576 },
93 { 3432, 3471, 432, 64 },
94 }
95 };
96
97 struct wzero3tp_pos {
98 int x;
99 int y;
100 int z; /* touch pressure */
101 };
102
103 struct wzero3tp_model;
104 struct wzero3tp_softc {
105 device_t sc_dev;
106 const struct wzero3tp_model *sc_model;
107 void *sc_gh;
108 struct callout sc_tp_poll;
109 int sc_enabled;
110 int sc_buttons; /* button emulation ? */
111 struct device *sc_wsmousedev;
112 struct wzero3tp_pos sc_oldpos;
113 struct tpcalib_softc sc_tpcalib;
114 };
115
116 static void nulldrv_init(void);
117 static int nulldrv_readpos(struct wzero3tp_pos *);
118 static void nulldrv_suspend(void);
119 static void nulldrv_resume(void);
120
121 static void ws007sh_wait_for_hsync(void);
122
123 void max1233_init(void);
124 int max1233_readpos(struct wzero3tp_pos *);
125 void max1233_suspend(void);
126 void max1233_resume(void);
127
128 void ads7846_init(void);
129 int ads7846_readpos(struct wzero3tp_pos *);
130 void ads7846_suspend(void);
131 void ads7846_resume(void);
132 extern void (*ads7846_wait_for_hsync)(void);
133
134 static int wzero3tp_match(device_t, cfdata_t, void *);
135 static void wzero3tp_attach(device_t, device_t, void *);
136
137 CFATTACH_DECL_NEW(wzero3tp, sizeof(struct wzero3tp_softc),
138 wzero3tp_match, wzero3tp_attach, NULL, NULL);
139
140 static int wzero3tp_enable(void *);
141 static void wzero3tp_disable(void *);
142 static bool wzero3tp_suspend(device_t dv, const pmf_qual_t *);
143 static bool wzero3tp_resume(device_t dv, const pmf_qual_t *);
144 static void wzero3tp_poll(void *);
145 static int wzero3tp_irq(void *);
146 static int wzero3tp_ioctl(void *, u_long, void *, int, struct lwp *);
147
148 static const struct wsmouse_accessops wzero3tp_accessops = {
149 wzero3tp_enable,
150 wzero3tp_ioctl,
151 wzero3tp_disable
152 };
153
154 struct wzero3tp_model {
155 platid_mask_t *platid;
156 const char *name;
157 int intr_pin;
158 const struct wsmouse_calibcoords *calib;
159 void (*wait_for_hsync)(void);
160 struct chip {
161 void (*init)(void);
162 int (*readpos)(struct wzero3tp_pos *);
163 void (*suspend)(void);
164 void (*resume)(void);
165 } chip;
166 } wzero3tp_table[] = {
167 /* WS003SH */
168 {
169 &platid_mask_MACH_SHARP_WZERO3_WS003SH,
170 "WS003SH",
171 GPIO_WS003SH_TOUCH_PANEL,
172 &ws003sh_default_calib,
173 NULL,
174 { max1233_init, max1233_readpos,
175 max1233_suspend, max1233_resume, },
176 },
177 /* WS004SH */
178 {
179 &platid_mask_MACH_SHARP_WZERO3_WS004SH,
180 "WS004SH",
181 GPIO_WS003SH_TOUCH_PANEL,
182 &ws003sh_default_calib,
183 NULL,
184 { max1233_init, max1233_readpos,
185 max1233_suspend, max1233_resume, },
186 },
187 /* WS007SH */
188 {
189 &platid_mask_MACH_SHARP_WZERO3_WS007SH,
190 "WS007SH",
191 GPIO_WS007SH_TOUCH_PANEL,
192 &ws007sh_default_calib,
193 ws007sh_wait_for_hsync,
194 { ads7846_init, ads7846_readpos,
195 ads7846_suspend, ads7846_resume, },
196 },
197 /* WS011SH */
198 {
199 &platid_mask_MACH_SHARP_WZERO3_WS011SH,
200 "WS011SH",
201 GPIO_WS011SH_TOUCH_PANEL,
202 NULL,
203 NULL,
204 { nulldrv_init, nulldrv_readpos,
205 nulldrv_suspend, nulldrv_resume, },
206 },
207 #if 0
208 /* WS0020H */
209 {
210 &platid_mask_MACH_SHARP_WZERO3_WS020SH,
211 "WS020SH",
212 -1,
213 NULL,
214 NULL,
215 { nulldrv_init, nulldrv_readpos,
216 nulldrv_suspend, nulldrv_resume, },
217 },
218 #endif
219 {
220 NULL, NULL, -1, NULL, NULL,
221 { nulldrv_init, nulldrv_readpos,
222 nulldrv_suspend, nulldrv_resume, },
223 },
224 };
225
226 static const struct wzero3tp_model *
227 wzero3tp_lookup(void)
228 {
229 const struct wzero3tp_model *model;
230
231 for (model = wzero3tp_table; model->platid != NULL; model++) {
232 if (platid_match(&platid, model->platid)) {
233 return model;
234 }
235 }
236 return NULL;
237 }
238
239 static int
240 wzero3tp_match(device_t parent, cfdata_t cf, void *aux)
241 {
242
243 if (strcmp(cf->cf_name, "wzero3tp") != 0)
244 return 0;
245 if (wzero3tp_lookup() == NULL)
246 return 0;
247 return 1;
248 }
249
250 static void
251 wzero3tp_attach(device_t parent, device_t self, void *aux)
252 {
253 struct wzero3tp_softc *sc = device_private(self);
254 struct wsmousedev_attach_args a;
255
256 sc->sc_dev = self;
257
258 aprint_normal(": touch panel\n");
259 aprint_naive("\n");
260
261 sc->sc_model = wzero3tp_lookup();
262 if (sc->sc_model == NULL) {
263 aprint_error_dev(self, "unknown model\n");
264 return;
265 }
266
267 callout_init(&sc->sc_tp_poll, 0);
268 callout_setfunc(&sc->sc_tp_poll, wzero3tp_poll, sc);
269
270 if (sc->sc_model->wait_for_hsync)
271 ads7846_wait_for_hsync = sc->sc_model->wait_for_hsync;
272
273 (*sc->sc_model->chip.init)();
274
275 a.accessops = &wzero3tp_accessops;
276 a.accesscookie = sc;
277
278 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
279
280 /* Initialize calibration, set default parameters. */
281 tpcalib_init(&sc->sc_tpcalib);
282 if (sc->sc_model->calib) {
283 tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
284 __UNCONST(sc->sc_model->calib), 0, 0);
285 }
286 }
287
288 static int
289 wzero3tp_enable(void *v)
290 {
291 struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v;
292
293 DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__));
294
295 if (sc->sc_enabled) {
296 DPRINTF(("%s: already enabled\n", device_xname(sc->sc_dev)));
297 return EBUSY;
298 }
299
300 callout_stop(&sc->sc_tp_poll);
301
302 if (!pmf_device_register(sc->sc_dev, wzero3tp_suspend, wzero3tp_resume))
303 aprint_error_dev(sc->sc_dev,
304 "couldn't establish power handler\n");
305
306 pxa2x0_gpio_set_function(sc->sc_model->intr_pin, GPIO_IN);
307
308 /* XXX */
309 if (sc->sc_gh == NULL) {
310 sc->sc_gh = pxa2x0_gpio_intr_establish(
311 sc->sc_model->intr_pin, IST_EDGE_FALLING, IPL_TTY,
312 wzero3tp_irq, sc);
313 } else {
314 pxa2x0_gpio_intr_unmask(sc->sc_gh);
315 }
316
317 /* enable interrupts */
318 sc->sc_enabled = 1;
319 sc->sc_buttons = 0;
320
321 return 0;
322 }
323
324 static void
325 wzero3tp_disable(void *v)
326 {
327 struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v;
328
329 DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__));
330
331 callout_stop(&sc->sc_tp_poll);
332
333 pmf_device_deregister(sc->sc_dev);
334
335 pxa2x0_gpio_intr_mask(sc->sc_gh);
336
337 /* disable interrupts */
338 sc->sc_enabled = 0;
339 }
340
341 static bool
342 wzero3tp_suspend(device_t dv, const pmf_qual_t *qual)
343 {
344 struct wzero3tp_softc *sc = device_private(dv);
345
346 DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__));
347
348 sc->sc_enabled = 0;
349 pxa2x0_gpio_intr_mask(sc->sc_gh);
350
351 callout_stop(&sc->sc_tp_poll);
352
353 (*sc->sc_model->chip.suspend)();
354
355 pxa2x0_gpio_set_function(sc->sc_model->intr_pin, GPIO_OUT|GPIO_SET);
356
357 return true;
358 }
359
360 static bool
361 wzero3tp_resume(device_t dv, const pmf_qual_t *qual)
362 {
363 struct wzero3tp_softc *sc = device_private(dv);
364
365 DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__));
366
367 pxa2x0_gpio_set_function(sc->sc_model->intr_pin, GPIO_IN);
368 pxa2x0_gpio_intr_mask(sc->sc_gh);
369
370 (*sc->sc_model->chip.resume)();
371
372 pxa2x0_gpio_intr_unmask(sc->sc_gh);
373 sc->sc_enabled = 1;
374
375 return true;
376 }
377
378 static void
379 wzero3tp_poll(void *v)
380 {
381 int s;
382
383 s = spltty();
384 (void)wzero3tp_irq(v);
385 splx(s);
386 }
387
388 static int
389 wzero3tp_irq(void *v)
390 {
391 struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v;
392 struct wzero3tp_pos tp = { 0, 0, 0 };
393 int pindown;
394 int down;
395 int x, y;
396 int s;
397
398 if (!sc->sc_enabled)
399 return 0;
400
401 s = splhigh();
402
403 pindown = pxa2x0_gpio_get_bit(sc->sc_model->intr_pin) ? 0 : 1;
404 DPRINTF(("%s: pindown = %d\n", device_xname(sc->sc_dev), pindown));
405 if (pindown) {
406 pxa2x0_gpio_intr_mask(sc->sc_gh);
407 callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE1);
408 }
409
410 down = (*sc->sc_model->chip.readpos)(&tp);
411 DPRINTF(("%s: x = %d, y = %d, z = %d, down = %d\n",
412 device_xname(sc->sc_dev), tp.x, tp.y, tp.z, down));
413
414 if (!pindown) {
415 pxa2x0_gpio_intr_unmask(sc->sc_gh);
416 callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE0);
417 }
418 pxa2x0_gpio_clear_intr(sc->sc_model->intr_pin);
419
420 splx(s);
421
422 if (down) {
423 if (!wzero3tp_rawmode) {
424 tpcalib_trans(&sc->sc_tpcalib, tp.x, tp.y, &x, &y);
425 DPRINTF(("%s: x = %d, y = %d\n",
426 device_xname(sc->sc_dev), x, y));
427 tp.x = x;
428 tp.y = y;
429 }
430 }
431
432 if (!down) {
433 /* x/y values are not reliable when pen is up */
434 tp = sc->sc_oldpos;
435 }
436
437 if (down || sc->sc_buttons != down) {
438 wsmouse_input(sc->sc_wsmousedev, down, tp.x, tp.y, 0, 0,
439 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
440 sc->sc_buttons = down;
441 sc->sc_oldpos = tp;
442 }
443
444 return 1;
445 }
446
447 static int
448 wzero3tp_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
449 {
450 struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v;
451 struct wsmouse_id *id;
452
453 switch (cmd) {
454 case WSMOUSEIO_GTYPE:
455 *(u_int *)data = WSMOUSE_TYPE_TPANEL;
456 return 0;
457
458 case WSMOUSEIO_GETID:
459 /*
460 * return unique ID string,
461 * "<vendor> <model> <serial number>"
462 */
463 id = (struct wsmouse_id *)data;
464 if (id->type != WSMOUSE_ID_TYPE_UIDSTR)
465 return EINVAL;
466 snprintf(id->data, WSMOUSE_ID_MAXLEN, "Sharp %s SN000000",
467 sc->sc_model->name);
468 id->length = strlen(id->data);
469 return 0;
470
471 case WSMOUSEIO_SCALIBCOORDS:
472 case WSMOUSEIO_GCALIBCOORDS:
473 return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
474 }
475
476 return EPASSTHROUGH;
477 }
478
479 /*----------------------------------------------------------------------------
480 * null driver
481 */
482 static void
483 nulldrv_init(void)
484 {
485
486 /* Nothing to do */
487 }
488
489 static int
490 nulldrv_readpos(struct wzero3tp_pos *pos)
491 {
492
493 pos->x = 0;
494 pos->y = 0;
495 pos->z = 0;
496
497 return 0;
498 }
499
500 static void
501 nulldrv_suspend(void)
502 {
503
504 /* Nothing to do */
505 }
506
507 static void
508 nulldrv_resume(void)
509 {
510
511 /* Nothing to do */
512 }
513
514 /*----------------------------------------------------------------------------
515 * model specific functions
516 */
517 static void
518 ws007sh_wait_for_hsync(void)
519 {
520
521 while (pxa2x0_gpio_get_bit(GPIO_WS007SH_HSYNC) == 0)
522 continue;
523 while (pxa2x0_gpio_get_bit(GPIO_WS007SH_HSYNC) != 0)
524 continue;
525 }
526
527 /*----------------------------------------------------------------------------
528 * MAX1233 touch screen controller for WS003SH/WS004SH
529 */
530 #define MAXCTRL_ADDR_SH 0 /* Address bit[5:0] */
531 #define MAXCTRL_PAGE_SH 6 /* Page bit (0:Data/1:Control) */
532 #define MAXCTRL_RW_SH 15 /* R/W bit (0:Write/1:Read) */
533
534 /* VREF=2.5V, sets interrupt initiated touch-screen scans
535 * 3.5us/sample, 4 data ave., settling time: 100us */
536 #define MAX1233_ADCCTRL 0x8b43
537
538 void
539 max1233_init(void)
540 {
541
542 /* Enable automatic low power mode. */
543 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
544 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
545 0x0001);
546 /* Wait for touch */
547 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
548 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
549 MAX1233_ADCCTRL);
550 }
551
552 void
553 max1233_suspend(void)
554 {
555
556 /* power down. */
557 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
558 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
559 0xc000);
560 /* DAC off */
561 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
562 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),
563 0x8000);
564 }
565
566 void
567 max1233_resume(void)
568 {
569
570 /* Enable automatic low power mode. */
571 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
572 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
573 0x0001);
574 /* Wait for touch */
575 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
576 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
577 MAX1233_ADCCTRL);
578 /* DAC on */
579 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
580 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),
581 0x0000);
582 }
583
584 int
585 max1233_readpos(struct wzero3tp_pos *pos)
586 {
587 uint32_t z1 = 0, z2 = 0, rt;
588 uint32_t status;
589 int down;
590
591 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
592 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
593 0x0bf3);
594
595 while ((status = (wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
596 (1<<MAXCTRL_RW_SH)
597 | (1<<MAXCTRL_PAGE_SH)
598 | (0<<MAXCTRL_ADDR_SH), 0) & 0x4000)) != 0x4000) {
599 DPRINTF(("%s: status=%#x\n", __func__, status));
600 }
601 DPRINTF(("%s: status=%#x\n", __func__, status));
602
603 z1 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
604 (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),0);
605 DPRINTF(("%s: first z1=%d\n", __func__, z1));
606
607 down = (z1 >= 10);
608 if (!down)
609 goto out;
610
611 pos->x = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
612 (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),0);
613 DPRINTF(("%s: x=%d\n", __func__, pos->x));
614 pos->y = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
615 (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (1<<MAXCTRL_ADDR_SH),0);
616 DPRINTF(("%s: y=%d\n", __func__, pos->y));
617 z1 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
618 (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),0);
619 DPRINTF(("%s: z1=%d\n", __func__, z1));
620 z2 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
621 (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (3<<MAXCTRL_ADDR_SH),0);
622 DPRINTF(("%s: z2=%d\n", __func__, z2));
623
624 if (z1) {
625 rt = 400/*XXX*/;
626 rt *= pos->x;
627 rt *= (z2 / z1) - 1;
628 rt >>= 12;
629 } else
630 rt = 0;
631 DPRINTF(("%s: rt=%d\n", __func__, rt));
632
633 /* check that pen is still down */
634 if (z1 == 0 || rt == 0)
635 down = 0;
636 pos->z = down;
637
638 out:
639 return down;
640 }
641
642 /*----------------------------------------------------------------------------
643 * ADS7846/TSC2046 touch screen controller for WS007SH
644 */
645 #define ADSCTRL_PD0_SH 0 /* PD0 bit */
646 #define ADSCTRL_PD1_SH 1 /* PD1 bit */
647 #define ADSCTRL_DFR_SH 2 /* SER/DFR bit */
648 #define ADSCTRL_MOD_SH 3 /* Mode bit */
649 #define ADSCTRL_ADR_SH 4 /* Address setting */
650 #define ADSCTRL_STS_SH 7 /* Start bit */
651
652 static uint32_t ads7846_sync(int, int, uint32_t);
653
654 void
655 ads7846_init(void)
656 {
657
658 /* Enable automatic low power mode. */
659 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846,
660 (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0);
661 }
662
663 void
664 ads7846_suspend(void)
665 {
666
667 /* Turn off reference voltage but leave ADC on. */
668 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846,
669 (1<<ADSCTRL_PD1_SH) | (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0);
670 }
671
672 void
673 ads7846_resume(void)
674 {
675
676 /* Enable automatic low power mode. */
677 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846,
678 (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0);
679 }
680
681 int
682 ads7846_readpos(struct wzero3tp_pos *pos)
683 {
684 int cmd, cmd0;
685 int z0, z1;
686 int down;
687
688 cmd0 = (1<<ADSCTRL_STS_SH) | (1<<ADSCTRL_PD0_SH) | (1<<ADSCTRL_PD1_SH);
689
690 /* check that pen is down */
691 cmd = cmd0 | (3<<ADSCTRL_ADR_SH);
692 z0 = wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0);
693 DPRINTF(("%s: first z0 = %d\n", __func__, z0));
694
695 down = (z0 >= 10);
696 if (!down)
697 goto out;
698
699 /* Y (discard) */
700 cmd = cmd0 | (1<<ADSCTRL_ADR_SH);
701 (void)ads7846_sync(0, 1, cmd);
702
703 /* Y */
704 cmd = cmd0 | (1<<ADSCTRL_ADR_SH);
705 (void)ads7846_sync(1, 1, cmd);
706
707 /* X */
708 cmd = cmd0 | (5<<ADSCTRL_ADR_SH);
709 pos->y = ads7846_sync(1, 1, cmd);
710 DPRINTF(("%s: y = %d\n", __func__, pos->y));
711
712 /* Z0 */
713 cmd = cmd0 | (3<<ADSCTRL_ADR_SH);
714 pos->x = ads7846_sync(1, 1, cmd);
715 DPRINTF(("%s: x = %d\n", __func__, pos->x));
716
717 /* Z1 */
718 cmd = cmd0 | (4<<ADSCTRL_ADR_SH);
719 z0 = ads7846_sync(1, 1, cmd);
720 z1 = ads7846_sync(1, 0, cmd);
721 DPRINTF(("%s: z0 = %d, z1 = %d\n", __func__, z0, z1));
722
723 /* check that pen is still down */
724 if (z0 == 0 || (pos->x * (z1 - z0) / z0) >= 15000)
725 down = 0;
726 pos->z = down;
727
728 out:
729 /* Enable automatic low power mode. */
730 cmd = (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH);
731 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0);
732
733 return down;
734 }
735
736 void (*ads7846_wait_for_hsync)(void);
737
738 /*
739 * Communicate synchronously with the ADS784x touch screen controller.
740 */
741 static uint32_t
742 ads7846_sync(int dorecv, int dosend, uint32_t cmd)
743 {
744 uint32_t rv = 0;
745
746 if (ads7846_wait_for_hsync)
747 (*ads7846_wait_for_hsync)();
748
749 if (dorecv)
750 rv = wzero3ssp_ic_stop(WZERO3_SSP_IC_ADS7846);
751
752 if (dosend) {
753 /* send dummy command; discard SSDR */
754 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0);
755
756 /* wait for refresh */
757 if (ads7846_wait_for_hsync)
758 (*ads7846_wait_for_hsync)();
759
760 /* send the actual command; keep ADS784x enabled */
761 wzero3ssp_ic_start(WZERO3_SSP_IC_ADS7846, cmd);
762 }
763
764 return rv;
765 }
766