xref: /netbsd-src/sys/arch/hpcarm/dev/wzero3_keypad.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /*	$NetBSD: wzero3_keypad.c,v 1.6 2021/08/07 16:18:53 thorpej Exp $	*/
29f093235Snonaka 
32388feefSnonaka /*-
42388feefSnonaka  * Copyright (C) 2010 NONAKA Kimihiro <nonaka@netbsd.org>
59f093235Snonaka  * All rights reserved.
69f093235Snonaka  *
79f093235Snonaka  * Redistribution and use in source and binary forms, with or without
89f093235Snonaka  * modification, are permitted provided that the following conditions
99f093235Snonaka  * are met:
109f093235Snonaka  * 1. Redistributions of source code must retain the above copyright
119f093235Snonaka  *    notice, this list of conditions and the following disclaimer.
129f093235Snonaka  * 2. Redistributions in binary form must reproduce the above copyright
139f093235Snonaka  *    notice, this list of conditions and the following disclaimer in the
149f093235Snonaka  *    documentation and/or other materials provided with the distribution.
159f093235Snonaka  *
162388feefSnonaka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
172388feefSnonaka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
182388feefSnonaka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
192388feefSnonaka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
202388feefSnonaka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
212388feefSnonaka  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
222388feefSnonaka  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
232388feefSnonaka  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
242388feefSnonaka  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
252388feefSnonaka  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
269f093235Snonaka  */
279f093235Snonaka 
289f093235Snonaka #include <sys/cdefs.h>
29*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: wzero3_keypad.c,v 1.6 2021/08/07 16:18:53 thorpej Exp $");
309f093235Snonaka 
319f093235Snonaka #include "wzero3lcd.h"
329f093235Snonaka #include "opt_wsdisplay_compat.h"
339f093235Snonaka 
349f093235Snonaka #include <sys/param.h>
359f093235Snonaka #include <sys/systm.h>
369f093235Snonaka #include <sys/device.h>
379f093235Snonaka #include <sys/kernel.h>
389f093235Snonaka #include <sys/callout.h>
399edf49b0Sdyoung #include <sys/bus.h>
409f093235Snonaka 
419f093235Snonaka #include <arm/xscale/pxa2x0cpu.h>
429f093235Snonaka #include <arm/xscale/pxa2x0var.h>
439f093235Snonaka #include <arm/xscale/pxa2x0_gpio.h>
449f093235Snonaka 
459f093235Snonaka #include <machine/bootinfo.h>
469f093235Snonaka #include <machine/config_hook.h>
479f093235Snonaka #include <machine/platid.h>
489f093235Snonaka #include <machine/platid_mask.h>
499f093235Snonaka 
509f093235Snonaka #include <dev/wscons/wsconsio.h>
519f093235Snonaka #include <dev/wscons/wskbdvar.h>
529f093235Snonaka #include <dev/wscons/wsksymvar.h>
539f093235Snonaka #include <dev/wscons/wsksymdef.h>
549f093235Snonaka 
559f093235Snonaka #ifdef WSDISPLAY_COMPAT_RAWKBD
569f093235Snonaka #include <dev/hpc/pckbd_encode.h>
579f093235Snonaka #endif
589f093235Snonaka 
599f093235Snonaka #include <arch/hpcarm/dev/wzero3_reg.h>
609f093235Snonaka #include <arch/hpcarm/dev/wzero3_sspvar.h>
619f093235Snonaka 
629f093235Snonaka enum {
639f093235Snonaka 	KD_0,
649f093235Snonaka 	KD_1,
659f093235Snonaka 	KD_2,
669f093235Snonaka 	KD_3,
679f093235Snonaka 	KD_4,
689f093235Snonaka 	KD_5,
699f093235Snonaka 	KD_6,
709f093235Snonaka 	KD_7,
719f093235Snonaka 	KD_8,
729f093235Snonaka 	KD_9,
739f093235Snonaka 	KD_ASTERISK,
749f093235Snonaka 	KD_NUMBER,
759f093235Snonaka 	KD_WINDOWS,
769f093235Snonaka 	KD_OK,
779f093235Snonaka 	KD_ONHOOK,
789f093235Snonaka 	KD_OFFHOOK,
799f093235Snonaka 	KD_CLEAR,
809f093235Snonaka 	KD_MOJI,
819f093235Snonaka 	KD_UP,
829f093235Snonaka 	KD_DOWN,
839f093235Snonaka 	KD_LEFT,
849f093235Snonaka 	KD_RIGHT,
859f093235Snonaka 	KD_CENTER_BUTTON,
869f093235Snonaka 	KD_LSOFT,
879f093235Snonaka 	KD_RSOFT,
889f093235Snonaka 	KD_NUM,
899f093235Snonaka 
909f093235Snonaka 	KD_INVALID = -1
919f093235Snonaka };
929f093235Snonaka 
939f093235Snonaka static int ws011sh_keyscan2keydown[32] = {
949f093235Snonaka 	KD_INVALID,
959f093235Snonaka 	KD_CLEAR,
969f093235Snonaka 	KD_INVALID,
979f093235Snonaka 	KD_OK,
989f093235Snonaka 	KD_INVALID,
999f093235Snonaka 	KD_LEFT,
1009f093235Snonaka 	KD_INVALID,
1019f093235Snonaka 	KD_ONHOOK,
1029f093235Snonaka 	KD_INVALID,
1039f093235Snonaka 	KD_UP,
1049f093235Snonaka 	KD_DOWN,
1059f093235Snonaka 	KD_MOJI,
1069f093235Snonaka 	KD_INVALID,
1079f093235Snonaka 	KD_WINDOWS,
1089f093235Snonaka 	KD_INVALID,
1099f093235Snonaka 	KD_RIGHT,
1109f093235Snonaka 	KD_INVALID,
1119f093235Snonaka 	KD_1,
1129f093235Snonaka 	KD_4,
1139f093235Snonaka 	KD_7,
1149f093235Snonaka 	KD_ASTERISK,
1159f093235Snonaka 	KD_2,
1169f093235Snonaka 	KD_5,
1179f093235Snonaka 	KD_8,
1189f093235Snonaka 	KD_0,
1199f093235Snonaka 	KD_CENTER_BUTTON,
1209f093235Snonaka 	KD_INVALID,
1219f093235Snonaka 	KD_3,
1229f093235Snonaka 	KD_6,
1239f093235Snonaka 	KD_9,
1249f093235Snonaka 	KD_NUMBER,
1259f093235Snonaka 	KD_INVALID,
1269f093235Snonaka };
1279f093235Snonaka 
1289f093235Snonaka struct wzero3keypad_softc {
1299f093235Snonaka 	device_t sc_dev;
1309f093235Snonaka 
1319f093235Snonaka 	void *sc_ih;
1329f093235Snonaka 	int sc_intr_pin;
1339f093235Snonaka 
1349f093235Snonaka 	uint32_t sc_okeystat;
1359f093235Snonaka 
1369f093235Snonaka 	struct callout sc_poll_ch;
1379f093235Snonaka 	int sc_poll_interval;
1389f093235Snonaka 
1399f093235Snonaka 	device_t sc_wskbddev;
1409f093235Snonaka 
1419f093235Snonaka #ifdef WSDISPLAY_COMPAT_RAWKBD
1429f093235Snonaka 	int sc_rawkbd;
1439f093235Snonaka #endif
1449f093235Snonaka };
1459f093235Snonaka 
1469f093235Snonaka static int wzero3keypad_match(device_t, cfdata_t, void *);
1479f093235Snonaka static void wzero3keypad_attach(device_t, device_t, void *);
1489f093235Snonaka 
1499f093235Snonaka CFATTACH_DECL_NEW(wzero3keypad, sizeof(struct wzero3keypad_softc),
1509f093235Snonaka     wzero3keypad_match, wzero3keypad_attach, NULL, NULL);
1519f093235Snonaka 
1529f093235Snonaka static int wzero3keypad_wskbd_enable(void *, int);
1539f093235Snonaka static void wzero3keypad_wskbd_set_leds(void *, int);
1549f093235Snonaka static int wzero3keypad_wskbd_ioctl(void *, u_long, void *, int, struct lwp *);
1559f093235Snonaka 
1569f093235Snonaka static const int wzero3keypad_wskbd_keys[] = {
1579f093235Snonaka 	82,	/* KD_0: 0 */
1589f093235Snonaka 	79,	/* KD_1: 1 */
1599f093235Snonaka 	80,	/* KD_2: 2 */
1609f093235Snonaka 	81,	/* KD_3: 3 */
1619f093235Snonaka 	75,	/* KD_4: 4 */
1629f093235Snonaka 	76,	/* KD_5: 5 */
1639f093235Snonaka 	77,	/* KD_6: 6 */
1649f093235Snonaka 	71,	/* KD_7: 7 */
1659f093235Snonaka 	72,	/* KD_8: 8 */
1669f093235Snonaka 	73,	/* KD_9: 9 */
1679f093235Snonaka 	64,	/* KD_ASTERISK: f6 */
1689f093235Snonaka 	65,	/* KD_NUMBER: f7 */
1699f093235Snonaka 	221,	/* KD_WINDOWS: Menu */
1709f093235Snonaka 	61,	/* KD_OK: f3 */
1719f093235Snonaka 	59,	/* KD_ONHOOK: f1 */
1729f093235Snonaka 	60,	/* KD_OFFHOOK: f2 */
1739f093235Snonaka 	62,	/* KD_CLEAR: f4 */
1749f093235Snonaka 	63,	/* KD_MOJI: f5 */
1759f093235Snonaka 	200,	/* KD_UP: Up */
1769f093235Snonaka 	208,	/* KD_DOWN: Down */
1779f093235Snonaka 	203,	/* KD_LEFT: Left */
1789f093235Snonaka 	205,	/* KD_RIGHT: Right */
1799f093235Snonaka 	156,	/* KD_CENTER_BUTTON: KP_Enter */
1809f093235Snonaka 	87,	/* KD_LSOFT: f11 */
1819f093235Snonaka 	88,	/* KD_RSOFT: f12 */
1829f093235Snonaka };
1839f093235Snonaka 
1849f093235Snonaka static const keysym_t wzero3keypad_wskbd_keydesc[] = {
1859f093235Snonaka 	KS_KEYCODE(59),		KS_f1,
1869f093235Snonaka 	KS_KEYCODE(60),		KS_f2,
1879f093235Snonaka 	KS_KEYCODE(61),		KS_f3,
1889f093235Snonaka 	KS_KEYCODE(62),		KS_f4,
1899f093235Snonaka 	KS_KEYCODE(63),		KS_f5,
1909f093235Snonaka 	KS_KEYCODE(64),		KS_f6,
1919f093235Snonaka 	KS_KEYCODE(65),		KS_f7,
1929f093235Snonaka 	KS_KEYCODE(71),		KS_7,
1939f093235Snonaka 	KS_KEYCODE(72),		KS_8,
1949f093235Snonaka 	KS_KEYCODE(73),		KS_9,
1959f093235Snonaka 	KS_KEYCODE(75),		KS_4,
1969f093235Snonaka 	KS_KEYCODE(76),		KS_5,
1979f093235Snonaka 	KS_KEYCODE(77),		KS_6,
1989f093235Snonaka 	KS_KEYCODE(79),		KS_1,
1999f093235Snonaka 	KS_KEYCODE(80),		KS_2,
2009f093235Snonaka 	KS_KEYCODE(81),		KS_3,
2019f093235Snonaka 	KS_KEYCODE(82),		KS_0,
2029f093235Snonaka 	KS_KEYCODE(87),		KS_f11,
2039f093235Snonaka 	KS_KEYCODE(88),		KS_f12,
2049f093235Snonaka 	KS_KEYCODE(156),	KS_KP_Enter,
2059f093235Snonaka 	KS_KEYCODE(200),	KS_Up,
2069f093235Snonaka 	KS_KEYCODE(203),	KS_Left,
2079f093235Snonaka 	KS_KEYCODE(205),	KS_Right,
2089f093235Snonaka 	KS_KEYCODE(208),	KS_Down,
2099f093235Snonaka 	KS_KEYCODE(221),	KS_Menu,
2109f093235Snonaka };
2119f093235Snonaka 
2129f093235Snonaka static const struct wscons_keydesc wzero3keypad_wskbd_keydesctab[] = {
2139f093235Snonaka 	{ KB_JP, 0,
2149f093235Snonaka 	  sizeof(wzero3keypad_wskbd_keydesc) / sizeof(keysym_t),
2159f093235Snonaka 	  wzero3keypad_wskbd_keydesc
2169f093235Snonaka 	},
2179f093235Snonaka 
2189f093235Snonaka 	{ 0, 0, 0, 0 }
2199f093235Snonaka };
2209f093235Snonaka 
2219f093235Snonaka static const struct wskbd_mapdata wzero3keypad_wskbd_keymapdata = {
2229f093235Snonaka 	wzero3keypad_wskbd_keydesctab, KB_JP
2239f093235Snonaka };
2249f093235Snonaka 
2259f093235Snonaka static const struct wskbd_accessops wzero3keypad_wskbd_accessops = {
2269f093235Snonaka 	wzero3keypad_wskbd_enable,
2279f093235Snonaka 	wzero3keypad_wskbd_set_leds,
2289f093235Snonaka 	wzero3keypad_wskbd_ioctl,
2299f093235Snonaka };
2309f093235Snonaka 
2319f093235Snonaka static int wzero3keypad_intr(void *);
2329f093235Snonaka static void wzero3keypad_poll(void *);
2339f093235Snonaka static void wzero3keypad_poll1(struct wzero3keypad_softc *, int);
2349f093235Snonaka 
2359f093235Snonaka static void wzero3keypad_init(struct wzero3keypad_softc *);
2369f093235Snonaka static uint32_t wzero3keypad_getkeydown(struct wzero3keypad_softc *, int);
2379f093235Snonaka 
2389f093235Snonaka static const struct wzero3keypad_model {
2399f093235Snonaka 	platid_mask_t *platid;
2409f093235Snonaka 	int intr_pin;
2419f093235Snonaka } wzero3keypad_table[] = {
2429f093235Snonaka #if 0
2439f093235Snonaka 	/* WS007SH */
2449f093235Snonaka 	{
2459f093235Snonaka 		&platid_mask_MACH_SHARP_WZERO3_WS007SH,
2469f093235Snonaka 		-1,	/* XXX */
2479f093235Snonaka 	},
2489f093235Snonaka #endif
2499f093235Snonaka 	/* WS011SH */
2509f093235Snonaka 	{
2519f093235Snonaka 		&platid_mask_MACH_SHARP_WZERO3_WS011SH,
2529f093235Snonaka 		GPIO_WS011SH_KEYPAD,
2539f093235Snonaka 	},
2549f093235Snonaka 
2559f093235Snonaka 	{ NULL, -1, }
2569f093235Snonaka };
2579f093235Snonaka 
2589f093235Snonaka static const struct wzero3keypad_model *
wzero3keypad_lookup(void)2599f093235Snonaka wzero3keypad_lookup(void)
2609f093235Snonaka {
2619f093235Snonaka 	const struct wzero3keypad_model *model;
2629f093235Snonaka 
2639f093235Snonaka 	for (model = wzero3keypad_table; model->platid != NULL; model++) {
2649f093235Snonaka 		if (platid_match(&platid, model->platid)) {
2659f093235Snonaka 			return model;
2669f093235Snonaka 		}
2679f093235Snonaka 	}
2689f093235Snonaka 	return NULL;
2699f093235Snonaka }
2709f093235Snonaka 
2719f093235Snonaka static int
wzero3keypad_match(device_t parent,cfdata_t cf,void * aux)272cbab9cadSchs wzero3keypad_match(device_t parent, cfdata_t cf, void *aux)
2739f093235Snonaka {
2749f093235Snonaka 
2759f093235Snonaka 	if (strcmp(cf->cf_name, "wzero3keypad") != 0)
2769f093235Snonaka 		return 0;
2779f093235Snonaka 	if (wzero3keypad_lookup() == NULL)
2789f093235Snonaka 		return 0;
2799f093235Snonaka 	return 1;
2809f093235Snonaka }
2819f093235Snonaka 
2829f093235Snonaka static void
wzero3keypad_attach(device_t parent,device_t self,void * aux)283cbab9cadSchs wzero3keypad_attach(device_t parent, device_t self, void *aux)
2849f093235Snonaka {
2859f093235Snonaka 	struct wzero3keypad_softc *sc = device_private(self);
2869f093235Snonaka 	const struct wzero3keypad_model *model;
2879f093235Snonaka 	struct wskbddev_attach_args wska;
2889f093235Snonaka #if NWZERO3LCD > 0
2899f093235Snonaka 	extern int screen_rotate;
2909f093235Snonaka #endif
2919f093235Snonaka 
2929f093235Snonaka 	sc->sc_dev = self;
2939f093235Snonaka 	sc->sc_okeystat = 0;
2949f093235Snonaka #ifdef WSDISPLAY_COMPAT_RAWKBD
2959f093235Snonaka 	sc->sc_rawkbd = 0;
2969f093235Snonaka #endif
2979f093235Snonaka 
2989f093235Snonaka 	model = wzero3keypad_lookup();
2999f093235Snonaka 	if (model == NULL) {
3009f093235Snonaka 		aprint_error(": unknown model\n");
3019f093235Snonaka 		return;
3029f093235Snonaka 	}
3039f093235Snonaka 
3049f093235Snonaka 	aprint_normal(": keypad\n");
3059f093235Snonaka 	aprint_naive("\n");
3069f093235Snonaka 
3079f093235Snonaka 	sc->sc_intr_pin = model->intr_pin;
3089f093235Snonaka 
3099f093235Snonaka 	callout_init(&sc->sc_poll_ch, 0);
3109f093235Snonaka 	callout_setfunc(&sc->sc_poll_ch, wzero3keypad_poll, sc);
3119f093235Snonaka 	sc->sc_poll_interval = hz / 32;
3129f093235Snonaka 
3139f093235Snonaka #if NWZERO3LCD > 0
3149f093235Snonaka 	switch (screen_rotate) {
3159f093235Snonaka 	default:
3169f093235Snonaka 	case 0:
3179f093235Snonaka 		break;
3189f093235Snonaka 
3199f093235Snonaka 	case 270:	/* counter clock-wise */
3209f093235Snonaka 		ws011sh_keyscan2keydown[5] = KD_UP;
3219f093235Snonaka 		ws011sh_keyscan2keydown[9] = KD_RIGHT;
3229f093235Snonaka 		ws011sh_keyscan2keydown[10] = KD_LEFT;
3239f093235Snonaka 		ws011sh_keyscan2keydown[15] = KD_DOWN;
3249f093235Snonaka 		break;
3259f093235Snonaka 	}
3269f093235Snonaka #endif
3279f093235Snonaka 
3289f093235Snonaka 	/* attach wskbd */
3299f093235Snonaka 	wska.console = 0;
3309f093235Snonaka 	wska.keymap = &wzero3keypad_wskbd_keymapdata;
3319f093235Snonaka 	wska.accessops = &wzero3keypad_wskbd_accessops;
3329f093235Snonaka 	wska.accesscookie = sc;
333*c7fb772bSthorpej 	sc->sc_wskbddev = config_found(self, &wska, wskbddevprint, CFARGS_NONE);
3349f093235Snonaka 
3359f093235Snonaka 	/* setup keypad interrupt */
3369f093235Snonaka 	pxa2x0_gpio_set_function(sc->sc_intr_pin, GPIO_IN);
3379f093235Snonaka 	sc->sc_ih = pxa2x0_gpio_intr_establish(sc->sc_intr_pin,
3389f093235Snonaka 	    IST_EDGE_RISING, IPL_TTY, wzero3keypad_intr, sc);
3399f093235Snonaka 	if (sc->sc_ih == NULL) {
3409f093235Snonaka 		aprint_error_dev(sc->sc_dev,
3419f093235Snonaka 		    "couldn't establish keypad interrupt\n");
3429f093235Snonaka 	}
3439f093235Snonaka 
3449f093235Snonaka 	/* init hardware */
3459f093235Snonaka 	wzero3keypad_init(sc);
3469f093235Snonaka }
3479f093235Snonaka 
3489f093235Snonaka static int
wzero3keypad_wskbd_enable(void * arg,int onoff)3499f093235Snonaka wzero3keypad_wskbd_enable(void *arg, int onoff)
3509f093235Snonaka {
3519f093235Snonaka 
3529f093235Snonaka 	return 0;
3539f093235Snonaka }
3549f093235Snonaka 
3559f093235Snonaka static void
wzero3keypad_wskbd_set_leds(void * arg,int leds)3569f093235Snonaka wzero3keypad_wskbd_set_leds(void *arg, int leds)
3579f093235Snonaka {
3589f093235Snonaka 
3599f093235Snonaka 	/* Nothing to do */
3609f093235Snonaka }
3619f093235Snonaka 
3629f093235Snonaka static int
wzero3keypad_wskbd_ioctl(void * arg,u_long cmd,void * data,int flags,struct lwp * l)3639f093235Snonaka wzero3keypad_wskbd_ioctl(void *arg, u_long cmd, void *data, int flags,
3649f093235Snonaka     struct lwp *l)
3659f093235Snonaka {
3669f093235Snonaka #ifdef WSDISPLAY_COMPAT_RAWKBD
3679f093235Snonaka 	struct wzero3keypad_softc *sc = (struct wzero3keypad_softc *)arg;
3689f093235Snonaka #endif
3699f093235Snonaka 
3709f093235Snonaka 	switch (cmd) {
3719f093235Snonaka 	case WSKBDIO_GTYPE:
3729f093235Snonaka 		*(int *)data = WSKBD_TYPE_HPC_KBD;
3739f093235Snonaka 		return 0;
3749f093235Snonaka 	case WSKBDIO_SETLEDS:
3759f093235Snonaka 		return 0;
3769f093235Snonaka 	case WSKBDIO_GETLEDS:
3779f093235Snonaka 		*(int *)data = 0;
3789f093235Snonaka 		return 0;
3799f093235Snonaka #ifdef WSDISPLAY_COMPAT_RAWKBD
3809f093235Snonaka 	case WSKBDIO_SETMODE:
3819f093235Snonaka 		sc->sc_rawkbd = (*(int *)data == WSKBD_RAW);
3829f093235Snonaka 		return 0;
3839f093235Snonaka #endif
3849f093235Snonaka 	}
3859f093235Snonaka 
3869f093235Snonaka 	return EPASSTHROUGH;
3879f093235Snonaka }
3889f093235Snonaka 
3899f093235Snonaka static int
wzero3keypad_intr(void * arg)3909f093235Snonaka wzero3keypad_intr(void *arg)
3919f093235Snonaka {
3929f093235Snonaka 	struct wzero3keypad_softc *sc = (struct wzero3keypad_softc *)arg;
3939f093235Snonaka 
3949f093235Snonaka 	pxa2x0_gpio_clear_intr(sc->sc_intr_pin);
3959f093235Snonaka 
3969f093235Snonaka 	wzero3keypad_poll1(sc, 0);
3979f093235Snonaka 
3989f093235Snonaka 	callout_schedule(&sc->sc_poll_ch, sc->sc_poll_interval);
3999f093235Snonaka 
4009f093235Snonaka 	return 1;
4019f093235Snonaka }
4029f093235Snonaka 
4039f093235Snonaka static void
wzero3keypad_poll(void * v)4049f093235Snonaka wzero3keypad_poll(void *v)
4059f093235Snonaka {
4069f093235Snonaka 	struct wzero3keypad_softc *sc = (struct wzero3keypad_softc *)v;
4079f093235Snonaka 
4089f093235Snonaka 	wzero3keypad_poll1(sc, 1);
4099f093235Snonaka 
4109f093235Snonaka 	callout_stop(&sc->sc_poll_ch);
4119f093235Snonaka }
4129f093235Snonaka 
4139f093235Snonaka static void
wzero3keypad_poll1(struct wzero3keypad_softc * sc,int doscan)4149f093235Snonaka wzero3keypad_poll1(struct wzero3keypad_softc *sc, int doscan)
4159f093235Snonaka {
4169f093235Snonaka 	uint32_t keydown;
4179f093235Snonaka 	uint32_t diff;
4189f093235Snonaka 	int i;
4199f093235Snonaka 	int s;
4209f093235Snonaka 
4219f093235Snonaka 	s = spltty();
4229f093235Snonaka 
4239f093235Snonaka 	keydown = wzero3keypad_getkeydown(sc, doscan);
4249f093235Snonaka 	diff = keydown ^ sc->sc_okeystat;
4259f093235Snonaka 	if (diff == 0)
4269f093235Snonaka 		goto out;
4279f093235Snonaka 
4289f093235Snonaka 	for (i = 0; i < KD_NUM; i++) {
4299f093235Snonaka 		if (diff & (1 << i)) {
4309f093235Snonaka 			int state = keydown & (1 << i);
4319f093235Snonaka 			int type = state ? WSCONS_EVENT_KEY_DOWN :
4329f093235Snonaka 			    WSCONS_EVENT_KEY_UP;
4339f093235Snonaka 			int key = wzero3keypad_wskbd_keys[i];
4349f093235Snonaka #ifdef WSDISPLAY_COMPAT_RAWKBD
4359f093235Snonaka 			if (sc->sc_rawkbd) {
4369f093235Snonaka 				int n;
4379f093235Snonaka 				u_char data[16];
4389f093235Snonaka 
4399f093235Snonaka 				n = pckbd_encode(type, key, data);
4409f093235Snonaka 				wskbd_rawinput(sc->sc_wskbddev, data, n);
4419f093235Snonaka 			} else
4429f093235Snonaka #endif
4439f093235Snonaka 				wskbd_input(sc->sc_wskbddev, type, key);
4449f093235Snonaka 		}
4459f093235Snonaka 	}
4469f093235Snonaka 	sc->sc_okeystat = keydown;
4479f093235Snonaka 
4489f093235Snonaka out:
4499f093235Snonaka 	splx(s);
4509f093235Snonaka }
4519f093235Snonaka 
4529f093235Snonaka /*----------------------------------------------------------------------------
4539f093235Snonaka  * AK4184 keypad controller for WS011SH
4549f093235Snonaka  */
4559f093235Snonaka /* ak4184 command register */
4569f093235Snonaka #define	AKMCTRL_WR_SH	7
4579f093235Snonaka #define	AKMCTRL_PAGE_SH	6
4589f093235Snonaka #define	AKMCTRL_ADDR_SH	0
4599f093235Snonaka #define	AKMCTRL_WRITE	(0<<AKMCTRL_WR_SH)
4609f093235Snonaka #define	AKMCTRL_READ	(1<<AKMCTRL_WR_SH)
4619f093235Snonaka #define	AKMCTRL_DATA	(0<<AKMCTRL_PAGE_SH)
4629f093235Snonaka #define	AKMCTRL_CTRL	(1<<AKMCTRL_PAGE_SH)
4639f093235Snonaka 
4649f093235Snonaka static void
wzero3keypad_init(struct wzero3keypad_softc * sc)4659f093235Snonaka wzero3keypad_init(struct wzero3keypad_softc *sc)
4669f093235Snonaka {
4679f093235Snonaka 	int s;
4689f093235Snonaka 
4699f093235Snonaka 	s = spltty();
4709f093235Snonaka 
4719f093235Snonaka #if 0
4729f093235Snonaka 	/*
4739f093235Snonaka 	 * - key interrupt enable
4749f093235Snonaka 	 * - key touch scan
4759f093235Snonaka 	 * - debounce time: 1ms
4769f093235Snonaka 	 * - wait 100us for debounce time
4779f093235Snonaka 	 */
4789f093235Snonaka 	(void) wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_KEYPAD,
4799f093235Snonaka 	    AKMCTRL_WRITE | AKMCTRL_CTRL | (0<<AKMCTRL_ADDR_SH), 0);
4809f093235Snonaka #endif
4819f093235Snonaka 
4829f093235Snonaka 	/* unmask all keys & columns */
4839f093235Snonaka 	(void) wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_KEYPAD,
4849f093235Snonaka 	    AKMCTRL_WRITE | AKMCTRL_CTRL | (1<<AKMCTRL_ADDR_SH), 0);
4859f093235Snonaka 	(void) wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_KEYPAD,
4869f093235Snonaka 	    AKMCTRL_WRITE | AKMCTRL_CTRL | (2<<AKMCTRL_ADDR_SH), 0);
4879f093235Snonaka 	(void) wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_KEYPAD,
4889f093235Snonaka 	    AKMCTRL_WRITE | AKMCTRL_CTRL | (3<<AKMCTRL_ADDR_SH), 0);
4899f093235Snonaka 
4909f093235Snonaka 	/* Enable keypad interrupt (kpdata dummy read) */
4919f093235Snonaka 	(void) wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_KEYPAD,
4929f093235Snonaka 	    AKMCTRL_READ | AKMCTRL_DATA | (1<<AKMCTRL_ADDR_SH), 0);
4939f093235Snonaka 
4949f093235Snonaka 	splx(s);
4959f093235Snonaka }
4969f093235Snonaka 
4979f093235Snonaka static uint32_t
wzero3keypad_getkeydown(struct wzero3keypad_softc * sc,int doscan)4989f093235Snonaka wzero3keypad_getkeydown(struct wzero3keypad_softc *sc, int doscan)
4999f093235Snonaka {
5009f093235Snonaka 	uint32_t keydown = 0;
5019f093235Snonaka 	uint16_t status;
5029f093235Snonaka 	uint16_t kpdata;
5039f093235Snonaka 	int timo;
5049f093235Snonaka 
5059f093235Snonaka 	if (doscan) {
5069f093235Snonaka 		/* host scan */
5079f093235Snonaka 		(void) wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_KEYPAD,
5089f093235Snonaka 		    AKMCTRL_WRITE | AKMCTRL_CTRL | (4<<AKMCTRL_ADDR_SH), 0);
5099f093235Snonaka 		delay(100);
5109f093235Snonaka 	}
5119f093235Snonaka 
5129f093235Snonaka 	timo = 1000;
5139f093235Snonaka 	do {
5149f093235Snonaka 		status = wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_KEYPAD,
5159f093235Snonaka 		    AKMCTRL_READ | AKMCTRL_CTRL | (0<<AKMCTRL_ADDR_SH), 0);
5169f093235Snonaka 	} while ((status & 0xc000) == 0 && timo-- > 0);
5179f093235Snonaka 
5189f093235Snonaka 	kpdata = wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_KEYPAD,
5199f093235Snonaka 	    AKMCTRL_READ | AKMCTRL_DATA | (1<<AKMCTRL_ADDR_SH), 0);
5209f093235Snonaka 	if ((status & 0xc000) == 0xc000) {
5219f093235Snonaka 		if (!(kpdata & 0x8000)) {
5229f093235Snonaka 			int i;
5239f093235Snonaka 
5249f093235Snonaka 			for (i = 0; i < 3; i++) {
5259f093235Snonaka 				int key, bits;
5269f093235Snonaka 
5279f093235Snonaka 				key = kpdata & 0x1f;
5289f093235Snonaka 				if (key == 0)
5299f093235Snonaka 					break;
5309f093235Snonaka 				bits = ws011sh_keyscan2keydown[key];
5319f093235Snonaka 				if (bits != KD_INVALID)
5329f093235Snonaka 					keydown |= 1 << bits;
5339f093235Snonaka 				kpdata >>= 5;
5349f093235Snonaka 			}
5359f093235Snonaka 		}
5369f093235Snonaka 	}
5379f093235Snonaka 
5389f093235Snonaka 	return keydown;
5399f093235Snonaka }
540