xref: /netbsd/sys/arch/hpcarm/dev/j720ssp.c (revision bf9ec67e)
1 /* $NetBSD: j720ssp.c,v 1.5 2002/03/17 19:40:39 atatat 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 #include <machine/bootinfo.h>
87 
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 static int j720kbdcons_initstate = 0;
160 
161 #define DEBUG
162 #ifdef DEBUG
163 int j720sspwaitcnt;
164 int j720sspwaittime;
165 extern int gettick();
166 #endif
167 
168 #define BIT_INVERT(x)	do {					\
169 	(x) = ((((x) & 0xf0) >> 4) | (((x) & 0x0f) << 4));	\
170 	(x) = ((((x) & 0xcc) >> 2) | (((x) & 0x33) << 2));	\
171 	(x) = ((((x) & 0xaa) >> 1) | (((x) & 0x55) << 1));	\
172 	} while(0)
173 
174 int
175 j720sspprobe(struct device *parent, struct cfdata *cf, void *aux)
176 {
177 	return (1);
178 }
179 
180 void
181 j720sspattach(struct device *parent, struct device *self, void *aux)
182 {
183 	struct j720ssp_softc *sc = (void *)self;
184 	struct sa11x0_softc *psc = (void *)parent;
185 	struct sa11x0_attach_args *sa = aux;
186 	struct wskbddev_attach_args a;
187 
188 	printf("\n");
189 
190 	sc->sc_iot = psc->sc_iot;
191 	sc->sc_gpioh = psc->sc_gpioh;
192 	if (bus_space_map(sc->sc_iot, sa->sa_addr, sa->sa_size, 0,
193 			  &sc->sc_ssph)) {
194 		printf("%s: unable to map SSP registers\n",
195 		       sc->sc_dev.dv_xname);
196 		return;
197 	}
198 
199 	sc->sc_si = softintr_establish(IPL_SOFTCLOCK, j720kbdsoft, sc);
200 
201 	sc->sc_enabled = 0;
202 
203 	a.console = 0;
204 
205 	a.keymap = &j720kbd_keymapdata;
206 
207 	a.accessops = &j720kbd_accessops;
208 	a.accesscookie = sc;
209 
210 	/* Do console initialization */
211 	if (! (bootinfo->bi_cnuse & BI_CNUSE_SERIAL)) {
212 		j720kbdcons_sc = *sc;
213 		a.console = 1;
214 
215 		wskbd_cnattach(&j720kbd_consops, NULL, &j720kbd_keymapdata);
216 		j720kbdcons_initstate = 1;
217 	}
218 
219 	/*
220 	 * Attach the wskbd, saving a handle to it.
221 	 * XXX XXX XXX
222 	 */
223 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
224 
225 #ifdef DEBUG
226 	/* Zero the stat counters */
227 	j720sspwaitcnt = 0;
228 	j720sspwaittime = 0;
229 #endif
230 
231 	if (j720kbdcons_initstate == 1)
232 		j720kbd_enable(sc, 1);
233 
234 	/* LCD control is on the same bus */
235 	config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS,
236 		    CONFIG_HOOK_SHARE, j720lcdparam, sc);
237 	config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS,
238 		    CONFIG_HOOK_SHARE, j720lcdparam, sc);
239 	config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS_MAX,
240 		    CONFIG_HOOK_SHARE, j720lcdparam, sc);
241 
242 	config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST,
243 		    CONFIG_HOOK_SHARE, j720lcdparam, sc);
244 	config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST,
245 		    CONFIG_HOOK_SHARE, j720lcdparam, sc);
246 	config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST_MAX,
247 		    CONFIG_HOOK_SHARE, j720lcdparam, sc);
248 }
249 
250 int
251 j720kbd_enable(void *v, int on)
252 {
253 	struct j720ssp_softc *sc = v;
254 
255 	if (! sc->sc_enabled) {
256 		sc->sc_enabled = 1;
257 
258 		sa11x0_intr_establish(0, 0, 1, IPL_BIO, j720kbd_intr, sc);
259 	}
260 	/* XXX */
261 	return (0);
262 }
263 
264 void
265 j720kbd_set_leds(void *v, int on)
266 {
267 	/* XXX */
268 	return;
269 }
270 
271 int
272 j720kbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
273 {
274 	return (EPASSTHROUGH);
275 }
276 
277 int
278 j720kbd_intr(void *arg)
279 {
280 	struct j720ssp_softc *sc = arg;
281 
282 	bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_EDR, 1);
283 
284 	/*
285 	 * Schedule a soft interrupt to process at lower priority,
286 	 * as reading keycodes takes time.
287 	 *
288 	 * Interrupts are generated every 25-33ms as long as there
289 	 * are unprocessed key events.  So it is not a good idea to
290 	 * use callout to call j720kbdsoft after some delay in hope
291 	 * of reducing interrupts.
292 	 */
293 	softintr_schedule(sc->sc_si);
294 
295 	return (1);
296 }
297 
298 void
299 j720kbdsoft(void *arg)
300 {
301 	struct j720ssp_softc *sc = arg;
302 	int s, type, value;
303 	char buf[9], *p;
304 
305 	j720kbd_read(sc, buf);
306 
307 	for(p = buf; *p; p++) {
308 		type = *p & 0x80 ? WSCONS_EVENT_KEY_UP :
309 		    WSCONS_EVENT_KEY_DOWN;
310 		value = *p & 0x7f;
311 		s = spltty();
312 		wskbd_input(sc->sc_wskbddev, type, value);
313 		splx(s);
314 		if (type == WSCONS_EVENT_KEY_DOWN &&
315 		    value == 0x7f) {
316 			j720ssp_powerstate = ! j720ssp_powerstate;
317 			config_hook_call(CONFIG_HOOK_POWERCONTROL,
318 					 CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
319 					 (void *)j720ssp_powerstate);
320 		}
321 	}
322 
323 	return;
324 }
325 
326 void
327 j720kbd_read(struct j720ssp_softc *sc, char *buf)
328 {
329 	int data, count;
330 #ifdef DEBUG
331 	u_int32_t oscr;
332 
333 	oscr = gettick();
334 #endif
335 	bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000);
336 
337 	/* send scan keycode command */
338 	if (j720ssp_readwrite(sc, 1, 0x900, &data) < 0 ||
339 	    data != 0x88)
340 		goto out;
341 
342 	/* read numbers of scancode available */
343 	if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0)
344 		goto out;
345 	BIT_INVERT(data);
346 	count = data;
347 
348 	for(; count; count--) {
349 		if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0)
350 			goto out;
351 		BIT_INVERT(data);
352 		*buf++ = data;
353 	}
354 	*buf = 0;
355 	bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000);
356 
357 #ifdef DEBUG
358 	oscr = (u_int32_t)gettick() - oscr;
359 	j720sspwaitcnt++;
360 	j720sspwaittime += oscr;
361 #endif
362 
363 	return;
364 
365 out:
366 	*buf = 0;
367 	bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000);
368 
369 	/* reset SSP */
370 	bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x307);
371 	delay(100);
372 	bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387);
373 printf("j720kbd_read: error %x\n", data);
374 }
375 
376 int
377 j720lcdparam(void *ctx, int type, long id, void *msg)
378 {
379 	struct j720ssp_softc *sc = ctx;
380 	int i, s;
381 	u_int32_t data[2], len;
382 
383 	switch (type) {
384 	case CONFIG_HOOK_GET:
385 		switch (id) {
386 		case CONFIG_HOOK_BRIGHTNESS_MAX:
387 		case CONFIG_HOOK_CONTRAST_MAX:
388 			*(int *)msg = 255;
389 			return 1;
390 		case CONFIG_HOOK_BRIGHTNESS:
391 			data[0] = 0x6b00;
392 			data[1] = 0x8800;
393 			len = 2;
394 			break;
395 		case CONFIG_HOOK_CONTRAST:
396 			data[0] = 0x2b00;
397 			data[1] = 0x8800;
398 			len = 2;
399 			break;
400 		default:
401 			return 0;
402 		}
403 		break;
404 
405 	case CONFIG_HOOK_SET:
406 		switch (id) {
407 		case CONFIG_HOOK_BRIGHTNESS:
408 			if (*(int *)msg >= 0) {
409 				data[0] = 0xcb00;
410 				data[1] = *(int *)msg;
411 				BIT_INVERT(data[1]);
412 				data[1] <<= 8;
413 				len = 2;
414 			} else {
415 				/* XXX hack */
416 				data[0] = 0xfb00;
417 				len = 1;
418 			}
419 			break;
420 		case CONFIG_HOOK_CONTRAST:
421 			data[0] = 0x8b00;
422 			data[1] = *(int *)msg;
423 			BIT_INVERT(data[1]);
424 			data[1] <<= 8;
425 			len = 2;
426 			break;
427 		default:
428 			return 0;
429 		}
430 	}
431 
432 	s = splbio();
433 	bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000);
434 
435 	for (i = 0; i < len; i++) {
436 		if (j720ssp_readwrite(sc, 1, data[i], &data[i]) < 0)
437 			goto out;
438 	}
439 	bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000);
440 	splx(s);
441 
442 	if (type == CONFIG_HOOK_SET)
443 		return 1;
444 
445 	BIT_INVERT(data[1]);
446 	*(int *)msg = data[1];
447 
448 	return 1;
449 
450 out:
451 	bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000);
452 
453 	/* reset SSP */
454 	bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x307);
455 	delay(100);
456 	bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387);
457 	splx(s);
458 	return 0;
459 }
460 
461 static int
462 j720ssp_readwrite(struct j720ssp_softc *sc, int drainfifo, int in, int *out)
463 {
464 	int timo;
465 
466 	timo = 100000;
467 	while(bus_space_read_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PLR) & 0x400)
468 		if (--timo == 0) {
469 			printf("timo0\n");
470 			return -1;
471 		}
472 	if (drainfifo) {
473 		while(bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) &
474 		      SR_RNE)
475 			bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR);
476 #if 1
477 		delay(5000);
478 #endif
479 	}
480 
481 	bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_DR, in);
482 
483 	delay(5000);
484 	timo = 100000;
485 	while(! (bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) & SR_RNE))
486 		if (--timo == 0) {
487 			printf("timo1\n");
488 			return -1;
489 		}
490 
491 	*out = bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR);
492 
493 	return 0;
494 }
495 
496 #if 0
497 int
498 j720kbd_cnattach()
499 {
500 	/* XXX defer initialization till j720sspattach */
501 
502 	return (0);
503 }
504 #endif
505 
506 /* ARGSUSED */
507 void
508 j720kbd_cngetc(void *v, u_int *type, int *data)
509 {
510 	char buf[9];
511 
512 	if (j720kbdcons_initstate < 1)
513 		return;
514 
515 	for (;;) {
516 		j720kbd_read(&j720kbdcons_sc, buf);
517 
518 		if (buf[0] != 0) {
519 			/* XXX we are discarding buffer contents */
520 			*type = buf[0] & 0x80 ? WSCONS_EVENT_KEY_UP :
521 			    WSCONS_EVENT_KEY_DOWN;
522 			*data = buf[0] & 0x7f;
523 			return;
524 		}
525 	}
526 }
527 
528 void
529 j720kbd_cnpollc(void *v, int on)
530 {
531 #if 0
532 	/* XXX */
533 	struct j720kbd_internal *t = v;
534 
535 	pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
536 #endif
537 }
538 
539 void
540 j720kbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
541 {
542 }
543 
544 int
545 j720lcdpower(void *ctx, int type, long id, void *msg)
546 {
547 	struct sed1356_softc *sc = ctx;
548 	struct sa11x0_softc *psc = sc->sc_parent;
549 	int val;
550 	u_int32_t reg;
551 
552 	if (type != CONFIG_HOOK_POWERCONTROL ||
553 	    id != CONFIG_HOOK_POWERCONTROL_LCDLIGHT)
554 		return 0;
555 
556 	sed1356_init_brightness(sc, 0);
557 	sed1356_init_contrast(sc, 0);
558 
559 	if (msg) {
560 		bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 0);
561 
562 		reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
563 		reg |= 0x1;
564 		bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
565 		delay(50000);
566 
567 		val = sc->sc_contrast;
568 		config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
569 		delay(100000);
570 
571 		reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
572 		reg |= 0x4;
573 		bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
574 
575 		val = sc->sc_brightness;
576 		config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
577 
578 		reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
579 		reg |= 0x2;
580 		bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
581 	} else {
582 		reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
583 		reg &= ~0x2;
584 		bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
585 		reg &= ~0x4;
586 		bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
587 		delay(100000);
588 
589 		val = -2;
590 		config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
591 
592 		bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 1);
593 
594 		delay(100000);
595 		reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR);
596 		reg &= ~0x1;
597 		bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg);
598 	}
599 	return 1;
600 }
601