Module Name:    src
Committed By:   jmcneill
Date:           Sat Jan 10 12:16:28 UTC 2015

Modified Files:
        src/sys/arch/arm/imx: imx23_rtcreg.h
Added Files:
        src/sys/arch/arm/imx: imx23_digfilt.c imx23_digfiltreg.h
            imx23_digfiltvar.h imx23_rtc.c imx23_rtcvar.h

Log Message:
>From Petri Laakso <petri.laa...@asd.fi>:
-       Audio output driver for imx23
-       Supporting code for audio driver


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/imx/imx23_digfilt.c \
    src/sys/arch/arm/imx/imx23_digfiltreg.h \
    src/sys/arch/arm/imx/imx23_digfiltvar.h src/sys/arch/arm/imx/imx23_rtc.c \
    src/sys/arch/arm/imx/imx23_rtcvar.h
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/imx/imx23_rtcreg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/imx/imx23_rtcreg.h
diff -u src/sys/arch/arm/imx/imx23_rtcreg.h:1.1 src/sys/arch/arm/imx/imx23_rtcreg.h:1.2
--- src/sys/arch/arm/imx/imx23_rtcreg.h:1.1	Tue Nov 20 19:06:13 2012
+++ src/sys/arch/arm/imx/imx23_rtcreg.h	Sat Jan 10 12:16:28 2015
@@ -1,4 +1,4 @@
-/* $Id: imx23_rtcreg.h,v 1.1 2012/11/20 19:06:13 jkunz Exp $ */
+/* $Id: imx23_rtcreg.h,v 1.2 2015/01/10 12:16:28 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -35,6 +35,7 @@
 #include <sys/cdefs.h>
 
 #define HW_RTC_BASE 0x8005C000
+#define HW_RTC_BASE_SIZE 0x2000
 
 /*
  * Real-Time Clock Control Register.

Added files:

Index: src/sys/arch/arm/imx/imx23_digfilt.c
diff -u /dev/null src/sys/arch/arm/imx/imx23_digfilt.c:1.1
--- /dev/null	Sat Jan 10 12:16:28 2015
+++ src/sys/arch/arm/imx/imx23_digfilt.c	Sat Jan 10 12:16:28 2015
@@ -0,0 +1,1130 @@
+/* $Id: imx23_digfilt.c,v 1.1 2015/01/10 12:16:28 jmcneill Exp $ */
+
+/*
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Petri Laakso.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/mutex.h>
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+#include <dev/auconv.h>
+#include <sys/mallocvar.h>
+#include <arm/imx/imx23_digfiltreg.h>
+#include <arm/imx/imx23_rtcvar.h>
+#include <arm/imx/imx23_clkctrlvar.h>
+#include <arm/imx/imx23_apbdmavar.h>
+#include <arm/imx/imx23_icollreg.h>
+#include <arm/imx/imx23var.h>
+
+#include <arm/pic/picvar.h>
+
+/* Autoconf. */
+static int digfilt_match(device_t, cfdata_t, void *);
+static void digfilt_attach(device_t, device_t, void *);
+static int digfilt_activate(device_t, enum devact);
+
+/* Audio driver interface. */
+static int digfilt_drain(void *);
+static int digfilt_query_encoding(void *, struct audio_encoding *);
+static int digfilt_set_params(void *, int, int, audio_params_t *,
+    audio_params_t *, stream_filter_list_t *,
+    stream_filter_list_t *);
+static int digfilt_round_blocksize(void *, int, int, const audio_params_t *);
+static int digfilt_init_output(void *, void *, int );
+static int digfilt_start_output(void *, void *, int, void (*)(void *), void *);
+static int digfilt_halt_output(void *);
+static int digfilt_getdev(void *, struct audio_device *);
+static int digfilt_set_port(void *, mixer_ctrl_t *);
+static int digfilt_get_port(void *, mixer_ctrl_t *);
+static int digfilt_query_devinfo(void *, mixer_devinfo_t *);
+static void *digfilt_allocm(void *, int, size_t);
+static void digfilt_freem(void *, void *, size_t);
+static size_t digfilt_round_buffersize(void *, int, size_t);
+static int digfilt_get_props(void *);
+static void digfilt_get_locks(void *, kmutex_t **, kmutex_t **);
+
+/* IRQs */
+static int dac_error_intr(void *);
+static int dac_dma_intr(void *);
+
+struct digfilt_softc;
+
+/* Audio out. */
+static void *digfilt_ao_alloc_dmachain(void *, size_t);
+static void digfilt_ao_apply_mutes(struct digfilt_softc *);
+static void digfilt_ao_init(struct digfilt_softc *);
+static void digfilt_ao_reset(struct digfilt_softc *);
+static void digfilt_ao_set_rate(struct digfilt_softc *, int);
+
+/* Audio in. */
+#if 0
+static void digfilt_ai_reset(struct digfilt_softc *);
+#endif
+
+#define DIGFILT_DMA_NSEGS 1
+#define DIGFILT_BLOCKSIZE_MAX 4096
+#define DIGFILT_BLOCKSIZE_ROUND 512
+#define DIGFILT_DMA_CHAIN_LENGTH 3
+#define DIGFILT_DMA_CHANNEL 1
+#define DIGFILT_MUTE_DAC 1
+#define DIGFILT_MUTE_HP 2
+#define DIGFILT_MUTE_LINE 4
+#define DIGFILT_SOFT_RST_LOOP 455	/* At least 1 us. */
+
+#define AO_RD(sc, reg)							\
+	bus_space_read_4(sc->sc_iot, sc->sc_aohdl, (reg))
+#define AO_WR(sc, reg, val)						\
+	bus_space_write_4(sc->sc_iot, sc->sc_aohdl, (reg), (val))
+#define AI_RD(sc, reg)							\
+	bus_space_read_4(sc->sc_iot, sc->sc_aihdl, (reg))
+#define AI_WR(sc, reg, val)						\
+	bus_space_write_4(sc->sc_iot, sc->sc_aihdl, (reg), (val))
+
+struct digfilt_softc {
+	device_t sc_dev;
+	device_t sc_audiodev;
+	struct audio_format sc_format;
+	struct audio_encoding_set *sc_encodings;
+	bus_space_handle_t sc_aihdl;
+	bus_space_handle_t sc_aohdl;
+	apbdma_softc_t sc_dmac;
+	bus_dma_tag_t sc_dmat;
+	bus_dmamap_t sc_dmamp;
+	bus_dmamap_t sc_c_dmamp;
+	bus_dma_segment_t sc_ds[DIGFILT_DMA_NSEGS];
+	bus_dma_segment_t sc_c_ds[DIGFILT_DMA_NSEGS];
+	bus_space_handle_t sc_hdl;
+	kmutex_t sc_intr_lock;
+	bus_space_tag_t	sc_iot;
+	kmutex_t sc_lock;
+	audio_params_t sc_pparam;
+	void *sc_buffer;
+	void *sc_dmachain;
+	void *sc_intarg;
+	void (*sc_intr)(void*);
+	uint8_t sc_mute;
+	uint8_t sc_cmd_index;
+};
+
+CFATTACH_DECL3_NEW(digfilt,
+	sizeof(struct digfilt_softc),
+	digfilt_match,
+	digfilt_attach,
+	NULL,
+	digfilt_activate,
+	NULL,
+	NULL,
+	0);
+
+static const struct audio_hw_if digfilt_hw_if = {
+	.open = NULL,
+	.close = NULL,
+	.drain = digfilt_drain,
+	.query_encoding = digfilt_query_encoding,
+	.set_params = digfilt_set_params,
+	.round_blocksize = digfilt_round_blocksize,
+	.commit_settings = NULL,
+	.init_output = digfilt_init_output,
+	.init_input = NULL,
+	.start_output = digfilt_start_output,
+	.start_input = NULL,
+	.halt_output = digfilt_halt_output,
+	.speaker_ctl = NULL,
+	.getdev = digfilt_getdev,
+	.setfd = NULL,
+	.set_port = digfilt_set_port,
+	.get_port = digfilt_get_port,
+	.query_devinfo = digfilt_query_devinfo,
+	.allocm = digfilt_allocm,
+	.freem = digfilt_freem,
+	.round_buffersize = digfilt_round_buffersize,
+	.mappage = NULL,
+	.get_props = digfilt_get_props,
+	.trigger_output = NULL,
+	.trigger_input = NULL,
+	.dev_ioctl = NULL,
+	.get_locks = digfilt_get_locks
+};
+
+enum {
+	DIGFILT_OUTPUT_CLASS,
+	DIGFILT_OUTPUT_DAC_VOLUME,
+	DIGFILT_OUTPUT_DAC_MUTE,
+	DIGFILT_OUTPUT_HP_VOLUME,
+	DIGFILT_OUTPUT_HP_MUTE,
+	DIGFILT_OUTPUT_LINE_VOLUME,
+	DIGFILT_OUTPUT_LINE_MUTE,
+	DIGFILT_ENUM_LAST
+};
+
+static int
+digfilt_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct apb_attach_args *aa = aux;
+
+	if (aa->aa_addr == HW_DIGFILT_BASE && aa->aa_size == HW_DIGFILT_SIZE)
+		return 1;
+	else
+		return 0;
+}
+
+static void
+digfilt_attach(device_t parent, device_t self, void *aux)
+{
+	struct apb_softc *sc_parent = device_private(parent);
+	struct digfilt_softc *sc = device_private(self);
+	struct apb_attach_args *aa = aux;
+	static int digfilt_attached = 0;
+	int error;
+	uint32_t v;
+	void *intr;
+
+	sc->sc_dev = self;
+	sc->sc_iot = aa->aa_iot;
+	sc->sc_dmat = aa->aa_dmat;
+
+	/* This driver requires DMA functionality from the bus.
+	 * Parent bus passes handle to the DMA controller instance. */
+	if (sc_parent->dmac == NULL) {
+		aprint_error_dev(sc->sc_dev, "DMA functionality missing\n");
+		return;
+	}
+	sc->sc_dmac = device_private(sc_parent->dmac);
+	
+	if (aa->aa_addr == HW_DIGFILT_BASE && digfilt_attached) {
+		aprint_error_dev(sc->sc_dev, "DIGFILT already attached\n");
+		return;
+	}
+
+	/* Allocate DMA for audio buffer. */
+	error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, DIGFILT_DMA_NSEGS,
+		MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &sc->sc_dmamp);
+	if (error) {
+		aprint_error_dev(sc->sc_dev,
+		    "Unable to allocate DMA handle\n");
+		return;
+	}
+
+	/* Allocate for DMA chain. */
+	error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, DIGFILT_DMA_NSEGS,
+		MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &sc->sc_c_dmamp);
+	if (error) {
+		aprint_error_dev(sc->sc_dev,
+		    "Unable to allocate DMA handle\n");
+		return;
+	}
+
+	/* Map DIGFILT bus space. */
+	if (bus_space_map(sc->sc_iot, HW_DIGFILT_BASE, HW_DIGFILT_SIZE, 0,
+	    &sc->sc_hdl)) {
+		aprint_error_dev(sc->sc_dev,
+		    "Unable to map DIGFILT bus space\n");
+		return;
+	}
+
+	/* Map AUDIOOUT subregion from parent bus space. */
+	if (bus_space_subregion(sc->sc_iot, sc->sc_hdl,
+	    (HW_AUDIOOUT_BASE - HW_DIGFILT_BASE), HW_AUDIOOUT_SIZE,
+	    &sc->sc_aohdl)) {
+		aprint_error_dev(sc->sc_dev,
+			"Unable to submap AUDIOOUT bus space\n");
+		return;
+	}
+
+	/* Map AUDIOIN subregion from parent bus space. */
+	if (bus_space_subregion(sc->sc_iot, sc->sc_hdl,
+	    (HW_AUDIOIN_BASE - HW_DIGFILT_BASE), HW_AUDIOIN_SIZE,
+	    &sc->sc_aihdl)) {
+		aprint_error_dev(sc->sc_dev,
+			"Unable to submap AUDIOIN bus space\n");
+		return;
+	}
+
+	/* Enable clocks to the DIGFILT block. */
+	clkctrl_en_filtclk();
+	delay(10);
+
+	digfilt_ao_reset(sc);	/* Reset AUDIOOUT. */
+	/* Not yet: digfilt_ai_reset(sc); */
+	
+	v = AO_RD(sc, HW_AUDIOOUT_VERSION);
+	aprint_normal(": DIGFILT Block v%" __PRIuBIT ".%" __PRIuBIT
+		".%" __PRIuBIT "\n",
+		__SHIFTOUT(v, HW_AUDIOOUT_VERSION_MAJOR),
+		__SHIFTOUT(v, HW_AUDIOOUT_VERSION_MINOR),
+		__SHIFTOUT(v, HW_AUDIOOUT_VERSION_STEP));
+
+	digfilt_ao_init(sc);
+	digfilt_ao_set_rate(sc, 44100);	/* Default sample rate 44.1 kHz. */
+
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+	/* HW supported formats. */
+	sc->sc_format.mode = AUMODE_PLAY|AUMODE_RECORD;
+	sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE;
+	sc->sc_format.validbits = 16;
+	sc->sc_format.precision = 16;
+	sc->sc_format.channels = 2;
+	sc->sc_format.channel_mask = AUFMT_STEREO;
+	sc->sc_format.frequency_type = 8;
+	sc->sc_format.frequency[0] = 8000;
+	sc->sc_format.frequency[1] = 11025;
+	sc->sc_format.frequency[2] = 12000;
+	sc->sc_format.frequency[3] = 16000;
+	sc->sc_format.frequency[4] = 22050;
+	sc->sc_format.frequency[5] = 24000;
+	sc->sc_format.frequency[6] = 32000;
+	sc->sc_format.frequency[7] = 44100;
+
+	if (auconv_create_encodings(&sc->sc_format, 1, &sc->sc_encodings)) {
+		aprint_error_dev(self, "could not create encodings\n");
+		return;
+	}
+
+	sc->sc_audiodev = audio_attach_mi(&digfilt_hw_if, sc, sc->sc_dev);
+
+	/* Default mutes. */
+	sc->sc_mute = DIGFILT_MUTE_LINE;
+	digfilt_ao_apply_mutes(sc);
+
+	/* Allocate DMA safe memory for the DMA chain. */
+	sc->sc_dmachain = digfilt_ao_alloc_dmachain(sc,
+		sizeof(struct apbdma_command) * DIGFILT_DMA_CHAIN_LENGTH);
+	if (sc->sc_dmachain == NULL) {
+		aprint_error_dev(self, "digfilt_ao_alloc_dmachain failed\n");
+		return;
+	}
+
+	intr = intr_establish(IRQ_DAC_DMA, IPL_SCHED, IST_LEVEL, dac_dma_intr,
+			sc);
+	if (intr == NULL) {
+		aprint_error_dev(sc->sc_dev,
+			"Unable to establish IRQ for DAC_DMA\n");
+		return;
+	}
+
+	intr = intr_establish(IRQ_DAC_ERROR, IPL_SCHED, IST_LEVEL,
+		dac_error_intr, sc);
+	if (intr == NULL) {
+		aprint_error_dev(sc->sc_dev,
+			"Unable to establish IRQ for DAC_ERROR\n");
+		return;
+	}
+
+	/* Initialize DMA channel. */
+	apbdma_chan_init(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
+
+	digfilt_attached = 1;
+
+	return;
+}
+
+static int
+digfilt_activate(device_t self, enum devact act)
+{
+	return EOPNOTSUPP;
+}
+
+static int
+digfilt_drain(void *priv)
+{
+
+	struct digfilt_softc *sc = priv;
+
+	apbdma_wait(sc->sc_dmac, 1);
+	sc->sc_cmd_index = 0;
+	
+	return 0;
+}
+
+static int
+digfilt_query_encoding(void *priv, struct audio_encoding *ae)
+{
+	struct digfilt_softc *sc = priv;
+	return auconv_query_encoding(sc->sc_encodings, ae);
+}
+
+static int
+digfilt_set_params(void *priv, int setmode, int usemode,
+    audio_params_t *play, audio_params_t *rec,
+    stream_filter_list_t *pfil, stream_filter_list_t *rfil)
+{
+	struct digfilt_softc *sc = priv;
+	int index;
+
+	if (play && (setmode & AUMODE_PLAY)) {
+		index = auconv_set_converter(&sc->sc_format, 1,
+		    AUMODE_PLAY, play, true, pfil);
+		if (index < 0)
+			return EINVAL;
+		sc->sc_pparam = pfil->req_size > 0 ?
+		    pfil->filters[0].param :
+		    *play;
+
+		/* At this point bitrate should be figured out. */
+		digfilt_ao_set_rate(sc, sc->sc_pparam.sample_rate);
+	}
+
+	return 0;
+}
+
+static int
+digfilt_round_blocksize(void *priv, int bs, int mode,
+const audio_params_t *param)
+{
+	int blocksize;
+
+	if (bs > DIGFILT_BLOCKSIZE_MAX)
+		blocksize = DIGFILT_BLOCKSIZE_MAX;
+	else
+		blocksize = bs & ~(DIGFILT_BLOCKSIZE_ROUND-1);
+
+	return blocksize;
+}
+
+static int
+digfilt_init_output(void *priv, void *buffer, int size)
+{
+	struct digfilt_softc *sc = priv;
+	apbdma_command_t dma_cmd;
+	int i;
+	dma_cmd = sc->sc_dmachain;
+	sc->sc_cmd_index = 0;
+
+	/*
+	 * Build circular DMA command chain template for later use.
+	 */
+	for (i = 0; i < DIGFILT_DMA_CHAIN_LENGTH; i++) {
+		/* Last entry loops back to first. */
+		if (i == DIGFILT_DMA_CHAIN_LENGTH - 1)
+			dma_cmd[i].next = (void *)(sc->sc_c_dmamp->dm_segs[0].ds_addr);
+		else
+			dma_cmd[i].next = (void *)(sc->sc_c_dmamp->dm_segs[0].ds_addr + (sizeof(struct apbdma_command) * (1 + i)));
+
+		dma_cmd[i].control = __SHIFTIN(DIGFILT_BLOCKSIZE_MAX,  APBDMA_CMD_XFER_COUNT) |
+		    __SHIFTIN(1, APBDMA_CMD_CMDPIOWORDS) |
+		    APBDMA_CMD_SEMAPHORE |
+		    APBDMA_CMD_IRQONCMPLT |
+		    APBDMA_CMD_CHAIN |
+		    __SHIFTIN(APBDMA_CMD_DMA_READ, APBDMA_CMD_COMMAND);
+
+		dma_cmd[i].buffer = (void *)(sc->sc_c_dmamp->dm_segs[0].ds_addr);
+
+		dma_cmd[i].pio_words[0] = HW_AUDIOOUT_CTRL_WORD_LENGTH |
+		    HW_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN |
+		    HW_AUDIOOUT_CTRL_RUN;
+
+	}
+
+	apbdma_chan_set_chain(sc->sc_dmac, DIGFILT_DMA_CHANNEL, sc->sc_c_dmamp);
+
+	return 0;
+}
+
+static int
+digfilt_start_output(void *priv, void *start, int bs, void (*intr)(void*), void *intarg)
+{
+	struct digfilt_softc *sc = priv;
+	apbdma_command_t dma_cmd;
+	bus_addr_t offset;
+
+	sc->sc_intr = intr;
+	sc->sc_intarg = intarg;
+	dma_cmd = sc->sc_dmachain;
+
+	offset = (bus_addr_t)start - (bus_addr_t)sc->sc_buffer;
+
+	dma_cmd[sc->sc_cmd_index].buffer =
+	    (void *)((bus_addr_t)sc->sc_dmamp->dm_segs[0].ds_addr + offset);
+
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamp, offset, bs, BUS_DMASYNC_PREWRITE);
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_c_dmamp,
+	    sizeof(struct apbdma_command) * sc->sc_cmd_index, sizeof(struct apbdma_command), BUS_DMASYNC_PREWRITE);
+
+	sc->sc_cmd_index++;
+	if (sc->sc_cmd_index > DIGFILT_DMA_CHAIN_LENGTH - 1)
+		sc->sc_cmd_index = 0;
+
+	apbdma_run(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
+
+	return 0;
+}
+
+static int
+digfilt_halt_output(void *priv)
+{
+	return 0;
+}
+
+static int
+digfilt_getdev(void *priv, struct audio_device *ad)
+{
+	struct digfilt_softc *sc = priv;
+
+	strncpy(ad->name, device_xname(sc->sc_dev), MAX_AUDIO_DEV_LEN);
+	strncpy(ad->version, "", MAX_AUDIO_DEV_LEN);
+	strncpy(ad->config, "", MAX_AUDIO_DEV_LEN);
+
+	return 0;
+}
+
+static int
+digfilt_set_port(void *priv, mixer_ctrl_t *mc)
+{
+	struct digfilt_softc *sc = priv;
+	uint32_t val;
+	uint8_t nvol;
+
+	switch (mc->dev) {
+	case DIGFILT_OUTPUT_DAC_VOLUME:
+		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
+		val &= ~(HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT |
+		    HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
+
+		/* DAC volume field is 8 bits. */
+		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
+		if (nvol > 0xff)
+			nvol = 0xff;
+
+		val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT);
+
+		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
+		if (nvol > 0xff)
+			nvol = 0xff;
+
+		val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
+
+		AO_WR(sc, HW_AUDIOOUT_DACVOLUME, val);
+
+		return 0;
+
+	case DIGFILT_OUTPUT_HP_VOLUME:
+		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
+		val &= ~(HW_AUDIOOUT_HPVOL_VOL_LEFT |
+		    HW_AUDIOOUT_HPVOL_VOL_RIGHT);
+
+		/* HP volume field is 7 bits. */
+		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
+		if (nvol > 0x7f)
+			nvol = 0x7f;
+
+		nvol = ~nvol;
+		val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_LEFT);
+
+		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
+		if (nvol > 0x7f)
+			nvol = 0x7f;
+
+		nvol = ~nvol;
+		val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_RIGHT);
+
+		AO_WR(sc, HW_AUDIOOUT_HPVOL, val);
+
+		return 0;
+
+	case DIGFILT_OUTPUT_LINE_VOLUME:
+		return 1;
+
+	case DIGFILT_OUTPUT_DAC_MUTE:
+		if (mc->un.ord)
+			sc->sc_mute |= DIGFILT_MUTE_DAC;
+		else
+			sc->sc_mute &= ~DIGFILT_MUTE_DAC;
+
+		digfilt_ao_apply_mutes(sc);
+
+		return 0;
+
+	case DIGFILT_OUTPUT_HP_MUTE:
+		if (mc->un.ord)
+			sc->sc_mute |= DIGFILT_MUTE_HP;
+		else
+			sc->sc_mute &= ~DIGFILT_MUTE_HP;
+
+		digfilt_ao_apply_mutes(sc);
+
+		return 0;
+
+	case DIGFILT_OUTPUT_LINE_MUTE:
+		if (mc->un.ord)
+			sc->sc_mute |= DIGFILT_MUTE_LINE;
+		else
+			sc->sc_mute &= ~DIGFILT_MUTE_LINE;
+
+		digfilt_ao_apply_mutes(sc);
+
+		return 0;
+	}
+
+	return ENXIO;
+}
+
+static int
+digfilt_get_port(void *priv, mixer_ctrl_t *mc)
+{
+	struct digfilt_softc *sc = priv;
+	uint32_t val;
+	uint8_t nvol;
+
+        switch (mc->dev) {
+        case DIGFILT_OUTPUT_DAC_VOLUME:
+		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
+
+		nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT);
+                mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = nvol;
+
+		nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
+                mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = nvol;
+
+                return 0;
+
+        case DIGFILT_OUTPUT_HP_VOLUME:
+		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
+
+		nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_LEFT);
+		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = ~nvol & 0x7f;
+
+		nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_RIGHT);
+		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = ~nvol & 0x7f;
+
+		return 0;
+
+	case DIGFILT_OUTPUT_LINE_VOLUME:
+		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 255;
+		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 255;
+
+		return 0;
+
+	case DIGFILT_OUTPUT_DAC_MUTE:
+		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
+
+		mc->un.ord = (val & (HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
+		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT)) ? 1 : 0;
+
+		return 0;
+
+	case DIGFILT_OUTPUT_HP_MUTE:
+		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
+
+		mc->un.ord = (val & HW_AUDIOOUT_HPVOL_MUTE) ? 1 : 0;
+
+		return 0;
+
+	case DIGFILT_OUTPUT_LINE_MUTE:
+		val = AO_RD(sc, HW_AUDIOOUT_SPEAKERCTRL);
+
+		mc->un.ord = (val & HW_AUDIOOUT_SPEAKERCTRL_MUTE) ? 1 : 0;
+
+		return 0;
+        }
+
+        return ENXIO;
+}
+
+static int
+digfilt_query_devinfo(void *priv, mixer_devinfo_t *di)
+{
+
+	switch (di->index) {
+	case DIGFILT_OUTPUT_CLASS:
+		di->mixer_class = DIGFILT_OUTPUT_CLASS;
+		strcpy(di->label.name, AudioCoutputs);
+		di->type = AUDIO_MIXER_CLASS;
+		di->next = di->prev = AUDIO_MIXER_LAST;
+		return 0;
+
+	case DIGFILT_OUTPUT_DAC_VOLUME:
+		di->mixer_class = DIGFILT_OUTPUT_CLASS;
+		strcpy(di->label.name, AudioNdac);
+		di->type = AUDIO_MIXER_VALUE;
+		di->prev = AUDIO_MIXER_LAST;
+		di->next = DIGFILT_OUTPUT_DAC_MUTE;
+		di->un.v.num_channels = 2;
+		strcpy(di->un.v.units.name, AudioNvolume);
+		return 0;
+
+	case DIGFILT_OUTPUT_DAC_MUTE:
+		di->mixer_class = DIGFILT_OUTPUT_CLASS;
+		di->type = AUDIO_MIXER_ENUM;
+		di->prev = DIGFILT_OUTPUT_DAC_VOLUME;
+		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 = 1;
+		strlcpy(di->un.e.member[1].label.name, AudioNoff,
+		    sizeof(di->un.e.member[1].label.name));
+		di->un.e.member[1].ord = 0;
+		return 0;
+
+	case DIGFILT_OUTPUT_HP_VOLUME:
+		di->mixer_class = DIGFILT_OUTPUT_CLASS;
+		strcpy(di->label.name, AudioNheadphone);
+		di->type = AUDIO_MIXER_VALUE;
+		di->prev = AUDIO_MIXER_LAST;
+		di->next = DIGFILT_OUTPUT_HP_MUTE;
+		di->un.v.num_channels = 2;
+		strcpy(di->un.v.units.name, AudioNvolume);
+		return 0;
+
+	case DIGFILT_OUTPUT_HP_MUTE:
+		di->mixer_class = DIGFILT_OUTPUT_CLASS;
+		di->type = AUDIO_MIXER_ENUM;
+		di->prev = DIGFILT_OUTPUT_HP_VOLUME;
+		di->next = AUDIO_MIXER_LAST;
+		goto mute;
+
+	case DIGFILT_OUTPUT_LINE_VOLUME:
+		di->mixer_class = DIGFILT_OUTPUT_CLASS;
+		strcpy(di->label.name, AudioNline);
+		di->type = AUDIO_MIXER_VALUE;
+		di->prev = AUDIO_MIXER_LAST;
+		di->next = DIGFILT_OUTPUT_LINE_MUTE;
+		di->un.v.num_channels = 2;
+		strcpy(di->un.v.units.name, AudioNvolume);
+		return 0;
+
+	case DIGFILT_OUTPUT_LINE_MUTE:
+		di->mixer_class = DIGFILT_OUTPUT_CLASS;
+		di->type = AUDIO_MIXER_ENUM;
+		di->prev = DIGFILT_OUTPUT_LINE_VOLUME;
+		di->next = AUDIO_MIXER_LAST;
+		goto mute;
+	}
+
+        return ENXIO;
+}
+
+static void *
+digfilt_allocm(void *priv, int direction, size_t size)
+{
+	struct digfilt_softc *sc = priv;
+	int rsegs;
+	int error;
+
+	sc->sc_buffer = NULL;
+
+	/*
+	 * AUMODE_PLAY is DMA from memory to device.
+	 */
+	if (direction != AUMODE_PLAY)
+		return NULL;
+
+	error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &sc->sc_ds[0], DIGFILT_DMA_NSEGS, &rsegs, BUS_DMA_NOWAIT);
+	if (error) {
+		aprint_error_dev(sc->sc_dev,
+		    "bus_dmamem_alloc: %d\n", error);
+		goto out;
+	}
+
+	error = bus_dmamem_map(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS, size, &sc->sc_buffer, BUS_DMA_NOWAIT);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "bus_dmamem_map: %d\n", error);
+		goto dmamem_free;
+	}
+
+	/* After load sc_dmamp is valid. */
+	error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamp, sc->sc_buffer, size, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "bus_dmamap_load: %d\n", error);
+		goto dmamem_unmap;
+	}
+
+	memset(sc->sc_buffer, 0x00, size);
+
+	return sc->sc_buffer;
+
+dmamem_unmap:
+	bus_dmamem_unmap(sc->sc_dmat, sc->sc_buffer, size);
+dmamem_free:
+	bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS);
+out:
+	return NULL;
+}
+
+static void
+digfilt_freem(void *priv, void *kvap, size_t size)
+{
+	struct digfilt_softc *sc = priv;
+
+	bus_dmamem_unmap(sc->sc_dmat, kvap, size);
+	bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS);
+
+	return;
+}
+
+static size_t
+digfilt_round_buffersize(void *hdl, int direction, size_t bs)
+{
+	int bufsize;
+	
+	bufsize = bs & ~(DIGFILT_BLOCKSIZE_MAX-1);
+
+	return bufsize;
+}
+
+static int
+digfilt_get_props(void *sc)
+{
+	return (AUDIO_PROP_PLAYBACK | AUDIO_PROP_INDEPENDENT);
+}
+
+static void
+digfilt_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread)
+{
+	struct digfilt_softc *sc = priv;
+
+	*intr = &sc->sc_intr_lock;
+	*thread = &sc->sc_lock;
+
+	return;
+}
+
+/*
+ * IRQ for DAC error.
+ */
+static int
+dac_error_intr(void *arg)
+{
+	struct digfilt_softc *sc = arg;
+	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ);
+	return 1;
+}
+
+/*
+ * IRQ from DMA.
+ */
+static int
+dac_dma_intr(void *arg)
+{
+	struct digfilt_softc *sc = arg;
+
+	unsigned int dma_err;
+
+	mutex_enter(&sc->sc_intr_lock);
+
+	dma_err = apbdma_intr_status(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
+
+	if (dma_err) {
+		apbdma_ack_error_intr(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
+	}
+
+	sc->sc_intr(sc->sc_intarg);
+	apbdma_ack_intr(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
+
+	mutex_exit(&sc->sc_intr_lock);
+
+	/* Return 1 to acknowledge IRQ. */
+	return 1;
+}
+
+static void *
+digfilt_ao_alloc_dmachain(void *priv, size_t size)
+{
+	struct digfilt_softc *sc = priv;
+	int rsegs;
+	int error;
+	void *kvap;
+
+	kvap = NULL;
+
+	error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &sc->sc_c_ds[0], DIGFILT_DMA_NSEGS, &rsegs, BUS_DMA_NOWAIT);
+	if (error) {
+		aprint_error_dev(sc->sc_dev,
+		    "bus_dmamem_alloc: %d\n", error);
+		goto out;
+	}
+
+	error = bus_dmamem_map(sc->sc_dmat, sc->sc_c_ds, DIGFILT_DMA_NSEGS, size, &kvap, BUS_DMA_NOWAIT);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "bus_dmamem_map: %d\n", error);
+		goto dmamem_free;
+	}
+
+	/* After load sc_c_dmamp is valid. */
+	error = bus_dmamap_load(sc->sc_dmat, sc->sc_c_dmamp, kvap, size, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "bus_dmamap_load: %d\n", error);
+		goto dmamem_unmap;
+	}
+
+	memset(kvap, 0x00, size);
+
+	return kvap;
+
+dmamem_unmap:
+	bus_dmamem_unmap(sc->sc_dmat, kvap, size);
+dmamem_free:
+	bus_dmamem_free(sc->sc_dmat, sc->sc_c_ds, DIGFILT_DMA_NSEGS);
+out:
+
+	return kvap;
+}
+
+static void
+digfilt_ao_apply_mutes(struct digfilt_softc *sc)
+{
+
+	/* DAC. */
+	if (sc->sc_mute & DIGFILT_MUTE_DAC) {
+		AO_WR(sc, HW_AUDIOOUT_DACVOLUME_SET,
+		    HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
+		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT
+		);
+	
+	} else {
+		AO_WR(sc, HW_AUDIOOUT_DACVOLUME_CLR,
+		    HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
+		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT
+		);
+	}
+
+	/* HP. */
+	if (sc->sc_mute & DIGFILT_MUTE_HP)
+		AO_WR(sc, HW_AUDIOOUT_HPVOL_SET, HW_AUDIOOUT_HPVOL_MUTE);
+	else
+		AO_WR(sc, HW_AUDIOOUT_HPVOL_CLR, HW_AUDIOOUT_HPVOL_MUTE);
+
+	/* Line. */
+	if (sc->sc_mute & DIGFILT_MUTE_LINE)
+		AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_SET,
+		    HW_AUDIOOUT_SPEAKERCTRL_MUTE);
+	else
+		AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_CLR,
+		    HW_AUDIOOUT_SPEAKERCTRL_MUTE);
+
+	return;
+}
+
+/*
+ * Initialize audio system.
+ */
+static void
+digfilt_ao_init(struct digfilt_softc *sc)
+{
+
+	AO_WR(sc, HW_AUDIOOUT_ANACLKCTRL_CLR, HW_AUDIOOUT_ANACLKCTRL_CLKGATE);
+	while ((AO_RD(sc, HW_AUDIOOUT_ANACLKCTRL) &
+	    HW_AUDIOOUT_ANACLKCTRL_CLKGATE));
+
+	/* Hold headphones outputs at ground. */
+	AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND);
+
+	/* Remove pulldown resistors on headphone outputs. */
+	rtc_release_gnd(1);
+
+	/* Release pull down */
+	AO_WR(sc, HW_AUDIOOUT_ANACTRL_CLR, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND);
+
+	AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_CLASSAB);
+
+	/* Enable Modules. */
+	AO_WR(sc, HW_AUDIOOUT_PWRDN_CLR,
+	    HW_AUDIOOUT_PWRDN_RIGHT_ADC |
+	    HW_AUDIOOUT_PWRDN_DAC |
+	    HW_AUDIOOUT_PWRDN_CAPLESS |
+	    HW_AUDIOOUT_PWRDN_HEADPHONE
+	);
+
+	return;
+}
+
+/*
+ * Reset the AUDIOOUT block.
+ *
+ * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
+ */
+static void
+digfilt_ao_reset(struct digfilt_softc *sc)
+{
+	unsigned int loop;
+
+	/* Prepare for soft-reset by making sure that SFTRST is not currently
+	* asserted. Also clear CLKGATE so we can wait for its assertion below.
+	*/
+	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST);
+
+	/* Wait at least a microsecond for SFTRST to deassert. */
+	loop = 0;
+	while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) ||
+	    (loop < DIGFILT_SOFT_RST_LOOP))
+		loop++;
+
+	/* Clear CLKGATE so we can wait for its assertion below. */
+	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE);
+
+	/* Soft-reset the block. */
+	AO_WR(sc, HW_AUDIOOUT_CTRL_SET, HW_AUDIOOUT_CTRL_SFTRST);
+
+	/* Wait until clock is in the gated state. */
+	while (!(AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE));
+
+	/* Bring block out of reset. */
+	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST);
+
+	loop = 0;
+	while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) ||
+	    (loop < DIGFILT_SOFT_RST_LOOP))
+		loop++;
+
+	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE);
+
+	/* Wait until clock is in the NON-gated state. */
+	while (AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE);
+
+	return;
+}
+
+static void
+digfilt_ao_set_rate(struct digfilt_softc *sc, int sr)
+{
+	uint32_t val;
+
+
+	val = AO_RD(sc, HW_AUDIOOUT_DACSRR);
+
+
+	val &= ~(HW_AUDIOOUT_DACSRR_BASEMULT | HW_AUDIOOUT_DACSRR_SRC_HOLD |
+	    HW_AUDIOOUT_DACSRR_SRC_INT | HW_AUDIOOUT_DACSRR_SRC_FRAC);
+
+	switch(sr) {
+	case 8000:
+		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
+		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
+		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
+		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
+		break;
+	case 11025:
+		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
+		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
+		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
+		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
+		break;
+	case 12000:
+		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
+		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
+		    __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) |
+		    __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC));
+		break;
+	case 16000:
+		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
+		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
+		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
+		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
+		break;
+	case 22050:
+		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
+		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
+		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
+		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
+		break;
+	case 24000:
+		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
+		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
+		    __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) |
+		    __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC));
+		break;
+	case 32000:
+		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
+		    __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
+		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
+		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
+		break;
+	default:
+		aprint_error_dev(sc->sc_dev, "uknown sample rate: %d\n", sr);
+	case 44100:
+		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
+		    __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
+		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
+		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
+		break;
+	}
+
+	AO_WR(sc, HW_AUDIOOUT_DACSRR, val);
+
+	val = AO_RD(sc, HW_AUDIOOUT_DACSRR);
+
+	return;
+}
+#if 0
+/*
+ * Reset the AUDIOIN block.
+ *
+ * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
+ */
+static void
+digfilt_ai_reset(struct digfilt_softc *sc)
+{
+	unsigned int loop;
+
+	/* Prepare for soft-reset by making sure that SFTRST is not currently
+	* asserted. Also clear CLKGATE so we can wait for its assertion below.
+	*/
+	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_SFTRST);
+
+	/* Wait at least a microsecond for SFTRST to deassert. */
+	loop = 0;
+	while ((AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_SFTRST) ||
+	    (loop < DIGFILT_SOFT_RST_LOOP))
+		loop++;
+
+	/* Clear CLKGATE so we can wait for its assertion below. */
+	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_CLKGATE);
+
+	/* Soft-reset the block. */
+	AI_WR(sc, HW_AUDIOIN_CTRL_SET, HW_AUDIOIN_CTRL_SFTRST);
+
+	/* Wait until clock is in the gated state. */
+	while (!(AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_CLKGATE));
+
+	/* Bring block out of reset. */
+	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_SFTRST);
+
+	loop = 0;
+	while ((AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_SFTRST) ||
+	    (loop < DIGFILT_SOFT_RST_LOOP))
+		loop++;
+
+	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_CLKGATE);
+
+	/* Wait until clock is in the NON-gated state. */
+	while (AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_CLKGATE);
+
+	return;
+}
+#endif
Index: src/sys/arch/arm/imx/imx23_digfiltreg.h
diff -u /dev/null src/sys/arch/arm/imx/imx23_digfiltreg.h:1.1
--- /dev/null	Sat Jan 10 12:16:28 2015
+++ src/sys/arch/arm/imx/imx23_digfiltreg.h	Sat Jan 10 12:16:28 2015
@@ -0,0 +1,382 @@
+/* $Id: imx23_digfiltreg.h,v 1.1 2015/01/10 12:16:28 jmcneill Exp $ */
+
+/*
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Petri Laakso.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_IMX_IMX23_AUDIOOUTREG_H_
+#define _ARM_IMX_IMX23_AUDIOOUTREG_H_
+
+#include <sys/cdefs.h>
+
+#define HW_DIGFILT_BASE		0x80048000
+#define HW_DIGFILT_SIZE		0x8000 /* 32 kB */
+
+#define HW_AUDIOOUT_BASE	0x80048000
+#define HW_AUDIOOUT_SIZE	0x2000 /* 8 kB */
+
+#define HW_AUDIOIN_BASE		0x8004C000
+#define HW_AUDIOIN_SIZE		0x2000 /* 8 kB */
+
+/*
+ * AUDIOIN Control Register.
+ */
+#define HW_AUDIOIN_CTRL		0x000
+#define HW_AUDIOIN_CTRL_SET	0x004
+#define HW_AUDIOIN_CTRL_CLR	0x008
+#define HW_AUDIOIN_CTRL_TOG	0x00C
+
+#define HW_AUDIOIN_CTRL_SFTRST			__BIT(31)
+#define HW_AUDIOIN_CTRL_CLKGATE			__BIT(30)
+#define HW_AUDIOIN_CTRL_RSRVD3			__BITS(29, 21)
+#define HW_AUDIOIN_CTRL_DMAWAIT_COUNT		__BITS(20, 16)
+#define HW_AUDIOIN_CTRL_RSRVD1			__BITS(15, 11)
+#define HW_AUDIOIN_CTRL_LR_SWAP			__BIT(10)
+#define HW_AUDIOIN_CTRL_EDGE_SYNC		__BIT(9)
+#define HW_AUDIOIN_CTRL_INVERT_1BIT		__BIT(8)
+#define HW_AUDIOIN_CTRL_OFFSET_ENABLE		__BIT(7)
+#define HW_AUDIOIN_CTRL_HPF_ENABLE		__BIT(6)
+#define HW_AUDIOIN_CTRL_WORD_LENGTH		__BIT(5)
+#define HW_AUDIOIN_CTRL_LOOPBACK		__BIT(4)
+#define HW_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ	__BIT(3)
+#define HW_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ	__BIT(2)
+#define HW_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN	__BIT(1)
+#define HW_AUDIOIN_CTRL_RUN			__BIT(0)
+
+/*
+ * AUDIOOUT Control Register.
+ */
+#define HW_AUDIOOUT_CTRL	0x000
+#define HW_AUDIOOUT_CTRL_SET	0x004
+#define HW_AUDIOOUT_CTRL_CLR	0x008
+
+#define HW_AUDIOOUT_CTRL_SFTRST			__BIT(31)
+#define HW_AUDIOOUT_CTRL_CLKGATE		__BIT(30)
+#define HW_AUDIOOUT_CTRL_RSRVD4			__BITS(29, 21)
+#define HW_AUDIOOUT_CTRL_DMAWAIT_COUNT		__BITS(20, 16)
+#define HW_AUDIOOUT_CTRL_RSRVD3			__BIT(15)
+#define HW_AUDIOOUT_CTRL_LR_SWAP		__BIT(14)
+#define HW_AUDIOOUT_CTRL_EDGE_SYNC		__BIT(13)
+#define HW_AUDIOOUT_CTRL_INVERT_1BIT		__BIT(12)
+#define HW_AUDIOOUT_CTRL_RSRVD2			__BITS(11, 10)
+#define HW_AUDIOOUT_CTRL_SS3D_EFFECT		__BITS(9, 8)
+#define HW_AUDIOOUT_CTRL_RSRVD1			__BIT(7)
+#define HW_AUDIOOUT_CTRL_WORD_LENGTH		__BIT(6)
+#define HW_AUDIOOUT_CTRL_DAC_ZERO_ENABLE	__BIT(5)
+#define HW_AUDIOOUT_CTRL_LOOPBACK		__BIT(4)
+#define HW_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ	__BIT(3)
+#define HW_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ	__BIT(2)
+#define HW_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN	__BIT(1)
+#define HW_AUDIOOUT_CTRL_RUN			__BIT(0)
+
+/*
+ * AUDIOOUT Status Register.
+ */
+#define HW_AUDIOOUT_STAT	0x010
+#define HW_AUDIOOUT_STAT_SET	0x014
+#define HW_AUDIOOUT_STAT_CLR	0x018
+#define HW_AUDIOOUT_STAT_TOG	0x01C
+
+#define HW_AUDIOOUT_STAT_DAC_PRESENT	__BIT(31)
+#define HW_AUDIOOUT_STAT_RSRVD1		__BITS(30, 0)
+
+/*
+ * AUDIOOUT Sample Rate Register.
+ */
+#define HW_AUDIOOUT_DACSRR	0x020
+#define HW_AUDIOOUT_DACSRR_SET	0x024
+#define HW_AUDIOOUT_DACSRR_CLR	0x028
+#define HW_AUDIOOUT_DACSRR_TOG	0x02C
+
+#define HW_AUDIOOUT_DACSRR_OSR		__BIT(31)
+#define HW_AUDIOOUT_DACSRR_BASEMULT	__BITS(30, 28)
+#define HW_AUDIOOUT_DACSRR_RSRVD2	__BIT(27)
+#define HW_AUDIOOUT_DACSRR_SRC_HOLD	__BITS(26, 24)
+#define HW_AUDIOOUT_DACSRR_RSRVD1	__BITS(23, 21)
+#define HW_AUDIOOUT_DACSRR_SRC_INT	__BITS(20, 16)
+#define HW_AUDIOOUT_DACSRR_RSRVD0	__BITS(15, 13)
+#define HW_AUDIOOUT_DACSRR_SRC_FRAC	__BITS(12, 0)
+
+/*
+ * AUDIOOUT Volume Register.
+ */
+#define HW_AUDIOOUT_DACVOLUME		0x030
+#define HW_AUDIOOUT_DACVOLUME_SET	0x034
+#define HW_AUDIOOUT_DACVOLUME_CLR	0x038
+#define HW_AUDIOOUT_DACVOLUME_TOG	0x03C
+
+#define HW_AUDIOOUT_DACVOLUME_RSRVD4			__BITS(31, 29)
+#define HW_AUDIOOUT_DACVOLUME_VOLUME_UPDATE_LEFT	__BIT(28)
+#define HW_AUDIOOUT_DACVOLUME_RSRVD3			__BITS(27, 26)
+#define HW_AUDIOOUT_DACVOLUME_EN_ZCD			__BIT(25)
+#define HW_AUDIOOUT_DACVOLUME_MUTE_LEFT			__BIT(24)
+#define HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT		__BITS(23, 16)
+#define HW_AUDIOOUT_DACVOLUME_RSRVD2			__BITS(15, 13)
+#define HW_AUDIOOUT_DACVOLUME_VOLUME_UPDATE_RIGHT	__BIT(12)
+#define HW_AUDIOOUT_DACVOLUME_RSRVD1			__BITS(11, 9)
+#define HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT		__BIT(8)
+#define HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT		__BITS(7, 0)
+
+/*
+ * AUDIOOUT Debug Register.
+ */
+#define HW_AUDIOOUT_DACDEBUG	0x040
+#define HW_AUDIOOUT_DACDEBUG_SET	0x044
+#define HW_AUDIOOUT_DACDEBUG_CLR	0x048
+#define HW_AUDIOOUT_DACDEBUG_TOG	0x04C
+
+#define HW_AUDIOOUT_DACDEBUG_ENABLE_DACDMA		__BIT(31)
+#define HW_AUDIOOUT_DACDEBUG_RSRVD2			__BITS(30, 12)
+#define HW_AUDIOOUT_DACDEBUG_RAM_SS			__BITS(11, 8)
+#define HW_AUDIOOUT_DACDEBUG_RSRVD1			__BITS(7, 6)
+#define HW_AUDIOOUT_DACDEBUG_SET_INTERRUPT1_CLK_CROSS	__BIT(5)
+#define HW_AUDIOOUT_DACDEBUG_SET_INTERRUPT0_CLK_CROSS	__BIT(4)
+#define HW_AUDIOOUT_DACDEBUG_SET_INTERRUPT1_HAND_SHAKE	__BIT(3)
+#define HW_AUDIOOUT_DACDEBUG_SET_INTERRUPT0_HAND_SHAKE	__BIT(2)
+#define HW_AUDIOOUT_DACDEBUG_DMA_PREQ			__BIT(1)
+#define HW_AUDIOOUT_DACDEBUG_FIFO_STATUS		__BIT(0)
+
+/*
+ * Headphone Volume and Select Control Register.
+ */
+#define HW_AUDIOOUT_HPVOL	0x050
+#define HW_AUDIOOUT_HPVOL_SET	0x054
+#define HW_AUDIOOUT_HPVOL_CLR		0x058
+#define HW_AUDIOOUT_HPVOL_TOG		0x05C
+
+#define HW_AUDIOOUT_HPVOL_RSRVD5		__BITS(31, 29)
+#define HW_AUDIOOUT_HPVOL_VOLUME_UPDATE_PENDING	__BIT(28)
+#define HW_AUDIOOUT_HPVOL_RSRVD4		__BITS(27, 26)
+#define HW_AUDIOOUT_HPVOL_EN_MSTR_ZCD		__BIT(25)
+#define HW_AUDIOOUT_HPVOL_MUTE			__BIT(24)
+#define HW_AUDIOOUT_HPVOL_RSRVD3		__BITS(23, 17)
+#define HW_AUDIOOUT_HPVOL_SELECT		__BIT(16)
+#define HW_AUDIOOUT_HPVOL_RSRVD2		__BIT(15)
+#define HW_AUDIOOUT_HPVOL_VOL_LEFT		__BITS(14, 8)
+#define HW_AUDIOOUT_HPVOL_RSRVD1		__BIT(7)
+#define HW_AUDIOOUT_HPVOL_VOL_RIGHT		__BITS(6, 0)
+
+/*
+ * Reserved Register.
+ */
+#define HW_AUDIOOUT_RESERVED	0x060
+#define HW_AUDIOOUT_RESERVED_SET	0x064
+#define HW_AUDIOOUT_RESERVED_CLR	0x068
+#define HW_AUDIOOUT_RESERVED_TOG	0x06C
+
+#define HW_AUDIOOUT_RESERVED_RSRVD1	__BITS(31, 0)
+
+/*
+ * Audio Power-Down Control Register.
+ */
+#define HW_AUDIOOUT_PWRDN	0x070
+#define HW_AUDIOOUT_PWRDN_SET	0x074
+#define HW_AUDIOOUT_PWRDN_CLR	0x078
+#define HW_AUDIOOUT_PWRDN_TOG	0x07C
+
+#define HW_AUDIOOUT_PWRDN_RSRVD7	__BITS(31, 25)
+#define HW_AUDIOOUT_PWRDN_SPEAKER	__BIT(24)
+#define HW_AUDIOOUT_PWRDN_RSRVD6	__BITS(23, 21)
+#define HW_AUDIOOUT_PWRDN_SELFBIAS	__BIT(20)
+#define HW_AUDIOOUT_PWRDN_RSRVD5	__BITS(19, 17)
+#define HW_AUDIOOUT_PWRDN_RIGHT_ADC	__BIT(16)
+#define HW_AUDIOOUT_PWRDN_RSRVD4	__BITS(15, 13)
+#define HW_AUDIOOUT_PWRDN_DAC		__BIT(12)
+#define HW_AUDIOOUT_PWRDN_RSRVD3	__BITS(11, 9)
+#define HW_AUDIOOUT_PWRDN_ADC		__BIT(8)
+#define HW_AUDIOOUT_PWRDN_RSRVD2	__BITS(7, 5)
+#define HW_AUDIOOUT_PWRDN_CAPLESS	__BIT(4)
+#define HW_AUDIOOUT_PWRDN_RSRVD1	__BITS(3, 1)
+#define HW_AUDIOOUT_PWRDN_HEADPHONE	__BIT(0)
+
+/*
+ * AUDIOOUT Reference Control Register.
+ */
+#define HW_AUDIOOUT_REFCTRL	0x080
+#define HW_AUDIOOUT_REFCTRL_SET	0x084
+#define HW_AUDIOOUT_REFCTRL_CLR	0x088
+#define HW_AUDIOOUT_REFCTRL_TOG	0x08C
+
+#define HW_AUDIOOUT_REFCTRL_RSRVD4		__BITS(31, 27)
+#define HW_AUDIOOUT_REFCTRL_FASTSETTLING	__BIT(26)
+#define HW_AUDIOOUT_REFCTRL_RAISE_REF		__BIT(25)
+#define HW_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS	__BIT(24)
+#define HW_AUDIOOUT_REFCTRL_RSRVD3		__BIT(23)
+#define HW_AUDIOOUT_REFCTRL_VBG_ADJ		__BITS(22, 20)
+#define HW_AUDIOOUT_REFCTRL_LOW_PWR		__BIT(19)
+#define HW_AUDIOOUT_REFCTRL_LW_REF		__BIT(18)
+#define HW_AUDIOOUT_REFCTRL_BIAS_CTRL		__BITS(17, 16)
+#define HW_AUDIOOUT_REFCTRL_RSRVD2		__BIT(15)
+#define HW_AUDIOOUT_REFCTRL_VDDXTAL_TO_VDDD	__BIT(14)
+#define HW_AUDIOOUT_REFCTRL_ADJ_ADC		__BIT(13)
+#define HW_AUDIOOUT_REFCTRL_ADJ_VAG		__BIT(12)
+#define HW_AUDIOOUT_REFCTRL_ADC_REFVAL		__BITS(11, 8)
+#define HW_AUDIOOUT_REFCTRL_VAG_VAL		__BITS(7, 4)
+#define HW_AUDIOOUT_REFCTRL_RSRVD1		__BIT(3)
+#define HW_AUDIOOUT_REFCTRL_DAC_ADJ		__BIT(2, 0)
+
+/*
+ * Miscellaneous Audio Controls Register.
+ */
+#define HW_AUDIOOUT_ANACTRL	0x090
+#define HW_AUDIOOUT_ANACTRL_SET	0x094
+#define HW_AUDIOOUT_ANACTRL_CLR	0x098
+#define HW_AUDIOOUT_ANACTRL_TOG	0x09C
+
+#define HW_AUDIOOUT_ANACTRL_RSRVD8		__BITS(31, 29)
+#define HW_AUDIOOUT_ANACTRL_SHORT_CM_STS	__BIT(28)
+#define HW_AUDIOOUT_ANACTRL_RSRVD7		__BITS(27, 25)
+#define HW_AUDIOOUT_ANACTRL_SHORT_LR_STS	__BIT(24)
+#define HW_AUDIOOUT_ANACTRL_RSRVD6		__BITS(23, 22)
+#define HW_AUDIOOUT_ANACTRL_SHORTMODE_CM	__BIT(21, 20)
+#define HW_AUDIOOUT_ANACTRL_RSRVD5		__BIT(19)
+#define HW_AUDIOOUT_ANACTRL_SHORTMODE_LR	__BITS(18, 17)
+#define HW_AUDIOOUT_ANACTRL_RSRVD4		__BITS(16, 15)
+#define HW_AUDIOOUT_ANACTRL_SHORT_LVLADJL	__BITS(14, 12)
+#define HW_AUDIOOUT_ANACTRL_RSRVD3		__BIT(11)
+#define HW_AUDIOOUT_ANACTRL_SHORT_LVLADJR	__BITS(10, 8)
+#define HW_AUDIOOUT_ANACTRL_RSRVD2		__BITS(7, 6)
+#define HW_AUDIOOUT_ANACTRL_HP_HOLD_GND		__BIT(5)
+#define HW_AUDIOOUT_ANACTRL_HP_CLASSAB		__BIT(4)
+#define HW_AUDIOOUT_ANACTRL_RSRVD1		__BITS(3, 0)
+
+/*
+ * Miscellaneous Test Audio Controls Register.
+ */
+#define HW_AUDIOOUT_TEST	0x0a0
+#define HW_AUDIOOUT_TEST_SET	0x0a4
+#define HW_AUDIOOUT_TEST_CLR	0x0a8
+#define HW_AUDIOOUT_TEST_TOG	0x0aC
+
+#define HW_AUDIOOUT_TEST_RSRVD4		__BIT(31)
+#define HW_AUDIOOUT_TEST_HP_ANTIPOP	__BITS(30, 28)
+#define HW_AUDIOOUT_TEST_RSRVD3		__BIT(27)
+#define HW_AUDIOOUT_TEST_TM_ADCIN_TOHP	__BIT(26)
+#define HW_AUDIOOUT_TEST_TM_LOOP	__BIT(25)
+#define HW_AUDIOOUT_TEST_TM_HPCOMMON	__BIT(24)
+#define HW_AUDIOOUT_TEST_HP_I1_ADJ	__BITS(23, 22)
+#define HW_AUDIOOUT_TEST_HP_IALL_ADJ	__BITS(21, 20)
+#define HW_AUDIOOUT_TEST_RSRVD2		__BITS(19, 14)
+#define HW_AUDIOOUT_TEST_VAG_CLASSA	__BIT(13)
+#define HW_AUDIOOUT_TEST_VAG_DOUBLE_I	__BIT(12)
+#define HW_AUDIOOUT_TEST_RSRVD1		__BITS(11, 4)
+#define HW_AUDIOOUT_TEST_ADCTODAC_LOOP	__BIT(3)
+#define HW_AUDIOOUT_TEST_DAC_CLASSA	__BIT(2)
+#define HW_AUDIOOUT_TEST_DAC_DOUBLE_I	__BIT(1)
+#define HW_AUDIOOUT_TEST_DAC_DIS_RTZ	__BIT(0)
+
+/*
+ * BIST Control and Status Register.
+ */
+#define HW_AUDIOOUT_BISTCTRL	0x0b0
+#define HW_AUDIOOUT_BISTCTRL_SET	0x0b4
+#define HW_AUDIOOUT_BISTCTRL_CLR	0x0b8
+#define HW_AUDIOOUT_BISTCTRL_TOG	0x0bC
+
+#define HW_AUDIOOUT_BISTCTRL_RSVD0	__BITS(31, 4)
+#define HW_AUDIOOUT_BISTCTRL_FAIL	__BIT(3)
+#define HW_AUDIOOUT_BISTCTRL_PASS	__BIT(2)
+#define HW_AUDIOOUT_BISTCTRL_DONE	__BIT(1)
+#define HW_AUDIOOUT_BISTCTRL_START	__BIT(0)
+
+/*
+ * Hardware BIST Status 0 Register.
+ */
+#define HW_AUDIOOUT_BISTSTAT0	0x0c0
+#define HW_AUDIOOUT_BISTSTAT0_SET	0x0c4
+#define HW_AUDIOOUT_BISTSTAT0_CLR	0x0c8
+#define HW_AUDIOOUT_BISTSTAT0_TOG	0x0cC
+
+#define HW_AUDIOOUT_BISTSTAT0_RSVD0	__BITS(31, 24)
+#define HW_AUDIOOUT_BISTSTAT0_DATA	__BITS(23, 0)
+
+/*
+ * Hardware AUDIOUT BIST Status 1 Register.
+ */
+#define HW_AUDIOOUT_BISTSTAT1	0x0d0
+#define HW_AUDIOOUT_BISTSTAT1_SET	0x0d4
+#define HW_AUDIOOUT_BISTSTAT1_CLR	0x0d8
+#define HW_AUDIOOUT_BISTSTAT1_TOG	0x0dC
+
+#define HW_AUDIOOUT_BISTSTAT1_RSVD1	__BITS(31, 29)
+#define HW_AUDIOOUT_BISTSTAT1_STATE	__BITS(28, 24)
+#define HW_AUDIOOUT_BISTSTAT1_RSVD0	__BITS(23, 8)
+#define HW_AUDIOOUT_BISTSTAT1_ADDR	__BITS(7, 0)
+
+/*
+ * Analog Clock Control Register.
+ */
+#define HW_AUDIOOUT_ANACLKCTRL	0x0e0
+#define HW_AUDIOOUT_ANACLKCTRL_SET	0x0e4
+#define HW_AUDIOOUT_ANACLKCTRL_CLR	0x0e8
+#define HW_AUDIOOUT_ANACLKCTRL_TOG	0x0eC
+
+#define HW_AUDIOOUT_ANACLKCTRL_CLKGATE		__BIT(31)
+#define HW_AUDIOOUT_ANACLKCTRL_RSRVD3		__BITS(30, 5)
+#define HW_AUDIOOUT_ANACLKCTRL_INVERT_DACCLK	__BIT(4)
+#define HW_AUDIOOUT_ANACLKCTRL_RSRVD2		__BIT(3)
+#define HW_AUDIOOUT_ANACLKCTRL_DACDIV		__BITS(2, 0)
+
+/*
+ * AUDIOOUT Write Data Register.
+ */
+#define HW_AUDIOOUT_DATA	0x0f0
+#define HW_AUDIOOUT_DATA_SET	0x0f4
+#define HW_AUDIOOUT_DATA_CLR	0x0f8
+#define HW_AUDIOOUT_DATA_TOG	0x0fC
+
+#define HW_AUDIOOUT_DATA_HIGH	__BITS(31, 16)
+#define HW_AUDIOOUT_DATA_LOW	__BITS(15, 0)
+
+/*
+ * AUDIOOUT Speaker Control Register.
+ */
+#define HW_AUDIOOUT_SPEAKERCTRL	0x100
+#define HW_AUDIOOUT_SPEAKERCTRL_SET	0x104
+#define HW_AUDIOOUT_SPEAKERCTRL_CLR	0x108
+#define HW_AUDIOOUT_SPEAKERCTRL_TOG	0x10C
+
+#define HW_AUDIOOUT_SPEAKERCTRL_RSRVD2		__BITS(31, 25)
+#define HW_AUDIOOUT_SPEAKERCTRL_MUTE		__BIT(24)
+#define HW_AUDIOOUT_SPEAKERCTRL_I1_ADJ		__BITS(23, 22)
+#define HW_AUDIOOUT_SPEAKERCTRL_IALL_ADJ	__BITS(21, 20)
+#define HW_AUDIOOUT_SPEAKERCTRL_RSRVD1		__BITS(19, 16)
+#define HW_AUDIOOUT_SPEAKERCTRL_POSDRIVER	__BITS(15, 14)
+#define HW_AUDIOOUT_SPEAKERCTRL_NEGDRIVER	__BITS(13, 12)
+#define HW_AUDIOOUT_SPEAKERCTRL_RSRVD0		__BITS(11, 0)
+
+/*
+ * AUDIOOUT Version Register.
+ */
+#define HW_AUDIOOUT_VERSION	0x200
+
+#define HW_AUDIOOUT_VERSION_MAJOR	__BITS(31, 24)
+#define HW_AUDIOOUT_VERSION_MINOR	__BITS(23, 16)
+#define HW_AUDIOOUT_VERSION_STEP	__BITS(15, 0)
+
+#endif /* !_ARM_IMX_IMX23_AUDIOOUTREG_H_ */
Index: src/sys/arch/arm/imx/imx23_digfiltvar.h
diff -u /dev/null src/sys/arch/arm/imx/imx23_digfiltvar.h:1.1
--- /dev/null	Sat Jan 10 12:16:28 2015
+++ src/sys/arch/arm/imx/imx23_digfiltvar.h	Sat Jan 10 12:16:28 2015
@@ -0,0 +1,35 @@
+/* $Id: imx23_digfiltvar.h,v 1.1 2015/01/10 12:16:28 jmcneill Exp $ */
+
+/*
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Petri Laakso.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_IMX_IMX23_AUDIOOUTVAR_H_
+#define _ARM_IMX_IMX23_AUDIOOUTVAR_H_
+
+#endif /* !_ARM_IMX_IMX23_AUDIOOUTVAR_H_ */
Index: src/sys/arch/arm/imx/imx23_rtc.c
diff -u /dev/null src/sys/arch/arm/imx/imx23_rtc.c:1.1
--- /dev/null	Sat Jan 10 12:16:28 2015
+++ src/sys/arch/arm/imx/imx23_rtc.c	Sat Jan 10 12:16:28 2015
@@ -0,0 +1,199 @@
+/* $Id: imx23_rtc.c,v 1.1 2015/01/10 12:16:28 jmcneill Exp $ */
+
+/*
+* Copyright (c) 2014 The NetBSD Foundation, Inc.
+* All rights reserved.
+*
+* This code is derived from software contributed to The NetBSD Foundation
+* by Petri Laakso.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/cdefs.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+
+#include <arm/imx/imx23_rtcreg.h>
+#include <arm/imx/imx23_rtcvar.h>
+#include <arm/imx/imx23var.h>
+
+typedef struct rtc_softc {
+	device_t sc_dev;
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_hdl;
+} *rtc_softc_t;
+
+static int	rtc_match(device_t, cfdata_t, void *);
+static void	rtc_attach(device_t, device_t, void *);
+static int	rtc_activate(device_t, enum devact);
+
+static void     rtc_init(struct rtc_softc *);
+static void     rtc_reset(struct rtc_softc *);
+
+static rtc_softc_t _sc = NULL;
+
+CFATTACH_DECL3_NEW(rtc,
+        sizeof(struct rtc_softc),
+        rtc_match,
+        rtc_attach,
+        NULL,
+        rtc_activate,
+        NULL,
+        NULL,
+        0
+);
+
+#define RTC_RD(sc, reg)                                                 \
+        bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
+#define RTC_WR(sc, reg, val)                                            \
+        bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
+
+#define RTC_SOFT_RST_LOOP 455 /* At least 1 us ... */
+
+static int
+rtc_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct apb_attach_args *aa = aux;
+
+	if ((aa->aa_addr == HW_RTC_BASE) &&
+	    (aa->aa_size == HW_RTC_BASE_SIZE))
+		return 1;
+
+	return 0;
+}
+
+static void
+rtc_attach(device_t parent, device_t self, void *aux)
+{
+	struct rtc_softc *sc = device_private(self);
+	struct apb_attach_args *aa = aux;
+	static int rtc_attached = 0;
+
+	sc->sc_dev = self;
+	sc->sc_iot = aa->aa_iot;
+	
+	if (rtc_attached) {
+		aprint_error_dev(sc->sc_dev, "rtc is already attached\n");
+		return;
+	}
+
+	if (bus_space_map(sc->sc_iot, aa->aa_addr, aa->aa_size, 0,
+	    &sc->sc_hdl))
+	{
+		aprint_error_dev(sc->sc_dev, "Unable to map bus space\n");
+		return;
+	}
+
+
+	rtc_init(sc);
+	rtc_reset(sc);
+
+	aprint_normal("\n");
+
+	rtc_attached = 1;
+
+	return;
+}
+
+static int
+rtc_activate(device_t self, enum devact act)
+{
+
+	return EOPNOTSUPP;
+}
+
+static void    
+rtc_init(struct rtc_softc *sc)
+{
+	_sc = sc;
+	return;
+}
+
+/*
+ * Remove pulldown resistors on the headphone outputs.
+ */
+void
+rtc_release_gnd(int val)
+{
+	struct rtc_softc *sc = _sc;
+
+        if (sc == NULL) {
+                aprint_error("rtc is not initalized");
+                return;
+        }
+	if(val)
+		RTC_WR(sc, HW_RTC_PERSISTENT0_SET, (1<<19));
+	else
+		RTC_WR(sc, HW_RTC_PERSISTENT0_CLR, (1<<19));
+
+	return;
+}
+
+/*
+ * Reset the RTC block.
+ *
+ * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
+ */
+static void
+rtc_reset(struct rtc_softc *sc)
+{
+        unsigned int loop;
+
+        /* Prepare for soft-reset by making sure that SFTRST is not currently
+        * asserted. Also clear CLKGATE so we can wait for its assertion below.
+        */
+        RTC_WR(sc, HW_RTC_CTRL_CLR, HW_RTC_CTRL_SFTRST);
+
+        /* Wait at least a microsecond for SFTRST to deassert. */
+        loop = 0;
+        while ((RTC_RD(sc, HW_RTC_CTRL) & HW_RTC_CTRL_SFTRST) ||
+            (loop < RTC_SOFT_RST_LOOP))
+                loop++;
+
+        /* Clear CLKGATE so we can wait for its assertion below. */
+        RTC_WR(sc, HW_RTC_CTRL_CLR, HW_RTC_CTRL_CLKGATE);
+
+        /* Soft-reset the block. */
+        RTC_WR(sc, HW_RTC_CTRL_SET, HW_RTC_CTRL_SFTRST);
+
+        /* Wait until clock is in the gated state. */
+        while (!(RTC_RD(sc, HW_RTC_CTRL) & HW_RTC_CTRL_CLKGATE));
+
+        /* Bring block out of reset. */
+        RTC_WR(sc, HW_RTC_CTRL_CLR, HW_RTC_CTRL_SFTRST);
+
+        loop = 0;
+        while ((RTC_RD(sc, HW_RTC_CTRL) & HW_RTC_CTRL_SFTRST) ||
+            (loop < RTC_SOFT_RST_LOOP))
+                loop++;
+
+        RTC_WR(sc, HW_RTC_CTRL_CLR, HW_RTC_CTRL_CLKGATE);
+
+        /* Wait until clock is in the NON-gated state. */
+        while (RTC_RD(sc, HW_RTC_CTRL) & HW_RTC_CTRL_CLKGATE);
+
+        return;
+}
Index: src/sys/arch/arm/imx/imx23_rtcvar.h
diff -u /dev/null src/sys/arch/arm/imx/imx23_rtcvar.h:1.1
--- /dev/null	Sat Jan 10 12:16:28 2015
+++ src/sys/arch/arm/imx/imx23_rtcvar.h	Sat Jan 10 12:16:28 2015
@@ -0,0 +1,37 @@
+/* $Id: imx23_rtcvar.h,v 1.1 2015/01/10 12:16:28 jmcneill Exp $ */
+
+/*
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Petri Laakso.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_IMX_IMX23_RTCVAR_H_
+#define _ARM_IMX_IMX23_RTCVAR_H_
+
+void rtc_release_gnd(int);
+
+#endif /* !_ARM_IMX_IMX23_RTCVAR_H_ */

Reply via email to