xref: /netbsd-src/sys/arch/zaurus/dev/ztp.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*	$NetBSD: ztp.c,v 1.14 2012/10/27 17:18:14 chs Exp $	*/
2 /* $OpenBSD: zts.c,v 1.9 2005/04/24 18:55:49 uwe Exp $ */
3 
4 /*
5  * Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: ztp.c,v 1.14 2012/10/27 17:18:14 chs Exp $");
22 
23 #include "lcd.h"
24 #include "w100lcd.h"
25 
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/device.h>
30 #include <sys/malloc.h>
31 #include <sys/kernel.h>
32 #include <sys/callout.h>
33 
34 #include <dev/wscons/wsconsio.h>
35 #include <dev/wscons/wsmousevar.h>
36 #include <dev/wscons/wsdisplayvar.h>
37 
38 #include <dev/hpc/hpcfbio.h>		/* XXX: for tpctl */
39 #include <dev/hpc/hpctpanelvar.h>
40 
41 #include <arm/xscale/pxa2x0cpu.h>
42 #include <arm/xscale/pxa2x0reg.h>
43 #include <arm/xscale/pxa2x0var.h>
44 #include <arm/xscale/xscalereg.h>
45 #include <arm/xscale/pxa2x0_gpio.h>
46 #if NLCD > 0
47 #include <arm/xscale/pxa2x0_lcd.h>
48 #endif
49 #if NW100LCD > 0
50 #include <zaurus/dev/w100var.h>
51 #endif
52 
53 #include <zaurus/zaurus/zaurus_var.h>
54 #include <zaurus/dev/zsspvar.h>
55 #ifdef ZTP_DEBUG
56 #define	DPRINTF(s)	printf s
57 #else
58 #define	DPRINTF(s)
59 #endif
60 
61 /*
62  * ADS784x touch screen controller
63  */
64 #define ADSCTRL_PD0_SH          0       /* PD0 bit */
65 #define ADSCTRL_PD1_SH          1       /* PD1 bit */
66 #define ADSCTRL_DFR_SH          2       /* SER/DFR bit */
67 #define ADSCTRL_MOD_SH          3       /* Mode bit */
68 #define ADSCTRL_ADR_SH          4       /* Address setting */
69 #define ADSCTRL_STS_SH          7       /* Start bit */
70 
71 #define GPIO_TP_INT_C3K		11
72 #define GPIO_HSYNC_C3K		22
73 #define GPIO_TP_INT_C860	5
74 #define GPIO_HSYNC_C860		44
75 
76 #define POLL_TIMEOUT_RATE0	((hz * 150)/1000)
77 #define POLL_TIMEOUT_RATE1	(hz / 100) /* XXX every tick */
78 
79 #define CCNT_HS_400_VGA_C3K 6250	/* 15.024us */
80 #define CCNT_HS_400_VGA_C860 7013	/* 17.615us */
81 
82 /* XXX need to ask lcd drivers for the screen dimension */
83 #if NLCD > 0
84 extern const struct lcd_panel_geometry lcd_panel_geometry_c3000;
85 #endif
86 #if NW100LCD > 0
87 extern const struct w100_panel_geometry lcd_panel_geometry_c700;
88 #endif
89 
90 /* Settable via sysctl. */
91 int ztp_rawmode;
92 
93 static const struct wsmouse_calibcoords ztp_default_calib = {
94 	0, 0, 479, 639,				/* minx, miny, maxx, maxy */
95 	5,					/* samplelen */
96 	{
97 		{ 1929, 2021, 240, 320 },	/* rawx, rawy, x, y */
98 		{  545, 3464,  48,  64 },
99 		{ 3308, 3452,  48, 576 },
100 		{ 2854,  768, 432, 576 },
101 		{  542,  593, 432,  64 }
102 	}
103 };
104 
105 struct ztp_pos {
106 	int x;
107 	int y;
108 	int z;			/* touch pressure */
109 };
110 
111 struct ztp_softc {
112 	device_t sc_dev;
113 	struct callout sc_tp_poll;
114 	void *sc_gh;
115 	int sc_enabled;
116 	int sc_buttons; /* button emulation ? */
117 	device_t sc_wsmousedev;
118 	struct ztp_pos sc_oldpos;
119 	int sc_resx;
120 	int sc_resy;
121 	struct tpcalib_softc sc_tpcalib;
122 
123 	u_int sc_tp_int_pin;
124 	u_int sc_hsync_pin;
125 	u_int sc_ccnt_hs;
126 };
127 
128 static int	ztp_match(device_t, cfdata_t, void *);
129 static void	ztp_attach(device_t, device_t, void *);
130 
131 CFATTACH_DECL_NEW(ztp, sizeof(struct ztp_softc),
132 	ztp_match, ztp_attach, NULL, NULL);
133 
134 static int	ztp_finalize(device_t);
135 static int	ztp_enable(void *);
136 static void	ztp_disable(void *);
137 static bool	ztp_suspend(device_t dv, const pmf_qual_t *);
138 static bool	ztp_resume(device_t dv, const pmf_qual_t *);
139 static void	ztp_poll(void *);
140 static int	ztp_irq(void *);
141 static int	ztp_ioctl(void *, u_long, void *, int, struct lwp *);
142 
143 static const struct wsmouse_accessops ztp_accessops = {
144         ztp_enable,
145 	ztp_ioctl,
146 	ztp_disable
147 };
148 
149 static int
150 ztp_match(device_t parent, cfdata_t cf, void *aux)
151 {
152 	struct zssp_attach_args *aa = aux;
153 
154 	if (strcmp("ztp", aa->zaa_name))
155 		return 0;
156 	return 1;
157 }
158 
159 static void
160 ztp_attach(device_t parent, device_t self, void *aux)
161 {
162 	struct ztp_softc *sc = device_private(self);
163 	struct wsmousedev_attach_args a;
164 
165 	sc->sc_dev = self;
166 
167 	aprint_normal("\n");
168 	aprint_naive("\n");
169 
170 	callout_init(&sc->sc_tp_poll, 0);
171 	callout_setfunc(&sc->sc_tp_poll, ztp_poll, sc);
172 
173 	/* defer initialization until all other devices are attached */
174 	config_finalize_register(self, ztp_finalize);
175 
176 	a.accessops = &ztp_accessops;
177 	a.accesscookie = sc;
178 
179 #if NLCD > 0 || NW100LCD > 0	/* XXX */
180 #if NLCD > 0
181 	if (ZAURUS_ISC1000 || ZAURUS_ISC3000) {
182 		sc->sc_resx = lcd_panel_geometry_c3000.panel_height;
183 		sc->sc_resy = lcd_panel_geometry_c3000.panel_width;
184 	} else
185 #endif
186 #if NW100LCD > 0
187 	if (ZAURUS_ISC860) {
188 		sc->sc_resx = lcd_panel_geometry_c700.panel_height;
189 		sc->sc_resy = lcd_panel_geometry_c700.panel_width;
190 	} else
191 #endif
192 #endif
193 	{
194 		sc->sc_resx = 480;	/* XXX */
195 		sc->sc_resy = 640;	/* XXX */
196 	}
197 
198 	if (ZAURUS_ISC1000 || ZAURUS_ISC3000) {
199 		sc->sc_tp_int_pin = GPIO_TP_INT_C3K;
200 		sc->sc_hsync_pin = GPIO_HSYNC_C3K;
201 		sc->sc_ccnt_hs = CCNT_HS_400_VGA_C3K;
202 	} else {
203 		/* C7x0/C860 */
204 		sc->sc_tp_int_pin = GPIO_TP_INT_C860;
205 		sc->sc_hsync_pin = GPIO_HSYNC_C860;
206 		sc->sc_ccnt_hs = CCNT_HS_400_VGA_C860;
207 	}
208 
209 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
210 
211 	/* Initialize calibration, set default parameters. */
212 	tpcalib_init(&sc->sc_tpcalib);
213 	tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
214 	    __UNCONST(&ztp_default_calib), 0, 0);
215 }
216 
217 static int
218 ztp_finalize(device_t dv)
219 {
220 
221 	/* Initialize ADS7846 Difference Reference mode */
222 	(void)zssp_ic_send(ZSSP_IC_ADS7846,
223 	    (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
224 	delay(5000);
225 	(void)zssp_ic_send(ZSSP_IC_ADS7846,
226 	    (3<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
227 	delay(5000);
228 	(void)zssp_ic_send(ZSSP_IC_ADS7846,
229 	    (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
230 	delay(5000);
231 	(void)zssp_ic_send(ZSSP_IC_ADS7846,
232 	    (5<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
233 	delay(5000);
234 
235 	return 0;
236 }
237 
238 static int
239 ztp_enable(void *v)
240 {
241 	struct ztp_softc *sc = (struct ztp_softc *)v;
242 
243 	DPRINTF(("%s: ztp_enable()\n", device_xname(sc->sc_dev)));
244 
245 	if (sc->sc_enabled) {
246 		DPRINTF(("%s: already enabled\n", device_xname(sc->sc_dev)));
247 		return EBUSY;
248 	}
249 
250 	callout_stop(&sc->sc_tp_poll);
251 
252 	if (!pmf_device_register(sc->sc_dev, ztp_suspend, ztp_resume))
253 		aprint_error_dev(sc->sc_dev,
254 		    "couldn't establish power handler\n");
255 
256 	pxa2x0_gpio_set_function(sc->sc_tp_int_pin, GPIO_IN);
257 
258 	/* XXX */
259 	if (sc->sc_gh == NULL) {
260 		sc->sc_gh = pxa2x0_gpio_intr_establish(sc->sc_tp_int_pin,
261 		    IST_EDGE_FALLING, IPL_TTY, ztp_irq, sc);
262 	} else {
263 		pxa2x0_gpio_intr_unmask(sc->sc_gh);
264 	}
265 
266 	/* enable interrupts */
267 	sc->sc_enabled = 1;
268 	sc->sc_buttons = 0;
269 
270 	return 0;
271 }
272 
273 static void
274 ztp_disable(void *v)
275 {
276 	struct ztp_softc *sc = (struct ztp_softc *)v;
277 
278 	DPRINTF(("%s: ztp_disable()\n", device_xname(sc->sc_dev)));
279 
280 	callout_stop(&sc->sc_tp_poll);
281 
282 	pmf_device_deregister(sc->sc_dev);
283 
284 	if (sc->sc_gh) {
285 		pxa2x0_gpio_intr_mask(sc->sc_gh);
286 	}
287 
288 	/* disable interrupts */
289 	sc->sc_enabled = 0;
290 }
291 
292 static bool
293 ztp_suspend(device_t dv, const pmf_qual_t *qual)
294 {
295 	struct ztp_softc *sc = device_private(dv);
296 
297 	DPRINTF(("%s: ztp_suspend()\n", device_xname(sc->sc_dev)));
298 
299 	sc->sc_enabled = 0;
300 	pxa2x0_gpio_intr_mask(sc->sc_gh);
301 
302 	callout_stop(&sc->sc_tp_poll);
303 
304 	/* Turn off reference voltage but leave ADC on. */
305 	(void)zssp_ic_send(ZSSP_IC_ADS7846, (1 << ADSCTRL_PD1_SH) |
306 	    (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH));
307 
308 	pxa2x0_gpio_set_function(sc->sc_tp_int_pin, GPIO_OUT | GPIO_SET);
309 
310 	return true;
311 }
312 
313 static bool
314 ztp_resume(device_t dv, const pmf_qual_t *qual)
315 {
316 	struct ztp_softc *sc = device_private(dv);
317 
318 	DPRINTF(("%s: ztp_resume()\n", device_xname(sc->sc_dev)));
319 
320 	pxa2x0_gpio_set_function(sc->sc_tp_int_pin, GPIO_IN);
321 	pxa2x0_gpio_intr_mask(sc->sc_gh);
322 
323 	/* Enable automatic low power mode. */
324 	(void)zssp_ic_send(ZSSP_IC_ADS7846,
325 	    (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH));
326 
327 	pxa2x0_gpio_intr_unmask(sc->sc_gh);
328 	sc->sc_enabled = 1;
329 
330 	return true;
331 }
332 
333 #define HSYNC()								\
334 do {									\
335 	while (pxa2x0_gpio_get_bit(sc->sc_hsync_pin) == 0)		\
336 		continue;						\
337 	while (pxa2x0_gpio_get_bit(sc->sc_hsync_pin) != 0)		\
338 		continue;						\
339 } while (/*CONSTCOND*/0)
340 
341 static inline uint32_t pxa2x0_ccnt_enable(uint32_t);
342 static inline uint32_t pxa2x0_read_ccnt(void);
343 static uint32_t ztp_sync_ads784x(struct ztp_softc *, int, int, uint32_t);
344 static void ztp_sync_send(struct ztp_softc *, uint32_t);
345 static int ztp_readpos(struct ztp_softc *, struct ztp_pos *);
346 
347 static inline uint32_t
348 pxa2x0_ccnt_enable(uint32_t reg)
349 {
350 	uint32_t rv;
351 
352 	__asm volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (rv));
353 	__asm volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (reg));
354 
355 	return rv;
356 }
357 
358 static inline uint32_t
359 pxa2x0_read_ccnt(void)
360 {
361 	uint32_t rv;
362 
363 	__asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (rv));
364 
365 	return rv;
366 }
367 
368 /*
369  * Communicate synchronously with the ADS784x touch screen controller.
370  */
371 static uint32_t
372 ztp_sync_ads784x(struct ztp_softc *sc, int dorecv/* XXX */,
373     int dosend/* XXX */, uint32_t cmd)
374 {
375 	uint32_t ccen;
376 	uint32_t rv = 0;
377 
378 	/* XXX poll hsync only if LCD is enabled */
379 
380 	/* start clock counter */
381 	ccen = pxa2x0_ccnt_enable(PMNC_E);
382 
383 	HSYNC();
384 
385 	if (dorecv) {
386 		/* read SSDR and disable ADS784x */
387 		rv = zssp_ic_stop(ZSSP_IC_ADS7846);
388 	}
389 
390 	if (dosend) {
391 		ztp_sync_send(sc, cmd);
392 	}
393 
394 	/* stop clock counter */
395 	pxa2x0_ccnt_enable(ccen);
396 
397 	return rv;
398 }
399 
400 void
401 ztp_sync_send(struct ztp_softc *sc, uint32_t cmd)
402 {
403 	volatile uint32_t base, now;
404 	uint32_t tck;
405 
406 	/* XXX */
407 	tck = sc->sc_ccnt_hs - 151;
408 	/* XXX: for one more delay(1) */
409 	tck -= 400;
410 
411 	/* send dummy command; discard SSDR */
412 	(void)zssp_ic_send(ZSSP_IC_ADS7846, cmd);
413 
414 	/* wait for refresh */
415 	HSYNC();
416 
417 	/* wait after refresh */
418 	base = pxa2x0_read_ccnt();
419 	now = pxa2x0_read_ccnt();
420 	while ((now - base) < tck)
421 		now = pxa2x0_read_ccnt();
422 
423 	/* send the actual command; keep ADS784x enabled */
424 	zssp_ic_start(ZSSP_IC_ADS7846, cmd);
425 }
426 
427 static int
428 ztp_readpos(struct ztp_softc *sc, struct ztp_pos *pos)
429 {
430 	int cmd;
431 	int t0, t1;
432 	int down;
433 
434 	/* XXX */
435 	pxa2x0_gpio_set_function(sc->sc_hsync_pin, GPIO_IN);
436 
437 	/* check that pen is down */
438 	cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
439 	    (3 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
440 	t0 = zssp_ic_send(ZSSP_IC_ADS7846, cmd);
441 	DPRINTF(("ztp_readpos(): t0 = %d\n", t0));
442 
443 	down = (t0 >= 10);
444 	if (down == 0)
445 		goto out;
446 
447 	/* Y */
448 	cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
449 	    (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
450 	(void)ztp_sync_ads784x(sc, 0, 1, cmd);
451 
452 	/* Y */
453 	cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
454 	    (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
455 	(void)ztp_sync_ads784x(sc, 1, 1, cmd);
456 
457 	/* X */
458 	cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
459 	    (5 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
460 	pos->y = ztp_sync_ads784x(sc, 1, 1, cmd);
461 	DPRINTF(("ztp_readpos(): y = %d\n", pos->y));
462 
463 	/* T0 */
464 	cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
465 	    (3 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
466 	pos->x = ztp_sync_ads784x(sc, 1, 1, cmd);
467 	DPRINTF(("ztp_readpos(): x = %d\n", pos->x));
468 
469 	/* T1 */
470 	cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
471 	    (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
472 	t0 = ztp_sync_ads784x(sc, 1, 1, cmd);
473 	t1 = ztp_sync_ads784x(sc, 1, 0, cmd);
474 	DPRINTF(("ztp_readpos(): t0 = %d, t1 = %d\n", t0, t1));
475 
476 	/* check that pen is still down */
477 	/* XXX pressure sensitivity varies with X or what? */
478 	if (t0 == 0 || (pos->x * (t1 - t0) / t0) >= 15000)
479 		down = 0;
480 	pos->z = down;
481 
482 out:
483 	/* Enable automatic low power mode. */
484         cmd = (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
485 	(void)zssp_ic_send(ZSSP_IC_ADS7846, cmd);
486 
487 	return down;
488 }
489 
490 static void
491 ztp_poll(void *v)
492 {
493 	int s;
494 
495 	s = spltty();
496 	(void)ztp_irq(v);
497 	splx(s);
498 }
499 
500 static int
501 ztp_irq(void *v)
502 {
503 	extern int zkbd_modstate;
504 	struct ztp_softc *sc = (struct ztp_softc *)v;
505 	struct ztp_pos tp = { 0, 0, 0 };
506 	int pindown;
507 	int down;
508 	int x, y;
509 	int s;
510 
511 	if (!sc->sc_enabled)
512 		return 0;
513 
514 	s = splhigh();
515 
516 	pindown = pxa2x0_gpio_get_bit(sc->sc_tp_int_pin) ? 0 : 1;
517 	DPRINTF(("%s: pindown = %d\n", device_xname(sc->sc_dev), pindown));
518 	if (pindown) {
519 		pxa2x0_gpio_intr_mask(sc->sc_gh);
520 		callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE1);
521 	}
522 
523 	down = ztp_readpos(sc, &tp);
524 	DPRINTF(("%s: x = %d, y = %d, z = %d, down = %d\n",
525 	    device_xname(sc->sc_dev), tp.x, tp.y, tp.z, down));
526 
527 	if (!pindown) {
528 		pxa2x0_gpio_intr_unmask(sc->sc_gh);
529 		callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE0);
530 	}
531 	pxa2x0_gpio_clear_intr(sc->sc_tp_int_pin);
532 
533 	splx(s);
534 
535 	if (down) {
536 		if (!ztp_rawmode) {
537 			tpcalib_trans(&sc->sc_tpcalib, tp.x, tp.y, &x, &y);
538 			DPRINTF(("%s: x = %d, y = %d\n",
539 			    device_xname(sc->sc_dev), x, y));
540 			tp.x = x;
541 			tp.y = y;
542 		}
543 	}
544 
545 	if (zkbd_modstate != 0 && down) {
546 		if (zkbd_modstate & (1 << 1)) {
547 			/* Fn */
548 			down = 2;
549 		} else if (zkbd_modstate & (1 << 2)) {
550 			/* 'Alt' */
551 			down = 4;
552 		}
553 	}
554 	if (!down) {
555 		/* x/y values are not reliable when pen is up */
556 		tp = sc->sc_oldpos;
557 	}
558 
559 	if (down || sc->sc_buttons != down) {
560 		wsmouse_input(sc->sc_wsmousedev, down, tp.x, tp.y, 0, 0,
561 		    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
562 		sc->sc_buttons = down;
563 		sc->sc_oldpos = tp;
564 	}
565 
566 	return 1;
567 }
568 
569 static int
570 ztp_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
571 {
572 	struct ztp_softc *sc = (struct ztp_softc *)v;
573 	struct wsmouse_id *id;
574 
575 	switch (cmd) {
576 	case WSMOUSEIO_GTYPE:
577 		*(u_int *)data = WSMOUSE_TYPE_TPANEL;
578 		return 0;
579 
580 	case WSMOUSEIO_GETID:
581 		/*
582 		 * return unique ID string,
583 		 * "<vendor> <model> <serial number>"
584 		 */
585 		id = (struct wsmouse_id *)data;
586 		if (id->type != WSMOUSE_ID_TYPE_UIDSTR)
587 			return EINVAL;
588 		strlcpy(id->data, "Sharp SL-C3x00 SN000000", WSMOUSE_ID_MAXLEN);
589 		id->length = strlen(id->data);
590 		return 0;
591 
592 	case WSMOUSEIO_SCALIBCOORDS:
593 	case WSMOUSEIO_GCALIBCOORDS:
594 		return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
595 	}
596 
597 	return EPASSTHROUGH;
598 }
599