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 <[email protected]>:
- 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_ */