Module Name:    src
Committed By:   jmcneill
Date:           Sun May 13 01:01:37 UTC 2018

Modified Files:
        src/sys/arch/arm/sunxi: sun50i_a64_acodec.c

Log Message:
Mixer improvements:

 - outputs.master switches between line and hp volume control, depending
   on jack sense
 - add outputs.source to override jack sense output routing
 - (playback) line and hp controls are in the input class
 - (capture) line and mic controls are in the record class


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/sunxi/sun50i_a64_acodec.c

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/sunxi/sun50i_a64_acodec.c
diff -u src/sys/arch/arm/sunxi/sun50i_a64_acodec.c:1.4 src/sys/arch/arm/sunxi/sun50i_a64_acodec.c:1.5
--- src/sys/arch/arm/sunxi/sun50i_a64_acodec.c:1.4	Fri May 11 23:05:41 2018
+++ src/sys/arch/arm/sunxi/sun50i_a64_acodec.c	Sun May 13 01:01:37 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: sun50i_a64_acodec.c,v 1.4 2018/05/11 23:05:41 jmcneill Exp $ */
+/* $NetBSD: sun50i_a64_acodec.c,v 1.5 2018/05/13 01:01:37 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sun50i_a64_acodec.c,v 1.4 2018/05/11 23:05:41 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sun50i_a64_acodec.c,v 1.5 2018/05/13 01:01:37 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -57,6 +57,7 @@ __KERNEL_RCSID(0, "$NetBSD: sun50i_a64_a
 #define	A64_LINEOUT_CTRL0	0x05
 #define	 A64_LINEOUT_LEFT_EN	__BIT(7)
 #define	 A64_LINEOUT_RIGHT_EN	__BIT(6)
+#define	 A64_LINEOUT_EN		(A64_LINEOUT_LEFT_EN|A64_LINEOUT_RIGHT_EN)
 #define	A64_LINEOUT_CTRL1	0x06
 #define	 A64_LINEOUT_VOL	__BITS(4,0)
 #define	A64_MIC1_CTRL		0x07
@@ -101,6 +102,7 @@ struct a64_acodec_softc {
 	int			sc_phandle;
 
 	struct audio_dai_device	sc_dai;
+	int			sc_master_dev;
 };
 
 enum a64_acodec_mixer_ctrl {
@@ -109,35 +111,38 @@ enum a64_acodec_mixer_ctrl {
 	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_OUTPUT_SOURCE,
+	A64_CODEC_INPUT_LINE_VOLUME,
+	A64_CODEC_INPUT_HP_VOLUME,
+	A64_CODEC_RECORD_LINE_VOLUME,
+	A64_CODEC_RECORD_MIC1_VOLUME,
+	A64_CODEC_RECORD_MIC2_VOLUME,
 	A64_CODEC_RECORD_AGC_VOLUME,
 	A64_CODEC_RECORD_SOURCE,
 
 	A64_CODEC_MIXER_CTRL_LAST
 };
 
+#define	A64_OUTPUT_SOURCE_LINE	__BIT(0)
+#define	A64_OUTPUT_SOURCE_HP	__BIT(1)
+
 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_LINE_VOLUME]	= { AudioNline,
 	    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_INPUT_HP_VOLUME]	= { AudioNheadphone,
+	    A64_CODEC_INPUT_CLASS, A64_HP_CTRL, A64_HPVOL },
+
+	[A64_CODEC_RECORD_LINE_VOLUME]	= { AudioNline,
+	    A64_CODEC_RECORD_CLASS, A64_LINEIN_CTRL, A64_LINEING },
+	[A64_CODEC_RECORD_MIC1_VOLUME]	= { "mic1",
+	    A64_CODEC_RECORD_CLASS, A64_MIC1_CTRL, A64_MIC1G },
+	[A64_CODEC_RECORD_MIC2_VOLUME]	= { "mic2",
+	    A64_CODEC_RECORD_CLASS, A64_MIC2_CTRL, A64_MIC2G },
 	[A64_CODEC_RECORD_AGC_VOLUME]	= { AudioNagc,
 	    A64_CODEC_RECORD_CLASS, A64_ADC_CTRL, A64_ADCG },
 };
@@ -281,17 +286,20 @@ a64_acodec_set_port(void *priv, mixer_ct
 	struct a64_acodec_softc * const sc = priv;
 	const struct a64_acodec_mixer *mix;
 	u_int val, shift;
-	int nvol;
+	int nvol, dev;
 
-	switch (mc->dev) {
-	case A64_CODEC_OUTPUT_MASTER_VOLUME:
-	case A64_CODEC_OUTPUT_HP_VOLUME:
-	case A64_CODEC_INPUT_DAC_VOLUME:
-	case A64_CODEC_INPUT_LINEIN_VOLUME:
-	case A64_CODEC_INPUT_MIC1_VOLUME:
-	case A64_CODEC_INPUT_MIC2_VOLUME:
+	dev = mc->dev;
+	if (dev == A64_CODEC_OUTPUT_MASTER_VOLUME)
+		dev = sc->sc_master_dev;
+
+	switch (dev) {
+	case A64_CODEC_INPUT_LINE_VOLUME:
+	case A64_CODEC_INPUT_HP_VOLUME:
+	case A64_CODEC_RECORD_LINE_VOLUME:
+	case A64_CODEC_RECORD_MIC1_VOLUME:
+	case A64_CODEC_RECORD_MIC2_VOLUME:
 	case A64_CODEC_RECORD_AGC_VOLUME:
-		mix = &a64_acodec_mixers[mc->dev];
+		mix = &a64_acodec_mixers[dev];
 		val = a64_acodec_pr_read(sc, mix->reg);
 		shift = 8 - fls32(__SHIFTOUT_MASK(mix->mask));
 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] >> shift;
@@ -300,6 +308,22 @@ a64_acodec_set_port(void *priv, mixer_ct
 		a64_acodec_pr_write(sc, mix->reg, val);
 		return 0;
 
+	case A64_CODEC_OUTPUT_SOURCE:
+		if (mc->un.mask & A64_OUTPUT_SOURCE_LINE)
+			a64_acodec_pr_set_clear(sc, A64_LINEOUT_CTRL0,
+			    A64_LINEOUT_EN, 0);
+		else
+			a64_acodec_pr_set_clear(sc, A64_LINEOUT_CTRL0,
+			    0, A64_LINEOUT_EN);
+
+		if (mc->un.mask & A64_OUTPUT_SOURCE_HP)
+			a64_acodec_pr_set_clear(sc, A64_HP_CTRL,
+			    A64_HPPA_EN, 0);
+		else
+			a64_acodec_pr_set_clear(sc, A64_HP_CTRL,
+			    0, A64_HPPA_EN);
+		return 0;
+
 	case A64_CODEC_RECORD_SOURCE:
 		a64_acodec_pr_write(sc, A64_L_ADCMIX_SRC, mc->un.mask);
 		a64_acodec_pr_write(sc, A64_R_ADCMIX_SRC, mc->un.mask);
@@ -315,17 +339,20 @@ a64_acodec_get_port(void *priv, mixer_ct
 	struct a64_acodec_softc * const sc = priv;
 	const struct a64_acodec_mixer *mix;
 	u_int val, shift;
-	int nvol;
+	int nvol, dev;
 
-	switch (mc->dev) {
-	case A64_CODEC_OUTPUT_MASTER_VOLUME:
-	case A64_CODEC_OUTPUT_HP_VOLUME:
-	case A64_CODEC_INPUT_DAC_VOLUME:
-	case A64_CODEC_INPUT_LINEIN_VOLUME:
-	case A64_CODEC_INPUT_MIC1_VOLUME:
-	case A64_CODEC_INPUT_MIC2_VOLUME:
+	dev = mc->dev;
+	if (dev == A64_CODEC_OUTPUT_MASTER_VOLUME)
+		dev = sc->sc_master_dev;
+
+	switch (dev) {
+	case A64_CODEC_INPUT_LINE_VOLUME:
+	case A64_CODEC_INPUT_HP_VOLUME:
+	case A64_CODEC_RECORD_LINE_VOLUME:
+	case A64_CODEC_RECORD_MIC1_VOLUME:
+	case A64_CODEC_RECORD_MIC2_VOLUME:
 	case A64_CODEC_RECORD_AGC_VOLUME:
-		mix = &a64_acodec_mixers[mc->dev];
+		mix = &a64_acodec_mixers[dev];
 		val = a64_acodec_pr_read(sc, mix->reg);
 		shift = 8 - fls32(__SHIFTOUT_MASK(mix->mask));
 		nvol = __SHIFTOUT(val, mix->mask) << shift;
@@ -333,6 +360,14 @@ a64_acodec_get_port(void *priv, mixer_ct
 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = nvol;
 		return 0;
 
+	case A64_CODEC_OUTPUT_SOURCE:
+		mc->un.mask = 0;
+		if (a64_acodec_pr_read(sc, A64_LINEOUT_CTRL0) & A64_LINEOUT_EN)
+			mc->un.mask |= A64_OUTPUT_SOURCE_LINE;
+		if (a64_acodec_pr_read(sc, A64_HP_CTRL) & A64_HPPA_EN)
+			mc->un.mask |= A64_OUTPUT_SOURCE_HP;
+		return 0;
+
 	case A64_CODEC_RECORD_SOURCE:
 		mc->un.mask =
 		    a64_acodec_pr_read(sc, A64_L_ADCMIX_SRC) |
@@ -346,6 +381,7 @@ a64_acodec_get_port(void *priv, mixer_ct
 static int
 a64_acodec_query_devinfo(void *priv, mixer_devinfo_t *di)
 {
+	struct a64_acodec_softc * const sc = priv;
 	const struct a64_acodec_mixer *mix;
 
 	switch (di->index) {
@@ -371,11 +407,22 @@ a64_acodec_query_devinfo(void *priv, mix
 		return 0;
 
 	case A64_CODEC_OUTPUT_MASTER_VOLUME:
-	case A64_CODEC_OUTPUT_HP_VOLUME:
-	case A64_CODEC_INPUT_DAC_VOLUME:
-	case A64_CODEC_INPUT_LINEIN_VOLUME:
-	case A64_CODEC_INPUT_MIC1_VOLUME:
-	case A64_CODEC_INPUT_MIC2_VOLUME:
+		mix = &a64_acodec_mixers[sc->sc_master_dev];
+		di->mixer_class = A64_CODEC_OUTPUT_CLASS;
+		strcpy(di->label.name, AudioNmaster);
+		di->un.v.delta =
+		    256 / (__SHIFTOUT_MASK(mix->mask) + 1);
+		di->type = AUDIO_MIXER_VALUE;
+		di->next = di->prev = AUDIO_MIXER_LAST;
+		di->un.v.num_channels = 2;
+		strcpy(di->un.v.units.name, AudioNvolume);
+		return 0;
+
+	case A64_CODEC_INPUT_LINE_VOLUME:
+	case A64_CODEC_INPUT_HP_VOLUME:
+	case A64_CODEC_RECORD_LINE_VOLUME:
+	case A64_CODEC_RECORD_MIC1_VOLUME:
+	case A64_CODEC_RECORD_MIC2_VOLUME:
 	case A64_CODEC_RECORD_AGC_VOLUME:
 		mix = &a64_acodec_mixers[di->index];
 		di->mixer_class = mix->mixer_class;
@@ -388,6 +435,18 @@ a64_acodec_query_devinfo(void *priv, mix
 		strcpy(di->un.v.units.name, AudioNvolume);
 		return 0;
 
+	case A64_CODEC_OUTPUT_SOURCE:
+		di->mixer_class = A64_CODEC_OUTPUT_CLASS;
+		strcpy(di->label.name, AudioNsource);
+		di->type = AUDIO_MIXER_SET;
+		di->next = di->prev = AUDIO_MIXER_LAST;
+		di->un.s.num_mem = 2;
+		strcpy(di->un.s.member[0].label.name, AudioNline);
+		di->un.s.member[0].mask = A64_OUTPUT_SOURCE_LINE;
+		strcpy(di->un.s.member[1].label.name, AudioNheadphone);
+		di->un.s.member[1].mask = A64_OUTPUT_SOURCE_HP;
+		return 0;
+
 	case A64_CODEC_RECORD_SOURCE:
 		di->mixer_class = A64_CODEC_RECORD_CLASS;
 		strcpy(di->label.name, AudioNsource);
@@ -438,23 +497,27 @@ static int
 a64_acodec_dai_jack_detect(audio_dai_tag_t dai, u_int jack, int present)
 {
 	struct a64_acodec_softc * const sc = audio_dai_private(dai);
-	const uint32_t lineout_mask = A64_LINEOUT_LEFT_EN | A64_LINEOUT_RIGHT_EN;
-	const uint32_t hppa_mask = A64_HPPA_EN;
 
 	switch (jack) {
 	case AUDIO_DAI_JACK_HP:
 		if (present) {
 			a64_acodec_pr_set_clear(sc, A64_LINEOUT_CTRL0,
-			    0, lineout_mask);
+			    0, A64_LINEOUT_EN);
 			a64_acodec_pr_set_clear(sc, A64_HP_CTRL,
-			    hppa_mask, 0);
+			    A64_HPPA_EN, 0);
 		} else {
 			a64_acodec_pr_set_clear(sc, A64_LINEOUT_CTRL0,
-			    lineout_mask, 0);
+			    A64_LINEOUT_EN, 0);
 			a64_acodec_pr_set_clear(sc, A64_HP_CTRL,
-			    0, hppa_mask);
+			    0, A64_HPPA_EN);
 		}
+
+		/* Master volume controls either HP or line out */
+		sc->sc_master_dev = present ?
+		    A64_CODEC_INPUT_HP_VOLUME : A64_CODEC_INPUT_LINE_VOLUME;
+
 		break;
+
 	case AUDIO_DAI_JACK_MIC:
 		/* XXX TODO */
 		break;
@@ -506,6 +569,7 @@ a64_acodec_attach(device_t parent, devic
 	    A64_HPPA_EN, 0);
 
 	/* Jack detect enable */
+	sc->sc_master_dev = A64_CODEC_INPUT_HP_VOLUME;
 	a64_acodec_pr_set_clear(sc, A64_JACK_MIC_CTRL,
 	    A64_JACKDETEN | A64_INNERRESEN | A64_AUTOPLEN, 0);
 

Reply via email to