Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/arm/allwinner Driver for "Audio Codec" block of A10...



details:   https://anonhg.NetBSD.org/src/rev/176ae3476ca2
branches:  trunk
changeset: 332001:176ae3476ca2
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Thu Sep 04 02:38:18 2014 +0000

description:
Driver for "Audio Codec" block of A10/A13/A20, not tested.

diffstat:

 sys/arch/arm/allwinner/awin_ac.c  |  690 ++++++++++++++++++++++++++++++++++++++
 sys/arch/arm/allwinner/awin_io.c  |    3 +-
 sys/arch/arm/allwinner/files.awin |    7 +-
 3 files changed, 698 insertions(+), 2 deletions(-)

diffs (truncated from 732 to 300 lines):

diff -r 1cb52c361b20 -r 176ae3476ca2 sys/arch/arm/allwinner/awin_ac.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/allwinner/awin_ac.c  Thu Sep 04 02:38:18 2014 +0000
@@ -0,0 +1,690 @@
+/* $NetBSD: awin_ac.c,v 1.1 2014/09/04 02:38:18 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2014 Jared D. McNeill <jmcneill%invisible.ca@localhost>
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR 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 "locators.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: awin_ac.c,v 1.1 2014/09/04 02:38:18 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+#include <dev/auconv.h>
+
+#include <arm/allwinner/awin_reg.h>
+#include <arm/allwinner/awin_var.h>
+
+#define AWINAC_TX_TRIG_LEVEL   64
+#define AWINAC_TX_MAX_LEVEL    128
+#define AWINAC_INIT_VOL                0x3b
+
+#define AC_DAC_DPC             0x00
+#define  DAC_DPC_EN_DA         __BIT(31)
+#define  DAC_DPC_MODQU         __BITS(28,25)
+#define  DAC_DPC_DWA           __BIT(24)
+#define  DAC_DPC_HPF_EN                __BIT(18)
+#define  DAC_DPC_DVOL          __BITS(17,12)
+#define AC_DAC_FIFOC           0x04
+#define  DAC_FIFOC_FS          __BITS(31,29)
+#define   DAC_FS_48KHZ         0
+#define   DAC_FS_32KHZ         1
+#define   DAC_FS_24KHZ         2
+#define   DAC_FS_16KHZ         3
+#define   DAC_FS_12KHZ         4
+#define   DAC_FS_8KHZ          5
+#define   DAC_FS_192KHZ                6
+#define   DAC_FS_96KHZ         7
+#define  DAC_FIFOC_FIR_VER     __BIT(28)
+#define  DAC_FIFOC_SEND_LASAT  __BIT(26)
+#define  DAC_FIFOC_FIFO_MODE   __BITS(25,24)
+#define   FIFO_MODE_24_31_8    0
+#define   FIFO_MODE_16_31_16   0
+#define   FIFO_MODE_16_15_0    1
+#define  DAC_FIFOC_DRQ_CLR_CNT __BITS(22,21)
+#define  DAC_FIFOC_TX_TRIG_LEVEL __BITS(14,8)
+#define  DAC_FIFOC_ADDA_LOOP_EN        __BIT(7)
+#define  DAC_FIFOC_MONO_EN     __BIT(6)
+#define  DAC_FIFOC_TX_SAMPLE_BITS __BIT(5)
+#define  DAC_FIFOC_DRQ_EN      __BIT(4)
+#define  DAC_FIFOC_IRQ_EN      __BIT(3)
+#define  DAC_FIFOC_FIFO_UNDERRUN_IRQ_EN __BIT(2)
+#define  DAC_FIFOC_FIFO_OVERRUN_IRQ_EN __BIT(1)
+#define  DAC_FIFOC_FIFO_FLUSH  __BIT(0)
+#define AC_DAC_FIFOS           0x08
+#define  DAC_FIFOS_TX_EMPTY    __BIT(23)
+#define  DAC_FIFOS_TXE_CNT     __BITS(22,8)
+#define  DAC_FIFOS_TXE_INT     __BIT(3)
+#define  DAC_FIFOS_TXU_INT     __BIT(2)
+#define  DAC_FIFOS_TXO_INT     __BIT(1)
+#define  DAC_FIFOS_INT_MASK    __BITS(3,1)
+#define AC_DAC_TXDATA          0x0c
+#define AC_DAC_ACTL            0x10
+#define  DAC_ACTL_DACAREN      __BIT(31)
+#define  DAC_ACTL_DACALEN      __BIT(30)
+#define  DAC_ACTL_MIXEN                __BIT(29)
+#define  DAC_ACTL_LNG          __BIT(26)
+#define  DAC_ACTL_FMG          __BITS(25,23)
+#define  DAC_ACTL_MICG         __BITS(22,20)
+#define  DAC_ACTL_LLNS         __BIT(19)
+#define  DAC_ACTL_RLNS         __BIT(18)
+#define  DAC_ACTL_LFMS         __BIT(17)
+#define  DAC_ACTL_RFMS         __BIT(16)
+#define  DAC_ACTL_LDACLMIXS    __BIT(15)
+#define  DAC_ACTL_RDACRMIXS    __BIT(14)
+#define  DAC_ACTL_LDACRMIXS    __BIT(13)
+#define  DAC_ACTL_MIC1LS       __BIT(12)
+#define  DAC_ACTL_MIC1RS       __BIT(11)
+#define  DAC_ACTL_MIC2LS       __BIT(10)
+#define  DAC_ACTL_MIC2RS       __BIT(9)
+#define  DAC_ACTL_DACPAS       __BIT(8)
+#define  DAC_ACTL_MIXPAS       __BIT(7)
+#define  DAC_ACTL_PAMUTE       __BIT(6)
+#define  DAC_ACTL_PAVOL                __BITS(5,0)
+#define AC_DAC_TUNE            0x14
+#define AC_ADC_FIFOC           0x1c
+#define AC_ADC_FIFOS           0x20
+#define AC_ADC_RXDATA          0x24
+#define AC_ADC_ACTL            0x28
+#define AC_DAC_CNT             0x30
+#define AC_ADC_CNT             0x34
+#define AC_DAC_CAL             0x38
+#define AC_MIC_PHONE_CAL       0x3c
+
+struct awinac_softc {
+       device_t                sc_dev;
+       device_t                sc_audiodev;
+
+       bus_space_tag_t         sc_bst;
+       bus_space_handle_t      sc_bsh;
+
+       kmutex_t                sc_lock;
+       kmutex_t                sc_intr_lock;
+
+       struct audio_format     sc_format;
+       struct audio_encoding_set *sc_encodings;
+
+       audio_params_t          sc_pparam;
+
+       void *                  sc_ih;
+       void *                  sc_sih;
+       int                     sc_psamples;
+       void                    (*sc_pint)(void *);
+       void                    *sc_pintarg;
+       int16_t                 *sc_pstart;
+       int16_t                 *sc_pend;
+       int16_t                 *sc_pcur;
+       int                     sc_pblksize;
+       int                     sc_pbytes;
+
+       struct awin_gpio_pindata sc_pactrl_gpio;
+       bool                    sc_has_pactrl_gpio;
+};
+
+static int     awinac_match(device_t, cfdata_t, void *);
+static void    awinac_attach(device_t, device_t, void *);
+static int     awinac_rescan(device_t, const char *, const int *);
+static void    awinac_childdet(device_t, device_t);
+
+static void    awinac_init(struct awinac_softc *);
+
+static int     awinac_intr(void *);
+static void    awinac_softintr(void *);
+
+static int     awinac_open(void *, int);
+static void    awinac_close(void *);
+static int     awinac_drain(void *);
+static int     awinac_query_encoding(void *, struct audio_encoding *);
+static int     awinac_set_params(void *, int, int,
+                                 audio_params_t *,
+                                 audio_params_t *,
+                                 stream_filter_list_t *,
+                                 stream_filter_list_t *);
+static int     awinac_commit_settings(void *);
+static int     awinac_halt_output(void *);
+static int     awinac_halt_input(void *);
+static int     awinac_set_port(void *, mixer_ctrl_t *);
+static int     awinac_get_port(void *, mixer_ctrl_t *);
+static int     awinac_query_devinfo(void *, mixer_devinfo_t *);
+static int     awinac_getdev(void *, struct audio_device *);
+static int     awinac_get_props(void *);
+static int     awinac_round_blocksize(void *, int, int,
+                                      const audio_params_t *);
+static size_t  awinac_round_buffersize(void *, int, size_t);
+static int     awinac_trigger_output(void *, void *, void *, int,
+                                     void (*)(void *), void *,
+                                     const audio_params_t *);
+static int     awinac_trigger_input(void *, void *, void *, int,
+                                    void (*)(void *), void *,
+                                    const audio_params_t *);
+static void    awinac_get_locks(void *, kmutex_t **, kmutex_t **);
+
+static const struct audio_hw_if awinac_hw_if = {
+       .open = awinac_open,
+       .close = awinac_close,
+       .drain = awinac_drain,
+       .query_encoding = awinac_query_encoding,
+       .set_params = awinac_set_params,
+       .commit_settings = awinac_commit_settings,
+       .halt_output = awinac_halt_output,
+       .halt_input = awinac_halt_input,
+       .getdev = awinac_getdev,
+       .set_port = awinac_set_port,
+       .get_port = awinac_get_port,
+       .query_devinfo = awinac_query_devinfo,
+       .get_props = awinac_get_props,
+       .round_blocksize = awinac_round_blocksize,
+       .round_buffersize = awinac_round_buffersize,
+       .trigger_output = awinac_trigger_output,
+       .trigger_input = awinac_trigger_input,
+       .get_locks = awinac_get_locks,
+};
+
+enum {
+       AC_OUTPUT_CLASS,
+       AC_INPUT_CLASS,
+       AC_OUTPUT_MASTER_VOLUME,
+       AC_INPUT_DAC_VOLUME,
+       AC_ENUM_LAST
+};
+
+CFATTACH_DECL2_NEW(awin_ac, sizeof(struct awinac_softc),
+       awinac_match, awinac_attach, NULL, NULL,
+       awinac_rescan, awinac_childdet);
+
+#define AC_WRITE(sc, reg, val) \
+       bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+#define AC_READ(sc, reg) \
+       bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+
+static int
+awinac_match(device_t parent, cfdata_t cf, void *aux)
+{
+       struct awinio_attach_args * const aio = aux;
+       const struct awin_locators * const loc = &aio->aio_loc;
+       const int port = cf->cf_loc[AWINIOCF_PORT];
+
+       if (strcmp(cf->cf_name, loc->loc_name))
+               return 0;
+
+       if (port != AWINIOCF_PORT_DEFAULT && port != loc->loc_port)
+               return 0;
+
+       return 1;
+}
+
+static void
+awinac_attach(device_t parent, device_t self, void *aux)
+{
+       struct awinac_softc * const sc = device_private(self);
+       struct awinio_attach_args * const aio = aux;
+       const struct awin_locators * const loc = &aio->aio_loc;
+       prop_dictionary_t cfg = device_properties(self);
+       const char *pin_name;
+       int error;
+
+       sc->sc_dev = self;
+       sc->sc_bst = aio->aio_core_bst;
+       bus_space_subregion(sc->sc_bst, aio->aio_core_bsh,
+           loc->loc_offset, loc->loc_size, &sc->sc_bsh);
+       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+       mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+       aprint_naive("\n");
+       aprint_normal(": CODEC\n");
+
+       if (prop_dictionary_get_cstring_nocopy(cfg, "pactrl-gpio", &pin_name)) {
+               if (!awin_gpio_pin_reserve(pin_name, &sc->sc_pactrl_gpio)) {
+                       aprint_error_dev(self,
+                           "failed to reserve GPIO \"%s\"\n", pin_name);
+               } else {
+                       sc->sc_has_pactrl_gpio = true;
+               }
+       }
+
+       awin_pll2_enable();
+       awin_reg_set_clear(sc->sc_bst, aio->aio_ccm_bsh,
+           AWIN_APB0_GATING_REG, AWIN_APB0_GATING_ADDA, 0);
+       awin_reg_set_clear(sc->sc_bst, aio->aio_ccm_bsh,
+           AWIN_AUDIO_CODEC_CLK_REG, AWIN_CLK_ENABLE, 0);
+
+       if (sc->sc_has_pactrl_gpio)
+               awin_gpio_pindata_write(&sc->sc_pactrl_gpio, 0);
+
+       awinac_init(sc);
+
+       sc->sc_ih = intr_establish(loc->loc_intr, IPL_SCHED, IST_LEVEL,
+           awinac_intr, sc);
+       if (sc->sc_ih == NULL) {
+               aprint_error_dev(self, "couldn't establish interrupt %d\n",
+                   loc->loc_intr);
+               return;
+       }
+
+       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;



Home | Main Index | Thread Index | Old Index