aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/sunxi
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sunxi')
-rw-r--r--sound/soc/sunxi/sun4i-codec.c2
-rw-r--r--sound/soc/sunxi/sun50i-codec-analog.c176
-rw-r--r--sound/soc/sunxi/sun8i-codec.c473
3 files changed, 422 insertions, 229 deletions
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 2af6404dbd62..6c13cc84b3fb 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -335,7 +335,7 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
/*
* FIXME: Undocumented in the datasheet, but
- * Allwinner's code mentions that it is related
+ * Allwinner's code mentions that it is
* related to microphone gain
*/
if (of_device_is_compatible(scodec->dev->of_node,
diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c
index f5b7069bcca2..a41e25ad0aaf 100644
--- a/sound/soc/sunxi/sun50i-codec-analog.c
+++ b/sound/soc/sunxi/sun50i-codec-analog.c
@@ -121,50 +121,50 @@
/* mixer controls */
static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = {
- SOC_DAPM_DOUBLE_R("DAC Playback Switch",
+ SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
SUN50I_ADDA_OL_MIX_CTRL,
SUN50I_ADDA_OR_MIX_CTRL,
- SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0),
- SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
+ SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0),
+ SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
SUN50I_ADDA_OL_MIX_CTRL,
SUN50I_ADDA_OR_MIX_CTRL,
- SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0),
+ SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0),
SOC_DAPM_DOUBLE_R("Line In Playback Switch",
SUN50I_ADDA_OL_MIX_CTRL,
SUN50I_ADDA_OR_MIX_CTRL,
SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0),
- SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
+ SOC_DAPM_DOUBLE_R("DAC Playback Switch",
SUN50I_ADDA_OL_MIX_CTRL,
SUN50I_ADDA_OR_MIX_CTRL,
- SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0),
- SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
+ SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0),
+ SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
SUN50I_ADDA_OL_MIX_CTRL,
SUN50I_ADDA_OR_MIX_CTRL,
- SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0),
+ SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0),
};
/* ADC mixer controls */
static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = {
- SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
+ SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
SUN50I_ADDA_L_ADCMIX_SRC,
SUN50I_ADDA_R_ADCMIX_SRC,
- SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0),
- SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
+ SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0),
+ SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
SUN50I_ADDA_L_ADCMIX_SRC,
SUN50I_ADDA_R_ADCMIX_SRC,
- SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0),
+ SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0),
SOC_DAPM_DOUBLE_R("Line In Capture Switch",
SUN50I_ADDA_L_ADCMIX_SRC,
SUN50I_ADDA_R_ADCMIX_SRC,
SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0),
- SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
+ SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
SUN50I_ADDA_L_ADCMIX_SRC,
SUN50I_ADDA_R_ADCMIX_SRC,
- SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0),
- SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
+ SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0),
+ SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
SUN50I_ADDA_L_ADCMIX_SRC,
SUN50I_ADDA_R_ADCMIX_SRC,
- SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0),
+ SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0),
};
static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale,
@@ -193,11 +193,6 @@ static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = {
SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0,
sun50i_codec_hp_vol_scale),
- SOC_DOUBLE("Headphone Playback Switch",
- SUN50I_ADDA_MIX_DAC_CTRL,
- SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE,
- SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0),
-
/* Mixer pre-gain */
SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL,
SUN50I_ADDA_MIC1_CTRL_MIC1G,
@@ -233,20 +228,10 @@ static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = {
SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0,
sun50i_codec_lineout_vol_scale),
- SOC_DOUBLE("Line Out Playback Switch",
- SUN50I_ADDA_LINEOUT_CTRL0,
- SUN50I_ADDA_LINEOUT_CTRL0_LEN,
- SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0),
-
SOC_SINGLE_TLV("Earpiece Playback Volume",
SUN50I_ADDA_EARPIECE_CTRL1,
SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL, 0x1f, 0,
sun50i_codec_earpiece_vol_scale),
-
- SOC_SINGLE("Earpiece Playback Switch",
- SUN50I_ADDA_EARPIECE_CTRL1,
- SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0),
-
};
static const char * const sun50i_codec_hp_src_enum_text[] = {
@@ -264,6 +249,12 @@ static const struct snd_kcontrol_new sun50i_codec_hp_src[] = {
sun50i_codec_hp_src_enum),
};
+static const struct snd_kcontrol_new sun50i_codec_hp_switch =
+ SOC_DAPM_DOUBLE("Headphone Playback Switch",
+ SUN50I_ADDA_MIX_DAC_CTRL,
+ SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE,
+ SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0);
+
static const char * const sun50i_codec_lineout_src_enum_text[] = {
"Stereo", "Mono Differential",
};
@@ -279,6 +270,12 @@ static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = {
sun50i_codec_lineout_src_enum),
};
+static const struct snd_kcontrol_new sun50i_codec_lineout_switch =
+ SOC_DAPM_DOUBLE("Line Out Playback Switch",
+ SUN50I_ADDA_LINEOUT_CTRL0,
+ SUN50I_ADDA_LINEOUT_CTRL0_LEN,
+ SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0);
+
static const char * const sun50i_codec_earpiece_src_enum_text[] = {
"DACR", "DACL", "Right Mixer", "Left Mixer",
};
@@ -293,6 +290,12 @@ static const struct snd_kcontrol_new sun50i_codec_earpiece_src[] = {
sun50i_codec_earpiece_src_enum),
};
+static const struct snd_kcontrol_new sun50i_codec_earpiece_switch[] = {
+ SOC_DAPM_SINGLE("Earpiece Playback Switch",
+ SUN50I_ADDA_EARPIECE_CTRL1,
+ SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0),
+};
+
static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
/* DAC */
SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
@@ -311,18 +314,37 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
*/
SND_SOC_DAPM_REGULATOR_SUPPLY("cpvdd", 0, 0),
- SND_SOC_DAPM_MUX("Headphone Source Playback Route",
+ SND_SOC_DAPM_MUX("Left Headphone Source",
+ SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
+ SND_SOC_DAPM_MUX("Right Headphone Source",
SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
- SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL,
+ SND_SOC_DAPM_SWITCH("Left Headphone Switch",
+ SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),
+ SND_SOC_DAPM_SWITCH("Right Headphone Switch",
+ SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),
+ SND_SOC_DAPM_OUT_DRV("Left Headphone Amp",
+ SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Right Headphone Amp",
+ SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Headphone Amp", SUN50I_ADDA_HP_CTRL,
SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("HP"),
- SND_SOC_DAPM_MUX("Line Out Source Playback Route",
+ SND_SOC_DAPM_MUX("Left Line Out Source",
SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
+ SND_SOC_DAPM_MUX("Right Line Out Source",
+ SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
+ SND_SOC_DAPM_SWITCH("Left Line Out Switch",
+ SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),
+ SND_SOC_DAPM_SWITCH("Right Line Out Switch",
+ SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),
SND_SOC_DAPM_OUTPUT("LINEOUT"),
SND_SOC_DAPM_MUX("Earpiece Source Playback Route",
SND_SOC_NOPM, 0, 0, sun50i_codec_earpiece_src),
+ SOC_MIXER_NAMED_CTL_ARRAY("Earpiece Switch",
+ SND_SOC_NOPM, 0, 0,
+ sun50i_codec_earpiece_switch),
SND_SOC_DAPM_OUT_DRV("Earpiece Amp", SUN50I_ADDA_EARPIECE_CTRL1,
SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("EARPIECE"),
@@ -363,83 +385,105 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0,
sun50i_a64_codec_mixer_controls,
ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
- SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN50I_ADDA_ADC_CTRL,
- SUN50I_ADDA_ADC_CTRL_ADCLEN, 0,
+ SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
sun50i_codec_adc_mixer_controls,
ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
- SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN50I_ADDA_ADC_CTRL,
- SUN50I_ADDA_ADC_CTRL_ADCREN, 0,
+ SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
sun50i_codec_adc_mixer_controls,
ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
};
static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
/* Left Mixer Routes */
+ { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
+ { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
+ { "Left Mixer", "Line In Playback Switch", "LINEIN" },
{ "Left Mixer", "DAC Playback Switch", "Left DAC" },
{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
- { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
/* Right Mixer Routes */
+ { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
+ { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
+ { "Right Mixer", "Line In Playback Switch", "LINEIN" },
{ "Right Mixer", "DAC Playback Switch", "Right DAC" },
{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
- { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
/* Left ADC Mixer Routes */
+ { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
+ { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
+ { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
{ "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
{ "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
- { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
/* Right ADC Mixer Routes */
+ { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
+ { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
+ { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
{ "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
{ "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
- { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
/* ADC Routes */
{ "Left ADC", NULL, "Left ADC Mixer" },
{ "Right ADC", NULL, "Right ADC Mixer" },
/* Headphone Routes */
- { "Headphone Source Playback Route", "DAC", "Left DAC" },
- { "Headphone Source Playback Route", "DAC", "Right DAC" },
- { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
- { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
- { "Headphone Amp", NULL, "Headphone Source Playback Route" },
+ { "Left Headphone Source", "DAC", "Left DAC" },
+ { "Left Headphone Source", "Mixer", "Left Mixer" },
+ { "Left Headphone Switch", "Headphone Playback Switch", "Left Headphone Source" },
+ { "Left Headphone Amp", NULL, "Left Headphone Switch" },
+ { "Left Headphone Amp", NULL, "Headphone Amp" },
+ { "HP", NULL, "Left Headphone Amp" },
+
+ { "Right Headphone Source", "DAC", "Right DAC" },
+ { "Right Headphone Source", "Mixer", "Right Mixer" },
+ { "Right Headphone Switch", "Headphone Playback Switch", "Right Headphone Source" },
+ { "Right Headphone Amp", NULL, "Right Headphone Switch" },
+ { "Right Headphone Amp", NULL, "Headphone Amp" },
+ { "HP", NULL, "Right Headphone Amp" },
+
{ "Headphone Amp", NULL, "cpvdd" },
- { "HP", NULL, "Headphone Amp" },
/* Microphone Routes */
{ "Mic1 Amplifier", NULL, "MIC1"},
/* Microphone Routes */
{ "Mic2 Amplifier", NULL, "MIC2"},
- { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
- { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
- { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
- { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
-
- /* Line-in Routes */
- { "Left Mixer", "Line In Playback Switch", "LINEIN" },
- { "Right Mixer", "Line In Playback Switch", "LINEIN" },
- { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
- { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
/* Line-out Routes */
- { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
- { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
- { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
- { "Line Out Source Playback Route", "Mono Differential",
- "Right Mixer" },
- { "LINEOUT", NULL, "Line Out Source Playback Route" },
+ { "Left Line Out Source", "Stereo", "Left Mixer" },
+ { "Left Line Out Source", "Mono Differential", "Left Mixer" },
+ { "Left Line Out Source", "Mono Differential", "Right Mixer" },
+ { "Left Line Out Switch", "Line Out Playback Switch", "Left Line Out Source" },
+ { "LINEOUT", NULL, "Left Line Out Switch" },
+
+ { "Right Line Out Switch", "Line Out Playback Switch", "Right Mixer" },
+ { "Right Line Out Source", "Stereo", "Right Line Out Switch" },
+ { "Right Line Out Source", "Mono Differential", "Left Line Out Switch" },
+ { "LINEOUT", NULL, "Right Line Out Source" },
/* Earpiece Routes */
{ "Earpiece Source Playback Route", "DACL", "Left DAC" },
{ "Earpiece Source Playback Route", "DACR", "Right DAC" },
{ "Earpiece Source Playback Route", "Left Mixer", "Left Mixer" },
{ "Earpiece Source Playback Route", "Right Mixer", "Right Mixer" },
- { "Earpiece Amp", NULL, "Earpiece Source Playback Route" },
+ { "Earpiece Switch", "Earpiece Playback Switch", "Earpiece Source Playback Route" },
+ { "Earpiece Amp", NULL, "Earpiece Switch" },
{ "EARPIECE", NULL, "Earpiece Amp" },
};
+static int sun50i_a64_codec_suspend(struct snd_soc_component *component)
+{
+ return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
+ BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE),
+ BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));
+}
+
+static int sun50i_a64_codec_resume(struct snd_soc_component *component)
+{
+ return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
+ BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), 0);
+}
+
static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
.controls = sun50i_a64_codec_controls,
.num_controls = ARRAY_SIZE(sun50i_a64_codec_controls),
@@ -447,6 +491,8 @@ static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
.num_dapm_widgets = ARRAY_SIZE(sun50i_a64_codec_widgets),
.dapm_routes = sun50i_a64_codec_routes,
.num_dapm_routes = ARRAY_SIZE(sun50i_a64_codec_routes),
+ .suspend = sun50i_a64_codec_suspend,
+ .resume = sun50i_a64_codec_resume,
};
static const struct of_device_id sun50i_codec_analog_of_match[] = {
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index ca51af114419..7590c4b04d14 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/log2.h>
@@ -23,10 +24,13 @@
#define SUN8I_SYSCLK_CTL 0x00c
#define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11
-#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL 9
-#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC 8
+#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL (0x2 << 8)
+#define SUN8I_SYSCLK_CTL_AIF2CLK_ENA 7
+#define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL (0x2 << 4)
#define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3
#define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0
+#define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK (0x0 << 0)
+#define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK (0x1 << 0)
#define SUN8I_MOD_CLK_ENA 0x010
#define SUN8I_MOD_CLK_ENA_AIF1 15
#define SUN8I_MOD_CLK_ENA_ADC 3
@@ -48,47 +52,58 @@
#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4)
#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2
#define SUN8I_AIF1_ADCDAT_CTRL 0x044
-#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA 15
-#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA 14
+#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_MXL_SRC_AIF1DA0L 15
-#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL 14
-#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL 13
-#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR 12
+#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L 15
+#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL 14
+#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL 13
+#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR 12
#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R 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_ADC_DIG_CTRL 0x100
-#define SUN8I_ADC_DIG_CTRL_ENDA 15
+#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_DAC_DIG_CTRL 0x120
-#define SUN8I_DAC_DIG_CTRL_ENDA 15
+#define SUN8I_DAC_DIG_CTRL_ENDA 15
#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
-#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12
-#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
-#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
-#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8
+#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK GENMASK(9, 8)
+#define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK GENMASK(5, 4)
#define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12)
#define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8)
-#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2)
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4)
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6)
#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9)
+#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6)
+#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4)
+#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2)
+
+struct sun8i_codec_quirks {
+ bool legacy_widgets : 1;
+ bool lrck_inversion : 1;
+};
struct sun8i_codec {
- struct regmap *regmap;
- struct clk *clk_module;
- struct clk *clk_bus;
+ struct regmap *regmap;
+ struct clk *clk_module;
+ const struct sun8i_codec_quirks *quirks;
};
static int sun8i_codec_runtime_resume(struct device *dev)
@@ -96,35 +111,15 @@ static int sun8i_codec_runtime_resume(struct device *dev)
struct sun8i_codec *scodec = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(scodec->clk_module);
- if (ret) {
- dev_err(dev, "Failed to enable the module clock\n");
- return ret;
- }
-
- ret = clk_prepare_enable(scodec->clk_bus);
- if (ret) {
- dev_err(dev, "Failed to enable the bus clock\n");
- goto err_disable_modclk;
- }
-
regcache_cache_only(scodec->regmap, false);
ret = regcache_sync(scodec->regmap);
if (ret) {
dev_err(dev, "Failed to sync regmap cache\n");
- goto err_disable_clk;
+ return ret;
}
return 0;
-
-err_disable_clk:
- clk_disable_unprepare(scodec->clk_bus);
-
-err_disable_modclk:
- clk_disable_unprepare(scodec->clk_module);
-
- return ret;
}
static int sun8i_codec_runtime_suspend(struct device *dev)
@@ -134,9 +129,6 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
regcache_cache_only(scodec->regmap, true);
regcache_mark_dirty(scodec->regmap);
- clk_disable_unprepare(scodec->clk_module);
- clk_disable_unprepare(scodec->clk_bus);
-
return 0;
}
@@ -175,7 +167,7 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
+ struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
u32 value;
/* clock masters */
@@ -209,18 +201,19 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
/*
- * It appears that the DAI and the codec don't share the same
- * polarity for the LRCK signal when they mean 'normal' and
- * 'inverted' in the datasheet.
+ * It appears that the DAI and the codec in the A33 SoC don't
+ * share the same polarity for the LRCK signal when they mean
+ * 'normal' and 'inverted' in the datasheet.
*
* Since the DAI here is our regular i2s driver that have been
* tested with way more codecs than just this one, it means
* that the codec probably gets it backward, and we have to
* invert the value here.
*/
+ value ^= scodec->quirks->lrck_inversion;
regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV),
- !value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
+ value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
/* DAI format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -306,7 +299,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
+ struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
int sample_rate, lrck_div;
u8 bclk_div;
@@ -339,13 +332,53 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
- regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
- SUN8I_SYS_SR_CTRL_AIF2_FS_MASK,
- sample_rate << SUN8I_SYS_SR_CTRL_AIF2_FS);
return 0;
}
+static const char *const sun8i_aif_stereo_mux_enum_values[] = {
+ "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_values);
+
+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 const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
+ SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
+ SUN8I_AIF1_MXR_SRC,
+ SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L,
+ SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
+ SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch",
+ SUN8I_AIF1_MXR_SRC,
+ SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL,
+ SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
+ SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
+ SUN8I_AIF1_MXR_SRC,
+ SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL,
+ SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
+ SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
+ SUN8I_AIF1_MXR_SRC,
+ SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR,
+ SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
+};
+
+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_values);
+
+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 const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
SUN8I_DAC_MXR_SRC,
@@ -363,125 +396,233 @@ static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
};
-static const struct snd_kcontrol_new sun8i_input_mixer_controls[] = {
- SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
- SUN8I_AIF1_MXR_SRC,
- SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L,
- SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
- SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC,
- SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL,
- SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
- SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
- SUN8I_AIF1_MXR_SRC,
- SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL,
- SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
- SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
- SUN8I_AIF1_MXR_SRC,
- SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR,
- SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
-};
-
static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
- /* Digital parts of the DACs and ADC */
- SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA,
- 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ADC", SUN8I_ADC_DIG_CTRL, SUN8I_ADC_DIG_CTRL_ENDA,
- 0, NULL, 0),
-
- /* Analog DAC AIF */
- SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left", "Playback", 0,
+ /* System Clocks */
+ SND_SOC_DAPM_CLOCK_SUPPLY("mod"),
+
+ SND_SOC_DAPM_SUPPLY("AIF1CLK",
+ SUN8I_SYSCLK_CTL,
+ SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SYSCLK",
+ SUN8I_SYSCLK_CTL,
+ SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
+
+ /* Module Clocks */
+ SND_SOC_DAPM_SUPPLY("CLK AIF1",
+ SUN8I_MOD_CLK_ENA,
+ SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("CLK ADC",
+ SUN8I_MOD_CLK_ENA,
+ SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("CLK DAC",
+ SUN8I_MOD_CLK_ENA,
+ SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
+
+ /* Module Resets */
+ SND_SOC_DAPM_SUPPLY("RST AIF1",
+ SUN8I_MOD_RST_CTL,
+ SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RST ADC",
+ SUN8I_MOD_RST_CTL,
+ SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RST DAC",
+ SUN8I_MOD_RST_CTL,
+ SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
+
+ /* Module Supplies */
+ SND_SOC_DAPM_SUPPLY("ADC",
+ SUN8I_ADC_DIG_CTRL,
+ SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC",
+ SUN8I_DAC_DIG_CTRL,
+ SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0),
+
+ /* AIF "ADC" Outputs */
+ SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "Capture", 0,
+ SUN8I_AIF1_ADCDAT_CTRL,
+ SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
+ SUN8I_AIF1_ADCDAT_CTRL,
+ SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
+
+ /* AIF "ADC" Mono/Stereo Muxes */
+ SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif1_ad0_stereo_mux_control),
+ SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif1_ad0_stereo_mux_control),
+
+ /* AIF "ADC" Mixers */
+ SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
+ sun8i_aif1_ad0_mixer_controls),
+ SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
+ sun8i_aif1_ad0_mixer_controls),
+
+ /* AIF "DAC" Mono/Stereo Muxes */
+ SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif1_da0_stereo_mux_control),
+ SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0,
+ &sun8i_aif1_da0_stereo_mux_control),
+
+ /* AIF "DAC" Inputs */
+ SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
SUN8I_AIF1_DACDAT_CTRL,
SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
- SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right", "Playback", 0,
+ SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
SUN8I_AIF1_DACDAT_CTRL,
SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
- /* Analog ADC AIF */
- SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left ADC", "Capture", 0,
- SUN8I_AIF1_ADCDAT_CTRL,
- SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA, 0),
- SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right ADC", "Capture", 0,
- SUN8I_AIF1_ADCDAT_CTRL,
- SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA, 0),
+ /* ADC Inputs (connected to analog codec DAPM context) */
+ SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
+
+ /* DAC Outputs (connected to analog codec DAPM context) */
+ SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
- /* DAC and ADC Mixers */
- SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
+ /* DAC Mixers */
+ SOC_MIXER_ARRAY("DACL Mixer", SND_SOC_NOPM, 0, 0,
sun8i_dac_mixer_controls),
- SOC_MIXER_ARRAY("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
+ SOC_MIXER_ARRAY("DACR Mixer", SND_SOC_NOPM, 0, 0,
sun8i_dac_mixer_controls),
- SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
- sun8i_input_mixer_controls),
- SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
- sun8i_input_mixer_controls),
+};
- /* Clocks */
- SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA,
- SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA,
- SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("MODCLK ADC", SUN8I_MOD_CLK_ENA,
- SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("AIF1", SUN8I_SYSCLK_CTL,
- SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL,
- SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
+static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
+ /* Clock Routes */
+ { "AIF1CLK", NULL, "mod" },
+
+ { "SYSCLK", NULL, "AIF1CLK" },
+
+ { "CLK AIF1", NULL, "AIF1CLK" },
+ { "CLK AIF1", NULL, "SYSCLK" },
+ { "RST AIF1", NULL, "CLK AIF1" },
+ { "AIF1 AD0L", NULL, "RST AIF1" },
+ { "AIF1 AD0R", NULL, "RST AIF1" },
+ { "AIF1 DA0L", NULL, "RST AIF1" },
+ { "AIF1 DA0R", NULL, "RST AIF1" },
+
+ { "CLK ADC", NULL, "SYSCLK" },
+ { "RST ADC", NULL, "CLK ADC" },
+ { "ADC", NULL, "RST ADC" },
+ { "ADCL", NULL, "ADC" },
+ { "ADCR", NULL, "ADC" },
+
+ { "CLK DAC", NULL, "SYSCLK" },
+ { "RST DAC", NULL, "CLK DAC" },
+ { "DAC", NULL, "RST DAC" },
+ { "DACL", NULL, "DAC" },
+ { "DACR", NULL, "DAC" },
+
+ /* AIF "ADC" Output Routes */
+ { "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
+ { "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
+
+ /* AIF "ADC" Mono/Stereo Mux Routes */
+ { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" },
+ { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" },
+ { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
+ { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
+ { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
+ { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
+
+ { "AIF1 AD0R Stereo Mux", "Stereo", "AIF1 AD0R Mixer" },
+ { "AIF1 AD0R Stereo Mux", "Reverse Stereo", "AIF1 AD0L Mixer" },
+ { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
+ { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
+ { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
+ { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
+
+ /* AIF "ADC" Mixer Routes */
+ { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
+ { "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+
+ { "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
+ { "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+
+ /* AIF "DAC" Mono/Stereo Mux Routes */
+ { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" },
+ { "AIF1 DA0L Stereo Mux", "Reverse Stereo", "AIF1 DA0R" },
+ { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0L" },
+ { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0R" },
+ { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0L" },
+ { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0R" },
+
+ { "AIF1 DA0R Stereo Mux", "Stereo", "AIF1 DA0R" },
+ { "AIF1 DA0R Stereo Mux", "Reverse Stereo", "AIF1 DA0L" },
+ { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0L" },
+ { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0R" },
+ { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" },
+ { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" },
+
+ /* DAC Output Routes */
+ { "DACL", NULL, "DACL Mixer" },
+ { "DACR", NULL, "DACR Mixer" },
- SND_SOC_DAPM_SUPPLY("AIF1 PLL", SUN8I_SYSCLK_CTL,
- SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL, 0, NULL, 0),
- /* Inversion as 0=AIF1, 1=AIF2 */
- SND_SOC_DAPM_SUPPLY("SYSCLK AIF1", SUN8I_SYSCLK_CTL,
- SUN8I_SYSCLK_CTL_SYSCLK_SRC, 1, NULL, 0),
+ /* DAC Mixer Routes */
+ { "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
+ { "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
- /* Module reset */
- SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL,
- SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL,
- SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("RST ADC", SUN8I_MOD_RST_CTL,
- SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
+ { "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
+ { "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
+};
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Mic", NULL),
+static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = {
+ /* Legacy ADC Inputs (connected to analog codec DAPM context) */
+ SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0),
+ /* Legacy DAC Outputs (connected to analog codec DAPM context) */
+ SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0),
};
-static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
- /* Clock Routes */
- { "AIF1", NULL, "SYSCLK AIF1" },
- { "AIF1 PLL", NULL, "AIF1" },
- { "RST AIF1", NULL, "AIF1 PLL" },
- { "MODCLK AFI1", NULL, "RST AIF1" },
- { "DAC", NULL, "MODCLK AFI1" },
- { "ADC", NULL, "MODCLK AFI1" },
+static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = {
+ /* Legacy ADC Routes */
+ { "ADCL", NULL, "AIF1 Slot 0 Left ADC" },
+ { "ADCR", NULL, "AIF1 Slot 0 Right ADC" },
- { "RST DAC", NULL, "SYSCLK" },
- { "MODCLK DAC", NULL, "RST DAC" },
- { "DAC", NULL, "MODCLK DAC" },
+ /* Legacy DAC Routes */
+ { "AIF1 Slot 0 Left", NULL, "DACL" },
+ { "AIF1 Slot 0 Right", NULL, "DACR" },
+};
- { "RST ADC", NULL, "SYSCLK" },
- { "MODCLK ADC", NULL, "RST ADC" },
- { "ADC", NULL, "MODCLK ADC" },
+static int sun8i_codec_component_probe(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
+ int ret;
- /* DAC Routes */
- { "AIF1 Slot 0 Right", NULL, "DAC" },
- { "AIF1 Slot 0 Left", NULL, "DAC" },
+ /* Add widgets for backward compatibility with old device trees. */
+ if (scodec->quirks->legacy_widgets) {
+ ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets,
+ ARRAY_SIZE(sun8i_codec_legacy_widgets));
+ if (ret)
+ return ret;
- /* DAC Mixer Routes */
- { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
- "AIF1 Slot 0 Left"},
- { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
- "AIF1 Slot 0 Right"},
-
- /* ADC Routes */
- { "AIF1 Slot 0 Right ADC", NULL, "ADC" },
- { "AIF1 Slot 0 Left ADC", NULL, "ADC" },
-
- /* ADC Mixer Routes */
- { "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch",
- "AIF1 Slot 0 Left ADC" },
- { "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch",
- "AIF1 Slot 0 Right ADC" },
-};
+ ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes,
+ ARRAY_SIZE(sun8i_codec_legacy_routes));
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod")
+ * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also
+ * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO
+ * directly to simplify the clock tree.
+ */
+ regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
+ SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK |
+ SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK,
+ SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL |
+ SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL);
+
+ /* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */
+ regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
+ BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC),
+ SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK);
+
+ return 0;
+}
static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
.hw_params = sun8i_codec_hw_params,
@@ -516,6 +657,7 @@ static const struct snd_soc_component_driver sun8i_soc_component = {
.num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
.dapm_routes = sun8i_codec_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes),
+ .probe = sun8i_codec_component_probe,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
@@ -547,25 +689,21 @@ static int sun8i_codec_probe(struct platform_device *pdev)
return PTR_ERR(scodec->clk_module);
}
- scodec->clk_bus = devm_clk_get(&pdev->dev, "bus");
- if (IS_ERR(scodec->clk_bus)) {
- dev_err(&pdev->dev, "Failed to get the bus clock\n");
- return PTR_ERR(scodec->clk_bus);
- }
-
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) {
dev_err(&pdev->dev, "Failed to map the registers\n");
return PTR_ERR(base);
}
- scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
- &sun8i_codec_regmap_config);
+ scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base,
+ &sun8i_codec_regmap_config);
if (IS_ERR(scodec->regmap)) {
dev_err(&pdev->dev, "Failed to create our regmap\n");
return PTR_ERR(scodec->regmap);
}
+ scodec->quirks = of_device_get_match_data(&pdev->dev);
+
platform_set_drvdata(pdev, scodec);
pm_runtime_enable(&pdev->dev);
@@ -603,8 +741,17 @@ static int sun8i_codec_remove(struct platform_device *pdev)
return 0;
}
+static const struct sun8i_codec_quirks sun8i_a33_quirks = {
+ .legacy_widgets = true,
+ .lrck_inversion = true,
+};
+
+static const struct sun8i_codec_quirks sun50i_a64_quirks = {
+};
+
static const struct of_device_id sun8i_codec_of_match[] = {
- { .compatible = "allwinner,sun8i-a33-codec" },
+ { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks },
+ { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks },
{}
};
MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);