xref: /netbsd-src/sys/arch/hpcmips/vr/vrpiu.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: vrpiu.c,v 1.42 2012/10/27 17:17:56 chs Exp $	*/
2 
3 /*
4  * Copyright (c) 1999-2003 TAKEMURA Shin All rights reserved.
5  * Copyright (c) 2000-2001 SATO Kazumi, All rights reserved.
6  * Copyright (c) 1999-2001 PocketBSD Project. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 /*
32  * A/D polling part written by SATO Kazumi.
33  */
34 
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: vrpiu.c,v 1.42 2012/10/27 17:17:56 chs Exp $");
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/kernel.h>
42 #include <sys/callout.h>
43 #include <sys/boot_flag.h>
44 
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/wscons/wsmousevar.h>
47 
48 #include <machine/bus.h>
49 #include <machine/platid.h>
50 #include <machine/platid_mask.h>
51 #include <machine/config_hook.h>
52 
53 #include <dev/hpc/hpctpanelvar.h>
54 
55 #include <dev/hpc/hpcbatteryvar.h>
56 #include <dev/hpc/hpcbatterytable.h>
57 
58 #include <hpcmips/vr/vrcpudef.h>
59 #include <hpcmips/vr/vripif.h>
60 #include <hpcmips/vr/cmureg.h>
61 #include <hpcmips/vr/vrpiuvar.h>
62 #define	PIUB_REG_OFFSSET	0
63 #include <hpcmips/vr/vrpiureg.h>
64 
65 /*
66  * contant and macro definitions
67  */
68 #define VRPIUDEBUG
69 #ifdef VRPIUDEBUG
70 int	vrpiu_debug = 0;
71 #define	DPRINTF(arg) if (vrpiu_debug) printf arg;
72 #define	VPRINTF(arg) if (bootverbose || vrpiu_debug) printf arg;
73 #else
74 #define	DPRINTF(arg)
75 #define	VPRINTF(arg) if (bootverbose) printf arg;
76 #endif
77 
78 #ifndef VRPIU_NO_ADHOC_BATTERY_EVENT
79 #define VRPIU_ADHOC_BATTERY_EVENT	/* currently... */
80 #endif /* VRPIU_NO_ADHOC_BATTERY_EVENT */
81 
82 #ifndef VRPIU_AD_POLL_INTERVAL
83 #define VRPIU_AD_POLL_INTERVAL	60	/* interval is 60 sec */
84 #endif /* VRPIU_AD_POLL_INTERTVAL */
85 
86 #define	PIUSIVL_SCANINTVAL_MIN	333			/* 10msec	*/
87 #define	PIUSIVL_SCANINTVAL_MAX	PIUSIVL_SCANINTVAL_MASK	/* 60msec	*/
88 #define VRPIU_TP_SCAN_TIMEOUT	(hz/10)		/* timeout is 100msec	*/
89 
90 #define TP_INTR	(PIUINT_ALLINTR & ~PIUINT_PADADPINTR)
91 #define AD_INTR	(PIUINT_PADADPINTR)
92 
93 /*
94  * data types
95  */
96 /* struct vrpiu_softc is defined in vrpiuvar.h */
97 
98 /*
99  * function prototypes
100  */
101 static int	vrpiumatch(device_t, cfdata_t, void *);
102 static void	vrpiuattach(device_t, device_t, void *);
103 static void	vrc4173piuattach(device_t, device_t, void *);
104 static void	vrpiu_init(struct vrpiu_softc *, void *);
105 
106 static void	vrpiu_write(struct vrpiu_softc *, int, unsigned short);
107 static u_short	vrpiu_read(struct vrpiu_softc *, int);
108 
109 static int	vrpiu_intr(void *);
110 static void	vrpiu_tp_intr(struct vrpiu_softc *);
111 static void	vrpiu_ad_intr(struct vrpiu_softc *);
112 #ifdef DEBUG
113 static void	vrpiu_dump_cntreg(unsigned int);
114 #endif
115 
116 static int	vrpiu_tp_enable(void *);
117 static int	vrpiu_tp_ioctl(void *, u_long, void *, int, struct lwp *);
118 static void	vrpiu_tp_disable(void *);
119 static void	vrpiu_tp_up(struct vrpiu_softc *);
120 static void	vrpiu_tp_timeout(void *);
121 int		vrpiu_ad_enable(void *);
122 void		vrpiu_ad_disable(void *);
123 static void	vrpiu_start_powerstate(void *);
124 static void	vrpiu_calc_powerstate(struct vrpiu_softc *);
125 static void	vrpiu_send_battery_event(struct vrpiu_softc *);
126 static void	vrpiu_power(int, void *);
127 static u_int	scan_interval(u_int data);
128 
129 /* mra is defined in mra.c */
130 int mra_Y_AX1_BX2_C(int *y, int ys, int *x1, int x1s, int *x2, int x2s,
131     int n, int scale, int *a, int *b, int *c);
132 
133 /*
134  * static or global variables
135  */
136 CFATTACH_DECL_NEW(vrpiu, sizeof(struct vrpiu_softc),
137     vrpiumatch, vrpiuattach, NULL, NULL);
138 CFATTACH_DECL_NEW(vrc4173piu, sizeof(struct vrpiu_softc),
139     vrpiumatch, vrc4173piuattach, NULL, NULL);
140 
141 const struct wsmouse_accessops vrpiu_accessops = {
142 	vrpiu_tp_enable,
143 	vrpiu_tp_ioctl,
144 	vrpiu_tp_disable,
145 };
146 
147 int vrpiu_ad_poll_interval = VRPIU_AD_POLL_INTERVAL;
148 
149 /*
150  * function definitions
151  */
152 static inline void
153 vrpiu_write(struct vrpiu_softc *sc, int port, unsigned short val)
154 {
155 
156 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
157 }
158 
159 static inline u_short
160 vrpiu_read(struct vrpiu_softc *sc, int port)
161 {
162 
163 	return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port));
164 }
165 
166 static inline u_short
167 vrpiu_buf_read(struct vrpiu_softc *sc, int port)
168 {
169 
170 	return (bus_space_read_2(sc->sc_iot, sc->sc_buf_ioh, port));
171 }
172 
173 static int
174 vrpiumatch(device_t parent, cfdata_t cf, void *aux)
175 {
176 
177 	return (1);
178 }
179 
180 static void
181 vrpiuattach(device_t parent, device_t self, void *aux)
182 {
183 	struct vrpiu_softc *sc = device_private(self);
184 
185 	sc->sc_dev = self;
186 	sc->sc_ab_paddata_mask = PIUAB_PADDATA_MASK;
187 	sc->sc_pb_paddata_mask = PIUPB_PADDATA_MASK;
188 	sc->sc_pb_paddata_max = PIUPB_PADDATA_MAX;
189 	vrpiu_init(sc, aux);
190 }
191 
192 static void
193 vrc4173piuattach(device_t parent, device_t self, void *aux)
194 {
195 	struct vrpiu_softc *sc = device_private(self);
196 
197 	sc->sc_dev = self;
198 	sc->sc_ab_paddata_mask = VRC4173PIUAB_PADDATA_MASK;
199 	sc->sc_pb_paddata_mask = VRC4173PIUPB_PADDATA_MASK;
200 	sc->sc_pb_paddata_max = VRC4173PIUPB_PADDATA_MAX;
201 	vrpiu_init(sc, aux);
202 }
203 
204 static void
205 vrpiu_init(struct vrpiu_softc *sc, void *aux)
206 {
207 	struct vrip_attach_args *va = aux;
208 	struct wsmousedev_attach_args wsmaa;
209 	int res;
210 	bus_space_tag_t iot = va->va_iot;
211 	struct platid_data *p;
212 
213 	if (va->va_parent_ioh != 0)
214 		res = bus_space_subregion(iot, va->va_parent_ioh, va->va_addr,
215 		    va->va_size, &sc->sc_ioh);
216 	else
217 		res = bus_space_map(iot, va->va_addr, va->va_size, 0,
218 		    &sc->sc_ioh);
219 	if (res != 0) {
220 		printf(": can't map bus space\n");
221 		return;
222 	}
223 	if (va->va_parent_ioh != 0)
224 		res = bus_space_subregion(iot, va->va_parent_ioh, va->va_addr2,
225 		    va->va_size2, &sc->sc_buf_ioh);
226 	else
227 		res = bus_space_map(iot, va->va_addr2, va->va_size2, 0,
228 		    &sc->sc_buf_ioh);
229 	if (res != 0) {
230 		printf(": can't map second bus space\n");
231 		return;
232 	}
233 
234 	sc->sc_iot = iot;
235 	sc->sc_unit = va->va_unit;
236 	sc->sc_vrip = va->va_vc;
237 
238 	sc->sc_interval = scan_interval(WSMOUSE_RES_DEFAULT);
239 	if ((p = platid_search_data(&platid, hpcbattery_parameters)) == NULL)
240 		sc->sc_battery_spec = NULL;
241 	else
242 		sc->sc_battery_spec  = p->data;
243 
244 	/*
245 	 * disable device until vrpiu_enable called
246 	 */
247 	sc->sc_tpstat = VRPIU_TP_STAT_DISABLE;
248 
249 	/* initialize touch panel timeout structure	*/
250 	callout_init(&sc->sc_tptimeout, 0);
251 
252 	/* initialize calibration context	*/
253 	tpcalib_init(&sc->sc_tpcalib);
254 #if 1
255 	/*
256 	 * XXX, calibrate parameters
257 	 */
258 	{
259 		int i;
260 		static const struct {
261 			platid_mask_t *mask;
262 			struct wsmouse_calibcoords coords;
263 		} calibrations[] = {
264 			{ &platid_mask_MACH_NEC_MCR_700,
265 			  { 0, 0, 799, 599,
266 			    4,
267 			    { { 115,  80,   0,   0 },
268 			      { 115, 966,   0, 599 },
269 			      { 912,  80, 799,   0 },
270 			      { 912, 966, 799, 599 } } } },
271 			{ &platid_mask_MACH_NEC_MCR_700A,
272 			  { 0, 0, 799, 599,
273 			    4,
274 			    { { 115,  80,   0,   0 },
275 			      { 115, 966,   0, 599 },
276 			      { 912,  80, 799,   0 },
277 			      { 912, 966, 799, 599 } } } },
278 			{ &platid_mask_MACH_NEC_MCR_730,
279 			  { 0, 0, 799, 599,
280 			    4,
281 			    { { 115,  80,   0,   0 },
282 			      { 115, 966,   0, 599 },
283 			      { 912,  80, 799,   0 },
284 			      { 912, 966, 799, 599 } } } },
285 			{ &platid_mask_MACH_NEC_MCR_730A,
286 			  { 0, 0, 799, 599,
287 			    4,
288 			    { { 115,  80,   0,   0 },
289 			      { 115, 966,   0, 599 },
290 			      { 912,  80, 799,   0 },
291 			      { 912, 966, 799, 599 } } } },
292 			{ NULL,		/* samples got on my MC-R500 */
293 			  { 0, 0, 639, 239,
294 			    5,
295 			    { { 502, 486, 320, 120 },
296 			      {  55, 109,   0,   0 },
297 			      {  54, 913,   0, 239 },
298 			      { 973, 924, 639, 239 },
299 			      { 975, 123, 639,   0 } } } },
300 		};
301 		for (i = 0; ; i++) {
302 			if (calibrations[i].mask == NULL
303 			    || platid_match(&platid, calibrations[i].mask))
304 				break;
305 		}
306 		tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
307 		    (void *)__UNCONST(&calibrations[i].coords), 0, 0);
308 	}
309 #endif
310 
311 	/* install interrupt handler and enable interrupt */
312 	if (!(sc->sc_handler =
313 	    vrip_intr_establish(sc->sc_vrip, sc->sc_unit, 0, IPL_TTY,
314 		vrpiu_intr, sc))) {
315 		printf (": can't map interrupt line.\n");
316 		return;
317 	}
318 
319 	/* mask level2 interrupt, stop scan sequencer and mask clock to piu */
320 	vrpiu_tp_disable(sc);
321 
322 	printf("\n");
323 
324 	wsmaa.accessops = &vrpiu_accessops;
325 	wsmaa.accesscookie = sc;
326 
327 	/*
328 	 * attach the wsmouse
329 	 */
330 	sc->sc_wsmousedev = config_found(sc->sc_dev, &wsmaa, wsmousedevprint);
331 
332 	/*
333 	 * power management events
334 	 */
335 	sc->sc_power_hook = powerhook_establish(device_xname(sc->sc_dev),
336 	    vrpiu_power, sc);
337 	if (sc->sc_power_hook == NULL)
338 		aprint_error("%s: WARNING: couldn't establish powerhook\n",
339 		    device_xname(sc->sc_dev));
340 
341 	/*
342 	 * init A/D port polling.
343 	 */
344 	sc->sc_battery.n_values = 3;
345 	sc->sc_battery.value[0] = -1;
346 	sc->sc_battery.value[1] = -1;
347 	sc->sc_battery.value[2] = -1;
348 	sc->sc_battery.nextpoll = hz*vrpiu_ad_poll_interval;
349 	callout_init(&sc->sc_adpoll, 0);
350 	callout_reset(&sc->sc_adpoll, hz, vrpiu_start_powerstate, sc);
351 }
352 
353 /*
354  * calculate interval value
355  *  input: WSMOUSE_RES_MIN - WSMOUSE_RES_MAX
356  * output: value for PIUSIVL_REG
357  */
358 static u_int
359 scan_interval(u_int data)
360 {
361 	int scale;
362 
363 	if (data < WSMOUSE_RES_MIN)
364 		data = WSMOUSE_RES_MIN;
365 
366 	if (WSMOUSE_RES_MAX < data)
367 		data = WSMOUSE_RES_MAX;
368 
369 	scale = WSMOUSE_RES_MAX - WSMOUSE_RES_MIN;
370 	data += WSMOUSE_RES_MIN;
371 
372 	return PIUSIVL_SCANINTVAL_MIN +
373 	    (PIUSIVL_SCANINTVAL_MAX - PIUSIVL_SCANINTVAL_MIN) *
374 	    (scale - data) / scale;
375 }
376 
377 int
378 vrpiu_ad_enable(void *v)
379 {
380 	struct vrpiu_softc *sc = v;
381 	int s;
382 	unsigned int cnt;
383 
384 	DPRINTF(("%s(%d): vrpiu_ad_enable(): interval=0x%03x\n",
385 	    __FILE__, __LINE__, sc->sc_interval));
386 	if (sc->sc_adstat != VRPIU_AD_STAT_DISABLE)
387 		return EBUSY;
388 
389 	/* supply clock to PIU */
390 	vrip_power(sc->sc_vrip, sc->sc_unit, 1);
391 
392 	/* set scan interval */
393 	vrpiu_write(sc, PIUSIVL_REG_W, sc->sc_interval);
394 
395 	s = spltty();
396 
397 	/* clear interrupt status */
398 	vrpiu_write(sc, PIUINT_REG_W, AD_INTR);
399 
400 	/* Disable -> Standby */
401 	cnt = PIUCNT_PIUPWR |
402 	    PIUCNT_PIUMODE_COORDINATE |
403 	    PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
404 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
405 
406 	/* Level2 interrupt register setting */
407 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AD_INTR, 1);
408 
409 	/* save pen status, touch or release */
410 	cnt = vrpiu_read(sc, PIUCNT_REG_W);
411 
412 	/*
413 	 * Enable scan sequencer operation
414 	 * Standby -> WaitPenTouch
415 	 */
416 	cnt |= PIUCNT_PIUSEQEN;
417 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
418 
419 	sc->sc_adstat = VRPIU_AD_STAT_ENABLE;
420 
421 	splx(s);
422 
423 	return 0;
424 }
425 
426 void
427 vrpiu_ad_disable(void *v)
428 {
429 	struct vrpiu_softc *sc = v;
430 
431 	DPRINTF(("%s(%d): vrpiu_ad_disable()\n", __FILE__, __LINE__));
432 
433 	/* Set level2 interrupt register to mask interrupts */
434 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AD_INTR, 0);
435 
436 	sc->sc_adstat = VRPIU_AD_STAT_DISABLE;
437 
438 	if (sc->sc_tpstat == VRPIU_TP_STAT_DISABLE){
439 		/* Disable scan sequencer operation and power off */
440 		vrpiu_write(sc, PIUCNT_REG_W, 0);
441 
442 		/* mask clock to PIU */
443 		vrip_power(sc->sc_vrip, sc->sc_unit, 0);
444 	}
445 }
446 
447 int
448 vrpiu_tp_enable(void *v)
449 {
450 	struct vrpiu_softc *sc = v;
451 	int s;
452 	unsigned int cnt;
453 
454 	DPRINTF(("%s(%d): vrpiu_tp_enable(): interval=0x%03x\n",
455 	    __FILE__, __LINE__, sc->sc_interval));
456 	if (sc->sc_tpstat != VRPIU_TP_STAT_DISABLE)
457 		return EBUSY;
458 
459 	/* supply clock to PIU */
460 	vrip_power(sc->sc_vrip, sc->sc_unit, 1);
461 
462 	/* set scan interval */
463 	vrpiu_write(sc, PIUSIVL_REG_W, sc->sc_interval);
464 
465 	s = spltty();
466 
467 	/* clear interrupt status */
468 	vrpiu_write(sc, PIUINT_REG_W, TP_INTR);
469 
470 	/* Disable -> Standby */
471 	cnt = PIUCNT_PIUPWR |
472 	    PIUCNT_PIUMODE_COORDINATE |
473 	    PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
474 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
475 
476 	/* Level2 interrupt register setting */
477 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, TP_INTR, 1);
478 
479 	/* save pen status, touch or release */
480 	cnt = vrpiu_read(sc, PIUCNT_REG_W);
481 
482 	/*
483 	 * Enable scan sequencer operation
484 	 * Standby -> WaitPenTouch
485 	 */
486 	cnt |= PIUCNT_PIUSEQEN;
487 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
488 
489 	/* transit status DISABLE -> TOUCH or RELEASE */
490 	sc->sc_tpstat = (cnt & PIUCNT_PENSTC) ?
491 	    VRPIU_TP_STAT_TOUCH : VRPIU_TP_STAT_RELEASE;
492 
493 	splx(s);
494 
495 	return 0;
496 }
497 
498 void
499 vrpiu_tp_disable(void *v)
500 {
501 	struct vrpiu_softc *sc = v;
502 
503 	DPRINTF(("%s(%d): vrpiu_tp_disable()\n", __FILE__, __LINE__));
504 
505 	/* Set level2 interrupt register to mask interrupts */
506 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, TP_INTR, 0);
507 
508 	sc->sc_tpstat = VRPIU_TP_STAT_DISABLE;
509 
510 	if (sc->sc_adstat == VRPIU_AD_STAT_DISABLE){
511 		/* Disable scan sequencer operation and power off */
512 		vrpiu_write(sc, PIUCNT_REG_W, 0);
513 
514 		/* mask clock to PIU */
515 		vrip_power(sc->sc_vrip, sc->sc_unit, 0);
516 	}
517 }
518 
519 int
520 vrpiu_tp_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
521 {
522 	struct vrpiu_softc *sc = v;
523 
524 	DPRINTF(("%s(%d): vrpiu_tp_ioctl(%08lx)\n", __FILE__, __LINE__, cmd));
525 
526 	switch (cmd) {
527 	case WSMOUSEIO_SRES:
528 	{
529 		int tp_enable;
530 		int ad_enable;
531 
532 		tp_enable = (sc->sc_tpstat != VRPIU_TP_STAT_DISABLE);
533 		ad_enable = (sc->sc_adstat != VRPIU_AD_STAT_DISABLE);
534 
535 		if (tp_enable)
536 			vrpiu_tp_disable(sc);
537 		if (ad_enable)
538 			vrpiu_ad_disable(sc);
539 
540 		sc->sc_interval = scan_interval(*(u_int *)data);
541 		DPRINTF(("%s(%d): WSMOUSEIO_SRES: *data=%d, interval=0x%03x\n",
542 		    __FILE__, __LINE__, *(u_int *)data, sc->sc_interval));
543 
544 		if (sc->sc_interval < PIUSIVL_SCANINTVAL_MIN)
545 			sc->sc_interval = PIUSIVL_SCANINTVAL_MIN;
546 
547 		if (PIUSIVL_SCANINTVAL_MAX < sc->sc_interval)
548 			sc->sc_interval = PIUSIVL_SCANINTVAL_MAX;
549 
550 		if (tp_enable)
551 			vrpiu_tp_enable(sc);
552 		if (ad_enable)
553 			vrpiu_ad_enable(sc);
554 	}
555 	break;
556 
557 	default:
558 		return hpc_tpanel_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
559 	}
560 	return 0;
561 }
562 
563 /*
564  * PIU AD interrupt handler.
565  */
566 void
567 vrpiu_ad_intr(struct vrpiu_softc *sc)
568 {
569 	unsigned int i;
570 	unsigned int intrstat;
571 
572 	intrstat = vrpiu_read(sc, PIUINT_REG_W);
573 
574 	if (sc->sc_adstat == VRPIU_AD_STAT_DISABLE) {
575 		/*
576 		 * the device isn't enabled. just clear interrupt.
577 		 */
578 		vrpiu_write(sc, PIUINT_REG_W, AD_INTR);
579 		return;
580 	}
581 
582 	if (intrstat & PIUINT_PADADPINTR) {
583 		sc->sc_battery.value[0] = (unsigned int)
584 		    vrpiu_buf_read(sc, PIUAB(0));
585 		sc->sc_battery.value[1] = (unsigned int)
586 		    vrpiu_buf_read(sc, PIUAB(1));
587 		sc->sc_battery.value[2] = (unsigned int)
588 		    vrpiu_buf_read(sc, PIUAB(2));
589 	}
590 
591 	if (intrstat & PIUINT_PADADPINTR) {
592 		for (i = 0; i < 3; i++) {
593 			if (sc->sc_battery.value[i] & PIUAB_VALID)
594 				sc->sc_battery.value[i] &=
595 					sc->sc_ab_paddata_mask;
596 			else
597 				sc->sc_battery.value[i] = 0;
598 		}
599 		vrpiu_calc_powerstate(sc);
600 	}
601 	vrpiu_write(sc, PIUINT_REG_W, AD_INTR);
602 
603 	return;
604 }
605 /*
606  * PIU TP interrupt handler.
607  */
608 void
609 vrpiu_tp_intr(struct vrpiu_softc *sc)
610 {
611 	unsigned int cnt, i;
612 	unsigned int intrstat, page;
613 	int tpx0, tpx1, tpy0, tpy1;
614 	int x, y, xraw, yraw;
615 
616 	tpx0 = tpx1 = tpy0 = tpy1 = 0;	/* XXX: gcc -Wuninitialized */
617 
618 	intrstat = vrpiu_read(sc, PIUINT_REG_W);
619 
620 	if (sc->sc_tpstat == VRPIU_TP_STAT_DISABLE) {
621 		/*
622 		 * the device isn't enabled. just clear interrupt.
623 		 */
624 		vrpiu_write(sc, PIUINT_REG_W, intrstat & TP_INTR);
625 		return;
626 	}
627 
628 	page = (intrstat & PIUINT_OVP) ? 1 : 0;
629 	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
630 		tpx0 = vrpiu_buf_read(sc, PIUPB(page, 0));
631 		tpx1 = vrpiu_buf_read(sc, PIUPB(page, 1));
632 		tpy0 = vrpiu_buf_read(sc, PIUPB(page, 2));
633 		tpy1 = vrpiu_buf_read(sc, PIUPB(page, 3));
634 	}
635 
636 	if (intrstat & PIUINT_PADDLOSTINTR) {
637 		page = page ? 0 : 1;
638 		for (i = 0; i < 4; i++)
639 			vrpiu_buf_read(sc, PIUPB(page, i));
640 	}
641 
642 	cnt = vrpiu_read(sc, PIUCNT_REG_W);
643 #ifdef DEBUG
644 	if (vrpiu_debug)
645 		vrpiu_dump_cntreg(cnt);
646 #endif
647 
648 	/* clear interrupt status */
649 	vrpiu_write(sc, PIUINT_REG_W, intrstat & TP_INTR);
650 
651 #if 0
652 	DPRINTF(("vrpiu_intr: OVP=%d", page));
653 	if (intrstat & PIUINT_PADCMDINTR)
654 		DPRINTF((" CMD"));
655 	if (intrstat & PIUINT_PADADPINTR)
656 		DPRINTF((" A/D"));
657 	if (intrstat & PIUINT_PADPAGE1INTR)
658 		DPRINTF((" PAGE1"));
659 	if (intrstat & PIUINT_PADPAGE0INTR)
660 		DPRINTF((" PAGE0"));
661 	if (intrstat & PIUINT_PADDLOSTINTR)
662 		DPRINTF((" DLOST"));
663 	if (intrstat & PIUINT_PENCHGINTR)
664 		DPRINTF((" PENCHG"));
665 	DPRINTF(("\n"));
666 #endif
667 	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
668 		/*
669 		 * just ignore scan data if status isn't Touch.
670 		 */
671 		if (sc->sc_tpstat == VRPIU_TP_STAT_TOUCH) {
672 			/* reset tp scan timeout	*/
673 			callout_reset(&sc->sc_tptimeout, VRPIU_TP_SCAN_TIMEOUT,
674 			    vrpiu_tp_timeout, sc);
675 
676 			if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) &&
677 			    (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) {
678 				printf("vrpiu: internal error,"
679 				    " data is not valid!\n");
680 			} else {
681 				tpx0 &= sc->sc_pb_paddata_mask;
682 				tpx1 &= sc->sc_pb_paddata_mask;
683 				tpy0 &= sc->sc_pb_paddata_mask;
684 				tpy1 &= sc->sc_pb_paddata_mask;
685 #define ISVALID(n, c)	((c) - (c)/5 < (n) && (n) < (c) + (c)/5)
686 				if (ISVALID(tpx0 + tpx1, sc->sc_pb_paddata_max) &&
687 				    ISVALID(tpy0 + tpy1, sc->sc_pb_paddata_max)) {
688 #if 0
689 					DPRINTF(("%04x %04x %04x %04x\n",
690 					    tpx0, tpx1, tpy0, tpy1));
691 					DPRINTF(("%3d %3d (%4d %4d)->", tpx0,
692 					    tpy0, tpx0 + tpx1, tpy0 + tpy1));
693 #endif
694 					xraw = tpy1 * sc->sc_pb_paddata_max / (tpy0 + tpy1);
695 					yraw = tpx1 * sc->sc_pb_paddata_max / (tpx0 + tpx1);
696 					DPRINTF(("%3d %3d", xraw, yraw));
697 
698 					tpcalib_trans(&sc->sc_tpcalib, xraw,
699 					    yraw, &x, &y);
700 
701 					DPRINTF(("->%4d %4d", x, y));
702 					wsmouse_input(sc->sc_wsmousedev,
703 					    1, /* button 0 down */
704 					    x, /* x */
705 					    y, /* y */
706 					    0, /* z */
707 					    0, /* w */
708 					    WSMOUSE_INPUT_ABSOLUTE_X |
709 					    WSMOUSE_INPUT_ABSOLUTE_Y);
710 					DPRINTF(("\n"));
711 				}
712 			}
713 		}
714 	}
715 
716 	if (cnt & PIUCNT_PENSTC) {
717 		if (sc->sc_tpstat == VRPIU_TP_STAT_RELEASE) {
718 			/*
719 			 * pen touch
720 			 */
721 			DPRINTF(("PEN TOUCH\n"));
722 			sc->sc_tpstat = VRPIU_TP_STAT_TOUCH;
723 			/*
724 			 * We should not report button down event while
725 			 * we don't know where it occur.
726 			 */
727 
728 			/* set tp scan timeout	*/
729 			callout_reset(&sc->sc_tptimeout, VRPIU_TP_SCAN_TIMEOUT,
730 			    vrpiu_tp_timeout, sc);
731 		}
732 	} else {
733 		vrpiu_tp_up(sc);
734 	}
735 
736 	if (intrstat & PIUINT_PADDLOSTINTR) {
737 		cnt |= PIUCNT_PIUSEQEN;
738 		vrpiu_write(sc, PIUCNT_REG_W, cnt);
739 	}
740 
741 	return;
742 }
743 
744 void
745 vrpiu_tp_up(struct vrpiu_softc *sc)
746 {
747 	if (sc->sc_tpstat == VRPIU_TP_STAT_TOUCH) {
748 		/*
749 		 * pen release
750 		 */
751 		DPRINTF(("RELEASE\n"));
752 		sc->sc_tpstat = VRPIU_TP_STAT_RELEASE;
753 
754 		/* clear tp scan timeout	*/
755 		callout_stop(&sc->sc_tptimeout);
756 
757 		/* button 0 UP */
758 		wsmouse_input(sc->sc_wsmousedev, 0, 0, 0, 0, 0, 0);
759 	}
760 }
761 
762 /* touch panel timeout handler */
763 void
764 vrpiu_tp_timeout(void *v)
765 {
766 	struct vrpiu_softc *sc = (struct vrpiu_softc *)v;
767 
768 #ifdef VRPIUDEBUG
769 	{
770 		unsigned int cnt = vrpiu_read(sc, PIUCNT_REG_W);
771 		DPRINTF(("TIMEOUT: stat=%s  reg=%s\n",
772 		    (sc->sc_tpstat == VRPIU_TP_STAT_TOUCH)?"touch":"release",
773 		    (cnt & PIUCNT_PENSTC)?"touch":"release"));
774 	}
775 #endif
776 	vrpiu_tp_up(sc);
777 }
778 
779 /*
780  * PIU interrupt handler.
781  */
782 int
783 vrpiu_intr(void *arg)
784 {
785         struct vrpiu_softc *sc = arg;
786 
787 	vrpiu_ad_intr(sc);
788 	vrpiu_tp_intr(sc);
789 
790 	return 0;
791 }
792 
793 void
794 vrpiu_start_powerstate(void *v)
795 {
796 	int mask;
797 	struct vrpiu_softc *sc = (struct vrpiu_softc *)v;
798 
799 	vrpiu_ad_enable(sc);
800 	mask = vrpiu_read(sc, PIUAMSK_REG_W);
801 	mask &= 0xff8f; /* XXX */
802 	vrpiu_write(sc, PIUAMSK_REG_W, mask);
803 	vrpiu_write(sc, PIUASCN_REG_W, PIUACN_ADPSSTART);
804 	/*
805 	 * restart next A/D polling
806 	 */
807 	callout_reset(&sc->sc_adpoll, hz*vrpiu_ad_poll_interval,
808 	    vrpiu_start_powerstate, sc);
809 }
810 
811 void
812 vrpiu_calc_powerstate(struct vrpiu_softc *sc)
813 {
814 	extern void vrgiu_diff_io(void);
815 	vrpiu_ad_disable(sc);
816 	VPRINTF(("vrpiu:AD: %d, %d, %d\n",
817 	    sc->sc_battery.value[0],
818 	    sc->sc_battery.value[1],
819 	    sc->sc_battery.value[2]));
820 	sc->sc_battery.nextpoll = hz*vrpiu_ad_poll_interval;
821 	vrpiu_send_battery_event(sc);
822 	/*
823 	 * restart next A/D polling if change polling timming.
824 	 */
825 	if (sc->sc_battery.nextpoll != hz*vrpiu_ad_poll_interval)
826 		callout_reset(&sc->sc_adpoll, sc->sc_battery.nextpoll,
827 		    vrpiu_start_powerstate, sc);
828 	if (bootverbose)
829 		vrgiu_diff_io();
830 
831 }
832 
833 static void
834 vrpiu_power(int why, void *arg)
835 {
836 	struct vrpiu_softc *sc = arg;
837 
838 	switch (why) {
839 	case PWR_STANDBY:
840 	case PWR_SUSPEND:
841 		break;
842 	case PWR_RESUME:
843 		callout_reset(&sc->sc_adpoll, hz,
844 		    vrpiu_start_powerstate, sc);
845 		break;
846 	}
847 }
848 
849 static void
850 vrpiu_send_battery_event(struct vrpiu_softc *sc)
851 {
852 #ifdef VRPIU_ADHOC_BATTERY_EVENT
853 	static int batteryhigh = 0;
854 	static int batterylow = 0;
855 	static int critical = 0;
856 
857 	if (sc->sc_battery_spec == NULL
858 	    || sc->sc_battery_spec->main_port == -1)
859 		return;
860 
861 	if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
862 	    <= sc->sc_battery_spec->dc_critical) {
863 		batteryhigh = 0;
864 		config_hook_call(CONFIG_HOOK_PMEVENT,
865 		    CONFIG_HOOK_PMEVENT_BATTERY,
866 		    (void *)CONFIG_HOOK_BATT_CRITICAL);
867 		batterylow = 3;
868 		if (critical) {
869 			config_hook_call(CONFIG_HOOK_PMEVENT,
870 			    CONFIG_HOOK_PMEVENT_SUSPENDREQ,
871 			    (void *)0);
872 			critical = 0;
873 			batterylow = 0;
874 		}
875 		critical++;
876 	} else if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
877 	    <= sc->sc_battery_spec->dc_20p) {
878 		batteryhigh = 0;
879 		if (batterylow == 1)
880 			config_hook_call(CONFIG_HOOK_PMEVENT,
881 			    CONFIG_HOOK_PMEVENT_BATTERY,
882 			    (void *)CONFIG_HOOK_BATT_20P);
883 		config_hook_call(CONFIG_HOOK_PMEVENT,
884 		    CONFIG_HOOK_PMEVENT_BATTERY,
885 		    (void *)CONFIG_HOOK_BATT_LOW);
886 		batterylow = 2;
887 	} else if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
888 	    <= sc->sc_battery_spec->dc_50p) {
889 		batteryhigh = 0;
890 		if (batterylow == 0) {
891 			batterylow = 1;
892 			config_hook_call(CONFIG_HOOK_PMEVENT,
893 			    CONFIG_HOOK_PMEVENT_BATTERY,
894 			    (void *)CONFIG_HOOK_BATT_50P);
895 		}
896 	} else if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
897 	    >= sc->sc_battery_spec->ac_80p) {
898 		batterylow = 0;
899 		if (batteryhigh == 0) {
900 			batteryhigh = 1;
901 			config_hook_call(CONFIG_HOOK_PMEVENT,
902 			    CONFIG_HOOK_PMEVENT_BATTERY,
903 			    (void *)CONFIG_HOOK_BATT_80P);
904 			config_hook_call(CONFIG_HOOK_PMEVENT,
905 			    CONFIG_HOOK_PMEVENT_BATTERY,
906 			    (void *)CONFIG_HOOK_BATT_HIGH);
907 		}
908 	}
909 #else /* VRPIU_ADHOC_BATTERY_EVENT */
910 	config_hook_call(CONFIG_HOOK_SET,
911 	    CONFIG_HOOK_BATTERYVAL,
912 	    (void *)&sc->sc_battery);
913 #endif /* VRPIU_ADHOC_BATTERY_EVENT */
914 }
915 
916 #ifdef DEBUG
917 void
918 vrpiu_dump_cntreg(unsigned int cnt)
919 {
920 	printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release");
921 	printf(" state=");
922 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan)
923 		printf("CmdScan");
924 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan)
925 		printf("IntervalNextScan");
926 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan)
927 		printf("PenDataScan");
928 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch)
929 		printf("WaitPenTouch");
930 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU)
931 		printf("???");
932 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan)
933 		printf("ADPortScan");
934 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby)
935 		printf("Standby");
936 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable)
937 		printf("Disable");
938 	if (cnt & PIUCNT_PADATSTOP)
939 		printf(" AutoStop");
940 	if (cnt & PIUCNT_PADATSTART)
941 		printf(" AutoStart");
942 	if (cnt & PIUCNT_PADSCANSTOP)
943 		printf(" Stop");
944 	if (cnt & PIUCNT_PADSCANSTART)
945 		printf(" Start");
946 	if (cnt & PIUCNT_PADSCANTYPE)
947 		printf(" ScanPressure");
948 	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER)
949 		printf(" A/D");
950 	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE)
951 		printf(" Coordinate");
952 	if (cnt & PIUCNT_PIUSEQEN)
953 		printf(" SeqEn");
954 	if ((cnt & PIUCNT_PIUPWR) == 0)
955 		printf(" PowerOff");
956 	if ((cnt & PIUCNT_PADRST) == 0)
957 		printf(" Reset");
958 	printf("\n");
959 }
960 #endif
961