summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2005-12-11 20:56:02 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2005-12-11 20:56:02 +0000
commit5d6043e6d902fe464bc94d1daee3a86dd3911c68 (patch)
tree716bdf1ca14b075b3ec22992efdf466f654d6f4c /sys/arch
parent20a582ff861e899b606c6ac1ede65faf0bb165bb (diff)
Fix mixer for machines that have lineout and/or don't have headphone.
ok joris@
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/macppc/dev/i2s.c128
1 files changed, 109 insertions, 19 deletions
diff --git a/sys/arch/macppc/dev/i2s.c b/sys/arch/macppc/dev/i2s.c
index 9d8c25f40d3..e66dd32c817 100644
--- a/sys/arch/macppc/dev/i2s.c
+++ b/sys/arch/macppc/dev/i2s.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i2s.c,v 1.4 2005/11/19 00:00:47 kettenis Exp $ */
+/* $OpenBSD: i2s.c,v 1.5 2005/12/11 20:56:01 kettenis Exp $ */
/* $NetBSD: i2s.c,v 1.1 2003/12/27 02:19:34 grant Exp $ */
/*-
@@ -59,8 +59,9 @@ static int gpio_read(char *);
static void gpio_write(char *, int);
void i2s_mute_speaker(struct i2s_softc *, int);
void i2s_mute_headphone(struct i2s_softc *, int);
+void i2s_mute_lineout(struct i2s_softc *, int);
int i2s_cint(void *);
-u_char *i2s_gpio_map(struct i2s_softc *, char *);
+u_char *i2s_gpio_map(struct i2s_softc *, char *, int *);
void i2s_init(struct i2s_softc *, int);
static void mono16_to_stereo16(void *, u_char *, int);
@@ -76,9 +77,12 @@ struct cfdriver i2s_cd = {
static u_char *amp_mute;
static u_char *headphone_mute;
+static u_char *lineout_mute;
static u_char *audio_hw_reset;
static u_char *headphone_detect;
static int headphone_detect_active;
+static u_char *lineout_detect;
+static int lineout_detect_active;
/* I2S registers */
@@ -530,10 +534,13 @@ i2s_set_port(h, mc)
i2s_mute_speaker(sc, 1);
i2s_mute_headphone(sc, 1);
+ i2s_mute_lineout(sc, 1);
if (mc->un.mask & 1 << 0)
i2s_mute_speaker(sc, 0);
if (mc->un.mask & 1 << 1)
i2s_mute_headphone(sc, 0);
+ if (mc->un.mask & 1 << 2)
+ i2s_mute_lineout(sc, 0);
sc->sc_output_mask = mc->un.mask;
return 0;
@@ -625,6 +632,8 @@ i2s_query_devinfo(h, dip)
void *h;
mixer_devinfo_t *dip;
{
+ int n = 0;
+
switch (dip->index) {
case I2S_OUTPUT_SELECT:
@@ -632,13 +641,21 @@ i2s_query_devinfo(h, dip)
strlcpy(dip->label.name, AudioNselect, sizeof(dip->label.name));
dip->type = AUDIO_MIXER_SET;
dip->prev = dip->next = AUDIO_MIXER_LAST;
- dip->un.s.num_mem = 2;
- strlcpy(dip->un.s.member[0].label.name, AudioNspeaker,
- sizeof(dip->un.s.member[0].label.name));
- dip->un.s.member[0].mask = 1 << 0;
- strlcpy(dip->un.s.member[1].label.name, AudioNheadphone,
- sizeof(dip->un.s.member[1].label.name));
- dip->un.s.member[1].mask = 1 << 1;
+ strlcpy(dip->un.s.member[n].label.name, AudioNspeaker,
+ sizeof(dip->un.s.member[n].label.name));
+ dip->un.s.member[n++].mask = 1 << 0;
+ if (headphone_mute) {
+ strlcpy(dip->un.s.member[n].label.name,
+ AudioNheadphone,
+ sizeof(dip->un.s.member[n].label.name));
+ dip->un.s.member[n++].mask = 1 << 1;
+ }
+ if (lineout_mute) {
+ strlcpy(dip->un.s.member[n].label.name, AudioNline,
+ sizeof(dip->un.s.member[n].label.name));
+ dip->un.s.member[n++].mask = 1 << 2;
+ }
+ dip->un.s.num_mem = n;
return 0;
case I2S_VOL_OUTPUT:
@@ -969,8 +986,9 @@ gpio_write(addr, val)
asm volatile ("eieio" ::: "memory");
}
-#define headphone_active 0 /* XXX OF */
#define amp_active 0 /* XXX OF */
+#define headphone_active 0 /* XXX OF */
+#define lineout_active 0 /* XXX OF */
void
i2s_mute_speaker(sc, mute)
@@ -979,6 +997,9 @@ i2s_mute_speaker(sc, mute)
{
u_int x;
+ if (amp_mute == NULL)
+ return;
+
DPRINTF(("ampmute %d --> ", gpio_read(amp_mute)));
if (mute)
@@ -998,6 +1019,9 @@ i2s_mute_headphone(sc, mute)
{
u_int x;
+ if (headphone_mute == NULL)
+ return;
+
DPRINTF(("headphonemute %d --> ", gpio_read(headphone_mute)));
if (mute)
@@ -1010,6 +1034,28 @@ i2s_mute_headphone(sc, mute)
DPRINTF(("%d\n", gpio_read(headphone_mute)));
}
+void
+i2s_mute_lineout(sc, mute)
+ struct i2s_softc *sc;
+ int mute;
+{
+ u_int x;
+
+ if (lineout_mute == NULL)
+ return;
+
+ DPRINTF(("lineout %d --> ", gpio_read(lineout_mute)));
+
+ if (mute)
+ x = lineout_active; /* mute */
+ else
+ x = !lineout_active; /* unmute */
+ if (x != gpio_read(lineout_mute))
+ gpio_write(lineout_mute, x);
+
+ DPRINTF(("%d\n", gpio_read(lineout_mute)));
+}
+
int
i2s_cint(v)
void *v;
@@ -1017,28 +1063,52 @@ i2s_cint(v)
struct i2s_softc *sc = v;
u_int sense;
- sense = *headphone_detect;
+ sc->sc_output_mask = 0;
+ i2s_mute_speaker(sc, 1);
+ i2s_mute_headphone(sc, 1);
+ i2s_mute_lineout(sc, 1);
+
+ if (headphone_detect)
+ sense = *headphone_detect;
+ else
+ sense = !headphone_detect_active << 1;
DPRINTF(("headphone detect = 0x%x\n", sense));
if (((sense & 0x02) >> 1) == headphone_detect_active) {
DPRINTF(("headphone is inserted\n"));
- i2s_mute_speaker(sc, 1);
+ sc->sc_output_mask |= 1 << 1;
i2s_mute_headphone(sc, 0);
- sc->sc_output_mask = 1 << 1;
} else {
DPRINTF(("headphone is NOT inserted\n"));
+ }
+
+ if (lineout_detect)
+ sense = *lineout_detect;
+ else
+ sense = !lineout_detect_active << 1;
+ DPRINTF(("lineout detect = 0x%x\n", sense));
+
+ if (((sense & 0x02) >> 1) == lineout_detect_active) {
+ DPRINTF(("lineout is inserted\n"));
+ sc->sc_output_mask |= 1 << 2;
+ i2s_mute_lineout(sc, 0);
+ } else {
+ DPRINTF(("lineout is NOT inserted\n"));
+ }
+
+ if (sc->sc_output_mask == 0) {
+ sc->sc_output_mask |= 1 << 0;
i2s_mute_speaker(sc, 0);
- i2s_mute_headphone(sc, 1);
- sc->sc_output_mask = 1 << 0;
}
return 1;
}
u_char *
-i2s_gpio_map(struct i2s_softc *sc, char *name)
+i2s_gpio_map(struct i2s_softc *sc, char *name, int *irq)
{
u_int32_t reg[2];
+ u_int32_t intr[2];
int gpio;
if (OF_getprop(sc->sc_node, name, &gpio,
@@ -1049,6 +1119,11 @@ i2s_gpio_map(struct i2s_softc *sc, char *name)
sizeof(reg[1])) != sizeof(reg[1]))
return NULL;
+ if (irq && OF_getprop(gpio, "interrupts",
+ intr, sizeof(intr)) == sizeof(intr)) {
+ *irq = intr[0];
+ }
+
return mapiodev(sc->sc_baseaddr + reg[0] + reg[1], 1);
}
@@ -1060,10 +1135,17 @@ i2s_gpio_init(sc, node, parent)
{
int gpio;
int headphone_detect_intr = -1, headphone_detect_intrtype;
+ int lineout_detect_intr = -1;
/* Map gpios. */
- amp_mute = i2s_gpio_map(sc, "platform-amp-mute");
- audio_hw_reset = i2s_gpio_map(sc, "platform-hw-reset");
+ amp_mute = i2s_gpio_map(sc, "platform-amp-mute", NULL);
+ headphone_mute = i2s_gpio_map(sc, "platform-headphone-mute", NULL);
+ headphone_detect = i2s_gpio_map(sc, "platform-headphone-detect",
+ &headphone_detect_intr);
+ lineout_mute = i2s_gpio_map(sc, "platform-lineout-mute", NULL);
+ lineout_detect = i2s_gpio_map(sc, "platform-lineout-detect",
+ &lineout_detect_intr);
+ audio_hw_reset = i2s_gpio_map(sc, "platform-hw-reset", NULL);
gpio = OF_getnodebyname(OF_parent(node), "gpio");
DPRINTF((" /gpio 0x%x\n", gpio));
@@ -1109,17 +1191,25 @@ i2s_gpio_init(sc, node, parent)
gpio = OF_peer(gpio);
}
- DPRINTF((" headphone-mute %p\n", headphone_mute));
DPRINTF((" amp-mute %p\n", amp_mute));
+ DPRINTF((" headphone-mute %p\n", headphone_mute));
DPRINTF((" headphone-detect %p\n", headphone_detect));
DPRINTF((" headphone-detect active %x\n", headphone_detect_active));
DPRINTF((" headphone-detect intr %x\n", headphone_detect_intr));
+ DPRINTF((" lineout-mute %p\n", lineout_mute));
+ DPRINTF((" lineout-detect %p\n", lineout_detect));
+ DPRINTF((" lineout-detect active %x\n", lineout_detect_active));
+ DPRINTF((" lineout-detect intr %x\n", lineout_detect_intr));
DPRINTF((" audio-hw-reset %p\n", audio_hw_reset));
if (headphone_detect_intr != -1)
mac_intr_establish(parent, headphone_detect_intr, IST_EDGE,
IPL_AUDIO, i2s_cint, sc, "i2s_h");
+ if (lineout_detect_intr != -1)
+ mac_intr_establish(parent, lineout_detect_intr, IST_EDGE,
+ IPL_AUDIO, i2s_cint, sc, "i2s_l");
+
/* Enable headphone interrupt? */
*headphone_detect |= 0x80;
asm volatile("eieio");