[PATCH 1/2] ASoC: sun8i-codec: Add ADC support for a33
Mylene Josserand
mylene.josserand at free-electrons.com
Tue May 9 23:58:09 PDT 2017
Hi Chen-Yu,
Thank you for the review!
On 03/05/2017 19:13, Chen-Yu Tsai wrote:
> Hi,
>
> On Wed, May 3, 2017 at 9:56 PM, Mylène Josserand
> <mylene.josserand at free-electrons.com> wrote:
>> Add ADC support for the sun8i-codec driver.
>>
>> This driver uses all the microphones widgets and routes provided by the
>> analog part (sun8i-codec-analog).
>> Some digital configurations are needed by creating new ADC widgets
>> and routes.
>>
>> Signed-off-by: Mylène Josserand <mylene.josserand at free-electrons.com>
>> ---
>> sound/soc/sunxi/sun8i-codec.c | 80 +++++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 78 insertions(+), 2 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 5723c3404f6b..b4938b06acec 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -37,9 +37,11 @@
>> #define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0
>> #define SUN8I_MOD_CLK_ENA 0x010
>> #define SUN8I_MOD_CLK_ENA_AIF1 15
>> +#define SUN8I_MOD_CLK_ENA_ADC 3
>> #define SUN8I_MOD_CLK_ENA_DAC 2
>> #define SUN8I_MOD_RST_CTL 0x014
>> #define SUN8I_MOD_RST_CTL_AIF1 15
>> +#define SUN8I_MOD_RST_CTL_ADC 3
>> #define SUN8I_MOD_RST_CTL_DAC 2
>> #define SUN8I_SYS_SR_CTRL 0x018
>> #define SUN8I_SYS_SR_CTRL_AIF1_FS 12
>> @@ -54,9 +56,25 @@
>> #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4
>> #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_DACDAT_CTRL 0x048
>> #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15
>> #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14
>> +#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_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
>
> The register bit name in the manual is ENAD, as in ENable ADc.
Okay, I did not know that, thanks.
>
>> +#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_MXR_SRC 0x130
>> @@ -276,10 +294,28 @@ 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),
>> +};
>
> This group of mixer controls is only for AIF1 slot 0 capture.
> So in fact they should all read "AIF1 Slot 0 Mixer X Capture Switch",
> with X replaced by "AIF1 Slot 0", "AIF2", "ADC", and "AIF2 Inv".
>
> This hopefully informs the user that these controls are for the AIF1
> slot 0 mixer, and are capture switch from the various sources listed
> above.
Sounds good.
>
>> +
>> static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
>> - /* Digital parts of the DACs */
>> + /* 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,
>> @@ -289,17 +325,31 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
>> SUN8I_AIF1_DACDAT_CTRL,
>> SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
>>
>> - /* DAC Mixers */
>> + /* 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),
>
> You want to use SND_SOC_DAPM_AIF_OUT here, for captured audio out of
> the codec and to the system. These are the last widgets in the capture
> path.
ACK
>
>> +
>> + /* DAC and ADC Mixers */
>> SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
>> sun8i_dac_mixer_controls),
>> SOC_MIXER_ARRAY("Right Digital DAC 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),
>
> And these should read "AIF1 Slot 0 Left/Right Mixer".
ACK
>
>>
>> /* 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,
>> @@ -316,6 +366,12 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
>> 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),
>> +
>> + SND_SOC_DAPM_MIC("Headset Mic", NULL),
>> + SND_SOC_DAPM_MIC("Mic", NULL),
>
> These Mics are board level widgets. Since you are using simple-card,
> you should add them in the device tree in the simple-card device
> node, using the "simple-audio-card,widgets" property.
>
> You probably should have done so for the output side as well.
> If simple-card were fully-routed, the existing device tree simply
> wouldn't work.
Okay, I will add them in the simple-audio-card node.
>
>> +
>> };
>>
>> static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
>> @@ -325,11 +381,16 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
>> { "RST AIF1", NULL, "AIF1 PLL" },
>> { "MODCLK AFI1", NULL, "RST AIF1" },
>> { "DAC", NULL, "MODCLK AFI1" },
>> + { "ADC", NULL, "MODCLK AFI1" },
>
> This makes no sense. Why would AIF1's module clock feed the ADC? Same goes
> for the existing DAC route.
>
It was difficult for me to know how to route the clocks with the DAC/ADC
widgets. As the clocks are needed to have a ADC/DAC working, I created
this route but it is, maybe, not the correct way to do it.
>>
>> { "RST DAC", NULL, "SYSCLK" },
>> { "MODCLK DAC", NULL, "RST DAC" },
>> { "DAC", NULL, "MODCLK DAC" },
>>
>> + { "RST ADC", NULL, "SYSCLK" },
>> + { "MODCLK ADC", NULL, "RST ADC" },
>> + { "ADC", NULL, "MODCLK ADC" },
>
> This makes little sense either. The SYSCLK probably feeds the ADC's
> module clock.
> The MODCLK then feeds the ADC. The ADC reset feeds the ADC (or rather the ADC
> depends on its reset). The "ADC" widget here is actually just the enable switch.
> But we can use it as a kind of placeholder, to setup the dependencies correctly.
>
Yep, that it is.
What do you have in mind about the ADC widget as a "placeholder"?
> I wish we had named the widgets better, but alas they are part of the
> device tree
> binding, even though they are not documented, so we can not change the existing
> ones.
I agree about the widgets names, they are not very clear.
>
>> +
>> /* DAC Routes */
>> { "AIF1 Slot 0 Right", NULL, "DAC" },
>> { "AIF1 Slot 0 Left", NULL, "DAC" },
>> @@ -339,6 +400,12 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
>> "AIF1 Slot 0 Left"},
>> { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
>> "AIF1 Slot 0 Right"},
>> +
>> + /* ADC 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" },
>
> Same thing about the "ADC Mixer" names.
>
> And these routes are completely backwards. "AIF1 Slot 0 Left/Right ADC" are
> the output stream widgets. They are fed from "AIF1 Slot 0 Left/Right Mixer"
> if you use the names I suggested, or "Left/Right Digital ADC Mixer" originally.
You are right, it make sense now.
>
> You then need other routes feeding the mixer. Looks like you also need ADC
> placeholder widgets on the digital side here, so you can hook up the analog
> side in simple-card more easily.
Okay, I will try to improve it.
>
> If you can, please dump the DAPM routes into a directed graph to check
> everything
> is connected and makes sense. I believe you have a script that does this.
Yes, I tested it and the ADC mixers are connected to nothing so this
route does not make sense. I will rework it.
>> };
>>
>> static struct snd_soc_dai_ops sun8i_codec_dai_ops = {
>> @@ -356,6 +423,15 @@ static struct snd_soc_dai_driver sun8i_codec_dai = {
>> .rates = SNDRV_PCM_RATE_8000_192000,
>> .formats = SNDRV_PCM_FMTBIT_S16_LE,
>> },
>> + /* capture capabilities */
>> + .capture = {
>> + .stream_name = "Capture",
>> + .channels_min = 1,
>> + .channels_max = 2,
>> + .rates = SNDRV_PCM_RATE_8000_192000,
>> + .formats = SNDRV_PCM_FMTBIT_S16_LE,
>> + .sig_bits = 24,
>> + },
>> /* pcm operations */
>> .ops = &sun8i_codec_dai_ops,
>> };
>> --
>> 2.11.0
>>
Thank you again,
Best regards,
--
Mylène Josserand, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
More information about the linux-arm-kernel
mailing list