Port-arm archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

imx23 audio output driver



Hi

I've hacked together audio output driver for imx23 olinuxino
and it has been playing tunes for few days without problems.

I'd be pleased if someone reviews and commits this to the current tree.
Patch can be found also from http://www.asd.fi/~petri/imx23_digfilt.patch

Best regards
Petri Laakso

This patch touches many files. I briefly comment all of those.

Index: sys/arch/arm/imx/files.imx23
-	Add new devices rtc and digfilt

Index: sys/arch/arm/imx/imx23_apbdma.c
Index: sys/arch/arm/imx/imx23_apbdmareg.h
Index: sys/arch/arm/imx/imx23_apbdmavar.h

-	Fix AHBH => APBH
-	Add support for APBX DMA
-	Added apbdma_wait() to wait for DMA completion

Index: sys/arch/arm/imx/imx23_clkctrl.c
Index: sys/arch/arm/imx/imx23_clkctrlvar.h
-	clkctrl_en_filtclk(): Enable 24MHz clock for the Digital Filter.

Index: sys/arch/arm/imx/imx23_digfilt.c
Index: sys/arch/arm/imx/imx23_digfiltreg.h
Index: sys/arch/arm/imx/imx23_digfiltvar.h
-	Audio output driver for imx23

Index: sys/arch/arm/imx/imx23_rtc.c
Index: sys/arch/arm/imx/imx23_rtcreg.h
Index: sys/arch/arm/imx/imx23_rtcvar.h
-	Supporting code for audio driver

Index: sys/arch/evbarm/conf/IMX23_OLINUXINO
-	New audio driver

Index: sys/arch/evbarm/conf/files.imx23_olinuxino
Index: sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c
-	Use BOOT_ARGS if defined
Index: sys/arch/arm/imx/files.imx23
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/imx/files.imx23,v
retrieving revision 1.2
diff -u -r1.2 files.imx23
--- sys/arch/arm/imx/files.imx23	7 Oct 2013 17:36:40 -0000	1.2
+++ sys/arch/arm/imx/files.imx23	27 Dec 2014 17:13:46 -0000
@@ -3,6 +3,8 @@
 # Freescale i.MX23 applications processor configuration info.
 #
 
+defflag opt_imx.h                               IMX23
+
 file	arch/arm/arm32/irq_dispatch.S	icoll
 file	arch/arm/imx/imx23_space.c	ahb|apbh|apbx
 file	arch/arm/imx/imx23_dma.c	ahb|apbh|apbx
@@ -80,3 +82,13 @@
 # EHCI
 attach	ehci at imxusbc with imxehci
 file	arch/arm/imx/imxusb.c		imxehci
+
+# RTC 
+device rtc
+attach rtc at apbx
+file arch/arm/imx/imx23_rtc.c		rtc
+
+# Digital filter: Audio I/O
+device digfilt: audiobus
+attach digfilt at apbx with digfilt
+file arch/arm/imx/imx23_digfilt.c	digfilt
Index: sys/arch/arm/imx/imx23_apbdma.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/imx/imx23_apbdma.c,v
retrieving revision 1.3
diff -u -r1.3 imx23_apbdma.c
--- sys/arch/arm/imx/imx23_apbdma.c	3 Mar 2013 10:33:56 -0000	1.3
+++ sys/arch/arm/imx/imx23_apbdma.c	27 Dec 2014 17:13:46 -0000
@@ -92,10 +92,10 @@
 	static u_int apbdma_attached = 0;
 
 	if ((strncmp(device_xname(parent), "apbh", 4) == 0) &&
-	    (apbdma_attached & F_AHBH_DMA))
+	    (apbdma_attached & F_APBH_DMA))
 		return;
 	if ((strncmp(device_xname(parent), "apbx", 4) == 0) &&
-	    (apbdma_attached & F_AHBX_DMA))
+	    (apbdma_attached & F_APBX_DMA))
 		return;
 
 	sc->sc_dev = self;
@@ -109,25 +109,30 @@
 	}
 
 	if (strncmp(device_xname(parent), "apbh", 4) == 0)
-		sc->flags = F_AHBH_DMA;
+		sc->flags = F_APBH_DMA;
 
 	if (strncmp(device_xname(parent), "apbx", 4) == 0)
-		sc->flags = F_AHBX_DMA;
+		sc->flags = F_APBX_DMA;
 
 	apbdma_reset(sc);
 	apbdma_init(sc);
 
-	if (sc->flags & F_AHBH_DMA)
-		apbdma_attached |= F_AHBH_DMA;
-	if (sc->flags & F_AHBX_DMA)
-		apbdma_attached |= F_AHBX_DMA;
+	if (sc->flags & F_APBH_DMA)
+		apbdma_attached |= F_APBH_DMA;
+	if (sc->flags & F_APBX_DMA)
+		apbdma_attached |= F_APBX_DMA;
 
 	sc_parent->dmac = self;
 
 	/* Initialize mutex to control concurrent access from the drivers. */
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
 
-	aprint_normal("\n");
+	if (sc->flags & F_APBH_DMA)
+		aprint_normal(": APBH DMA\n");
+	else if (sc->flags & F_APBX_DMA)
+		aprint_normal(": APBX DMA\n");
+	else
+		panic("dma flag missing!\n");
 
 	return;
 }
@@ -192,7 +197,7 @@
 apbdma_init(struct apbdma_softc *sc)
 {
 
-	if (sc->flags & F_AHBH_DMA) {
+	if (sc->flags & F_APBH_DMA) {
 		DMA_WR(sc, HW_APBH_CTRL0_SET, HW_APBH_CTRL0_AHB_BURST8_EN);
 		DMA_WR(sc, HW_APBH_CTRL0_SET, HW_APBH_CTRL0_APB_BURST4_EN);
 	}
@@ -279,7 +284,7 @@
 {
 	uint32_t reg;
 
-	if (sc->flags & F_AHBH_DMA)
+	if (sc->flags & F_APBH_DMA)
 		reg = HW_APB_CHN_NXTCMDAR(HW_APBH_CH0_NXTCMDAR, channel);
 	else
 		reg = HW_APB_CHN_NXTCMDAR(HW_APBX_CH0_NXTCMDAR, channel);
@@ -301,7 +306,7 @@
 	uint32_t reg;
 	uint8_t val;
 
-	if (sc->flags & F_AHBH_DMA) {
+	if (sc->flags & F_APBH_DMA) {
 		reg = HW_APB_CHN_SEMA(HW_APBH_CH0_SEMA, channel);
 		val = __SHIFTIN(1, HW_APBH_CH0_SEMA_INCREMENT_SEMA);
 	 } else {
@@ -324,7 +329,11 @@
 {
 
 	mutex_enter(&sc->sc_lock);
-	DMA_WR(sc, HW_APB_CTRL1_CLR, (1<<channel));
+	if (sc->flags & F_APBH_DMA) {
+		DMA_WR(sc, HW_APB_CTRL1_CLR, (1<<channel));
+	} else {
+		DMA_WR(sc, HW_APB_CTRL1_CLR, (1<<channel));
+	}
 	mutex_exit(&sc->sc_lock);
 
 	return;
@@ -383,11 +392,34 @@
 	
 	mutex_enter(&sc->sc_lock);
 
-	DMA_WR(sc, HW_APB_CTRL0_SET,
-	    __SHIFTIN((1<<channel), HW_APBH_CTRL0_RESET_CHANNEL));
-	while(DMA_RD(sc, HW_APB_CTRL0) & HW_APBH_CTRL0_RESET_CHANNEL);
+	if (sc->flags & F_APBH_DMA) {
+		DMA_WR(sc, HW_APB_CTRL0_SET,
+		    __SHIFTIN((1<<channel), HW_APBH_CTRL0_RESET_CHANNEL));
+		while(DMA_RD(sc, HW_APB_CTRL0) & HW_APBH_CTRL0_RESET_CHANNEL);
+	} else {
+		DMA_WR(sc, HW_APBX_CHANNEL_CTRL_SET,
+			__SHIFTIN((1<<channel), HW_APBH_CTRL0_RESET_CHANNEL));
+		while(DMA_RD(sc, HW_APBX_CHANNEL_CTRL) & (1<<channel));
+	}
 
 	mutex_exit(&sc->sc_lock);
 
 	return;
 }
+
+void
+apbdma_wait(struct apbdma_softc *sc, unsigned int channel)
+{
+
+	mutex_enter(&sc->sc_lock);
+	
+	if (sc->flags & F_APBH_DMA) {
+		while (DMA_RD(sc, HW_APB_CHN_SEMA(HW_APBH_CH0_SEMA, channel)) & HW_APBH_CH0_SEMA_PHORE)
+			;
+	 } else {
+		while (DMA_RD(sc, HW_APB_CHN_SEMA(HW_APBX_CH0_SEMA, channel)) & HW_APBX_CH0_SEMA_PHORE)
+			;
+	}
+
+	mutex_exit(&sc->sc_lock);
+}
Index: sys/arch/arm/imx/imx23_apbdmareg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/imx/imx23_apbdmareg.h,v
retrieving revision 1.2
diff -u -r1.2 imx23_apbdmareg.h
--- sys/arch/arm/imx/imx23_apbdmareg.h	3 Mar 2013 10:33:56 -0000	1.2
+++ sys/arch/arm/imx/imx23_apbdmareg.h	27 Dec 2014 17:13:46 -0000
@@ -66,4 +66,6 @@
 #define HW_APB_CTRL2_CLR	0x028
 #define HW_APB_CTRL2_TOG	0x02C
 
+#define HW_APBX_CHANNEL_CTRL 0x30
+#define HW_APBX_CHANNEL_CTRL_SET 0x34
 #endif /* !_ARM_IMX_IMX23_APBDMAREG_H_ */
Index: sys/arch/arm/imx/imx23_apbdmavar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/imx/imx23_apbdmavar.h,v
retrieving revision 1.1
diff -u -r1.1 imx23_apbdmavar.h
--- sys/arch/arm/imx/imx23_apbdmavar.h	3 Mar 2013 10:33:56 -0000	1.1
+++ sys/arch/arm/imx/imx23_apbdmavar.h	27 Dec 2014 17:13:46 -0000
@@ -58,8 +58,8 @@
 #define APBDMA_CMD_DMA_SENSE		3
 
 /* Flags. */
-#define F_AHBH_DMA			__BIT(0)
-#define F_AHBX_DMA			__BIT(1)
+#define F_APBH_DMA			__BIT(0)
+#define F_APBX_DMA			__BIT(1)
 
 /* Number of channels. */
 #define AHBH_DMA_CHANNELS		8
@@ -133,5 +133,6 @@
 void apbdma_ack_error_intr(struct apbdma_softc *, unsigned int);
 unsigned int apbdma_intr_status(struct apbdma_softc *, unsigned int);
 void apbdma_chan_reset(struct apbdma_softc *, unsigned int);
+void apbdma_wait(struct apbdma_softc *, unsigned int);
 
 #endif /* !_ARM_IMX_IMX23_APBDMAVAR_H_ */
Index: sys/arch/arm/imx/imx23_clkctrl.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/imx/imx23_clkctrl.c,v
retrieving revision 1.1
diff -u -r1.1 imx23_clkctrl.c
--- sys/arch/arm/imx/imx23_clkctrl.c	7 Oct 2013 17:36:40 -0000	1.1
+++ sys/arch/arm/imx/imx23_clkctrl.c	27 Dec 2014 17:13:46 -0000
@@ -149,3 +149,22 @@
 
 	return;
 }
+
+/*
+ * Enable 24MHz clock for the Digital Filter. 
+ *
+ */
+void
+clkctrl_en_filtclk(void)
+{
+	struct clkctrl_softc *sc = _sc;
+
+	if (sc == NULL) {
+		aprint_error("clkctrl is not initalized");
+		return;
+	}
+
+	CLKCTRL_WR(sc, HW_CLKCTRL_XTAL_CLR, HW_CLKCTRL_XTAL_FILT_CLK24M_GATE);
+
+	return;
+}
Index: sys/arch/arm/imx/imx23_clkctrlvar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/imx/imx23_clkctrlvar.h,v
retrieving revision 1.1
diff -u -r1.1 imx23_clkctrlvar.h
--- sys/arch/arm/imx/imx23_clkctrlvar.h	7 Oct 2013 17:36:40 -0000	1.1
+++ sys/arch/arm/imx/imx23_clkctrlvar.h	27 Dec 2014 17:13:46 -0000
@@ -33,5 +33,6 @@
 #define _ARM_IMX_IMX23_CLKCTRLVAR_H_
 
 void clkctrl_en_usb(void);
+void clkctrl_en_filtclk(void);
 
 #endif /* !_ARM_IMX_IMX23_CLKCTRLVAR_H_ */
Index: sys/arch/arm/imx/imx23_digfilt.c
===================================================================
RCS file: sys/arch/arm/imx/imx23_digfilt.c
diff -N sys/arch/arm/imx/imx23_digfilt.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arch/arm/imx/imx23_digfilt.c	27 Dec 2014 17:13:46 -0000
@@ -0,0 +1,1136 @@
+/* $Id$ */
+
+/*
+ * 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;
+
+	//printf("sc->sc_cmd_index = %d\n", sc->sc_cmd_index);
+	//apbdma_print(sc->sc_dmac);
+	apbdma_wait(sc->sc_dmac, 1);
+	sc->sc_cmd_index = 0;
+	//printf("sc->sc_cmd_index = %d\n", sc->sc_cmd_index);
+	//apbdma_print(sc->sc_dmac);
+	
+	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, 1);
+
+	if (dma_err) {
+		apbdma_ack_error_intr(sc->sc_dmac, 1);
+	}// else {
+		//apbdma_ack_intr(sc->sc_dmac, 1);
+	//}
+
+	sc->sc_intr(sc->sc_intarg);
+	apbdma_ack_intr(sc->sc_dmac, 1);
+
+	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: sys/arch/arm/imx/imx23_digfiltreg.h
===================================================================
RCS file: sys/arch/arm/imx/imx23_digfiltreg.h
diff -N sys/arch/arm/imx/imx23_digfiltreg.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arch/arm/imx/imx23_digfiltreg.h	27 Dec 2014 17:13:46 -0000
@@ -0,0 +1,382 @@
+/* $Id$ */
+
+/*
+ * 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: sys/arch/arm/imx/imx23_digfiltvar.h
===================================================================
RCS file: sys/arch/arm/imx/imx23_digfiltvar.h
diff -N sys/arch/arm/imx/imx23_digfiltvar.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arch/arm/imx/imx23_digfiltvar.h	27 Dec 2014 17:13:46 -0000
@@ -0,0 +1,35 @@
+/* $Id$ */
+
+/*
+ * 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: sys/arch/arm/imx/imx23_rtc.c
===================================================================
RCS file: sys/arch/arm/imx/imx23_rtc.c
diff -N sys/arch/arm/imx/imx23_rtc.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arch/arm/imx/imx23_rtc.c	27 Dec 2014 17:13:46 -0000
@@ -0,0 +1,199 @@
+/* $Id$ */
+
+/*
+* 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 SSP 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: sys/arch/arm/imx/imx23_rtcreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/imx/imx23_rtcreg.h,v
retrieving revision 1.1
diff -u -r1.1 imx23_rtcreg.h
--- sys/arch/arm/imx/imx23_rtcreg.h	20 Nov 2012 19:06:13 -0000	1.1
+++ sys/arch/arm/imx/imx23_rtcreg.h	27 Dec 2014 17:13:46 -0000
@@ -35,6 +35,7 @@
 #include <sys/cdefs.h>
 
 #define HW_RTC_BASE 0x8005C000
+#define HW_RTC_BASE_SIZE 0x2000
 
 /*
  * Real-Time Clock Control Register.
Index: sys/arch/arm/imx/imx23_rtcvar.h
===================================================================
RCS file: sys/arch/arm/imx/imx23_rtcvar.h
diff -N sys/arch/arm/imx/imx23_rtcvar.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arch/arm/imx/imx23_rtcvar.h	27 Dec 2014 17:13:46 -0000
@@ -0,0 +1,37 @@
+/* $Id$ */
+
+/*
+ * 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_ */
Index: sys/arch/evbarm/conf/IMX23_OLINUXINO
===================================================================
RCS file: /cvsroot/src/sys/arch/evbarm/conf/IMX23_OLINUXINO,v
retrieving revision 1.10
diff -u -r1.10 IMX23_OLINUXINO
--- sys/arch/evbarm/conf/IMX23_OLINUXINO	11 Oct 2014 11:55:07 -0000	1.10
+++ sys/arch/evbarm/conf/IMX23_OLINUXINO	27 Dec 2014 17:13:47 -0000
@@ -66,6 +66,13 @@
 # Clock control
 clkctrl0	at apbx? addr 0x80040000 size 0x2000 irq -1
 
+# RTC
+rtc0		at apbx? addr 0x8005C000 size 0x2000 irq -1
+
+# Digital filter: Audio I/O
+digfilt0	at apbx? addr 0x80048000 size 0x8000 irq -1
+audio0		at digfilt0
+
 # USB host
 ehci0		at imxusbc0 unit 0 irq 11
 # USB OTG
Index: sys/arch/evbarm/conf/files.imx23_olinuxino
===================================================================
RCS file: /cvsroot/src/sys/arch/evbarm/conf/files.imx23_olinuxino,v
retrieving revision 1.2
diff -u -r1.2 files.imx23_olinuxino
--- sys/arch/evbarm/conf/files.imx23_olinuxino	7 Oct 2013 17:36:40 -0000	1.2
+++ sys/arch/evbarm/conf/files.imx23_olinuxino	27 Dec 2014 17:13:47 -0000
@@ -6,6 +6,9 @@
 # Pull in SoC support
 include "arch/arm/imx/files.imx23"
 
+# Kernel boot arguments
+defparam opt_machdep.h				BOOT_ARGS
+
 file	arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c
 file	arch/arm/arm32/arm32_kvminit.c
 file	arch/arm/arm32/arm32_boot.c
Index: sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c,v
retrieving revision 1.4
diff -u -r1.4 imx23_olinuxino_machdep.c
--- sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c	29 Oct 2014 11:21:51 -0000	1.4
+++ sys/arch/evbarm/imx23_olinuxino/imx23_olinuxino_machdep.c	27 Dec 2014 17:13:47 -0000
@@ -65,6 +65,7 @@
 #endif
 
 #include "opt_evbarm_boardtype.h"
+#include "opt_machdep.h"
 
 #define	KERNEL_VM_BASE	(KERNEL_BASE + 0x8000000)
 #define	KERNEL_VM_SIZE	0x20000000
@@ -161,6 +162,9 @@
 	/* Copy boot arguments passed from bootimx23. */
 	boot_args = (char *)KERN_PHYSTOV(BOOTIMX23_ARGS);
 	memcpy(kernel_boot_args, boot_args, MAX_BOOT_STRING);
+#ifdef BOOT_ARGS
+	strcpy(kernel_boot_args, BOOT_ARGS);
+#endif
 	boot_args = kernel_boot_args;
 #ifdef VERBOSE_INIT_ARM
 	printf("boot_args @ %lx: '%s'\n", KERN_PHYSTOV(BOOTIMX23_ARGS),


Home | Main Index | Thread Index | Old Index