diff options
author | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2005-05-23 22:44:58 +0000 |
---|---|---|
committer | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2005-05-23 22:44:58 +0000 |
commit | a49c3d2e6f2795763326ab450e262d618a616db3 (patch) | |
tree | 42200d04689b132f1c63ec3f40bcc41af999882d /sys/arch/zaurus/dev | |
parent | 50aaf2ae990b7e1ae83950552f80c26675cb8b2d (diff) |
Headphone output and volume control support.
ok dlg@
Diffstat (limited to 'sys/arch/zaurus/dev')
-rw-r--r-- | sys/arch/zaurus/dev/zaurus_audio.c | 256 | ||||
-rw-r--r-- | sys/arch/zaurus/dev/zaurus_scoop.c | 24 | ||||
-rw-r--r-- | sys/arch/zaurus/dev/zaurus_scoopvar.h | 4 |
3 files changed, 247 insertions, 37 deletions
diff --git a/sys/arch/zaurus/dev/zaurus_audio.c b/sys/arch/zaurus/dev/zaurus_audio.c index 436435b861f..d99d05c0eea 100644 --- a/sys/arch/zaurus/dev/zaurus_audio.c +++ b/sys/arch/zaurus/dev/zaurus_audio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: zaurus_audio.c,v 1.3 2005/04/21 13:43:48 pascoe Exp $ */ +/* $OpenBSD: zaurus_audio.c,v 1.4 2005/05/23 22:44:57 pascoe Exp $ */ /* * Copyright (c) 2005 Christopher Pascoe <pascoe@openbsd.org> @@ -18,11 +18,8 @@ /* * TODO: - * - zaudio(4) * - powerhooks (currently only works until first suspend) - * - headphone jack support * - record support - * - mixer support (codec has independent o/p volume, l/r mix, equalizer) */ #include <sys/param.h> @@ -59,6 +56,14 @@ void zaudio_attach(struct device *, struct device *, void *); int zaudio_detach(struct device *, int); void zaudio_power(int, void *); +#define ZAUDIO_OP_SPKR 0 +#define ZAUDIO_OP_HP 1 + +struct zaudio_volume { + u_int8_t left; + u_int8_t right; +}; + struct zaudio_softc { struct device sc_dev; @@ -71,6 +76,9 @@ struct zaudio_softc { void *sc_powerhook; int sc_playing; + + struct zaudio_volume sc_volume[2]; + char sc_unmute[2]; }; struct cfattach zaudio_ca = { @@ -90,6 +98,8 @@ struct audio_device wm8750_device = { void zaudio_init(struct zaudio_softc *); void zaudio_standby(struct zaudio_softc *); +void zaudio_update_volume(struct zaudio_softc *, int); +void zaudio_update_mutes(struct zaudio_softc *); void zaudio_play_setup(struct zaudio_softc *); int zaudio_open(void *, int); void zaudio_close(void *); @@ -151,17 +161,9 @@ static const unsigned short playback_registers[][2] = { /* Set DAC voltage references */ { PWRMGMT1_REG, PWRMGMT1_SET_VMIDSEL(1) | PWRMGMT1_VREF }, - /* Power DACs and outputs */ - { PWRMGMT2_REG, PWRMGMT2_DACL | PWRMGMT2_DACR | PWRMGMT2_LOUT1 | - PWRMGMT2_ROUT1 | PWRMGMT2_LOUT2 | PWRMGMT2_ROUT2 }, - - /* Set left/right channel mix mixer */ - { LOUTMIX1_REG, LOUTMIX1_LD2LO | LOUTMIX1_SET_LI2LOVOL(5) }, - { ROUTMIX2_REG, ROUTMIX2_RD2RO | ROUTMIX2_SET_RI2ROVOL(5) }, - - /* Set speaker volume */ - { LOUT2VOL_REG, LOUT2VOL_LO2VU | LOUT2VOL_SET_LOUT2VOL(SPKR_VOLUME) }, - { ROUT2VOL_REG, ROUT2VOL_RO2VU | ROUT2VOL_SET_ROUT2VOL(0) }, + /* Direct DACs to output mixers */ + { LOUTMIX1_REG, LOUTMIX1_LD2LO }, + { ROUTMIX2_REG, ROUTMIX2_RD2RO }, /* End of list */ { 0xffff, 0xffff } @@ -210,6 +212,13 @@ zaudio_attach(struct device *parent, struct device *self, void *aux) } delay(100); + /* Speaker on, headphones off by default. */ + sc->sc_volume[ZAUDIO_OP_SPKR].left = 240; + sc->sc_unmute[ZAUDIO_OP_SPKR] = 1; + sc->sc_volume[ZAUDIO_OP_HP].left = 180; + sc->sc_volume[ZAUDIO_OP_HP].right = 180; + sc->sc_unmute[ZAUDIO_OP_HP] = 0; + zaudio_init(sc); pxa2x0_i2c_close(&sc->sc_i2c); @@ -267,6 +276,11 @@ zaudio_init(struct zaudio_softc *sc) /* Configure digital interface for I2S */ wm8750_write(sc, AUDINT_REG, AUDINT_SET_FORMAT(2)); + + /* Initialise volume levels */ + zaudio_update_volume(sc, ZAUDIO_OP_SPKR); + zaudio_update_volume(sc, ZAUDIO_OP_HP); + scoop_set_headphone(0); } void @@ -278,10 +292,53 @@ zaudio_standby(struct zaudio_softc *sc) wm8750_write(sc, PWRMGMT1_REG, PWRMGMT1_SET_VMIDSEL(2)); wm8750_write(sc, PWRMGMT2_REG, 0); + scoop_set_headphone(0); + pxa2x0_i2c_close(&sc->sc_i2c); } void +zaudio_update_volume(struct zaudio_softc *sc, int output) +{ + switch(output) { + case ZAUDIO_OP_SPKR: + wm8750_write(sc, LOUT2VOL_REG, LOUT2VOL_LO2VU | LOUT2VOL_LO2ZC | + LOUT2VOL_SET_LOUT2VOL(sc->sc_volume[ZAUDIO_OP_SPKR + ].left >> 1)); + wm8750_write(sc, ROUT2VOL_REG, ROUT2VOL_RO2VU | ROUT2VOL_RO2ZC | + ROUT2VOL_SET_ROUT2VOL(sc->sc_volume[ZAUDIO_OP_SPKR + ].left >> 1)); + break; + case ZAUDIO_OP_HP: + wm8750_write(sc, LOUT1VOL_REG, LOUT1VOL_LO1VU | LOUT1VOL_LO1ZC | + LOUT1VOL_SET_LOUT1VOL(sc->sc_volume[ZAUDIO_OP_HP + ].left >> 1)); + wm8750_write(sc, ROUT1VOL_REG, ROUT1VOL_RO1VU | ROUT1VOL_RO1ZC | + ROUT1VOL_SET_ROUT1VOL(sc->sc_volume[ZAUDIO_OP_HP + ].right >> 1)); + break; + } +} + +void +zaudio_update_mutes(struct zaudio_softc *sc) +{ + unsigned short val; + + val = PWRMGMT2_DACL | PWRMGMT2_DACR; + + if (sc->sc_unmute[ZAUDIO_OP_SPKR]) + val |= PWRMGMT2_LOUT2 | PWRMGMT2_ROUT2; + + if (sc->sc_unmute[ZAUDIO_OP_HP]) + val |= PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1; + + wm8750_write(sc, PWRMGMT2_REG, val); + + scoop_set_headphone(sc->sc_unmute[ZAUDIO_OP_HP]); +} + +void zaudio_play_setup(struct zaudio_softc *sc) { int i = 0; @@ -294,6 +351,7 @@ zaudio_play_setup(struct zaudio_softc *sc) playback_registers[i][1]); i++; } + zaudio_update_mutes(sc); pxa2x0_i2c_close(&sc->sc_i2c); } @@ -305,7 +363,6 @@ zaudio_open(void *hdl, int flags) /* Power on the I2S bus and codec */ pxa2x0_i2s_open(&sc->sc_i2s); - scoop_audio_set(1); return 0; } @@ -317,7 +374,6 @@ zaudio_close(void *hdl) /* Power off the I2S bus and codec */ pxa2x0_i2s_close(&sc->sc_i2s); - scoop_audio_set(0); } int @@ -626,20 +682,120 @@ zaudio_getdev(void *hdl, struct audio_device *ret) return 0; } +#define ZAUDIO_SPKR_LVL 0 +#define ZAUDIO_SPKR_MUTE 1 +#define ZAUDIO_HP_LVL 2 +#define ZAUDIO_HP_MUTE 3 +#define ZAUDIO_OUTPUT_CLASS 4 + int zaudio_set_port(void *hdl, struct mixer_ctrl *mc) { - /* struct zaudio_softc *sc = hdl; */ + struct zaudio_softc *sc = hdl; + int error = EINVAL; - return 0; + pxa2x0_i2c_open(&sc->sc_i2c); + + switch (mc->dev) { + case ZAUDIO_SPKR_LVL: + if (mc->type != AUDIO_MIXER_VALUE) + break; + if (mc->un.value.num_channels == 1) + sc->sc_volume[ZAUDIO_OP_SPKR].left = + mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; + else + break; + zaudio_update_volume(sc, ZAUDIO_OP_SPKR); + error = 0; + break; + case ZAUDIO_SPKR_MUTE: + if (mc->type != AUDIO_MIXER_ENUM) + break; + sc->sc_unmute[ZAUDIO_OP_SPKR] = mc->un.ord ? 1 : 0; + zaudio_update_mutes(sc); + error = 0; + break; + case ZAUDIO_HP_LVL: + if (mc->type != AUDIO_MIXER_VALUE) + break; + if (mc->un.value.num_channels == 1) { + sc->sc_volume[ZAUDIO_OP_HP].left = + mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; + sc->sc_volume[ZAUDIO_OP_HP].right = + mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; + } else if (mc->un.value.num_channels == 2) { + sc->sc_volume[ZAUDIO_OP_HP].left = + mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; + sc->sc_volume[ZAUDIO_OP_HP].right = + mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; + } + else + break; + zaudio_update_volume(sc, ZAUDIO_OP_HP); + error = 0; + break; + case ZAUDIO_HP_MUTE: + if (mc->type != AUDIO_MIXER_ENUM) + break; + sc->sc_unmute[ZAUDIO_OP_HP] = mc->un.ord ? 1 : 0; + zaudio_update_mutes(sc); + error = 0; + break; + } + + pxa2x0_i2c_close(&sc->sc_i2c); + + return error; } int zaudio_get_port(void *hdl, struct mixer_ctrl *mc) { - /* struct zaudio_softc *sc = hdl; */ + struct zaudio_softc *sc = hdl; + int error = EINVAL; - return 0; + switch (mc->dev) { + case ZAUDIO_SPKR_LVL: + if (mc->type != AUDIO_MIXER_VALUE) + break; + if (mc->un.value.num_channels == 1) + mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = + sc->sc_volume[ZAUDIO_OP_SPKR].left; + else + break; + error = 0; + break; + case ZAUDIO_SPKR_MUTE: + if (mc->type != AUDIO_MIXER_ENUM) + break; + mc->un.ord = sc->sc_unmute[ZAUDIO_OP_SPKR] ? 1 : 0; + error = 0; + break; + case ZAUDIO_HP_LVL: + if (mc->type != AUDIO_MIXER_VALUE) + break; + if (mc->un.value.num_channels == 1) + mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = + sc->sc_volume[ZAUDIO_OP_HP].left; + else if (mc->un.value.num_channels == 2) { + mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = + sc->sc_volume[ZAUDIO_OP_HP].left; + mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = + sc->sc_volume[ZAUDIO_OP_HP].right; + } + else + break; + error = 0; + break; + case ZAUDIO_HP_MUTE: + if (mc->type != AUDIO_MIXER_ENUM) + break; + mc->un.ord = sc->sc_unmute[ZAUDIO_OP_HP] ? 1 : 0; + error = 0; + break; + } + + return error; } int @@ -647,9 +803,63 @@ zaudio_query_devinfo(void *hdl, struct mixer_devinfo *di) { /* struct zaudio_softc *sc = hdl; */ - di->prev = di->next = AUDIO_MIXER_LAST; + switch (di->index) { + case ZAUDIO_SPKR_LVL: + di->type = AUDIO_MIXER_VALUE; + di->mixer_class = ZAUDIO_OUTPUT_CLASS; + di->prev = AUDIO_MIXER_LAST; + di->next = ZAUDIO_SPKR_MUTE; + strlcpy(di->label.name, AudioNspeaker, + sizeof(di->label.name)); + strlcpy(di->un.v.units.name, AudioNvolume, + sizeof(di->un.v.units.name)); + di->un.v.num_channels = 1; + break; + case ZAUDIO_SPKR_MUTE: + di->type = AUDIO_MIXER_ENUM; + di->mixer_class = ZAUDIO_OUTPUT_CLASS; + di->prev = ZAUDIO_SPKR_LVL; + di->next = AUDIO_MIXER_LAST; + goto mute; + case ZAUDIO_HP_LVL: + di->type = AUDIO_MIXER_VALUE; + di->mixer_class = ZAUDIO_OUTPUT_CLASS; + di->prev = AUDIO_MIXER_LAST; + di->next = ZAUDIO_HP_MUTE; + strlcpy(di->label.name, AudioNheadphone, + sizeof(di->label.name)); + di->un.v.num_channels = 1; + strlcpy(di->un.v.units.name, AudioNvolume, + sizeof(di->un.v.units.name)); + break; + case ZAUDIO_HP_MUTE: + di->type = AUDIO_MIXER_ENUM; + di->mixer_class = ZAUDIO_OUTPUT_CLASS; + di->prev = ZAUDIO_HP_LVL; + di->next = AUDIO_MIXER_LAST; +mute: + strlcpy(di->label.name, AudioNmute, sizeof(di->label.name)); + di->un.e.num_mem = 2; + strlcpy(di->un.e.member[0].label.name, AudioNon, + sizeof(di->un.e.member[0].label.name)); + di->un.e.member[0].ord = 0; + strlcpy(di->un.e.member[1].label.name, AudioNoff, + sizeof(di->un.e.member[1].label.name)); + di->un.e.member[1].ord = 1; + break; + case ZAUDIO_OUTPUT_CLASS: + di->type = AUDIO_MIXER_CLASS; + di->mixer_class = ZAUDIO_OUTPUT_CLASS; + di->prev = AUDIO_MIXER_LAST; + di->next = AUDIO_MIXER_LAST; + strlcpy(di->label.name, AudioCoutputs, + sizeof(di->label.name)); + break; + default: + return ENXIO; + } - return ENXIO; + return 0; } int diff --git a/sys/arch/zaurus/dev/zaurus_scoop.c b/sys/arch/zaurus/dev/zaurus_scoop.c index 5902e030271..60347e5c1ad 100644 --- a/sys/arch/zaurus/dev/zaurus_scoop.c +++ b/sys/arch/zaurus/dev/zaurus_scoop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: zaurus_scoop.c,v 1.9 2005/05/09 15:16:36 uwe Exp $ */ +/* $OpenBSD: zaurus_scoop.c,v 1.10 2005/05/23 22:44:57 pascoe Exp $ */ /* * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de> @@ -186,29 +186,29 @@ scoop_led_set(int led, int on) } /* - * Mute or unmute audio signals going to the internal speaker (and - * the headphone jack as well?) + * Enable or disable the headphone output connection. */ void -scoop_audio_set(int on) +scoop_set_headphone(int on) { if (scoop_cd.cd_ndevs < 1 || scoop_cd.cd_devs[0] == NULL) return; + scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_L, + GPIO_PIN_OUTPUT); + scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_R, + GPIO_PIN_OUTPUT); + if (on) { - scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_L, - GPIO_PIN_OUTPUT); - scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_R, - GPIO_PIN_OUTPUT); scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_L, - GPIO_PIN_LOW); + GPIO_PIN_HIGH); scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R, - GPIO_PIN_LOW); + GPIO_PIN_HIGH); } else { scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_L, - GPIO_PIN_HIGH); + GPIO_PIN_LOW); scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R, - GPIO_PIN_HIGH); + GPIO_PIN_LOW); } } diff --git a/sys/arch/zaurus/dev/zaurus_scoopvar.h b/sys/arch/zaurus/dev/zaurus_scoopvar.h index 19d094248d3..bdddf7e06eb 100644 --- a/sys/arch/zaurus/dev/zaurus_scoopvar.h +++ b/sys/arch/zaurus/dev/zaurus_scoopvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: zaurus_scoopvar.h,v 1.8 2005/05/09 15:16:36 uwe Exp $ */ +/* $OpenBSD: zaurus_scoopvar.h,v 1.9 2005/05/23 22:44:57 pascoe Exp $ */ /* * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de> @@ -26,6 +26,6 @@ void scoop_battery_temp_adc(int); void scoop_charge_battery(int, int); void scoop_discharge_battery(int); void scoop_check_mcr(void); -void scoop_audio_set(int); +void scoop_set_headphone(int); void scoop_suspend(void); void scoop_resume(void); |