Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/arm/imx From Petri Laakso <petri.laakso%asd.fi@localhost>:



details:   https://anonhg.NetBSD.org/src/rev/9eb16dba3487
branches:  trunk
changeset: 335498:9eb16dba3487
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Jan 10 12:16:28 2015 +0000

description:
>From Petri Laakso <petri.laakso%asd.fi@localhost>:
-       Audio output driver for imx23
-       Supporting code for audio driver

diffstat:

 sys/arch/arm/imx/imx23_digfilt.c    |  1130 +++++++++++++++++++++++++++++++++++
 sys/arch/arm/imx/imx23_digfiltreg.h |   382 +++++++++++
 sys/arch/arm/imx/imx23_digfiltvar.h |    35 +
 sys/arch/arm/imx/imx23_rtc.c        |   199 ++++++
 sys/arch/arm/imx/imx23_rtcreg.h     |     3 +-
 sys/arch/arm/imx/imx23_rtcvar.h     |    37 +
 6 files changed, 1785 insertions(+), 1 deletions(-)

diffs (truncated from 1820 to 300 lines):

diff -r aab760eb2d0c -r 9eb16dba3487 sys/arch/arm/imx/imx23_digfilt.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/imx/imx23_digfilt.c  Sat Jan 10 12:16:28 2015 +0000
@@ -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;



Home | Main Index | Thread Index | Old Index