1 /* $NetBSD: j720tp.c,v 1.9 2008/04/28 20:23:21 martin Exp $ */
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by IWAMOTO Toshihiro and Peter Postma.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 /* Jornada 720 touch-panel driver. */
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: j720tp.c,v 1.9 2008/04/28 20:23:21 martin Exp $");
38 #include "opt_j720tp.h"
39 #include "opt_wsdisplay_compat.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/ioctl.h>
48 #include <sys/callout.h>
49 #include <sys/sysctl.h>
51 #include <machine/platid.h>
52 #include <machine/platid_mask.h>
54 #include <arm/sa11x0/sa11x0_var.h>
55 #include <arm/sa11x0/sa11x0_gpioreg.h>
56 #include <arm/sa11x0/sa11x0_ppcreg.h>
57 #include <arm/sa11x0/sa11x0_sspreg.h>
59 #include <dev/wscons/wsconsio.h>
60 #include <dev/wscons/wsmousevar.h>
61 #include <dev/wscons/wskbdvar.h>
62 #include <dev/wscons/wsksymvar.h>
63 #include <dev/wscons/wsksymdef.h>
64 #include <dev/hpc/hpctpanelvar.h>
66 #include <hpcarm/dev/j720sspvar.h>
68 #ifdef WSDISPLAY_COMPAT_RAWKBD
69 #include <dev/hpc/pckbd_encode.h>
72 #define arraysize(ary) (sizeof(ary) / sizeof(ary[0]))
76 #define DPRINTF(arg) if (j720tp_debug) aprint_normal arg
77 #define DPRINTFN(n, arg) if (j720tp_debug >= (n)) aprint_normal arg
79 #define DPRINTF(arg) /* nothing */
80 #define DPRINTFN(n, arg) /* nothing */
86 #define J720TP_WSMOUSE_ENABLED 0x01
87 #define J720TP_WSKBD_ENABLED 0x02
90 #ifdef WSDISPLAY_COMPAT_RAWKBD
94 struct callout sc_tpcallout
;
95 struct j720ssp_softc
*sc_ssp
;
97 device_t sc_wsmousedev
;
100 struct tpcalib_softc sc_tpcalib
;
103 static int j720tp_match(device_t
, cfdata_t
, void *);
104 static void j720tp_attach(device_t
, device_t
, void *);
106 static int j720tp_wsmouse_enable(void *);
107 static int j720tp_wsmouse_ioctl(void *, u_long
, void *, int,
109 static void j720tp_wsmouse_disable(void *);
111 static int j720tp_wskbd_enable(void *, int);
112 static void j720tp_wskbd_set_leds(void *, int);
113 static int j720tp_wskbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
115 static void j720tp_enable_intr(struct j720tp_softc
*);
116 static void j720tp_disable_intr(struct j720tp_softc
*);
117 static int j720tp_intr(void *);
118 static int j720tp_get_rawxy(struct j720tp_softc
*, int *, int *);
119 static int j720tp_get_hard_icon(struct j720tp_softc
*, int, int);
120 static void j720tp_wsmouse_input(struct j720tp_softc
*, int, int);
121 static void j720tp_wsmouse_callout(void *);
122 static void j720tp_wskbd_input(struct j720tp_softc
*, u_int
);
123 static void j720tp_wskbd_callout(void *);
125 const struct wsmouse_accessops j720tp_wsmouse_accessops
= {
126 j720tp_wsmouse_enable
,
127 j720tp_wsmouse_ioctl
,
128 j720tp_wsmouse_disable
131 static const struct wsmouse_calibcoords j720tp_default_calib
= {
136 { 988, 927, 0, 239 },
137 { 88, 940, 639, 239 }}
140 const struct wskbd_accessops j720tp_wskbd_accessops
= {
142 j720tp_wskbd_set_leds
,
146 #ifndef J720TP_SETTINGS_ICON_KEYSYM
147 #define J720TP_SETTINGS_ICON_KEYSYM KS_Home
149 #ifndef J720TP_BACKUP_ICON_KEYSYM
150 #define J720TP_BACKUP_ICON_KEYSYM KS_Prior
152 #ifndef J720TP_DIALUP_ICON_KEYSYM
153 #define J720TP_DIALUP_ICON_KEYSYM KS_Next
155 #ifndef J720TP_MEDIA_ICON_KEYSYM
156 #define J720TP_MEDIA_ICON_KEYSYM KS_End
159 /* Max Y value of the n'th hard icon. */
160 #define J720TP_HARD_ICON_MAX_Y(n) \
161 (((j720tp_hard_icon_bottom - j720tp_hard_icon_top) / 4) * (n)) + \
164 /* Default raw X/Y values of the hard icon area. */
165 static int j720tp_hard_icon_left
= 70;
166 static int j720tp_hard_icon_right
= 20;
167 static int j720tp_hard_icon_top
= 70;
168 static int j720tp_hard_icon_bottom
= 940;
170 /* Maps the icon number to a raw keycode. */
171 static const int j720tp_wskbd_keys
[] = {
178 static const keysym_t j720tp_wskbd_keydesc
[] = {
179 KS_KEYCODE(199), J720TP_SETTINGS_ICON_KEYSYM
,
180 KS_KEYCODE(201), J720TP_BACKUP_ICON_KEYSYM
,
181 KS_KEYCODE(209), J720TP_DIALUP_ICON_KEYSYM
,
182 KS_KEYCODE(207), J720TP_MEDIA_ICON_KEYSYM
185 const struct wscons_keydesc j720tp_wskbd_keydesctab
[] = {
187 sizeof(j720tp_wskbd_keydesc
) / sizeof(keysym_t
),
193 const struct wskbd_mapdata j720tp_wskbd_keymapdata
= {
194 j720tp_wskbd_keydesctab
, KB_US
197 CFATTACH_DECL_NEW(j720tp
, sizeof(struct j720tp_softc
),
198 j720tp_match
, j720tp_attach
, NULL
, NULL
);
202 j720tp_match(device_t parent
, cfdata_t cf
, void *aux
)
205 if (!platid_match(&platid
, &platid_mask_MACH_HP_JORNADA_7XX
))
207 if (strcmp(cf
->cf_name
, "j720tp") != 0)
214 j720tp_attach(device_t parent
, device_t self
, void *aux
)
216 struct j720tp_softc
*sc
= device_private(self
);
217 struct wsmousedev_attach_args wsma
;
218 struct wskbddev_attach_args wska
;
223 sc
->sc_ssp
= device_private(parent
);
225 sc
->sc_hard_icon
= 0;
228 /* Touch-panel as a pointing device. */
229 wsma
.accessops
= &j720tp_wsmouse_accessops
;
230 wsma
.accesscookie
= sc
;
232 sc
->sc_wsmousedev
= config_found_ia(self
, "wsmousedev", &wsma
,
234 if (sc
->sc_wsmousedev
== NULL
)
237 /* Initialize calibration, set default parameters. */
238 tpcalib_init(&sc
->sc_tpcalib
);
239 tpcalib_ioctl(&sc
->sc_tpcalib
, WSMOUSEIO_SCALIBCOORDS
,
240 __UNCONST(&j720tp_default_calib
), 0, 0);
242 callout_init(&sc
->sc_tpcallout
, 0);
244 j720tp_wsmouse_disable(sc
);
246 /* On-screen "hard icons" as a keyboard device. */
248 wska
.keymap
= &j720tp_wskbd_keymapdata
;
249 wska
.accessops
= &j720tp_wskbd_accessops
;
250 wska
.accesscookie
= sc
;
252 sc
->sc_wskbddev
= config_found_ia(self
, "wskbddev", &wska
,
255 /* Setup touch-panel interrupt. */
256 sa11x0_intr_establish(0, 9, 1, IPL_TTY
, j720tp_intr
, sc
);
260 j720tp_wsmouse_enable(void *self
)
262 struct j720tp_softc
*sc
= self
;
267 j720tp_enable_intr(sc
);
269 sc
->sc_enabled
|= J720TP_WSMOUSE_ENABLED
;
276 j720tp_wsmouse_ioctl(void *self
, u_long cmd
, void *data
, int flag
,
279 struct j720tp_softc
*sc
= self
;
281 return hpc_tpanel_ioctl(&sc
->sc_tpcalib
, cmd
, data
, flag
, l
);
285 j720tp_wsmouse_disable(void *self
)
287 struct j720tp_softc
*sc
= self
;
292 j720tp_disable_intr(sc
);
293 callout_stop(&sc
->sc_tpcallout
);
295 sc
->sc_enabled
&= ~J720TP_WSMOUSE_ENABLED
;
301 j720tp_wskbd_enable(void *self
, int on
)
303 struct j720tp_softc
*sc
= self
;
307 sc
->sc_enabled
|= J720TP_WSKBD_ENABLED
;
314 j720tp_wskbd_set_leds(void *self
, int leds
)
320 j720tp_wskbd_ioctl(void *self
, u_long cmd
, void *data
, int flag
,
323 #ifdef WSDISPLAY_COMPAT_RAWKBD
324 struct j720tp_softc
*sc
= self
;
329 *(int *)data
= WSKBD_TYPE_HPC_BTN
;
331 case WSKBDIO_GETLEDS
:
334 #ifdef WSDISPLAY_COMPAT_RAWKBD
335 case WSKBDIO_SETMODE
:
336 sc
->sc_rawkbd
= (*(int *)data
== WSKBD_RAW
);
345 * Enable touch-panel interrupt. Must be called at spltty().
348 j720tp_enable_intr(struct j720tp_softc
*sc
)
350 struct j720ssp_softc
*ssp
= sc
->sc_ssp
;
353 er
= bus_space_read_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_FER
);
355 bus_space_write_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_FER
, er
);
359 * Disable touch-panel interrupt. Must be called at spltty().
362 j720tp_disable_intr(struct j720tp_softc
*sc
)
364 struct j720ssp_softc
*ssp
= sc
->sc_ssp
;
367 er
= bus_space_read_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_FER
);
369 bus_space_write_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_FER
, er
);
373 j720tp_intr(void *arg
)
375 struct j720tp_softc
*sc
= arg
;
376 struct j720ssp_softc
*ssp
= sc
->sc_ssp
;
379 bus_space_write_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_EDR
, 1 << 9);
381 if (!(sc
->sc_enabled
& J720TP_WSMOUSE_ENABLED
)) {
382 DPRINTF(("j720tp_intr: !sc_enabled\n"));
386 j720tp_disable_intr(sc
);
388 if (j720tp_get_rawxy(sc
, &rawx
, &rawy
)) {
389 sc
->sc_hard_icon
= j720tp_get_hard_icon(sc
, rawx
, rawy
);
391 if (sc
->sc_hard_icon
> 0) {
392 j720tp_wskbd_input(sc
, WSCONS_EVENT_KEY_DOWN
);
393 callout_reset(&sc
->sc_tpcallout
, hz
/ 32,
394 j720tp_wskbd_callout
, sc
);
396 j720tp_wsmouse_input(sc
, rawx
, rawy
);
397 callout_reset(&sc
->sc_tpcallout
, hz
/ 32,
398 j720tp_wsmouse_callout
, sc
);
406 j720tp_get_rawxy(struct j720tp_softc
*sc
, int *rawx
, int *rawy
)
408 struct j720ssp_softc
*ssp
= sc
->sc_ssp
;
411 bus_space_write_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_PCR
, 0x2000000);
413 /* Send read touch-panel command. */
414 if (j720ssp_readwrite(ssp
, 1, 0xa0, &data
, 100) < 0 || data
!= 0x11) {
415 DPRINTF(("j720tp_get_rawxy: no dummy received\n"));
419 for (i
= 0; i
< 8; i
++) {
420 if (j720ssp_readwrite(ssp
, 0, 0x11, &data
, 100) < 0)
425 bus_space_write_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_PSR
, 0x2000000);
429 for (i
= 0; i
< 3; i
++) {
430 buf
[i
] |= buf
[6] & 0x300;
432 buf
[i
+ 3] |= buf
[7] & 0x300;
436 DPRINTFN(2, ("j720tp_get_rawxy: %d:%d:%d:%d:%d:%d:%d:%d\n",
437 buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5], buf
[6], buf
[7]));
444 bus_space_write_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_PSR
, 0x2000000);
447 bus_space_write_4(ssp
->sc_iot
, ssp
->sc_ssph
, SASSP_CR0
, 0x307);
449 bus_space_write_4(ssp
->sc_iot
, ssp
->sc_ssph
, SASSP_CR0
, 0x387);
451 DPRINTF(("j720tp_get_rawxy: error %x\n", data
));
456 j720tp_get_hard_icon(struct j720tp_softc
*sc
, int rawx
, int rawy
)
460 if (!(sc
->sc_enabled
& J720TP_WSKBD_ENABLED
))
462 /* Check if the touch was in the hard icons area. */
463 if (rawx
> j720tp_hard_icon_left
)
466 if (rawy
< J720TP_HARD_ICON_MAX_Y(1))
468 else if (rawy
< J720TP_HARD_ICON_MAX_Y(2))
470 else if (rawy
< J720TP_HARD_ICON_MAX_Y(3))
472 else if (rawy
< J720TP_HARD_ICON_MAX_Y(4))
479 j720tp_wsmouse_input(struct j720tp_softc
*sc
, int rawx
, int rawy
)
483 tpcalib_trans(&sc
->sc_tpcalib
, rawx
, rawy
, &x
, &y
);
484 wsmouse_input(sc
->sc_wsmousedev
, 1, x
, y
, 0, 0,
485 WSMOUSE_INPUT_ABSOLUTE_X
| WSMOUSE_INPUT_ABSOLUTE_Y
);
489 j720tp_wsmouse_callout(void *arg
)
491 struct j720tp_softc
*sc
= arg
;
492 struct j720ssp_softc
*ssp
= sc
->sc_ssp
;
497 if (!(sc
->sc_enabled
& J720TP_WSMOUSE_ENABLED
)) {
498 DPRINTF(("j720tp_wsmouse_callout: !sc_enabled\n"));
503 if (bus_space_read_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_PLR
) & (1<<9)) {
504 wsmouse_input(sc
->sc_wsmousedev
, 0, 0, 0, 0, 0, 0);
505 j720tp_enable_intr(sc
);
507 if (j720tp_get_rawxy(sc
, &rawx
, &rawy
))
508 j720tp_wsmouse_input(sc
, rawx
, rawy
);
509 callout_schedule(&sc
->sc_tpcallout
, hz
/ 32);
516 j720tp_wskbd_input(struct j720tp_softc
*sc
, u_int evtype
)
518 int key
= j720tp_wskbd_keys
[sc
->sc_hard_icon
- 1];
520 #ifdef WSDISPLAY_COMPAT_RAWKBD
525 n
= pckbd_encode(evtype
, key
, data
);
526 wskbd_rawinput(sc
->sc_wskbddev
, data
, n
);
529 wskbd_input(sc
->sc_wskbddev
, evtype
, key
);
533 j720tp_wskbd_callout(void *arg
)
535 struct j720tp_softc
*sc
= arg
;
536 struct j720ssp_softc
*ssp
= sc
->sc_ssp
;
541 if (!sc
->sc_enabled
) {
542 DPRINTF(("j720tp_wskbd_callout: !sc_enabled\n"));
547 if (bus_space_read_4(ssp
->sc_iot
, ssp
->sc_gpioh
, SAGPIO_PLR
) & (1<<9)) {
548 j720tp_wskbd_input(sc
, WSCONS_EVENT_KEY_UP
);
549 j720tp_enable_intr(sc
);
551 callout_schedule(&sc
->sc_tpcallout
, hz
/ 32);
557 SYSCTL_SETUP(sysctl_j720tp
, "sysctl j720tp subtree setup")
559 const struct sysctlnode
*rnode
;
562 if ((rc
= sysctl_createv(clog
, 0, NULL
, &rnode
,
563 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, "hw", NULL
,
564 NULL
, 0, NULL
, 0, CTL_HW
, CTL_EOL
)) != 0)
567 if ((rc
= sysctl_createv(clog
, 0, &rnode
, &rnode
,
568 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, "j720tp",
569 SYSCTL_DESCR("Jornada 720 touch panel controls"),
570 NULL
, 0, NULL
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
574 if ((rc
= sysctl_createv(clog
, 0, &rnode
, NULL
,
575 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
, CTLTYPE_INT
, "debug",
576 SYSCTL_DESCR("Verbosity of debugging messages"),
577 NULL
, 0, &j720tp_debug
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
579 #endif /* J720TP_DEBUG */
581 if ((rc
= sysctl_createv(clog
, 0, &rnode
, &rnode
,
582 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, "hard_icons",
583 SYSCTL_DESCR("Touch panel hard icons controls"),
584 NULL
, 0, NULL
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
587 if ((rc
= sysctl_createv(clog
, 0, &rnode
, NULL
,
588 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
, CTLTYPE_INT
, "left",
589 SYSCTL_DESCR("Raw left X value of the hard icon area"),
590 NULL
, 0, &j720tp_hard_icon_left
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
593 if ((rc
= sysctl_createv(clog
, 0, &rnode
, NULL
,
594 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
, CTLTYPE_INT
, "right",
595 SYSCTL_DESCR("Raw right X value of the hard icon area"),
596 NULL
, 0, &j720tp_hard_icon_right
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
599 if ((rc
= sysctl_createv(clog
, 0, &rnode
, NULL
,
600 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
, CTLTYPE_INT
, "top",
601 SYSCTL_DESCR("Raw top Y value of the hard icon area"),
602 NULL
, 0, &j720tp_hard_icon_top
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
605 if ((rc
= sysctl_createv(clog
, 0, &rnode
, NULL
,
606 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
, CTLTYPE_INT
, "bottom",
607 SYSCTL_DESCR("Raw bottom Y value of the hard icon area"),
608 NULL
, 0, &j720tp_hard_icon_bottom
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
613 aprint_normal("%s: sysctl_createv failed (rc = %d)\n", __func__
, rc
);