summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Pascoe <pascoe@cvs.openbsd.org>2005-04-15 01:05:52 +0000
committerChristopher Pascoe <pascoe@cvs.openbsd.org>2005-04-15 01:05:52 +0000
commite98c8eadc2a658a4599ac3c5b74fcca6f94420d5 (patch)
tree31f2c2f0b0237bc01eb60051de7954a6e0e64505
parent89ffd6176c431304bc414278cedeb5aed33a580a (diff)
Add basic audio playback support for the Zaurus SL-C3000.
ok dlg@ drahn@ uwe@ deraadt@
-rw-r--r--sys/arch/zaurus/conf/GENERIC5
-rw-r--r--sys/arch/zaurus/conf/files.zaurus9
-rw-r--r--sys/arch/zaurus/dev/zaurus_audio.c679
-rw-r--r--sys/arch/zaurus/dev/zaurus_scoop.c25
-rw-r--r--sys/arch/zaurus/dev/zaurus_scoopvar.h3
-rw-r--r--sys/dev/i2c/wm8750reg.h317
6 files changed, 1033 insertions, 5 deletions
diff --git a/sys/arch/zaurus/conf/GENERIC b/sys/arch/zaurus/conf/GENERIC
index bc0248518c4..eacbdf27b6b 100644
--- a/sys/arch/zaurus/conf/GENERIC
+++ b/sys/arch/zaurus/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.32 2005/04/14 23:40:34 pascoe Exp $
+# $OpenBSD: GENERIC,v 1.33 2005/04/15 01:05:50 pascoe Exp $
#
# GENERIC machine description file
#
@@ -148,7 +148,8 @@ com1 at pxaip? addr 0x40200000 intr 21 # BlueTooth UART
options FFUARTCONSOLE
#options BTUARTCONSOLE
-#aupxa0 at pxaip? # AC97 interface
+zaudio0 at pxaip? # Zaurus I2S/I2C sound
+audio* at zaudio?
# CF (pcmcia) support
pxapcic0 at pxaip?
diff --git a/sys/arch/zaurus/conf/files.zaurus b/sys/arch/zaurus/conf/files.zaurus
index 51726538074..6813b3395e9 100644
--- a/sys/arch/zaurus/conf/files.zaurus
+++ b/sys/arch/zaurus/conf/files.zaurus
@@ -1,4 +1,4 @@
-# $OpenBSD: files.zaurus,v 1.15 2005/01/28 17:14:31 drahn Exp $
+# $OpenBSD: files.zaurus,v 1.16 2005/04/15 01:05:50 pascoe Exp $
#
# First try for arm-specific configuration info
#
@@ -52,6 +52,13 @@ device zts: wsmousedev
attach zts at pxaip
file arch/zaurus/dev/zts.c zts
+# Zaurus sound
+device zaudio: audio
+attach zaudio at pxaip
+file arch/zaurus/dev/zaurus_audio.c zaudio
+file arch/arm/xscale/pxa2x0_i2s.c zaudio
+file arch/arm/xscale/pxa2x0_i2c.c zaudio
+
#
# Machine-independent ATA drivers
#
diff --git a/sys/arch/zaurus/dev/zaurus_audio.c b/sys/arch/zaurus/dev/zaurus_audio.c
new file mode 100644
index 00000000000..478e6990976
--- /dev/null
+++ b/sys/arch/zaurus/dev/zaurus_audio.c
@@ -0,0 +1,679 @@
+/* $OpenBSD: zaurus_audio.c,v 1.1 2005/04/15 01:05:51 pascoe Exp $ */
+
+/*
+ * Copyright (c) 2005 Christopher Pascoe <pascoe@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/audioio.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <arm/xscale/pxa2x0reg.h>
+#include <arm/xscale/pxa2x0var.h>
+#include <arm/xscale/pxa2x0_i2c.h>
+#include <arm/xscale/pxa2x0_i2s.h>
+#include <arm/xscale/pxa2x0_dmac.h>
+
+#include <zaurus/dev/zaurus_scoopvar.h>
+#include <dev/i2c/wm8750reg.h>
+
+#include <dev/audio_if.h>
+#include <dev/mulaw.h>
+#include <dev/auconv.h>
+
+#define WM8750_ADDRESS 0x1B
+#define SPKR_VOLUME 112
+
+#define wm8750_write(sc, reg, val) pxa2x0_i2c_write_2(&sc->sc_i2c, \
+ WM8750_ADDRESS, (((reg) << 9) | ((val) & 0x1ff)))
+
+int zaudio_match(struct device *, void *, void *);
+void zaudio_attach(struct device *, struct device *, void *);
+int zaudio_detach(struct device *, int);
+void zaudio_power(int, void *);
+
+struct zaudio_softc {
+ struct device sc_dev;
+
+ /* i2s device softc */
+ /* NB: pxa2x0_i2s requires this to be the second struct member */
+ struct pxa2x0_i2s_softc sc_i2s;
+
+ /* i2c device softc */
+ struct pxa2x0_i2c_softc sc_i2c;
+
+ void *sc_powerhook;
+ int sc_playing;
+};
+
+struct cfattach zaudio_ca = {
+ sizeof(struct zaudio_softc), zaudio_match, zaudio_attach,
+ zaudio_detach
+};
+
+struct cfdriver zaudio_cd = {
+ NULL, "zaudio", DV_DULL
+};
+
+struct audio_device wm8750_device = {
+ "WM8750",
+ "1.0",
+ "wm"
+};
+
+void zaudio_init(struct zaudio_softc *);
+void zaudio_standby(struct zaudio_softc *);
+void zaudio_play_setup(struct zaudio_softc *);
+int zaudio_open(void *, int);
+void zaudio_close(void *);
+int zaudio_query_encoding(void *, struct audio_encoding *);
+int zaudio_set_params(void *, int, int, struct audio_params *,
+ struct audio_params *);
+int zaudio_halt_output(void *);
+int zaudio_halt_input(void *);
+int zaudio_getdev(void *, struct audio_device *);
+int zaudio_set_port(void *, struct mixer_ctrl *);
+int zaudio_get_port(void *, struct mixer_ctrl *);
+int zaudio_query_devinfo(void *, struct mixer_devinfo *);
+int zaudio_get_props(void *);
+int zaudio_start_output(void *, void *, int, void (*)(void *), void *);
+int zaudio_start_input(void *, void *, int, void (*)(void *), void *);
+
+struct audio_hw_if wm8750_hw_if = {
+ zaudio_open,
+ zaudio_close,
+ NULL /* zaudio_drain */,
+ zaudio_query_encoding,
+ zaudio_set_params,
+ pxa2x0_i2s_round_blocksize,
+ NULL /* zaudio_commit_settings */,
+ NULL /* zaudio_init_output */,
+ NULL /* zaudio_init_input */,
+ zaudio_start_output,
+ zaudio_start_input,
+ zaudio_halt_output,
+ zaudio_halt_input,
+ NULL /* zaudio_speaker_ctl */,
+ zaudio_getdev,
+ NULL /* zaudio_setfd */,
+ zaudio_set_port,
+ zaudio_get_port,
+ zaudio_query_devinfo,
+ pxa2x0_i2s_allocm,
+ pxa2x0_i2s_freem,
+ pxa2x0_i2s_round_buffersize,
+ pxa2x0_i2s_mappage,
+ zaudio_get_props,
+ NULL /* zaudio_trigger_output */,
+ NULL /* zaudio_trigger_input */
+};
+
+static const unsigned short playback_registers[][2] = {
+ /* Unmute DAC */
+ { ADCDACCTL_REG, 0x000 },
+
+ /* 16 bit audio words */
+ { AUDINT_REG, AUDINT_SET_FORMAT(2) },
+
+ /* Enable thermal protection, power */
+ { ADCTL1_REG, ADCTL1_TSDEN | ADCTL1_SET_VSEL(3) },
+
+ /* Enable speaker driver, DAC oversampling */
+ { ADCTL2_REG, ADCTL2_ROUT2INV | ADCTL2_DACOSR },
+
+ /* 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) },
+
+ /* End of list */
+ { 0xffff, 0xffff }
+};
+
+int
+zaudio_match(struct device *parent, void *match, void *aux)
+{
+ return (1);
+}
+
+void
+zaudio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct zaudio_softc *sc = (struct zaudio_softc *)self;
+ struct pxaip_attach_args *pxa = aux;
+
+ sc->sc_powerhook = powerhook_establish(zaudio_power, sc);
+ if (sc->sc_powerhook == NULL) {
+ printf(": unable to establish powerhook\n");
+ return;
+ }
+
+ sc->sc_i2s.sc_iot = pxa->pxa_iot;
+ sc->sc_i2s.sc_dmat = pxa->pxa_dmat;
+ sc->sc_i2s.sc_size = PXA2X0_I2S_SIZE;
+ if (pxa2x0_i2s_attach_sub(&sc->sc_i2s)) {
+ printf(": unable to attach I2S\n");
+ goto fail_i2s;
+ }
+
+ sc->sc_i2c.sc_iot = pxa->pxa_iot;
+ sc->sc_i2c.sc_size = PXA2X0_I2C_SIZE;
+ if (pxa2x0_i2c_attach_sub(&sc->sc_i2c)) {
+ printf(": unable to attach I2C\n");
+ goto fail_i2c;
+ }
+
+ /* Check for an I2C response from the wm8750 */
+ pxa2x0_i2s_open(&sc->sc_i2s); /* supply the codec with a clock */
+ pxa2x0_i2c_open(&sc->sc_i2c);
+
+ if (wm8750_write(sc, RESET_REG, 0)) {
+ printf(": codec failed to respond\n");
+ goto fail_probe;
+ }
+ delay(100);
+
+ zaudio_init(sc);
+
+ pxa2x0_i2c_close(&sc->sc_i2c);
+ pxa2x0_i2s_close(&sc->sc_i2s);
+
+ printf(": I2C, I2S, WM8750 Audio\n");
+
+ audio_attach_mi(&wm8750_hw_if, sc, &sc->sc_dev);
+
+ return;
+
+fail_probe:
+ pxa2x0_i2c_close(&sc->sc_i2c);
+ pxa2x0_i2s_close(&sc->sc_i2s);
+ pxa2x0_i2c_detach_sub(&sc->sc_i2c);
+fail_i2c:
+ pxa2x0_i2s_detach_sub(&sc->sc_i2s);
+fail_i2s:
+ powerhook_disestablish(sc->sc_powerhook);
+}
+
+int
+zaudio_detach(struct device *self, int flags)
+{
+ struct zaudio_softc *sc = (struct zaudio_softc *)self;
+
+ if (sc->sc_powerhook != NULL) {
+ powerhook_disestablish(sc->sc_powerhook);
+ sc->sc_powerhook = NULL;
+ }
+
+ pxa2x0_i2c_detach_sub(&sc->sc_i2c);
+ pxa2x0_i2s_detach_sub(&sc->sc_i2s);
+
+ return (0);
+}
+
+void
+zaudio_power(int why, void *arg)
+{
+ /* XXX */
+ return;
+}
+
+void
+zaudio_init(struct zaudio_softc *sc)
+{
+ /* Reset the codec */
+ wm8750_write(sc, RESET_REG, 0);
+ delay(100);
+
+ /* Switch to standby power only */
+ wm8750_write(sc, PWRMGMT1_REG, PWRMGMT1_SET_VMIDSEL(2));
+ wm8750_write(sc, PWRMGMT2_REG, 0);
+
+ /* Configure digital interface for I2S */
+ wm8750_write(sc, AUDINT_REG, AUDINT_SET_FORMAT(2));
+}
+
+void
+zaudio_standby(struct zaudio_softc *sc)
+{
+ /* Switch codec to standby power only */
+ wm8750_write(sc, PWRMGMT1_REG, PWRMGMT1_SET_VMIDSEL(2));
+ wm8750_write(sc, PWRMGMT2_REG, 0);
+}
+
+void
+zaudio_play_setup(struct zaudio_softc *sc)
+{
+ int i = 0;
+
+ pxa2x0_i2c_open(&sc->sc_i2c);
+
+ /* Program the codec with playback settings */
+ while (playback_registers[i][0] != 0xffff) {
+ wm8750_write(sc, playback_registers[i][0],
+ playback_registers[i][1]);
+ i++;
+ }
+
+ pxa2x0_i2c_close(&sc->sc_i2c);
+}
+
+int
+zaudio_open(void *hdl, int flags)
+{
+ struct zaudio_softc *sc = hdl;
+
+ /* Power on the I2S bus and codec */
+ pxa2x0_i2s_open(&sc->sc_i2s);
+ scoop_audio_set(1);
+
+ return 0;
+}
+
+void
+zaudio_close(void *hdl)
+{
+ struct zaudio_softc *sc = hdl;
+
+ /* Power off the I2S bus and codec */
+ pxa2x0_i2s_close(&sc->sc_i2s);
+ scoop_audio_set(0);
+}
+
+int
+zaudio_query_encoding(void *hdl, struct audio_encoding *aep)
+{
+ switch (aep->index) {
+ case 0:
+ strlcpy(aep->name, AudioEulinear, sizeof(aep->name));
+ aep->encoding = AUDIO_ENCODING_ULINEAR;
+ aep->precision = 8;
+ aep->flags = 0;
+ return (0);
+ case 1:
+ strlcpy(aep->name, AudioEmulaw, sizeof(aep->name));
+ aep->encoding = AUDIO_ENCODING_ULAW;
+ aep->precision = 8;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 2:
+ strlcpy(aep->name, AudioEalaw, sizeof(aep->name));
+ aep->encoding = AUDIO_ENCODING_ALAW;
+ aep->precision = 8;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 3:
+ strlcpy(aep->name, AudioEslinear, sizeof(aep->name));
+ aep->encoding = AUDIO_ENCODING_SLINEAR;
+ aep->precision = 8;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 4:
+ strlcpy(aep->name, AudioEslinear_le, sizeof(aep->name));
+ aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ aep->precision = 16;
+ aep->flags = 0;
+ return (0);
+ case 5:
+ strlcpy(aep->name, AudioEulinear_le, sizeof(aep->name));
+ aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
+ aep->precision = 16;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 6:
+ strlcpy(aep->name, AudioEslinear_be, sizeof(aep->name));
+ aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
+ aep->precision = 16;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 7:
+ strlcpy(aep->name, AudioEulinear_be, sizeof(aep->name));
+ aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
+ aep->precision = 16;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+}
+
+int
+zaudio_set_params(void *hdl, int setmode, int usemode,
+ struct audio_params *play, struct audio_params *rec)
+{
+ struct zaudio_softc *sc = hdl;
+
+ if (setmode & AUMODE_PLAY) {
+ play->factor = 1;
+ play->sw_code = NULL;
+ switch(play->encoding) {
+ case AUDIO_ENCODING_ULAW:
+ switch (play->channels) {
+ case 1:
+ play->factor = 4;
+ play->sw_code = mulaw_to_slinear16_mts;
+ break;
+ case 2:
+ play->factor = 2;
+ play->sw_code = mulaw_to_slinear16;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ case AUDIO_ENCODING_SLINEAR_LE:
+ switch (play->precision) {
+ case 8:
+ switch (play->channels) {
+ case 1:
+ play->factor = 4;
+ play->sw_code = linear8_to_linear16_mts;
+ break;
+ case 2:
+ play->factor = 2;
+ play->sw_code = linear8_to_linear16;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ case 16:
+ switch (play->channels) {
+ case 1:
+ play->factor = 2;
+ play->sw_code = noswap_bytes_mts;
+ break;
+ case 2:
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ case AUDIO_ENCODING_ULINEAR_LE:
+ switch (play->precision) {
+ case 8:
+ switch (play->channels) {
+ case 1:
+ play->factor = 4;
+ play->sw_code =
+ ulinear8_to_linear16_mts;
+ break;
+ case 2:
+ play->factor = 2;
+ play->sw_code = ulinear8_to_linear16;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ case 16:
+ switch (play->channels) {
+ case 1:
+ play->factor = 2;
+ play->sw_code = change_sign16_mts;
+ break;
+ case 2:
+ play->sw_code = change_sign16;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ case AUDIO_ENCODING_ALAW:
+ switch (play->channels) {
+ case 1:
+ play->factor = 4;
+ play->sw_code = alaw_to_slinear16_mts;
+ case 2:
+ play->factor = 2;
+ play->sw_code = alaw_to_slinear16;
+ default:
+ return (EINVAL);
+ }
+ break;
+ case AUDIO_ENCODING_SLINEAR_BE:
+ switch (play->precision) {
+ case 8:
+ switch (play->channels) {
+ case 1:
+ play->factor = 4;
+ play->sw_code =
+ linear8_to_linear16_mts;
+ break;
+ case 2:
+ play->factor = 2;
+ play->sw_code = linear8_to_linear16;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ case 16:
+ switch (play->channels) {
+ case 1:
+ play->factor = 2;
+ play->sw_code = swap_bytes_mts;
+ break;
+ case 2:
+ play->sw_code = swap_bytes;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ case AUDIO_ENCODING_ULINEAR_BE:
+ switch (play->precision) {
+ case 8:
+ switch (play->channels) {
+ case 1:
+ play->factor = 4;
+ play->sw_code =
+ ulinear8_to_linear16_mts;
+ break;
+ case 2:
+ play->factor = 2;
+ play->sw_code = ulinear8_to_linear16;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ case 16:
+ switch (play->channels) {
+ case 1:
+ play->factor = 2;
+ play->sw_code =
+ change_sign16_swap_bytes_mts;
+ break;
+ case 2:
+ play->sw_code =
+ change_sign16_swap_bytes;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ pxa2x0_i2s_setspeed(&sc->sc_i2s, &play->sample_rate);
+ }
+
+#if RECORD_XXX_NOT_YET
+ if (setmode & AUMODE_RECORD) {
+ rec->factor = 1;
+ rec->sw_code = NULL;
+ switch(rec->encoding) {
+ case AUDIO_ENCODING_ULAW:
+ rec->sw_code = ulinear8_to_mulaw;
+ break;
+ case AUDIO_ENCODING_SLINEAR_LE:
+ if (rec->precision == 8)
+ rec->sw_code = change_sign8;
+ break;
+ case AUDIO_ENCODING_ULINEAR_LE:
+ if (rec->precision == 16)
+ rec->sw_code = change_sign16;
+ break;
+ case AUDIO_ENCODING_ALAW:
+ rec->sw_code = ulinear8_to_alaw;
+ break;
+ case AUDIO_ENCODING_SLINEAR_BE:
+ if (rec->precision == 16)
+ rec->sw_code = swap_bytes;
+ else
+ rec->sw_code = change_sign8;
+ break;
+ case AUDIO_ENCODING_ULINEAR_BE:
+ if (rec->precision == 16)
+ rec->sw_code = swap_bytes_change_sign16;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ pxa2x0_i2s_setspeed(sc, &rec->sample_rate);
+ }
+#endif
+
+ return (0);
+}
+
+int
+zaudio_halt_output(void *hdl)
+{
+ struct zaudio_softc *sc = hdl;
+
+ /* XXX forcibly stop output DMA? */
+
+ pxa2x0_i2c_open(&sc->sc_i2c);
+
+ zaudio_standby(sc);
+ sc->sc_playing = 0;
+
+ pxa2x0_i2c_close(&sc->sc_i2c);
+
+ return 0;
+}
+
+int
+zaudio_halt_input(void *hdl)
+{
+ /* struct zaudio_softc *sc = hdl; */
+
+ return 0;
+}
+
+int
+zaudio_getdev(void *hdl, struct audio_device *ret)
+{
+ /* struct zaudio_softc *sc = hdl; */
+
+ *ret = wm8750_device;
+ return 0;
+}
+
+int
+zaudio_set_port(void *hdl, struct mixer_ctrl *mc)
+{
+ /* struct zaudio_softc *sc = hdl; */
+
+ return 0;
+}
+
+int
+zaudio_get_port(void *hdl, struct mixer_ctrl *mc)
+{
+ /* struct zaudio_softc *sc = hdl; */
+
+ return 0;
+}
+
+int
+zaudio_query_devinfo(void *hdl, struct mixer_devinfo *di)
+{
+ /* struct zaudio_softc *sc = hdl; */
+
+ di->prev = di->next = AUDIO_MIXER_LAST;
+
+ return ENXIO;
+}
+
+int
+zaudio_get_props(void *hdl)
+{
+ return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
+}
+
+int
+zaudio_start_output(void *hdl, void *block, int bsize, void (*intr)(void *),
+ void *intrarg)
+{
+ struct zaudio_softc *sc = hdl;
+ int err;
+
+ /* Power up codec if we are not already playing. */
+ if (!sc->sc_playing) {
+ sc->sc_playing = 1;
+ zaudio_play_setup(sc);
+ }
+
+ /* Start DMA via I2S */
+ err = pxa2x0_i2s_start_output(&sc->sc_i2s, block, bsize, intr, intrarg);
+ if (err) {
+ zaudio_standby(sc);
+ sc->sc_playing = 0;
+ }
+ return err;
+}
+
+int
+zaudio_start_input(void *hdl, void *block, int bsize, void (*intr)(void *),
+ void *intrarg)
+{
+ return ENXIO;
+}
diff --git a/sys/arch/zaurus/dev/zaurus_scoop.c b/sys/arch/zaurus/dev/zaurus_scoop.c
index b741464aa33..e46e28e93a1 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.7 2005/03/08 23:29:06 uwe Exp $ */
+/* $OpenBSD: zaurus_scoop.c,v 1.8 2005/04/15 01:05:51 pascoe Exp $ */
/*
* Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
@@ -166,6 +166,29 @@ scoop_led_set(int led, int on)
}
void
+scoop_audio_set(int on)
+{
+ if (scoop_cd.cd_ndevs < 1 || scoop_cd.cd_devs[0] == NULL)
+ return;
+
+ 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);
+ scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R,
+ GPIO_PIN_LOW);
+ } else {
+ scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_L,
+ GPIO_PIN_HIGH);
+ scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R,
+ GPIO_PIN_HIGH);
+ }
+}
+
+void
scoop_battery_temp_adc(int enable)
{
diff --git a/sys/arch/zaurus/dev/zaurus_scoopvar.h b/sys/arch/zaurus/dev/zaurus_scoopvar.h
index 31307a16142..20c02284a49 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.6 2005/02/22 21:53:03 uwe Exp $ */
+/* $OpenBSD: zaurus_scoopvar.h,v 1.7 2005/04/15 01:05:51 pascoe Exp $ */
/*
* Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
@@ -25,5 +25,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_suspend(void);
void scoop_resume(void);
diff --git a/sys/dev/i2c/wm8750reg.h b/sys/dev/i2c/wm8750reg.h
new file mode 100644
index 00000000000..1d786964e98
--- /dev/null
+++ b/sys/dev/i2c/wm8750reg.h
@@ -0,0 +1,317 @@
+/* $OpenBSD: wm8750reg.h,v 1.1 2005/04/15 01:05:51 pascoe Exp $ */
+
+/*
+ * Copyright (c) 2005 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Wolfson Microelectronics' WM8750 I2C/I2S audio codec:
+ * - I2C register definitions. Used in the Sharp Zaurus SL-C3000.
+ */
+
+#define LINVOL_REG 0x00 /* Left Input volume */
+#define LINVOL_LIVU 0x100
+#define LINVOL_LINMUTE 0x80
+#define LINVOL_LIZC 0x40
+#define LINVOL_LINVOL_MASK 0x3F
+#define LINVOL_GET_LINVOL(x) ((x) & 0x3F)
+#define LINVOL_SET_LINVOL(x) (x)
+
+#define RINVOL_REG 0x01 /* Right Input volume */
+#define RINVOL_RIVU 0x100
+#define RINVOL_RINMUTE 0x80
+#define RINVOL_RIZC 0x40
+#define RINVOL_RINVOL_MASK 0x3F
+#define RINVOL_GET_RINVOL(x) ((x) & 0x3F)
+#define RINVOL_SET_RINVOL(x) (x)
+
+#define LOUT1VOL_REG 0x02 /* LOUT1 volume */
+#define LOUT1VOL_LO1VU 0x100
+#define LOUT1VOL_LO1ZC 0x80
+#define LOUT1VOL_LOUT1VOL_MASK 0x7F
+#define LOUT1VOL_GET_LOUT1VOL(x) ((x) & 0x7F)
+#define LOUT1VOL_SET_LOUT1VOL(x) (x)
+
+#define ROUT1VOL_REG 0x03 /* ROUT1 volume */
+#define ROUT1VOL_RO1VU 0x100
+#define ROUT1VOL_RO1ZC 0x80
+#define ROUT1VOL_ROUT1VOL_MASK 0x7F
+#define ROUT1VOL_GET_ROUT1VOL(x) ((x) & 0x7F)
+#define ROUT1VOL_SET_ROUT1VOL(x) (x)
+
+#define ADCDACCTL_REG 0x05 /* ADC & DAC Control */
+#define ADCDACCTL_ADCDIV2 0x100
+#define ADCDACCTL_DACDIV2 0x80
+#define ADCDACCTL_ADCPOL_MASK 0x60
+#define ADCDACCTL_GET_ADCPOL(x) (((x) >> 5) & 0x60)
+#define ADCDACCTL_SET_ADCPOL(x) ((x) << 5)
+#define ADCDACCTL_HPOR 0x10
+#define ADCDACCTL_DACMU 0x8
+#define ADCDACCTL_DEEMPH_MASK 0x6
+#define ADCDACCTL_GET_DEEMPH(x) (((x) >> 1) & 0x6)
+#define ADCDACCTL_SET_DEEMPH(x) ((x) << 1)
+#define ADCDACCTL_ADCHPD 0x1
+
+#define AUDINT_REG 0x07 /* Audio Interface */
+#define AUDINT_BCLKINV 0x80
+#define AUDINT_MS 0x40
+#define AUDINT_LRSWAP 0x20
+#define AUDINT_LRP 0x10
+#define AUDINT_WL_MASK 0xC
+#define AUDINT_GET_WL(x) (((x) >> 2) & 0xC)
+#define AUDINT_SET_WL(x) ((x) << 2)
+#define AUDINT_FORMAT_MASK 0x3
+#define AUDINT_GET_FORMAT(x) ((x) & 0x3)
+#define AUDINT_SET_FORMAT(x) (x)
+
+#define SRATE_REG 0x08 /* Sample rate */
+#define SRATE_BCM_MASK 0x180
+#define SRATE_GET_BCM(x) (((x) >> 7) & 0x180)
+#define SRATE_SET_BCM(x) ((x) << 7)
+#define SRATE_CLKDIV2 0x40
+#define SRATE_SR_MASK 0x3E
+#define SRATE_GET_SR(x) (((x) >> 1) & 0x3E)
+#define SRATE_SET_SR(x) ((x) << 1)
+#define SRATE_USB 0x1
+
+#define LDACVOL_REG 0x0A /* Left DAC volume */
+#define LDACVOL_LDVU 0x100
+#define LDACVOL_LDACVOL_MASK 0xFF
+#define LDACVOL_GET_LDACVOL(x) ((x) & 0xFF)
+#define LDACVOL_SET_LDACVOL(x) (x)
+
+#define RDACVOL_REG 0x0B /* Right DAC volume */
+#define RDACVOL_RDVU 0x100
+#define RDACVOL_RDACVOL_MASK 0xFF
+#define RDACVOL_GET_RDACVOL(x) ((x) & 0xFF)
+#define RDACVOL_SET_RDACVOL(x) (x)
+
+#define BASSCTL_REG 0x0C /* Bass control */
+#define BASSCTL_BB 0x80
+#define BASSCTL_BC 0x40
+#define BASSCTL_BASS_MASK 0xF
+#define BASSCTL_GET_BASS(x) ((x) & 0xF)
+#define BASSCTL_SET_BASS(x) (x)
+
+#define TREBCTL_REG 0x0D /* Treble control */
+#define TREBCTL_TC 0x40
+#define TREBCTL_TRBL_MASK 0xF
+#define TREBCTL_GET_TRBL(x) ((x) & 0xF)
+#define TREBCTL_SET_TRBL(x) (x)
+
+#define RESET_REG 0x0F /* Reset */
+
+#define C3DCTL_REG 0x10 /* 3D control */
+#define C3DCTL_MODE3D 0x80
+#define C3DCTL_3DUC 0x40
+#define C3DCTL_3DLC 0x20
+#define C3DCTL_3DDEPTH_MASK 0x1E
+#define C3DCTL_GET_3DDEPTH(x) (((x) >> 1) & 0x1E)
+#define C3DCTL_SET_3DDEPTH(x) ((x) << 1)
+#define C3DCTL_3DEN 0x1
+
+#define ALC1_REG 0x11 /* ALC1 */
+#define ALC1_ALCSEL_MASK 0x180
+#define ALC1_GET_ALCSEL(x) (((x) >> 7) & 0x180)
+#define ALC1_SET_ALCSEL(x) ((x) << 7)
+#define ALC1_MAXGAIN_MASK 0x70
+#define ALC1_GET_MAXGAIN(x) (((x) >> 4) & 0x70)
+#define ALC1_SET_MAXGAIN(x) ((x) << 4)
+#define ALC1_ALCL_MASK 0xF
+#define ALC1_GET_ALCL(x) ((x) & 0xF)
+#define ALC1_SET_ALCL(x) (x)
+
+#define ALC2_REG 0x12 /* ALC2 */
+#define ALC2_ALCZC 0x80
+#define ALC2_HLD_MASK 0xF
+#define ALC2_GET_HLD(x) ((x) & 0xF)
+#define ALC2_SET_HLD(x) (x)
+
+#define ALC3_REG 0x13 /* ALC3 */
+#define ALC3_DCY_MASK 0xF0
+#define ALC3_GET_DCY(x) (((x) >> 4) & 0xF0)
+#define ALC3_SET_DCY(x) ((x) << 4)
+#define ALC3_ATK_MASK 0xF
+#define ALC3_GET_ATK(x) ((x) & 0xF)
+#define ALC3_SET_ATK(x) (x)
+
+#define NOISEGATE_REG 0x14 /* Noise Gate */
+#define NOISEGATE_NGTH_MASK 0xF8
+#define NOISEGATE_GET_NGTH(x) (((x) >> 3) & 0xF8)
+#define NOISEGATE_SET_NGTH(x) ((x) << 3)
+#define NOISEGATE_NGG_MASK 0x6
+#define NOISEGATE_GET_NGG(x) (((x) >> 1) & 0x6)
+#define NOISEGATE_SET_NGG(x) ((x) << 1)
+#define NOISEGATE_NGAT 0x1
+
+#define LADCVOL_REG 0x15 /* Left ADC volume */
+#define LADCVOL_LAVU 0x100
+#define LADCVOL_LADCVOL_MASK 0xFF
+#define LADCVOL_GET_LADCVOL(x) ((x) & 0xFF)
+#define LADCVOL_SET_LADCVOL(x) (x)
+
+#define RADCVOL_REG 0x16 /* Right ADC volume */
+#define RADCVOL_RAVU 0x100
+#define RADCVOL_RADCVOL_MASK 0xFF
+#define RADCVOL_GET_RADCVOL(x) ((x) & 0xFF)
+#define RADCVOL_SET_RADCVOL(x) (x)
+
+#define ADCTL1_REG 0x17 /* Additional control(1) */
+#define ADCTL1_TSDEN 0x100
+#define ADCTL1_VSEL_MASK 0xC0
+#define ADCTL1_GET_VSEL(x) (((x) >> 6) & 0xC0)
+#define ADCTL1_SET_VSEL(x) ((x) << 6)
+#define ADCTL1_DMONOMIX_MASK 0x30
+#define ADCTL1_GET_DMONOMIX(x) (((x) >> 4) & 0x30)
+#define ADCTL1_SET_DMONOMIX(x) ((x) << 4)
+#define ADCTL1_DATSEL_MASK 0xC
+#define ADCTL1_GET_DATSEL(x) (((x) >> 2) & 0xC)
+#define ADCTL1_SET_DATSEL(x) ((x) << 2)
+#define ADCTL1_DACINV 0x2
+#define ADCTL1_TOEN 0x1
+
+#define ADCTL2_REG 0x18 /* Additional control(2) */
+#define ADCTL2_OUTSW3_MASK 0x180
+#define ADCTL2_GET_OUTSW3(x) (((x) >> 7) & 0x180)
+#define ADCTL2_SET_OUTSW3(x) ((x) << 7)
+#define ADCTL2_HPSWEN 0x40
+#define ADCTL2_HPSWPOL 0x20
+#define ADCTL2_ROUT2INV 0x10
+#define ADCTL2_TRI 0x08
+#define ADCTL2_LRCM 0x04
+#define ADCTL2_ADCOSR 0x02
+#define ADCTL2_DACOSR 0x01
+
+#define PWRMGMT1_REG 0x19 /* Pwr Mgmt (1) */
+#define PWRMGMT1_VMIDSEL_MASK 0x180
+#define PWRMGMT1_GET_VMIDSEL(x) (((x) >> 7) & 0x180)
+#define PWRMGMT1_SET_VMIDSEL(x) ((x) << 7)
+#define PWRMGMT1_VREF 0x40
+#define PWRMGMT1_AINL 0x20
+#define PWRMGMT1_AINR 0x10
+#define PWRMGMT1_ADCL 0x8
+#define PWRMGMT1_ADCR 0x4
+#define PWRMGMT1_MICB 0x2
+#define PWRMGMT1_DIGENB 0x1
+
+#define PWRMGMT2_REG 0x1A /* Pwr Mgmt (2) */
+#define PWRMGMT2_DACL 0x100
+#define PWRMGMT2_DACR 0x80
+#define PWRMGMT2_LOUT1 0x40
+#define PWRMGMT2_ROUT1 0x20
+#define PWRMGMT2_LOUT2 0x10
+#define PWRMGMT2_ROUT2 0x8
+#define PWRMGMT2_MONO 0x4
+#define PWRMGMT2_OUT3 0x2
+
+#define ADCTL3_REG 0x1B /* Additional Control (3) */
+#define ADCTL3_ADCLRM_MASK 0x180
+#define ADCTL3_GET_ADCLRM(x) (((x) >> 7) & 0x180)
+#define ADCTL3_SET_ADCLRM(x) ((x) << 7)
+#define ADCTL3_VROI 0x40
+#define ADCTL3_HPFLREN 0x20
+
+#define ADCINPMODE_REG 0x1F /* ADC input mode */
+#define ADCINPMODE_DS 0x100
+#define ADCINPMODE_MONOMIX_MASK 0xC0
+#define ADCINPMODE_GET_MONOMIX(x) (((x) >> 6) & 0xC0)
+#define ADCINPMODE_SET_MONOMIX(x) ((x) << 6)
+#define ADCINPMODE_RDCM 0x20
+#define ADCINPMODE_LDCM 0x10
+
+#define ADCLSPATH_REG 0x20 /* ADCL signal path */
+#define ADCLSPATH_LINSEL_MASK 0xC0
+#define ADCLSPATH_GET_LINSEL(x) (((x) >> 6) & 0xC0)
+#define ADCLSPATH_SET_LINSEL(x) ((x) << 6)
+#define ADCLSPATH_LMICBOOST_MASK 0x30
+#define ADCLSPATH_GET_LMICBOOST(x) (((x) >> 4) & 0x30)
+#define ADCLSPATH_SET_LMICBOOST(x) ((x) << 4)
+
+#define ADCRSPATH_REG 0x21 /* ADCR signal path */
+#define ADCRSPATH_RINSEL_MASK 0xC0
+#define ADCRSPATH_GET_RINSEL(x) (((x) >> 6) & 0xC0)
+#define ADCRSPATH_SET_RINSEL(x) ((x) << 6)
+#define ADCRSPATH_RMICBOOST_MASK 0x30
+#define ADCRSPATH_GET_RMICBOOST(x) (((x) >> 4) & 0x30)
+#define ADCRSPATH_SET_RMICBOOST(x) ((x) << 4)
+
+#define LOUTMIX1_REG 0x22 /* Left out Mix (1) */
+#define LOUTMIX1_LD2LO 0x100
+#define LOUTMIX1_LI2LO 0x80
+#define LOUTMIX1_LI2LOVOL_MASK 0x70
+#define LOUTMIX1_GET_LI2LOVOL(x) (((x) >> 4) & 0x70)
+#define LOUTMIX1_SET_LI2LOVOL(x) ((x) << 4)
+#define LOUTMIX1_LMIXSEL_MASK 0x7
+#define LOUTMIX1_GET_LMIXSEL(x) ((x) & 0x7)
+#define LOUTMIX1_SET_LMIXSEL(x) (x)
+
+#define LOUTMIX2_REG 0x23 /* Left out Mix (2) */
+#define LOUTMIX2_RD2LO 0x100
+#define LOUTMIX2_RI2LO 0x80
+#define LOUTMIX2_RI2LOVOL_MASK 0x70
+#define LOUTMIX2_GET_RI2LOVOL(x) (((x) >> 4) & 0x70)
+#define LOUTMIX2_SET_RI2LOVOL(x) ((x) << 4)
+
+#define ROUTMIX1_REG 0x24 /* Right out Mix (1) */
+#define ROUTMIX1_LD2RO 0x100
+#define ROUTMIX1_LI2RO 0x80
+#define ROUTMIX1_LI2ROVOL_MASK 0x70
+#define ROUTMIX1_GET_LI2ROVOL(x) (((x) >> 4) & 0x70)
+#define ROUTMIX1_SET_LI2ROVOL(x) ((x) << 4)
+#define ROUTMIX1_RMIXSEL_MASK 0x7
+#define ROUTMIX1_GET_RMIXSEL(x) ((x) & 0x7)
+#define ROUTMIX1_SET_RMIXSEL(x) (x)
+
+#define ROUTMIX2_REG 0x25 /* Right out Mix (2) */
+#define ROUTMIX2_RD2RO 0x100
+#define ROUTMIX2_RI2RO 0x80
+#define ROUTMIX2_RI2ROVOL_MASK 0x70
+#define ROUTMIX2_GET_RI2ROVOL(x) (((x) >> 4) & 0x70)
+#define ROUTMIX2_SET_RI2ROVOL(x) ((x) << 4)
+
+#define MOUTMIX1_REG 0x26 /* Mono out Mix (1) */
+#define MOUTMIX1_LD2MO 0x100
+#define MOUTMIX1_LI2MO 0x80
+#define MOUTMIX1_LI2MOVOL_MASK 0x70
+#define MOUTMIX1_GET_LI2MOVOL(x) (((x) >> 4) & 0x70)
+#define MOUTMIX1_SET_LI2MOVOL(x) ((x) << 4)
+
+#define MOUTMIX2_REG 0x27 /* Mono out Mix (2) */
+#define MOUTMIX2_RD2MO 0x100
+#define MOUTMIX2_RI2MO 0x80
+#define MOUTMIX2_RI2MOVOL_MASK 0x70
+#define MOUTMIX2_GET_RI2MOVOL(x) (((x) >> 4) & 0x70)
+#define MOUTMIX2_SET_RI2MOVOL(x) ((x) << 4)
+
+#define LOUT2VOL_REG 0x28 /* LOUT2 volume */
+#define LOUT2VOL_LO2VU 0x100
+#define LOUT2VOL_LO2ZC 0x80
+#define LOUT2VOL_LOUT2VOL_MASK 0x7F
+#define LOUT2VOL_GET_LOUT2VOL(x) ((x) & 0x7F)
+#define LOUT2VOL_SET_LOUT2VOL(x) (x)
+
+#define ROUT2VOL_REG 0x29 /* ROUT2 volume */
+#define ROUT2VOL_RO2VU 0x100
+#define ROUT2VOL_RO2ZC 0x80
+#define ROUT2VOL_ROUT2VOL_MASK 0x7F
+#define ROUT2VOL_GET_ROUT2VOL(x) ((x) & 0x7F)
+#define ROUT2VOL_SET_ROUT2VOL(x) (x)
+
+#define MOUTVOL_REG 0x2A /* MONOOUT volume */
+#define MOUTVOL_MOZC 0x80
+#define MOUTVOL_MOUTVOL_MASK 0x7F
+#define MOUTVOL_GET_MOUTVOL(x) ((x) & 0x7F)
+#define MOUTVOL_SET_MOUTVOL(x) (x)
+