ASoC: sun8i-codec: Add AIF, ADC, and DAC volume controls
authorSamuel Holland <samuel@sholland.org>
Thu, 18 Nov 2021 03:36:45 +0000 (21:36 -0600)
committerMark Brown <broonie@kernel.org>
Mon, 29 Nov 2021 12:19:47 +0000 (12:19 +0000)
This allows changing the volume of each digital input/output
independently, and provides the only "master volume" for the DAC.
(The ADC also has a gain control on the analog side.)

While the hardware supports digital gain up to +72dB, the controls here
are limited to +24dB maximum, as any gain above that level makes volume
sliders difficult to use, and is extremely likely to cause clipping.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Link: https://lore.kernel.org/r/20211118033645.43524-1-samuel@sholland.org
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sunxi/sun8i-codec.c

index 518bfb724a5b26bbb9898009ce00c81238479fb8..0bea2162f68d98464ab650118270b6fb6bfa7de9 100644 (file)
@@ -21,6 +21,7 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/tlv.h>
 
 #define SUN8I_SYSCLK_CTL                               0x00c
 #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA                   11
 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR       10
 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR           9
 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL       8
+#define SUN8I_AIF1_VOL_CTRL1                           0x050
+#define SUN8I_AIF1_VOL_CTRL1_AD0L_VOL                  8
+#define SUN8I_AIF1_VOL_CTRL1_AD0R_VOL                  0
+#define SUN8I_AIF1_VOL_CTRL3                           0x058
+#define SUN8I_AIF1_VOL_CTRL3_DA0L_VOL                  8
+#define SUN8I_AIF1_VOL_CTRL3_DA0R_VOL                  0
 #define SUN8I_AIF2_ADCDAT_CTRL                         0x084
 #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA           15
 #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA           14
 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R       10
 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL       9
 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR           8
+#define SUN8I_AIF2_VOL_CTRL1                           0x090
+#define SUN8I_AIF2_VOL_CTRL1_ADCL_VOL                  8
+#define SUN8I_AIF2_VOL_CTRL1_ADCR_VOL                  0
+#define SUN8I_AIF2_VOL_CTRL2                           0x098
+#define SUN8I_AIF2_VOL_CTRL2_DACL_VOL                  8
+#define SUN8I_AIF2_VOL_CTRL2_DACR_VOL                  0
 #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1          (0x0 << 0)
 #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2          (0x1 << 0)
 #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1CLK       (0x2 << 0)
 #define SUN8I_ADC_DIG_CTRL_ENAD                                15
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS                   2
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY                   1
+#define SUN8I_ADC_VOL_CTRL                             0x104
+#define SUN8I_ADC_VOL_CTRL_ADCL_VOL                    8
+#define SUN8I_ADC_VOL_CTRL_ADCR_VOL                    0
 #define SUN8I_DAC_DIG_CTRL                             0x120
 #define SUN8I_DAC_DIG_CTRL_ENDA                                15
+#define SUN8I_DAC_VOL_CTRL                             0x124
+#define SUN8I_DAC_VOL_CTRL_DACL_VOL                    8
+#define SUN8I_DAC_VOL_CTRL_DACR_VOL                    0
 #define SUN8I_DAC_MXR_SRC                              0x130
 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L                15
 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L                14
@@ -696,6 +715,41 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
        },
 };
 
+static const DECLARE_TLV_DB_SCALE(sun8i_codec_vol_scale, -12000, 75, 1);
+
+static const struct snd_kcontrol_new sun8i_codec_controls[] = {
+       SOC_DOUBLE_TLV("AIF1 AD0 Capture Volume",
+                      SUN8I_AIF1_VOL_CTRL1,
+                      SUN8I_AIF1_VOL_CTRL1_AD0L_VOL,
+                      SUN8I_AIF1_VOL_CTRL1_AD0R_VOL,
+                      0xc0, 0, sun8i_codec_vol_scale),
+       SOC_DOUBLE_TLV("AIF1 DA0 Playback Volume",
+                      SUN8I_AIF1_VOL_CTRL3,
+                      SUN8I_AIF1_VOL_CTRL3_DA0L_VOL,
+                      SUN8I_AIF1_VOL_CTRL3_DA0R_VOL,
+                      0xc0, 0, sun8i_codec_vol_scale),
+       SOC_DOUBLE_TLV("AIF2 ADC Capture Volume",
+                      SUN8I_AIF2_VOL_CTRL1,
+                      SUN8I_AIF2_VOL_CTRL1_ADCL_VOL,
+                      SUN8I_AIF2_VOL_CTRL1_ADCR_VOL,
+                      0xc0, 0, sun8i_codec_vol_scale),
+       SOC_DOUBLE_TLV("AIF2 DAC Playback Volume",
+                      SUN8I_AIF2_VOL_CTRL2,
+                      SUN8I_AIF2_VOL_CTRL2_DACL_VOL,
+                      SUN8I_AIF2_VOL_CTRL2_DACR_VOL,
+                      0xc0, 0, sun8i_codec_vol_scale),
+       SOC_DOUBLE_TLV("ADC Capture Volume",
+                      SUN8I_ADC_VOL_CTRL,
+                      SUN8I_ADC_VOL_CTRL_ADCL_VOL,
+                      SUN8I_ADC_VOL_CTRL_ADCR_VOL,
+                      0xc0, 0, sun8i_codec_vol_scale),
+       SOC_DOUBLE_TLV("DAC Playback Volume",
+                      SUN8I_DAC_VOL_CTRL,
+                      SUN8I_DAC_VOL_CTRL_DACL_VOL,
+                      SUN8I_DAC_VOL_CTRL_DACR_VOL,
+                      0xc0, 0, sun8i_codec_vol_scale),
+};
+
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
                                 struct snd_kcontrol *kcontrol, int event)
 {
@@ -1215,6 +1269,8 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 }
 
 static const struct snd_soc_component_driver sun8i_soc_component = {
+       .controls               = sun8i_codec_controls,
+       .num_controls           = ARRAY_SIZE(sun8i_codec_controls),
        .dapm_widgets           = sun8i_codec_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(sun8i_codec_dapm_widgets),
        .dapm_routes            = sun8i_codec_dapm_routes,