xref: /netbsd-src/sys/arch/hpcarm/dev/wzero3_tp.c (revision 5c46dd73a9bcb28b2994504ea090f64066b17a77)
1 /*	$NetBSD: wzero3_tp.c,v 1.5 2010/05/30 10:00:27 nonaka Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 NONAKA Kimihiro <nonaka@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.5 2010/05/30 10:00:27 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 static const struct wsmouse_calibcoords ws011sh_default_calib = {
98 	0, 0, 479, 799,				/* minx, miny, maxx, maxy */
99 	5,					/* samplelen */
100 	{
101 		{ 2126, 2048, 240, 400 },	/* rawx, rawy, x, y */
102 		{  527, 3464,  48,  80 },
103 		{ 3628, 3376,  48, 720 },
104 		{ 3351,  595, 432, 720 },
105 		{  554,  562, 432,  80 },
106 	}
107 };
108 
109 struct wzero3tp_pos {
110 	int x;
111 	int y;
112 	int z;			/* touch pressure */
113 };
114 
115 struct wzero3tp_model;
116 struct wzero3tp_softc {
117 	device_t sc_dev;
118 	const struct wzero3tp_model *sc_model;
119 	void *sc_gh;
120 	struct callout sc_tp_poll;
121 	int sc_enabled;
122 	int sc_buttons; /* button emulation ? */
123 	struct device *sc_wsmousedev;
124 	struct wzero3tp_pos sc_oldpos;
125 	struct tpcalib_softc sc_tpcalib;
126 };
127 
128 static void nulldrv_init(void);
129 static int nulldrv_readpos(struct wzero3tp_pos *);
130 static void nulldrv_suspend(void);
131 static void nulldrv_resume(void);
132 
133 static void ws007sh_wait_for_hsync(void);
134 
135 void max1233_init(void);
136 int max1233_readpos(struct wzero3tp_pos *);
137 void max1233_suspend(void);
138 void max1233_resume(void);
139 
140 void ads7846_init(void);
141 int ads7846_readpos(struct wzero3tp_pos *);
142 void ads7846_suspend(void);
143 void ads7846_resume(void);
144 extern void (*ads7846_wait_for_hsync)(void);
145 
146 void ak4184_init(void);
147 int ak4184_readpos(struct wzero3tp_pos *);
148 void ak4184_suspend(void);
149 void ak4184_resume(void);
150 
151 static int	wzero3tp_match(device_t, cfdata_t, void *);
152 static void	wzero3tp_attach(device_t, device_t, void *);
153 
154 CFATTACH_DECL_NEW(wzero3tp, sizeof(struct wzero3tp_softc),
155 	wzero3tp_match, wzero3tp_attach, NULL, NULL);
156 
157 static int	wzero3tp_enable(void *);
158 static void	wzero3tp_disable(void *);
159 static bool	wzero3tp_suspend(device_t dv, const pmf_qual_t *);
160 static bool	wzero3tp_resume(device_t dv, const pmf_qual_t *);
161 static void	wzero3tp_poll(void *);
162 static int	wzero3tp_irq(void *);
163 static int	wzero3tp_ioctl(void *, u_long, void *, int, struct lwp *);
164 
165 static const struct wsmouse_accessops wzero3tp_accessops = {
166         wzero3tp_enable,
167 	wzero3tp_ioctl,
168 	wzero3tp_disable
169 };
170 
171 struct wzero3tp_model {
172 	platid_mask_t *platid;
173 	const char *name;
174 	int intr_pin;
175 	const struct wsmouse_calibcoords *calib;
176 	void (*wait_for_hsync)(void);
177 	struct chip {
178 		void (*init)(void);
179 		int (*readpos)(struct wzero3tp_pos *);
180 		void (*suspend)(void);
181 		void (*resume)(void);
182 	} chip;
183 } wzero3tp_table[] = {
184 	/* WS003SH */
185 	{
186 		&platid_mask_MACH_SHARP_WZERO3_WS003SH,
187 		"WS003SH",
188 		GPIO_WS003SH_TOUCH_PANEL,
189 		&ws003sh_default_calib,
190 		NULL,
191 		{ max1233_init, max1233_readpos,
192 		  max1233_suspend, max1233_resume, },
193 	},
194 	/* WS004SH */
195 	{
196 		&platid_mask_MACH_SHARP_WZERO3_WS004SH,
197 		"WS004SH",
198 		GPIO_WS003SH_TOUCH_PANEL,
199 		&ws003sh_default_calib,
200 		NULL,
201 		{ max1233_init, max1233_readpos,
202 		  max1233_suspend, max1233_resume, },
203 	},
204 	/* WS007SH */
205 	{
206 		&platid_mask_MACH_SHARP_WZERO3_WS007SH,
207 		"WS007SH",
208 		GPIO_WS007SH_TOUCH_PANEL,
209 		&ws007sh_default_calib,
210 		ws007sh_wait_for_hsync,
211 		{ ads7846_init, ads7846_readpos,
212 		  ads7846_suspend, ads7846_resume, },
213 	},
214 	/* WS011SH */
215 	{
216 		&platid_mask_MACH_SHARP_WZERO3_WS011SH,
217 		"WS011SH",
218 		GPIO_WS011SH_TOUCH_PANEL,
219 		&ws011sh_default_calib,
220 		NULL,
221 		{ ak4184_init, ak4184_readpos,
222 		  ak4184_suspend, ak4184_resume, },
223 	},
224 #if 0
225 	/* WS0020H */
226 	{
227 		&platid_mask_MACH_SHARP_WZERO3_WS020SH,
228 		"WS020SH",
229 		-1,
230 		NULL,
231 		NULL,
232 		{ nulldrv_init, nulldrv_readpos,
233 		  nulldrv_suspend, nulldrv_resume, },
234 	},
235 #endif
236 	{
237 		NULL, NULL, -1, NULL, NULL,
238 		{ nulldrv_init, nulldrv_readpos,
239 		  nulldrv_suspend, nulldrv_resume, },
240 	},
241 };
242 
243 static const struct wzero3tp_model *
244 wzero3tp_lookup(void)
245 {
246 	const struct wzero3tp_model *model;
247 
248 	for (model = wzero3tp_table; model->platid != NULL; model++) {
249 		if (platid_match(&platid, model->platid)) {
250 			return model;
251 		}
252 	}
253 	return NULL;
254 }
255 
256 static int
257 wzero3tp_match(device_t parent, cfdata_t cf, void *aux)
258 {
259 
260 	if (strcmp(cf->cf_name, "wzero3tp") != 0)
261 		return 0;
262 	if (wzero3tp_lookup() == NULL)
263 		return 0;
264 	return 1;
265 }
266 
267 static void
268 wzero3tp_attach(device_t parent, device_t self, void *aux)
269 {
270 	struct wzero3tp_softc *sc = device_private(self);
271 	struct wsmousedev_attach_args a;
272 
273 	sc->sc_dev = self;
274 
275 	aprint_normal(": touch panel\n");
276 	aprint_naive("\n");
277 
278 	sc->sc_model = wzero3tp_lookup();
279 	if (sc->sc_model == NULL) {
280 		aprint_error_dev(self, "unknown model\n");
281 		return;
282 	}
283 
284 	callout_init(&sc->sc_tp_poll, 0);
285 	callout_setfunc(&sc->sc_tp_poll, wzero3tp_poll, sc);
286 
287 	if (sc->sc_model->wait_for_hsync)
288 		ads7846_wait_for_hsync = sc->sc_model->wait_for_hsync;
289 
290 	(*sc->sc_model->chip.init)();
291 
292 	a.accessops = &wzero3tp_accessops;
293 	a.accesscookie = sc;
294 
295 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
296 
297 	/* Initialize calibration, set default parameters. */
298 	tpcalib_init(&sc->sc_tpcalib);
299 	if (sc->sc_model->calib) {
300 		tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
301 		    __UNCONST(sc->sc_model->calib), 0, 0);
302 	}
303 }
304 
305 static int
306 wzero3tp_enable(void *v)
307 {
308 	struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v;
309 
310 	DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__));
311 
312 	if (sc->sc_enabled) {
313 		DPRINTF(("%s: already enabled\n", device_xname(sc->sc_dev)));
314 		return EBUSY;
315 	}
316 
317 	callout_stop(&sc->sc_tp_poll);
318 
319 	if (!pmf_device_register(sc->sc_dev, wzero3tp_suspend, wzero3tp_resume))
320 		aprint_error_dev(sc->sc_dev,
321 		    "couldn't establish power handler\n");
322 
323 	pxa2x0_gpio_set_function(sc->sc_model->intr_pin, GPIO_IN);
324 
325 	/* XXX */
326 	if (sc->sc_gh == NULL) {
327 		sc->sc_gh = pxa2x0_gpio_intr_establish(
328 		    sc->sc_model->intr_pin, IST_EDGE_FALLING, IPL_TTY,
329 		    wzero3tp_irq, sc);
330 	} else {
331 		pxa2x0_gpio_intr_unmask(sc->sc_gh);
332 	}
333 
334 	/* enable interrupts */
335 	sc->sc_enabled = 1;
336 	sc->sc_buttons = 0;
337 
338 	return 0;
339 }
340 
341 static void
342 wzero3tp_disable(void *v)
343 {
344 	struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v;
345 
346 	DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__));
347 
348 	callout_stop(&sc->sc_tp_poll);
349 
350 	pmf_device_deregister(sc->sc_dev);
351 
352 	pxa2x0_gpio_intr_mask(sc->sc_gh);
353 
354 	/* disable interrupts */
355 	sc->sc_enabled = 0;
356 }
357 
358 static bool
359 wzero3tp_suspend(device_t dv, const pmf_qual_t *qual)
360 {
361 	struct wzero3tp_softc *sc = device_private(dv);
362 
363 	DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__));
364 
365 	sc->sc_enabled = 0;
366 	pxa2x0_gpio_intr_mask(sc->sc_gh);
367 
368 	callout_stop(&sc->sc_tp_poll);
369 
370 	(*sc->sc_model->chip.suspend)();
371 
372 	pxa2x0_gpio_set_function(sc->sc_model->intr_pin, GPIO_OUT|GPIO_SET);
373 
374 	return true;
375 }
376 
377 static bool
378 wzero3tp_resume(device_t dv, const pmf_qual_t *qual)
379 {
380 	struct wzero3tp_softc *sc = device_private(dv);
381 
382 	DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__));
383 
384 	pxa2x0_gpio_set_function(sc->sc_model->intr_pin, GPIO_IN);
385 	pxa2x0_gpio_intr_mask(sc->sc_gh);
386 
387 	(*sc->sc_model->chip.resume)();
388 
389 	pxa2x0_gpio_intr_unmask(sc->sc_gh);
390 	sc->sc_enabled = 1;
391 
392 	return true;
393 }
394 
395 static void
396 wzero3tp_poll(void *v)
397 {
398 	int s;
399 
400 	s = spltty();
401 	(void)wzero3tp_irq(v);
402 	splx(s);
403 }
404 
405 static int
406 wzero3tp_irq(void *v)
407 {
408 	struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v;
409 	struct wzero3tp_pos tp = { 0, 0, 0 };
410 	int pindown;
411 	int down;
412 	int x, y;
413 	int s;
414 
415 	if (!sc->sc_enabled)
416 		return 0;
417 
418 	s = splhigh();
419 
420 	pindown = pxa2x0_gpio_get_bit(sc->sc_model->intr_pin) ? 0 : 1;
421 	DPRINTF(("%s: pindown = %d\n", device_xname(sc->sc_dev), pindown));
422 	if (pindown) {
423 		pxa2x0_gpio_intr_mask(sc->sc_gh);
424 		callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE1);
425 	}
426 
427 	down = (*sc->sc_model->chip.readpos)(&tp);
428 	DPRINTF(("%s: x = %d, y = %d, z = %d, down = %d\n",
429 	    device_xname(sc->sc_dev), tp.x, tp.y, tp.z, down));
430 
431 	if (!pindown) {
432 		pxa2x0_gpio_intr_unmask(sc->sc_gh);
433 		callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE0);
434 	}
435 	pxa2x0_gpio_clear_intr(sc->sc_model->intr_pin);
436 
437 	splx(s);
438 
439 	if (down) {
440 		if (!wzero3tp_rawmode) {
441 			tpcalib_trans(&sc->sc_tpcalib, tp.x, tp.y, &x, &y);
442 			DPRINTF(("%s: x = %d, y = %d\n",
443 			    device_xname(sc->sc_dev), x, y));
444 			tp.x = x;
445 			tp.y = y;
446 		}
447 	}
448 
449 	if (!down) {
450 		/* x/y values are not reliable when pen is up */
451 		tp = sc->sc_oldpos;
452 	}
453 
454 	if (down || sc->sc_buttons != down) {
455 		wsmouse_input(sc->sc_wsmousedev, down, tp.x, tp.y, 0, 0,
456 		    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
457 		sc->sc_buttons = down;
458 		sc->sc_oldpos = tp;
459 	}
460 
461 	return 1;
462 }
463 
464 static int
465 wzero3tp_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
466 {
467 	struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v;
468 	struct wsmouse_id *id;
469 
470 	switch (cmd) {
471 	case WSMOUSEIO_GTYPE:
472 		*(u_int *)data = WSMOUSE_TYPE_TPANEL;
473 		return 0;
474 
475 	case WSMOUSEIO_GETID:
476 		/*
477 		 * return unique ID string,
478 		 * "<vendor> <model> <serial number>"
479 		 */
480 		id = (struct wsmouse_id *)data;
481 		if (id->type != WSMOUSE_ID_TYPE_UIDSTR)
482 			return EINVAL;
483 		snprintf(id->data, WSMOUSE_ID_MAXLEN, "Sharp %s SN000000",
484 		    sc->sc_model->name);
485 		id->length = strlen(id->data);
486 		return 0;
487 
488 	case WSMOUSEIO_SCALIBCOORDS:
489 	case WSMOUSEIO_GCALIBCOORDS:
490 		return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
491 	}
492 
493 	return EPASSTHROUGH;
494 }
495 
496 /*----------------------------------------------------------------------------
497  * null driver
498  */
499 static void
500 nulldrv_init(void)
501 {
502 
503 	/* Nothing to do */
504 }
505 
506 static int
507 nulldrv_readpos(struct wzero3tp_pos *pos)
508 {
509 
510 	pos->x = 0;
511 	pos->y = 0;
512 	pos->z = 0;
513 
514 	return 0;
515 }
516 
517 static void
518 nulldrv_suspend(void)
519 {
520 
521 	/* Nothing to do */
522 }
523 
524 static void
525 nulldrv_resume(void)
526 {
527 
528 	/* Nothing to do */
529 }
530 
531 /*----------------------------------------------------------------------------
532  * model specific functions
533  */
534 static void
535 ws007sh_wait_for_hsync(void)
536 {
537 
538 	while (pxa2x0_gpio_get_bit(GPIO_WS007SH_HSYNC) == 0)
539 		continue;
540 	while (pxa2x0_gpio_get_bit(GPIO_WS007SH_HSYNC) != 0)
541 		continue;
542 }
543 
544 /*----------------------------------------------------------------------------
545  * MAX1233 touch screen controller for WS003SH/WS004SH
546  */
547 #define	MAXCTRL_ADDR_SH		0	/* Address bit[5:0] */
548 #define	MAXCTRL_PAGE_SH		6	/* Page bit (0:Data/1:Control) */
549 #define	MAXCTRL_RW_SH		15	/* R/W bit (0:Write/1:Read) */
550 
551 /* VREF=2.5V, sets interrupt initiated touch-screen scans
552  * 3.5us/sample, 4 data ave., settling time: 100us */
553 #define	MAX1233_ADCCTRL		0x8b43
554 
555 void
556 max1233_init(void)
557 {
558 
559 	/* Enable automatic low power mode. */
560 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
561 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
562 	    0x0001);
563 	/* Wait for touch */
564 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
565 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
566 	    MAX1233_ADCCTRL);
567 }
568 
569 void
570 max1233_suspend(void)
571 {
572 
573 	/* power down. */
574 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
575 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
576 	    0xc000);
577 	/* DAC off */
578 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
579 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),
580 	    0x8000);
581 }
582 
583 void
584 max1233_resume(void)
585 {
586 
587 	/* Enable automatic low power mode. */
588 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
589 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
590 	    0x0001);
591 	/* Wait for touch */
592 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
593 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
594 	    MAX1233_ADCCTRL);
595 	/* DAC on */
596 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
597 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),
598 	    0x0000);
599 }
600 
601 int
602 max1233_readpos(struct wzero3tp_pos *pos)
603 {
604 	uint32_t z1 = 0, z2 = 0, rt;
605 	uint32_t status;
606 	int down;
607 
608 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
609 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
610 	    0x0bf3);
611 
612 	while ((status = (wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
613 		    (1<<MAXCTRL_RW_SH)
614 		    | (1<<MAXCTRL_PAGE_SH)
615 		    | (0<<MAXCTRL_ADDR_SH), 0) & 0x4000)) != 0x4000) {
616 		DPRINTF(("%s: status=%#x\n", __func__, status));
617 	}
618 	DPRINTF(("%s: status=%#x\n", __func__, status));
619 
620 	z1 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
621 	    (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),0);
622 	DPRINTF(("%s: first z1=%d\n", __func__, z1));
623 
624 	down = (z1 >= 10);
625 	if (!down)
626 		goto out;
627 
628 	pos->x = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
629 	    (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),0);
630 	DPRINTF(("%s: x=%d\n", __func__, pos->x));
631 	pos->y = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
632 	    (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (1<<MAXCTRL_ADDR_SH),0);
633 	DPRINTF(("%s: y=%d\n", __func__, pos->y));
634 	z1 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
635 	    (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),0);
636 	DPRINTF(("%s: z1=%d\n", __func__, z1));
637 	z2 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
638 	    (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (3<<MAXCTRL_ADDR_SH),0);
639 	DPRINTF(("%s: z2=%d\n", __func__, z2));
640 
641 	if (z1) {
642 		rt = 400 /* XXX: X plate ohms */;
643 		rt *= pos->x;
644 		rt *= (z2 / z1) - 1;
645 		rt >>= 12;
646 	} else
647 		rt = 0;
648 	DPRINTF(("%s: rt=%d\n", __func__, rt));
649 
650 	/* check that pen is still down */
651 	if (z1 == 0 || rt == 0)
652 		down = 0;
653 	pos->z = down;
654 
655 out:
656 	return down;
657 }
658 
659 /*----------------------------------------------------------------------------
660  * ADS7846/TSC2046 touch screen controller for WS007SH
661  */
662 #define ADSCTRL_PD0_SH		0	/* PD0 bit */
663 #define ADSCTRL_PD1_SH		1	/* PD1 bit */
664 #define ADSCTRL_DFR_SH		2	/* SER/DFR bit */
665 #define ADSCTRL_MOD_SH		3	/* Mode bit */
666 #define ADSCTRL_ADR_SH		4	/* Address setting */
667 #define ADSCTRL_STS_SH		7	/* Start bit */
668 
669 static uint32_t ads7846_sync(int, int, uint32_t);
670 
671 void
672 ads7846_init(void)
673 {
674 
675 	/* Enable automatic low power mode. */
676 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846,
677 	    (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0);
678 }
679 
680 void
681 ads7846_suspend(void)
682 {
683 
684 	/* Turn off reference voltage but leave ADC on. */
685 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846,
686 	    (1<<ADSCTRL_PD1_SH) | (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0);
687 }
688 
689 void
690 ads7846_resume(void)
691 {
692 
693 	/* Enable automatic low power mode. */
694 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846,
695 	    (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0);
696 }
697 
698 int
699 ads7846_readpos(struct wzero3tp_pos *pos)
700 {
701 	int cmd, cmd0;
702 	int z0, z1;
703 	int down;
704 
705 	cmd0 = (1<<ADSCTRL_STS_SH) | (1<<ADSCTRL_PD0_SH) | (1<<ADSCTRL_PD1_SH);
706 
707 	/* check that pen is down */
708 	cmd = cmd0 | (3<<ADSCTRL_ADR_SH);
709 	z0 = wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0);
710 	DPRINTF(("%s: first z0 = %d\n", __func__, z0));
711 
712 	down = (z0 >= 10);
713 	if (!down)
714 		goto out;
715 
716 	/* Y (discard) */
717 	cmd = cmd0 | (1<<ADSCTRL_ADR_SH);
718 	(void)ads7846_sync(0, 1, cmd);
719 
720 	/* Y */
721 	cmd = cmd0 | (1<<ADSCTRL_ADR_SH);
722 	(void)ads7846_sync(1, 1, cmd);
723 
724 	/* X */
725 	cmd = cmd0 | (5<<ADSCTRL_ADR_SH);
726 	pos->y = ads7846_sync(1, 1, cmd);
727 	DPRINTF(("%s: y = %d\n", __func__, pos->y));
728 
729 	/* Z0 */
730 	cmd = cmd0 | (3<<ADSCTRL_ADR_SH);
731 	pos->x = ads7846_sync(1, 1, cmd);
732 	DPRINTF(("%s: x = %d\n", __func__, pos->x));
733 
734 	/* Z1 */
735 	cmd = cmd0 | (4<<ADSCTRL_ADR_SH);
736 	z0 = ads7846_sync(1, 1, cmd);
737 	z1 = ads7846_sync(1, 0, cmd);
738 	DPRINTF(("%s: z0 = %d, z1 = %d\n", __func__, z0, z1));
739 
740 	/* check that pen is still down */
741 	if (z0 == 0 || (pos->x * (z1 - z0) / z0) >= 15000)
742 		down = 0;
743 	pos->z = down;
744 
745 out:
746 	/* Enable automatic low power mode. */
747 	cmd = (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH);
748 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0);
749 
750 	return down;
751 }
752 
753 void (*ads7846_wait_for_hsync)(void);
754 
755 /*
756  * Communicate synchronously with the ADS784x touch screen controller.
757  */
758 static uint32_t
759 ads7846_sync(int dorecv, int dosend, uint32_t cmd)
760 {
761 	uint32_t rv = 0;
762 
763 	if (ads7846_wait_for_hsync)
764 		(*ads7846_wait_for_hsync)();
765 
766 	if (dorecv)
767 		rv = wzero3ssp_ic_stop(WZERO3_SSP_IC_ADS7846);
768 
769 	if (dosend) {
770 		/* send dummy command; discard SSDR */
771 		(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0);
772 
773 		/* wait for refresh */
774 		if (ads7846_wait_for_hsync)
775 			(*ads7846_wait_for_hsync)();
776 
777 		/* send the actual command; keep ADS784x enabled */
778 		wzero3ssp_ic_start(WZERO3_SSP_IC_ADS7846, cmd);
779 	}
780 
781 	return rv;
782 }
783 
784 /*----------------------------------------------------------------------------
785  * AK4184 touch screen controller for WS011SH
786  */
787 #define AKMCTRL_PD_SH	12	/* Power down bit */
788 #define AKMCTRL_ADR_SH	13	/* Address setting bits */
789 #define AKMCTRL_STS_SH	15	/* Start bit */
790 
791 static uint32_t ak4184_sync(int, int, uint32_t);
792 
793 void
794 ak4184_init(void)
795 {
796 
797 	/* Enable automatic low power mode. */
798 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP,
799 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (0<<AKMCTRL_PD_SH), 0);
800 }
801 
802 int
803 ak4184_readpos(struct wzero3tp_pos *pos)
804 {
805 	u_int rt;
806 	int z1, z2;
807 
808 	/* X (discard) */
809 	(void)ak4184_sync(0, 1,
810 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
811 
812 	/* X */
813 	(void)ak4184_sync(1, 1,
814 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
815 
816 	/* Y */
817 	pos->x = ak4184_sync(1, 1,
818 	    (1<<AKMCTRL_STS_SH) | (1<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
819 	DPRINTF(("%s: x=%d\n", __func__, pos->x));
820 	pos->y = ak4184_sync(1, 1,
821 	    (1<<AKMCTRL_STS_SH) | (2<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
822 	DPRINTF(("%s: y=%d\n", __func__, pos->y));
823 	z1 = ak4184_sync(1, 1,
824 	    (1<<AKMCTRL_STS_SH) | (3<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
825 	DPRINTF(("%s: z1=%d\n", __func__, z1));
826 	z2 = ak4184_sync(1, 0,
827 	    (1<<AKMCTRL_STS_SH) | (3<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
828 	DPRINTF(("%s: z2=%d\n", __func__, z2));
829 
830 	if (z1 >= 10) {
831 		rt = 400 /* XXX: X plate ohms */;
832 		rt *= pos->x;
833 		rt *= (z2 / z1) - 1;
834 		rt >>= 12;
835 	} else
836 		rt = 0;
837 	DPRINTF(("%s: rt=%d\n", __func__, rt));
838 
839 	/* check that pen is still down */
840 	if (z1 == 0 || rt == 0)
841 		pos->z = 0;
842 	else
843 		pos->z = 1;
844 
845 	/* Enable automatic low power mode. */
846 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP,
847 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (0<<AKMCTRL_PD_SH), 0);
848 
849 	return pos->z;
850 }
851 
852 void
853 ak4184_suspend(void)
854 {
855 
856 	/* Nothing to do */
857 }
858 
859 void
860 ak4184_resume(void)
861 {
862 
863 	/* Enable automatic low power mode. */
864 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP,
865 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (0<<AKMCTRL_PD_SH), 0);
866 }
867 
868 static uint32_t
869 ak4184_sync(int dorecv, int dosend, uint32_t cmd)
870 {
871 	uint32_t rv = 0;
872 
873 	if (dorecv)
874 		rv = wzero3ssp_ic_stop(WZERO3_SSP_IC_AK4184_TP);
875 
876 	if (dosend) {
877 		/* send dummy command; discard SSDR */
878 		(void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP, cmd, 0);
879 
880 		/* send the actual command; keep AK4184 enabled */
881 		wzero3ssp_ic_start(WZERO3_SSP_IC_AK4184_TP, cmd);
882 	}
883 
884 	return rv;
885 }
886