Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/arm/sunxi Add support for Allwinner A64 audio codec.



details:   https://anonhg.NetBSD.org/src/rev/d0c929617360
branches:  trunk
changeset: 322634:d0c929617360
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Thu May 10 00:00:21 2018 +0000

description:
Add support for Allwinner A64 audio codec.

diffstat:

 sys/arch/arm/sunxi/files.sunxi         |   17 +-
 sys/arch/arm/sunxi/sun50i_a64_acodec.c |  483 +++++++++++++++++++
 sys/arch/arm/sunxi/sun8i_codec.c       |  312 ++++++++++++
 sys/arch/arm/sunxi/sunxi_i2s.c         |  827 +++++++++++++++++++++++++++++++++
 4 files changed, 1638 insertions(+), 1 deletions(-)

diffs (truncated from 1670 to 300 lines):

diff -r 888febd6fd90 -r d0c929617360 sys/arch/arm/sunxi/files.sunxi
--- a/sys/arch/arm/sunxi/files.sunxi    Wed May 09 23:59:05 2018 +0000
+++ b/sys/arch/arm/sunxi/files.sunxi    Thu May 10 00:00:21 2018 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.sunxi,v 1.54 2018/05/06 10:34:34 jmcneill Exp $
+#      $NetBSD: files.sunxi,v 1.55 2018/05/10 00:00:21 jmcneill Exp $
 #
 # Configuration info for Allwinner sunxi family SoCs
 #
@@ -208,11 +208,26 @@
 file   arch/arm/sunxi/sun4i_a10_codec.c        sunxi_codec
 file   arch/arm/sunxi/sun6i_a31_codec.c        sunxi_codec
 
+# Audio codec (sun8i)
+device sun8icodec
+attach sun8icodec at fdt with sun8i_codec
+file   arch/arm/sunxi/sun8i_codec.c            sun8i_codec
+
 # H3 Audio codec (analog part)
 device h3codec
 attach h3codec at fdt with h3_codec
 file   arch/arm/sunxi/sun8i_h3_codec.c         h3_codec needs-flag
 
+# A64 Audio codec (analog part)
+device a64acodec
+attach a64acodec at fdt with a64_acodec
+file   arch/arm/sunxi/sun50i_a64_acodec.c      a64_acodec
+
+# I2S/PCM controller
+device sunxii2s: auconv, mulaw, aurateconv
+attach sunxii2s at fdt with sunxi_i2s
+file   arch/arm/sunxi/sunxi_i2s.c              sunxi_i2s
+
 # Display controller
 attach genfb at fdt with simplefb
 file   dev/fdt/simplefb.c                      simplefb
diff -r 888febd6fd90 -r d0c929617360 sys/arch/arm/sunxi/sun50i_a64_acodec.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/sunxi/sun50i_a64_acodec.c    Thu May 10 00:00:21 2018 +0000
@@ -0,0 +1,483 @@
+/* $NetBSD: sun50i_a64_acodec.c,v 1.1 2018/05/10 00:00:21 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared 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 <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sun50i_a64_acodec.c,v 1.1 2018/05/10 00:00:21 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+#include <sys/bitops.h>
+
+#include <dev/audio_dai.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#define        A64_PR_CFG              0x00
+#define         A64_AC_PR_RST          __BIT(28)
+#define         A64_AC_PR_RW           __BIT(24)
+#define         A64_AC_PR_ADDR         __BITS(20,16)
+#define         A64_ACDA_PR_WDAT       __BITS(15,8)
+#define         A64_ACDA_PR_RDAT       __BITS(7,0)
+
+#define        A64_HP_CTRL             0x00
+#define         A64_HPPA_EN            __BIT(6)
+#define         A64_HPVOL              __BITS(5,0)
+#define        A64_OL_MIX_CTRL         0x01
+#define         A64_LMIXMUTE_LDAC      __BIT(1)
+#define        A64_OR_MIX_CTRL         0x02
+#define         A64_RMIXMUTE_RDAC      __BIT(1)
+#define        A64_LINEOUT_CTRL0       0x05
+#define         A64_LINEOUT_LEFT_EN    __BIT(7)
+#define         A64_LINEOUT_RIGHT_EN   __BIT(6)
+#define        A64_LINEOUT_CTRL1       0x06
+#define         A64_LINEOUT_VOL        __BITS(4,0)
+#define        A64_MIC1_CTRL           0x07
+#define         A64_MIC1G              __BITS(6,4)
+#define         A64_MIC1AMPEN          __BIT(3)
+#define         A64_MIC1BOOST          __BITS(2,0)
+#define        A64_MIC2_CTRL           0x08
+#define         A64_MIC2_SEL           __BIT(7)
+#define         A64_MIC2G              __BITS(6,4)
+#define         A64_MIC2AMPEN          __BIT(3)
+#define         A64_MIC2BOOST          __BITS(2,0)
+#define        A64_LINEIN_CTRL         0x09
+#define         A64_LINEING            __BITS(6,4)
+#define        A64_MIX_DAC_CTRL        0x0a
+#define         A64_DACAREN            __BIT(7)
+#define         A64_DACALEN            __BIT(6)
+#define         A64_RMIXEN             __BIT(5)
+#define         A64_LMIXEN             __BIT(4)
+#define         A64_RHPPAMUTE          __BIT(3)
+#define         A64_LHPPAMUTE          __BIT(2)
+#define         A64_RHPIS              __BIT(1)
+#define         A64_LHPIS              __BIT(0)
+#define        A64_L_ADCMIX_SRC        0x0b
+#define        A64_R_ADCMIX_SRC        0x0c
+#define         A64_ADCMIX_SRC_MIC1    __BIT(6)
+#define         A64_ADCMIX_SRC_MIC2    __BIT(5)
+#define         A64_ADCMIX_SRC_LINEIN  __BIT(2)
+#define         A64_ADCMIX_SRC_OMIXER  __BIT(0)
+#define        A64_ADC_CTRL            0x0d
+#define         A64_ADCREN             __BIT(7)
+#define         A64_ADCLEN             __BIT(6)
+#define         A64_ADCG               __BITS(2,0)
+
+struct a64_acodec_softc {
+       device_t                sc_dev;
+       bus_space_tag_t         sc_bst;
+       bus_space_handle_t      sc_bsh;
+       int                     sc_phandle;
+
+       struct audio_dai_device sc_dai;
+};
+
+enum a64_acodec_mixer_ctrl {
+       A64_CODEC_OUTPUT_CLASS,
+       A64_CODEC_INPUT_CLASS,
+       A64_CODEC_RECORD_CLASS,
+
+       A64_CODEC_OUTPUT_MASTER_VOLUME,
+       A64_CODEC_OUTPUT_HP_VOLUME,
+       A64_CODEC_INPUT_DAC_VOLUME,
+       A64_CODEC_INPUT_LINEIN_VOLUME,
+       A64_CODEC_INPUT_MIC1_VOLUME,
+       A64_CODEC_INPUT_MIC2_VOLUME,
+       A64_CODEC_RECORD_AGC_VOLUME,
+       A64_CODEC_RECORD_SOURCE,
+
+       A64_CODEC_MIXER_CTRL_LAST
+};
+
+static const struct a64_acodec_mixer {
+       const char *                    name;
+       enum a64_acodec_mixer_ctrl      mixer_class;
+       u_int                           reg;
+       u_int                           mask;
+} a64_acodec_mixers[A64_CODEC_MIXER_CTRL_LAST] = {
+       [A64_CODEC_OUTPUT_MASTER_VOLUME]        = { AudioNmaster,
+           A64_CODEC_OUTPUT_CLASS, A64_LINEOUT_CTRL1, A64_LINEOUT_VOL },
+       [A64_CODEC_OUTPUT_HP_VOLUME]    = { AudioNheadphone,
+           A64_CODEC_OUTPUT_CLASS, A64_HP_CTRL, A64_HPVOL },
+       [A64_CODEC_INPUT_DAC_VOLUME]    = { AudioNdac,
+           A64_CODEC_INPUT_CLASS, A64_LINEOUT_CTRL1, A64_LINEOUT_VOL },
+       [A64_CODEC_INPUT_LINEIN_VOLUME] = { AudioNline,
+           A64_CODEC_INPUT_CLASS, A64_LINEIN_CTRL, A64_LINEING },
+       [A64_CODEC_INPUT_MIC1_VOLUME]   = { "mic1",
+           A64_CODEC_INPUT_CLASS, A64_MIC1_CTRL, A64_MIC1G },
+       [A64_CODEC_INPUT_MIC2_VOLUME]   = { "mic2",
+           A64_CODEC_INPUT_CLASS, A64_MIC2_CTRL, A64_MIC2G },
+       [A64_CODEC_RECORD_AGC_VOLUME]   = { AudioNagc,
+           A64_CODEC_RECORD_CLASS, A64_ADC_CTRL, A64_ADCG },
+};
+
+#define        RD4(sc, reg)                    \
+       bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define        WR4(sc, reg, val)               \
+       bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static u_int
+a64_acodec_pr_read(struct a64_acodec_softc *sc, u_int addr)
+{
+       uint32_t val;
+
+       /* Read current value */
+       val = RD4(sc, A64_PR_CFG);
+
+       /* De-assert reset */
+       val |= A64_AC_PR_RST;
+       WR4(sc, A64_PR_CFG, val);
+
+       /* Read mode */
+       val &= ~A64_AC_PR_RW;
+       WR4(sc, A64_PR_CFG, val);
+
+       /* Set address */
+       val &= ~A64_AC_PR_ADDR;
+       val |= __SHIFTIN(addr, A64_AC_PR_ADDR);
+       WR4(sc, A64_PR_CFG, val);
+
+       /* Read data */
+       return __SHIFTOUT(RD4(sc, A64_PR_CFG), A64_ACDA_PR_RDAT);
+}
+
+static void
+a64_acodec_pr_write(struct a64_acodec_softc *sc, u_int addr, u_int data)
+{
+       uint32_t val;
+
+       /* Read current value */
+       val = RD4(sc, A64_PR_CFG);
+
+       /* De-assert reset */
+       val |= A64_AC_PR_RST;
+       WR4(sc, A64_PR_CFG, val);
+
+       /* Set address */
+       val &= ~A64_AC_PR_ADDR;
+       val |= __SHIFTIN(addr, A64_AC_PR_ADDR);
+       WR4(sc, A64_PR_CFG, val);
+
+       /* Write data */
+       val &= ~A64_ACDA_PR_WDAT;
+       val |= __SHIFTIN(data, A64_ACDA_PR_WDAT);
+       WR4(sc, A64_PR_CFG, val);
+
+       /* Write mode */
+       val |= A64_AC_PR_RW;
+       WR4(sc, A64_PR_CFG, val);
+
+       /* Clear write mode */
+       val &= ~A64_AC_PR_RW;
+       WR4(sc, A64_PR_CFG, val);
+}
+
+static void
+a64_acodec_pr_set_clear(struct a64_acodec_softc *sc, u_int addr, u_int set, u_int clr)
+{
+       u_int old, new;
+
+       old = a64_acodec_pr_read(sc, addr);
+       new = set | (old & ~clr);
+       a64_acodec_pr_write(sc, addr, new);
+}
+
+static int
+a64_acodec_trigger_output(void *priv, void *start, void *end, int blksize,
+    void (*intr)(void *), void *intrarg, const audio_params_t *params)
+{
+       struct a64_acodec_softc * const sc = priv;
+
+       /* Enable DAC analog l/r channels and output mixer */
+       a64_acodec_pr_set_clear(sc, A64_MIX_DAC_CTRL,
+           A64_DACAREN | A64_DACALEN | A64_RMIXEN | A64_LMIXEN, 0);
+       /* Unmute DAC l/r channels to output mixer */
+       a64_acodec_pr_set_clear(sc, A64_OL_MIX_CTRL,
+           A64_LMIXMUTE_LDAC, 0);
+       a64_acodec_pr_set_clear(sc, A64_OR_MIX_CTRL,
+           A64_RMIXMUTE_RDAC, 0);
+
+       return 0;
+}
+
+static int
+a64_acodec_trigger_input(void *priv, void *start, void *end, int blksize,
+    void (*intr)(void *), void *intrarg, const audio_params_t *params)
+{
+       struct a64_acodec_softc * const sc = priv;
+
+       /* Enable ADC analog l/r channels */
+       a64_acodec_pr_set_clear(sc, A64_ADC_CTRL,
+           A64_ADCREN | A64_ADCLEN, 0);
+
+       return 0;
+}
+
+static int
+a64_acodec_halt_output(void *priv)
+{
+       struct a64_acodec_softc * const sc = priv;
+
+       /* Mute DAC l/r channels to output mixer */
+       a64_acodec_pr_set_clear(sc, A64_OL_MIX_CTRL,
+           0, A64_LMIXMUTE_LDAC);
+       a64_acodec_pr_set_clear(sc, A64_OR_MIX_CTRL,
+           0, A64_RMIXMUTE_RDAC);
+       /* Disable DAC analog l/r channels and output mixer */
+       a64_acodec_pr_set_clear(sc, A64_MIX_DAC_CTRL,
+           0, A64_DACAREN | A64_DACALEN | A64_RMIXEN | A64_LMIXEN);
+
+       return 0;
+}
+
+static int



Home | Main Index | Thread Index | Old Index