1187692Snwhitehorn/*-
2187692Snwhitehorn * Copyright 2008 by Marco Trillo. All rights reserved.
3187692Snwhitehorn *
4187692Snwhitehorn * Redistribution and use in source and binary forms, with or without
5187692Snwhitehorn * modification, are permitted provided that the following conditions
6187692Snwhitehorn * are met:
7187692Snwhitehorn * 1. Redistributions of source code must retain the above copyright
8187692Snwhitehorn *    notice, this list of conditions and the following disclaimer.
9187692Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
10187692Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
11187692Snwhitehorn *    documentation and/or other materials provided with the distribution.
12187692Snwhitehorn *
13187692Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14187692Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15187692Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16187692Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17187692Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18187692Snwhitehorn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19187692Snwhitehorn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
20187692Snwhitehorn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21187692Snwhitehorn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22187692Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23187692Snwhitehorn * SUCH DAMAGE.
24187692Snwhitehorn *
25187692Snwhitehorn * $FreeBSD$
26187692Snwhitehorn */
27187692Snwhitehorn
28187692Snwhitehorn/*
29187692Snwhitehorn *	Apple DAVbus audio controller.
30187692Snwhitehorn */
31187692Snwhitehorn
32187692Snwhitehorn#include <sys/param.h>
33187692Snwhitehorn#include <sys/systm.h>
34187692Snwhitehorn#include <sys/bus.h>
35187692Snwhitehorn#include <sys/kernel.h>
36187692Snwhitehorn#include <sys/lock.h>
37187692Snwhitehorn#include <sys/malloc.h>
38187692Snwhitehorn#include <sys/module.h>
39187692Snwhitehorn#include <sys/mutex.h>
40187692Snwhitehorn#include <sys/rman.h>
41187692Snwhitehorn
42187692Snwhitehorn#include <dev/ofw/ofw_bus.h>
43193640Sariff
44193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
45193640Sariff#include "opt_snd.h"
46193640Sariff#endif
47193640Sariff
48187692Snwhitehorn#include <dev/sound/pcm/sound.h>
49193640Sariff
50187692Snwhitehorn#include <dev/sound/macio/aoa.h>
51187692Snwhitehorn#include <dev/sound/macio/davbusreg.h>
52187692Snwhitehorn
53187692Snwhitehorn#include <machine/intr_machdep.h>
54187692Snwhitehorn#include <machine/resource.h>
55187692Snwhitehorn#include <machine/bus.h>
56187692Snwhitehorn
57187692Snwhitehorn#include "mixer_if.h"
58187692Snwhitehorn
59187692Snwhitehornstruct davbus_softc {
60187692Snwhitehorn	struct aoa_softc 	 aoa;
61187692Snwhitehorn	phandle_t 		 node;
62187692Snwhitehorn	phandle_t 		 soundnode;
63187692Snwhitehorn	struct resource 	*reg;
64187692Snwhitehorn	struct mtx 		 mutex;
65187692Snwhitehorn	int 			 device_id;
66187692Snwhitehorn	u_int 			 output_mask;
67187692Snwhitehorn	u_int 			(*read_status)(struct davbus_softc *, u_int);
68187692Snwhitehorn	void			(*set_outputs)(struct davbus_softc *, u_int);
69187692Snwhitehorn};
70187692Snwhitehorn
71187692Snwhitehornstatic int 	davbus_probe(device_t);
72187692Snwhitehornstatic int 	davbus_attach(device_t);
73187692Snwhitehornstatic void	davbus_cint(void *);
74187692Snwhitehorn
75187692Snwhitehornstatic device_method_t pcm_davbus_methods[] = {
76187692Snwhitehorn	/* Device interface. */
77187692Snwhitehorn	DEVMETHOD(device_probe,		davbus_probe),
78187692Snwhitehorn	DEVMETHOD(device_attach, 	davbus_attach),
79187692Snwhitehorn
80187692Snwhitehorn	{ 0, 0 }
81187692Snwhitehorn};
82187692Snwhitehorn
83187692Snwhitehornstatic driver_t pcm_davbus_driver = {
84187692Snwhitehorn	"pcm",
85187692Snwhitehorn	pcm_davbus_methods,
86187717Snwhitehorn	PCM_SOFTC_SIZE
87187692Snwhitehorn};
88187692Snwhitehorn
89187692SnwhitehornDRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, pcm_devclass, 0, 0);
90187692SnwhitehornMODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
91187692Snwhitehorn
92187692Snwhitehorn/*****************************************************************************
93187692Snwhitehorn			Probe and attachment routines.
94187692Snwhitehorn *****************************************************************************/
95187692Snwhitehornstatic int
96187692Snwhitehorndavbus_probe(device_t self)
97187692Snwhitehorn{
98187692Snwhitehorn	const char 		*name;
99187692Snwhitehorn
100187692Snwhitehorn	name = ofw_bus_get_name(self);
101187692Snwhitehorn	if (!name)
102187692Snwhitehorn		return (ENXIO);
103187692Snwhitehorn
104187692Snwhitehorn	if (strcmp(name, "davbus") != 0)
105187692Snwhitehorn		return (ENXIO);
106187692Snwhitehorn
107187692Snwhitehorn	device_set_desc(self, "Apple DAVBus Audio Controller");
108187692Snwhitehorn
109187692Snwhitehorn	return (0);
110187692Snwhitehorn}
111187692Snwhitehorn
112187692Snwhitehorn/*
113187692Snwhitehorn * Burgundy codec control
114187692Snwhitehorn */
115187692Snwhitehorn
116187692Snwhitehornstatic int	burgundy_init(struct snd_mixer *m);
117187692Snwhitehornstatic int	burgundy_uninit(struct snd_mixer *m);
118187692Snwhitehornstatic int	burgundy_reinit(struct snd_mixer *m);
119187692Snwhitehornstatic void 	burgundy_write_locked(struct davbus_softc *, u_int, u_int);
120187692Snwhitehornstatic void	burgundy_set_outputs(struct davbus_softc *d, u_int mask);
121187692Snwhitehornstatic u_int	burgundy_read_status(struct davbus_softc *d, u_int status);
122187692Snwhitehornstatic int	burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left,
123187692Snwhitehorn		    unsigned right);
124193640Sariffstatic u_int32_t	burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src);
125187692Snwhitehorn
126187692Snwhitehornstatic kobj_method_t burgundy_mixer_methods[] = {
127187692Snwhitehorn	KOBJMETHOD(mixer_init, 		burgundy_init),
128187692Snwhitehorn	KOBJMETHOD(mixer_uninit, 	burgundy_uninit),
129187692Snwhitehorn	KOBJMETHOD(mixer_reinit, 	burgundy_reinit),
130187692Snwhitehorn	KOBJMETHOD(mixer_set, 		burgundy_set),
131187692Snwhitehorn	KOBJMETHOD(mixer_setrecsrc,	burgundy_setrecsrc),
132193640Sariff	KOBJMETHOD_END
133187692Snwhitehorn};
134187692Snwhitehorn
135187692SnwhitehornMIXER_DECLARE(burgundy_mixer);
136187692Snwhitehorn
137187692Snwhitehornstatic int
138187692Snwhitehornburgundy_init(struct snd_mixer *m)
139187692Snwhitehorn{
140187692Snwhitehorn	struct davbus_softc *d;
141187692Snwhitehorn
142187692Snwhitehorn	d = mix_getdevinfo(m);
143187692Snwhitehorn
144187692Snwhitehorn	d->read_status = burgundy_read_status;
145187692Snwhitehorn	d->set_outputs = burgundy_set_outputs;
146187692Snwhitehorn
147187692Snwhitehorn	/*
148187692Snwhitehorn	 * We configure the Burgundy codec as follows:
149187692Snwhitehorn	 *
150187692Snwhitehorn	 * 	o Input subframe 0 is connected to input digital
151187692Snwhitehorn	 *	  stream A (ISA).
152187692Snwhitehorn	 *	o Stream A (ISA) is mixed in mixer 2 (MIX2).
153187692Snwhitehorn	 *	o Output of mixer 2 (MIX2) is routed to output sources
154187692Snwhitehorn	 *	  OS0 and OS1 which can be converted to analog.
155187692Snwhitehorn	 *
156187692Snwhitehorn	 */
157187692Snwhitehorn	mtx_lock(&d->mutex);
158187692Snwhitehorn
159187692Snwhitehorn	burgundy_write_locked(d, 0x16700, 0x40);
160187692Snwhitehorn
161187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_MIX0_REG, 0);
162187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_MIX1_REG, 0);
163187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_MIX2_REG, BURGUNDY_MIX_ISA);
164187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_MIX3_REG, 0);
165187692Snwhitehorn
166187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_OS_REG, BURGUNDY_OS0_MIX2 |
167187692Snwhitehorn	    BURGUNDY_OS1_MIX2);
168187692Snwhitehorn
169187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_SDIN_REG, BURGUNDY_ISA_SF0);
170187692Snwhitehorn
171187692Snwhitehorn	/* Set several digital scalers to unity gain. */
172187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_MXS2L_REG, BURGUNDY_MXS_UNITY);
173187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_MXS2R_REG, BURGUNDY_MXS_UNITY);
174187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_OSS0L_REG, BURGUNDY_OSS_UNITY);
175187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_OSS0R_REG, BURGUNDY_OSS_UNITY);
176187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_OSS1L_REG, BURGUNDY_OSS_UNITY);
177187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_OSS1R_REG, BURGUNDY_OSS_UNITY);
178187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_ISSAL_REG, BURGUNDY_ISS_UNITY);
179187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_ISSAR_REG, BURGUNDY_ISS_UNITY);
180187692Snwhitehorn
181187692Snwhitehorn	burgundy_set_outputs(d, burgundy_read_status(d,
182187692Snwhitehorn	    bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
183187692Snwhitehorn
184187692Snwhitehorn	mtx_unlock(&d->mutex);
185187692Snwhitehorn
186187692Snwhitehorn	mix_setdevs(m, SOUND_MASK_VOLUME);
187187692Snwhitehorn
188187692Snwhitehorn	return (0);
189187692Snwhitehorn}
190187692Snwhitehorn
191187692Snwhitehornstatic int
192187692Snwhitehornburgundy_uninit(struct snd_mixer *m)
193187692Snwhitehorn{
194187692Snwhitehorn	return (0);
195187692Snwhitehorn}
196187692Snwhitehorn
197187692Snwhitehornstatic int
198187692Snwhitehornburgundy_reinit(struct snd_mixer *m)
199187692Snwhitehorn{
200187692Snwhitehorn	return (0);
201187692Snwhitehorn}
202187692Snwhitehorn
203187692Snwhitehornstatic void
204187692Snwhitehornburgundy_write_locked(struct davbus_softc *d, u_int reg, u_int val)
205187692Snwhitehorn{
206187692Snwhitehorn	u_int size, addr, offset, data, i;
207187692Snwhitehorn
208187692Snwhitehorn	size = (reg & 0x00FF0000) >> 16;
209187692Snwhitehorn	addr = (reg & 0x0000FF00) >> 8;
210187692Snwhitehorn	offset = reg & 0xFF;
211187692Snwhitehorn
212187692Snwhitehorn	for (i = offset; i < offset + size; ++i) {
213187692Snwhitehorn		data = BURGUNDY_CTRL_WRITE | (addr << 12) |
214187692Snwhitehorn		    ((size + offset - 1) << 10) | (i << 8) | (val & 0xFF);
215187692Snwhitehorn		if (i == offset)
216187692Snwhitehorn			data |= BURGUNDY_CTRL_RESET;
217187692Snwhitehorn
218187692Snwhitehorn		bus_write_4(d->reg, DAVBUS_CODEC_CTRL, data);
219187692Snwhitehorn
220187692Snwhitehorn		while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) &
221187692Snwhitehorn		    DAVBUS_CODEC_BUSY)
222187692Snwhitehorn			DELAY(1);
223187692Snwhitehorn
224187692Snwhitehorn		val >>= 8; /* next byte. */
225187692Snwhitehorn	}
226187692Snwhitehorn}
227187692Snwhitehorn
228187692Snwhitehorn/* Must be called with d->mutex held. */
229187692Snwhitehornstatic void
230187692Snwhitehornburgundy_set_outputs(struct davbus_softc *d, u_int mask)
231187692Snwhitehorn{
232187692Snwhitehorn	u_int	x = 0;
233187692Snwhitehorn
234187692Snwhitehorn	if (mask == d->output_mask)
235187692Snwhitehorn		return;
236187692Snwhitehorn
237187692Snwhitehorn	/*
238187692Snwhitehorn	 *	Bordeaux card wirings:
239187692Snwhitehorn	 *		Port 15:	RCA out
240187692Snwhitehorn	 *		Port 16:	Minijack out
241187692Snwhitehorn	 *		Port 17:	Internal speaker
242187692Snwhitehorn	 *
243187692Snwhitehorn	 *	B&W G3 wirings:
244187692Snwhitehorn	 *		Port 14:	Minijack out
245187692Snwhitehorn	 *		Port 17:	Internal speaker
246187692Snwhitehorn	 */
247187692Snwhitehorn
248187692Snwhitehorn	DPRINTF(("Enabled outputs:"));
249187692Snwhitehorn	if (mask & (1 << 0)) {
250187692Snwhitehorn		DPRINTF((" SPEAKER"));
251187692Snwhitehorn		x |= BURGUNDY_P17M_EN;
252187692Snwhitehorn	}
253187692Snwhitehorn	if (mask & (1 << 1)) {
254187692Snwhitehorn		DPRINTF((" HEADPHONES"));
255187692Snwhitehorn		x |= BURGUNDY_P14L_EN | BURGUNDY_P14R_EN;
256187692Snwhitehorn	}
257187692Snwhitehorn	DPRINTF(("\n"));
258187692Snwhitehorn
259187692Snwhitehorn	burgundy_write_locked(d, BURGUNDY_MUTE_REG, x);
260187692Snwhitehorn	d->output_mask = mask;
261187692Snwhitehorn}
262187692Snwhitehorn
263187692Snwhitehornstatic u_int
264187692Snwhitehornburgundy_read_status(struct davbus_softc *d, u_int status)
265187692Snwhitehorn{
266187692Snwhitehorn	if (status & 0x4)
267187692Snwhitehorn		return (1 << 1);
268187692Snwhitehorn	else
269187692Snwhitehorn		return (1 << 0);
270187692Snwhitehorn}
271187692Snwhitehorn
272187692Snwhitehornstatic int
273187692Snwhitehornburgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
274187692Snwhitehorn{
275187692Snwhitehorn	struct davbus_softc *d;
276187692Snwhitehorn	int lval, rval;
277187692Snwhitehorn
278187692Snwhitehorn	lval = ((100 - left) * 15 / 100) & 0xf;
279187692Snwhitehorn	rval = ((100 - right) * 15 / 100) & 0xf;
280187692Snwhitehorn	DPRINTF(("volume %d %d\n", lval, rval));
281187692Snwhitehorn
282187692Snwhitehorn	d = mix_getdevinfo(m);
283187692Snwhitehorn
284187692Snwhitehorn	switch (dev) {
285187692Snwhitehorn	case SOUND_MIXER_VOLUME:
286187692Snwhitehorn		mtx_lock(&d->mutex);
287187692Snwhitehorn
288187692Snwhitehorn		burgundy_write_locked(d, BURGUNDY_OL13_REG, lval);
289187692Snwhitehorn		burgundy_write_locked(d, BURGUNDY_OL14_REG, (rval << 4) | lval);
290187692Snwhitehorn		burgundy_write_locked(d, BURGUNDY_OL15_REG, (rval << 4) | lval);
291187692Snwhitehorn		burgundy_write_locked(d, BURGUNDY_OL16_REG, (rval << 4) | lval);
292187692Snwhitehorn		burgundy_write_locked(d, BURGUNDY_OL17_REG, lval);
293187692Snwhitehorn
294187692Snwhitehorn		mtx_unlock(&d->mutex);
295187692Snwhitehorn
296187692Snwhitehorn		return (left | (right << 8));
297187692Snwhitehorn	}
298187692Snwhitehorn
299187692Snwhitehorn	return (0);
300187692Snwhitehorn}
301187692Snwhitehorn
302193640Sariffstatic u_int32_t
303187692Snwhitehornburgundy_setrecsrc(struct snd_mixer *m, u_int32_t src)
304187692Snwhitehorn{
305187692Snwhitehorn	return (0);
306187692Snwhitehorn}
307187692Snwhitehorn
308187692Snwhitehorn/*
309187692Snwhitehorn * Screamer Codec Control
310187692Snwhitehorn */
311187692Snwhitehorn
312187692Snwhitehornstatic int	screamer_init(struct snd_mixer *m);
313187692Snwhitehornstatic int	screamer_uninit(struct snd_mixer *m);
314187692Snwhitehornstatic int	screamer_reinit(struct snd_mixer *m);
315187692Snwhitehornstatic void 	screamer_write_locked(struct davbus_softc *, u_int, u_int);
316187692Snwhitehornstatic void	screamer_set_outputs(struct davbus_softc *d, u_int mask);
317187692Snwhitehornstatic u_int	screamer_read_status(struct davbus_softc *d, u_int status);
318187692Snwhitehornstatic int	screamer_set(struct snd_mixer *m, unsigned dev, unsigned left,
319187692Snwhitehorn		    unsigned right);
320193640Sariffstatic u_int32_t	screamer_setrecsrc(struct snd_mixer *m, u_int32_t src);
321187692Snwhitehorn
322187692Snwhitehornstatic kobj_method_t screamer_mixer_methods[] = {
323187692Snwhitehorn	KOBJMETHOD(mixer_init, 		screamer_init),
324187692Snwhitehorn	KOBJMETHOD(mixer_uninit, 	screamer_uninit),
325187692Snwhitehorn	KOBJMETHOD(mixer_reinit, 	screamer_reinit),
326187692Snwhitehorn	KOBJMETHOD(mixer_set, 		screamer_set),
327187692Snwhitehorn	KOBJMETHOD(mixer_setrecsrc,	screamer_setrecsrc),
328193640Sariff	KOBJMETHOD_END
329187692Snwhitehorn};
330187692Snwhitehorn
331187692SnwhitehornMIXER_DECLARE(screamer_mixer);
332187692Snwhitehorn
333187692Snwhitehornstatic int
334187692Snwhitehornscreamer_init(struct snd_mixer *m)
335187692Snwhitehorn{
336187692Snwhitehorn	struct davbus_softc *d;
337187692Snwhitehorn
338187692Snwhitehorn	d = mix_getdevinfo(m);
339187692Snwhitehorn
340187692Snwhitehorn	d->read_status = screamer_read_status;
341187692Snwhitehorn	d->set_outputs = screamer_set_outputs;
342187692Snwhitehorn
343187692Snwhitehorn	mtx_lock(&d->mutex);
344187692Snwhitehorn
345187692Snwhitehorn	screamer_write_locked(d, SCREAMER_CODEC_ADDR0, SCREAMER_INPUT_CD |
346187692Snwhitehorn	    SCREAMER_DEFAULT_CD_GAIN);
347187692Snwhitehorn
348187692Snwhitehorn	screamer_set_outputs(d, screamer_read_status(d,
349187692Snwhitehorn	    bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
350187692Snwhitehorn
351187692Snwhitehorn	screamer_write_locked(d, SCREAMER_CODEC_ADDR2, 0);
352187692Snwhitehorn	screamer_write_locked(d, SCREAMER_CODEC_ADDR4, 0);
353187692Snwhitehorn	screamer_write_locked(d, SCREAMER_CODEC_ADDR5, 0);
354187692Snwhitehorn	screamer_write_locked(d, SCREAMER_CODEC_ADDR6, 0);
355187692Snwhitehorn
356187692Snwhitehorn	mtx_unlock(&d->mutex);
357187692Snwhitehorn
358187692Snwhitehorn	mix_setdevs(m, SOUND_MASK_VOLUME);
359187692Snwhitehorn
360187692Snwhitehorn	return (0);
361187692Snwhitehorn}
362187692Snwhitehorn
363187692Snwhitehornstatic int
364187692Snwhitehornscreamer_uninit(struct snd_mixer *m)
365187692Snwhitehorn{
366187692Snwhitehorn	return (0);
367187692Snwhitehorn}
368187692Snwhitehorn
369187692Snwhitehornstatic int
370187692Snwhitehornscreamer_reinit(struct snd_mixer *m)
371187692Snwhitehorn{
372187692Snwhitehorn	return (0);
373187692Snwhitehorn}
374187692Snwhitehorn
375187692Snwhitehorn
376187692Snwhitehornstatic void
377187692Snwhitehornscreamer_write_locked(struct davbus_softc *d, u_int reg, u_int val)
378187692Snwhitehorn{
379187692Snwhitehorn	u_int 		x;
380187692Snwhitehorn
381187692Snwhitehorn	KASSERT(val == (val & 0xfff), ("bad val"));
382187692Snwhitehorn
383187692Snwhitehorn	while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY)
384187692Snwhitehorn		DELAY(100);
385187692Snwhitehorn
386187692Snwhitehorn	x = reg;
387187692Snwhitehorn	x |= SCREAMER_CODEC_EMSEL0;
388187692Snwhitehorn	x |= val;
389187692Snwhitehorn	bus_write_4(d->reg, DAVBUS_CODEC_CTRL, x);
390187692Snwhitehorn
391187692Snwhitehorn	while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY)
392187692Snwhitehorn		DELAY(100);
393187692Snwhitehorn}
394187692Snwhitehorn
395187692Snwhitehorn/* Must be called with d->mutex held. */
396187692Snwhitehornstatic void
397187692Snwhitehornscreamer_set_outputs(struct davbus_softc *d, u_int mask)
398187692Snwhitehorn{
399187692Snwhitehorn	u_int 	x;
400187692Snwhitehorn
401187692Snwhitehorn	if (mask == d->output_mask) {
402187692Snwhitehorn		return;
403187692Snwhitehorn	}
404187692Snwhitehorn
405187692Snwhitehorn	x = SCREAMER_MUTE_SPEAKER | SCREAMER_MUTE_HEADPHONES;
406187692Snwhitehorn
407187692Snwhitehorn	DPRINTF(("Enabled outputs: "));
408187692Snwhitehorn
409187692Snwhitehorn	if (mask & (1 << 0)) {
410187692Snwhitehorn		DPRINTF(("SPEAKER "));
411187692Snwhitehorn		x &= ~SCREAMER_MUTE_SPEAKER;
412187692Snwhitehorn	}
413187692Snwhitehorn	if (mask & (1 << 1)) {
414187692Snwhitehorn		DPRINTF(("HEADPHONES "));
415187692Snwhitehorn		x &= ~SCREAMER_MUTE_HEADPHONES;
416187692Snwhitehorn	}
417187692Snwhitehorn
418187692Snwhitehorn	DPRINTF(("\n"));
419187692Snwhitehorn
420187692Snwhitehorn	if (d->device_id == 5 || d->device_id == 11) {
421187692Snwhitehorn		DPRINTF(("Enabling programmable output.\n"));
422187692Snwhitehorn		x |= SCREAMER_PROG_OUTPUT0;
423187692Snwhitehorn	}
424187692Snwhitehorn	if (d->device_id == 8 || d->device_id == 11) {
425187692Snwhitehorn		x &= ~SCREAMER_MUTE_SPEAKER;
426187692Snwhitehorn
427187692Snwhitehorn		if (mask & (1 << 0))
428187692Snwhitehorn			x |= SCREAMER_PROG_OUTPUT1; /* enable speaker. */
429187692Snwhitehorn	}
430187692Snwhitehorn
431187692Snwhitehorn	screamer_write_locked(d, SCREAMER_CODEC_ADDR1, x);
432187692Snwhitehorn	d->output_mask = mask;
433187692Snwhitehorn}
434187692Snwhitehorn
435187692Snwhitehornstatic u_int
436187692Snwhitehornscreamer_read_status(struct davbus_softc *d, u_int status)
437187692Snwhitehorn{
438187692Snwhitehorn	int 	headphones;
439187692Snwhitehorn
440187692Snwhitehorn	switch (d->device_id) {
441187692Snwhitehorn	case 5: /* Sawtooth */
442187692Snwhitehorn		headphones = (status & 0x4);
443187692Snwhitehorn		break;
444187692Snwhitehorn
445187692Snwhitehorn	case 8:
446187692Snwhitehorn	case 11: /* iMac DV */
447187692Snwhitehorn		/* The iMac DV has 2 headphone outputs. */
448187692Snwhitehorn		headphones = (status & 0x7);
449187692Snwhitehorn		break;
450187692Snwhitehorn
451187692Snwhitehorn	default:
452187692Snwhitehorn		headphones = (status & 0x8);
453187692Snwhitehorn	}
454187692Snwhitehorn
455187692Snwhitehorn	if (headphones)
456187692Snwhitehorn		return (1 << 1);
457187692Snwhitehorn	else
458187692Snwhitehorn		return (1 << 0);
459187692Snwhitehorn}
460187692Snwhitehorn
461187692Snwhitehornstatic int
462187692Snwhitehornscreamer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
463187692Snwhitehorn{
464187692Snwhitehorn	struct davbus_softc *d;
465187692Snwhitehorn	int lval, rval;
466187692Snwhitehorn
467187692Snwhitehorn	lval = ((100 - left) * 15 / 100) & 0xf;
468187692Snwhitehorn	rval = ((100 - right) * 15 / 100) & 0xf;
469187692Snwhitehorn	DPRINTF(("volume %d %d\n", lval, rval));
470187692Snwhitehorn
471187692Snwhitehorn	d = mix_getdevinfo(m);
472187692Snwhitehorn
473187692Snwhitehorn	switch (dev) {
474187692Snwhitehorn	case SOUND_MIXER_VOLUME:
475187692Snwhitehorn		mtx_lock(&d->mutex);
476187692Snwhitehorn		screamer_write_locked(d, SCREAMER_CODEC_ADDR2, (lval << 6) |
477187692Snwhitehorn		    rval);
478187692Snwhitehorn		screamer_write_locked(d, SCREAMER_CODEC_ADDR4, (lval << 6) |
479187692Snwhitehorn		    rval);
480187692Snwhitehorn		mtx_unlock(&d->mutex);
481187692Snwhitehorn
482187692Snwhitehorn		return (left | (right << 8));
483187692Snwhitehorn	}
484187692Snwhitehorn
485187692Snwhitehorn	return (0);
486187692Snwhitehorn}
487187692Snwhitehorn
488193640Sariffstatic u_int32_t
489187692Snwhitehornscreamer_setrecsrc(struct snd_mixer *m, u_int32_t src)
490187692Snwhitehorn{
491187692Snwhitehorn	return (0);
492187692Snwhitehorn}
493187692Snwhitehorn
494187692Snwhitehornstatic int
495187692Snwhitehorndavbus_attach(device_t self)
496187692Snwhitehorn{
497187717Snwhitehorn	struct davbus_softc 	*sc;
498187692Snwhitehorn	struct resource 	*dbdma_irq, *cintr;
499187692Snwhitehorn	void 			*cookie;
500187692Snwhitehorn	char			 compat[64];
501187692Snwhitehorn	int 			 rid, oirq, err;
502187692Snwhitehorn
503187717Snwhitehorn	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
504187717Snwhitehorn
505188259Snwhitehorn	sc->aoa.sc_dev = self;
506187692Snwhitehorn	sc->node = ofw_bus_get_node(self);
507187692Snwhitehorn	sc->soundnode = OF_child(sc->node);
508187692Snwhitehorn
509187692Snwhitehorn	/* Map the controller register space. */
510187692Snwhitehorn	rid = 0;
511187692Snwhitehorn	sc->reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
512187692Snwhitehorn	if (sc->reg == NULL)
513187692Snwhitehorn		return (ENXIO);
514187692Snwhitehorn
515187692Snwhitehorn	/* Map the DBDMA channel register space. */
516187692Snwhitehorn	rid = 1;
517187692Snwhitehorn	sc->aoa.sc_odma = bus_alloc_resource_any(self, SYS_RES_MEMORY,
518187692Snwhitehorn	    &rid, RF_ACTIVE);
519187692Snwhitehorn	if (sc->aoa.sc_odma == NULL)
520187692Snwhitehorn		return (ENXIO);
521187692Snwhitehorn
522187692Snwhitehorn	/* Establish the DBDMA channel edge-triggered interrupt. */
523187692Snwhitehorn	rid = 1;
524187692Snwhitehorn	dbdma_irq = bus_alloc_resource_any(self, SYS_RES_IRQ,
525187692Snwhitehorn	    &rid, RF_SHAREABLE | RF_ACTIVE);
526187692Snwhitehorn	if (dbdma_irq == NULL)
527187692Snwhitehorn		return (ENXIO);
528187692Snwhitehorn
529187692Snwhitehorn	oirq = rman_get_start(dbdma_irq);
530187692Snwhitehorn
531187692Snwhitehorn	DPRINTF(("interrupting at irq %d\n", oirq));
532187692Snwhitehorn
533187692Snwhitehorn	err = powerpc_config_intr(oirq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
534187692Snwhitehorn	if (err != 0)
535187692Snwhitehorn		return (err);
536187692Snwhitehorn
537188259Snwhitehorn	snd_setup_intr(self, dbdma_irq, INTR_MPSAFE, aoa_interrupt,
538188259Snwhitehorn	    sc, &cookie);
539187692Snwhitehorn
540187692Snwhitehorn	/* Now initialize the controller. */
541187692Snwhitehorn
542187692Snwhitehorn	bzero(compat, sizeof(compat));
543187692Snwhitehorn	OF_getprop(sc->soundnode, "compatible", compat, sizeof(compat));
544187692Snwhitehorn	OF_getprop(sc->soundnode, "device-id", &sc->device_id, sizeof(u_int));
545187692Snwhitehorn
546187692Snwhitehorn	mtx_init(&sc->mutex, "DAVbus", NULL, MTX_DEF);
547187692Snwhitehorn
548187692Snwhitehorn	device_printf(self, "codec: <%s>\n", compat);
549187692Snwhitehorn
550187692Snwhitehorn	/* Setup the control interrupt. */
551187692Snwhitehorn	rid = 0;
552187692Snwhitehorn	cintr = bus_alloc_resource_any(self, SYS_RES_IRQ,
553187692Snwhitehorn	     &rid, RF_SHAREABLE | RF_ACTIVE);
554187692Snwhitehorn	if (cintr != NULL)
555187692Snwhitehorn		bus_setup_intr(self, cintr, INTR_TYPE_MISC | INTR_MPSAFE,
556187692Snwhitehorn		    NULL, davbus_cint, sc, &cookie);
557187692Snwhitehorn
558187692Snwhitehorn	/* Initialize controller registers. */
559187692Snwhitehorn        bus_write_4(sc->reg, DAVBUS_SOUND_CTRL, DAVBUS_INPUT_SUBFRAME0 |
560187692Snwhitehorn	    DAVBUS_OUTPUT_SUBFRAME0 | DAVBUS_RATE_44100 | DAVBUS_INTR_PORTCHG);
561187692Snwhitehorn
562187692Snwhitehorn	/* Attach DBDMA engine and PCM layer */
563188259Snwhitehorn	err = aoa_attach(sc);
564187692Snwhitehorn	if (err)
565187692Snwhitehorn		return (err);
566187692Snwhitehorn
567187692Snwhitehorn	/* Install codec module */
568187692Snwhitehorn	if (strcmp(compat, "screamer") == 0)
569187692Snwhitehorn		mixer_init(self, &screamer_mixer_class, sc);
570187692Snwhitehorn	else if (strcmp(compat, "burgundy") == 0)
571187692Snwhitehorn		mixer_init(self, &burgundy_mixer_class, sc);
572187692Snwhitehorn
573187692Snwhitehorn	return (0);
574187692Snwhitehorn}
575187692Snwhitehorn
576187692Snwhitehornstatic void
577187692Snwhitehorndavbus_cint(void *ptr)
578187692Snwhitehorn{
579187692Snwhitehorn	struct davbus_softc *d = ptr;
580187692Snwhitehorn	u_int	reg, status, mask;
581187692Snwhitehorn
582187692Snwhitehorn	mtx_lock(&d->mutex);
583187692Snwhitehorn
584187692Snwhitehorn	reg = bus_read_4(d->reg, DAVBUS_SOUND_CTRL);
585187692Snwhitehorn	if (reg & DAVBUS_PORTCHG) {
586187692Snwhitehorn
587187692Snwhitehorn		status = bus_read_4(d->reg, DAVBUS_CODEC_STATUS);
588187692Snwhitehorn
589187692Snwhitehorn		if (d->read_status && d->set_outputs) {
590187692Snwhitehorn
591187692Snwhitehorn			mask = (*d->read_status)(d, status);
592187692Snwhitehorn			(*d->set_outputs)(d, mask);
593187692Snwhitehorn		}
594187692Snwhitehorn
595187692Snwhitehorn		/* Clear the interrupt. */
596187692Snwhitehorn		bus_write_4(d->reg, DAVBUS_SOUND_CTRL, reg);
597187692Snwhitehorn	}
598187692Snwhitehorn
599187692Snwhitehorn	mtx_unlock(&d->mutex);
600187692Snwhitehorn}
601187692Snwhitehorn
602