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