1 /* $NetBSD: j720ssp.c,v 1.2 2001/06/29 17:22:50 toshii Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 1990 The Regents of the University of California. 41 * All rights reserved. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * William Jolitz and Don Ahn. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. All advertising materials mentioning features or use of this software 55 * must display the following acknowledgement: 56 * This product includes software developed by the University of 57 * California, Berkeley and its contributors. 58 * 4. Neither the name of the University nor the names of its contributors 59 * may be used to endorse or promote products derived from this software 60 * without specific prior written permission. 61 * 62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 * SUCH DAMAGE. 73 * 74 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 75 */ 76 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/device.h> 80 #include <sys/kernel.h> 81 #include <sys/malloc.h> 82 #include <sys/ioctl.h> 83 84 #include <machine/bus.h> 85 #include <machine/config_hook.h> 86 87 #include <hpc/hpc/config_hook.h> 88 #include <hpcarm/dev/sed1356var.h> 89 #include <hpcarm/sa11x0/sa11x0_var.h> 90 #include <hpcarm/sa11x0/sa11x0_gpioreg.h> 91 #include <hpcarm/sa11x0/sa11x0_ppcreg.h> 92 #include <hpcarm/sa11x0/sa11x0_sspreg.h> 93 94 #include <dev/wscons/wsconsio.h> 95 #include <dev/wscons/wskbdvar.h> 96 #include <dev/wscons/wsksymdef.h> 97 #include <dev/wscons/wsksymvar.h> 98 99 extern const struct wscons_keydesc j720kbd_keydesctab[]; 100 101 struct j720ssp_softc { 102 struct device sc_dev; 103 104 bus_space_tag_t sc_iot; 105 bus_space_handle_t sc_gpioh; 106 bus_space_handle_t sc_ssph; 107 108 struct device *sc_wskbddev; 109 110 void *sc_si; 111 int sc_enabled; 112 }; 113 114 int j720kbd_intr(void *); 115 void j720kbdsoft(void *); 116 int j720lcdparam(void *, int, long, void *); 117 static void j720kbd_read(struct j720ssp_softc *, char *); 118 static int j720ssp_readwrite(struct j720ssp_softc *, int, int, int *); 119 120 int j720sspprobe(struct device *, struct cfdata *, void *); 121 void j720sspattach(struct device *, struct device *, void *); 122 123 int j720kbd_enable(void *, int); 124 void j720kbd_set_leds(void *, int); 125 int j720kbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 126 127 struct cfattach j720ssp_ca = { 128 sizeof(struct j720ssp_softc), j720sspprobe, j720sspattach, 129 }; 130 131 const struct wskbd_accessops j720kbd_accessops = { 132 j720kbd_enable, 133 j720kbd_set_leds, 134 j720kbd_ioctl, 135 }; 136 137 void j720kbd_cngetc(void *, u_int *, int *); 138 void j720kbd_cnpollc(void *, int); 139 void j720kbd_cnbell(void *, u_int, u_int, u_int); 140 141 const struct wskbd_consops j720kbd_consops = { 142 j720kbd_cngetc, 143 j720kbd_cnpollc, 144 j720kbd_cnbell, 145 }; 146 147 const struct wskbd_mapdata j720kbd_keymapdata = { 148 j720kbd_keydesctab, 149 #ifdef J720KBD_LAYOUT 150 J720KBD_LAYOUT, 151 #else 152 KB_US, 153 #endif 154 }; 155 156 static int j720ssp_powerstate = 1; 157 158 static struct j720ssp_softc j720kbdcons_sc; 159 160 #define DEBUG 161 #ifdef DEBUG 162 int j720sspwaitcnt; 163 int j720sspwaittime; 164 extern int gettick(); 165 #endif 166 167 #define BIT_INVERT(x) do { \ 168 (x) = ((((x) & 0xf0) >> 4) | (((x) & 0x0f) << 4)); \ 169 (x) = ((((x) & 0xcc) >> 2) | (((x) & 0x33) << 2)); \ 170 (x) = ((((x) & 0xaa) >> 1) | (((x) & 0x55) << 1)); \ 171 } while(0) 172 173 int 174 j720sspprobe(struct device *parent, struct cfdata *cf, void *aux) 175 { 176 return (1); 177 } 178 179 void 180 j720sspattach(struct device *parent, struct device *self, void *aux) 181 { 182 struct j720ssp_softc *sc = (void *)self; 183 struct sa11x0_softc *psc = (void *)parent; 184 struct sa11x0_attach_args *sa = aux; 185 struct wskbddev_attach_args a; 186 187 printf("\n"); 188 189 sc->sc_iot = psc->sc_iot; 190 sc->sc_gpioh = psc->sc_gpioh; 191 if (bus_space_map(sc->sc_iot, sa->sa_addr, sa->sa_size, 0, 192 &sc->sc_ssph)) { 193 printf("%s: unable to map SSP registers\n", 194 sc->sc_dev.dv_xname); 195 return; 196 } 197 198 sc->sc_si = softintr_establish(IPL_SOFTCLOCK, j720kbdsoft, sc); 199 200 sc->sc_enabled = 0; 201 202 a.console = 0; 203 204 a.keymap = &j720kbd_keymapdata; 205 206 a.accessops = &j720kbd_accessops; 207 a.accesscookie = sc; 208 209 /* 210 * Attach the wskbd, saving a handle to it. 211 * XXX XXX XXX 212 */ 213 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 214 215 #ifdef DEBUG 216 /* Zero the stat counters */ 217 j720sspwaitcnt = 0; 218 j720sspwaittime = 0; 219 #endif 220 221 /* LCD control is on the same bus */ 222 config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, 223 CONFIG_HOOK_SHARE, j720lcdparam, sc); 224 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS, 225 CONFIG_HOOK_SHARE, j720lcdparam, sc); 226 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS_MAX, 227 CONFIG_HOOK_SHARE, j720lcdparam, sc); 228 229 config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, 230 CONFIG_HOOK_SHARE, j720lcdparam, sc); 231 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST, 232 CONFIG_HOOK_SHARE, j720lcdparam, sc); 233 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST_MAX, 234 CONFIG_HOOK_SHARE, j720lcdparam, sc); 235 } 236 237 int 238 j720kbd_enable(void *v, int on) 239 { 240 struct j720ssp_softc *sc = v; 241 242 if (! sc->sc_enabled) { 243 sc->sc_enabled = 1; 244 245 sa11x0_intr_establish(0, 0, 1, IPL_BIO, j720kbd_intr, sc); 246 } 247 /* XXX */ 248 return (0); 249 } 250 251 void 252 j720kbd_set_leds(void *v, int on) 253 { 254 /* XXX */ 255 return; 256 } 257 258 int 259 j720kbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 260 { 261 return (-1); 262 } 263 264 int 265 j720kbd_intr(void *arg) 266 { 267 struct j720ssp_softc *sc = arg; 268 269 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_EDR, 1); 270 271 /* 272 * Schedule a soft interrupt to process at lower priority, 273 * as reading keycodes takes time. 274 * 275 * Interrupts are generated every 25-33ms as long as there 276 * are unprocessed key events. So it is not a good idea to 277 * use callout to call j720kbdsoft after some delay in hope 278 * of reducing interrupts. 279 */ 280 softintr_schedule(sc->sc_si); 281 282 return (1); 283 } 284 285 void 286 j720kbdsoft(void *arg) 287 { 288 struct j720ssp_softc *sc = arg; 289 int s, type, value; 290 char buf[9], *p; 291 292 j720kbd_read(sc, buf); 293 294 for(p = buf; *p; p++) { 295 type = *p & 0x80 ? WSCONS_EVENT_KEY_UP : 296 WSCONS_EVENT_KEY_DOWN; 297 value = *p & 0x7f; 298 s = spltty(); 299 wskbd_input(sc->sc_wskbddev, type, value); 300 splx(s); 301 if (type == WSCONS_EVENT_KEY_DOWN && 302 value == 0x7f) { 303 j720ssp_powerstate = ! j720ssp_powerstate; 304 config_hook_call(CONFIG_HOOK_POWERCONTROL, 305 CONFIG_HOOK_POWERCONTROL_LCDLIGHT, 306 (void *)j720ssp_powerstate); 307 } 308 } 309 310 return; 311 } 312 313 void 314 j720kbd_read(struct j720ssp_softc *sc, char *buf) 315 { 316 int data, count; 317 #ifdef DEBUG 318 u_int32_t oscr; 319 320 oscr = gettick(); 321 #endif 322 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000); 323 324 /* send scan keycode command */ 325 if (j720ssp_readwrite(sc, 1, 0x900, &data) < 0 || 326 data != 0x88) 327 goto out; 328 329 /* read numbers of scancode available */ 330 if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0) 331 goto out; 332 BIT_INVERT(data); 333 count = data; 334 335 for(; count; count--) { 336 if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0) 337 goto out; 338 BIT_INVERT(data); 339 *buf++ = data; 340 } 341 *buf = 0; 342 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 343 344 #ifdef DEBUG 345 oscr = (u_int32_t)gettick() - oscr; 346 j720sspwaitcnt++; 347 j720sspwaittime += oscr; 348 #endif 349 350 return; 351 352 out: 353 *buf = 0; 354 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 355 356 /* reset SSP */ 357 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x307); 358 delay(100); 359 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387); 360 printf("j720kbd_read: error %x\n", data); 361 } 362 363 int 364 j720lcdparam(void *ctx, int type, long id, void *msg) 365 { 366 struct j720ssp_softc *sc = ctx; 367 int i, s; 368 u_int32_t data[2], len; 369 370 switch (type) { 371 case CONFIG_HOOK_GET: 372 switch (id) { 373 case CONFIG_HOOK_BRIGHTNESS_MAX: 374 case CONFIG_HOOK_CONTRAST_MAX: 375 *(int *)msg = 255; 376 return 1; 377 case CONFIG_HOOK_BRIGHTNESS: 378 data[0] = 0x6b00; 379 data[1] = 0x8800; 380 len = 2; 381 break; 382 case CONFIG_HOOK_CONTRAST: 383 data[0] = 0x2b00; 384 data[1] = 0x8800; 385 len = 2; 386 break; 387 default: 388 return 0; 389 } 390 break; 391 392 case CONFIG_HOOK_SET: 393 switch (id) { 394 case CONFIG_HOOK_BRIGHTNESS: 395 if (*(int *)msg >= 0) { 396 data[0] = 0xcb00; 397 data[1] = *(int *)msg; 398 BIT_INVERT(data[1]); 399 data[1] <<= 8; 400 len = 2; 401 } else { 402 /* XXX hack */ 403 data[0] = 0xfb00; 404 len = 1; 405 } 406 break; 407 case CONFIG_HOOK_CONTRAST: 408 data[0] = 0x8b00; 409 data[1] = *(int *)msg; 410 BIT_INVERT(data[1]); 411 data[1] <<= 8; 412 len = 2; 413 break; 414 default: 415 return 0; 416 } 417 } 418 419 s = splbio(); 420 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000); 421 422 for (i = 0; i < len; i++) { 423 if (j720ssp_readwrite(sc, 1, data[i], &data[i]) < 0) 424 goto out; 425 } 426 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 427 splx(s); 428 429 if (type == CONFIG_HOOK_SET) 430 return 1; 431 432 BIT_INVERT(data[1]); 433 *(int *)msg = data[1]; 434 435 return 1; 436 437 out: 438 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 439 440 /* reset SSP */ 441 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x307); 442 delay(100); 443 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387); 444 splx(s); 445 return 0; 446 } 447 448 static int 449 j720ssp_readwrite(struct j720ssp_softc *sc, int drainfifo, int in, int *out) 450 { 451 int timo; 452 453 timo = 100000; 454 while(bus_space_read_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PLR) & 0x400) 455 if (--timo == 0) { 456 printf("timo0\n"); 457 return -1; 458 } 459 if (drainfifo) { 460 while(bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) & 461 SR_RNE) 462 bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR); 463 #if 1 464 delay(5000); 465 #endif 466 } 467 468 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_DR, in); 469 470 delay(5000); 471 timo = 100000; 472 while(! (bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) & SR_RNE)) 473 if (--timo == 0) { 474 printf("timo1\n"); 475 return -1; 476 } 477 478 *out = bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR); 479 480 return 0; 481 } 482 483 484 #if 0 485 int 486 j720kbd_cnattach() 487 { 488 /* XXX */ 489 } 490 #endif 491 492 /* ARGSUSED */ 493 void 494 j720kbd_cngetc(void *v, u_int *type, int *data) 495 { 496 char buf[9]; 497 498 for (;;) { 499 j720kbd_read(&j720kbdcons_sc, buf); 500 501 if (buf[0] != 0) { 502 /* XXX we are discarding buffer contents */ 503 *type = buf[0] & 0x80 ? WSCONS_EVENT_KEY_UP : 504 WSCONS_EVENT_KEY_DOWN; 505 *data = buf[0] & 0x7f; 506 return; 507 } 508 } 509 } 510 511 void 512 j720kbd_cnpollc(void *v, int on) 513 { 514 #if 0 515 /* XXX */ 516 struct j720kbd_internal *t = v; 517 518 pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on); 519 #endif 520 } 521 522 void 523 j720kbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 524 { 525 } 526 527 int 528 j720lcdpower(void *ctx, int type, long id, void *msg) 529 { 530 struct sed1356_softc *sc = ctx; 531 struct sa11x0_softc *psc = sc->sc_parent; 532 int val; 533 u_int32_t reg; 534 535 if (type != CONFIG_HOOK_POWERCONTROL || 536 id != CONFIG_HOOK_POWERCONTROL_LCDLIGHT) 537 return 0; 538 539 sed1356_init_brightness(sc, 0); 540 sed1356_init_contrast(sc, 0); 541 542 if (msg) { 543 bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 0); 544 545 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 546 reg |= 0x1; 547 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 548 delay(50000); 549 550 val = sc->sc_contrast; 551 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val); 552 delay(100000); 553 554 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 555 reg |= 0x4; 556 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 557 558 val = sc->sc_brightness; 559 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val); 560 561 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 562 reg |= 0x2; 563 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 564 } else { 565 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 566 reg &= ~0x2; 567 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 568 reg &= ~0x4; 569 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 570 delay(100000); 571 572 val = -2; 573 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val); 574 575 bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 1); 576 577 delay(100000); 578 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 579 reg &= ~0x1; 580 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 581 } 582 return 1; 583 } 584