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 Mixer improvements:



details:   https://anonhg.NetBSD.org/src/rev/2fa493abb141
branches:  trunk
changeset: 319008:2fa493abb141
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sun May 13 01:01:37 2018 +0000
description:
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

diffstat:

 sys/arch/arm/sunxi/sun50i_a64_acodec.c |  158 +++++++++++++++++++++++---------
 1 files changed, 111 insertions(+), 47 deletions(-)

diffs (284 lines):

diff -r 9c240ffb9f45 -r 2fa493abb141 sys/arch/arm/sunxi/sun50i_a64_acodec.c
--- a/sys/arch/arm/sunxi/sun50i_a64_acodec.c    Sun May 13 00:04:23 2018 +0000
+++ b/sys/arch/arm/sunxi/sun50i_a64_acodec.c    Sun May 13 01:01:37 2018 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -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 @@
 #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 @@
        int                     sc_phandle;
 
        struct audio_dai_device sc_dai;
+       int                     sc_master_dev;
 };
 
 enum a64_acodec_mixer_ctrl {
@@ -109,35 +111,38 @@
        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 @@
        struct a64_acodec_softc * const sc = priv;
        const struct a64_acodec_mixer *mix;
        u_int val, shift;
-       int nvol;
+       int nvol, dev;
+
+       dev = mc->dev;
+       if (dev == A64_CODEC_OUTPUT_MASTER_VOLUME)
+               dev = sc->sc_master_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:
+       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_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 @@
        struct a64_acodec_softc * const sc = priv;
        const struct a64_acodec_mixer *mix;
        u_int val, shift;
-       int nvol;
+       int nvol, dev;
+
+       dev = mc->dev;
+       if (dev == A64_CODEC_OUTPUT_MASTER_VOLUME)
+               dev = sc->sc_master_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:
+       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 @@
                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 @@
 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 @@
                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 @@
                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 @@
 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_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);
 



Home | Main Index | Thread Index | Old Index