xref: /netbsd-src/sys/arch/hpcarm/dev/wzero3_tp.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: wzero3_tp.c,v 1.6 2010/07/19 15:20:21 tsutsui 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.6 2010/07/19 15:20:21 tsutsui 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, 16 data ave., 12 bit, settling time: 100us */
553 #define	MAX1233_ADCCTRL		0x8be3
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 	/* DAC on */
568 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
569 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),
570 	    0x0000);
571 }
572 
573 void
574 max1233_suspend(void)
575 {
576 
577 	/* power down. */
578 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
579 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
580 	    0xc000);
581 	/* DAC off */
582 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
583 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),
584 	    0x8000);
585 }
586 
587 void
588 max1233_resume(void)
589 {
590 
591 	/* Enable automatic low power mode. */
592 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
593 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
594 	    0x0001);
595 	/* Wait for touch */
596 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
597 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
598 	    MAX1233_ADCCTRL);
599 	/* DAC on */
600 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
601 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),
602 	    0x0000);
603 }
604 
605 int
606 max1233_readpos(struct wzero3tp_pos *pos)
607 {
608 	uint32_t x, y, z1 = 0, z2 = 0, rt;
609 	uint32_t status;
610 	int down;
611 
612 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
613 	    (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),
614 	    0x0bf3);
615 	DELAY(300);
616 
617 	while ((status = (wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
618 		    (1<<MAXCTRL_RW_SH)
619 		    | (1<<MAXCTRL_PAGE_SH)
620 		    | (0<<MAXCTRL_ADDR_SH), 0) & 0x4000)) != 0x4000) {
621 		DPRINTF(("%s: status=%#x\n", __func__, status));
622 		DELAY(10);
623 	}
624 	DPRINTF(("%s: status=%#x\n", __func__, status));
625 
626 	x = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
627 	    (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),0);
628 	DPRINTF(("%s: x=%d\n", __func__, x));
629 	y = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
630 	    (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (1<<MAXCTRL_ADDR_SH),0);
631 	DPRINTF(("%s: y=%d\n", __func__, y));
632 	z1 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
633 	    (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),0);
634 	DPRINTF(("%s: z1=%d\n", __func__, z1));
635 	z2 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233,
636 	    (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (3<<MAXCTRL_ADDR_SH),0);
637 	DPRINTF(("%s: z2=%d\n", __func__, z2));
638 
639 	if (z1 >= 10) {
640 		rt = 400 /* XXX: X plate ohms */;
641 		rt *= x;
642 		rt *= (z2 / z1) - 1;
643 		rt >>= 12;
644 	} else
645 		rt = 0;
646 	DPRINTF(("%s: rt=%d\n", __func__, rt));
647 
648 	down = (rt != 0);
649 	if (down) {
650 		pos->x = x;
651 		pos->y = y;
652 	}
653 	pos->z = down;
654 
655 	return down;
656 }
657 
658 /*----------------------------------------------------------------------------
659  * ADS7846/TSC2046 touch screen controller for WS007SH
660  */
661 #define ADSCTRL_PD0_SH		0	/* PD0 bit */
662 #define ADSCTRL_PD1_SH		1	/* PD1 bit */
663 #define ADSCTRL_DFR_SH		2	/* SER/DFR bit */
664 #define ADSCTRL_MOD_SH		3	/* Mode bit */
665 #define ADSCTRL_ADR_SH		4	/* Address setting */
666 #define ADSCTRL_STS_SH		7	/* Start bit */
667 
668 static uint32_t ads7846_sync(int, int, uint32_t);
669 
670 void
671 ads7846_init(void)
672 {
673 
674 	/* Enable automatic low power mode. */
675 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846,
676 	    (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0);
677 }
678 
679 void
680 ads7846_suspend(void)
681 {
682 
683 	/* Turn off reference voltage but leave ADC on. */
684 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846,
685 	    (1<<ADSCTRL_PD1_SH) | (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0);
686 }
687 
688 void
689 ads7846_resume(void)
690 {
691 
692 	/* Enable automatic low power mode. */
693 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846,
694 	    (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0);
695 }
696 
697 int
698 ads7846_readpos(struct wzero3tp_pos *pos)
699 {
700 	int cmd, cmd0;
701 	int z0, z1;
702 	int down;
703 
704 	cmd0 = (1<<ADSCTRL_STS_SH) | (1<<ADSCTRL_PD0_SH) | (1<<ADSCTRL_PD1_SH);
705 
706 	/* check that pen is down */
707 	cmd = cmd0 | (3<<ADSCTRL_ADR_SH);
708 	z0 = wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0);
709 	DPRINTF(("%s: first z0 = %d\n", __func__, z0));
710 
711 	down = (z0 >= 10);
712 	if (!down)
713 		goto out;
714 
715 	/* Y (discard) */
716 	cmd = cmd0 | (1<<ADSCTRL_ADR_SH);
717 	(void)ads7846_sync(0, 1, cmd);
718 
719 	/* Y */
720 	cmd = cmd0 | (1<<ADSCTRL_ADR_SH);
721 	(void)ads7846_sync(1, 1, cmd);
722 
723 	/* X */
724 	cmd = cmd0 | (5<<ADSCTRL_ADR_SH);
725 	pos->y = ads7846_sync(1, 1, cmd);
726 	DPRINTF(("%s: y = %d\n", __func__, pos->y));
727 
728 	/* Z0 */
729 	cmd = cmd0 | (3<<ADSCTRL_ADR_SH);
730 	pos->x = ads7846_sync(1, 1, cmd);
731 	DPRINTF(("%s: x = %d\n", __func__, pos->x));
732 
733 	/* Z1 */
734 	cmd = cmd0 | (4<<ADSCTRL_ADR_SH);
735 	z0 = ads7846_sync(1, 1, cmd);
736 	z1 = ads7846_sync(1, 0, cmd);
737 	DPRINTF(("%s: z0 = %d, z1 = %d\n", __func__, z0, z1));
738 
739 	/* check that pen is still down */
740 	if (z0 == 0 || (pos->x * (z1 - z0) / z0) >= 15000)
741 		down = 0;
742 	pos->z = down;
743 
744 out:
745 	/* Enable automatic low power mode. */
746 	cmd = (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH);
747 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0);
748 
749 	return down;
750 }
751 
752 void (*ads7846_wait_for_hsync)(void);
753 
754 /*
755  * Communicate synchronously with the ADS784x touch screen controller.
756  */
757 static uint32_t
758 ads7846_sync(int dorecv, int dosend, uint32_t cmd)
759 {
760 	uint32_t rv = 0;
761 
762 	if (ads7846_wait_for_hsync)
763 		(*ads7846_wait_for_hsync)();
764 
765 	if (dorecv)
766 		rv = wzero3ssp_ic_stop(WZERO3_SSP_IC_ADS7846);
767 
768 	if (dosend) {
769 		/* send dummy command; discard SSDR */
770 		(void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0);
771 
772 		/* wait for refresh */
773 		if (ads7846_wait_for_hsync)
774 			(*ads7846_wait_for_hsync)();
775 
776 		/* send the actual command; keep ADS784x enabled */
777 		wzero3ssp_ic_start(WZERO3_SSP_IC_ADS7846, cmd);
778 	}
779 
780 	return rv;
781 }
782 
783 /*----------------------------------------------------------------------------
784  * AK4184 touch screen controller for WS011SH
785  */
786 #define AKMCTRL_PD_SH	12	/* Power down bit */
787 #define AKMCTRL_ADR_SH	13	/* Address setting bits */
788 #define AKMCTRL_STS_SH	15	/* Start bit */
789 
790 static uint32_t ak4184_sync(int, int, uint32_t);
791 
792 void
793 ak4184_init(void)
794 {
795 
796 	/* Enable automatic low power mode. */
797 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP,
798 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (0<<AKMCTRL_PD_SH), 0);
799 }
800 
801 int
802 ak4184_readpos(struct wzero3tp_pos *pos)
803 {
804 	u_int rt;
805 	int z1, z2;
806 
807 	/* X (discard) */
808 	(void)ak4184_sync(0, 1,
809 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
810 
811 	/* X */
812 	(void)ak4184_sync(1, 1,
813 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
814 
815 	/* Y */
816 	pos->x = ak4184_sync(1, 1,
817 	    (1<<AKMCTRL_STS_SH) | (1<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
818 	DPRINTF(("%s: x=%d\n", __func__, pos->x));
819 	pos->y = ak4184_sync(1, 1,
820 	    (1<<AKMCTRL_STS_SH) | (2<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
821 	DPRINTF(("%s: y=%d\n", __func__, pos->y));
822 	z1 = ak4184_sync(1, 1,
823 	    (1<<AKMCTRL_STS_SH) | (3<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
824 	DPRINTF(("%s: z1=%d\n", __func__, z1));
825 	z2 = ak4184_sync(1, 0,
826 	    (1<<AKMCTRL_STS_SH) | (3<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH));
827 	DPRINTF(("%s: z2=%d\n", __func__, z2));
828 
829 	if (z1 >= 10) {
830 		rt = 400 /* XXX: X plate ohms */;
831 		rt *= pos->x;
832 		rt *= (z2 / z1) - 1;
833 		rt >>= 12;
834 	} else
835 		rt = 0;
836 	DPRINTF(("%s: rt=%d\n", __func__, rt));
837 
838 	/* check that pen is still down */
839 	if (z1 == 0 || rt == 0)
840 		pos->z = 0;
841 	else
842 		pos->z = 1;
843 
844 	/* Enable automatic low power mode. */
845 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP,
846 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (0<<AKMCTRL_PD_SH), 0);
847 
848 	return pos->z;
849 }
850 
851 void
852 ak4184_suspend(void)
853 {
854 
855 	/* Nothing to do */
856 }
857 
858 void
859 ak4184_resume(void)
860 {
861 
862 	/* Enable automatic low power mode. */
863 	(void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP,
864 	    (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (0<<AKMCTRL_PD_SH), 0);
865 }
866 
867 static uint32_t
868 ak4184_sync(int dorecv, int dosend, uint32_t cmd)
869 {
870 	uint32_t rv = 0;
871 
872 	if (dorecv)
873 		rv = wzero3ssp_ic_stop(WZERO3_SSP_IC_AK4184_TP);
874 
875 	if (dosend) {
876 		/* send dummy command; discard SSDR */
877 		(void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP, cmd, 0);
878 
879 		/* send the actual command; keep AK4184 enabled */
880 		wzero3ssp_ic_start(WZERO3_SSP_IC_AK4184_TP, cmd);
881 	}
882 
883 	return rv;
884 }
885