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