xref: /netbsd-src/sys/arch/hpcsh/dev/psh3tp.c (revision 7433666e375b3ac4cc764df5a6726be98bc1cdd5)
1*7433666eSthorpej /*	$NetBSD: psh3tp.c,v 1.18 2023/12/20 14:50:02 thorpej Exp $	*/
2725081c0Skiyohara /*
3725081c0Skiyohara  * Copyright (c) 2005 KIYOHARA Takashi
4725081c0Skiyohara  * All rights reserved.
5725081c0Skiyohara  *
6725081c0Skiyohara  * Redistribution and use in source and binary forms, with or without
7725081c0Skiyohara  * modification, are permitted provided that the following conditions
8725081c0Skiyohara  * are met:
9725081c0Skiyohara  * 1. Redistributions of source code must retain the above copyright
10725081c0Skiyohara  *    notice, this list of conditions and the following disclaimer.
11725081c0Skiyohara  * 2. Redistributions in binary form must reproduce the above copyright
12725081c0Skiyohara  *    notice, this list of conditions and the following disclaimer in the
13725081c0Skiyohara  *    documentation and/or other materials provided with the distribution.
14725081c0Skiyohara  *
15725081c0Skiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16725081c0Skiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17725081c0Skiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18725081c0Skiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19725081c0Skiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20725081c0Skiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21725081c0Skiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22725081c0Skiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23725081c0Skiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24725081c0Skiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25725081c0Skiyohara  * POSSIBILITY OF SUCH DAMAGE.
26725081c0Skiyohara  *
27725081c0Skiyohara  */
28725081c0Skiyohara 
29725081c0Skiyohara #include <sys/cdefs.h>
30725081c0Skiyohara 
31e3e6e213Skiyohara #include <sys/types.h>
32725081c0Skiyohara #include <sys/param.h>
33725081c0Skiyohara #include <sys/device.h>
34e3e6e213Skiyohara #include <sys/errno.h>
35e3e6e213Skiyohara #include <sys/kernel.h>
36725081c0Skiyohara #include <sys/systm.h>
37725081c0Skiyohara #include <sys/callout.h>
38725081c0Skiyohara 
39725081c0Skiyohara #include "opt_psh3tp.h"
40725081c0Skiyohara 
41725081c0Skiyohara #include <dev/wscons/wsconsio.h>
42725081c0Skiyohara #include <dev/wscons/wsmousevar.h>
43725081c0Skiyohara #include <dev/hpc/hpctpanelvar.h>
44725081c0Skiyohara 
45725081c0Skiyohara #include <machine/platid.h>
46725081c0Skiyohara #include <machine/platid_mask.h>
47725081c0Skiyohara 
48725081c0Skiyohara #include <machine/intr.h>
49725081c0Skiyohara 
50725081c0Skiyohara #include <sh3/exception.h>
51725081c0Skiyohara #include <sh3/intcreg.h>
52725081c0Skiyohara #include <sh3/pfcreg.h>
53725081c0Skiyohara #include <sh3/adcreg.h>
54725081c0Skiyohara 
55725081c0Skiyohara #include <sh3/dev/adcvar.h>
56725081c0Skiyohara 
57725081c0Skiyohara 
58725081c0Skiyohara #ifdef PSH3TP_DEBUG
59725081c0Skiyohara volatile int psh3tp_debug = 4;
60725081c0Skiyohara #define DPRINTF_PRINTF		printf_nolog
61725081c0Skiyohara #define DPRINTF(arg)		if (psh3tp_debug) DPRINTF_PRINTF arg
62725081c0Skiyohara #define DPRINTFN(n, arg)	if (psh3tp_debug > (n)) DPRINTF_PRINTF arg
63725081c0Skiyohara #else
64725081c0Skiyohara #define DPRINTF(arg)		((void)0)
65725081c0Skiyohara #define DPRINTFN(n, arg)	((void)0)
66725081c0Skiyohara #endif
67725081c0Skiyohara 
68725081c0Skiyohara 
69725081c0Skiyohara /*
70725081c0Skiyohara  * PFC bits pertinent to PERSONA HPW-50PA touch-panel
71725081c0Skiyohara  */
72725081c0Skiyohara #define PHDR_TP_PEN_UP		0x40
73725081c0Skiyohara #define SCPDR_TP_SCAN_ENABLE	0x20
74725081c0Skiyohara #define SCPDR_TP_SCAN_DISABLE	0x01
75725081c0Skiyohara #define SCPDR_TP_SCAN_X		0x06
76725081c0Skiyohara #define SCPDR_TP_SCAN_Y		0x09
77725081c0Skiyohara 
78725081c0Skiyohara /*
79725081c0Skiyohara  * A/D converter channels to get x/y from
80725081c0Skiyohara  */
81725081c0Skiyohara #define ADC_CHANNEL_TP_X	1
82725081c0Skiyohara #define ADC_CHANNEL_TP_Y	0
83725081c0Skiyohara 
84725081c0Skiyohara /*
85725081c0Skiyohara  * Default (read: my device) raw X/Y values for framebuffer edges.
86725081c0Skiyohara  */
87725081c0Skiyohara #define PSH3TP_FB_RIGHT		 56
88725081c0Skiyohara #define PSH3TP_FB_LEFT		969
89725081c0Skiyohara #define PSH3TP_FB_TOP		848
90725081c0Skiyohara #define PSH3TP_FB_BOTTOM	121
91725081c0Skiyohara 
92725081c0Skiyohara 
93725081c0Skiyohara struct psh3tp_softc {
94aaf18737Skiyohara 	device_t sc_dev;
95725081c0Skiyohara 
96725081c0Skiyohara #define PSH3TP_WSMOUSE_ENABLED	0x01
97725081c0Skiyohara 	int sc_enabled;
98725081c0Skiyohara 	struct callout sc_touch_ch;
99aaf18737Skiyohara 	device_t sc_wsmousedev;
100725081c0Skiyohara 	struct tpcalib_softc sc_tpcalib; /* calibration info for wsmouse */
101725081c0Skiyohara };
102725081c0Skiyohara 
103725081c0Skiyohara 
104725081c0Skiyohara /* config machinery */
105aaf18737Skiyohara static int psh3tp_match(device_t, struct cfdata *, void *);
106aaf18737Skiyohara static void psh3tp_attach(device_t, device_t, void *);
107725081c0Skiyohara 
108725081c0Skiyohara /* wsmouse accessops */
109725081c0Skiyohara static int psh3tp_wsmouse_enable(void *);
11053524e44Schristos static int psh3tp_wsmouse_ioctl(void *, u_long, void *, int, struct lwp *);
111725081c0Skiyohara static void psh3tp_wsmouse_disable(void *);
112725081c0Skiyohara 
113725081c0Skiyohara /* internal driver routines */
114725081c0Skiyohara static void psh3tp_enable(struct psh3tp_softc *);
115725081c0Skiyohara static void psh3tp_disable(struct psh3tp_softc *);
116725081c0Skiyohara static int psh3tp_set_enable(struct psh3tp_softc *, int, int);
117725081c0Skiyohara static int psh3tp_intr(void *);
118725081c0Skiyohara static void psh3tp_start_polling(void *);
119725081c0Skiyohara static void psh3tp_stop_polling(struct psh3tp_softc *);
120725081c0Skiyohara static void psh3tp_callout_wsmouse(void *);
121725081c0Skiyohara static void psh3tp_wsmouse_input(struct psh3tp_softc *, int, int);
122725081c0Skiyohara static void psh3tp_get_raw_xy(int *, int *);
123725081c0Skiyohara 
124725081c0Skiyohara 
125725081c0Skiyohara const struct wsmouse_accessops psh3tp_accessops = {
126725081c0Skiyohara 	psh3tp_wsmouse_enable,
127725081c0Skiyohara 	psh3tp_wsmouse_ioctl,
128725081c0Skiyohara 	psh3tp_wsmouse_disable
129725081c0Skiyohara };
130725081c0Skiyohara 
131725081c0Skiyohara static const struct wsmouse_calibcoords psh3tp_default_calib = {
132725081c0Skiyohara 	0, 0, 639, 239,
133725081c0Skiyohara 	4,
134725081c0Skiyohara 	{{ PSH3TP_FB_LEFT,  PSH3TP_FB_TOP,      0,   0 },
135725081c0Skiyohara 	 { PSH3TP_FB_RIGHT, PSH3TP_FB_TOP,    639,   0 },
136725081c0Skiyohara 	 { PSH3TP_FB_LEFT,  PSH3TP_FB_BOTTOM,   0, 239 },
137725081c0Skiyohara 	 { PSH3TP_FB_RIGHT, PSH3TP_FB_BOTTOM, 639, 239 }}
138725081c0Skiyohara };
139725081c0Skiyohara 
140725081c0Skiyohara 
141aaf18737Skiyohara CFATTACH_DECL_NEW(psh3tp, sizeof(struct psh3tp_softc),
142725081c0Skiyohara     psh3tp_match, psh3tp_attach, NULL, NULL);
143725081c0Skiyohara 
144725081c0Skiyohara 
145e3e6e213Skiyohara /* ARGSUSED */
146725081c0Skiyohara static int
psh3tp_match(device_t parent __unused,struct cfdata * cf,void * aux __unused)147aaf18737Skiyohara psh3tp_match(device_t parent __unused, struct cfdata *cf, void *aux __unused)
148725081c0Skiyohara {
149725081c0Skiyohara 
150725081c0Skiyohara 	if (!platid_match(&platid, &platid_mask_MACH_HITACHI_PERSONA))
151e3e6e213Skiyohara 		return 0;
152725081c0Skiyohara 
153725081c0Skiyohara 	if (strcmp(cf->cf_name, "psh3tp") != 0)
154e3e6e213Skiyohara 		return 0;
155725081c0Skiyohara 
156e3e6e213Skiyohara 	return 1;
157725081c0Skiyohara }
158725081c0Skiyohara 
159725081c0Skiyohara 
160725081c0Skiyohara /*
161725081c0Skiyohara  * Attach the touch panel driver and its wsmouse child.
162725081c0Skiyohara  *
163725081c0Skiyohara  * Note that we have to use submatch to distinguish between child because
164725081c0Skiyohara  * wsmouse_match matches unconditionally.
165725081c0Skiyohara  */
166e3e6e213Skiyohara /* ARGSUSED */
167725081c0Skiyohara static void
psh3tp_attach(device_t parent __unused,device_t self,void * aux __unused)168aaf18737Skiyohara psh3tp_attach(device_t parent __unused, device_t self, void *aux __unused)
169725081c0Skiyohara {
170e3e6e213Skiyohara 	struct psh3tp_softc *sc = device_private(self);
171725081c0Skiyohara 	struct wsmousedev_attach_args wsma;
172725081c0Skiyohara 
173e3e6e213Skiyohara 	aprint_naive("\n");
174e3e6e213Skiyohara 	aprint_normal("\n");
175725081c0Skiyohara 
176aaf18737Skiyohara 	sc->sc_dev = self;
177725081c0Skiyohara 	sc->sc_enabled = 0;
178725081c0Skiyohara 
179725081c0Skiyohara 	/* touch-panel as a pointing device */
180725081c0Skiyohara 	wsma.accessops = &psh3tp_accessops;
181725081c0Skiyohara 	wsma.accesscookie = sc;
182725081c0Skiyohara 
1832685996bSthorpej 	sc->sc_wsmousedev = config_found(
184c7fb772bSthorpej 	    self, &wsma, wsmousedevprint, CFARGS_NONE);
185725081c0Skiyohara 	if (sc->sc_wsmousedev == NULL)
186725081c0Skiyohara 		return;
187725081c0Skiyohara 
188725081c0Skiyohara 	/* init calibration, set default parameters */
189725081c0Skiyohara 	tpcalib_init(&sc->sc_tpcalib);
19094216ed6Suwe 	tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
19153524e44Schristos 	    (void *)__UNCONST(&psh3tp_default_calib), 0, 0);
192725081c0Skiyohara 
193725081c0Skiyohara 	/* used when in polling mode */
19488ab7da9Sad 	callout_init(&sc->sc_touch_ch, 0);
195725081c0Skiyohara 
196725081c0Skiyohara 	/* establish interrupt handler, but disable until opened */
197725081c0Skiyohara 	intc_intr_establish(SH7709_INTEVT2_IRQ2,
198725081c0Skiyohara 	    IST_EDGE, IPL_TTY, psh3tp_intr, sc);
199725081c0Skiyohara 	intc_intr_disable(SH7709_INTEVT2_IRQ2);
2001edc5585Skiyohara 
2011edc5585Skiyohara  	if (!pmf_device_register(self, NULL, NULL))
2021edc5585Skiyohara  		aprint_error_dev(self, "unable to establish power handler\n");
203725081c0Skiyohara }
204725081c0Skiyohara 
205725081c0Skiyohara 
206725081c0Skiyohara /*
207725081c0Skiyohara  * Enable touch panel:  we start in interrupt mode.
208725081c0Skiyohara  * Must be called at spltty().
209725081c0Skiyohara  */
210e3e6e213Skiyohara /* ARGSUSED */
211725081c0Skiyohara static void
psh3tp_enable(struct psh3tp_softc * sc __unused)212e3e6e213Skiyohara psh3tp_enable(struct psh3tp_softc *sc __unused)
213725081c0Skiyohara {
214725081c0Skiyohara 
215be240ba6Schs 	DPRINTFN(2, ("%s: enable\n", device_xname(sc->sc_dev)));
216725081c0Skiyohara 	intc_intr_enable(SH7709_INTEVT2_IRQ2);
217725081c0Skiyohara }
218725081c0Skiyohara 
219725081c0Skiyohara 
220725081c0Skiyohara /*
221725081c0Skiyohara  * Disable touch panel: disable interrupt, cancel pending callout.
222725081c0Skiyohara  * Must be called at spltty().
223725081c0Skiyohara  */
224725081c0Skiyohara static void
psh3tp_disable(struct psh3tp_softc * sc)225725081c0Skiyohara psh3tp_disable(struct psh3tp_softc *sc)
226725081c0Skiyohara {
227725081c0Skiyohara 
228be240ba6Schs 	DPRINTFN(2, ("%s: disable\n", device_xname(sc->sc_dev)));
229725081c0Skiyohara 	intc_intr_disable(SH7709_INTEVT2_IRQ2);
230725081c0Skiyohara 	callout_stop(&sc->sc_touch_ch);
231725081c0Skiyohara }
232725081c0Skiyohara 
233725081c0Skiyohara 
234725081c0Skiyohara static int
psh3tp_set_enable(struct psh3tp_softc * sc,int on,int child)235725081c0Skiyohara psh3tp_set_enable(struct psh3tp_softc *sc, int on, int child)
236725081c0Skiyohara {
237725081c0Skiyohara 	int s = spltty();
238725081c0Skiyohara 
239725081c0Skiyohara 	if (on) {
240725081c0Skiyohara 		if (!sc->sc_enabled)
241725081c0Skiyohara 			psh3tp_enable(sc);
242725081c0Skiyohara 		sc->sc_enabled |= child;
243725081c0Skiyohara 	} else {
244725081c0Skiyohara 		sc->sc_enabled &= ~child;
245725081c0Skiyohara 		if (!sc->sc_enabled)
246725081c0Skiyohara 			psh3tp_disable(sc);
247725081c0Skiyohara 	}
248725081c0Skiyohara 
249725081c0Skiyohara 	splx(s);
250e3e6e213Skiyohara 	return 0;
251725081c0Skiyohara }
252725081c0Skiyohara 
253725081c0Skiyohara 
254725081c0Skiyohara static int
psh3tp_wsmouse_enable(void * cookie)25546e6b513Stsutsui psh3tp_wsmouse_enable(void *cookie)
256725081c0Skiyohara {
25746e6b513Stsutsui 	struct psh3tp_softc *sc = (struct psh3tp_softc *)cookie;
258725081c0Skiyohara 
259be240ba6Schs 	DPRINTFN(1, ("%s: wsmouse enable\n", device_xname(sc->sc_dev)));
260e3e6e213Skiyohara 	return psh3tp_set_enable(sc, 1, PSH3TP_WSMOUSE_ENABLED);
261725081c0Skiyohara }
262725081c0Skiyohara 
263725081c0Skiyohara 
264725081c0Skiyohara static void
psh3tp_wsmouse_disable(void * cookie)26546e6b513Stsutsui psh3tp_wsmouse_disable(void *cookie)
266725081c0Skiyohara {
26746e6b513Stsutsui 	struct psh3tp_softc *sc = (struct psh3tp_softc *)cookie;
268725081c0Skiyohara 
269be240ba6Schs 	DPRINTFN(1, ("%s: wsmouse disable\n", device_xname(sc->sc_dev)));
270725081c0Skiyohara 	psh3tp_set_enable(sc, 0, PSH3TP_WSMOUSE_ENABLED);
271725081c0Skiyohara }
272725081c0Skiyohara 
273725081c0Skiyohara 
274725081c0Skiyohara static int
psh3tp_intr(void * arg)27546e6b513Stsutsui psh3tp_intr(void *arg)
276725081c0Skiyohara {
27746e6b513Stsutsui 	struct psh3tp_softc *sc = (struct psh3tp_softc *)arg;
278725081c0Skiyohara 
279725081c0Skiyohara 	uint8_t irr0;
280725081c0Skiyohara 	uint8_t phdr, touched;
281725081c0Skiyohara 	unsigned int steady, tremor_timeout;
282725081c0Skiyohara 
283725081c0Skiyohara 	irr0 = _reg_read_1(SH7709_IRR0);
284725081c0Skiyohara 	if ((irr0 & IRR0_IRQ2) == 0) {
285725081c0Skiyohara #ifdef DIAGNOSTIC
286be240ba6Schs 		printf("%s: irr0 %02x?\n", device_xname(sc->sc_dev), irr0);
287725081c0Skiyohara #endif
288e3e6e213Skiyohara 		return 0;
289725081c0Skiyohara 	}
290725081c0Skiyohara 
291725081c0Skiyohara 	if (!sc->sc_enabled) {
292be240ba6Schs 		DPRINTFN(1, ("%s: intr: !sc_enabled\n", device_xname(sc->sc_dev)));
293725081c0Skiyohara 		intc_intr_disable(SH7709_INTEVT2_IRQ2);
294725081c0Skiyohara 		goto served;
295725081c0Skiyohara 	}
296725081c0Skiyohara 
297725081c0Skiyohara 	/*
298725081c0Skiyohara 	 * Number of times the "touched" bit should be read
299725081c0Skiyohara 	 * consecutively.
300725081c0Skiyohara 	 */
301725081c0Skiyohara #define TREMOR_THRESHOLD 0x300
302725081c0Skiyohara 	steady = 0;
303725081c0Skiyohara 	tremor_timeout = TREMOR_THRESHOLD * 16;	/* XXX: arbitrary */
30416ed6645Sthorpej 	touched = true;		/* we start with "touched" state */
305725081c0Skiyohara 
306725081c0Skiyohara 	do {
307725081c0Skiyohara 		uint8_t state;
308725081c0Skiyohara 
309725081c0Skiyohara 		phdr = _reg_read_1(SH7709_PHDR);
310725081c0Skiyohara 		state = ((phdr & PHDR_TP_PEN_UP) != PHDR_TP_PEN_UP);
311725081c0Skiyohara 
312725081c0Skiyohara 		if (state == touched)
313725081c0Skiyohara 			++steady;
314725081c0Skiyohara 		else {
315725081c0Skiyohara 			steady = 0;
316725081c0Skiyohara 			touched = state;
317725081c0Skiyohara 		}
318725081c0Skiyohara 
319725081c0Skiyohara 		if (--tremor_timeout == 0) {
320be240ba6Schs 			DPRINTF(("%s: tremor timeout!\n",
321be240ba6Schs 			    device_xname(sc->sc_dev)));
322725081c0Skiyohara 			goto served;
323725081c0Skiyohara 		}
324725081c0Skiyohara 	} while (steady < TREMOR_THRESHOLD);
325725081c0Skiyohara 
326725081c0Skiyohara 	if (touched) {
327725081c0Skiyohara 		intc_intr_disable(SH7709_INTEVT2_IRQ2);
328725081c0Skiyohara 
329725081c0Skiyohara 		/*
330725081c0Skiyohara 		 * ADC readings are not stable yet, so schedule
331725081c0Skiyohara 		 * callout instead of accessing ADC from the interrupt
332725081c0Skiyohara 		 * handler only to immediately delay().
333725081c0Skiyohara 		 */
334725081c0Skiyohara 		callout_reset(&sc->sc_touch_ch,
335725081c0Skiyohara 		    hz/32, psh3tp_start_polling, sc);
336725081c0Skiyohara 	} else
337be240ba6Schs 		DPRINTFN(1, ("%s: tremor\n", device_xname(sc->sc_dev)));
338725081c0Skiyohara served:
339725081c0Skiyohara 	/* clear the interrupt */
340725081c0Skiyohara 	_reg_write_1(SH7709_IRR0, irr0 & ~IRR0_IRQ2);
341725081c0Skiyohara 
342e3e6e213Skiyohara 	return 1;
343725081c0Skiyohara }
344725081c0Skiyohara 
345725081c0Skiyohara 
346725081c0Skiyohara /*
347725081c0Skiyohara  * Called from the interrupt handler at spltty() upon first touch.
348725081c0Skiyohara  * Decide if we are going to report this touch as a mouse click/drag.
349725081c0Skiyohara  */
350725081c0Skiyohara static void
psh3tp_start_polling(void * arg)35146e6b513Stsutsui psh3tp_start_polling(void *arg)
352725081c0Skiyohara {
35346e6b513Stsutsui 	struct psh3tp_softc *sc = (struct psh3tp_softc *)arg;
354725081c0Skiyohara 	uint8_t phdr;
355725081c0Skiyohara 	int rawx, rawy;
356725081c0Skiyohara 
357725081c0Skiyohara 	phdr = _reg_read_1(SH7709_PHDR);
358725081c0Skiyohara 	if ((phdr & PHDR_TP_PEN_UP) == PHDR_TP_PEN_UP) {
359725081c0Skiyohara 		DPRINTFN(2, ("%s: start: pen is not down\n",
360be240ba6Schs 		    device_xname(sc->sc_dev)));
361725081c0Skiyohara 		psh3tp_stop_polling(sc);
362725081c0Skiyohara 		return;
363725081c0Skiyohara 	}
364725081c0Skiyohara 
365725081c0Skiyohara 	psh3tp_get_raw_xy(&rawx, &rawy);
366725081c0Skiyohara 	DPRINTFN(2, ("%s: start: %4d %4d -> ",
367be240ba6Schs 	    device_xname(sc->sc_dev), rawx, rawy));
368725081c0Skiyohara 
369725081c0Skiyohara 	if (sc->sc_enabled & PSH3TP_WSMOUSE_ENABLED) {
370725081c0Skiyohara 		DPRINTFN(2, ("mouse\n"));
371725081c0Skiyohara 		psh3tp_wsmouse_input(sc, rawx, rawy);
372725081c0Skiyohara 		callout_reset(&sc->sc_touch_ch,
373725081c0Skiyohara 		    hz/32, psh3tp_callout_wsmouse, sc);
374725081c0Skiyohara 	} else {
375725081c0Skiyohara 		DPRINTFN(2, ("ignore\n"));
376725081c0Skiyohara 		psh3tp_stop_polling(sc);
377725081c0Skiyohara 	}
378725081c0Skiyohara }
379725081c0Skiyohara 
380725081c0Skiyohara 
381725081c0Skiyohara /*
382725081c0Skiyohara  * Re-enable touch panel interrupt.
383725081c0Skiyohara  * Called at spltty() when polling code detects pen-up.
384725081c0Skiyohara  */
385e3e6e213Skiyohara /* ARGSUSED */
386725081c0Skiyohara static void
psh3tp_stop_polling(struct psh3tp_softc * sc __unused)387e3e6e213Skiyohara psh3tp_stop_polling(struct psh3tp_softc *sc __unused)
388725081c0Skiyohara {
389725081c0Skiyohara 	uint8_t irr0;
390725081c0Skiyohara 
391be240ba6Schs 	DPRINTFN(2, ("%s: stop\n", device_xname(sc->sc_dev)));
392725081c0Skiyohara 
393725081c0Skiyohara 	/* clear pending interrupt signal before re-enabling the interrupt */
394725081c0Skiyohara 	irr0 = _reg_read_1(SH7709_IRR0);
395725081c0Skiyohara 	if ((irr0 & IRR0_IRQ2) != 0)
396725081c0Skiyohara 		_reg_write_1(SH7709_IRR0, irr0 & ~IRR0_IRQ2);
397725081c0Skiyohara 
398725081c0Skiyohara 	intc_intr_enable(SH7709_INTEVT2_IRQ2);
399725081c0Skiyohara }
400725081c0Skiyohara 
401725081c0Skiyohara 
402725081c0Skiyohara /*
403725081c0Skiyohara  * We are reporting this touch as a mouse click/drag.
404725081c0Skiyohara  */
405725081c0Skiyohara static void
psh3tp_callout_wsmouse(void * arg)40646e6b513Stsutsui psh3tp_callout_wsmouse(void *arg)
407725081c0Skiyohara {
40846e6b513Stsutsui 	struct psh3tp_softc *sc = (struct psh3tp_softc *)arg;
409725081c0Skiyohara 	uint8_t phdr;
410725081c0Skiyohara 	int rawx, rawy;
411725081c0Skiyohara 	int s;
412725081c0Skiyohara 
413725081c0Skiyohara 	s = spltty();
414725081c0Skiyohara 
415725081c0Skiyohara 	if (!sc->sc_enabled) {
416725081c0Skiyohara 		DPRINTFN(1, ("%s: wsmouse callout: !sc_enabled\n",
417be240ba6Schs 		    device_xname(sc->sc_dev)));
418725081c0Skiyohara 		splx(s);
419725081c0Skiyohara 		return;
420725081c0Skiyohara 	}
421725081c0Skiyohara 
422725081c0Skiyohara 	phdr = _reg_read_1(SH7709_PHDR);
423725081c0Skiyohara 	if ((phdr & PHDR_TP_PEN_UP) != PHDR_TP_PEN_UP) {
424725081c0Skiyohara 		psh3tp_get_raw_xy(&rawx, &rawy);
425725081c0Skiyohara 		psh3tp_wsmouse_input(sc, rawx, rawy); /* mouse dragged */
426725081c0Skiyohara 		callout_schedule(&sc->sc_touch_ch, hz/32);
427725081c0Skiyohara 	} else {
428725081c0Skiyohara 		wsmouse_input( /* button up */
42957c0199dSplunky 		    sc->sc_wsmousedev, 0, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA);
430725081c0Skiyohara 		psh3tp_stop_polling(sc);
431725081c0Skiyohara 	}
432725081c0Skiyohara 	splx(s);
433725081c0Skiyohara }
434725081c0Skiyohara 
435725081c0Skiyohara 
436725081c0Skiyohara /*
437725081c0Skiyohara  * Report mouse click/drag.
438725081c0Skiyohara  */
439725081c0Skiyohara static void
psh3tp_wsmouse_input(struct psh3tp_softc * sc,int rawx,int rawy)440725081c0Skiyohara psh3tp_wsmouse_input(struct psh3tp_softc *sc, int rawx, int rawy)
441725081c0Skiyohara {
442725081c0Skiyohara 	int x, y;
443725081c0Skiyohara 
444725081c0Skiyohara 	tpcalib_trans(&sc->sc_tpcalib, rawx, rawy, &x, &y);
445725081c0Skiyohara 
446725081c0Skiyohara 	DPRINTFN(3, ("%s: %4d %4d -> %3d %3d\n",
447be240ba6Schs 	     device_xname(sc->sc_dev), rawx, rawy, x, y));
448725081c0Skiyohara 
449725081c0Skiyohara 	wsmouse_input(sc->sc_wsmousedev,
450725081c0Skiyohara 	    1,	/* button */
45157c0199dSplunky 	    x, y, 0, 0,
452725081c0Skiyohara 	    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
453725081c0Skiyohara }
454725081c0Skiyohara 
455725081c0Skiyohara 
456725081c0Skiyohara /*
457725081c0Skiyohara  * Read raw X/Y coordinates from the ADC.
458725081c0Skiyohara  */
459725081c0Skiyohara static void
psh3tp_get_raw_xy(int * rawxp,int * rawyp)460725081c0Skiyohara psh3tp_get_raw_xy(int *rawxp, int *rawyp)
461725081c0Skiyohara {
462725081c0Skiyohara 	uint8_t scpdr;
463725081c0Skiyohara 
464725081c0Skiyohara 	/* X axis */
465725081c0Skiyohara 	scpdr = _reg_read_1(SH7709_SCPDR);
466725081c0Skiyohara 	scpdr &= ~SCPDR_TP_SCAN_DISABLE;
467725081c0Skiyohara 	scpdr |= (SCPDR_TP_SCAN_ENABLE | SCPDR_TP_SCAN_X);
468725081c0Skiyohara 	_reg_write_1(SH7709_SCPDR, scpdr);
469725081c0Skiyohara 	delay(40);
470725081c0Skiyohara 
471725081c0Skiyohara 	*rawxp = adc_sample_channel(ADC_CHANNEL_TP_X);
472725081c0Skiyohara 
473725081c0Skiyohara 	/* Y axis */
474725081c0Skiyohara 	scpdr = _reg_read_1(SH7709_SCPDR);
475725081c0Skiyohara 	scpdr &=  ~SCPDR_TP_SCAN_X;
476725081c0Skiyohara 	scpdr |= (SCPDR_TP_SCAN_ENABLE | SCPDR_TP_SCAN_Y);
477725081c0Skiyohara 	_reg_write_1(SH7709_SCPDR, scpdr);
478725081c0Skiyohara 	delay(40);
479725081c0Skiyohara 
480725081c0Skiyohara 	*rawyp = adc_sample_channel(ADC_CHANNEL_TP_Y);
481725081c0Skiyohara 
482725081c0Skiyohara 	/* restore SCPDR */
483725081c0Skiyohara 	scpdr = _reg_read_1(SH7709_SCPDR);
484725081c0Skiyohara 	scpdr &= ~(SCPDR_TP_SCAN_ENABLE | SCPDR_TP_SCAN_Y);
485725081c0Skiyohara 	scpdr |= SCPDR_TP_SCAN_DISABLE;
486725081c0Skiyohara 	_reg_write_1(SH7709_SCPDR, scpdr);
487725081c0Skiyohara }
488725081c0Skiyohara 
489725081c0Skiyohara 
490725081c0Skiyohara static int
psh3tp_wsmouse_ioctl(void * cookie,u_long cmd,void * data,int flag,struct lwp * l)49146e6b513Stsutsui psh3tp_wsmouse_ioctl(void *cookie, u_long cmd, void *data, int flag,
492e3e6e213Skiyohara 		     struct lwp *l)
493725081c0Skiyohara {
49446e6b513Stsutsui 	struct psh3tp_softc *sc = (struct psh3tp_softc *)cookie;
495725081c0Skiyohara 
496e3e6e213Skiyohara 	return hpc_tpanel_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
497725081c0Skiyohara }
498