1 /* $NetBSD: j720kbd.c,v 1.6 2009/05/29 14:15:45 rjs Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by IWAMOTO Toshihiro and Peter Postma. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* Jornada 720 keyboard driver. */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: j720kbd.c,v 1.6 2009/05/29 14:15:45 rjs Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/kernel.h> 41 42 #include <machine/bootinfo.h> 43 #include <machine/config_hook.h> 44 #include <machine/platid.h> 45 #include <machine/platid_mask.h> 46 47 #include <arm/sa11x0/sa11x0_var.h> 48 #include <arm/sa11x0/sa11x0_gpioreg.h> 49 #include <arm/sa11x0/sa11x0_ppcreg.h> 50 #include <arm/sa11x0/sa11x0_sspreg.h> 51 52 #include <dev/hpc/hpckbdvar.h> 53 54 #include <hpcarm/dev/j720sspvar.h> 55 56 #ifdef DEBUG 57 #define DPRINTF(arg) aprint_normal arg 58 #else 59 #define DPRINTF(arg) /* nothing */ 60 #endif 61 62 struct j720kbd_chip { 63 int scc_enabled; 64 65 struct j720ssp_softc *scc_ssp; 66 67 struct hpckbd_ic_if scc_if; 68 struct hpckbd_if *scc_hpckbd; 69 }; 70 71 struct j720kbd_softc { 72 device_t sc_dev; 73 74 struct j720kbd_chip *sc_chip; 75 }; 76 77 static struct j720kbd_chip j720kbd_chip; 78 79 static int j720kbd_match(device_t, cfdata_t, void *); 80 static void j720kbd_attach(device_t, device_t, void *); 81 82 static void j720kbd_cnattach(void); 83 static void j720kbd_ifsetup(struct j720kbd_chip *); 84 static int j720kbd_input_establish(void *, struct hpckbd_if *); 85 static int j720kbd_intr(void *); 86 static int j720kbd_poll(void *); 87 static void j720kbd_read(struct j720kbd_chip *, char *); 88 89 CFATTACH_DECL_NEW(j720kbd, sizeof(struct j720kbd_softc), 90 j720kbd_match, j720kbd_attach, NULL, NULL); 91 92 93 static int 94 j720kbd_match(device_t parent, cfdata_t cf, void *aux) 95 { 96 97 if (!platid_match(&platid, &platid_mask_MACH_HP_JORNADA_7XX)) 98 return 0; 99 if (strcmp(cf->cf_name, "j720kbd") != 0) 100 return 0; 101 102 return 1; 103 } 104 105 static void 106 j720kbd_attach(device_t parent, device_t self, void *aux) 107 { 108 struct j720kbd_softc *sc = device_private(self); 109 struct hpckbd_attach_args haa; 110 111 aprint_normal("\n"); 112 113 sc->sc_dev = self; 114 sc->sc_chip = &j720kbd_chip; 115 sc->sc_chip->scc_ssp = device_private(parent); 116 sc->sc_chip->scc_enabled = 0; 117 118 /* Attach console if not using serial. */ 119 if (!(bootinfo->bi_cnuse & BI_CNUSE_SERIAL)) 120 j720kbd_cnattach(); 121 122 j720kbd_ifsetup(sc->sc_chip); 123 124 /* Install interrupt handler. */ 125 sa11x0_intr_establish(0, 0, 1, IPL_TTY, j720kbd_intr, sc); 126 127 /* Attach hpckbd. */ 128 haa.haa_ic = &sc->sc_chip->scc_if; 129 config_found(self, &haa, hpckbd_print); 130 } 131 132 static void 133 j720kbd_cnattach(void) 134 { 135 struct j720kbd_chip *scc = &j720kbd_chip; 136 137 /* Initialize interface. */ 138 j720kbd_ifsetup(scc); 139 140 /* Attach console. */ 141 hpckbd_cnattach(&scc->scc_if); 142 } 143 144 static void 145 j720kbd_ifsetup(struct j720kbd_chip *scc) 146 { 147 148 scc->scc_if.hii_ctx = scc; 149 scc->scc_if.hii_establish = j720kbd_input_establish; 150 scc->scc_if.hii_poll = j720kbd_poll; 151 } 152 153 static int 154 j720kbd_input_establish(void *ic, struct hpckbd_if *kbdif) 155 { 156 struct j720kbd_chip *scc = ic; 157 158 /* Save hpckbd interface. */ 159 scc->scc_hpckbd = kbdif; 160 161 scc->scc_enabled = 1; 162 163 return 0; 164 } 165 166 static int 167 j720kbd_intr(void *arg) 168 { 169 struct j720kbd_softc *sc = arg; 170 struct j720ssp_softc *ssp = sc->sc_chip->scc_ssp; 171 172 bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_EDR, 1); 173 174 return j720kbd_poll(sc->sc_chip); 175 } 176 177 static int 178 j720kbd_poll(void *arg) 179 { 180 struct j720kbd_chip *scc = arg; 181 int type, key; 182 char buf[9], *p; 183 184 if (!scc->scc_enabled) { 185 DPRINTF(("j720kbd_poll: !scc_enabled\n")); 186 return 0; 187 } 188 189 j720kbd_read(scc, buf); 190 191 for (p = buf; *p; p++) { 192 type = *p & 0x80 ? 0 : 1; 193 key = *p & 0x7f; 194 195 hpckbd_input(scc->scc_hpckbd, type, key); 196 } 197 198 return 1; 199 } 200 201 static void 202 j720kbd_read(struct j720kbd_chip *scc, char *buf) 203 { 204 struct j720ssp_softc *ssp = scc->scc_ssp; 205 int data, count; 206 207 bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PCR, 0x2000000); 208 209 /* Send scan keycode command. */ 210 if (j720ssp_readwrite(ssp, 1, 0x90, &data, 500) < 0 || data != 0x11) { 211 DPRINTF(("j720kbd_read: no dummy received\n")); 212 goto out; 213 } 214 215 /* Read number of scancodes available. */ 216 if (j720ssp_readwrite(ssp, 0, 0x11, &data, 500) < 0) { 217 DPRINTF(("j720kbd_read: unable to read number of scancodes\n")); 218 goto out; 219 } 220 count = data; 221 222 for (; count; count--) { 223 if (j720ssp_readwrite(ssp, 0, 0x11, &data, 100) < 0) 224 goto out; 225 *buf++ = data; 226 } 227 *buf = 0; 228 bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PSR, 0x2000000); 229 230 return; 231 232 out: 233 *buf = 0; 234 bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PSR, 0x2000000); 235 236 /* reset SSP */ 237 bus_space_write_4(ssp->sc_iot, ssp->sc_ssph, SASSP_CR0, 0x307); 238 delay(100); 239 bus_space_write_4(ssp->sc_iot, ssp->sc_ssph, SASSP_CR0, 0x387); 240 241 DPRINTF(("j720kbd_read: error %x\n", data)); 242 } 243