1 /* $NetBSD: j720kbd.c,v 1.5 2008/04/28 20:23:21 martin 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.5 2008/04/28 20:23:21 martin 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) printf 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 struct device sc_dev; 73 74 struct j720kbd_chip *sc_chip; 75 }; 76 77 static struct j720kbd_chip j720kbd_chip; 78 79 static int j720kbd_match(struct device *, struct cfdata *, void *); 80 static void j720kbd_attach(struct device *, struct device *, 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(j720kbd, sizeof(struct j720kbd_softc), 90 j720kbd_match, j720kbd_attach, NULL, NULL); 91 92 93 static int 94 j720kbd_match(struct device *parent, struct cfdata *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(struct device *parent, struct device *self, void *aux) 107 { 108 struct j720kbd_softc *sc = (void *)self; 109 struct hpckbd_attach_args haa; 110 111 printf("\n"); 112 113 sc->sc_chip = &j720kbd_chip; 114 sc->sc_chip->scc_ssp = (struct j720ssp_softc *)parent; 115 sc->sc_chip->scc_enabled = 0; 116 117 /* Attach console if not using serial. */ 118 if (!(bootinfo->bi_cnuse & BI_CNUSE_SERIAL)) 119 j720kbd_cnattach(); 120 121 j720kbd_ifsetup(sc->sc_chip); 122 123 /* Install interrupt handler. */ 124 sa11x0_intr_establish(0, 0, 1, IPL_TTY, j720kbd_intr, sc); 125 126 /* Attach hpckbd. */ 127 haa.haa_ic = &sc->sc_chip->scc_if; 128 config_found(self, &haa, hpckbd_print); 129 } 130 131 static void 132 j720kbd_cnattach(void) 133 { 134 struct j720kbd_chip *scc = &j720kbd_chip; 135 136 /* Initialize interface. */ 137 j720kbd_ifsetup(scc); 138 139 /* Attach console. */ 140 hpckbd_cnattach(&scc->scc_if); 141 } 142 143 static void 144 j720kbd_ifsetup(struct j720kbd_chip *scc) 145 { 146 147 scc->scc_if.hii_ctx = scc; 148 scc->scc_if.hii_establish = j720kbd_input_establish; 149 scc->scc_if.hii_poll = j720kbd_poll; 150 } 151 152 static int 153 j720kbd_input_establish(void *ic, struct hpckbd_if *kbdif) 154 { 155 struct j720kbd_chip *scc = ic; 156 157 /* Save hpckbd interface. */ 158 scc->scc_hpckbd = kbdif; 159 160 scc->scc_enabled = 1; 161 162 return 0; 163 } 164 165 static int 166 j720kbd_intr(void *arg) 167 { 168 struct j720kbd_softc *sc = arg; 169 struct j720ssp_softc *ssp = sc->sc_chip->scc_ssp; 170 171 bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_EDR, 1); 172 173 return j720kbd_poll(sc->sc_chip); 174 } 175 176 static int 177 j720kbd_poll(void *arg) 178 { 179 struct j720kbd_chip *scc = arg; 180 int type, key; 181 char buf[9], *p; 182 183 if (!scc->scc_enabled) { 184 DPRINTF(("j720kbd_poll: !scc_enabled\n")); 185 return 0; 186 } 187 188 j720kbd_read(scc, buf); 189 190 for (p = buf; *p; p++) { 191 type = *p & 0x80 ? 0 : 1; 192 key = *p & 0x7f; 193 194 hpckbd_input(scc->scc_hpckbd, type, key); 195 } 196 197 return 1; 198 } 199 200 static void 201 j720kbd_read(struct j720kbd_chip *scc, char *buf) 202 { 203 struct j720ssp_softc *ssp = scc->scc_ssp; 204 int data, count; 205 206 bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PCR, 0x2000000); 207 208 /* Send scan keycode command. */ 209 if (j720ssp_readwrite(ssp, 1, 0x90, &data, 500) < 0 || data != 0x11) { 210 DPRINTF(("j720kbd_read: no dummy received\n")); 211 goto out; 212 } 213 214 /* Read number of scancodes available. */ 215 if (j720ssp_readwrite(ssp, 0, 0x11, &data, 500) < 0) { 216 DPRINTF(("j720kbd_read: unable to read number of scancodes\n")); 217 goto out; 218 } 219 count = data; 220 221 for (; count; count--) { 222 if (j720ssp_readwrite(ssp, 0, 0x11, &data, 100) < 0) 223 goto out; 224 *buf++ = data; 225 } 226 *buf = 0; 227 bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PSR, 0x2000000); 228 229 return; 230 231 out: 232 *buf = 0; 233 bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PSR, 0x2000000); 234 235 /* reset SSP */ 236 bus_space_write_4(ssp->sc_iot, ssp->sc_ssph, SASSP_CR0, 0x307); 237 delay(100); 238 bus_space_write_4(ssp->sc_iot, ssp->sc_ssph, SASSP_CR0, 0x387); 239 240 DPRINTF(("j720kbd_read: error %x\n", data)); 241 } 242