[alsa-devel] [RFC PATCH 27/34] ASoC: sun8i-codec: Add AIF mono/stereo controls

Samuel Holland
2020-02-17T07:00:11Z

This allows changing the channel mapping for each digital input/output.
This is useful when the DAI (or the device on the other end of the link)
supports a different number of channels than are desired for routing,
for example when using an I2S-format DAI link with a mono endpoint.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
sound/soc/sunxi/sun8i-codec.c | 160 +++++++++++++++++++++++++++++++---
1 file changed, 146 insertions(+), 14 deletions(-)

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 71c4c1f47201..fdb9bf346cc2 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -56,9 +56,13 @@
#define SUN8I_AIF1_ADCDAT_CTRL 0x044
#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15
#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA 14
+#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC 10
+#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC 8
#define SUN8I_AIF1_DACDAT_CTRL 0x048
#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15
#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14
+#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC 10
+#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC 8
#define SUN8I_AIF1_MXR_SRC 0x04c
#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L 15
#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL 14
@@ -71,9 +75,13 @@
#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_ADCDAT_CTRL_AIF2_ADCL_SRC 10
+#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC 8
#define SUN8I_AIF2_DACDAT_CTRL 0x088
#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA 15
#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA 14
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC 10
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC 8
#define SUN8I_AIF2_MXR_SRC 0x08c
#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L 15
#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L 14
@@ -511,6 +519,50 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
},
};

+static const char *const sun8i_aif_stereo_mux_enum_names[] = {
+ "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono"
+};
+
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
+ SUN8I_AIF1_ADCDAT_CTRL,
+ SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC,
+ SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC,
+ sun8i_aif_stereo_mux_enum_names);
+
+static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control =
+ SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route",
+ sun8i_aif1_ad0_stereo_mux_enum);
+
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum,
+ SUN8I_AIF1_DACDAT_CTRL,
+ SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC,
+ SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC,
+ sun8i_aif_stereo_mux_enum_names);
+
+static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control =
+ SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route",
+ sun8i_aif1_da0_stereo_mux_enum);
+
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum,
+ SUN8I_AIF2_ADCDAT_CTRL,
+ SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC,
+ SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC,
+ sun8i_aif_stereo_mux_enum_names);
+
+static const struct snd_kcontrol_new sun8i_aif2_adc_stereo_mux_control =
+ SOC_DAPM_ENUM("AIF2 ADC Stereo Capture Route",
+ sun8i_aif2_adc_stereo_mux_enum);
+
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_dac_stereo_mux_enum,
+ SUN8I_AIF2_DACDAT_CTRL,
+ SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC,
+ SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC,
+ sun8i_aif_stereo_mux_enum_names);
+
+static const struct snd_kcontrol_new sun8i_aif2_dac_stereo_mux_control =
+ SOC_DAPM_ENUM("AIF2 DAC Stereo Playback Route",
+ sun8i_aif2_dac_stereo_mux_enum);
+
static const char *const sun8i_aif3_mux_enum_names[] = {
"None", "AIF2 Left", "AIF2 Right"
};
@@ -609,6 +661,17 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("AIF3 ADC", "AIF3 Capture", 0,
SND_SOC_NOPM, 0, 0),

+ /* AIF "ADC" Mono/Stereo Muxes */
+ SND_SOC_DAPM_MUX("AIF1 AD0 Left Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif1_ad0_stereo_mux_control),
+ SND_SOC_DAPM_MUX("AIF1 AD0 Right Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif1_ad0_stereo_mux_control),
+
+ SND_SOC_DAPM_MUX("AIF2 ADC Left Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif2_adc_stereo_mux_control),
+ SND_SOC_DAPM_MUX("AIF2 ADC Right Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif2_adc_stereo_mux_control),
+
/* AIF "ADC" Muxes */
SND_SOC_DAPM_MUX("AIF3 ADC Capture Route", SND_SOC_NOPM, 0, 0,
&sun8i_aif3_adc_mux_control),
@@ -630,6 +693,17 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
SND_SOC_DAPM_MUX("AIF2 DAC Right Mux", SND_SOC_NOPM, 0, 0,
&sun8i_aif2_dac_mux_control),

+ /* AIF "DAC" Mono/Stereo Muxes */
+ SND_SOC_DAPM_MUX("AIF1 DA0 Left Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif1_da0_stereo_mux_control),
+ SND_SOC_DAPM_MUX("AIF1 DA0 Right Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif1_da0_stereo_mux_control),
+
+ SND_SOC_DAPM_MUX("AIF2 DAC Left Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif2_dac_stereo_mux_control),
+ SND_SOC_DAPM_MUX("AIF2 DAC Right Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif2_dac_stereo_mux_control),
+
/* AIF "DAC" Inputs */
SND_SOC_DAPM_AIF_IN("AIF1 DA0 Left", "AIF1 Playback", 0,
SUN8I_AIF1_DACDAT_CTRL,
@@ -703,52 +777,110 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {

static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
/* AIF "ADC" Output Routes */
- { "AIF1 AD0 Left", NULL, "AIF1 AD0 Left Mixer" },
- { "AIF1 AD0 Right", NULL, "AIF1 AD0 Right Mixer" },
+ { "AIF1 AD0 Left", NULL, "AIF1 AD0 Left Stereo Mux" },
+ { "AIF1 AD0 Right", NULL, "AIF1 AD0 Right Stereo Mux" },

{ "AIF1 AD0 Left", NULL, "AIF1CLK" },
{ "AIF1 AD0 Right", NULL, "AIF1CLK" },

- { "AIF2 ADC Left", NULL, "AIF2 ADC Left Mixer" },
- { "AIF2 ADC Right", NULL, "AIF2 ADC Right Mixer" },
+ { "AIF2 ADC Left", NULL, "AIF2 ADC Left Stereo Mux" },
+ { "AIF2 ADC Right", NULL, "AIF2 ADC Right Stereo Mux" },

{ "AIF2 ADC Left", NULL, "AIF2CLK" },
{ "AIF2 ADC Right", NULL, "AIF2CLK" },

{ "AIF3 ADC", NULL, "AIF3 ADC Capture Route" },

+ /* AIF "ADC" Mono/Stereo Mux Routes */
+ { "AIF1 AD0 Left Stereo Mux", "Stereo", "AIF1 AD0 Left Mixer" },
+ { "AIF1 AD0 Left Stereo Mux", "Reverse Stereo", "AIF1 AD0 Right Mixer" },
+ { "AIF1 AD0 Left Stereo Mux", "Sum Mono", "AIF1 AD0 Left Mixer" },
+ { "AIF1 AD0 Left Stereo Mux", "Sum Mono", "AIF1 AD0 Right Mixer" },
+ { "AIF1 AD0 Left Stereo Mux", "Mix Mono", "AIF1 AD0 Left Mixer" },
+ { "AIF1 AD0 Left Stereo Mux", "Mix Mono", "AIF1 AD0 Right Mixer" },
+
+ { "AIF1 AD0 Right Stereo Mux", "Stereo", "AIF1 AD0 Right Mixer" },
+ { "AIF1 AD0 Right Stereo Mux", "Reverse Stereo", "AIF1 AD0 Left Mixer" },
+ { "AIF1 AD0 Right Stereo Mux", "Sum Mono", "AIF1 AD0 Left Mixer" },
+ { "AIF1 AD0 Right Stereo Mux", "Sum Mono", "AIF1 AD0 Right Mixer" },
+ { "AIF1 AD0 Right Stereo Mux", "Mix Mono", "AIF1 AD0 Left Mixer" },
+ { "AIF1 AD0 Right Stereo Mux", "Mix Mono", "AIF1 AD0 Right Mixer" },
+
+ { "AIF2 ADC Left Stereo Mux", "Stereo", "AIF2 ADC Left Mixer" },
+ { "AIF2 ADC Left Stereo Mux", "Reverse Stereo", "AIF2 ADC Right Mixer" },
+ { "AIF2 ADC Left Stereo Mux", "Sum Mono", "AIF2 ADC Left Mixer" },
+ { "AIF2 ADC Left Stereo Mux", "Sum Mono", "AIF2 ADC Right Mixer" },
+ { "AIF2 ADC Left Stereo Mux", "Mix Mono", "AIF2 ADC Left Mixer" },
+ { "AIF2 ADC Left Stereo Mux", "Mix Mono", "AIF2 ADC Right Mixer" },
+
+ { "AIF2 ADC Right Stereo Mux", "Stereo", "AIF2 ADC Right Mixer" },
+ { "AIF2 ADC Right Stereo Mux", "Reverse Stereo", "AIF2 ADC Left Mixer" },
+ { "AIF2 ADC Right Stereo Mux", "Sum Mono", "AIF2 ADC Left Mixer" },
+ { "AIF2 ADC Right Stereo Mux", "Sum Mono", "AIF2 ADC Right Mixer" },
+ { "AIF2 ADC Right Stereo Mux", "Mix Mono", "AIF2 ADC Left Mixer" },
+ { "AIF2 ADC Right Stereo Mux", "Mix Mono", "AIF2 ADC Right Mixer" },
+
/* AIF "ADC" Mux Routes */
{ "AIF3 ADC Capture Route", "AIF2 Left", "AIF2 ADC Left Mixer" },
{ "AIF3 ADC Capture Route", "AIF2 Right", "AIF2 ADC Right Mixer" },

/* AIF "ADC" Mixer Routes */
- { "AIF1 AD0 Left Mixer", "AIF1 AD0 Mixer AIF1 DA0 Capture Switch", "AIF1 DA0 Left" },
+ { "AIF1 AD0 Left Mixer", "AIF1 AD0 Mixer AIF1 DA0 Capture Switch", "AIF1 DA0 Left Stereo Mux" },
{ "AIF1 AD0 Left Mixer", "AIF1 AD0 Mixer AIF2 DAC Capture Switch", "AIF2 DAC Left Mux" },
{ "AIF1 AD0 Left Mixer", "AIF1 AD0 Mixer ADC Capture Switch", "ADC Left" },
{ "AIF1 AD0 Left Mixer", "AIF1 AD0 Mixer AIF2 DAC Rev Capture Switch", "AIF2 DAC Right Mux" },

- { "AIF1 AD0 Right Mixer", "AIF1 AD0 Mixer AIF1 DA0 Capture Switch", "AIF1 DA0 Right" },
+ { "AIF1 AD0 Right Mixer", "AIF1 AD0 Mixer AIF1 DA0 Capture Switch", "AIF1 DA0 Right Stereo Mux" },
{ "AIF1 AD0 Right Mixer", "AIF1 AD0 Mixer AIF2 DAC Capture Switch", "AIF2 DAC Right Mux" },
{ "AIF1 AD0 Right Mixer", "AIF1 AD0 Mixer ADC Capture Switch", "ADC Right" },
{ "AIF1 AD0 Right Mixer", "AIF1 AD0 Mixer AIF2 DAC Rev Capture Switch", "AIF2 DAC Left Mux" },

- { "AIF2 ADC Left Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0 Left" },
+ { "AIF2 ADC Left Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0 Left Stereo Mux" },
{ "AIF2 ADC Left Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DAC Right Mux" },
{ "AIF2 ADC Left Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADC Left" },

- { "AIF2 ADC Right Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0 Right" },
+ { "AIF2 ADC Right Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0 Right Stereo Mux" },
{ "AIF2 ADC Right Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DAC Left Mux" },
{ "AIF2 ADC Right Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADC Right" },

/* AIF "DAC" Mux Routes */
- { "AIF2 DAC Left Mux", "None", "AIF2 DAC Left" },
+ { "AIF2 DAC Left Mux", "None", "AIF2 DAC Left Stereo Mux" },
{ "AIF2 DAC Left Mux", "AIF2 Left", "AIF3 DAC" },
- { "AIF2 DAC Left Mux", "AIF2 Right", "AIF2 DAC Left" },
+ { "AIF2 DAC Left Mux", "AIF2 Right", "AIF2 DAC Left Stereo Mux" },

- { "AIF2 DAC Right Mux", "None", "AIF2 DAC Right" },
- { "AIF2 DAC Right Mux", "AIF2 Left", "AIF2 DAC Right" },
+ { "AIF2 DAC Right Mux", "None", "AIF2 DAC Right Stereo Mux" },
+ { "AIF2 DAC Right Mux", "AIF2 Left", "AIF2 DAC Right Stereo Mux" },
{ "AIF2 DAC Right Mux", "AIF2 Right", "AIF3 DAC" },

+ /* AIF "DAC" Mono/Stereo Mux Routes */
+ { "AIF1 DA0 Left Stereo Mux", "Stereo", "AIF1 DA0 Left" },
+ { "AIF1 DA0 Left Stereo Mux", "Reverse Stereo", "AIF1 DA0 Right" },
+ { "AIF1 DA0 Left Stereo Mux", "Sum Mono", "AIF1 DA0 Left" },
+ { "AIF1 DA0 Left Stereo Mux", "Sum Mono", "AIF1 DA0 Right" },
+ { "AIF1 DA0 Left Stereo Mux", "Mix Mono", "AIF1 DA0 Left" },
+ { "AIF1 DA0 Left Stereo Mux", "Mix Mono", "AIF1 DA0 Right" },
+
+ { "AIF1 DA0 Right Stereo Mux", "Stereo", "AIF1 DA0 Right" },
+ { "AIF1 DA0 Right Stereo Mux", "Reverse Stereo", "AIF1 DA0 Left" },
+ { "AIF1 DA0 Right Stereo Mux", "Sum Mono", "AIF1 DA0 Left" },
+ { "AIF1 DA0 Right Stereo Mux", "Sum Mono", "AIF1 DA0 Right" },
+ { "AIF1 DA0 Right Stereo Mux", "Mix Mono", "AIF1 DA0 Left" },
+ { "AIF1 DA0 Right Stereo Mux", "Mix Mono", "AIF1 DA0 Right" },
+
+ { "AIF2 DAC Left Stereo Mux", "Stereo", "AIF2 DAC Left" },
+ { "AIF2 DAC Left Stereo Mux", "Reverse Stereo", "AIF2 DAC Right" },
+ { "AIF2 DAC Left Stereo Mux", "Sum Mono", "AIF2 DAC Left" },
+ { "AIF2 DAC Left Stereo Mux", "Sum Mono", "AIF2 DAC Right" },
+ { "AIF2 DAC Left Stereo Mux", "Mix Mono", "AIF2 DAC Left" },
+ { "AIF2 DAC Left Stereo Mux", "Mix Mono", "AIF2 DAC Right" },
+
+ { "AIF2 DAC Right Stereo Mux", "Stereo", "AIF2 DAC Right" },
+ { "AIF2 DAC Right Stereo Mux", "Reverse Stereo", "AIF2 DAC Left" },
+ { "AIF2 DAC Right Stereo Mux", "Sum Mono", "AIF2 DAC Left" },
+ { "AIF2 DAC Right Stereo Mux", "Sum Mono", "AIF2 DAC Right" },
+ { "AIF2 DAC Right Stereo Mux", "Mix Mono", "AIF2 DAC Left" },
+ { "AIF2 DAC Right Stereo Mux", "Mix Mono", "AIF2 DAC Right" },
+
/* AIF "DAC" Input Routes */
{ "AIF1 DA0 Left", NULL, "AIF1CLK" },
{ "AIF1 DA0 Right", NULL, "AIF1CLK" },
@@ -764,11 +896,11 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
{ "DAC Right", NULL, "DAC" },

/* Main DAC Mixer Routes */
- { "DAC Left Mixer", "DAC Mixer AIF1 DA0 Playback Switch", "AIF1 DA0 Left" },
+ { "DAC Left Mixer", "DAC Mixer AIF1 DA0 Playback Switch", "AIF1 DA0 Left Stereo Mux" },
{ "DAC Left Mixer", "DAC Mixer AIF2 DAC Playback Switch", "AIF2 DAC Left Mux" },
{ "DAC Left Mixer", "DAC Mixer ADC Playback Switch", "ADC Left" },

- { "DAC Right Mixer", "DAC Mixer AIF1 DA0 Playback Switch", "AIF1 DA0 Right" },
+ { "DAC Right Mixer", "DAC Mixer AIF1 DA0 Playback Switch", "AIF1 DA0 Right Stereo Mux" },
{ "DAC Right Mixer", "DAC Mixer AIF2 DAC Playback Switch", "AIF2 DAC Right Mux" },
{ "DAC Right Mixer", "DAC Mixer ADC Playback Switch", "ADC Right" },