xref: /netbsd/sys/arch/hpcarm/dev/wzero3_kbd.c (revision beecddb6)
1*beecddb6Sthorpej /*	$NetBSD: wzero3_kbd.c,v 1.12 2021/08/07 16:18:53 thorpej Exp $	*/
2b62fc9e2Snonaka 
30a5ccc74Snonaka /*-
40a5ccc74Snonaka  * Copyright (C) 2008, 2009, 2010 NONAKA Kimihiro <nonaka@netbsd.org>
5b62fc9e2Snonaka  * All rights reserved.
6b62fc9e2Snonaka  *
7b62fc9e2Snonaka  * Redistribution and use in source and binary forms, with or without
8b62fc9e2Snonaka  * modification, are permitted provided that the following conditions
9b62fc9e2Snonaka  * are met:
10b62fc9e2Snonaka  * 1. Redistributions of source code must retain the above copyright
11b62fc9e2Snonaka  *    notice, this list of conditions and the following disclaimer.
12b62fc9e2Snonaka  * 2. Redistributions in binary form must reproduce the above copyright
13b62fc9e2Snonaka  *    notice, this list of conditions and the following disclaimer in the
14b62fc9e2Snonaka  *    documentation and/or other materials provided with the distribution.
15b62fc9e2Snonaka  *
160a5ccc74Snonaka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
170a5ccc74Snonaka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
180a5ccc74Snonaka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
190a5ccc74Snonaka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
200a5ccc74Snonaka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
210a5ccc74Snonaka  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
220a5ccc74Snonaka  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
230a5ccc74Snonaka  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
240a5ccc74Snonaka  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
250a5ccc74Snonaka  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26b62fc9e2Snonaka  */
27b62fc9e2Snonaka 
28b62fc9e2Snonaka #include <sys/cdefs.h>
29*beecddb6Sthorpej __KERNEL_RCSID(0, "$NetBSD: wzero3_kbd.c,v 1.12 2021/08/07 16:18:53 thorpej Exp $");
30b62fc9e2Snonaka 
31b62fc9e2Snonaka #include <sys/param.h>
32b62fc9e2Snonaka #include <sys/systm.h>
33b62fc9e2Snonaka #include <sys/device.h>
34b62fc9e2Snonaka #include <sys/kernel.h>
3543acb194Sthorpej #include <sys/kmem.h>
36b62fc9e2Snonaka #include <sys/callout.h>
37d8e81853Sdyoung #include <sys/bus.h>
38b62fc9e2Snonaka 
39b62fc9e2Snonaka #include <dev/sysmon/sysmonvar.h>
40b62fc9e2Snonaka #include <dev/sysmon/sysmon_taskq.h>
41b62fc9e2Snonaka 
42b62fc9e2Snonaka #include <arm/xscale/pxa2x0cpu.h>
43b62fc9e2Snonaka #include <arm/xscale/pxa2x0var.h>
44b62fc9e2Snonaka #include <arm/xscale/pxa2x0_gpio.h>
45b62fc9e2Snonaka 
46b62fc9e2Snonaka #include <machine/bootinfo.h>
47b62fc9e2Snonaka #include <machine/config_hook.h>
48b62fc9e2Snonaka #include <machine/platid.h>
49b62fc9e2Snonaka #include <machine/platid_mask.h>
50b62fc9e2Snonaka 
51b62fc9e2Snonaka #include <dev/hpc/hpckbdvar.h>
52b62fc9e2Snonaka 
53b62fc9e2Snonaka #include <arch/hpcarm/dev/wzero3_reg.h>
54b62fc9e2Snonaka 
55b62fc9e2Snonaka #ifdef DEBUG
56b62fc9e2Snonaka #define DPRINTF(arg)	printf arg
57b62fc9e2Snonaka #else
58b62fc9e2Snonaka #define DPRINTF(arg)	/* nothing */
59b62fc9e2Snonaka #endif
60b62fc9e2Snonaka 
61b62fc9e2Snonaka #define	CSR_READ1(r)	bus_space_read_1(sc->sc_iot, sc->sc_ioh, (r))
62b62fc9e2Snonaka #define	CSR_WRITE1(r,v)	bus_space_write_1(sc->sc_iot, sc->sc_ioh, (r), (v))
63b62fc9e2Snonaka #define	CSR_READ2(r)	bus_space_read_2(sc->sc_iot, sc->sc_ioh, (r))
64b62fc9e2Snonaka #define	CSR_WRITE2(r,v)	bus_space_write_2(sc->sc_iot, sc->sc_ioh, (r), (v))
65b62fc9e2Snonaka #define	CSR_READ4(r)	bus_space_read_4(sc->sc_iot, sc->sc_ioh, (r))
66b62fc9e2Snonaka #define	CSR_WRITE4(r,v)	bus_space_write_4(sc->sc_iot, sc->sc_ioh, (r), (v))
67b62fc9e2Snonaka 
68b62fc9e2Snonaka /* register */
69b62fc9e2Snonaka #define	KBDCOL_L	(0x00)	/* Write */
70b62fc9e2Snonaka #define	KBDCOL_U	(0x04)	/* Write */
71b62fc9e2Snonaka #define	KBDCHARGE	(0x08)	/* Write */
72b62fc9e2Snonaka #define	KBDDATA		(0x08)	/* Read */
73b62fc9e2Snonaka #define	REGMAPSIZE	0x0c
74b62fc9e2Snonaka 
75b62fc9e2Snonaka #define	KEYWAIT		20	/* us */
76b62fc9e2Snonaka 
77b62fc9e2Snonaka #define	WS003SH_NCOLUMN	12
78b62fc9e2Snonaka #define	WS003SH_NROW	7
79b62fc9e2Snonaka 
80b62fc9e2Snonaka struct wzero3kbd_softc {
81b62fc9e2Snonaka 	device_t sc_dev;
82b62fc9e2Snonaka 
83b62fc9e2Snonaka 	bus_space_tag_t sc_iot;
84b62fc9e2Snonaka 	bus_space_handle_t sc_ioh;
85b62fc9e2Snonaka 
86b62fc9e2Snonaka 	int sc_ncolumn;
87b62fc9e2Snonaka 	int sc_nrow;
88b62fc9e2Snonaka 	uint8_t *sc_okeystat;
89b62fc9e2Snonaka 	uint8_t *sc_keystat;
90b62fc9e2Snonaka 
91b62fc9e2Snonaka 	void *sc_key_ih;
92b62fc9e2Snonaka 	void *sc_power_ih;
93b62fc9e2Snonaka 	void *sc_reset_ih;
94b62fc9e2Snonaka 
95b62fc9e2Snonaka 	int sc_key_pin;
96b62fc9e2Snonaka 	int sc_power_pin;
97b62fc9e2Snonaka 	int sc_reset_pin;
98b62fc9e2Snonaka 
99b62fc9e2Snonaka 	struct hpckbd_ic_if sc_if;
100b62fc9e2Snonaka 	struct hpckbd_if *sc_hpckbd;
101b62fc9e2Snonaka 
102b62fc9e2Snonaka 	struct sysmon_pswitch sc_smpsw; /* for reset key */
103b62fc9e2Snonaka 
104b62fc9e2Snonaka 	int sc_enabled;
105b62fc9e2Snonaka 
106b62fc9e2Snonaka 	/* polling stuff */
107b62fc9e2Snonaka 	struct callout sc_keyscan_ch;
108b62fc9e2Snonaka 	int sc_interval;
109b62fc9e2Snonaka #define	KEY_INTERVAL	50	/* ms */
110b62fc9e2Snonaka 
111b62fc9e2Snonaka #if defined(KEYTEST) || defined(KEYTEST2) || defined(KEYTEST3) || defined(KEYTEST4) || defined(KEYTEST5)
112b62fc9e2Snonaka 	void *sc_test_ih;
113b62fc9e2Snonaka 	int sc_test_pin;
114b62fc9e2Snonaka 	int sc_nouse_pin;
115b62fc9e2Snonaka 	int sc_nouse_pin2;
116b62fc9e2Snonaka 	int sc_nouse_pin3;
117b62fc9e2Snonaka 	int sc_bit;
118b62fc9e2Snonaka #endif
119b62fc9e2Snonaka };
120b62fc9e2Snonaka 
121b62fc9e2Snonaka static int wzero3kbd_match(device_t, cfdata_t, void *);
122b62fc9e2Snonaka static void wzero3kbd_attach(device_t, device_t, void *);
123b62fc9e2Snonaka 
124b62fc9e2Snonaka CFATTACH_DECL_NEW(wzero3kbd, sizeof(struct wzero3kbd_softc),
125b62fc9e2Snonaka     wzero3kbd_match, wzero3kbd_attach, NULL, NULL);
126b62fc9e2Snonaka 
127b62fc9e2Snonaka static int wzero3kbd_intr(void *arg);
128b62fc9e2Snonaka #if defined(KEYTEST)
129b62fc9e2Snonaka static int wzero3kbd_intr2(void *arg);
130b62fc9e2Snonaka #endif
131b62fc9e2Snonaka #if defined(KEYTEST3)
132b62fc9e2Snonaka static int wzero3kbd_intr3(void *arg);
133b62fc9e2Snonaka #endif
134b62fc9e2Snonaka static void wzero3kbd_tick(void *arg);
135b62fc9e2Snonaka static int wzero3kbd_power_intr(void *arg);
136b62fc9e2Snonaka static int wzero3kbd_reset_intr(void *arg);
137b62fc9e2Snonaka static int wzero3kbd_input_establish(void *arg, struct hpckbd_if *kbdif);
138b62fc9e2Snonaka static void wzero3kbd_sysmon_reset_event(void *arg);
139b62fc9e2Snonaka static int wzero3kbd_poll(void *arg);
140b62fc9e2Snonaka static int wzero3kbd_poll1(void *arg);
141b62fc9e2Snonaka 
142b62fc9e2Snonaka /*
143250a759eSnonaka  * WS003SH/WS004SH/WS007SH keyscan map
144b62fc9e2Snonaka 	col#0	col#1	col#2	col#3	col#4	col#5	col#6	col#7	col#8	col#9	col#10	col#11
145b62fc9e2Snonaka row#0:	CTRL	1	3	5	6	7	9	0	BS	(none)	ROTATE	CAMERA
146b62fc9e2Snonaka row#1:	(none)	2	4	r	y	8	i	o	p	(none)	VOL-	VOL+
147b62fc9e2Snonaka row#2:	TAB	q	e	t	g	u	j	k	(none)	(none)	(none)	(none)
148b62fc9e2Snonaka row#3:	(none)	w	s	f	v	h	m	l	(none)	(none)	SHIFT	(none)
149b62fc9e2Snonaka row#4:	CALL	a	d	c	b	n	.	(none)	ENTER	(none)	WIN	(none)
150b62fc9e2Snonaka row#5:	MAIL	z	x	-	SPACE	/	(none)	UP	(none)	(none)	LSOFT	FN
151b62fc9e2Snonaka row#6:	IE	MOJI	(none)	OK	ACTION	,	LEFT	DOWN	RIGHT	(none)	RSOFT	(none)
152b62fc9e2Snonaka */
153b62fc9e2Snonaka 
154b62fc9e2Snonaka /*
155b62fc9e2Snonaka  * WS011SH keyscan map
156b62fc9e2Snonaka 	col#0	col#1	col#2	col#3	col#4	col#5	col#6	col#7	col#8	col#9	col#10	col#11
157b62fc9e2Snonaka row#0	Ctrl	(none)	(none)	(none)	(none)	(none)	(none)	(none)	Del	(none)	ROTATE	(none)
158250a759eSnonaka row#1	(none)	(none)	(none)	R	Y	(none)	I	O	P	(none)	(none)	(none)
159b62fc9e2Snonaka row#2	Tab	Q	E	T	G	U	J	K	(none)	(none)	(none)	(none)
160b62fc9e2Snonaka row#3	(none)	W	S	F	V	H	M	L	(none)	(none)	Shift	(none)
161b62fc9e2Snonaka row#4	(none)	A	D	C	B	N	.	(none)	Enter	(none)	(none)	(none)
162250a759eSnonaka row#5	(none)	Z	X	-	Space	/	(none)	UP	(none)	(none)	(none)	Fn
163250a759eSnonaka row#6	(none)	MOJI	HAN/ZEN	OK	(none)	,	LEFT	DOWN	RIGHT	(none)	(none)	(none)
164250a759eSnonaka */
165250a759eSnonaka 
166250a759eSnonaka /*
167250a759eSnonaka  * WS020SH keyscan map
168250a759eSnonaka 	col#0	col#1	col#2	col#3	col#4	col#5	col#6	col#7	col#8	col#9	col#10	col#11
169250a759eSnonaka row#0	Ctrl	(none)	(none)	(none)	(none)	(none)	(none)	(none)	Del	(none)	ROTATE	(none)
170250a759eSnonaka row#1	(none)	(none)	(none)	R	Y	(none)	I	O	P	(none)	MEDIA	(none)
171250a759eSnonaka row#2	Tab	Q	E	T	G	U	J	K	(none)	(none)	(none)	(none)
172250a759eSnonaka row#3	(none)	W	S	F	V	H	M	L	(none)	(none)	LShift	(none)
173250a759eSnonaka row#4	(none)	A	D	C	B	N	.	(none)	Enter	(none)	RShift	(none)
174250a759eSnonaka row#5	(none)	Z	X	-	Space	/	(none)	UP	(none)	DOWN	(none)	Fn
175250a759eSnonaka row#6	(none)	MOJI	HAN/ZEN	OK	(none)	,	LEFT	(none)	RIGHT	(none)	(none)	(none)
176b62fc9e2Snonaka */
177b62fc9e2Snonaka 
178b62fc9e2Snonaka static const struct wzero3kbd_model {
179b62fc9e2Snonaka 	platid_mask_t *platid;
180b62fc9e2Snonaka 	int key_pin;
181b62fc9e2Snonaka 	int power_pin;
182b62fc9e2Snonaka 	int reset_pin;
183b62fc9e2Snonaka 	int ncolumn;
184b62fc9e2Snonaka 	int nrow;
185b62fc9e2Snonaka } wzero3kbd_table[] = {
186b62fc9e2Snonaka 	/* WS003SH */
187b62fc9e2Snonaka 	{
188b62fc9e2Snonaka 		&platid_mask_MACH_SHARP_WZERO3_WS003SH,
189b62fc9e2Snonaka 		-1,	/* XXX */
190b62fc9e2Snonaka 		GPIO_WS003SH_POWER_BUTTON,
191b62fc9e2Snonaka 		-1,	/* None */
192b62fc9e2Snonaka 		WS003SH_NCOLUMN,
193b62fc9e2Snonaka 		WS003SH_NROW,
194b62fc9e2Snonaka 	},
195b62fc9e2Snonaka 	/* WS004SH */
196b62fc9e2Snonaka 	{
197b62fc9e2Snonaka 		&platid_mask_MACH_SHARP_WZERO3_WS004SH,
198b62fc9e2Snonaka 		-1,	/* XXX */
199b62fc9e2Snonaka 		GPIO_WS003SH_POWER_BUTTON,
200b62fc9e2Snonaka 		-1,	/* None */
201b62fc9e2Snonaka 		WS003SH_NCOLUMN,
202b62fc9e2Snonaka 		WS003SH_NROW,
203b62fc9e2Snonaka 	},
204b62fc9e2Snonaka 	/* WS007SH */
205b62fc9e2Snonaka 	{
206b62fc9e2Snonaka 		&platid_mask_MACH_SHARP_WZERO3_WS007SH,
207b62fc9e2Snonaka 		-1,	/* XXX */
208b62fc9e2Snonaka 		GPIO_WS007SH_POWER_BUTTON,
209b62fc9e2Snonaka 		GPIO_WS007SH_RESET_BUTTON,
210b62fc9e2Snonaka 		WS003SH_NCOLUMN,
211b62fc9e2Snonaka 		WS003SH_NROW,
212b62fc9e2Snonaka 	},
213b62fc9e2Snonaka 	/* WS011SH */
214b62fc9e2Snonaka 	{
215b62fc9e2Snonaka 		&platid_mask_MACH_SHARP_WZERO3_WS011SH,
216b62fc9e2Snonaka 		-1,	/* XXX */
217b62fc9e2Snonaka 		GPIO_WS011SH_POWER_BUTTON,
218b62fc9e2Snonaka 		GPIO_WS011SH_RESET_BUTTON,
219b62fc9e2Snonaka 		WS003SH_NCOLUMN,
220b62fc9e2Snonaka 		WS003SH_NROW,
221b62fc9e2Snonaka 	},
222b62fc9e2Snonaka 	/* WS020SH */
223b62fc9e2Snonaka 	{
224b62fc9e2Snonaka 		&platid_mask_MACH_SHARP_WZERO3_WS020SH,
225b62fc9e2Snonaka 		-1,	/* XXX */
226250a759eSnonaka 		GPIO_WS020SH_POWER_BUTTON,
227250a759eSnonaka 		GPIO_WS020SH_RESET_BUTTON,
228b62fc9e2Snonaka 		WS003SH_NCOLUMN,
229b62fc9e2Snonaka 		WS003SH_NROW,
230b62fc9e2Snonaka 	},
231b62fc9e2Snonaka 
232b62fc9e2Snonaka 	{ NULL, -1, -1, -1, 0, 0, }
233b62fc9e2Snonaka };
234b62fc9e2Snonaka 
235b62fc9e2Snonaka static const struct wzero3kbd_model *
wzero3kbd_lookup(void)236b62fc9e2Snonaka wzero3kbd_lookup(void)
237b62fc9e2Snonaka {
238b62fc9e2Snonaka 	const struct wzero3kbd_model *model;
239b62fc9e2Snonaka 
240b62fc9e2Snonaka 	for (model = wzero3kbd_table; model->platid != NULL; model++) {
241b62fc9e2Snonaka 		if (platid_match(&platid, model->platid)) {
242b62fc9e2Snonaka 			return model;
243b62fc9e2Snonaka 		}
244b62fc9e2Snonaka 	}
245b62fc9e2Snonaka 	return NULL;
246b62fc9e2Snonaka }
247b62fc9e2Snonaka 
248b62fc9e2Snonaka static int
wzero3kbd_match(device_t parent,cfdata_t cf,void * aux)2495f819ca3Schs wzero3kbd_match(device_t parent, cfdata_t cf, void *aux)
250b62fc9e2Snonaka {
251b62fc9e2Snonaka 
252b62fc9e2Snonaka 	if (strcmp(cf->cf_name, "wzero3kbd") != 0)
253b62fc9e2Snonaka 		return 0;
254b62fc9e2Snonaka 	if (wzero3kbd_lookup() == NULL)
255b62fc9e2Snonaka 		return 0;
256b62fc9e2Snonaka 	return 1;
257b62fc9e2Snonaka }
258b62fc9e2Snonaka 
259b62fc9e2Snonaka static void
wzero3kbd_attach(device_t parent,device_t self,void * aux)2605f819ca3Schs wzero3kbd_attach(device_t parent, device_t self, void *aux)
261b62fc9e2Snonaka {
262b62fc9e2Snonaka 	struct wzero3kbd_softc *sc = device_private(self);
263b62fc9e2Snonaka 	struct pxaip_attach_args *pxa = (struct pxaip_attach_args *)aux;
264b62fc9e2Snonaka 	struct hpckbd_attach_args haa;
265b62fc9e2Snonaka 	const struct wzero3kbd_model *model;
266b62fc9e2Snonaka 
267b62fc9e2Snonaka 	sc->sc_dev = self;
268b62fc9e2Snonaka 
269b62fc9e2Snonaka 	model = wzero3kbd_lookup();
270b62fc9e2Snonaka 	if (model == NULL) {
271b62fc9e2Snonaka 		aprint_error(": unknown model\n");
272b62fc9e2Snonaka 		return;
273b62fc9e2Snonaka 	}
274b62fc9e2Snonaka 
275b62fc9e2Snonaka 	aprint_normal(": keyboard\n");
276b62fc9e2Snonaka 	aprint_naive("\n");
277b62fc9e2Snonaka 
278b62fc9e2Snonaka 	sc->sc_key_pin = model->key_pin;
279b62fc9e2Snonaka 	sc->sc_power_pin = model->power_pin;
280b62fc9e2Snonaka 	sc->sc_reset_pin = model->reset_pin;
281b62fc9e2Snonaka 	sc->sc_ncolumn = model->ncolumn;
282b62fc9e2Snonaka 	sc->sc_nrow = model->nrow;
283b62fc9e2Snonaka 
284b62fc9e2Snonaka 	sc->sc_iot = pxa->pxa_iot;
285b62fc9e2Snonaka 	if (bus_space_map(sc->sc_iot, PXA2X0_CS2_START, REGMAPSIZE, 0,
286b62fc9e2Snonaka 	    &sc->sc_ioh)) {
287b62fc9e2Snonaka 		aprint_error_dev(self, "couldn't map registers.\n");
288b62fc9e2Snonaka 		return;
289b62fc9e2Snonaka 	}
290b62fc9e2Snonaka 
29143acb194Sthorpej 	sc->sc_okeystat = kmem_zalloc(sc->sc_nrow * sc->sc_ncolumn, KM_SLEEP);
29243acb194Sthorpej 	sc->sc_keystat = kmem_zalloc(sc->sc_nrow * sc->sc_ncolumn, KM_SLEEP);
293b62fc9e2Snonaka 
294b62fc9e2Snonaka 	sc->sc_if.hii_ctx = sc;
295b62fc9e2Snonaka 	sc->sc_if.hii_establish = wzero3kbd_input_establish;
296b62fc9e2Snonaka 	sc->sc_if.hii_poll = wzero3kbd_poll;
297b62fc9e2Snonaka 
298b62fc9e2Snonaka 	/* Attach console if not using serial. */
299b62fc9e2Snonaka 	if (!(bootinfo->bi_cnuse & BI_CNUSE_SERIAL))
300b62fc9e2Snonaka 		hpckbd_cnattach(&sc->sc_if);
301b62fc9e2Snonaka 
302b62fc9e2Snonaka 	/* Install interrupt handler. */
303b62fc9e2Snonaka 	if (sc->sc_key_pin >= 0) {
304b62fc9e2Snonaka 		pxa2x0_gpio_set_function(sc->sc_key_pin, GPIO_IN);
305b62fc9e2Snonaka 		sc->sc_key_ih = pxa2x0_gpio_intr_establish(sc->sc_key_pin,
306b62fc9e2Snonaka 		    IST_EDGE_BOTH, IPL_TTY, wzero3kbd_intr, sc);
307b62fc9e2Snonaka 		if (sc->sc_key_ih == NULL) {
308b62fc9e2Snonaka 			aprint_error_dev(sc->sc_dev,
309b62fc9e2Snonaka 			    "couldn't establish key interrupt\n");
310b62fc9e2Snonaka 		}
311b62fc9e2Snonaka 	} else {
312b62fc9e2Snonaka 		sc->sc_interval = KEY_INTERVAL / (1000 / hz);
313b62fc9e2Snonaka 		if (sc->sc_interval < 1)
314b62fc9e2Snonaka 			sc->sc_interval = 1;
315b62fc9e2Snonaka 		callout_init(&sc->sc_keyscan_ch, 0);
316b62fc9e2Snonaka 		callout_reset(&sc->sc_keyscan_ch, sc->sc_interval,
317b62fc9e2Snonaka 		    wzero3kbd_tick, sc);
318b62fc9e2Snonaka 	}
319b62fc9e2Snonaka 
320b62fc9e2Snonaka 	/* power key */
321b62fc9e2Snonaka 	if (sc->sc_power_pin >= 0) {
322b62fc9e2Snonaka 		pxa2x0_gpio_set_function(sc->sc_power_pin, GPIO_IN);
323b62fc9e2Snonaka 		sc->sc_power_ih = pxa2x0_gpio_intr_establish(
324b62fc9e2Snonaka 		    sc->sc_power_pin, IST_EDGE_BOTH, IPL_TTY,
325b62fc9e2Snonaka 		    wzero3kbd_power_intr, sc);
326b62fc9e2Snonaka 		if (sc->sc_power_ih == NULL) {
327b62fc9e2Snonaka 			aprint_error_dev(sc->sc_dev,
328b62fc9e2Snonaka 			    "couldn't establish power key interrupt\n");
329b62fc9e2Snonaka 		}
330b62fc9e2Snonaka 	}
331b62fc9e2Snonaka 
332b62fc9e2Snonaka 	/* reset button */
333b62fc9e2Snonaka 	if (sc->sc_reset_pin >= 0) {
334b62fc9e2Snonaka 		pxa2x0_gpio_set_function(sc->sc_reset_pin, GPIO_IN);
335b62fc9e2Snonaka 		sc->sc_reset_ih = pxa2x0_gpio_intr_establish(
336b62fc9e2Snonaka 		    sc->sc_reset_pin, IST_EDGE_BOTH, IPL_TTY,
337b62fc9e2Snonaka 		    wzero3kbd_reset_intr, sc);
338b62fc9e2Snonaka 		if (sc->sc_reset_ih == NULL) {
339b62fc9e2Snonaka 			aprint_error_dev(sc->sc_dev,
340b62fc9e2Snonaka 			    "couldn't establish reset key interrupt\n");
341b62fc9e2Snonaka 		}
342b62fc9e2Snonaka 
343b62fc9e2Snonaka 		sc->sc_smpsw.smpsw_name = device_xname(self);
344b62fc9e2Snonaka 		sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_RESET;
345b62fc9e2Snonaka 		if (sysmon_pswitch_register(&sc->sc_smpsw) != 0) {
346b62fc9e2Snonaka 			aprint_error_dev(sc->sc_dev,
347b62fc9e2Snonaka 			    "unable to register reset event handler\n");
348b62fc9e2Snonaka 		}
349b62fc9e2Snonaka 	}
350b62fc9e2Snonaka 
351b62fc9e2Snonaka 	/* Attach hpckbd. */
352b62fc9e2Snonaka 	haa.haa_ic = &sc->sc_if;
353*beecddb6Sthorpej 	config_found(self, &haa, hpckbd_print, CFARGS_NONE);
354b62fc9e2Snonaka 
355b62fc9e2Snonaka #if defined(KEYTEST) || defined(KEYTEST2) || defined(KEYTEST3) || defined(KEYTEST4) || defined(KEYTEST5)
356b62fc9e2Snonaka 	sc->sc_test_ih = NULL;
357b62fc9e2Snonaka 	sc->sc_test_pin = -1;
358b62fc9e2Snonaka 	sc->sc_nouse_pin = -1;
359b62fc9e2Snonaka 	sc->sc_nouse_pin2 = -1;
360b62fc9e2Snonaka 	sc->sc_nouse_pin3 = -1;
361b62fc9e2Snonaka 	sc->sc_bit = 0x01;
362b62fc9e2Snonaka 	if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS003SH)
363b62fc9e2Snonaka 	 || platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS004SH)) {
364b62fc9e2Snonaka 		sc->sc_nouse_pin = GPIO_WS003SH_SD_DETECT;  /* SD_DETECT */
365b62fc9e2Snonaka 		sc->sc_nouse_pin2 = 86;  /* Vsync? */
366b62fc9e2Snonaka 		sc->sc_nouse_pin3 = 89;  /* RESET? */
367b62fc9e2Snonaka 	}
368b62fc9e2Snonaka 	if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS007SH)) {
369b62fc9e2Snonaka 		sc->sc_nouse_pin = GPIO_WS007SH_SD_DETECT;  /* SD_DETECT */
370b62fc9e2Snonaka 		sc->sc_nouse_pin2 = 77;  /* Vsync? */
371b62fc9e2Snonaka 	}
372b62fc9e2Snonaka 	if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS011SH)) {
373b62fc9e2Snonaka 		sc->sc_nouse_pin = GPIO_WS011SH_SD_DETECT;  /* SD_DETECT */
374b62fc9e2Snonaka 		sc->sc_nouse_pin2 = 77;  /* Vsync? */
375b62fc9e2Snonaka 	}
376250a759eSnonaka 	if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS020SH)) {
377250a759eSnonaka 		sc->sc_nouse_pin = GPIO_WS020SH_SD_DETECT;  /* SD_DETECT */
378250a759eSnonaka 		sc->sc_nouse_pin2 = 77;  /* Vsync? */
379250a759eSnonaka 	}
380b62fc9e2Snonaka 
381b62fc9e2Snonaka #ifdef KEYTEST
382b62fc9e2Snonaka 	for (sc->sc_test_pin = 2; sc->sc_test_pin < PXA270_GPIO_NPINS; sc->sc_test_pin++) {
383b62fc9e2Snonaka 		if (sc->sc_test_pin != sc->sc_nouse_pin
384b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_nouse_pin2
385b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_nouse_pin3
386b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_key_pin
387b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_power_pin
388b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_reset_pin
389b62fc9e2Snonaka 		 && GPIO_IS_GPIO_IN(pxa2x0_gpio_get_function(sc->sc_test_pin)))
390b62fc9e2Snonaka 			break;
391b62fc9e2Snonaka 	}
392b62fc9e2Snonaka 	if (sc->sc_test_pin < PXA270_GPIO_NPINS) {
393b62fc9e2Snonaka 		printf("GPIO_IN: GPIO pin #%d\n", sc->sc_test_pin);
394b62fc9e2Snonaka 		sc->sc_test_ih = pxa2x0_gpio_intr_establish(sc->sc_test_pin,
395b62fc9e2Snonaka 		    IST_EDGE_BOTH, IPL_TTY, wzero3kbd_intr2, sc);
396b62fc9e2Snonaka 	} else {
397b62fc9e2Snonaka 		sc->sc_test_pin = -1;
398b62fc9e2Snonaka 	}
399b62fc9e2Snonaka #endif
400b62fc9e2Snonaka 
401b62fc9e2Snonaka #ifdef KEYTEST3
402b62fc9e2Snonaka 	{
403b62fc9e2Snonaka 		int i;
404b62fc9e2Snonaka 		printf("pin: ");
405b62fc9e2Snonaka 		for (i = 0; i < PXA270_GPIO_NPINS; i++) {
406b62fc9e2Snonaka 			if (i == sc->sc_nouse_pin
407b62fc9e2Snonaka 			 || i == sc->sc_nouse_pin2
408b62fc9e2Snonaka 			 || i == sc->sc_nouse_pin3
409b62fc9e2Snonaka 			 || i == sc->sc_key_pin
410b62fc9e2Snonaka 			 || i == sc->sc_power_pin
411b62fc9e2Snonaka 			 || i == sc->sc_reset_pin)
412b62fc9e2Snonaka 				continue;
413b62fc9e2Snonaka 
414b62fc9e2Snonaka 			printf("%d, ", i);
415b62fc9e2Snonaka 			if (GPIO_IS_GPIO_IN(pxa2x0_gpio_get_function(i))) {
416b62fc9e2Snonaka 				pxa2x0_gpio_intr_establish(i, IST_EDGE_BOTH,
417b62fc9e2Snonaka 				    IPL_TTY, wzero3kbd_intr3, (void *)(long)i);
418b62fc9e2Snonaka 			}
419b62fc9e2Snonaka 		}
420b62fc9e2Snonaka 	}
421b62fc9e2Snonaka #endif
422b62fc9e2Snonaka 
423b62fc9e2Snonaka #ifdef KEYTEST4
424b62fc9e2Snonaka 	for (sc->sc_test_pin = 2; sc->sc_test_pin < PXA270_GPIO_NPINS; sc->sc_test_pin++) {
425b62fc9e2Snonaka 		if (sc->sc_test_pin != sc->sc_nouse_pin
426b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_nouse_pin2
427b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_nouse_pin3
428b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_key_pin
429b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_power_pin
430b62fc9e2Snonaka 		 && sc->sc_test_pin != sc->sc_reset_pin
431b62fc9e2Snonaka 		 && GPIO_IS_GPIO_OUT(pxa2x0_gpio_get_function(sc->sc_test_pin)))
432b62fc9e2Snonaka 			break;
433b62fc9e2Snonaka 	}
434b62fc9e2Snonaka 	if (sc->sc_test_pin < PXA270_GPIO_NPINS) {
435b62fc9e2Snonaka 		printf("GPIO_OUT: GPIO pin #%d\n", sc->sc_test_pin);
436b62fc9e2Snonaka 	} else {
437b62fc9e2Snonaka 		sc->sc_test_pin = -1;
438b62fc9e2Snonaka 	}
439b62fc9e2Snonaka #endif
440b62fc9e2Snonaka #ifdef KEYTEST5
441b62fc9e2Snonaka 	sc->sc_test_pin = 0x00;
442b62fc9e2Snonaka 	sc->sc_bit = 0x01;
443b62fc9e2Snonaka #endif
444b62fc9e2Snonaka #endif
445b62fc9e2Snonaka }
446b62fc9e2Snonaka 
447b62fc9e2Snonaka static int
wzero3kbd_intr(void * arg)448b62fc9e2Snonaka wzero3kbd_intr(void *arg)
449b62fc9e2Snonaka {
450b62fc9e2Snonaka 	struct wzero3kbd_softc *sc = (struct wzero3kbd_softc *)arg;
451b62fc9e2Snonaka 
452b62fc9e2Snonaka #if defined(KEYTEST) || defined(KEYTEST2) || defined(KEYTEST3) || defined(KEYTEST4) || defined(KEYTEST5)
453b62fc9e2Snonaka 	printf("wzero3kbd_intr: GPIO pin #%d = %s\n", sc->sc_key_pin,
454b62fc9e2Snonaka 	    pxa2x0_gpio_get_bit(sc->sc_key_pin) ? "on" : "off");
455b62fc9e2Snonaka #endif
456b62fc9e2Snonaka 
457b62fc9e2Snonaka #if defined(KEYTEST4)
458b62fc9e2Snonaka 	if (sc->sc_test_pin >= 0) {
459b62fc9e2Snonaka 		if (pxa2x0_gpio_get_bit(sc->sc_test_pin)) {
460b62fc9e2Snonaka 			printf("GPIO_OUT: GPIO pin #%d: L\n",sc->sc_test_pin);
461b62fc9e2Snonaka 			pxa2x0_gpio_clear_bit(sc->sc_test_pin);
462b62fc9e2Snonaka 		} else {
463b62fc9e2Snonaka 			printf("GPIO_OUT: GPIO pin #%d: H\n", sc->sc_test_pin);
464b62fc9e2Snonaka 			pxa2x0_gpio_set_bit(sc->sc_test_pin);
465b62fc9e2Snonaka 		}
466b62fc9e2Snonaka 	}
467b62fc9e2Snonaka #endif
468b62fc9e2Snonaka #if defined(KEYTEST5)
469b62fc9e2Snonaka 	printf("CPLD(%#x): value=%#x, mask=%#x\n",
470b62fc9e2Snonaka 	    sc->sc_test_pin, CSR_READ4(sc->sc_test_pin), sc->sc_bit);
471b62fc9e2Snonaka 	if (CSR_READ4(sc->sc_test_pin) & sc->sc_bit) {
472b62fc9e2Snonaka 		printf("CPLD_OUT: CPLD: L\n");
473b62fc9e2Snonaka 		CSR_WRITE4(sc->sc_test_pin,
474b62fc9e2Snonaka 		    CSR_READ4(sc->sc_test_pin) & ~sc->sc_bit);
475b62fc9e2Snonaka 	} else {
476b62fc9e2Snonaka 		printf("CPLD_OUT: CPLD: H\n");
477b62fc9e2Snonaka 		CSR_WRITE4(sc->sc_test_pin,
478b62fc9e2Snonaka 		    CSR_READ4(sc->sc_test_pin) | sc->sc_bit);
479b62fc9e2Snonaka 	}
480b62fc9e2Snonaka #endif
481b62fc9e2Snonaka 
482b62fc9e2Snonaka 	(void) wzero3kbd_poll1(sc);
483b62fc9e2Snonaka 
484b62fc9e2Snonaka 	pxa2x0_gpio_clear_intr(sc->sc_key_pin);
485b62fc9e2Snonaka 
486b62fc9e2Snonaka 	return 1;
487b62fc9e2Snonaka }
488b62fc9e2Snonaka 
489b62fc9e2Snonaka #if defined(KEYTEST)
490b62fc9e2Snonaka static int
wzero3kbd_intr2(void * arg)491b62fc9e2Snonaka wzero3kbd_intr2(void *arg)
492b62fc9e2Snonaka {
493b62fc9e2Snonaka 	struct wzero3kbd_softc *sc = (struct wzero3kbd_softc *)arg;
494b62fc9e2Snonaka 
495b62fc9e2Snonaka 	printf("wzero3kbd_intr2: GPIO_IN: GPIO pin #%d = %s\n", sc->sc_test_pin,
496b62fc9e2Snonaka 	    pxa2x0_gpio_get_bit(sc->sc_test_pin) ? "on" : "off");
497b62fc9e2Snonaka 
498b62fc9e2Snonaka 	return 1;
499b62fc9e2Snonaka }
500b62fc9e2Snonaka #endif
501b62fc9e2Snonaka 
502b62fc9e2Snonaka #if defined(KEYTEST3)
503b62fc9e2Snonaka static int
wzero3kbd_intr3(void * arg)504b62fc9e2Snonaka wzero3kbd_intr3(void *arg)
505b62fc9e2Snonaka {
506b62fc9e2Snonaka 	int pin = (int)arg;
507b62fc9e2Snonaka 
508b62fc9e2Snonaka 	printf("wzero3kbd_intr3: GPIO pin #%d = %s\n", pin,
509b62fc9e2Snonaka 	    pxa2x0_gpio_get_bit(pin) ? "on" : "off");
510b62fc9e2Snonaka 
511b62fc9e2Snonaka 	return 1;
512b62fc9e2Snonaka }
513b62fc9e2Snonaka #endif
514b62fc9e2Snonaka 
515b62fc9e2Snonaka 
516b62fc9e2Snonaka static void
wzero3kbd_tick(void * arg)517b62fc9e2Snonaka wzero3kbd_tick(void *arg)
518b62fc9e2Snonaka {
519b62fc9e2Snonaka 	struct wzero3kbd_softc *sc = (struct wzero3kbd_softc *)arg;
520b62fc9e2Snonaka 
521b62fc9e2Snonaka 	(void) wzero3kbd_poll1(sc);
522b62fc9e2Snonaka 
52357e70595Snonaka 	callout_schedule(&sc->sc_keyscan_ch, sc->sc_interval);
524b62fc9e2Snonaka }
525b62fc9e2Snonaka 
526b62fc9e2Snonaka static int
wzero3kbd_power_intr(void * arg)527b62fc9e2Snonaka wzero3kbd_power_intr(void *arg)
528b62fc9e2Snonaka {
529b62fc9e2Snonaka 	struct wzero3kbd_softc *sc = (struct wzero3kbd_softc *)arg;
530b62fc9e2Snonaka 
531b62fc9e2Snonaka #if defined(KEYTEST) || defined(KEYTEST2) || defined(KEYTEST3) || defined(KEYTEST4)
532b62fc9e2Snonaka 	printf("wzero3kbd_power_intr: status = %s\n",
533b62fc9e2Snonaka 	    pxa2x0_gpio_get_bit(sc->sc_power_pin) ? "on" : "off");
534b62fc9e2Snonaka #endif
535b62fc9e2Snonaka 
536b62fc9e2Snonaka #if defined(KEYTEST)
537b62fc9e2Snonaka 	if (pxa2x0_gpio_get_bit(sc->sc_power_pin)) {
538b62fc9e2Snonaka 		if (sc->sc_test_pin >= 0) {
539b62fc9e2Snonaka 			int orig_pin = sc->sc_test_pin;
540b62fc9e2Snonaka 			pxa2x0_gpio_intr_disestablish(sc->sc_test_ih);
541b62fc9e2Snonaka 			sc->sc_test_ih = NULL;
542b62fc9e2Snonaka 
543b62fc9e2Snonaka 			for (;;) {
544b62fc9e2Snonaka 				if (++sc->sc_test_pin >= PXA270_GPIO_NPINS)
545b62fc9e2Snonaka 					sc->sc_test_pin = 2;
546b62fc9e2Snonaka 				if (sc->sc_test_pin == orig_pin)
547b62fc9e2Snonaka 					break;
548b62fc9e2Snonaka 				if (sc->sc_test_pin != sc->sc_nouse_pin
549b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_nouse_pin2
550b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_nouse_pin3
551b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_key_pin
552b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_power_pin
553b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_reset_pin
554b62fc9e2Snonaka 				 && GPIO_IS_GPIO_IN(pxa2x0_gpio_get_function(sc->sc_test_pin)))
555b62fc9e2Snonaka 					break;
556b62fc9e2Snonaka 			}
557b62fc9e2Snonaka 			if (sc->sc_test_pin != orig_pin) {
558b62fc9e2Snonaka 				printf("GPIO_IN: GPIO pin #%d\n",
559b62fc9e2Snonaka 				    sc->sc_test_pin);
560b62fc9e2Snonaka 				sc->sc_test_ih =
561b62fc9e2Snonaka 				    pxa2x0_gpio_intr_establish(sc->sc_test_pin,
562b62fc9e2Snonaka 				    IST_EDGE_BOTH, IPL_TTY, wzero3kbd_intr2,sc);
563b62fc9e2Snonaka 			} else {
564b62fc9e2Snonaka 				sc->sc_test_pin = -1;
565b62fc9e2Snonaka 			}
566b62fc9e2Snonaka 		}
567b62fc9e2Snonaka 	}
568b62fc9e2Snonaka #endif
569b62fc9e2Snonaka 
570b62fc9e2Snonaka #if defined(KEYTEST2)
571b62fc9e2Snonaka 	if (pxa2x0_gpio_get_bit(sc->sc_power_pin)) {
572b62fc9e2Snonaka 		sc->sc_enabled ^= 2;
573b62fc9e2Snonaka 		if (sc->sc_enabled & 2) {
574b62fc9e2Snonaka 			printf("print col/row\n");
575b62fc9e2Snonaka 		} else {
576b62fc9e2Snonaka 			printf("keyscan\n");
577b62fc9e2Snonaka 		}
578b62fc9e2Snonaka 	}
579b62fc9e2Snonaka #endif
580b62fc9e2Snonaka #if defined(KEYTEST4)
581b62fc9e2Snonaka 	if (pxa2x0_gpio_get_bit(sc->sc_power_pin)) {
582b62fc9e2Snonaka 		if (sc->sc_test_pin >= 0) {
583b62fc9e2Snonaka 			int orig_pin = sc->sc_test_pin;
584b62fc9e2Snonaka 			for (;;) {
585b62fc9e2Snonaka 				if (++sc->sc_test_pin >= PXA270_GPIO_NPINS)
586b62fc9e2Snonaka 					sc->sc_test_pin = 2;
587b62fc9e2Snonaka 				if (sc->sc_test_pin == orig_pin)
588b62fc9e2Snonaka 					break;
589b62fc9e2Snonaka 				if (sc->sc_test_pin != sc->sc_nouse_pin
590b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_nouse_pin2
591b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_nouse_pin3
592b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_key_pin
593b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_power_pin
594b62fc9e2Snonaka 				 && sc->sc_test_pin != sc->sc_reset_pin
595b62fc9e2Snonaka 				 && GPIO_IS_GPIO_OUT(pxa2x0_gpio_get_function(sc->sc_test_pin)))
596b62fc9e2Snonaka 				break;
597b62fc9e2Snonaka 			}
598b62fc9e2Snonaka 			if (sc->sc_test_pin != orig_pin) {
599b62fc9e2Snonaka 				printf("GPIO_OUT: GPIO pin #%d\n", sc->sc_test_pin);
600b62fc9e2Snonaka 			} else {
601b62fc9e2Snonaka 				sc->sc_test_pin = -1;
602b62fc9e2Snonaka 			}
603b62fc9e2Snonaka 		}
604b62fc9e2Snonaka 	}
605b62fc9e2Snonaka #endif
606b62fc9e2Snonaka #if defined(KEYTEST5)
607b62fc9e2Snonaka 	if (pxa2x0_gpio_get_bit(sc->sc_power_pin)) {
608b62fc9e2Snonaka 		sc->sc_bit <<= 1;
609b62fc9e2Snonaka 		if (sc->sc_bit & ~0xff) {
610b62fc9e2Snonaka 			sc->sc_bit = 0x01;
611b62fc9e2Snonaka 			sc->sc_test_pin += 0x4;
612b62fc9e2Snonaka 			if (sc->sc_test_pin >= 0x20) {
613b62fc9e2Snonaka 				sc->sc_test_pin = 0x00;
614b62fc9e2Snonaka 			}
615b62fc9e2Snonaka 		}
616b62fc9e2Snonaka 		printf("CPLD(%#x), mask=%#x\n", sc->sc_test_pin, sc->sc_bit);
617b62fc9e2Snonaka 	}
618b62fc9e2Snonaka #endif
619b62fc9e2Snonaka 
620b62fc9e2Snonaka 	pxa2x0_gpio_clear_intr(sc->sc_power_pin);
621b62fc9e2Snonaka 
622b62fc9e2Snonaka 	return 1;
623b62fc9e2Snonaka }
624b62fc9e2Snonaka 
625b62fc9e2Snonaka static int
wzero3kbd_reset_intr(void * arg)626b62fc9e2Snonaka wzero3kbd_reset_intr(void *arg)
627b62fc9e2Snonaka {
628b62fc9e2Snonaka 	struct wzero3kbd_softc *sc = (struct wzero3kbd_softc *)arg;
629b62fc9e2Snonaka 
630b62fc9e2Snonaka 	sysmon_task_queue_sched(0, wzero3kbd_sysmon_reset_event, sc);
631b62fc9e2Snonaka 
632b62fc9e2Snonaka 	pxa2x0_gpio_clear_intr(sc->sc_reset_pin);
633b62fc9e2Snonaka 
634b62fc9e2Snonaka 	return 1;
635b62fc9e2Snonaka }
636b62fc9e2Snonaka 
637b62fc9e2Snonaka static int
wzero3kbd_input_establish(void * arg,struct hpckbd_if * kbdif)638b62fc9e2Snonaka wzero3kbd_input_establish(void *arg, struct hpckbd_if *kbdif)
639b62fc9e2Snonaka {
640b62fc9e2Snonaka 	struct wzero3kbd_softc *sc = (struct wzero3kbd_softc *)arg;
641b62fc9e2Snonaka 
642b62fc9e2Snonaka 	/* Save hpckbd interface. */
643b62fc9e2Snonaka 	sc->sc_hpckbd = kbdif;
644b62fc9e2Snonaka 	sc->sc_enabled = 1;
645b62fc9e2Snonaka 
646b62fc9e2Snonaka 	return 0;
647b62fc9e2Snonaka }
648b62fc9e2Snonaka 
649b62fc9e2Snonaka static void
wzero3kbd_sysmon_reset_event(void * arg)650b62fc9e2Snonaka wzero3kbd_sysmon_reset_event(void *arg)
651b62fc9e2Snonaka {
652b62fc9e2Snonaka 	struct wzero3kbd_softc *sc = (struct wzero3kbd_softc *)arg;
653b62fc9e2Snonaka 
654b62fc9e2Snonaka 	sysmon_pswitch_event(&sc->sc_smpsw, PSWITCH_EVENT_PRESSED);
655b62fc9e2Snonaka }
656b62fc9e2Snonaka 
657b62fc9e2Snonaka static int
wzero3kbd_poll(void * arg)658b62fc9e2Snonaka wzero3kbd_poll(void *arg)
659b62fc9e2Snonaka {
660b62fc9e2Snonaka 	int keydown;
661b62fc9e2Snonaka 
662b62fc9e2Snonaka 	keydown = wzero3kbd_poll1(arg);
663b62fc9e2Snonaka 
664b62fc9e2Snonaka 	return keydown;
665b62fc9e2Snonaka }
666b62fc9e2Snonaka 
667b62fc9e2Snonaka static int
wzero3kbd_poll1(void * arg)668b62fc9e2Snonaka wzero3kbd_poll1(void *arg)
669b62fc9e2Snonaka {
670b62fc9e2Snonaka 	struct wzero3kbd_softc *sc = (struct wzero3kbd_softc *)arg;
671b62fc9e2Snonaka 	int row, col, data;
67256de8227Snonaka 	int keycol;
673b62fc9e2Snonaka 	int keydown;
674b62fc9e2Snonaka 	int i;
675b62fc9e2Snonaka 	int s;
676b62fc9e2Snonaka 
677b62fc9e2Snonaka 	if (!sc->sc_enabled) {
678b62fc9e2Snonaka 		DPRINTF(("wzero3kbd_poll: disabled\n"));
679b62fc9e2Snonaka 		return 0;
680b62fc9e2Snonaka 	}
681b62fc9e2Snonaka 
682b62fc9e2Snonaka 	s = spltty();
683b62fc9e2Snonaka 
684b62fc9e2Snonaka 	for (col = 0; col < sc->sc_ncolumn; col++) {
685b62fc9e2Snonaka 		/* deselect column# and charge */
686b62fc9e2Snonaka 		CSR_WRITE1(KBDCOL_L, 0);
687b62fc9e2Snonaka 		CSR_WRITE1(KBDCOL_U, 0);
688b62fc9e2Snonaka 		CSR_WRITE1(KBDCHARGE, 1);
689b62fc9e2Snonaka 		delay(KEYWAIT);
690b62fc9e2Snonaka 		CSR_WRITE1(KBDCHARGE, 0);
691b62fc9e2Snonaka 
692b62fc9e2Snonaka 		/* select scan column# */
693e8fe64adSnonaka 		keycol = 1 << col;
69456de8227Snonaka 		CSR_WRITE1(KBDCOL_L, keycol & 0xff);
69556de8227Snonaka 		CSR_WRITE1(KBDCOL_U, keycol >> 8);
696b62fc9e2Snonaka 		delay(KEYWAIT);
697b62fc9e2Snonaka 		CSR_WRITE1(KBDCHARGE, 0);
698b62fc9e2Snonaka 
699b62fc9e2Snonaka 		/* read key data */
700b62fc9e2Snonaka 		data = CSR_READ1(KBDDATA);
701b62fc9e2Snonaka 		for (row = 0; row < sc->sc_nrow; row++) {
702b62fc9e2Snonaka #ifdef KEYTEST2
703b62fc9e2Snonaka 			if (!(sc->sc_enabled & 2)) {
704b62fc9e2Snonaka #endif
705b62fc9e2Snonaka 			sc->sc_keystat[row + col * sc->sc_nrow] =
706b62fc9e2Snonaka 			    (data >> row) & 1;
707b62fc9e2Snonaka #ifdef KEYTEST2
708b62fc9e2Snonaka 			} else if (data & (1 << row)) {
709b62fc9e2Snonaka 				printf("col = %d, row = %d, idx = %d, data = 0x%02x\n", col, row, row + col * sc->sc_nrow, data);
710b62fc9e2Snonaka 			}
711b62fc9e2Snonaka #endif
712b62fc9e2Snonaka 		}
713b62fc9e2Snonaka 	}
714b62fc9e2Snonaka 
715b62fc9e2Snonaka 	/* deselect column# and charge */
716b62fc9e2Snonaka 	CSR_WRITE1(KBDCOL_L, 0);
717b62fc9e2Snonaka 	CSR_WRITE1(KBDCOL_U, 0);
718b62fc9e2Snonaka 	CSR_WRITE1(KBDCHARGE, 1);
719b62fc9e2Snonaka 	delay(KEYWAIT);
720b62fc9e2Snonaka 	CSR_WRITE1(KBDCHARGE, 0);
721b62fc9e2Snonaka 
722b62fc9e2Snonaka 	/* send key scan code */
723b62fc9e2Snonaka 	keydown = 0;
724b62fc9e2Snonaka 	for (i = 0; i < sc->sc_nrow * sc->sc_ncolumn; i++) {
72556de8227Snonaka 		if (sc->sc_keystat[i] == sc->sc_okeystat[i])
72656de8227Snonaka 			continue;
72756de8227Snonaka 
72856de8227Snonaka 		keydown |= sc->sc_keystat[i];
72956de8227Snonaka 		hpckbd_input(sc->sc_hpckbd, sc->sc_keystat[i], i);
73056de8227Snonaka 		sc->sc_okeystat[i] = sc->sc_keystat[i];
731b62fc9e2Snonaka 	}
732b62fc9e2Snonaka 
733b62fc9e2Snonaka 	splx(s);
734b62fc9e2Snonaka 
735b62fc9e2Snonaka 	return keydown;
736b62fc9e2Snonaka }
737