xref: /netbsd-src/sys/arch/macppc/dev/snapper.c (revision de1dfb1250df962f1ff3a011772cf58e605aed11)
1 /*	$NetBSD: snapper.c,v 1.1 2003/12/27 02:19:34 grant Exp $	*/
2 /*	Id: snapper.c,v 1.11 2002/10/31 17:42:13 tsubai Exp	*/
3 
4 /*-
5  * Copyright (c) 2002 Tsubai Masanari.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * Datasheet is available from
32  * http://www.ti.com/sc/docs/products/analog/tas3004.html
33  */
34 
35 #include <sys/param.h>
36 #include <sys/audioio.h>
37 #include <sys/device.h>
38 #include <sys/systm.h>
39 
40 #include <dev/auconv.h>
41 #include <dev/audio_if.h>
42 #include <dev/mulaw.h>
43 #include <dev/ofw/openfirm.h>
44 #include <macppc/dev/dbdma.h>
45 
46 #include <uvm/uvm_extern.h>
47 
48 #include <machine/autoconf.h>
49 #include <machine/pio.h>
50 
51 #ifdef SNAPPER_DEBUG
52 # define DPRINTF printf
53 #else
54 # define DPRINTF while (0) printf
55 #endif
56 
57 struct snapper_softc {
58 	struct device sc_dev;
59 	int sc_flags;
60 	int sc_node;
61 
62 	void (*sc_ointr)(void *);	/* dma completion intr handler */
63 	void *sc_oarg;			/* arg for sc_ointr() */
64 	int sc_opages;			/* # of output pages */
65 
66 	void (*sc_iintr)(void *);	/* dma completion intr handler */
67 	void *sc_iarg;			/* arg for sc_iintr() */
68 
69 	u_int sc_record_source;		/* recording source mask */
70 	u_int sc_output_mask;		/* output source mask */
71 
72 	u_char *sc_reg;
73 	struct device *sc_i2c;
74 
75 	u_int sc_vol_l;
76 	u_int sc_vol_r;
77 
78 	dbdma_regmap_t *sc_odma;
79 	dbdma_regmap_t *sc_idma;
80 	struct dbdma_command sc_odmacmd[20];
81 	struct dbdma_command sc_idmacmd[20];
82 };
83 
84 int snapper_match(struct device *, struct cfdata *, void *);
85 void snapper_attach(struct device *, struct device *, void *);
86 void snapper_defer(struct device *);
87 int snapper_intr(void *);
88 int snapper_open(void *, int);
89 void snapper_close(void *);
90 int snapper_query_encoding(void *, struct audio_encoding *);
91 int snapper_set_params(void *, int, int, struct audio_params *,
92     struct audio_params *);
93 int snapper_round_blocksize(void *, int);
94 int snapper_halt_output(void *);
95 int snapper_halt_input(void *);
96 int snapper_getdev(void *, struct audio_device *);
97 int snapper_set_port(void *, mixer_ctrl_t *);
98 int snapper_get_port(void *, mixer_ctrl_t *);
99 int snapper_query_devinfo(void *, mixer_devinfo_t *);
100 size_t snapper_round_buffersize(void *, int, size_t);
101 paddr_t snapper_mappage(void *, void *, off_t, int);
102 int snapper_get_props(void *);
103 int snapper_trigger_output(void *, void *, void *, int, void (*)(void *),
104     void *, struct audio_params *);
105 int snapper_trigger_input(void *, void *, void *, int, void (*)(void *),
106     void *, struct audio_params *);
107 void snapper_set_volume(struct snapper_softc *, int, int);
108 int snapper_set_rate(struct snapper_softc *, int);
109 
110 int tas3004_write(struct snapper_softc *, u_int, const void *);
111 static int gpio_read(char *);
112 static void gpio_write(char *, int);
113 void snapper_mute_speaker(struct snapper_softc *, int);
114 void snapper_mute_headphone(struct snapper_softc *, int);
115 int snapper_cint(void *);
116 int tas3004_init(struct snapper_softc *);
117 void snapper_init(struct snapper_softc *, int);
118 
119 static void mono16_to_stereo16(void *, u_char *, int);
120 static void swap_bytes_mono16_to_stereo16(void *, u_char *, int);
121 
122 /* XXX */
123 int ki2c_setmode(struct device *, int);
124 int ki2c_write(struct device *, int, int, const void *, int);
125 void ki2c_writereg(struct device *, int, u_int);
126 
127 
128 struct cfattach snapper_ca = {
129 	"snapper", {}, sizeof(struct snapper_softc),
130 	snapper_match, snapper_attach
131 };
132 
133 struct audio_hw_if snapper_hw_if = {
134 	snapper_open,
135 	snapper_close,
136 	NULL,
137 	snapper_query_encoding,
138 	snapper_set_params,
139 	snapper_round_blocksize,
140 	NULL,
141 	NULL,
142 	NULL,
143 	NULL,
144 	NULL,
145 	snapper_halt_output,
146 	snapper_halt_input,
147 	NULL,
148 	snapper_getdev,
149 	NULL,
150 	snapper_set_port,
151 	snapper_get_port,
152 	snapper_query_devinfo,
153 	NULL,
154 	NULL,
155 	snapper_round_buffersize,
156 	snapper_mappage,
157 	snapper_get_props,
158 	snapper_trigger_output,
159 	snapper_trigger_input,
160 	NULL
161 };
162 
163 struct audio_device snapper_device = {
164 	"SNAPPER",
165 	"",
166 	"snapper"
167 };
168 
169 static u_char *amp_mute;
170 static u_char *headphone_mute;
171 static u_char *audio_hw_reset;
172 static u_char *headphone_detect;
173 static int headphone_detect_active;
174 
175 
176 /* I2S registers */
177 #define I2S_INT		0x00
178 #define I2S_FORMAT	0x10
179 #define I2S_FRAMECOUNT	0x40
180 #define I2S_FRAMEMATCH	0x50
181 #define I2S_WORDSIZE	0x60
182 
183 /* TAS3004 registers */
184 #define DEQ_MCR1	0x01	/* Main control register 1 (1byte) */
185 #define DEQ_DRC		0x02	/* Dynamic range compression (6bytes?) */
186 #define DEQ_VOLUME	0x04	/* Volume (6bytes) */
187 #define DEQ_TREBLE	0x05	/* Treble control (1byte) */
188 #define DEQ_BASS	0x06	/* Bass control (1byte) */
189 #define DEQ_MIXER_L	0x07	/* Mixer left gain (9bytes) */
190 #define DEQ_MIXER_R	0x08	/* Mixer right gain (9bytes) */
191 #define DEQ_LB0		0x0a	/* Left biquad 0 (15bytes) */
192 #define DEQ_LB1		0x0b	/* Left biquad 1 (15bytes) */
193 #define DEQ_LB2		0x0c	/* Left biquad 2 (15bytes) */
194 #define DEQ_LB3		0x0d	/* Left biquad 3 (15bytes) */
195 #define DEQ_LB4		0x0e	/* Left biquad 4 (15bytes) */
196 #define DEQ_LB5		0x0f	/* Left biquad 5 (15bytes) */
197 #define DEQ_LB6		0x10	/* Left biquad 6 (15bytes) */
198 #define DEQ_RB0		0x13	/* Right biquad 0 (15bytes) */
199 #define DEQ_RB1		0x14	/* Right biquad 1 (15bytes) */
200 #define DEQ_RB2		0x15	/* Right biquad 2 (15bytes) */
201 #define DEQ_RB3		0x16	/* Right biquad 3 (15bytes) */
202 #define DEQ_RB4		0x17	/* Right biquad 4 (15bytes) */
203 #define DEQ_RB5		0x18	/* Right biquad 5 (15bytes) */
204 #define DEQ_RB6		0x19	/* Right biquad 6 (15bytes) */
205 #define DEQ_LLB		0x21	/* Left loudness biquad (15bytes) */
206 #define DEQ_RLB		0x22	/* Right loudness biquad (15bytes) */
207 #define DEQ_LLB_GAIN	0x23	/* Left loudness biquad gain (3bytes) */
208 #define DEQ_RLB_GAIN	0x24	/* Right loudness biquad gain (3bytes) */
209 #define DEQ_ACR		0x40	/* Analog control register (1byte) */
210 #define DEQ_MCR2	0x43	/* Main control register 2 (1byte) */
211 
212 #define DEQ_MCR1_FL	0x80	/* Fast load */
213 #define DEQ_MCR1_SC	0x40	/* SCLK frequency */
214 #define  DEQ_MCR1_SC_32	0x00	/*  32fs */
215 #define  DEQ_MCR1_SC_64	0x40	/*  64fs */
216 #define DEQ_MCR1_SM	0x30	/* Output serial port mode */
217 #define  DEQ_MCR1_SM_L	0x00	/*  Left justified */
218 #define  DEQ_MCR1_SM_R	0x10	/*  Right justified */
219 #define  DEQ_MCR1_SM_I2S 0x20	/*  I2S */
220 #define DEQ_MCR1_W	0x03	/* Serial port word length */
221 #define  DEQ_MCR1_W_16	0x00	/*  16 bit */
222 #define  DEQ_MCR1_W_18	0x01	/*  18 bit */
223 #define  DEQ_MCR1_W_20	0x02	/*  20 bit */
224 
225 #define DEQ_MCR2_DL	0x80	/* Download */
226 #define DEQ_MCR2_AP	0x02	/* All pass mode */
227 
228 #define DEQ_ACR_ADM	0x80	/* ADC output mode */
229 #define DEQ_ACR_LRB	0x40	/* Select B input */
230 #define DEQ_ACR_DM	0x0c	/* De-emphasis control */
231 #define  DEQ_ACR_DM_OFF	0x00	/*  off */
232 #define  DEQ_ACR_DM_48	0x04	/*  fs = 48kHz */
233 #define  DEQ_ACR_DM_44	0x08	/*  fs = 44.1kHz */
234 #define DEQ_ACR_INP	0x02	/* Analog input select */
235 #define  DEQ_ACR_INP_A	0x00	/*  A */
236 #define  DEQ_ACR_INP_B	0x02	/*  B */
237 #define DEQ_ACR_APD	0x01	/* Analog power down */
238 
239 struct tas3004_reg {
240 	u_char MCR1[1];
241 	u_char DRC[6];
242 	u_char VOLUME[6];
243 	u_char TREBLE[1];
244 	u_char BASS[1];
245 	u_char MIXER_L[9];
246 	u_char MIXER_R[9];
247 	u_char LB0[15];
248 	u_char LB1[15];
249 	u_char LB2[15];
250 	u_char LB3[15];
251 	u_char LB4[15];
252 	u_char LB5[15];
253 	u_char LB6[15];
254 	u_char RB0[15];
255 	u_char RB1[15];
256 	u_char RB2[15];
257 	u_char RB3[15];
258 	u_char RB4[15];
259 	u_char RB5[15];
260 	u_char RB6[15];
261 	u_char LLB[15];
262 	u_char RLB[15];
263 	u_char LLB_GAIN[3];
264 	u_char RLB_GAIN[3];
265 	u_char ACR[1];
266 	u_char MCR2[1];
267 };
268 
269 #define GPIO_OUTSEL	0xf0	/* Output select */
270 		/*	0x00	GPIO bit0 is output
271 			0x10	media-bay power
272 			0x20	reserved
273 			0x30	MPIC */
274 
275 #define GPIO_ALTOE	0x08	/* Alternate output enable */
276 		/*	0x00	Use DDR
277 			0x08	Use output select */
278 
279 #define GPIO_DDR	0x04	/* Data direction */
280 #define GPIO_DDR_OUTPUT	0x04	/* Output */
281 #define GPIO_DDR_INPUT	0x00	/* Input */
282 
283 #define GPIO_LEVEL	0x02	/* Pin level (RO) */
284 
285 #define	GPIO_DATA	0x01	/* Data */
286 
287 int
288 snapper_match(parent, match, aux)
289 	struct device *parent;
290 	struct cfdata *match;
291 	void *aux;
292 {
293 	struct confargs *ca = aux;
294 	int soundbus, soundchip;
295 	char compat[32];
296 
297 	if (strcmp(ca->ca_name, "i2s") != 0)
298 		return 0;
299 
300 	if ((soundbus = OF_child(ca->ca_node)) == 0 ||
301 	    (soundchip = OF_child(soundbus)) == 0)
302 		return 0;
303 
304 	bzero(compat, sizeof compat);
305 	OF_getprop(soundchip, "compatible", compat, sizeof compat);
306 
307 	if (strcmp(compat, "snapper") != 0)
308 		return 0;
309 
310 	return 1;
311 }
312 
313 void
314 snapper_attach(parent, self, aux)
315 	struct device *parent;
316 	struct device *self;
317 	void *aux;
318 {
319 	struct snapper_softc *sc = (struct snapper_softc *)self;
320 	struct confargs *ca = aux;
321 	int cirq, oirq, iirq, cirq_type, oirq_type, iirq_type;
322 	int soundbus, intr[6];
323 
324 #ifdef DIAGNOSTIC
325 	if ((vaddr_t)sc->sc_odmacmd & 0x0f) {
326 		printf(": bad dbdma alignment\n");
327 		return;
328 	}
329 #endif
330 
331 	ca->ca_reg[0] += ca->ca_baseaddr;
332 	ca->ca_reg[2] += ca->ca_baseaddr;
333 	ca->ca_reg[4] += ca->ca_baseaddr;
334 
335 	sc->sc_node = ca->ca_node;
336 	sc->sc_reg = (void *)ca->ca_reg[0];
337 	sc->sc_odma = (void *)ca->ca_reg[2];
338 	sc->sc_idma = (void *)ca->ca_reg[4];
339 
340 	soundbus = OF_child(ca->ca_node);
341 	OF_getprop(soundbus, "interrupts", intr, sizeof intr);
342 	cirq = intr[0];
343 	oirq = intr[2];
344 	iirq = intr[4];
345 	cirq_type = intr[1] ? IST_LEVEL : IST_EDGE;
346 	oirq_type = intr[3] ? IST_LEVEL : IST_EDGE;
347 	iirq_type = intr[5] ? IST_LEVEL : IST_EDGE;
348 
349 	/* intr_establish(cirq, cirq_type, IPL_AUDIO, snapper_intr, sc); */
350 	intr_establish(oirq, oirq_type, IPL_AUDIO, snapper_intr, sc);
351 	/* intr_establish(iirq, iirq_type, IPL_AUDIO, snapper_intr, sc); */
352 
353 	printf("%s: irq %d,%d,%d\n", sc->sc_dev.dv_xname, cirq, oirq, iirq);
354 
355 	config_interrupts(self, snapper_defer);
356 }
357 
358 void
359 snapper_defer(struct device *dev)
360 {
361 	struct snapper_softc *sc = (struct snapper_softc *)dev;
362 	struct device *dv;
363 
364 	for (dv = alldevs.tqh_first; dv; dv=dv->dv_list.tqe_next)
365 		if (strncmp(dv->dv_xname, "ki2c", 4) == 0 &&
366 		    strncmp(dv->dv_parent->dv_xname, "obio", 4) == 0)
367 			sc->sc_i2c = dv;
368 	if (sc->sc_i2c == NULL) {
369 		printf("%s: unable to find i2c\n", sc->sc_dev.dv_xname);
370 		return;
371 	}
372 
373 	/* XXX If i2c was failed to attach, what should we do? */
374 
375 	audio_attach_mi(&snapper_hw_if, sc, &sc->sc_dev);
376 
377 	/* ki2c_setmode(sc->sc_i2c, I2C_STDSUBMODE); */
378 	snapper_init(sc, sc->sc_node);
379 }
380 
381 int
382 snapper_intr(v)
383 	void *v;
384 {
385 	struct snapper_softc *sc = v;
386 	struct dbdma_command *cmd = sc->sc_odmacmd;
387 	int count = sc->sc_opages;
388 	int status;
389 
390 	/* Fill used buffer(s). */
391 	while (count-- > 0) {
392 		if ((dbdma_ld16(&cmd->d_command) & 0x30) == 0x30) {
393 			status = dbdma_ld16(&cmd->d_status);
394 			cmd->d_status = 0;
395 			if (status)	/* status == 0x8400 */
396 				if (sc->sc_ointr)
397 					(*sc->sc_ointr)(sc->sc_oarg);
398 		}
399 		cmd++;
400 	}
401 
402 	return 1;
403 }
404 
405 int
406 snapper_open(h, flags)
407 	void *h;
408 	int flags;
409 {
410 	return 0;
411 }
412 
413 /*
414  * Close function is called at splaudio().
415  */
416 void
417 snapper_close(h)
418 	void *h;
419 {
420 	struct snapper_softc *sc = h;
421 
422 	snapper_halt_output(sc);
423 	snapper_halt_input(sc);
424 
425 	sc->sc_ointr = 0;
426 	sc->sc_iintr = 0;
427 }
428 
429 int
430 snapper_query_encoding(h, ae)
431 	void *h;
432 	struct audio_encoding *ae;
433 {
434 	ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
435 
436 	switch (ae->index) {
437 	case 0:
438 		strcpy(ae->name, AudioEslinear);
439 		ae->encoding = AUDIO_ENCODING_SLINEAR;
440 		ae->precision = 16;
441 		ae->flags = 0;
442 		return 0;
443 	case 1:
444 		strcpy(ae->name, AudioEslinear_be);
445 		ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
446 		ae->precision = 16;
447 		ae->flags = 0;
448 		return 0;
449 	case 2:
450 		strcpy(ae->name, AudioEslinear_le);
451 		ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
452 		ae->precision = 16;
453 		return 0;
454 	case 3:
455 		strcpy(ae->name, AudioEulinear_be);
456 		ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
457 		ae->precision = 16;
458 		return 0;
459 	case 4:
460 		strcpy(ae->name, AudioEulinear_le);
461 		ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
462 		ae->precision = 16;
463 		return 0;
464 	case 5:
465 		strcpy(ae->name, AudioEmulaw);
466 		ae->encoding = AUDIO_ENCODING_ULAW;
467 		ae->precision = 8;
468 		return 0;
469 	case 6:
470 		strcpy(ae->name, AudioEalaw);
471 		ae->encoding = AUDIO_ENCODING_ALAW;
472 		ae->precision = 8;
473 		return 0;
474 	default:
475 		return EINVAL;
476 	}
477 }
478 
479 static void
480 mono16_to_stereo16(v, p, cc)
481 	void *v;
482 	u_char *p;
483 	int cc;
484 {
485 	int x;
486 	int16_t *src, *dst;
487 
488 	src = (void *)(p + cc);
489 	dst = (void *)(p + cc * 2);
490 	while (cc > 0) {
491 		x = *--src;
492 		*--dst = x;
493 		*--dst = x;
494 		cc -= 2;
495 	}
496 }
497 
498 static void
499 swap_bytes_mono16_to_stereo16(v, p, cc)
500 	void *v;
501 	u_char *p;
502 	int cc;
503 {
504 	swap_bytes(v, p, cc);
505 	mono16_to_stereo16(v, p, cc);
506 }
507 
508 int
509 snapper_set_params(h, setmode, usemode, play, rec)
510 	void *h;
511 	int setmode, usemode;
512 	struct audio_params *play, *rec;
513 {
514 	struct snapper_softc *sc = h;
515 	struct audio_params *p;
516 	int mode, rate;
517 
518 	p = NULL;
519 
520 	/*
521 	 * This device only has one clock, so make the sample rates match.
522 	 */
523 	if (play->sample_rate != rec->sample_rate &&
524 	    usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
525 		if (setmode == AUMODE_PLAY) {
526 			rec->sample_rate = play->sample_rate;
527 			setmode |= AUMODE_RECORD;
528 		} else if (setmode == AUMODE_RECORD) {
529 			play->sample_rate = rec->sample_rate;
530 			setmode |= AUMODE_PLAY;
531 		} else
532 			return EINVAL;
533 	}
534 
535 	for (mode = AUMODE_RECORD; mode != -1;
536 	     mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
537 		if ((setmode & mode) == 0)
538 			continue;
539 
540 		p = mode == AUMODE_PLAY ? play : rec;
541 
542 		if (p->sample_rate < 4000 || p->sample_rate > 50000 ||
543 		    (p->precision != 8 && p->precision != 16) ||
544 		    (p->channels != 1 && p->channels != 2))
545 			return EINVAL;
546 
547 		p->factor = 1;
548 		p->sw_code = 0;
549 
550 		switch (p->encoding) {
551 
552 		case AUDIO_ENCODING_SLINEAR_LE:
553 			if (p->channels == 2 && p->precision == 16) {
554 				p->sw_code = swap_bytes;
555 				break;
556 			}
557 			if (p->channels == 1 && p->precision == 16) {
558 				p->factor = 2;
559 				p->sw_code = swap_bytes_mono16_to_stereo16;
560 				break;
561 			}
562 			return EINVAL;
563 		case AUDIO_ENCODING_SLINEAR_BE:
564 			if (p->channels == 1 && p->precision == 16) {
565 				p->factor = 2;
566 				p->sw_code = mono16_to_stereo16;
567 				break;
568 			}
569 			if (p->channels == 2 && p->precision == 16)
570 				break;
571 
572 			return EINVAL;
573 
574 		case AUDIO_ENCODING_ULINEAR_LE:
575 			if (p->channels == 2 && p->precision == 16) {
576 				p->sw_code = swap_bytes_change_sign16_be;
577 				break;
578 			}
579 			return EINVAL;
580 
581 		case AUDIO_ENCODING_ULINEAR_BE:
582 			if (p->channels == 2 && p->precision == 16) {
583 				p->sw_code = change_sign16_be;
584 				break;
585 			}
586 			return EINVAL;
587 
588 		case AUDIO_ENCODING_ULAW:
589 			if (mode == AUMODE_PLAY) {
590 				p->factor = 2;
591 				p->sw_code = mulaw_to_slinear16_be;
592 				break;
593 			} else
594 				break;		/* XXX */
595 
596 			return EINVAL;
597 
598 		case AUDIO_ENCODING_ALAW:
599 			if (mode == AUMODE_PLAY) {
600 				p->factor = 2;
601 				p->sw_code = alaw_to_slinear16_be;
602 				break;
603 			}
604 			return EINVAL;
605 
606 		default:
607 			return EINVAL;
608 		}
609 	}
610 
611 	/* Set the speed */
612 	rate = p->sample_rate;
613 
614 	if (snapper_set_rate(sc, rate))
615 		return EINVAL;
616 
617 	return 0;
618 }
619 
620 int
621 snapper_round_blocksize(h, size)
622 	void *h;
623 	int size;
624 {
625 	if (size < NBPG)
626 		size = NBPG;
627 	return size & ~PGOFSET;
628 }
629 
630 int
631 snapper_halt_output(h)
632 	void *h;
633 {
634 	struct snapper_softc *sc = h;
635 
636 	dbdma_stop(sc->sc_odma);
637 	dbdma_reset(sc->sc_odma);
638 	return 0;
639 }
640 
641 int
642 snapper_halt_input(h)
643 	void *h;
644 {
645 	struct snapper_softc *sc = h;
646 
647 	dbdma_stop(sc->sc_idma);
648 	dbdma_reset(sc->sc_idma);
649 	return 0;
650 }
651 
652 int
653 snapper_getdev(h, retp)
654 	void *h;
655 	struct audio_device *retp;
656 {
657 	*retp = snapper_device;
658 	return 0;
659 }
660 
661 enum {
662 	SNAPPER_MONITOR_CLASS,
663 	SNAPPER_OUTPUT_CLASS,
664 	SNAPPER_RECORD_CLASS,
665 	SNAPPER_OUTPUT_SELECT,
666 	SNAPPER_VOL_OUTPUT,
667 	SNAPPER_INPUT_SELECT,
668 	SNAPPER_VOL_INPUT,
669 	SNAPPER_ENUM_LAST
670 };
671 
672 int
673 snapper_set_port(h, mc)
674 	void *h;
675 	mixer_ctrl_t *mc;
676 {
677 	struct snapper_softc *sc = h;
678 	int l, r;
679 
680 	DPRINTF("snapper_set_port dev = %d, type = %d\n", mc->dev, mc->type);
681 
682 	l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
683 	r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
684 
685 	switch (mc->dev) {
686 	case SNAPPER_OUTPUT_SELECT:
687 		/* No change necessary? */
688 		if (mc->un.mask == sc->sc_output_mask)
689 			return 0;
690 
691 		snapper_mute_speaker(sc, 1);
692 		snapper_mute_headphone(sc, 1);
693 		if (mc->un.mask & 1 << 0)
694 			snapper_mute_speaker(sc, 0);
695 		if (mc->un.mask & 1 << 1)
696 			snapper_mute_headphone(sc, 0);
697 
698 		sc->sc_output_mask = mc->un.mask;
699 		return 0;
700 
701 	case SNAPPER_VOL_OUTPUT:
702 		snapper_set_volume(sc, l, r);
703 		return 0;
704 
705 	case SNAPPER_INPUT_SELECT:
706 		/* no change necessary? */
707 		if (mc->un.mask == sc->sc_record_source)
708 			return 0;
709 		switch (mc->un.mask) {
710 		case 1 << 0: /* CD */
711 		case 1 << 1: /* microphone */
712 		case 1 << 2: /* line in */
713 			/* XXX TO BE DONE */
714 			break;
715 		default: /* invalid argument */
716 			return EINVAL;
717 		}
718 		sc->sc_record_source = mc->un.mask;
719 		return 0;
720 
721 	case SNAPPER_VOL_INPUT:
722 		/* XXX TO BE DONE */
723 		return 0;
724 	}
725 
726 	return ENXIO;
727 }
728 
729 int
730 snapper_get_port(h, mc)
731 	void *h;
732 	mixer_ctrl_t *mc;
733 {
734 	struct snapper_softc *sc = h;
735 
736 	DPRINTF("snapper_get_port dev = %d, type = %d\n", mc->dev, mc->type);
737 
738 	switch (mc->dev) {
739 	case SNAPPER_OUTPUT_SELECT:
740 		mc->un.mask = sc->sc_output_mask;
741 		return 0;
742 
743 	case SNAPPER_VOL_OUTPUT:
744 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_vol_l;
745 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = sc->sc_vol_r;
746 		return 0;
747 
748 	case SNAPPER_INPUT_SELECT:
749 		mc->un.mask = sc->sc_record_source;
750 		return 0;
751 
752 	case SNAPPER_VOL_INPUT:
753 		/* XXX TO BE DONE */
754 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 0;
755 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 0;
756 		return 0;
757 
758 	default:
759 		return ENXIO;
760 	}
761 
762 	return 0;
763 }
764 
765 int
766 snapper_query_devinfo(h, dip)
767 	void *h;
768 	mixer_devinfo_t *dip;
769 {
770 	switch (dip->index) {
771 
772 	case SNAPPER_OUTPUT_SELECT:
773 		dip->mixer_class = SNAPPER_MONITOR_CLASS;
774 		strcpy(dip->label.name, AudioNoutput);
775 		dip->type = AUDIO_MIXER_SET;
776 		dip->prev = dip->next = AUDIO_MIXER_LAST;
777 		dip->un.s.num_mem = 2;
778 		strcpy(dip->un.s.member[0].label.name, AudioNspeaker);
779 		dip->un.s.member[0].mask = 1 << 0;
780 		strcpy(dip->un.s.member[1].label.name, AudioNheadphone);
781 		dip->un.s.member[1].mask = 1 << 1;
782 		return 0;
783 
784 	case SNAPPER_VOL_OUTPUT:
785 		dip->mixer_class = SNAPPER_MONITOR_CLASS;
786 		strcpy(dip->label.name, AudioNmaster);
787 		dip->type = AUDIO_MIXER_VALUE;
788 		dip->prev = dip->next = AUDIO_MIXER_LAST;
789 		dip->un.v.num_channels = 2;
790 		strcpy(dip->un.v.units.name, AudioNvolume);
791 		return 0;
792 
793 	case SNAPPER_INPUT_SELECT:
794 		dip->mixer_class = SNAPPER_RECORD_CLASS;
795 		strcpy(dip->label.name, AudioNsource);
796 		dip->type = AUDIO_MIXER_SET;
797 		dip->prev = dip->next = AUDIO_MIXER_LAST;
798 		dip->un.s.num_mem = 3;
799 		strcpy(dip->un.s.member[0].label.name, AudioNcd);
800 		dip->un.s.member[0].mask = 1 << 0;
801 		strcpy(dip->un.s.member[1].label.name, AudioNmicrophone);
802 		dip->un.s.member[1].mask = 1 << 1;
803 		strcpy(dip->un.s.member[2].label.name, AudioNline);
804 		dip->un.s.member[2].mask = 1 << 2;
805 		return 0;
806 
807 	case SNAPPER_VOL_INPUT:
808 		dip->mixer_class = SNAPPER_RECORD_CLASS;
809 		strcpy(dip->label.name, AudioNrecord);
810 		dip->type = AUDIO_MIXER_VALUE;
811 		dip->prev = dip->next = AUDIO_MIXER_LAST;
812 		dip->un.v.num_channels = 2;
813 		strcpy(dip->un.v.units.name, AudioNvolume);
814 		return 0;
815 
816 	case SNAPPER_MONITOR_CLASS:
817 		dip->mixer_class = SNAPPER_MONITOR_CLASS;
818 		strcpy(dip->label.name, AudioCmonitor);
819 		dip->type = AUDIO_MIXER_CLASS;
820 		dip->next = dip->prev = AUDIO_MIXER_LAST;
821 		return 0;
822 
823 	case SNAPPER_OUTPUT_CLASS:
824 		dip->mixer_class = SNAPPER_OUTPUT_CLASS;
825 		strcpy(dip->label.name, AudioCoutputs);
826 		dip->type = AUDIO_MIXER_CLASS;
827 		dip->next = dip->prev = AUDIO_MIXER_LAST;
828 		return 0;
829 
830 	case SNAPPER_RECORD_CLASS:
831 		dip->mixer_class = SNAPPER_RECORD_CLASS;
832 		strcpy(dip->label.name, AudioCrecord);
833 		dip->type = AUDIO_MIXER_CLASS;
834 		dip->next = dip->prev = AUDIO_MIXER_LAST;
835 		return 0;
836 	}
837 
838 	return ENXIO;
839 }
840 
841 size_t
842 snapper_round_buffersize(h, dir, size)
843 	void *h;
844 	int dir;
845 	size_t size;
846 {
847 	if (size > 65536)
848 		size = 65536;
849 	return size;
850 }
851 
852 paddr_t
853 snapper_mappage(h, mem, off, prot)
854 	void *h;
855 	void *mem;
856 	off_t off;
857 	int prot;
858 {
859 	if (off < 0)
860 		return -1;
861 	return -1;	/* XXX */
862 }
863 
864 int
865 snapper_get_props(h)
866 	void *h;
867 {
868 	return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */;
869 }
870 
871 int
872 snapper_trigger_output(h, start, end, bsize, intr, arg, param)
873 	void *h;
874 	void *start, *end;
875 	int bsize;
876 	void (*intr)(void *);
877 	void *arg;
878 	struct audio_params *param;
879 {
880 	struct snapper_softc *sc = h;
881 	struct dbdma_command *cmd = sc->sc_odmacmd;
882 	vaddr_t va;
883 	int i, len, intmode;
884 
885 	DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize);
886 
887 	sc->sc_ointr = intr;
888 	sc->sc_oarg = arg;
889 	sc->sc_opages = ((char *)end - (char *)start) / NBPG;
890 
891 #ifdef DIAGNOSTIC
892 	if (sc->sc_opages > 16)
893 		panic("snapper_trigger_output");
894 #endif
895 
896 	va = (vaddr_t)start;
897 	len = 0;
898 	for (i = sc->sc_opages; i > 0; i--) {
899 		len += NBPG;
900 		if (len < bsize)
901 			intmode = 0;
902 		else {
903 			len = 0;
904 			intmode = DBDMA_INT_ALWAYS;
905 		}
906 
907 		DBDMA_BUILD(cmd, DBDMA_CMD_OUT_MORE, 0, NBPG, vtophys(va), intmode, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
908 		cmd++;
909 		va += NBPG;
910 	}
911 
912 	DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0,
913 	    0/*vtophys((vaddr_t)sc->sc_odmacmd)*/, 0, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
914 
915 	dbdma_st32(&cmd->d_cmddep, vtophys((vaddr_t)sc->sc_odmacmd));
916 
917 	dbdma_start(sc->sc_odma, sc->sc_odmacmd);
918 
919 	return 0;
920 }
921 
922 int
923 snapper_trigger_input(h, start, end, bsize, intr, arg, param)
924 	void *h;
925 	void *start, *end;
926 	int bsize;
927 	void (*intr)(void *);
928 	void *arg;
929 	struct audio_params *param;
930 {
931 	printf("snapper_trigger_input called\n");
932 
933 	return 1;
934 }
935 
936 void
937 snapper_set_volume(sc, left, right)
938 	struct snapper_softc *sc;
939 	int left, right;
940 {
941 	u_char vol[6];
942 
943 	sc->sc_vol_l = left;
944 	sc->sc_vol_r = right;
945 
946 	left <<= 8;	/* XXX for now */
947 	right <<= 8;
948 
949 	vol[0] = left >> 16;
950 	vol[1] = left >> 8;
951 	vol[2] = left;
952 	vol[3] = right >> 16;
953 	vol[4] = right >> 8;
954 	vol[5] = right;
955 
956 	tas3004_write(sc, DEQ_VOLUME, vol);
957 }
958 
959 #define CLKSRC_49MHz	0x80000000	/* Use 49152000Hz Osc. */
960 #define CLKSRC_45MHz	0x40000000	/* Use 45158400Hz Osc. */
961 #define CLKSRC_18MHz	0x00000000	/* Use 18432000Hz Osc. */
962 #define MCLK_DIV	0x1f000000	/* MCLK = SRC / DIV */
963 #define  MCLK_DIV1	0x14000000	/*  MCLK = SRC */
964 #define  MCLK_DIV3	0x13000000	/*  MCLK = SRC / 3 */
965 #define  MCLK_DIV5	0x12000000	/*  MCLK = SRC / 5 */
966 #define SCLK_DIV	0x00f00000	/* SCLK = MCLK / DIV */
967 #define  SCLK_DIV1	0x00800000
968 #define  SCLK_DIV3	0x00900000
969 #define SCLK_MASTER	0x00080000	/* Master mode */
970 #define SCLK_SLAVE	0x00000000	/* Slave mode */
971 #define SERIAL_FORMAT	0x00070000
972 #define  SERIAL_SONY	0x00000000
973 #define  SERIAL_64x	0x00010000
974 #define  SERIAL_32x	0x00020000
975 #define  SERIAL_DAV	0x00040000
976 #define  SERIAL_SILICON	0x00050000
977 
978 // rate = fs = LRCLK
979 // SCLK = 64*LRCLK (I2S)
980 // MCLK = 256fs (typ. -- changeable)
981 
982 // MCLK = clksrc / mdiv
983 // SCLK = MCLK / sdiv
984 // rate = SCLK / 64    ( = LRCLK = fs)
985 
986 int
987 snapper_set_rate(sc, rate)
988 	struct snapper_softc *sc;
989 	int rate;
990 {
991 	u_int reg = 0;
992 	int MCLK;
993 	int clksrc, mdiv, sdiv;
994 	int mclk_fs;
995 
996 	switch (rate) {
997 	case 8000:
998 		clksrc = 18432000;		/* 18MHz */
999 		reg = CLKSRC_18MHz;
1000 		mclk_fs = 256;
1001 		break;
1002 
1003 	case 44100:
1004 		clksrc = 45158400;		/* 45MHz */
1005 		reg = CLKSRC_45MHz;
1006 		mclk_fs = 256;
1007 		break;
1008 
1009 	case 48000:
1010 		clksrc = 49152000;		/* 49MHz */
1011 		reg = CLKSRC_49MHz;
1012 		mclk_fs = 256;
1013 		break;
1014 
1015 	default:
1016 		return EINVAL;
1017 	}
1018 
1019 	MCLK = rate * mclk_fs;
1020 	mdiv = clksrc / MCLK;			// 4
1021 	sdiv = mclk_fs / 64;			// 4
1022 
1023 	switch (mdiv) {
1024 	case 1:
1025 		reg |= MCLK_DIV1;
1026 		break;
1027 	case 3:
1028 		reg |= MCLK_DIV3;
1029 		break;
1030 	case 5:
1031 		reg |= MCLK_DIV5;
1032 		break;
1033 	default:
1034 		reg |= ((mdiv / 2 - 1) << 24) & 0x1f000000;
1035 		break;
1036 	}
1037 
1038 	switch (sdiv) {
1039 	case 1:
1040 		reg |= SCLK_DIV1;
1041 		break;
1042 	case 3:
1043 		reg |= SCLK_DIV3;
1044 		break;
1045 	default:
1046 		reg |= ((sdiv / 2 - 1) << 20) & 0x00f00000;
1047 		break;
1048 	}
1049 
1050 	reg |= SCLK_MASTER;	/* XXX master mode */
1051 
1052 	reg |= SERIAL_64x;
1053 
1054 	/* stereo input and output */
1055 	DPRINTF("I2SSetDataWordSizeReg 0x%08x -> 0x%08x\n",
1056 	    in32rb(sc->sc_reg + I2S_WORDSIZE), 0x02000200);
1057 	out32rb(sc->sc_reg + I2S_WORDSIZE, 0x02000200);
1058 
1059 	DPRINTF("I2SSetSerialFormatReg 0x%x -> 0x%x\n",
1060 	    in32rb(sc->sc_reg + I2S_FORMAT), reg);
1061 	out32rb(sc->sc_reg + I2S_FORMAT, reg);
1062 
1063 	return 0;
1064 }
1065 
1066 #define DEQaddr 0x6a
1067 
1068 const struct tas3004_reg tas3004_initdata = {
1069 	{ DEQ_MCR1_SC_64 | DEQ_MCR1_SM_I2S | DEQ_MCR1_W_20 },	/* MCR1 */
1070 	{ 1, 0, 0, 0, 0, 0 },					/* DRC */
1071 	{ 0, 0, 0, 0, 0, 0 },					/* VOLUME */
1072 	{ 0x72 },						/* TREBLE */
1073 	{ 0x72 },						/* BASS */
1074 	{ 0x10, 0x00, 0x00, 0, 0, 0, 0, 0, 0 },			/* MIXER_L */
1075 	{ 0x10, 0x00, 0x00, 0, 0, 0, 0, 0, 0 },			/* MIXER_R */
1076 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1077 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1078 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1079 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1080 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1081 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1082 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1083 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1084 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1085 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1086 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1087 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1088 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1089 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1090 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1091 	{ 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* BIQUAD */
1092 	{ 0, 0, 0 },						/* LLB_GAIN */
1093 	{ 0, 0, 0 },						/* RLB_GAIN */
1094 	{ 0 },							/* ACR */
1095 	{ 0 }							/* MCR2 */
1096 };
1097 
1098 const char tas3004_regsize[] = {
1099 	0,					/* 0x00 */
1100 	sizeof tas3004_initdata.MCR1,		/* 0x01 */
1101 	sizeof tas3004_initdata.DRC,		/* 0x02 */
1102 	0,					/* 0x03 */
1103 	sizeof tas3004_initdata.VOLUME,		/* 0x04 */
1104 	sizeof tas3004_initdata.TREBLE,		/* 0x05 */
1105 	sizeof tas3004_initdata.BASS,		/* 0x06 */
1106 	sizeof tas3004_initdata.MIXER_L,	/* 0x07 */
1107 	sizeof tas3004_initdata.MIXER_R,	/* 0x08 */
1108 	0,					/* 0x09 */
1109 	sizeof tas3004_initdata.LB0,		/* 0x0a */
1110 	sizeof tas3004_initdata.LB1,		/* 0x0b */
1111 	sizeof tas3004_initdata.LB2,		/* 0x0c */
1112 	sizeof tas3004_initdata.LB3,		/* 0x0d */
1113 	sizeof tas3004_initdata.LB4,		/* 0x0e */
1114 	sizeof tas3004_initdata.LB5,		/* 0x0f */
1115 	sizeof tas3004_initdata.LB6,		/* 0x10 */
1116 	0,					/* 0x11 */
1117 	0,					/* 0x12 */
1118 	sizeof tas3004_initdata.RB0,		/* 0x13 */
1119 	sizeof tas3004_initdata.RB1,		/* 0x14 */
1120 	sizeof tas3004_initdata.RB2,		/* 0x15 */
1121 	sizeof tas3004_initdata.RB3,		/* 0x16 */
1122 	sizeof tas3004_initdata.RB4,		/* 0x17 */
1123 	sizeof tas3004_initdata.RB5,		/* 0x18 */
1124 	sizeof tas3004_initdata.RB6,		/* 0x19 */
1125 	0,0,0,0, 0,0,
1126 	0,					/* 0x20 */
1127 	sizeof tas3004_initdata.LLB,		/* 0x21 */
1128 	sizeof tas3004_initdata.RLB,		/* 0x22 */
1129 	sizeof tas3004_initdata.LLB_GAIN,	/* 0x23 */
1130 	sizeof tas3004_initdata.RLB_GAIN,	/* 0x24 */
1131 	0,0,0,0, 0,0,0,0, 0,0,0,
1132 	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1133 	sizeof tas3004_initdata.ACR,		/* 0x40 */
1134 	0,					/* 0x41 */
1135 	0,					/* 0x42 */
1136 	sizeof tas3004_initdata.MCR2		/* 0x43 */
1137 };
1138 
1139 int
1140 tas3004_write(sc, reg, data)
1141 	struct snapper_softc *sc;
1142 	u_int reg;
1143 	const void *data;
1144 {
1145 	int size;
1146 
1147 	KASSERT(reg < sizeof tas3004_regsize);
1148 	size = tas3004_regsize[reg];
1149 	KASSERT(size > 0);
1150 
1151 	if (ki2c_write(sc->sc_i2c, DEQaddr, reg, data, size))
1152 		return -1;
1153 
1154 	return 0;
1155 }
1156 
1157 int
1158 gpio_read(addr)
1159 	char *addr;
1160 {
1161 	if (*addr & GPIO_DATA)
1162 		return 1;
1163 	return 0;
1164 }
1165 
1166 void
1167 gpio_write(addr, val)
1168 	char *addr;
1169 	int val;
1170 {
1171 	u_int data = GPIO_DDR_OUTPUT;
1172 
1173 	if (val)
1174 		data |= GPIO_DATA;
1175 	*addr = data;
1176 	asm volatile ("eieio");
1177 }
1178 
1179 #define headphone_active 0	/* XXX OF */
1180 #define amp_active 0		/* XXX OF */
1181 
1182 void
1183 snapper_mute_speaker(sc, mute)
1184 	struct snapper_softc *sc;
1185 	int mute;
1186 {
1187 	u_int x;
1188 
1189 	DPRINTF("ampmute %d --> ", gpio_read(amp_mute));
1190 
1191 	if (mute)
1192 		x = amp_active;		/* mute */
1193 	else
1194 		x = !amp_active;	/* unmute */
1195 	if (x != gpio_read(amp_mute))
1196 		gpio_write(amp_mute, x);
1197 
1198 	DPRINTF("%d\n", gpio_read(amp_mute));
1199 }
1200 
1201 void
1202 snapper_mute_headphone(sc, mute)
1203 	struct snapper_softc *sc;
1204 	int mute;
1205 {
1206 	u_int x;
1207 
1208 	DPRINTF("headphonemute %d --> ", gpio_read(headphone_mute));
1209 
1210 	if (mute)
1211 		x = headphone_active;	/* mute */
1212 	else
1213 		x = !headphone_active;	/* unmute */
1214 	if (x != gpio_read(headphone_mute))
1215 		gpio_write(headphone_mute, x);
1216 
1217 	DPRINTF("%d\n", gpio_read(headphone_mute));
1218 }
1219 
1220 int
1221 snapper_cint(v)
1222 	void *v;
1223 {
1224 	struct snapper_softc *sc = v;
1225 	u_int sense;
1226 
1227 	sense = *headphone_detect;
1228 	DPRINTF("headphone detect = 0x%x\n", sense);
1229 
1230 	if (((sense & 0x02) >> 1) == headphone_detect_active) {
1231 		DPRINTF("headphone is inserted\n");
1232 		snapper_mute_speaker(sc, 1);
1233 		snapper_mute_headphone(sc, 0);
1234 		sc->sc_output_mask = 1 << 1;
1235 	} else {
1236 		DPRINTF("headphone is NOT inserted\n");
1237 		snapper_mute_speaker(sc, 0);
1238 		snapper_mute_headphone(sc, 1);
1239 		sc->sc_output_mask = 1 << 0;
1240 	}
1241 
1242 	return 1;
1243 }
1244 
1245 #define reset_active 0	/* XXX OF */
1246 
1247 #define DEQ_WRITE(sc, reg, addr) \
1248 	if (tas3004_write(sc, reg, addr)) goto err
1249 
1250 int
1251 tas3004_init(sc)
1252 	struct snapper_softc *sc;
1253 {
1254 
1255 	/* No reset port.  Nothing to do. */
1256 	if (audio_hw_reset == NULL)
1257 		goto noreset;
1258 
1259 	/* Reset TAS3004. */
1260 	gpio_write(audio_hw_reset, !reset_active);	/* Negate RESET */
1261 	delay(100000);				/* XXX Really needed? */
1262 
1263 	gpio_write(audio_hw_reset, reset_active);	/* Assert RESET */
1264 	delay(1);
1265 
1266 	gpio_write(audio_hw_reset, !reset_active);	/* Negate RESET */
1267 	delay(10000);
1268 
1269 noreset:
1270 	DEQ_WRITE(sc, DEQ_LB0, tas3004_initdata.LB0);
1271 	DEQ_WRITE(sc, DEQ_LB1, tas3004_initdata.LB1);
1272 	DEQ_WRITE(sc, DEQ_LB2, tas3004_initdata.LB2);
1273 	DEQ_WRITE(sc, DEQ_LB3, tas3004_initdata.LB3);
1274 	DEQ_WRITE(sc, DEQ_LB4, tas3004_initdata.LB4);
1275 	DEQ_WRITE(sc, DEQ_LB5, tas3004_initdata.LB5);
1276 	DEQ_WRITE(sc, DEQ_LB6, tas3004_initdata.LB6);
1277 	DEQ_WRITE(sc, DEQ_RB0, tas3004_initdata.RB0);
1278 	DEQ_WRITE(sc, DEQ_RB1, tas3004_initdata.RB1);
1279 	DEQ_WRITE(sc, DEQ_RB1, tas3004_initdata.RB1);
1280 	DEQ_WRITE(sc, DEQ_RB2, tas3004_initdata.RB2);
1281 	DEQ_WRITE(sc, DEQ_RB3, tas3004_initdata.RB3);
1282 	DEQ_WRITE(sc, DEQ_RB4, tas3004_initdata.RB4);
1283 	DEQ_WRITE(sc, DEQ_RB5, tas3004_initdata.RB5);
1284 	DEQ_WRITE(sc, DEQ_MCR1, tas3004_initdata.MCR1);
1285 	DEQ_WRITE(sc, DEQ_MCR2, tas3004_initdata.MCR2);
1286 	DEQ_WRITE(sc, DEQ_DRC, tas3004_initdata.DRC);
1287 	DEQ_WRITE(sc, DEQ_VOLUME, tas3004_initdata.VOLUME);
1288 	DEQ_WRITE(sc, DEQ_TREBLE, tas3004_initdata.TREBLE);
1289 	DEQ_WRITE(sc, DEQ_BASS, tas3004_initdata.BASS);
1290 	DEQ_WRITE(sc, DEQ_MIXER_L, tas3004_initdata.MIXER_L);
1291 	DEQ_WRITE(sc, DEQ_MIXER_R, tas3004_initdata.MIXER_R);
1292 	DEQ_WRITE(sc, DEQ_LLB, tas3004_initdata.LLB);
1293 	DEQ_WRITE(sc, DEQ_RLB, tas3004_initdata.RLB);
1294 	DEQ_WRITE(sc, DEQ_LLB_GAIN, tas3004_initdata.LLB_GAIN);
1295 	DEQ_WRITE(sc, DEQ_RLB_GAIN, tas3004_initdata.RLB_GAIN);
1296 	DEQ_WRITE(sc, DEQ_ACR, tas3004_initdata.ACR);
1297 
1298 	return 0;
1299 err:
1300 	printf("tas3004_init: error\n");
1301 	return -1;
1302 }
1303 
1304 /* FCR(0x3c) bits */
1305 #define I2S0CLKEN	0x1000
1306 #define I2S0EN		0x2000
1307 #define I2S1CLKEN	0x080000
1308 #define I2S1EN		0x100000
1309 
1310 #define FCR3C_BITMASK "\020\25I2S1EN\24I2S1CLKEN\16I2S0EN\15I2S0CLKEN"
1311 
1312 void
1313 snapper_init(sc, node)
1314 	struct snapper_softc *sc;
1315 	int node;
1316 {
1317 	int gpio;
1318 	int headphone_detect_intr = -1, headphone_detect_intrtype;
1319 
1320 #ifdef SNAPPER_DEBUG
1321 	char fcr[32];
1322 
1323 	bitmask_snprintf(in32rb(0x8000003c), FCR3C_BITMASK, fcr, sizeof fcr);
1324 	printf("FCR(0x3c) 0x%s\n", fcr);
1325 #endif
1326 
1327 	gpio = getnodebyname(OF_parent(node), "gpio");
1328 	DPRINTF(" /gpio 0x%x\n", gpio);
1329 	gpio = OF_child(gpio);
1330 	while (gpio) {
1331 		char name[64], audio_gpio[64];
1332 		int intr[2];
1333 		char *addr;
1334 
1335 		bzero(name, sizeof name);
1336 		bzero(audio_gpio, sizeof audio_gpio);
1337 		addr = 0;
1338 		OF_getprop(gpio, "name", name, sizeof name);
1339 		OF_getprop(gpio, "audio-gpio", audio_gpio, sizeof audio_gpio);
1340 		OF_getprop(gpio, "AAPL,address", &addr, sizeof addr);
1341 		/* printf("0x%x %s %s\n", gpio, name, audio_gpio); */
1342 
1343 		/* gpio5 */
1344 		if (strcmp(audio_gpio, "headphone-mute") == 0)
1345 			headphone_mute = addr;
1346 		/* gpio6 */
1347 		if (strcmp(audio_gpio, "amp-mute") == 0)
1348 			amp_mute = addr;
1349 		/* extint-gpio15 */
1350 		if (strcmp(audio_gpio, "headphone-detect") == 0) {
1351 			headphone_detect = addr;
1352 			OF_getprop(gpio, "audio-gpio-active-state",
1353 			    &headphone_detect_active, 4);
1354 			OF_getprop(gpio, "interrupts", intr, 8);
1355 			headphone_detect_intr = intr[0];
1356 			headphone_detect_intrtype = intr[1];
1357 		}
1358 		/* gpio11 (keywest-11) */
1359 		if (strcmp(audio_gpio, "audio-hw-reset") == 0)
1360 			audio_hw_reset = addr;
1361 		gpio = OF_peer(gpio);
1362 	}
1363 	DPRINTF(" headphone-mute %p\n", headphone_mute);
1364 	DPRINTF(" amp-mute %p\n", amp_mute);
1365 	DPRINTF(" headphone-detect %p\n", headphone_detect);
1366 	DPRINTF(" headphone-detect active %x\n", headphone_detect_active);
1367 	DPRINTF(" headphone-detect intr %x\n", headphone_detect_intr);
1368 	DPRINTF(" audio-hw-reset %p\n", audio_hw_reset);
1369 
1370 	if (headphone_detect_intr != -1)
1371 		intr_establish(headphone_detect_intr, IST_EDGE, IPL_AUDIO,
1372 		    snapper_cint, sc);
1373 
1374 	/* "sample-rates" (44100, 48000) */
1375 	snapper_set_rate(sc, 44100);
1376 
1377 	/* Enable headphone interrupt? */
1378 	*headphone_detect |= 0x80;
1379 	asm volatile ("eieio");
1380 
1381 	/* i2c_set_port(port); */
1382 
1383 #if 1
1384 	/* Enable I2C interrupts. */
1385 #define IER 4
1386 #define I2C_INT_DATA 0x01
1387 #define I2C_INT_ADDR 0x02
1388 #define I2C_INT_STOP 0x04
1389 	ki2c_writereg(sc->sc_i2c, IER,I2C_INT_DATA|I2C_INT_ADDR|I2C_INT_STOP);
1390 #endif
1391 
1392 	if (tas3004_init(sc))
1393 		return;
1394 
1395 	/* Update headphone status. */
1396 	snapper_cint(sc);
1397 
1398 	snapper_set_volume(sc, 80, 80);
1399 }
1400