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