xref: /netbsd-src/sys/arch/hpcsh/dev/pfckbd.c (revision 9719c27fead1c730f6066a84ea96173b9f4ed9e7)
1*9719c27fSandvar /*	$NetBSD: pfckbd.c,v 1.33 2023/06/01 20:15:16 andvar Exp $	*/
2f4cdccecSuch 
3f4cdccecSuch /*-
4415a0562Such  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
5f4cdccecSuch  * All rights reserved.
6f4cdccecSuch  *
7f4cdccecSuch  * This code is derived from software contributed to The NetBSD Foundation
8f4cdccecSuch  * by UCHIYAMA Yasushi.
9f4cdccecSuch  *
10f4cdccecSuch  * Redistribution and use in source and binary forms, with or without
11f4cdccecSuch  * modification, are permitted provided that the following conditions
12f4cdccecSuch  * are met:
13f4cdccecSuch  * 1. Redistributions of source code must retain the above copyright
14f4cdccecSuch  *    notice, this list of conditions and the following disclaimer.
15f4cdccecSuch  * 2. Redistributions in binary form must reproduce the above copyright
16f4cdccecSuch  *    notice, this list of conditions and the following disclaimer in the
17f4cdccecSuch  *    documentation and/or other materials provided with the distribution.
18f4cdccecSuch  *
19f4cdccecSuch  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20f4cdccecSuch  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21f4cdccecSuch  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22f4cdccecSuch  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23f4cdccecSuch  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24f4cdccecSuch  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25f4cdccecSuch  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26f4cdccecSuch  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27f4cdccecSuch  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28f4cdccecSuch  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29f4cdccecSuch  * POSSIBILITY OF SUCH DAMAGE.
30f4cdccecSuch  */
31415a0562Such 
32ea99f7e9Suwe /*
33ea99f7e9Suwe  * Matrix scan keyboard connected to SH7709, SH7709A PFC module.
34ea99f7e9Suwe  * currently, HP Jornada 680/690, HITACHI PERSONA HPW-50PAD only.
35ea99f7e9Suwe  */
360c82163cSlukem #include <sys/cdefs.h>
37*9719c27fSandvar __KERNEL_RCSID(0, "$NetBSD: pfckbd.c,v 1.33 2023/06/01 20:15:16 andvar Exp $");
380c82163cSlukem 
39415a0562Such #include "debug_hpcsh.h"
40f4cdccecSuch 
41f4cdccecSuch #include <sys/param.h>
42f4cdccecSuch #include <sys/systm.h>
43f4cdccecSuch #include <sys/device.h>
44f4cdccecSuch #include <sys/callout.h>
45f48d88bfSdyoung #include <sys/bus.h>
46f4cdccecSuch 
47a9700422Such #include <machine/platid.h>
48a9700422Such #include <machine/platid_mask.h>
49a9700422Such 
50f4cdccecSuch #include <dev/hpc/hpckbdvar.h>
51f4cdccecSuch 
52f4cdccecSuch #include <sh3/pfcreg.h>
53f4cdccecSuch 
54f4cdccecSuch #include <hpcsh/dev/pfckbdvar.h>
55f4cdccecSuch 
56f4cdccecSuch #ifdef	PFCKBD_DEBUG
57415a0562Such #define DPRINTF_ENABLE
58415a0562Such #define DPRINTF_DEBUG	pfckbd_debug
59f4cdccecSuch #endif
607d170993Such #include <machine/debug.h>
61f4cdccecSuch 
62ea99f7e9Suwe static struct pfckbd_core {
63f4cdccecSuch 	int pc_attached;
64f4cdccecSuch 	int pc_enabled;
65f4cdccecSuch 	struct callout pc_soft_ch;
66f4cdccecSuch 	struct hpckbd_ic_if pc_if;
67f4cdccecSuch 	struct hpckbd_if *pc_hpckbd;
685176524bSuwe 	uint16_t pc_column[8];
69ffcff524Suwe 	void (*pc_callout)(struct pfckbd_core *);
70f4cdccecSuch } pfckbd_core;
71f4cdccecSuch 
7299111ebaSuwe static int pfckbd_match(device_t, cfdata_t, void *);
7399111ebaSuwe static void pfckbd_attach(device_t, device_t, void *);
742889a03eSuwe 
7599111ebaSuwe CFATTACH_DECL_NEW(pfckbd, 0,
762889a03eSuwe     pfckbd_match, pfckbd_attach, NULL, NULL);
772889a03eSuwe 
782889a03eSuwe static void pfckbd_ifsetup(struct pfckbd_core *);
792889a03eSuwe 
802889a03eSuwe /* callbacks for hpckbd */
812889a03eSuwe static int pfckbd_input_establish(void *, struct hpckbd_if *);
822889a03eSuwe static int pfckbd_poll(void *);
832889a03eSuwe 
842889a03eSuwe static void pfckbd_input(struct pfckbd_core *, int, uint16_t);
852889a03eSuwe 
86ffcff524Suwe static void (*pfckbd_callout_lookup(void))(struct pfckbd_core *);
87ffcff524Suwe static void pfckbd_callout(void *);
88ffcff524Suwe static void pfckbd_callout_hp(struct pfckbd_core *);
89ffcff524Suwe static void pfckbd_callout_hitachi(struct pfckbd_core *);
90685380a8Skiyohara void pfckbd_poll_hitachi_power(void);
91685380a8Skiyohara 
922889a03eSuwe 
93*9719c27fSandvar /* callout function table. this function is platform specific. */
94ea99f7e9Suwe static const struct {
95a9700422Such 	platid_mask_t *platform;
96ffcff524Suwe 	void (*func)(struct pfckbd_core *);
97a9700422Such } pfckbd_calloutfunc_table[] = {
98a9700422Such 	{ &platid_mask_MACH_HP		, pfckbd_callout_hp },
99a9700422Such 	{ &platid_mask_MACH_HITACHI	, pfckbd_callout_hitachi }
100f4cdccecSuch };
101f4cdccecSuch 
102f4cdccecSuch 
103f4cdccecSuch void
pfckbd_cnattach(void)104df7f595eScegger pfckbd_cnattach(void)
105f4cdccecSuch {
106f4cdccecSuch 	struct pfckbd_core *pc = &pfckbd_core;
107f4cdccecSuch 
1082889a03eSuwe 	if ((cpu_product != CPU_PRODUCT_7709)
1092889a03eSuwe 	    && (cpu_product != CPU_PRODUCT_7709A))
110bbc655c4Such 		return;
111bbc655c4Such 
112f4cdccecSuch 	/* initialize interface */
113f4cdccecSuch 	pfckbd_ifsetup(pc);
114a9700422Such 
1152889a03eSuwe 	/* attach descendants */
116f4cdccecSuch 	hpckbd_cnattach(&pc->pc_if);
117f4cdccecSuch }
118f4cdccecSuch 
119ea99f7e9Suwe static int
pfckbd_match(device_t parent,cfdata_t cf,void * aux)12099111ebaSuwe pfckbd_match(device_t parent, cfdata_t cf, void *aux)
121f4cdccecSuch {
122f4cdccecSuch 
1232889a03eSuwe 	if ((cpu_product != CPU_PRODUCT_7709)
1242889a03eSuwe 	    && (cpu_product != CPU_PRODUCT_7709A))
1252889a03eSuwe 		return 0;
126000bb389Such 
1272889a03eSuwe 	return !pfckbd_core.pc_attached; /* attach only once */
128f4cdccecSuch }
129f4cdccecSuch 
130ea99f7e9Suwe static void
pfckbd_attach(device_t parent,device_t self,void * aux)13199111ebaSuwe pfckbd_attach(device_t parent, device_t self, void *aux)
132f4cdccecSuch {
133f4cdccecSuch 	struct hpckbd_attach_args haa;
134f4cdccecSuch 
13599111ebaSuwe 	aprint_naive("\n");
13699111ebaSuwe 	aprint_normal("\n");
137f4cdccecSuch 
138f4cdccecSuch 	pfckbd_core.pc_attached = 1;
1392889a03eSuwe 
140f4cdccecSuch 	pfckbd_ifsetup(&pfckbd_core);
141f4cdccecSuch 
142f4cdccecSuch 	/* attach hpckbd */
1432889a03eSuwe 	haa.haa_ic = &pfckbd_core.pc_if; /* tell hpckbd our interface */
144c7fb772bSthorpej 	config_found(self, &haa, hpckbd_print, CFARGS_NONE);
145f4cdccecSuch 
146f4cdccecSuch 	/* install callout handler */
147ffcff524Suwe 	if (pfckbd_core.pc_callout != NULL) {
14888ab7da9Sad 		callout_init(&pfckbd_core.pc_soft_ch, 0);
1492889a03eSuwe 		callout_reset(&pfckbd_core.pc_soft_ch, 1,
150ffcff524Suwe 			      pfckbd_callout, &pfckbd_core);
151ffcff524Suwe 	}
152ffcff524Suwe 	else
153ffcff524Suwe 		aprint_error_dev(self, "unsupported platform\n");
1544e37bb5aSuwe 
1554e37bb5aSuwe 	if (!pmf_device_register(self, NULL, NULL))
1564e37bb5aSuwe 		aprint_error_dev(self, "unable to establish power handler\n");
157f4cdccecSuch }
158f4cdccecSuch 
159ea99f7e9Suwe static void
pfckbd_ifsetup(struct pfckbd_core * pc)160f4cdccecSuch pfckbd_ifsetup(struct pfckbd_core *pc)
161f4cdccecSuch {
162f4cdccecSuch 	int i;
163f4cdccecSuch 
164f4cdccecSuch 	pc->pc_if.hii_ctx = pc;
165f4cdccecSuch 	pc->pc_if.hii_establish	= pfckbd_input_establish;
166f4cdccecSuch 	pc->pc_if.hii_poll = pfckbd_poll;
1672889a03eSuwe 
168f4cdccecSuch 	for (i = 0; i < 8; i++)
16927e08ba4Such 		pc->pc_column[i] = 0xdfff;
170a9700422Such 
171a9700422Such 	/* select PFC access method */
172a9700422Such 	pc->pc_callout = pfckbd_callout_lookup();
173f4cdccecSuch }
174f4cdccecSuch 
1752889a03eSuwe 
1762889a03eSuwe /*
1772889a03eSuwe  * Callback for hpckbd_initif
1782889a03eSuwe  */
1792889a03eSuwe static int
pfckbd_input_establish(void * ic,struct hpckbd_if * kbdif)1802889a03eSuwe pfckbd_input_establish(void *ic, struct hpckbd_if *kbdif)
1812889a03eSuwe {
1822889a03eSuwe 	struct pfckbd_core *pc = ic;
1832889a03eSuwe 
1842889a03eSuwe 	pc->pc_hpckbd = kbdif;	/* save hpckbd interface */
1852889a03eSuwe 	pc->pc_enabled = 1;	/* ok to talk to hpckbd */
1862889a03eSuwe 
1872889a03eSuwe 	return 0;
1882889a03eSuwe }
1892889a03eSuwe 
1902889a03eSuwe /*
1912889a03eSuwe  * Callback for hpckbd_cngetc
1922889a03eSuwe  */
1932889a03eSuwe static int
pfckbd_poll(void * ic)1942889a03eSuwe pfckbd_poll(void *ic)
1952889a03eSuwe {
1962889a03eSuwe 	struct pfckbd_core *pc = ic;
1972889a03eSuwe 
198ffcff524Suwe 	if (pc->pc_enabled && pc->pc_callout != NULL)
1992889a03eSuwe 		(*pc->pc_callout)(pc);
2002889a03eSuwe 
2012889a03eSuwe 	return 0;
2022889a03eSuwe }
2032889a03eSuwe 
204ffcff524Suwe static void
pfckbd_callout(void * arg)205ffcff524Suwe pfckbd_callout(void *arg)
206ffcff524Suwe {
207ffcff524Suwe 	struct pfckbd_core *pc = arg;
208ffcff524Suwe 
209ffcff524Suwe 	(*pc->pc_callout)(pc);
210ffcff524Suwe 	callout_schedule(&pc->pc_soft_ch, 1);
211ffcff524Suwe }
212ffcff524Suwe 
213ffcff524Suwe 
2142889a03eSuwe /*
2152889a03eSuwe  * Called by platform specific scan routines to report key events to hpckbd
2162889a03eSuwe  */
217ea99f7e9Suwe static void
pfckbd_input(struct pfckbd_core * pc,int column,uint16_t data)2182889a03eSuwe pfckbd_input(struct pfckbd_core *pc, int column, uint16_t data)
219f4cdccecSuch {
220a9700422Such 	int row, type, val;
221131f4396Suwe 	unsigned int edge, mask;
22227e08ba4Such 
2232889a03eSuwe 	edge = data ^ pc->pc_column[column];
2242889a03eSuwe 	if (edge == 0)
2252889a03eSuwe 		return;		/* no changes in this column */
226f4cdccecSuch 
2272889a03eSuwe 	pc->pc_column[column] = data;
2282889a03eSuwe 
2292889a03eSuwe 	for (row = 0, mask = 1; row < 16; ++row, mask <<= 1) {
230f4cdccecSuch 		if (mask & edge) {
2312889a03eSuwe 			type = mask & data ? /* up */ 0 : /* down */ 1;
2322889a03eSuwe 			DPRINTF("(%2d, %2d) %d \n", row, column, type);
2332889a03eSuwe 
234f4cdccecSuch 			val = row * 8 + column;
2352889a03eSuwe 			hpckbd_input(pc->pc_hpckbd, type, val);
236f4cdccecSuch 		}
237f4cdccecSuch 	}
238f4cdccecSuch }
2392889a03eSuwe 
240f4cdccecSuch 
241a9700422Such /*
2422889a03eSuwe  * Platform dependent scan routines.
243a9700422Such  */
244a9700422Such 
245a9700422Such /* Look up appropriate callback handler */
246ea99f7e9Suwe static void
pfckbd_callout_lookup(void)247ffcff524Suwe (*pfckbd_callout_lookup(void))(struct pfckbd_core *)
248a9700422Such {
2492889a03eSuwe 	int i, n;
2502889a03eSuwe 
2512889a03eSuwe 	n = sizeof(pfckbd_calloutfunc_table)
2522889a03eSuwe 		/ sizeof(pfckbd_calloutfunc_table[0]);
253a9700422Such 
254a9700422Such 	for (i = 0; i < n; i++)
255a9700422Such 		if (platid_match(&platid,
256a9700422Such 				 pfckbd_calloutfunc_table[i].platform))
2572889a03eSuwe 			return pfckbd_calloutfunc_table[i].func;
258a9700422Such 
259ffcff524Suwe 	return NULL;
260a9700422Such }
261a9700422Such 
2622889a03eSuwe /*
2632889a03eSuwe  * HP Jornada680/690, HP620LX
2642889a03eSuwe  */
265ea99f7e9Suwe static void
pfckbd_callout_hp(struct pfckbd_core * pc)266ffcff524Suwe pfckbd_callout_hp(struct pfckbd_core *pc)
267a9700422Such {
268580c60b3Suwe #define PFCKBD_HP_PDCR_MASK 0xcc0c
269580c60b3Suwe #define PFCKBD_HP_PECR_MASK 0xf0cf
270580c60b3Suwe 
271580c60b3Suwe 	/*
272580c60b3Suwe 	 * Disable output on all lines but the n'th line in D.
273580c60b3Suwe 	 * Pull the n'th scan line in D low.
274580c60b3Suwe 	 */
275580c60b3Suwe #define PD(n)								\
2765176524bSuwe 	{ (uint16_t)(PFCKBD_HP_PDCR_MASK & (~(1 << (2*(n)+1)))),	\
2775176524bSuwe 	  (uint16_t)(PFCKBD_HP_PECR_MASK & 0xffff),			\
2785176524bSuwe 	  (uint8_t)~(1 << (n)),						\
279580c60b3Suwe 	  0xff }
280580c60b3Suwe 
281580c60b3Suwe 	/* Ditto for E */
282580c60b3Suwe #define PE(n)								\
2835176524bSuwe 	{ (uint16_t)(PFCKBD_HP_PDCR_MASK & 0xffff),			\
2845176524bSuwe 	  (uint16_t)(PFCKBD_HP_PECR_MASK & (~(1 << (2*(n)+1)))),	\
285580c60b3Suwe 	  0xff,								\
2865176524bSuwe 	  (uint8_t)~(1 << (n)) }
287580c60b3Suwe 
288a9700422Such 	static const struct {
2895176524bSuwe 		uint16_t dc, ec; uint8_t d, e;
290a9700422Such 	} scan[] = {
291580c60b3Suwe 		PD(1), PD(5), PE(1), PE(6), PE(7), PE(3), PE(0), PD(7)
292a9700422Such 	};
293580c60b3Suwe 
294580c60b3Suwe #undef PD
295580c60b3Suwe #undef PE
296580c60b3Suwe 
2975176524bSuwe 	uint16_t dc, ec;
298a9700422Such 	int column;
2995176524bSuwe 	uint16_t data;
300a9700422Such 
301a9700422Such 	if (!pc->pc_enabled)
302ffcff524Suwe 		return;
303a9700422Such 
304580c60b3Suwe 	/* bits in D/E control regs we do not touch (XXX: can they change?) */
305580c60b3Suwe 	dc = _reg_read_2(SH7709_PDCR) & ~PFCKBD_HP_PDCR_MASK;
306580c60b3Suwe 	ec = _reg_read_2(SH7709_PECR) & ~PFCKBD_HP_PECR_MASK;
307580c60b3Suwe 
308a9700422Such 	for (column = 0; column < 8; column++) {
309580c60b3Suwe 		/* disable output to all lines except the one we scan */
310580c60b3Suwe 		_reg_write_2(SH7709_PDCR, dc | scan[column].dc);
311580c60b3Suwe 		_reg_write_2(SH7709_PECR, ec | scan[column].ec);
312580c60b3Suwe 		delay(5);
313580c60b3Suwe 
314580c60b3Suwe 		/* pull the scan line low */
315bbc655c4Such 		_reg_write_1(SH7709_PDDR, scan[column].d);
316bbc655c4Such 		_reg_write_1(SH7709_PEDR, scan[column].e);
317a9700422Such 		delay(50);
318580c60b3Suwe 
319580c60b3Suwe 		/* read sense */
3202889a03eSuwe 		data = _reg_read_1(SH7709_PFDR)
3212889a03eSuwe 			| (_reg_read_1(SH7709_PCDR) << 8);
322a9700422Such 
3232889a03eSuwe 		pfckbd_input(pc, column, data);
324a9700422Such 	}
325a9700422Such 
326580c60b3Suwe 	/* scan no lines */
327bbc655c4Such 	_reg_write_1(SH7709_PDDR, 0xff);
328bbc655c4Such 	_reg_write_1(SH7709_PEDR, 0xff);
329580c60b3Suwe 
330580c60b3Suwe 	/* enable all scan lines */
331580c60b3Suwe 	_reg_write_2(SH7709_PDCR, dc | (0x5555 & PFCKBD_HP_PDCR_MASK));
332580c60b3Suwe 	_reg_write_2(SH7709_PECR, ec | (0x5555 & PFCKBD_HP_PECR_MASK));
333580c60b3Suwe 
3343fcefe2aSuwe #if 0
335580c60b3Suwe 	/* (ignore) extra keys/events (recorder buttons, lid, cable &c) */
336bbc655c4Such 	data = _reg_read_1(SH7709_PGDR) | (_reg_read_1(SH7709_PHDR) << 8);
3373fcefe2aSuwe #endif
338a9700422Such }
339a9700422Such 
3402889a03eSuwe /*
3412889a03eSuwe  * HITACH PERSONA (HPW-50PAD)
3422889a03eSuwe  */
343ea99f7e9Suwe static void
pfckbd_callout_hitachi(struct pfckbd_core * pc)344ffcff524Suwe pfckbd_callout_hitachi(struct pfckbd_core *pc)
345a9700422Such {
346dad1ac75Skiyohara #define PFCKBD_HITACHI_PCCR_MASK 0xfff3
347a1e2e32eSuwe #define PFCKBD_HITACHI_PDCR_MASK 0x000c
348a1e2e32eSuwe #define PFCKBD_HITACHI_PECR_MASK 0x30cf
349a1e2e32eSuwe 
350dad1ac75Skiyohara #define PFCKBD_HITACHI_PCDR_SCN_MASK 0xfd
351685380a8Skiyohara #define PFCKBD_HITACHI_PDDR_SCN_MASK 0x02
352685380a8Skiyohara #define PFCKBD_HITACHI_PEDR_SCN_MASK 0x4b
353a1e2e32eSuwe 
354a1e2e32eSuwe #define PFCKBD_HITACHI_PCDR_SNS_MASK 0x01
355a1e2e32eSuwe #define PFCKBD_HITACHI_PFDR_SNS_MASK 0xfe
356a1e2e32eSuwe 
357a1e2e32eSuwe 	/*
358a1e2e32eSuwe 	 * Disable output on all lines but the n'th line in C.
359a1e2e32eSuwe 	 * Pull the n'th scan line in C low.
360a1e2e32eSuwe 	 */
361a1e2e32eSuwe #define PC(n)								\
3625176524bSuwe 	{ (uint16_t)(PFCKBD_HITACHI_PCCR_MASK & (~(1 << (2*(n)+1)))),	\
3635176524bSuwe 	  (uint16_t)(PFCKBD_HITACHI_PDCR_MASK & 0xffff),		\
3645176524bSuwe 	  (uint16_t)(PFCKBD_HITACHI_PECR_MASK & 0xffff),		\
3655176524bSuwe 	  (uint8_t)(PFCKBD_HITACHI_PCDR_SCN_MASK & ~(1 << (n))),	\
366a1e2e32eSuwe 	  PFCKBD_HITACHI_PDDR_SCN_MASK,					\
367a1e2e32eSuwe 	  PFCKBD_HITACHI_PEDR_SCN_MASK }
368a1e2e32eSuwe 
369a1e2e32eSuwe 	/* Ditto for D */
370a1e2e32eSuwe #define PD(n)								\
3715176524bSuwe 	{ (uint16_t)(PFCKBD_HITACHI_PCCR_MASK & 0xffff),		\
3725176524bSuwe 	  (uint16_t)(PFCKBD_HITACHI_PDCR_MASK & (~(1 << (2*(n)+1)))),	\
3735176524bSuwe 	  (uint16_t)(PFCKBD_HITACHI_PECR_MASK & 0xffff),		\
374a1e2e32eSuwe 	  PFCKBD_HITACHI_PCDR_SCN_MASK,					\
3755176524bSuwe 	  (uint8_t)(PFCKBD_HITACHI_PDDR_SCN_MASK & ~(1 << (n))),	\
376a1e2e32eSuwe 	  PFCKBD_HITACHI_PEDR_SCN_MASK }
377a1e2e32eSuwe 
378a1e2e32eSuwe 	/* Ditto for E */
379a1e2e32eSuwe #define PE(n)								\
3805176524bSuwe 	{ (uint16_t)(PFCKBD_HITACHI_PCCR_MASK & 0xffff),		\
3815176524bSuwe 	  (uint16_t)(PFCKBD_HITACHI_PDCR_MASK & 0xffff),		\
3825176524bSuwe 	  (uint16_t)(PFCKBD_HITACHI_PECR_MASK & (~(1 << (2*(n)+1)))),	\
383a1e2e32eSuwe 	  PFCKBD_HITACHI_PCDR_SCN_MASK,					\
384a1e2e32eSuwe 	  PFCKBD_HITACHI_PDDR_SCN_MASK,					\
3855176524bSuwe 	  (uint8_t)(PFCKBD_HITACHI_PEDR_SCN_MASK & ~(1 << (n))) }
386a1e2e32eSuwe 
387a9700422Such 	static const struct {
3885176524bSuwe 		uint16_t cc, dc, ec; uint8_t c, d, e;
389a9700422Such 	} scan[] = {
390a1e2e32eSuwe 		PE(6), PE(3), PE(1), PE(0), PC(7), PC(6), PC(5), PC(4),
391dad1ac75Skiyohara 		PC(3), PC(2), PD(1), PC(0)
392a9700422Such 	};
393a1e2e32eSuwe 
3945176524bSuwe 	uint16_t cc, dc, ec;
395dad1ac75Skiyohara 	uint8_t data[2], cd, dd, ed;
396a1e2e32eSuwe 	int i;
397a9700422Such 
398a9700422Such 	if (!pc->pc_enabled)
399ffcff524Suwe 		return;
400a9700422Such 
401a1e2e32eSuwe 	/* bits in C/D/E control regs we do not touch (XXX: can they change?) */
402a1e2e32eSuwe 	cc = _reg_read_2(SH7709_PCCR) & ~PFCKBD_HITACHI_PCCR_MASK;
403a1e2e32eSuwe 	dc = _reg_read_2(SH7709_PDCR) & ~PFCKBD_HITACHI_PDCR_MASK;
404a1e2e32eSuwe 	ec = _reg_read_2(SH7709_PECR) & ~PFCKBD_HITACHI_PECR_MASK;
405a9700422Such 
406a1e2e32eSuwe 	for (i = 0; i < 12; i++) {
407a1e2e32eSuwe 		/* disable output to all lines except the one we scan */
408dad1ac75Skiyohara 		_reg_write_2(SH7709_PCCR, cc | scan[i].cc);
409a1e2e32eSuwe 		_reg_write_2(SH7709_PDCR, dc | scan[i].dc);
410a1e2e32eSuwe 		_reg_write_2(SH7709_PECR, ec | scan[i].ec);
411a1e2e32eSuwe 		delay(5);
412a1e2e32eSuwe 
413685380a8Skiyohara 		cd = _reg_read_1(SH7709_PCDR) & ~PFCKBD_HITACHI_PCDR_SCN_MASK;
414685380a8Skiyohara 		dd = _reg_read_1(SH7709_PDDR) & ~PFCKBD_HITACHI_PDDR_SCN_MASK;
415685380a8Skiyohara 		ed = _reg_read_1(SH7709_PEDR) & ~PFCKBD_HITACHI_PEDR_SCN_MASK;
416685380a8Skiyohara 
417a1e2e32eSuwe 		/* pull the scan line low */
418685380a8Skiyohara 		_reg_write_1(SH7709_PCDR, cd | scan[i].c);
419685380a8Skiyohara 		_reg_write_1(SH7709_PDDR, dd | scan[i].d);
420685380a8Skiyohara 		_reg_write_1(SH7709_PEDR, ed | scan[i].e);
421a1e2e32eSuwe 		delay(50);
422a1e2e32eSuwe 
423a1e2e32eSuwe 		/* read sense */
424a1e2e32eSuwe 		data[i & 0x1] =
4252889a03eSuwe 		    (_reg_read_1(SH7709_PCDR) & PFCKBD_HITACHI_PCDR_SNS_MASK)
4262889a03eSuwe 		  | (_reg_read_1(SH7709_PFDR) & PFCKBD_HITACHI_PFDR_SNS_MASK);
427a1e2e32eSuwe 
428a1e2e32eSuwe 		if (i & 0x1)
4292889a03eSuwe 			pfckbd_input(pc, (i >> 1), (data[0] | (data[1] << 8)));
430a9700422Such 	}
431a9700422Such 
432a1e2e32eSuwe 	/* enable all scan lines */
433a1e2e32eSuwe 	_reg_write_2(SH7709_PCCR, cc | (0x5555 & PFCKBD_HITACHI_PCCR_MASK));
434a1e2e32eSuwe 	_reg_write_2(SH7709_PDCR, dc | (0x5555 & PFCKBD_HITACHI_PDCR_MASK));
435a1e2e32eSuwe 	_reg_write_2(SH7709_PECR, ec | (0x5555 & PFCKBD_HITACHI_PECR_MASK));
436f4cdccecSuch }
437685380a8Skiyohara 
438685380a8Skiyohara void
pfckbd_poll_hitachi_power(void)439df7f595eScegger pfckbd_poll_hitachi_power(void)
440685380a8Skiyohara {
441685380a8Skiyohara 	static const struct {
442685380a8Skiyohara 		uint16_t cc, dc, ec; uint8_t c, d, e;
443685380a8Skiyohara 	} poll = PD(1);
444685380a8Skiyohara 
445685380a8Skiyohara #undef PC
446685380a8Skiyohara #undef PD
447685380a8Skiyohara #undef PE
448685380a8Skiyohara 
449685380a8Skiyohara 	uint16_t cc, dc, ec;
450685380a8Skiyohara 	uint8_t cd, dd, ed;
451685380a8Skiyohara 
452685380a8Skiyohara 	/* bits in C/D/E control regs we do not touch (XXX: can they change?) */
453685380a8Skiyohara 	cc = _reg_read_2(SH7709_PCCR) & ~PFCKBD_HITACHI_PCCR_MASK;
454685380a8Skiyohara 	dc = _reg_read_2(SH7709_PDCR) & ~PFCKBD_HITACHI_PDCR_MASK;
455685380a8Skiyohara 	ec = _reg_read_2(SH7709_PECR) & ~PFCKBD_HITACHI_PECR_MASK;
456685380a8Skiyohara 
457685380a8Skiyohara 	/* disable output to all lines except the one we scan */
458685380a8Skiyohara 	_reg_write_2(SH7709_PCCR, cc | poll.cc);
459685380a8Skiyohara 	_reg_write_2(SH7709_PDCR, dc | poll.dc);
460685380a8Skiyohara 	_reg_write_2(SH7709_PECR, ec | poll.ec);
461685380a8Skiyohara 	delay(5);
462685380a8Skiyohara 
463685380a8Skiyohara 	cd = _reg_read_1(SH7709_PCDR) & ~PFCKBD_HITACHI_PCDR_SCN_MASK;
464685380a8Skiyohara 	dd = _reg_read_1(SH7709_PDDR) & ~PFCKBD_HITACHI_PDDR_SCN_MASK;
465685380a8Skiyohara 	ed = _reg_read_1(SH7709_PEDR) & ~PFCKBD_HITACHI_PEDR_SCN_MASK;
466685380a8Skiyohara 
467685380a8Skiyohara 	/* pull the scan line low */
468685380a8Skiyohara 	_reg_write_1(SH7709_PCDR, cd | poll.c);
469685380a8Skiyohara 	_reg_write_1(SH7709_PDDR, dd | poll.d);
470685380a8Skiyohara 	_reg_write_1(SH7709_PEDR, ed | poll.e);
471685380a8Skiyohara 	delay(50);
472685380a8Skiyohara 
473685380a8Skiyohara 	/* poll POWER On */
474685380a8Skiyohara 	while (_reg_read_1(SH7709_PCDR) & PFCKBD_HITACHI_PCDR_SNS_MASK & 0x01);
475685380a8Skiyohara 
476685380a8Skiyohara 	/* enable all scan lines */
477685380a8Skiyohara 	_reg_write_2(SH7709_PCCR, cc | (0x5555 & PFCKBD_HITACHI_PCCR_MASK));
478685380a8Skiyohara 	_reg_write_2(SH7709_PDCR, dc | (0x5555 & PFCKBD_HITACHI_PDCR_MASK));
479685380a8Skiyohara 	_reg_write_2(SH7709_PECR, ec | (0x5555 & PFCKBD_HITACHI_PECR_MASK));
480685380a8Skiyohara }
481