All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/25] ASoC: sun8i-codec: support for AIF2 and AIF3
@ 2020-10-01  2:11 ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

This series adds support the other two AIFs present in the sun8i codec,
which can be used for codec2codec DAI links.

This series first cleans up the DAPM component driver so there is an
organized place to put the new widgets. Then it fills out the DAI
driver, removing assumptions that were made for AIF1 (16 bits, 2
channels, certain clock inversions). Some new logic is required to
handle 3 DAIs and the ADC/DAC sharing the same clock. Finally, it adds
the new DAIs, and hooks them up with DAPM widgets and routes per the
hardware topology.

To minimize the number of patches in this series, related device tree
patches (increasing #sound-dai-cells, adding new DAI links) will be sent
separately.

Samuel Holland (25):
  ASoC: sun8i-codec: Set up clock tree at probe time
  ASoC: sun8i-codec: Swap module clock/reset dependencies
  ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
  ASoC: sun8i-codec: Consistently name DAPM widgets and routes
  ASoC: sun8i-codec: Correct DAPM widget types
  ASoC: sun8i-codec: Fix AIF widget channel references
  ASoC: sun8i-codec: Enable AIF mono/stereo control
  ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
  ASoC: sun8i-codec: Prepare to extend the DAI driver
  ASoC: sun8i-codec: Program format before clock inversion
  ASoC: sun8i-codec: Enable all supported clock inversions
  ASoC: sun8i-codec: Program the correct word size
  ASoC: sun8i-codec: Round up the LRCK divisor
  ASoC: sun8i-codec: Correct the BCLK divisor calculation
  ASoC: sun8i-codec: Support the TDM slot binding
  ASoC: sun8i-codec: Enforce symmetric DAI parameters
  ASoC: sun8i-codec: Enable all supported sample rates
  ASoC: sun8i-codec: Automatically set the system sample rate
  ASoC: sun8i-codec: Constrain to compatible sample rates
  ASoC: sun8i-codec: Protect the clock rate while streams are open
  ASoC: sun8i-codec: Require an exact BCLK divisor match
  ASoC: sun8i-codec: Enable all supported PCM formats
  ASoC: sun8i-codec: Generalize AIF clock control
  ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2
  ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF3

 sound/soc/sunxi/sun8i-codec.c | 1135 ++++++++++++++++++++++++++-------
 1 file changed, 894 insertions(+), 241 deletions(-)

-- 
2.26.2


^ permalink raw reply	[flat|nested] 181+ messages in thread

* [PATCH 00/25] ASoC: sun8i-codec: support for AIF2 and AIF3
@ 2020-10-01  2:11 ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

This series adds support the other two AIFs present in the sun8i codec,
which can be used for codec2codec DAI links.

This series first cleans up the DAPM component driver so there is an
organized place to put the new widgets. Then it fills out the DAI
driver, removing assumptions that were made for AIF1 (16 bits, 2
channels, certain clock inversions). Some new logic is required to
handle 3 DAIs and the ADC/DAC sharing the same clock. Finally, it adds
the new DAIs, and hooks them up with DAPM widgets and routes per the
hardware topology.

To minimize the number of patches in this series, related device tree
patches (increasing #sound-dai-cells, adding new DAI links) will be sent
separately.

Samuel Holland (25):
  ASoC: sun8i-codec: Set up clock tree at probe time
  ASoC: sun8i-codec: Swap module clock/reset dependencies
  ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
  ASoC: sun8i-codec: Consistently name DAPM widgets and routes
  ASoC: sun8i-codec: Correct DAPM widget types
  ASoC: sun8i-codec: Fix AIF widget channel references
  ASoC: sun8i-codec: Enable AIF mono/stereo control
  ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
  ASoC: sun8i-codec: Prepare to extend the DAI driver
  ASoC: sun8i-codec: Program format before clock inversion
  ASoC: sun8i-codec: Enable all supported clock inversions
  ASoC: sun8i-codec: Program the correct word size
  ASoC: sun8i-codec: Round up the LRCK divisor
  ASoC: sun8i-codec: Correct the BCLK divisor calculation
  ASoC: sun8i-codec: Support the TDM slot binding
  ASoC: sun8i-codec: Enforce symmetric DAI parameters
  ASoC: sun8i-codec: Enable all supported sample rates
  ASoC: sun8i-codec: Automatically set the system sample rate
  ASoC: sun8i-codec: Constrain to compatible sample rates
  ASoC: sun8i-codec: Protect the clock rate while streams are open
  ASoC: sun8i-codec: Require an exact BCLK divisor match
  ASoC: sun8i-codec: Enable all supported PCM formats
  ASoC: sun8i-codec: Generalize AIF clock control
  ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2
  ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF3

 sound/soc/sunxi/sun8i-codec.c | 1135 ++++++++++++++++++++++++++-------
 1 file changed, 894 insertions(+), 241 deletions(-)

-- 
2.26.2


^ permalink raw reply	[flat|nested] 181+ messages in thread

* [PATCH 00/25] ASoC: sun8i-codec: support for AIF2 and AIF3
@ 2020-10-01  2:11 ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

This series adds support the other two AIFs present in the sun8i codec,
which can be used for codec2codec DAI links.

This series first cleans up the DAPM component driver so there is an
organized place to put the new widgets. Then it fills out the DAI
driver, removing assumptions that were made for AIF1 (16 bits, 2
channels, certain clock inversions). Some new logic is required to
handle 3 DAIs and the ADC/DAC sharing the same clock. Finally, it adds
the new DAIs, and hooks them up with DAPM widgets and routes per the
hardware topology.

To minimize the number of patches in this series, related device tree
patches (increasing #sound-dai-cells, adding new DAI links) will be sent
separately.

Samuel Holland (25):
  ASoC: sun8i-codec: Set up clock tree at probe time
  ASoC: sun8i-codec: Swap module clock/reset dependencies
  ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
  ASoC: sun8i-codec: Consistently name DAPM widgets and routes
  ASoC: sun8i-codec: Correct DAPM widget types
  ASoC: sun8i-codec: Fix AIF widget channel references
  ASoC: sun8i-codec: Enable AIF mono/stereo control
  ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
  ASoC: sun8i-codec: Prepare to extend the DAI driver
  ASoC: sun8i-codec: Program format before clock inversion
  ASoC: sun8i-codec: Enable all supported clock inversions
  ASoC: sun8i-codec: Program the correct word size
  ASoC: sun8i-codec: Round up the LRCK divisor
  ASoC: sun8i-codec: Correct the BCLK divisor calculation
  ASoC: sun8i-codec: Support the TDM slot binding
  ASoC: sun8i-codec: Enforce symmetric DAI parameters
  ASoC: sun8i-codec: Enable all supported sample rates
  ASoC: sun8i-codec: Automatically set the system sample rate
  ASoC: sun8i-codec: Constrain to compatible sample rates
  ASoC: sun8i-codec: Protect the clock rate while streams are open
  ASoC: sun8i-codec: Require an exact BCLK divisor match
  ASoC: sun8i-codec: Enable all supported PCM formats
  ASoC: sun8i-codec: Generalize AIF clock control
  ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2
  ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF3

 sound/soc/sunxi/sun8i-codec.c | 1135 ++++++++++++++++++++++++++-------
 1 file changed, 894 insertions(+), 241 deletions(-)

-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* [PATCH 01/25] ASoC: sun8i-codec: Set up clock tree at probe time
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

The sun8i codec is effectively an on-die variant of the X-Powers AC100
codec. The AC100 can derive its clocks from either of two I2S master
clocks or an internal PLL. For the on-die variant, Allwinner replaced
the codec's own PLL with a connection to SoC's existing PLL_AUDIO, and
they connected both I2S MCLK inputs to the same source -- which happens
to be an integer divider from the same PLL_AUDIO.

So there's actually no clocking flexibility. To run SYSCLK at the
required rate, it must be run straight from the PLL. The only choice is
whether it goes through AIF1CLK or AIF2CLK. Since both run at the same
rate, the only effect of that choice is which field in SYS_SR_CTRL
(AIF1_FS or AIF2_FS) controls the system sample rate.

Since AIFnCLK is required to bring up the corresponding DAI, and AIF1
(connected to the CPU) is used most often, let's use AIF1CLK as the
SYSCLK parent. That means we no longer need to set AIF2_FS.

Since this clock tree never changes, we can program it from the
component probe function, instead of using DAPM widgets. The DAPM
widgets unnecessarily change clock parents when the codec goes in/out
of idle and the supply widgets are powered up/down.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 178f6fb31fd4..407f0fedc4ed 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -19,20 +19,23 @@
 #include <linux/log2.h>
 
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
 #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
 #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
@@ -74,16 +77,18 @@
 #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_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_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 {
@@ -318,19 +323,16 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 
 	sample_rate = sun8i_codec_get_hw_rate(params);
 	if (sample_rate < 0)
 		return sample_rate;
 
 	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 struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
@@ -361,18 +363,26 @@ static const struct snd_kcontrol_new sun8i_input_mixer_controls[] = {
 			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 const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
+	/* 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),
+
 	/* 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_ENAD,
 			    0, NULL, 0),
 
 	/* AIF "DAC" Inputs */
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
@@ -410,44 +420,33 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* Clocks */
 	SND_SOC_DAPM_SUPPLY("MODCLK AIF1", 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),
-
-	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),
 
 	/* 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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
-	{ "AIF1", NULL, "mod" },
+	{ "AIF1CLK", NULL, "mod" },
 
-	{ "AIF1", NULL, "SYSCLK AIF1" },
-	{ "AIF1 PLL", NULL, "AIF1" },
-	{ "SYSCLK", NULL, "AIF1 PLL" },
+	{ "SYSCLK", NULL, "AIF1CLK" },
 
+	{ "RST AIF1", NULL, "AIF1CLK" },
 	{ "RST AIF1", NULL, "SYSCLK" },
 	{ "MODCLK AIF1", NULL, "RST AIF1" },
 	{ "AIF1 AD0L", NULL, "MODCLK AIF1" },
 	{ "AIF1 AD0R", NULL, "MODCLK AIF1" },
 	{ "AIF1 DA0L", NULL, "MODCLK AIF1" },
 	{ "AIF1 DA0R", NULL, "MODCLK AIF1" },
 
 	{ "RST DAC", NULL, "SYSCLK" },
@@ -519,16 +518,33 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 			return ret;
 
 		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,
 	.set_fmt = sun8i_set_fmt,
 };
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 01/25] ASoC: sun8i-codec: Set up clock tree at probe time
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The sun8i codec is effectively an on-die variant of the X-Powers AC100
codec. The AC100 can derive its clocks from either of two I2S master
clocks or an internal PLL. For the on-die variant, Allwinner replaced
the codec's own PLL with a connection to SoC's existing PLL_AUDIO, and
they connected both I2S MCLK inputs to the same source -- which happens
to be an integer divider from the same PLL_AUDIO.

So there's actually no clocking flexibility. To run SYSCLK at the
required rate, it must be run straight from the PLL. The only choice is
whether it goes through AIF1CLK or AIF2CLK. Since both run at the same
rate, the only effect of that choice is which field in SYS_SR_CTRL
(AIF1_FS or AIF2_FS) controls the system sample rate.

Since AIFnCLK is required to bring up the corresponding DAI, and AIF1
(connected to the CPU) is used most often, let's use AIF1CLK as the
SYSCLK parent. That means we no longer need to set AIF2_FS.

Since this clock tree never changes, we can program it from the
component probe function, instead of using DAPM widgets. The DAPM
widgets unnecessarily change clock parents when the codec goes in/out
of idle and the supply widgets are powered up/down.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 178f6fb31fd4..407f0fedc4ed 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -19,20 +19,23 @@
 #include <linux/log2.h>
 
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
 #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
 #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
@@ -74,16 +77,18 @@
 #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_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_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 {
@@ -318,19 +323,16 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 
 	sample_rate = sun8i_codec_get_hw_rate(params);
 	if (sample_rate < 0)
 		return sample_rate;
 
 	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 struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
@@ -361,18 +363,26 @@ static const struct snd_kcontrol_new sun8i_input_mixer_controls[] = {
 			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 const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
+	/* 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),
+
 	/* 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_ENAD,
 			    0, NULL, 0),
 
 	/* AIF "DAC" Inputs */
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
@@ -410,44 +420,33 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* Clocks */
 	SND_SOC_DAPM_SUPPLY("MODCLK AIF1", 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),
-
-	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),
 
 	/* 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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
-	{ "AIF1", NULL, "mod" },
+	{ "AIF1CLK", NULL, "mod" },
 
-	{ "AIF1", NULL, "SYSCLK AIF1" },
-	{ "AIF1 PLL", NULL, "AIF1" },
-	{ "SYSCLK", NULL, "AIF1 PLL" },
+	{ "SYSCLK", NULL, "AIF1CLK" },
 
+	{ "RST AIF1", NULL, "AIF1CLK" },
 	{ "RST AIF1", NULL, "SYSCLK" },
 	{ "MODCLK AIF1", NULL, "RST AIF1" },
 	{ "AIF1 AD0L", NULL, "MODCLK AIF1" },
 	{ "AIF1 AD0R", NULL, "MODCLK AIF1" },
 	{ "AIF1 DA0L", NULL, "MODCLK AIF1" },
 	{ "AIF1 DA0R", NULL, "MODCLK AIF1" },
 
 	{ "RST DAC", NULL, "SYSCLK" },
@@ -519,16 +518,33 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 			return ret;
 
 		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,
 	.set_fmt = sun8i_set_fmt,
 };
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 01/25] ASoC: sun8i-codec: Set up clock tree at probe time
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The sun8i codec is effectively an on-die variant of the X-Powers AC100
codec. The AC100 can derive its clocks from either of two I2S master
clocks or an internal PLL. For the on-die variant, Allwinner replaced
the codec's own PLL with a connection to SoC's existing PLL_AUDIO, and
they connected both I2S MCLK inputs to the same source -- which happens
to be an integer divider from the same PLL_AUDIO.

So there's actually no clocking flexibility. To run SYSCLK at the
required rate, it must be run straight from the PLL. The only choice is
whether it goes through AIF1CLK or AIF2CLK. Since both run at the same
rate, the only effect of that choice is which field in SYS_SR_CTRL
(AIF1_FS or AIF2_FS) controls the system sample rate.

Since AIFnCLK is required to bring up the corresponding DAI, and AIF1
(connected to the CPU) is used most often, let's use AIF1CLK as the
SYSCLK parent. That means we no longer need to set AIF2_FS.

Since this clock tree never changes, we can program it from the
component probe function, instead of using DAPM widgets. The DAPM
widgets unnecessarily change clock parents when the codec goes in/out
of idle and the supply widgets are powered up/down.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 178f6fb31fd4..407f0fedc4ed 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -19,20 +19,23 @@
 #include <linux/log2.h>
 
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
 #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
 #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
@@ -74,16 +77,18 @@
 #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_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_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 {
@@ -318,19 +323,16 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 
 	sample_rate = sun8i_codec_get_hw_rate(params);
 	if (sample_rate < 0)
 		return sample_rate;
 
 	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 struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
@@ -361,18 +363,26 @@ static const struct snd_kcontrol_new sun8i_input_mixer_controls[] = {
 			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 const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
+	/* 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),
+
 	/* 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_ENAD,
 			    0, NULL, 0),
 
 	/* AIF "DAC" Inputs */
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
@@ -410,44 +420,33 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* Clocks */
 	SND_SOC_DAPM_SUPPLY("MODCLK AIF1", 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),
-
-	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),
 
 	/* 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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
-	{ "AIF1", NULL, "mod" },
+	{ "AIF1CLK", NULL, "mod" },
 
-	{ "AIF1", NULL, "SYSCLK AIF1" },
-	{ "AIF1 PLL", NULL, "AIF1" },
-	{ "SYSCLK", NULL, "AIF1 PLL" },
+	{ "SYSCLK", NULL, "AIF1CLK" },
 
+	{ "RST AIF1", NULL, "AIF1CLK" },
 	{ "RST AIF1", NULL, "SYSCLK" },
 	{ "MODCLK AIF1", NULL, "RST AIF1" },
 	{ "AIF1 AD0L", NULL, "MODCLK AIF1" },
 	{ "AIF1 AD0R", NULL, "MODCLK AIF1" },
 	{ "AIF1 DA0L", NULL, "MODCLK AIF1" },
 	{ "AIF1 DA0R", NULL, "MODCLK AIF1" },
 
 	{ "RST DAC", NULL, "SYSCLK" },
@@ -519,16 +518,33 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 			return ret;
 
 		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,
 	.set_fmt = sun8i_set_fmt,
 };
 
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 02/25] ASoC: sun8i-codec: Swap module clock/reset dependencies
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

This matches the module power-up/down sequence from the vendor's driver.

While updating these widgets/routes, reorder them to match the register
and bit layout of the hardware. This puts them in the same place in the
widget and route arrays (previously they were at opposite ends), and it
makes it easier to track which parts of which registers are implemented.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 407f0fedc4ed..6887a2e897f4 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -373,16 +373,38 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	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),
+
 	/* 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_ENAD,
 			    0, NULL, 0),
 
 	/* AIF "DAC" Inputs */
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
@@ -412,60 +434,44 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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),
-
-	/* Clocks */
-	SND_SOC_DAPM_SUPPLY("MODCLK AIF1", 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),
-
-	/* 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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
 	{ "AIF1CLK", NULL, "mod" },
 
 	{ "SYSCLK", NULL, "AIF1CLK" },
 
-	{ "RST AIF1", NULL, "AIF1CLK" },
-	{ "RST AIF1", NULL, "SYSCLK" },
-	{ "MODCLK AIF1", NULL, "RST AIF1" },
-	{ "AIF1 AD0L", NULL, "MODCLK AIF1" },
-	{ "AIF1 AD0R", NULL, "MODCLK AIF1" },
-	{ "AIF1 DA0L", NULL, "MODCLK AIF1" },
-	{ "AIF1 DA0R", NULL, "MODCLK AIF1" },
-
-	{ "RST DAC", NULL, "SYSCLK" },
-	{ "MODCLK DAC", NULL, "RST DAC" },
-	{ "DAC", NULL, "MODCLK DAC" },
-	{ "DACL", NULL, "DAC" },
-	{ "DACR", NULL, "DAC" },
-
-	{ "RST ADC", NULL, "SYSCLK" },
-	{ "MODCLK ADC", NULL, "RST ADC" },
-	{ "ADC", NULL, "MODCLK ADC" },
+	{ "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" },
+
 	/* DAC Routes */
 	{ "DACL", NULL, "Left Digital DAC Mixer" },
 	{ "DACR", NULL, "Right Digital DAC Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
 	{ "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 02/25] ASoC: sun8i-codec: Swap module clock/reset dependencies
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

This matches the module power-up/down sequence from the vendor's driver.

While updating these widgets/routes, reorder them to match the register
and bit layout of the hardware. This puts them in the same place in the
widget and route arrays (previously they were at opposite ends), and it
makes it easier to track which parts of which registers are implemented.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 407f0fedc4ed..6887a2e897f4 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -373,16 +373,38 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	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),
+
 	/* 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_ENAD,
 			    0, NULL, 0),
 
 	/* AIF "DAC" Inputs */
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
@@ -412,60 +434,44 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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),
-
-	/* Clocks */
-	SND_SOC_DAPM_SUPPLY("MODCLK AIF1", 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),
-
-	/* 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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
 	{ "AIF1CLK", NULL, "mod" },
 
 	{ "SYSCLK", NULL, "AIF1CLK" },
 
-	{ "RST AIF1", NULL, "AIF1CLK" },
-	{ "RST AIF1", NULL, "SYSCLK" },
-	{ "MODCLK AIF1", NULL, "RST AIF1" },
-	{ "AIF1 AD0L", NULL, "MODCLK AIF1" },
-	{ "AIF1 AD0R", NULL, "MODCLK AIF1" },
-	{ "AIF1 DA0L", NULL, "MODCLK AIF1" },
-	{ "AIF1 DA0R", NULL, "MODCLK AIF1" },
-
-	{ "RST DAC", NULL, "SYSCLK" },
-	{ "MODCLK DAC", NULL, "RST DAC" },
-	{ "DAC", NULL, "MODCLK DAC" },
-	{ "DACL", NULL, "DAC" },
-	{ "DACR", NULL, "DAC" },
-
-	{ "RST ADC", NULL, "SYSCLK" },
-	{ "MODCLK ADC", NULL, "RST ADC" },
-	{ "ADC", NULL, "MODCLK ADC" },
+	{ "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" },
+
 	/* DAC Routes */
 	{ "DACL", NULL, "Left Digital DAC Mixer" },
 	{ "DACR", NULL, "Right Digital DAC Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
 	{ "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 02/25] ASoC: sun8i-codec: Swap module clock/reset dependencies
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

This matches the module power-up/down sequence from the vendor's driver.

While updating these widgets/routes, reorder them to match the register
and bit layout of the hardware. This puts them in the same place in the
widget and route arrays (previously they were at opposite ends), and it
makes it easier to track which parts of which registers are implemented.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 407f0fedc4ed..6887a2e897f4 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -373,16 +373,38 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	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),
+
 	/* 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_ENAD,
 			    0, NULL, 0),
 
 	/* AIF "DAC" Inputs */
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
@@ -412,60 +434,44 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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),
-
-	/* Clocks */
-	SND_SOC_DAPM_SUPPLY("MODCLK AIF1", 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),
-
-	/* 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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
 	{ "AIF1CLK", NULL, "mod" },
 
 	{ "SYSCLK", NULL, "AIF1CLK" },
 
-	{ "RST AIF1", NULL, "AIF1CLK" },
-	{ "RST AIF1", NULL, "SYSCLK" },
-	{ "MODCLK AIF1", NULL, "RST AIF1" },
-	{ "AIF1 AD0L", NULL, "MODCLK AIF1" },
-	{ "AIF1 AD0R", NULL, "MODCLK AIF1" },
-	{ "AIF1 DA0L", NULL, "MODCLK AIF1" },
-	{ "AIF1 DA0R", NULL, "MODCLK AIF1" },
-
-	{ "RST DAC", NULL, "SYSCLK" },
-	{ "MODCLK DAC", NULL, "RST DAC" },
-	{ "DAC", NULL, "MODCLK DAC" },
-	{ "DACL", NULL, "DAC" },
-	{ "DACR", NULL, "DAC" },
-
-	{ "RST ADC", NULL, "SYSCLK" },
-	{ "MODCLK ADC", NULL, "RST ADC" },
-	{ "ADC", NULL, "MODCLK ADC" },
+	{ "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" },
+
 	/* DAC Routes */
 	{ "DACL", NULL, "Left Digital DAC Mixer" },
 	{ "DACR", NULL, "Right Digital DAC Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
 	{ "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 03/25] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

Sort the remaining pieces of the DAPM driver so that they are all in the
same order among controls/widgets/routes, and so they roughly match the
register word and bit order of the hardware. This nicely separates the
AIF-related widgets from the ADC/DAC widgets, which allows the AIF
widgets to stay in a logical order as more AIFs are added to the driver.

No widgets are renamed, to ease verification that this commit makes no
functional change.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 6887a2e897f4..d14243c434f9 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -327,16 +327,35 @@ 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);
 
 	return 0;
 }
 
+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 const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
@@ -344,34 +363,16 @@ static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
 	SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
 			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_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 const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	/* 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",
@@ -395,55 +396,59 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			    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),
 
-	/* 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_ENAD,
-			    0, NULL, 0),
-
-	/* 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 DA0R", "Playback", 0,
-			    SUN8I_AIF1_DACDAT_CTRL,
-			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 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_IN("AIF1 AD0L", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
 	SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
+	/* AIF "ADC" Mixers */
+	SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif1_ad0_mixer_controls),
+	SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif1_ad0_mixer_controls),
+
+	/* 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 DA0R", "Playback", 0,
+			    SUN8I_AIF1_DACDAT_CTRL,
+			    SUN8I_AIF1_DACDAT_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 */
+	/* DAC 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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
 	{ "AIF1CLK", NULL, "mod" },
 
 	{ "SYSCLK", NULL, "AIF1CLK" },
 
@@ -462,37 +467,37 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "ADCR", NULL, "ADC" },
 
 	{ "CLK DAC", NULL, "SYSCLK" },
 	{ "RST DAC", NULL, "CLK DAC" },
 	{ "DAC", NULL, "RST DAC" },
 	{ "DACL", NULL, "DAC" },
 	{ "DACR", NULL, "DAC" },
 
-	/* DAC Routes */
+	/* AIF "ADC" Output Routes */
+	{ "AIF1 AD0L", NULL, "Left Digital ADC Mixer" },
+	{ "AIF1 AD0R", NULL, "Right Digital ADC Mixer" },
+
+	/* AIF "ADC" Mixer Routes */
+	{ "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
+	{ "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+
+	{ "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
+	{ "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+
+	/* DAC Output Routes */
 	{ "DACL", NULL, "Left Digital DAC Mixer" },
 	{ "DACR", NULL, "Right Digital DAC Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
 	{ "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
 	{ "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
 	{ "Right Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
-
-	/* ADC Routes */
-	{ "AIF1 AD0L", NULL, "Left Digital ADC Mixer" },
-	{ "AIF1 AD0R", NULL, "Right Digital ADC Mixer" },
-
-	/* ADC Mixer Routes */
-	{ "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
-	{ "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
-
-	{ "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
-	{ "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
 };
 
 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) */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 03/25] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Sort the remaining pieces of the DAPM driver so that they are all in the
same order among controls/widgets/routes, and so they roughly match the
register word and bit order of the hardware. This nicely separates the
AIF-related widgets from the ADC/DAC widgets, which allows the AIF
widgets to stay in a logical order as more AIFs are added to the driver.

No widgets are renamed, to ease verification that this commit makes no
functional change.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 6887a2e897f4..d14243c434f9 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -327,16 +327,35 @@ 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);
 
 	return 0;
 }
 
+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 const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
@@ -344,34 +363,16 @@ static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
 	SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
 			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_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 const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	/* 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",
@@ -395,55 +396,59 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			    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),
 
-	/* 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_ENAD,
-			    0, NULL, 0),
-
-	/* 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 DA0R", "Playback", 0,
-			    SUN8I_AIF1_DACDAT_CTRL,
-			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 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_IN("AIF1 AD0L", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
 	SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
+	/* AIF "ADC" Mixers */
+	SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif1_ad0_mixer_controls),
+	SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif1_ad0_mixer_controls),
+
+	/* 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 DA0R", "Playback", 0,
+			    SUN8I_AIF1_DACDAT_CTRL,
+			    SUN8I_AIF1_DACDAT_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 */
+	/* DAC 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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
 	{ "AIF1CLK", NULL, "mod" },
 
 	{ "SYSCLK", NULL, "AIF1CLK" },
 
@@ -462,37 +467,37 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "ADCR", NULL, "ADC" },
 
 	{ "CLK DAC", NULL, "SYSCLK" },
 	{ "RST DAC", NULL, "CLK DAC" },
 	{ "DAC", NULL, "RST DAC" },
 	{ "DACL", NULL, "DAC" },
 	{ "DACR", NULL, "DAC" },
 
-	/* DAC Routes */
+	/* AIF "ADC" Output Routes */
+	{ "AIF1 AD0L", NULL, "Left Digital ADC Mixer" },
+	{ "AIF1 AD0R", NULL, "Right Digital ADC Mixer" },
+
+	/* AIF "ADC" Mixer Routes */
+	{ "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
+	{ "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+
+	{ "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
+	{ "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+
+	/* DAC Output Routes */
 	{ "DACL", NULL, "Left Digital DAC Mixer" },
 	{ "DACR", NULL, "Right Digital DAC Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
 	{ "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
 	{ "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
 	{ "Right Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
-
-	/* ADC Routes */
-	{ "AIF1 AD0L", NULL, "Left Digital ADC Mixer" },
-	{ "AIF1 AD0R", NULL, "Right Digital ADC Mixer" },
-
-	/* ADC Mixer Routes */
-	{ "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
-	{ "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
-
-	{ "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
-	{ "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
 };
 
 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) */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 03/25] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Sort the remaining pieces of the DAPM driver so that they are all in the
same order among controls/widgets/routes, and so they roughly match the
register word and bit order of the hardware. This nicely separates the
AIF-related widgets from the ADC/DAC widgets, which allows the AIF
widgets to stay in a logical order as more AIFs are added to the driver.

No widgets are renamed, to ease verification that this commit makes no
functional change.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 6887a2e897f4..d14243c434f9 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -327,16 +327,35 @@ 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);
 
 	return 0;
 }
 
+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 const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
@@ -344,34 +363,16 @@ static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
 	SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
 			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_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 const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	/* 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",
@@ -395,55 +396,59 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			    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),
 
-	/* 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_ENAD,
-			    0, NULL, 0),
-
-	/* 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 DA0R", "Playback", 0,
-			    SUN8I_AIF1_DACDAT_CTRL,
-			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 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_IN("AIF1 AD0L", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
 	SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
+	/* AIF "ADC" Mixers */
+	SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif1_ad0_mixer_controls),
+	SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif1_ad0_mixer_controls),
+
+	/* 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 DA0R", "Playback", 0,
+			    SUN8I_AIF1_DACDAT_CTRL,
+			    SUN8I_AIF1_DACDAT_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 */
+	/* DAC 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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
 	{ "AIF1CLK", NULL, "mod" },
 
 	{ "SYSCLK", NULL, "AIF1CLK" },
 
@@ -462,37 +467,37 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "ADCR", NULL, "ADC" },
 
 	{ "CLK DAC", NULL, "SYSCLK" },
 	{ "RST DAC", NULL, "CLK DAC" },
 	{ "DAC", NULL, "RST DAC" },
 	{ "DACL", NULL, "DAC" },
 	{ "DACR", NULL, "DAC" },
 
-	/* DAC Routes */
+	/* AIF "ADC" Output Routes */
+	{ "AIF1 AD0L", NULL, "Left Digital ADC Mixer" },
+	{ "AIF1 AD0R", NULL, "Right Digital ADC Mixer" },
+
+	/* AIF "ADC" Mixer Routes */
+	{ "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
+	{ "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+
+	{ "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
+	{ "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+
+	/* DAC Output Routes */
 	{ "DACL", NULL, "Left Digital DAC Mixer" },
 	{ "DACR", NULL, "Right Digital DAC Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
 	{ "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
 	{ "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
 	{ "Right Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
-
-	/* ADC Routes */
-	{ "AIF1 AD0L", NULL, "Left Digital ADC Mixer" },
-	{ "AIF1 AD0R", NULL, "Right Digital ADC Mixer" },
-
-	/* ADC Mixer Routes */
-	{ "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
-	{ "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
-
-	{ "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
-	{ "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
 };
 
 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) */
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 04/25] ASoC: sun8i-codec: Consistently name DAPM widgets and routes
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

This cleans up the mixer widget names. The AIF1 AD0 Mixer names were
previously wrong -- they do not control the digital side of the ADC. The
DAC mixer widgets were not wrong, but they were verbose and did not
match the naming scheme of the other widgets.

The mixer controls are not renamed because they are exposed to
userspace.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index d14243c434f9..30fe27648254 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -413,19 +413,19 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_IN("AIF1 AD0L", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
 	SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
 	/* AIF "ADC" Mixers */
-	SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+	SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif1_ad0_mixer_controls),
-	SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+	SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif1_ad0_mixer_controls),
 
 	/* 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 DA0R", "Playback", 0,
 			    SUN8I_AIF1_DACDAT_CTRL,
@@ -435,19 +435,19 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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 Mixers */
-	SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
+	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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
 	{ "AIF1CLK", NULL, "mod" },
 
 	{ "SYSCLK", NULL, "AIF1CLK" },
@@ -468,36 +468,36 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	{ "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, "Left Digital ADC Mixer" },
-	{ "AIF1 AD0R", NULL, "Right Digital ADC Mixer" },
+	{ "AIF1 AD0L", NULL, "AIF1 AD0L Mixer" },
+	{ "AIF1 AD0R", NULL, "AIF1 AD0R Mixer" },
 
 	/* AIF "ADC" Mixer Routes */
-	{ "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
-	{ "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
+	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
 
-	{ "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
-	{ "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
+	{ "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
 
 	/* DAC Output Routes */
-	{ "DACL", NULL, "Left Digital DAC Mixer" },
-	{ "DACR", NULL, "Right Digital DAC Mixer" },
+	{ "DACL", NULL, "DACL Mixer" },
+	{ "DACR", NULL, "DACR Mixer" },
 
 	/* DAC Mixer Routes */
-	{ "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
-	{ "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
+	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
+	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
-	{ "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
-	{ "Right Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
+	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
+	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
 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) */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 04/25] ASoC: sun8i-codec: Consistently name DAPM widgets and routes
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

This cleans up the mixer widget names. The AIF1 AD0 Mixer names were
previously wrong -- they do not control the digital side of the ADC. The
DAC mixer widgets were not wrong, but they were verbose and did not
match the naming scheme of the other widgets.

The mixer controls are not renamed because they are exposed to
userspace.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index d14243c434f9..30fe27648254 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -413,19 +413,19 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_IN("AIF1 AD0L", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
 	SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
 	/* AIF "ADC" Mixers */
-	SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+	SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif1_ad0_mixer_controls),
-	SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+	SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif1_ad0_mixer_controls),
 
 	/* 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 DA0R", "Playback", 0,
 			    SUN8I_AIF1_DACDAT_CTRL,
@@ -435,19 +435,19 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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 Mixers */
-	SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
+	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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
 	{ "AIF1CLK", NULL, "mod" },
 
 	{ "SYSCLK", NULL, "AIF1CLK" },
@@ -468,36 +468,36 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	{ "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, "Left Digital ADC Mixer" },
-	{ "AIF1 AD0R", NULL, "Right Digital ADC Mixer" },
+	{ "AIF1 AD0L", NULL, "AIF1 AD0L Mixer" },
+	{ "AIF1 AD0R", NULL, "AIF1 AD0R Mixer" },
 
 	/* AIF "ADC" Mixer Routes */
-	{ "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
-	{ "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
+	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
 
-	{ "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
-	{ "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
+	{ "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
 
 	/* DAC Output Routes */
-	{ "DACL", NULL, "Left Digital DAC Mixer" },
-	{ "DACR", NULL, "Right Digital DAC Mixer" },
+	{ "DACL", NULL, "DACL Mixer" },
+	{ "DACR", NULL, "DACR Mixer" },
 
 	/* DAC Mixer Routes */
-	{ "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
-	{ "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
+	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
+	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
-	{ "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
-	{ "Right Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
+	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
+	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
 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) */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 04/25] ASoC: sun8i-codec: Consistently name DAPM widgets and routes
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

This cleans up the mixer widget names. The AIF1 AD0 Mixer names were
previously wrong -- they do not control the digital side of the ADC. The
DAC mixer widgets were not wrong, but they were verbose and did not
match the naming scheme of the other widgets.

The mixer controls are not renamed because they are exposed to
userspace.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index d14243c434f9..30fe27648254 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -413,19 +413,19 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_IN("AIF1 AD0L", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
 	SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0,
 			    SUN8I_AIF1_ADCDAT_CTRL,
 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
 	/* AIF "ADC" Mixers */
-	SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+	SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif1_ad0_mixer_controls),
-	SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
+	SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif1_ad0_mixer_controls),
 
 	/* 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 DA0R", "Playback", 0,
 			    SUN8I_AIF1_DACDAT_CTRL,
@@ -435,19 +435,19 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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 Mixers */
-	SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
+	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),
 };
 
 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	/* Clock Routes */
 	{ "AIF1CLK", NULL, "mod" },
 
 	{ "SYSCLK", NULL, "AIF1CLK" },
@@ -468,36 +468,36 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	{ "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, "Left Digital ADC Mixer" },
-	{ "AIF1 AD0R", NULL, "Right Digital ADC Mixer" },
+	{ "AIF1 AD0L", NULL, "AIF1 AD0L Mixer" },
+	{ "AIF1 AD0R", NULL, "AIF1 AD0R Mixer" },
 
 	/* AIF "ADC" Mixer Routes */
-	{ "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
-	{ "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" },
+	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
 
-	{ "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
-	{ "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" },
+	{ "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
 
 	/* DAC Output Routes */
-	{ "DACL", NULL, "Left Digital DAC Mixer" },
-	{ "DACR", NULL, "Right Digital DAC Mixer" },
+	{ "DACL", NULL, "DACL Mixer" },
+	{ "DACR", NULL, "DACR Mixer" },
 
 	/* DAC Mixer Routes */
-	{ "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
-	{ "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
+	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
+	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
-	{ "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
-	{ "Right Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
+	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
+	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
 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) */
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 05/25] ASoC: sun8i-codec: Correct DAPM widget types
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

Whie the aif_in and aif_out widget types are handled exactly the same in
the core DAPM code, a future widget event hook will need the correct
widget type to derive the associated substream. Clean up the widget type
for that reason, and so these widgets will match newly-added widgets for
the other AIFs.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 30fe27648254..d0028883950c 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -405,22 +405,22 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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_IN("AIF1 AD0L", "Capture", 0,
-			    SUN8I_AIF1_ADCDAT_CTRL,
-			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
-	SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0,
-			    SUN8I_AIF1_ADCDAT_CTRL,
-			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
+	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", 0,
+			     SUN8I_AIF1_ADCDAT_CTRL,
+			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
 	/* 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" Inputs */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 05/25] ASoC: sun8i-codec: Correct DAPM widget types
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Whie the aif_in and aif_out widget types are handled exactly the same in
the core DAPM code, a future widget event hook will need the correct
widget type to derive the associated substream. Clean up the widget type
for that reason, and so these widgets will match newly-added widgets for
the other AIFs.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 30fe27648254..d0028883950c 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -405,22 +405,22 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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_IN("AIF1 AD0L", "Capture", 0,
-			    SUN8I_AIF1_ADCDAT_CTRL,
-			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
-	SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0,
-			    SUN8I_AIF1_ADCDAT_CTRL,
-			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
+	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", 0,
+			     SUN8I_AIF1_ADCDAT_CTRL,
+			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
 	/* 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" Inputs */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 05/25] ASoC: sun8i-codec: Correct DAPM widget types
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Whie the aif_in and aif_out widget types are handled exactly the same in
the core DAPM code, a future widget event hook will need the correct
widget type to derive the associated substream. Clean up the widget type
for that reason, and so these widgets will match newly-added widgets for
the other AIFs.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 30fe27648254..d0028883950c 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -405,22 +405,22 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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_IN("AIF1 AD0L", "Capture", 0,
-			    SUN8I_AIF1_ADCDAT_CTRL,
-			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
-	SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0,
-			    SUN8I_AIF1_ADCDAT_CTRL,
-			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
+	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", 0,
+			     SUN8I_AIF1_ADCDAT_CTRL,
+			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
 	/* 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" Inputs */
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 06/25] ASoC: sun8i-codec: Fix AIF widget channel references
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

Both the left and right side widgets referenced channel 0. This would
unnecessarily power on the right side widget (and its associated path)
when a mono stream was active.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index d0028883950c..2c89974243e1 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -408,31 +408,31 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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", 0,
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
 	/* 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" 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 DA0R", "Playback", 0,
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_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) */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 06/25] ASoC: sun8i-codec: Fix AIF widget channel references
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Both the left and right side widgets referenced channel 0. This would
unnecessarily power on the right side widget (and its associated path)
when a mono stream was active.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index d0028883950c..2c89974243e1 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -408,31 +408,31 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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", 0,
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
 	/* 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" 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 DA0R", "Playback", 0,
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_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) */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 06/25] ASoC: sun8i-codec: Fix AIF widget channel references
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Both the left and right side widgets referenced channel 0. This would
unnecessarily power on the right side widget (and its associated path)
when a mono stream was active.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index d0028883950c..2c89974243e1 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -408,31 +408,31 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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", 0,
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
 	/* 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" 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 DA0R", "Playback", 0,
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_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) */
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 07/25] ASoC: sun8i-codec: Enable AIF mono/stereo control
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

Each left/right pair of AIF input/output channels can be swapped or
combined. This is useful for sending a mono audio source to both sides
of a stereo sink, or for creating complex mixing scenarios.

Add the support to control this feature from userspace.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 2c89974243e1..578c0c0e6330 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -49,19 +49,23 @@
 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
 #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_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
 #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
@@ -327,16 +331,30 @@ 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);
 
 	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,
@@ -346,16 +364,26 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
 			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,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
@@ -412,22 +440,34 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	/* 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 DA0R", "Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
 
@@ -468,35 +508,65 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	{ "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 Mixer" },
-	{ "AIF1 AD0R", NULL, "AIF1 AD0R Mixer" },
+	{ "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" },
+	{ "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" },
+	{ "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" },
 
 	/* DAC Mixer Routes */
-	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
+	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
 	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
-	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
+	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
 	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
 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),
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 07/25] ASoC: sun8i-codec: Enable AIF mono/stereo control
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Each left/right pair of AIF input/output channels can be swapped or
combined. This is useful for sending a mono audio source to both sides
of a stereo sink, or for creating complex mixing scenarios.

Add the support to control this feature from userspace.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 2c89974243e1..578c0c0e6330 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -49,19 +49,23 @@
 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
 #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_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
 #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
@@ -327,16 +331,30 @@ 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);
 
 	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,
@@ -346,16 +364,26 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
 			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,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
@@ -412,22 +440,34 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	/* 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 DA0R", "Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
 
@@ -468,35 +508,65 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	{ "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 Mixer" },
-	{ "AIF1 AD0R", NULL, "AIF1 AD0R Mixer" },
+	{ "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" },
+	{ "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" },
+	{ "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" },
 
 	/* DAC Mixer Routes */
-	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
+	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
 	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
-	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
+	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
 	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
 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),
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 07/25] ASoC: sun8i-codec: Enable AIF mono/stereo control
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Each left/right pair of AIF input/output channels can be swapped or
combined. This is useful for sending a mono audio source to both sides
of a stereo sink, or for creating complex mixing scenarios.

Add the support to control this feature from userspace.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 2c89974243e1..578c0c0e6330 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -49,19 +49,23 @@
 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
 #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_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
 #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
@@ -327,16 +331,30 @@ 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);
 
 	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,
@@ -346,16 +364,26 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
 			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,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
@@ -412,22 +440,34 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	/* 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 DA0R", "Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
 
@@ -468,35 +508,65 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	{ "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 Mixer" },
-	{ "AIF1 AD0R", NULL, "AIF1 AD0R Mixer" },
+	{ "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" },
+	{ "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" },
+	{ "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" },
 
 	/* DAC Mixer Routes */
-	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" },
+	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
 	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
-	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" },
+	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
 	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
 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),
 
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 08/25] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

Remove a level of indirection by getting the device directly from the
passed-in struct snd_soc_dai, instead of going through its component.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 578c0c0e6330..7590c4b04d14 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -162,17 +162,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
 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 */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
@@ -294,17 +294,17 @@ static int sun8i_codec_get_lrck_div(unsigned int channels,
 
 	return ilog2(div) - 4;
 }
 
 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;
 
 	/*
 	 * The CPU DAI handles only a sample of 16 bits. Configure the
 	 * codec to handle this type of sample resolution.
 	 */
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 08/25] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Remove a level of indirection by getting the device directly from the
passed-in struct snd_soc_dai, instead of going through its component.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 578c0c0e6330..7590c4b04d14 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -162,17 +162,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
 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 */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
@@ -294,17 +294,17 @@ static int sun8i_codec_get_lrck_div(unsigned int channels,
 
 	return ilog2(div) - 4;
 }
 
 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;
 
 	/*
 	 * The CPU DAI handles only a sample of 16 bits. Configure the
 	 * codec to handle this type of sample resolution.
 	 */
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 08/25] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Remove a level of indirection by getting the device directly from the
passed-in struct snd_soc_dai, instead of going through its component.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 578c0c0e6330..7590c4b04d14 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -162,17 +162,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
 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 */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
@@ -294,17 +294,17 @@ static int sun8i_codec_get_lrck_div(unsigned int channels,
 
 	return ilog2(div) - 4;
 }
 
 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;
 
 	/*
 	 * The CPU DAI handles only a sample of 16 bits. Configure the
 	 * codec to handle this type of sample resolution.
 	 */
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 09/25] ASoC: sun8i-codec: Prepare to extend the DAI driver
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

In preparation for adding additional DAIs to this component, convert the
DAI driver definition to an array. Since this changes all of the lines
in the definition anyway, let's move it closer to the ops function
definitions, instead of on the far side of the DAPM arrays. And while
moving the DAI driver ops, rename the set_fmt hook to match the usual
naming scheme.

Give the existing DAI an explicit ID and more meaningful stream names,
so it will remain unique as more DAIs are added. The AIF widget streams
must be updated to match.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 7590c4b04d14..346f699c2e86 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -90,16 +90,21 @@
 #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_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)
 
+enum {
+	AIF1,
+	NAIFS
+};
+
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
@@ -160,17 +165,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 		return 0x9;
 	case 192000:
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
-static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	u32 value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
@@ -331,16 +336,46 @@ 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);
 
 	return 0;
 }
 
+static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
+	.set_fmt	= sun8i_codec_set_fmt,
+	.hw_params	= sun8i_codec_hw_params,
+};
+
+static struct snd_soc_dai_driver sun8i_codec_dais[] = {
+	{
+		.name	= "sun8i-codec-aif1",
+		.id	= AIF1,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF1 Capture",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF1 Playback",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	},
+};
+
 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,
@@ -433,20 +468,20 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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,
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "AIF1 Capture", 0,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
-	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 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),
@@ -459,20 +494,20 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* 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,
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "AIF1 Playback", 0,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
-	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_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) */
@@ -619,44 +654,16 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 	/* 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,
-	.set_fmt = sun8i_set_fmt,
-};
-
-static struct snd_soc_dai_driver sun8i_codec_dai = {
-	.name = "sun8i",
-	/* playback capabilities */
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 1,
-		.channels_max = 2,
-		.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,
-};
-
 static const struct snd_soc_component_driver sun8i_soc_component = {
 	.dapm_widgets		= sun8i_codec_dapm_widgets,
 	.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,
@@ -709,17 +716,18 @@ static int sun8i_codec_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	if (!pm_runtime_enabled(&pdev->dev)) {
 		ret = sun8i_codec_runtime_resume(&pdev->dev);
 		if (ret)
 			goto err_pm_disable;
 	}
 
 	ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
-				     &sun8i_codec_dai, 1);
+					      sun8i_codec_dais,
+					      ARRAY_SIZE(sun8i_codec_dais));
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register codec\n");
 		goto err_suspend;
 	}
 
 	return ret;
 
 err_suspend:
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 09/25] ASoC: sun8i-codec: Prepare to extend the DAI driver
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

In preparation for adding additional DAIs to this component, convert the
DAI driver definition to an array. Since this changes all of the lines
in the definition anyway, let's move it closer to the ops function
definitions, instead of on the far side of the DAPM arrays. And while
moving the DAI driver ops, rename the set_fmt hook to match the usual
naming scheme.

Give the existing DAI an explicit ID and more meaningful stream names,
so it will remain unique as more DAIs are added. The AIF widget streams
must be updated to match.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 7590c4b04d14..346f699c2e86 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -90,16 +90,21 @@
 #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_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)
 
+enum {
+	AIF1,
+	NAIFS
+};
+
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
@@ -160,17 +165,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 		return 0x9;
 	case 192000:
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
-static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	u32 value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
@@ -331,16 +336,46 @@ 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);
 
 	return 0;
 }
 
+static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
+	.set_fmt	= sun8i_codec_set_fmt,
+	.hw_params	= sun8i_codec_hw_params,
+};
+
+static struct snd_soc_dai_driver sun8i_codec_dais[] = {
+	{
+		.name	= "sun8i-codec-aif1",
+		.id	= AIF1,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF1 Capture",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF1 Playback",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	},
+};
+
 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,
@@ -433,20 +468,20 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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,
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "AIF1 Capture", 0,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
-	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 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),
@@ -459,20 +494,20 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* 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,
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "AIF1 Playback", 0,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
-	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_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) */
@@ -619,44 +654,16 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 	/* 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,
-	.set_fmt = sun8i_set_fmt,
-};
-
-static struct snd_soc_dai_driver sun8i_codec_dai = {
-	.name = "sun8i",
-	/* playback capabilities */
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 1,
-		.channels_max = 2,
-		.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,
-};
-
 static const struct snd_soc_component_driver sun8i_soc_component = {
 	.dapm_widgets		= sun8i_codec_dapm_widgets,
 	.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,
@@ -709,17 +716,18 @@ static int sun8i_codec_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	if (!pm_runtime_enabled(&pdev->dev)) {
 		ret = sun8i_codec_runtime_resume(&pdev->dev);
 		if (ret)
 			goto err_pm_disable;
 	}
 
 	ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
-				     &sun8i_codec_dai, 1);
+					      sun8i_codec_dais,
+					      ARRAY_SIZE(sun8i_codec_dais));
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register codec\n");
 		goto err_suspend;
 	}
 
 	return ret;
 
 err_suspend:
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 09/25] ASoC: sun8i-codec: Prepare to extend the DAI driver
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

In preparation for adding additional DAIs to this component, convert the
DAI driver definition to an array. Since this changes all of the lines
in the definition anyway, let's move it closer to the ops function
definitions, instead of on the far side of the DAPM arrays. And while
moving the DAI driver ops, rename the set_fmt hook to match the usual
naming scheme.

Give the existing DAI an explicit ID and more meaningful stream names,
so it will remain unique as more DAIs are added. The AIF widget streams
must be updated to match.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 7590c4b04d14..346f699c2e86 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -90,16 +90,21 @@
 #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_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)
 
+enum {
+	AIF1,
+	NAIFS
+};
+
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
@@ -160,17 +165,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 		return 0x9;
 	case 192000:
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
-static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	u32 value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
@@ -331,16 +336,46 @@ 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);
 
 	return 0;
 }
 
+static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
+	.set_fmt	= sun8i_codec_set_fmt,
+	.hw_params	= sun8i_codec_hw_params,
+};
+
+static struct snd_soc_dai_driver sun8i_codec_dais[] = {
+	{
+		.name	= "sun8i-codec-aif1",
+		.id	= AIF1,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF1 Capture",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF1 Playback",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	},
+};
+
 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,
@@ -433,20 +468,20 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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,
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "AIF1 Capture", 0,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
-	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 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),
@@ -459,20 +494,20 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* 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,
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "AIF1 Playback", 0,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
-	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_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) */
@@ -619,44 +654,16 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 	/* 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,
-	.set_fmt = sun8i_set_fmt,
-};
-
-static struct snd_soc_dai_driver sun8i_codec_dai = {
-	.name = "sun8i",
-	/* playback capabilities */
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 1,
-		.channels_max = 2,
-		.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,
-};
-
 static const struct snd_soc_component_driver sun8i_soc_component = {
 	.dapm_widgets		= sun8i_codec_dapm_widgets,
 	.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,
@@ -709,17 +716,18 @@ static int sun8i_codec_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	if (!pm_runtime_enabled(&pdev->dev)) {
 		ret = sun8i_codec_runtime_resume(&pdev->dev);
 		if (ret)
 			goto err_pm_disable;
 	}
 
 	ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
-				     &sun8i_codec_dai, 1);
+					      sun8i_codec_dais,
+					      ARRAY_SIZE(sun8i_codec_dais));
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register codec\n");
 		goto err_suspend;
 	}
 
 	return ret;
 
 err_suspend:
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 10/25] ASoC: sun8i-codec: Program format before clock inversion
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

The LRCK inversion bit has a different meaning in DSP mode: it selects
between DSP A and DSP B formats. To support this, we need to know if
the selected format is a DSP format. One easy way to do this is to set
the format field before the inversion fields.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 346f699c2e86..0b713b2a2028 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -168,33 +168,55 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	default:
 		return -EINVAL;
 	}
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-	u32 value;
+	u32 format, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
 		break;
 	default:
 		return -EINVAL;
 	}
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
 			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
 
+	/* DAI format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format = 0x0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format = 0x1;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		format = 0x2;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		format = 0x3;
+		break;
+	default:
+		return -EINVAL;
+	}
+	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
+			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
+
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
 	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
 		value = 0x1;
 		break;
@@ -215,38 +237,16 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	 * 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);
 
-	/* DAI format */
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-		value = 0x0;
-		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		value = 0x1;
-		break;
-	case SND_SOC_DAIFMT_RIGHT_J:
-		value = 0x2;
-		break;
-	case SND_SOC_DAIFMT_DSP_A:
-	case SND_SOC_DAIFMT_DSP_B:
-		value = 0x3;
-		break;
-	default:
-		return -EINVAL;
-	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
-
 	return 0;
 }
 
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 10/25] ASoC: sun8i-codec: Program format before clock inversion
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The LRCK inversion bit has a different meaning in DSP mode: it selects
between DSP A and DSP B formats. To support this, we need to know if
the selected format is a DSP format. One easy way to do this is to set
the format field before the inversion fields.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 346f699c2e86..0b713b2a2028 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -168,33 +168,55 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	default:
 		return -EINVAL;
 	}
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-	u32 value;
+	u32 format, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
 		break;
 	default:
 		return -EINVAL;
 	}
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
 			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
 
+	/* DAI format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format = 0x0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format = 0x1;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		format = 0x2;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		format = 0x3;
+		break;
+	default:
+		return -EINVAL;
+	}
+	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
+			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
+
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
 	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
 		value = 0x1;
 		break;
@@ -215,38 +237,16 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	 * 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);
 
-	/* DAI format */
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-		value = 0x0;
-		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		value = 0x1;
-		break;
-	case SND_SOC_DAIFMT_RIGHT_J:
-		value = 0x2;
-		break;
-	case SND_SOC_DAIFMT_DSP_A:
-	case SND_SOC_DAIFMT_DSP_B:
-		value = 0x3;
-		break;
-	default:
-		return -EINVAL;
-	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
-
 	return 0;
 }
 
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 10/25] ASoC: sun8i-codec: Program format before clock inversion
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The LRCK inversion bit has a different meaning in DSP mode: it selects
between DSP A and DSP B formats. To support this, we need to know if
the selected format is a DSP format. One easy way to do this is to set
the format field before the inversion fields.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 346f699c2e86..0b713b2a2028 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -168,33 +168,55 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	default:
 		return -EINVAL;
 	}
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-	u32 value;
+	u32 format, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
 		break;
 	default:
 		return -EINVAL;
 	}
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
 			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
 
+	/* DAI format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format = 0x0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format = 0x1;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		format = 0x2;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		format = 0x3;
+		break;
+	default:
+		return -EINVAL;
+	}
+	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
+			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
+
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
 	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
 		value = 0x1;
 		break;
@@ -215,38 +237,16 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	 * 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);
 
-	/* DAI format */
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-		value = 0x0;
-		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		value = 0x1;
-		break;
-	case SND_SOC_DAIFMT_RIGHT_J:
-		value = 0x2;
-		break;
-	case SND_SOC_DAIFMT_DSP_A:
-	case SND_SOC_DAIFMT_DSP_B:
-		value = 0x3;
-		break;
-	default:
-		return -EINVAL;
-	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
-
 	return 0;
 }
 
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
 
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
LRCK inversion is not supported. The register bit is repurposed to
select between DSP_A and DSP_B. Extend the driver to support this.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 0b713b2a2028..506420fb355c 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -39,18 +39,17 @@
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF1CLK_CTRL				0x040
 #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
+#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
 #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_AD0L_ENA		15
 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
@@ -85,16 +84,17 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
 enum {
 	AIF1,
 	NAIFS
@@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	default:
 		return -EINVAL;
 	}
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-	u32 format, value;
+	u32 format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
@@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		format = 0x1;
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
 		format = 0x2;
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
+		format = 0x3;
+		invert = 0x0; /* Set LRCK_INV to 0 */
+		break;
 	case SND_SOC_DAIFMT_DSP_B:
 		format = 0x3;
+		invert = 0x1; /* Set LRCK_INV to 1 */
 		break;
 	default:
 		return -EINVAL;
 	}
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
 			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
 
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
-	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
+	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
 		value = 0x1;
 		break;
+	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
+		value = 0x2;
+		break;
+	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
+		value = 0x3;
+		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
 
-	/*
-	 * 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;
+	if (format == 0x3) {
+		/* Inverted LRCK is not available in DSP mode. */
+		if (value & BIT(0))
+			return -EINVAL;
+
+		/* Instead, the bit selects between DSP A/B formats. */
+		value |= invert;
+	} else {
+		/*
+		 * 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);
+			   SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
+			   value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);
 
 	return 0;
 }
 
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
LRCK inversion is not supported. The register bit is repurposed to
select between DSP_A and DSP_B. Extend the driver to support this.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 0b713b2a2028..506420fb355c 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -39,18 +39,17 @@
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF1CLK_CTRL				0x040
 #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
+#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
 #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_AD0L_ENA		15
 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
@@ -85,16 +84,17 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
 enum {
 	AIF1,
 	NAIFS
@@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	default:
 		return -EINVAL;
 	}
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-	u32 format, value;
+	u32 format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
@@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		format = 0x1;
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
 		format = 0x2;
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
+		format = 0x3;
+		invert = 0x0; /* Set LRCK_INV to 0 */
+		break;
 	case SND_SOC_DAIFMT_DSP_B:
 		format = 0x3;
+		invert = 0x1; /* Set LRCK_INV to 1 */
 		break;
 	default:
 		return -EINVAL;
 	}
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
 			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
 
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
-	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
+	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
 		value = 0x1;
 		break;
+	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
+		value = 0x2;
+		break;
+	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
+		value = 0x3;
+		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
 
-	/*
-	 * 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;
+	if (format == 0x3) {
+		/* Inverted LRCK is not available in DSP mode. */
+		if (value & BIT(0))
+			return -EINVAL;
+
+		/* Instead, the bit selects between DSP A/B formats. */
+		value |= invert;
+	} else {
+		/*
+		 * 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);
+			   SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
+			   value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);
 
 	return 0;
 }
 
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
LRCK inversion is not supported. The register bit is repurposed to
select between DSP_A and DSP_B. Extend the driver to support this.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 0b713b2a2028..506420fb355c 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -39,18 +39,17 @@
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF1CLK_CTRL				0x040
 #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
+#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
 #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_AD0L_ENA		15
 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
@@ -85,16 +84,17 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
 enum {
 	AIF1,
 	NAIFS
@@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	default:
 		return -EINVAL;
 	}
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-	u32 format, value;
+	u32 format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
@@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		format = 0x1;
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
 		format = 0x2;
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
+		format = 0x3;
+		invert = 0x0; /* Set LRCK_INV to 0 */
+		break;
 	case SND_SOC_DAIFMT_DSP_B:
 		format = 0x3;
+		invert = 0x1; /* Set LRCK_INV to 1 */
 		break;
 	default:
 		return -EINVAL;
 	}
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
 			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
 
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
-	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
+	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
 		value = 0x1;
 		break;
+	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
+		value = 0x2;
+		break;
+	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
+		value = 0x3;
+		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
 
-	/*
-	 * 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;
+	if (format == 0x3) {
+		/* Inverted LRCK is not available in DSP mode. */
+		if (value & BIT(0))
+			return -EINVAL;
+
+		/* Instead, the bit selects between DSP A/B formats. */
+		value |= invert;
+	} else {
+		/*
+		 * 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);
+			   SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
+			   value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);
 
 	return 0;
 }
 
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 12/25] ASoC: sun8i-codec: Program the correct word size
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

The hardware supports 8 to 24-bit word sizes on all three of its DAIs,
only one of which is connected to the CPU DAI. Program the word size
based on the actual selected format, instead of relying on limitations
in another driver (which, incedentally, has patches pending to remove
that limitation).

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 506420fb355c..e7f01a4b4001 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -43,17 +43,16 @@
 #define SUN8I_SYS_SR_CTRL_AIF1_FS			12
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF1CLK_CTRL				0x040
 #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
 #define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
 #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_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
@@ -317,26 +316,40 @@ static int sun8i_codec_get_lrck_div(unsigned int channels,
 	return ilog2(div) - 4;
 }
 
 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_dai_get_drvdata(dai);
-	int sample_rate, lrck_div;
+	int lrck_div, sample_rate, word_size;
 	u8 bclk_div;
 
-	/*
-	 * The CPU DAI handles only a sample of 16 bits. Configure the
-	 * codec to handle this type of sample resolution.
-	 */
+	/* word size */
+	switch (params_width(params)) {
+	case 8:
+		word_size = 0x0;
+		break;
+	case 16:
+		word_size = 0x1;
+		break;
+	case 20:
+		word_size = 0x2;
+		break;
+	case 24:
+		word_size = 0x3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
-			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
+			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
 
 	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
 	lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
 					    params_physical_width(params));
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 12/25] ASoC: sun8i-codec: Program the correct word size
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The hardware supports 8 to 24-bit word sizes on all three of its DAIs,
only one of which is connected to the CPU DAI. Program the word size
based on the actual selected format, instead of relying on limitations
in another driver (which, incedentally, has patches pending to remove
that limitation).

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 506420fb355c..e7f01a4b4001 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -43,17 +43,16 @@
 #define SUN8I_SYS_SR_CTRL_AIF1_FS			12
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF1CLK_CTRL				0x040
 #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
 #define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
 #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_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
@@ -317,26 +316,40 @@ static int sun8i_codec_get_lrck_div(unsigned int channels,
 	return ilog2(div) - 4;
 }
 
 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_dai_get_drvdata(dai);
-	int sample_rate, lrck_div;
+	int lrck_div, sample_rate, word_size;
 	u8 bclk_div;
 
-	/*
-	 * The CPU DAI handles only a sample of 16 bits. Configure the
-	 * codec to handle this type of sample resolution.
-	 */
+	/* word size */
+	switch (params_width(params)) {
+	case 8:
+		word_size = 0x0;
+		break;
+	case 16:
+		word_size = 0x1;
+		break;
+	case 20:
+		word_size = 0x2;
+		break;
+	case 24:
+		word_size = 0x3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
-			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
+			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
 
 	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
 	lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
 					    params_physical_width(params));
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 12/25] ASoC: sun8i-codec: Program the correct word size
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The hardware supports 8 to 24-bit word sizes on all three of its DAIs,
only one of which is connected to the CPU DAI. Program the word size
based on the actual selected format, instead of relying on limitations
in another driver (which, incedentally, has patches pending to remove
that limitation).

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 506420fb355c..e7f01a4b4001 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -43,17 +43,16 @@
 #define SUN8I_SYS_SR_CTRL_AIF1_FS			12
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF1CLK_CTRL				0x040
 #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
 #define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
 #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_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
@@ -317,26 +316,40 @@ static int sun8i_codec_get_lrck_div(unsigned int channels,
 	return ilog2(div) - 4;
 }
 
 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_dai_get_drvdata(dai);
-	int sample_rate, lrck_div;
+	int lrck_div, sample_rate, word_size;
 	u8 bclk_div;
 
-	/*
-	 * The CPU DAI handles only a sample of 16 bits. Configure the
-	 * codec to handle this type of sample resolution.
-	 */
+	/* word size */
+	switch (params_width(params)) {
+	case 8:
+		word_size = 0x0;
+		break;
+	case 16:
+		word_size = 0x1;
+		break;
+	case 20:
+		word_size = 0x2;
+		break;
+	case 24:
+		word_size = 0x3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
-			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
+			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
 
 	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
 	lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
 					    params_physical_width(params));
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 13/25] ASoC: sun8i-codec: Round up the LRCK divisor
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

The codec supports only power-of-two BCLK/LRCK divisors. If either the
slot width or the number of slots is not a power of two, the LRCK
divisor must be rounded up to provide enough space. To do that, use
order_base_2 (instead of ilog2, which rounds down).

Since the rounded divisor is also needed for setting the SYSCLK/BCLK
divisor, return the order base 2 instead of fully calculating the
hardware register encoding.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index e7f01a4b4001..779853d023fe 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -300,33 +300,35 @@ static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
 			best_diff = diff;
 			best_val = bdiv->val;
 		}
 	}
 
 	return best_val;
 }
 
-static int sun8i_codec_get_lrck_div(unsigned int channels,
-				    unsigned int word_size)
+static int sun8i_codec_get_lrck_div_order(unsigned int slots,
+					  unsigned int slot_width)
 {
-	unsigned int div = word_size * channels;
+	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
 		return -EINVAL;
 
-	return ilog2(div) - 4;
+	return order_base_2(div);
 }
 
 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_dai_get_drvdata(dai);
-	int lrck_div, sample_rate, word_size;
+	unsigned int slots = params_channels(params);
+	unsigned int slot_width = params_width(params);
+	int lrck_div_order, sample_rate, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
@@ -346,24 +348,24 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
 			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
 
 	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
-	lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
-					    params_physical_width(params));
-	if (lrck_div < 0)
-		return lrck_div;
+	/* LRCK divider (BCLK/LRCK ratio) */
+	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
+	if (lrck_div_order < 0)
+		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
-			   lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
+			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	sample_rate = sun8i_codec_get_hw_rate(params);
 	if (sample_rate < 0)
 		return sample_rate;
 
 	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 13/25] ASoC: sun8i-codec: Round up the LRCK divisor
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The codec supports only power-of-two BCLK/LRCK divisors. If either the
slot width or the number of slots is not a power of two, the LRCK
divisor must be rounded up to provide enough space. To do that, use
order_base_2 (instead of ilog2, which rounds down).

Since the rounded divisor is also needed for setting the SYSCLK/BCLK
divisor, return the order base 2 instead of fully calculating the
hardware register encoding.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index e7f01a4b4001..779853d023fe 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -300,33 +300,35 @@ static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
 			best_diff = diff;
 			best_val = bdiv->val;
 		}
 	}
 
 	return best_val;
 }
 
-static int sun8i_codec_get_lrck_div(unsigned int channels,
-				    unsigned int word_size)
+static int sun8i_codec_get_lrck_div_order(unsigned int slots,
+					  unsigned int slot_width)
 {
-	unsigned int div = word_size * channels;
+	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
 		return -EINVAL;
 
-	return ilog2(div) - 4;
+	return order_base_2(div);
 }
 
 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_dai_get_drvdata(dai);
-	int lrck_div, sample_rate, word_size;
+	unsigned int slots = params_channels(params);
+	unsigned int slot_width = params_width(params);
+	int lrck_div_order, sample_rate, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
@@ -346,24 +348,24 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
 			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
 
 	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
-	lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
-					    params_physical_width(params));
-	if (lrck_div < 0)
-		return lrck_div;
+	/* LRCK divider (BCLK/LRCK ratio) */
+	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
+	if (lrck_div_order < 0)
+		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
-			   lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
+			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	sample_rate = sun8i_codec_get_hw_rate(params);
 	if (sample_rate < 0)
 		return sample_rate;
 
 	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 13/25] ASoC: sun8i-codec: Round up the LRCK divisor
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The codec supports only power-of-two BCLK/LRCK divisors. If either the
slot width or the number of slots is not a power of two, the LRCK
divisor must be rounded up to provide enough space. To do that, use
order_base_2 (instead of ilog2, which rounds down).

Since the rounded divisor is also needed for setting the SYSCLK/BCLK
divisor, return the order base 2 instead of fully calculating the
hardware register encoding.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index e7f01a4b4001..779853d023fe 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -300,33 +300,35 @@ static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
 			best_diff = diff;
 			best_val = bdiv->val;
 		}
 	}
 
 	return best_val;
 }
 
-static int sun8i_codec_get_lrck_div(unsigned int channels,
-				    unsigned int word_size)
+static int sun8i_codec_get_lrck_div_order(unsigned int slots,
+					  unsigned int slot_width)
 {
-	unsigned int div = word_size * channels;
+	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
 		return -EINVAL;
 
-	return ilog2(div) - 4;
+	return order_base_2(div);
 }
 
 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_dai_get_drvdata(dai);
-	int lrck_div, sample_rate, word_size;
+	unsigned int slots = params_channels(params);
+	unsigned int slot_width = params_width(params);
+	int lrck_div_order, sample_rate, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
@@ -346,24 +348,24 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
 			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
 
 	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
-	lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
-					    params_physical_width(params));
-	if (lrck_div < 0)
-		return lrck_div;
+	/* LRCK divider (BCLK/LRCK ratio) */
+	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
+	if (lrck_div_order < 0)
+		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
-			   lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
+			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	sample_rate = sun8i_codec_get_hw_rate(params);
 	if (sample_rate < 0)
 		return sample_rate;
 
 	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 14/25] ASoC: sun8i-codec: Correct the BCLK divisor calculation
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

Previously, the BCLK divisor calculation assumed a power-of-two slot
width and exactly two slots. In order to support the TDM slot binding
and 20/24-bit word sizes, those assumptions must be removed.

Due to hardware limitations, the BCLK/LRCK ratio is not as simple as
"slot_width * slots". However, the correct value is already calculated
elsewhere in this function, since it must also be programmed into the
hardware. Reuse that value to calculate the correct SYSCLK/BCLK divisor.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 779853d023fe..78feed37aa42 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -279,21 +279,21 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 48,	.val = 9 },
 	{ .div = 64,	.val = 10 },
 	{ .div = 96,	.val = 11 },
 	{ .div = 128,	.val = 12 },
 	{ .div = 192,	.val = 13 },
 };
 
 static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
-				   unsigned int rate,
-				   unsigned int word_size)
+				   unsigned int lrck_div_order,
+				   unsigned int sample_rate)
 {
 	unsigned long clk_rate = clk_get_rate(scodec->clk_module);
-	unsigned int div = clk_rate / rate / word_size / 2;
+	unsigned int div = clk_rate / sample_rate >> lrck_div_order;
 	unsigned int best_val = 0, best_diff = ~0;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
 		unsigned int diff = abs(bdiv->div - div);
 
 		if (diff < best_diff) {
@@ -343,30 +343,31 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
 			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
 
-	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
-			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
-
 	/* LRCK divider (BCLK/LRCK ratio) */
 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
+	/* BCLK divider (SYSCLK/BCLK ratio) */
+	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, params_rate(params));
+	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
+			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
+
 	sample_rate = sun8i_codec_get_hw_rate(params);
 	if (sample_rate < 0)
 		return sample_rate;
 
 	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 14/25] ASoC: sun8i-codec: Correct the BCLK divisor calculation
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Previously, the BCLK divisor calculation assumed a power-of-two slot
width and exactly two slots. In order to support the TDM slot binding
and 20/24-bit word sizes, those assumptions must be removed.

Due to hardware limitations, the BCLK/LRCK ratio is not as simple as
"slot_width * slots". However, the correct value is already calculated
elsewhere in this function, since it must also be programmed into the
hardware. Reuse that value to calculate the correct SYSCLK/BCLK divisor.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 779853d023fe..78feed37aa42 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -279,21 +279,21 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 48,	.val = 9 },
 	{ .div = 64,	.val = 10 },
 	{ .div = 96,	.val = 11 },
 	{ .div = 128,	.val = 12 },
 	{ .div = 192,	.val = 13 },
 };
 
 static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
-				   unsigned int rate,
-				   unsigned int word_size)
+				   unsigned int lrck_div_order,
+				   unsigned int sample_rate)
 {
 	unsigned long clk_rate = clk_get_rate(scodec->clk_module);
-	unsigned int div = clk_rate / rate / word_size / 2;
+	unsigned int div = clk_rate / sample_rate >> lrck_div_order;
 	unsigned int best_val = 0, best_diff = ~0;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
 		unsigned int diff = abs(bdiv->div - div);
 
 		if (diff < best_diff) {
@@ -343,30 +343,31 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
 			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
 
-	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
-			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
-
 	/* LRCK divider (BCLK/LRCK ratio) */
 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
+	/* BCLK divider (SYSCLK/BCLK ratio) */
+	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, params_rate(params));
+	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
+			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
+
 	sample_rate = sun8i_codec_get_hw_rate(params);
 	if (sample_rate < 0)
 		return sample_rate;
 
 	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 14/25] ASoC: sun8i-codec: Correct the BCLK divisor calculation
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Previously, the BCLK divisor calculation assumed a power-of-two slot
width and exactly two slots. In order to support the TDM slot binding
and 20/24-bit word sizes, those assumptions must be removed.

Due to hardware limitations, the BCLK/LRCK ratio is not as simple as
"slot_width * slots". However, the correct value is already calculated
elsewhere in this function, since it must also be programmed into the
hardware. Reuse that value to calculate the correct SYSCLK/BCLK divisor.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 779853d023fe..78feed37aa42 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -279,21 +279,21 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 48,	.val = 9 },
 	{ .div = 64,	.val = 10 },
 	{ .div = 96,	.val = 11 },
 	{ .div = 128,	.val = 12 },
 	{ .div = 192,	.val = 13 },
 };
 
 static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
-				   unsigned int rate,
-				   unsigned int word_size)
+				   unsigned int lrck_div_order,
+				   unsigned int sample_rate)
 {
 	unsigned long clk_rate = clk_get_rate(scodec->clk_module);
-	unsigned int div = clk_rate / rate / word_size / 2;
+	unsigned int div = clk_rate / sample_rate >> lrck_div_order;
 	unsigned int best_val = 0, best_diff = ~0;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
 		unsigned int diff = abs(bdiv->div - div);
 
 		if (diff < best_diff) {
@@ -343,30 +343,31 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
 			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
 
-	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
-			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
-
 	/* LRCK divider (BCLK/LRCK ratio) */
 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
+	/* BCLK divider (SYSCLK/BCLK ratio) */
+	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, params_rate(params));
+	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
+			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
+
 	sample_rate = sun8i_codec_get_hw_rate(params);
 	if (sample_rate < 0)
 		return sample_rate;
 
 	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 15/25] ASoC: sun8i-codec: Support the TDM slot binding
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

Now that BCLK and LRCK rate calculations can handle any
hardware-supported slot width and number of slots, enable
support for overriding these parameters from the device tree.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 78feed37aa42..0a53dc0c34d0 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -94,25 +94,31 @@
 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK	GENMASK(5, 4)
 #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK	GENMASK(3, 2)
 
 enum {
 	AIF1,
 	NAIFS
 };
 
+struct sun8i_codec_aif {
+	unsigned int	slots;
+	unsigned int	slot_width;
+};
+
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
 	const struct sun8i_codec_quirks	*quirks;
+	struct sun8i_codec_aif		aifs[NAIFS];
 };
 
 static int sun8i_codec_runtime_resume(struct device *dev)
 {
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
 	int ret;
 
 	regcache_cache_only(scodec->regmap, false);
@@ -256,16 +262,32 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
 			   value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);
 
 	return 0;
 }
 
+static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int slots, int slot_width)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+
+	if (slot_width && !is_power_of_2(slot_width))
+		return -EINVAL;
+
+	aif->slots = slots;
+	aif->slot_width = slot_width;
+
+	return 0;
+}
+
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
 
 static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 1,	.val = 0 },
 	{ .div = 2,	.val = 1 },
@@ -316,18 +338,19 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 	return order_base_2(div);
 }
 
 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_dai_get_drvdata(dai);
-	unsigned int slots = params_channels(params);
-	unsigned int slot_width = params_width(params);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+	unsigned int slots = aif->slots ?: params_channels(params);
+	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	int lrck_div_order, sample_rate, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
@@ -371,16 +394,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
+	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
 	.hw_params	= sun8i_codec_hw_params,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 	{
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 15/25] ASoC: sun8i-codec: Support the TDM slot binding
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Now that BCLK and LRCK rate calculations can handle any
hardware-supported slot width and number of slots, enable
support for overriding these parameters from the device tree.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 78feed37aa42..0a53dc0c34d0 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -94,25 +94,31 @@
 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK	GENMASK(5, 4)
 #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK	GENMASK(3, 2)
 
 enum {
 	AIF1,
 	NAIFS
 };
 
+struct sun8i_codec_aif {
+	unsigned int	slots;
+	unsigned int	slot_width;
+};
+
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
 	const struct sun8i_codec_quirks	*quirks;
+	struct sun8i_codec_aif		aifs[NAIFS];
 };
 
 static int sun8i_codec_runtime_resume(struct device *dev)
 {
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
 	int ret;
 
 	regcache_cache_only(scodec->regmap, false);
@@ -256,16 +262,32 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
 			   value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);
 
 	return 0;
 }
 
+static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int slots, int slot_width)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+
+	if (slot_width && !is_power_of_2(slot_width))
+		return -EINVAL;
+
+	aif->slots = slots;
+	aif->slot_width = slot_width;
+
+	return 0;
+}
+
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
 
 static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 1,	.val = 0 },
 	{ .div = 2,	.val = 1 },
@@ -316,18 +338,19 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 	return order_base_2(div);
 }
 
 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_dai_get_drvdata(dai);
-	unsigned int slots = params_channels(params);
-	unsigned int slot_width = params_width(params);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+	unsigned int slots = aif->slots ?: params_channels(params);
+	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	int lrck_div_order, sample_rate, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
@@ -371,16 +394,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
+	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
 	.hw_params	= sun8i_codec_hw_params,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 	{
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 15/25] ASoC: sun8i-codec: Support the TDM slot binding
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Now that BCLK and LRCK rate calculations can handle any
hardware-supported slot width and number of slots, enable
support for overriding these parameters from the device tree.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 78feed37aa42..0a53dc0c34d0 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -94,25 +94,31 @@
 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK	GENMASK(5, 4)
 #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK	GENMASK(3, 2)
 
 enum {
 	AIF1,
 	NAIFS
 };
 
+struct sun8i_codec_aif {
+	unsigned int	slots;
+	unsigned int	slot_width;
+};
+
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
 	const struct sun8i_codec_quirks	*quirks;
+	struct sun8i_codec_aif		aifs[NAIFS];
 };
 
 static int sun8i_codec_runtime_resume(struct device *dev)
 {
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
 	int ret;
 
 	regcache_cache_only(scodec->regmap, false);
@@ -256,16 +262,32 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
 			   value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);
 
 	return 0;
 }
 
+static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int slots, int slot_width)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+
+	if (slot_width && !is_power_of_2(slot_width))
+		return -EINVAL;
+
+	aif->slots = slots;
+	aif->slot_width = slot_width;
+
+	return 0;
+}
+
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
 
 static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 1,	.val = 0 },
 	{ .div = 2,	.val = 1 },
@@ -316,18 +338,19 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 	return order_base_2(div);
 }
 
 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_dai_get_drvdata(dai);
-	unsigned int slots = params_channels(params);
-	unsigned int slot_width = params_width(params);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+	unsigned int slots = aif->slots ?: params_channels(params);
+	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	int lrck_div_order, sample_rate, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
@@ -371,16 +394,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
+	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
 	.hw_params	= sun8i_codec_hw_params,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 	{
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 16/25] ASoC: sun8i-codec: Enforce symmetric DAI parameters
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

The AIFs have a single register controlling DAI parameters in both
directions, including BCLK/LRCK divisor word size. The DAIs produce only
noise or silence if any of these parameters is wrong. Therefore, we need
to enforce symmetry for these parameters, so starting a new substream
will not break an existing substream.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 0a53dc0c34d0..f21274530a0e 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -420,16 +420,19 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 		/* playback capabilities */
 		.playback = {
 			.stream_name	= "AIF1 Playback",
 			.channels_min	= 1,
 			.channels_max	= 2,
 			.rates		= SNDRV_PCM_RATE_8000_192000,
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
 	},
 };
 
 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,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 16/25] ASoC: sun8i-codec: Enforce symmetric DAI parameters
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The AIFs have a single register controlling DAI parameters in both
directions, including BCLK/LRCK divisor word size. The DAIs produce only
noise or silence if any of these parameters is wrong. Therefore, we need
to enforce symmetry for these parameters, so starting a new substream
will not break an existing substream.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 0a53dc0c34d0..f21274530a0e 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -420,16 +420,19 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 		/* playback capabilities */
 		.playback = {
 			.stream_name	= "AIF1 Playback",
 			.channels_min	= 1,
 			.channels_max	= 2,
 			.rates		= SNDRV_PCM_RATE_8000_192000,
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
 	},
 };
 
 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,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 16/25] ASoC: sun8i-codec: Enforce symmetric DAI parameters
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The AIFs have a single register controlling DAI parameters in both
directions, including BCLK/LRCK divisor word size. The DAIs produce only
noise or silence if any of these parameters is wrong. Therefore, we need
to enforce symmetry for these parameters, so starting a new substream
will not break an existing substream.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 0a53dc0c34d0..f21274530a0e 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -420,16 +420,19 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 		/* playback capabilities */
 		.playback = {
 			.stream_name	= "AIF1 Playback",
 			.channels_min	= 1,
 			.channels_max	= 2,
 			.rates		= SNDRV_PCM_RATE_8000_192000,
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
 	},
 };
 
 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,
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 17/25] ASoC: sun8i-codec: Enable all supported sample rates
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

The system sample rate programmed into the hardware is really a clock
divider from SYSCLK to the ADC and DAC. Since we support two SYSCLK
frequencies, we can use all sample rates corresponding to one of those
frequencies divided by any available divisor.

This commit enables support for those sample rates. It also stops
advertising support for a 64 kHz sample rate, which is not supported.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index f21274530a0e..f4b2a7cc9810 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -89,16 +89,23 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
+#define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
+				 SNDRV_PCM_RATE_88200     |\
+				 SNDRV_PCM_RATE_96000     |\
+				 SNDRV_PCM_RATE_176400    |\
+				 SNDRV_PCM_RATE_192000    |\
+				 SNDRV_PCM_RATE_KNOT)
+
 enum {
 	AIF1,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
 	unsigned int	slots;
 	unsigned int	slot_width;
@@ -142,37 +149,41 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
 	return 0;
 }
 
 static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 {
 	unsigned int rate = params_rate(params);
 
 	switch (rate) {
-	case 8000:
 	case 7350:
+	case 8000:
 		return 0x0;
 	case 11025:
 		return 0x1;
 	case 12000:
 		return 0x2;
+	case 14700:
 	case 16000:
 		return 0x3;
 	case 22050:
 		return 0x4;
 	case 24000:
 		return 0x5;
+	case 29400:
 	case 32000:
 		return 0x6;
 	case 44100:
 		return 0x7;
 	case 48000:
 		return 0x8;
+	case 88200:
 	case 96000:
 		return 0x9;
+	case 176400:
 	case 192000:
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -408,26 +419,26 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
 		/* capture capabilities */
 		.capture = {
 			.stream_name	= "AIF1 Capture",
 			.channels_min	= 1,
 			.channels_max	= 2,
-			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 			.sig_bits	= 24,
 		},
 		/* playback capabilities */
 		.playback = {
 			.stream_name	= "AIF1 Playback",
 			.channels_min	= 1,
 			.channels_max	= 2,
-			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
 };
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 17/25] ASoC: sun8i-codec: Enable all supported sample rates
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The system sample rate programmed into the hardware is really a clock
divider from SYSCLK to the ADC and DAC. Since we support two SYSCLK
frequencies, we can use all sample rates corresponding to one of those
frequencies divided by any available divisor.

This commit enables support for those sample rates. It also stops
advertising support for a 64 kHz sample rate, which is not supported.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index f21274530a0e..f4b2a7cc9810 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -89,16 +89,23 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
+#define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
+				 SNDRV_PCM_RATE_88200     |\
+				 SNDRV_PCM_RATE_96000     |\
+				 SNDRV_PCM_RATE_176400    |\
+				 SNDRV_PCM_RATE_192000    |\
+				 SNDRV_PCM_RATE_KNOT)
+
 enum {
 	AIF1,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
 	unsigned int	slots;
 	unsigned int	slot_width;
@@ -142,37 +149,41 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
 	return 0;
 }
 
 static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 {
 	unsigned int rate = params_rate(params);
 
 	switch (rate) {
-	case 8000:
 	case 7350:
+	case 8000:
 		return 0x0;
 	case 11025:
 		return 0x1;
 	case 12000:
 		return 0x2;
+	case 14700:
 	case 16000:
 		return 0x3;
 	case 22050:
 		return 0x4;
 	case 24000:
 		return 0x5;
+	case 29400:
 	case 32000:
 		return 0x6;
 	case 44100:
 		return 0x7;
 	case 48000:
 		return 0x8;
+	case 88200:
 	case 96000:
 		return 0x9;
+	case 176400:
 	case 192000:
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -408,26 +419,26 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
 		/* capture capabilities */
 		.capture = {
 			.stream_name	= "AIF1 Capture",
 			.channels_min	= 1,
 			.channels_max	= 2,
-			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 			.sig_bits	= 24,
 		},
 		/* playback capabilities */
 		.playback = {
 			.stream_name	= "AIF1 Playback",
 			.channels_min	= 1,
 			.channels_max	= 2,
-			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
 };
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 17/25] ASoC: sun8i-codec: Enable all supported sample rates
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The system sample rate programmed into the hardware is really a clock
divider from SYSCLK to the ADC and DAC. Since we support two SYSCLK
frequencies, we can use all sample rates corresponding to one of those
frequencies divided by any available divisor.

This commit enables support for those sample rates. It also stops
advertising support for a 64 kHz sample rate, which is not supported.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index f21274530a0e..f4b2a7cc9810 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -89,16 +89,23 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
+#define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
+				 SNDRV_PCM_RATE_88200     |\
+				 SNDRV_PCM_RATE_96000     |\
+				 SNDRV_PCM_RATE_176400    |\
+				 SNDRV_PCM_RATE_192000    |\
+				 SNDRV_PCM_RATE_KNOT)
+
 enum {
 	AIF1,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
 	unsigned int	slots;
 	unsigned int	slot_width;
@@ -142,37 +149,41 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
 	return 0;
 }
 
 static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 {
 	unsigned int rate = params_rate(params);
 
 	switch (rate) {
-	case 8000:
 	case 7350:
+	case 8000:
 		return 0x0;
 	case 11025:
 		return 0x1;
 	case 12000:
 		return 0x2;
+	case 14700:
 	case 16000:
 		return 0x3;
 	case 22050:
 		return 0x4;
 	case 24000:
 		return 0x5;
+	case 29400:
 	case 32000:
 		return 0x6;
 	case 44100:
 		return 0x7;
 	case 48000:
 		return 0x8;
+	case 88200:
 	case 96000:
 		return 0x9;
+	case 176400:
 	case 192000:
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -408,26 +419,26 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
 		/* capture capabilities */
 		.capture = {
 			.stream_name	= "AIF1 Capture",
 			.channels_min	= 1,
 			.channels_max	= 2,
-			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 			.sig_bits	= 24,
 		},
 		/* playback capabilities */
 		.playback = {
 			.stream_name	= "AIF1 Playback",
 			.channels_min	= 1,
 			.channels_max	= 2,
-			.rates		= SNDRV_PCM_RATE_8000_192000,
+			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
 };
 
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 18/25] ASoC: sun8i-codec: Automatically set the system sample rate
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

The sun8i codec has three clock/sample rate domains:
 - The AIF1 domain, with a sample rate equal to AIF1 LRCK
 - The AIF2 domain, with a sample rate equal to AIF2 LRCK
 - The SYSCLK domain, containing the ADC, DAC, and effects (AGC/DRC),
   with a sample rate given by a divisor from SYSCLK. The divisor is
   controlled by the AIF1_FS or AIF2_FS field in SYS_SR_CTRL, depending
   on if SYSCLK's source is AIF1CLK or AIF2CLK, respectively. The exact
   sample rate depends on if SYSCLK is running at 22.6 MHz or 24.6 MHz.

When an AIF (currently only AIF1) is active, the ADC and DAC should run
at that sample rate to avoid artifacting. Sample rate conversion is only
available when multiple AIFs are active and are routed to each other;
this means the sample rate conversion hardware usually cannot be used.

Only attach the event hook to the channel 0 AIF widgets, since we only
need one event when a DAI stream starts or stops. Channel 0 is always
brought up with a DAI stream, regardless of the number of channels in
the stream.

The ADC and DAC (along with their effects blocks) can be used even if
no AIFs are in use. In that case, we should select an appropriate sample
rate divisor, instead of keeping the last-used AIF sample rate.
44.1/48 kHz was chosen to balance audio quality and power consumption.

Since the sample rate is tied to active AIF paths, disabling pmdown_time
allows switching to the optimal sample rate immediately, instead of
after a 5 second delay.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index f4b2a7cc9810..43b4319e3d84 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -89,31 +89,36 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
+#define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
+
 #define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
 				 SNDRV_PCM_RATE_88200     |\
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
 	AIF1,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
+	unsigned int	sample_rate;
 	unsigned int	slots;
 	unsigned int	slot_width;
+	unsigned int	active_streams	: 2;
+	unsigned int	open_streams	: 2;
 };
 
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
@@ -144,21 +149,19 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
 
 	regcache_cache_only(scodec->regmap, true);
 	regcache_mark_dirty(scodec->regmap);
 
 	return 0;
 }
 
-static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
+static int sun8i_codec_get_hw_rate(unsigned int sample_rate)
 {
-	unsigned int rate = params_rate(params);
-
-	switch (rate) {
+	switch (sample_rate) {
 	case 7350:
 	case 8000:
 		return 0x0;
 	case 11025:
 		return 0x1;
 	case 12000:
 		return 0x2;
 	case 14700:
@@ -181,16 +184,43 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	case 176400:
 	case 192000:
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
+static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
+{
+	unsigned int max_rate = 0;
+	int hw_rate, i;
+
+	for (i = AIF1; i < NAIFS; ++i) {
+		struct sun8i_codec_aif *aif = &scodec->aifs[i];
+
+		if (aif->active_streams)
+			max_rate = max(max_rate, aif->sample_rate);
+	}
+
+	/* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
+	if (!max_rate)
+		max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
+
+	hw_rate = sun8i_codec_get_hw_rate(max_rate);
+	if (hw_rate < 0)
+		return hw_rate;
+
+	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
+			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
+			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+
+	return 0;
+}
+
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	u32 format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
@@ -350,19 +380,20 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 }
 
 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_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
-	int lrck_div_order, sample_rate, word_size;
+	int lrck_div_order, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
@@ -387,36 +418,48 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
-	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, params_rate(params));
+	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, sample_rate);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
-	sample_rate = sun8i_codec_get_hw_rate(params);
-	if (sample_rate < 0)
-		return sample_rate;
+	aif->sample_rate = sample_rate;
+	aif->open_streams |= BIT(substream->stream);
 
-	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
-			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
-			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+	return sun8i_codec_update_sample_rate(scodec);
+}
+
+static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+
+	if (aif->open_streams != BIT(substream->stream))
+		goto done;
 
+	aif->sample_rate = 0;
+
+done:
+	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
 	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
 	.hw_params	= sun8i_codec_hw_params,
+	.hw_free	= sun8i_codec_hw_free,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 	{
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
 		/* capture capabilities */
@@ -437,16 +480,32 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
 };
 
+static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
+	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
+	int stream = w->id == snd_soc_dapm_aif_out;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		aif->active_streams |= BIT(stream);
+	else
+		aif->active_streams &= ~BIT(stream);
+
+	return sun8i_codec_update_sample_rate(scodec);
+}
+
 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,
@@ -539,19 +598,21 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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", "AIF1 Capture", 0,
-			     SUN8I_AIF1_ADCDAT_CTRL,
-			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
+	SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
+			       SUN8I_AIF1_ADCDAT_CTRL,
+			       SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 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,
@@ -565,19 +626,21 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* 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", "AIF1 Playback", 0,
-			    SUN8I_AIF1_DACDAT_CTRL,
-			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
+	SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
+			      SUN8I_AIF1_DACDAT_CTRL,
+			      SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_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),
 
@@ -722,27 +785,29 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 			   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);
 
+	/* Program the default sample rate. */
+	sun8i_codec_update_sample_rate(scodec);
+
 	return 0;
 }
 
 static const struct snd_soc_component_driver sun8i_soc_component = {
 	.dapm_widgets		= sun8i_codec_dapm_widgets,
 	.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,
 	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config sun8i_codec_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
 	.val_bits	= 32,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 18/25] ASoC: sun8i-codec: Automatically set the system sample rate
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The sun8i codec has three clock/sample rate domains:
 - The AIF1 domain, with a sample rate equal to AIF1 LRCK
 - The AIF2 domain, with a sample rate equal to AIF2 LRCK
 - The SYSCLK domain, containing the ADC, DAC, and effects (AGC/DRC),
   with a sample rate given by a divisor from SYSCLK. The divisor is
   controlled by the AIF1_FS or AIF2_FS field in SYS_SR_CTRL, depending
   on if SYSCLK's source is AIF1CLK or AIF2CLK, respectively. The exact
   sample rate depends on if SYSCLK is running at 22.6 MHz or 24.6 MHz.

When an AIF (currently only AIF1) is active, the ADC and DAC should run
at that sample rate to avoid artifacting. Sample rate conversion is only
available when multiple AIFs are active and are routed to each other;
this means the sample rate conversion hardware usually cannot be used.

Only attach the event hook to the channel 0 AIF widgets, since we only
need one event when a DAI stream starts or stops. Channel 0 is always
brought up with a DAI stream, regardless of the number of channels in
the stream.

The ADC and DAC (along with their effects blocks) can be used even if
no AIFs are in use. In that case, we should select an appropriate sample
rate divisor, instead of keeping the last-used AIF sample rate.
44.1/48 kHz was chosen to balance audio quality and power consumption.

Since the sample rate is tied to active AIF paths, disabling pmdown_time
allows switching to the optimal sample rate immediately, instead of
after a 5 second delay.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index f4b2a7cc9810..43b4319e3d84 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -89,31 +89,36 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
+#define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
+
 #define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
 				 SNDRV_PCM_RATE_88200     |\
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
 	AIF1,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
+	unsigned int	sample_rate;
 	unsigned int	slots;
 	unsigned int	slot_width;
+	unsigned int	active_streams	: 2;
+	unsigned int	open_streams	: 2;
 };
 
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
@@ -144,21 +149,19 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
 
 	regcache_cache_only(scodec->regmap, true);
 	regcache_mark_dirty(scodec->regmap);
 
 	return 0;
 }
 
-static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
+static int sun8i_codec_get_hw_rate(unsigned int sample_rate)
 {
-	unsigned int rate = params_rate(params);
-
-	switch (rate) {
+	switch (sample_rate) {
 	case 7350:
 	case 8000:
 		return 0x0;
 	case 11025:
 		return 0x1;
 	case 12000:
 		return 0x2;
 	case 14700:
@@ -181,16 +184,43 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	case 176400:
 	case 192000:
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
+static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
+{
+	unsigned int max_rate = 0;
+	int hw_rate, i;
+
+	for (i = AIF1; i < NAIFS; ++i) {
+		struct sun8i_codec_aif *aif = &scodec->aifs[i];
+
+		if (aif->active_streams)
+			max_rate = max(max_rate, aif->sample_rate);
+	}
+
+	/* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
+	if (!max_rate)
+		max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
+
+	hw_rate = sun8i_codec_get_hw_rate(max_rate);
+	if (hw_rate < 0)
+		return hw_rate;
+
+	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
+			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
+			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+
+	return 0;
+}
+
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	u32 format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
@@ -350,19 +380,20 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 }
 
 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_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
-	int lrck_div_order, sample_rate, word_size;
+	int lrck_div_order, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
@@ -387,36 +418,48 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
-	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, params_rate(params));
+	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, sample_rate);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
-	sample_rate = sun8i_codec_get_hw_rate(params);
-	if (sample_rate < 0)
-		return sample_rate;
+	aif->sample_rate = sample_rate;
+	aif->open_streams |= BIT(substream->stream);
 
-	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
-			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
-			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+	return sun8i_codec_update_sample_rate(scodec);
+}
+
+static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+
+	if (aif->open_streams != BIT(substream->stream))
+		goto done;
 
+	aif->sample_rate = 0;
+
+done:
+	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
 	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
 	.hw_params	= sun8i_codec_hw_params,
+	.hw_free	= sun8i_codec_hw_free,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 	{
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
 		/* capture capabilities */
@@ -437,16 +480,32 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
 };
 
+static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
+	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
+	int stream = w->id == snd_soc_dapm_aif_out;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		aif->active_streams |= BIT(stream);
+	else
+		aif->active_streams &= ~BIT(stream);
+
+	return sun8i_codec_update_sample_rate(scodec);
+}
+
 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,
@@ -539,19 +598,21 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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", "AIF1 Capture", 0,
-			     SUN8I_AIF1_ADCDAT_CTRL,
-			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
+	SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
+			       SUN8I_AIF1_ADCDAT_CTRL,
+			       SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 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,
@@ -565,19 +626,21 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* 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", "AIF1 Playback", 0,
-			    SUN8I_AIF1_DACDAT_CTRL,
-			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
+	SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
+			      SUN8I_AIF1_DACDAT_CTRL,
+			      SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_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),
 
@@ -722,27 +785,29 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 			   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);
 
+	/* Program the default sample rate. */
+	sun8i_codec_update_sample_rate(scodec);
+
 	return 0;
 }
 
 static const struct snd_soc_component_driver sun8i_soc_component = {
 	.dapm_widgets		= sun8i_codec_dapm_widgets,
 	.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,
 	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config sun8i_codec_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
 	.val_bits	= 32,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 18/25] ASoC: sun8i-codec: Automatically set the system sample rate
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The sun8i codec has three clock/sample rate domains:
 - The AIF1 domain, with a sample rate equal to AIF1 LRCK
 - The AIF2 domain, with a sample rate equal to AIF2 LRCK
 - The SYSCLK domain, containing the ADC, DAC, and effects (AGC/DRC),
   with a sample rate given by a divisor from SYSCLK. The divisor is
   controlled by the AIF1_FS or AIF2_FS field in SYS_SR_CTRL, depending
   on if SYSCLK's source is AIF1CLK or AIF2CLK, respectively. The exact
   sample rate depends on if SYSCLK is running at 22.6 MHz or 24.6 MHz.

When an AIF (currently only AIF1) is active, the ADC and DAC should run
at that sample rate to avoid artifacting. Sample rate conversion is only
available when multiple AIFs are active and are routed to each other;
this means the sample rate conversion hardware usually cannot be used.

Only attach the event hook to the channel 0 AIF widgets, since we only
need one event when a DAI stream starts or stops. Channel 0 is always
brought up with a DAI stream, regardless of the number of channels in
the stream.

The ADC and DAC (along with their effects blocks) can be used even if
no AIFs are in use. In that case, we should select an appropriate sample
rate divisor, instead of keeping the last-used AIF sample rate.
44.1/48 kHz was chosen to balance audio quality and power consumption.

Since the sample rate is tied to active AIF paths, disabling pmdown_time
allows switching to the optimal sample rate immediately, instead of
after a 5 second delay.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index f4b2a7cc9810..43b4319e3d84 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -89,31 +89,36 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
+#define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
+
 #define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
 				 SNDRV_PCM_RATE_88200     |\
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
 	AIF1,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
+	unsigned int	sample_rate;
 	unsigned int	slots;
 	unsigned int	slot_width;
+	unsigned int	active_streams	: 2;
+	unsigned int	open_streams	: 2;
 };
 
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
@@ -144,21 +149,19 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
 
 	regcache_cache_only(scodec->regmap, true);
 	regcache_mark_dirty(scodec->regmap);
 
 	return 0;
 }
 
-static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
+static int sun8i_codec_get_hw_rate(unsigned int sample_rate)
 {
-	unsigned int rate = params_rate(params);
-
-	switch (rate) {
+	switch (sample_rate) {
 	case 7350:
 	case 8000:
 		return 0x0;
 	case 11025:
 		return 0x1;
 	case 12000:
 		return 0x2;
 	case 14700:
@@ -181,16 +184,43 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	case 176400:
 	case 192000:
 		return 0xa;
 	default:
 		return -EINVAL;
 	}
 }
 
+static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
+{
+	unsigned int max_rate = 0;
+	int hw_rate, i;
+
+	for (i = AIF1; i < NAIFS; ++i) {
+		struct sun8i_codec_aif *aif = &scodec->aifs[i];
+
+		if (aif->active_streams)
+			max_rate = max(max_rate, aif->sample_rate);
+	}
+
+	/* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
+	if (!max_rate)
+		max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
+
+	hw_rate = sun8i_codec_get_hw_rate(max_rate);
+	if (hw_rate < 0)
+		return hw_rate;
+
+	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
+			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
+			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+
+	return 0;
+}
+
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	u32 format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
@@ -350,19 +380,20 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 }
 
 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_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
-	int lrck_div_order, sample_rate, word_size;
+	int lrck_div_order, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
@@ -387,36 +418,48 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
-	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, params_rate(params));
+	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, sample_rate);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
-	sample_rate = sun8i_codec_get_hw_rate(params);
-	if (sample_rate < 0)
-		return sample_rate;
+	aif->sample_rate = sample_rate;
+	aif->open_streams |= BIT(substream->stream);
 
-	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
-			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
-			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+	return sun8i_codec_update_sample_rate(scodec);
+}
+
+static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+
+	if (aif->open_streams != BIT(substream->stream))
+		goto done;
 
+	aif->sample_rate = 0;
+
+done:
+	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
 	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
 	.hw_params	= sun8i_codec_hw_params,
+	.hw_free	= sun8i_codec_hw_free,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 	{
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
 		/* capture capabilities */
@@ -437,16 +480,32 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
 };
 
+static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
+	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
+	int stream = w->id == snd_soc_dapm_aif_out;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		aif->active_streams |= BIT(stream);
+	else
+		aif->active_streams &= ~BIT(stream);
+
+	return sun8i_codec_update_sample_rate(scodec);
+}
+
 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,
@@ -539,19 +598,21 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	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", "AIF1 Capture", 0,
-			     SUN8I_AIF1_ADCDAT_CTRL,
-			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
+	SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
+			       SUN8I_AIF1_ADCDAT_CTRL,
+			       SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 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,
@@ -565,19 +626,21 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* 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", "AIF1 Playback", 0,
-			    SUN8I_AIF1_DACDAT_CTRL,
-			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
+	SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
+			      SUN8I_AIF1_DACDAT_CTRL,
+			      SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_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),
 
@@ -722,27 +785,29 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 			   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);
 
+	/* Program the default sample rate. */
+	sun8i_codec_update_sample_rate(scodec);
+
 	return 0;
 }
 
 static const struct snd_soc_component_driver sun8i_soc_component = {
 	.dapm_widgets		= sun8i_codec_dapm_widgets,
 	.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,
 	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config sun8i_codec_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
 	.val_bits	= 32,
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 19/25] ASoC: sun8i-codec: Constrain to compatible sample rates
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

While another stream is active, only allow userspace to use sample rates
that are compatible with the current SYSCLK frequency. This ensures the
actual sample rate will always match what is given in hw_params.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 43b4319e3d84..501af64d43a0 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -121,16 +121,18 @@ struct sun8i_codec_quirks {
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
 	const struct sun8i_codec_quirks	*quirks;
 	struct sun8i_codec_aif		aifs[NAIFS];
+	unsigned int			sysclk_rate;
+	int				sysclk_refcnt;
 };
 
 static int sun8i_codec_runtime_resume(struct device *dev)
 {
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
 	int ret;
 
 	regcache_cache_only(scodec->regmap, false);
@@ -319,16 +321,57 @@ static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
 		return -EINVAL;
 
 	aif->slots = slots;
 	aif->slot_width = slot_width;
 
 	return 0;
 }
 
+static const unsigned int sun8i_codec_rates[] = {
+	  7350,   8000,  11025,  12000,  14700,  16000,  22050,  24000,
+	 29400,  32000,  44100,  48000,  88200,  96000, 176400, 192000,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+	.mask	= 0x5555,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+	.mask	= 0xaaaa,
+};
+
+static int sun8i_codec_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	const struct snd_pcm_hw_constraint_list *list;
+
+	if (!scodec->sysclk_refcnt)
+		list = &sun8i_codec_all_rates;
+	else if (scodec->sysclk_rate == 22579200)
+		list = &sun8i_codec_22M_rates;
+	else if (scodec->sysclk_rate == 24576000)
+		list = &sun8i_codec_24M_rates;
+	else
+		return -EINVAL;
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE, list);
+}
+
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
 
 static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 1,	.val = 0 },
 	{ .div = 2,	.val = 1 },
@@ -341,22 +384,21 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 32,	.val = 8 },
 	{ .div = 48,	.val = 9 },
 	{ .div = 64,	.val = 10 },
 	{ .div = 96,	.val = 11 },
 	{ .div = 128,	.val = 12 },
 	{ .div = 192,	.val = 13 },
 };
 
-static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
+static u8 sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
 				   unsigned int lrck_div_order,
 				   unsigned int sample_rate)
 {
-	unsigned long clk_rate = clk_get_rate(scodec->clk_module);
-	unsigned int div = clk_rate / sample_rate >> lrck_div_order;
+	unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
 	unsigned int best_val = 0, best_diff = ~0;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
 		unsigned int diff = abs(bdiv->div - div);
 
 		if (diff < best_diff) {
@@ -383,16 +425,17 @@ 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_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
+	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
 	int lrck_div_order, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
@@ -418,46 +461,54 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
-	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, sample_rate);
+	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
+	if (!aif->open_streams) {
+		scodec->sysclk_rate = sysclk_rate;
+		scodec->sysclk_refcnt++;
+	}
+
 	aif->sample_rate = sample_rate;
 	aif->open_streams |= BIT(substream->stream);
 
 	return sun8i_codec_update_sample_rate(scodec);
 }
 
 static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
 	if (aif->open_streams != BIT(substream->stream))
 		goto done;
 
+	scodec->sysclk_refcnt--;
+
 	aif->sample_rate = 0;
 
 done:
 	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
 	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
+	.startup	= sun8i_codec_startup,
 	.hw_params	= sun8i_codec_hw_params,
 	.hw_free	= sun8i_codec_hw_free,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 	{
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 19/25] ASoC: sun8i-codec: Constrain to compatible sample rates
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

While another stream is active, only allow userspace to use sample rates
that are compatible with the current SYSCLK frequency. This ensures the
actual sample rate will always match what is given in hw_params.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 43b4319e3d84..501af64d43a0 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -121,16 +121,18 @@ struct sun8i_codec_quirks {
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
 	const struct sun8i_codec_quirks	*quirks;
 	struct sun8i_codec_aif		aifs[NAIFS];
+	unsigned int			sysclk_rate;
+	int				sysclk_refcnt;
 };
 
 static int sun8i_codec_runtime_resume(struct device *dev)
 {
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
 	int ret;
 
 	regcache_cache_only(scodec->regmap, false);
@@ -319,16 +321,57 @@ static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
 		return -EINVAL;
 
 	aif->slots = slots;
 	aif->slot_width = slot_width;
 
 	return 0;
 }
 
+static const unsigned int sun8i_codec_rates[] = {
+	  7350,   8000,  11025,  12000,  14700,  16000,  22050,  24000,
+	 29400,  32000,  44100,  48000,  88200,  96000, 176400, 192000,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+	.mask	= 0x5555,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+	.mask	= 0xaaaa,
+};
+
+static int sun8i_codec_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	const struct snd_pcm_hw_constraint_list *list;
+
+	if (!scodec->sysclk_refcnt)
+		list = &sun8i_codec_all_rates;
+	else if (scodec->sysclk_rate == 22579200)
+		list = &sun8i_codec_22M_rates;
+	else if (scodec->sysclk_rate == 24576000)
+		list = &sun8i_codec_24M_rates;
+	else
+		return -EINVAL;
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE, list);
+}
+
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
 
 static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 1,	.val = 0 },
 	{ .div = 2,	.val = 1 },
@@ -341,22 +384,21 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 32,	.val = 8 },
 	{ .div = 48,	.val = 9 },
 	{ .div = 64,	.val = 10 },
 	{ .div = 96,	.val = 11 },
 	{ .div = 128,	.val = 12 },
 	{ .div = 192,	.val = 13 },
 };
 
-static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
+static u8 sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
 				   unsigned int lrck_div_order,
 				   unsigned int sample_rate)
 {
-	unsigned long clk_rate = clk_get_rate(scodec->clk_module);
-	unsigned int div = clk_rate / sample_rate >> lrck_div_order;
+	unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
 	unsigned int best_val = 0, best_diff = ~0;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
 		unsigned int diff = abs(bdiv->div - div);
 
 		if (diff < best_diff) {
@@ -383,16 +425,17 @@ 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_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
+	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
 	int lrck_div_order, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
@@ -418,46 +461,54 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
-	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, sample_rate);
+	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
+	if (!aif->open_streams) {
+		scodec->sysclk_rate = sysclk_rate;
+		scodec->sysclk_refcnt++;
+	}
+
 	aif->sample_rate = sample_rate;
 	aif->open_streams |= BIT(substream->stream);
 
 	return sun8i_codec_update_sample_rate(scodec);
 }
 
 static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
 	if (aif->open_streams != BIT(substream->stream))
 		goto done;
 
+	scodec->sysclk_refcnt--;
+
 	aif->sample_rate = 0;
 
 done:
 	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
 	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
+	.startup	= sun8i_codec_startup,
 	.hw_params	= sun8i_codec_hw_params,
 	.hw_free	= sun8i_codec_hw_free,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 	{
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 19/25] ASoC: sun8i-codec: Constrain to compatible sample rates
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

While another stream is active, only allow userspace to use sample rates
that are compatible with the current SYSCLK frequency. This ensures the
actual sample rate will always match what is given in hw_params.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 43b4319e3d84..501af64d43a0 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -121,16 +121,18 @@ struct sun8i_codec_quirks {
 	bool lrck_inversion	: 1;
 };
 
 struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
 	const struct sun8i_codec_quirks	*quirks;
 	struct sun8i_codec_aif		aifs[NAIFS];
+	unsigned int			sysclk_rate;
+	int				sysclk_refcnt;
 };
 
 static int sun8i_codec_runtime_resume(struct device *dev)
 {
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
 	int ret;
 
 	regcache_cache_only(scodec->regmap, false);
@@ -319,16 +321,57 @@ static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
 		return -EINVAL;
 
 	aif->slots = slots;
 	aif->slot_width = slot_width;
 
 	return 0;
 }
 
+static const unsigned int sun8i_codec_rates[] = {
+	  7350,   8000,  11025,  12000,  14700,  16000,  22050,  24000,
+	 29400,  32000,  44100,  48000,  88200,  96000, 176400, 192000,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+	.mask	= 0x5555,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+	.mask	= 0xaaaa,
+};
+
+static int sun8i_codec_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	const struct snd_pcm_hw_constraint_list *list;
+
+	if (!scodec->sysclk_refcnt)
+		list = &sun8i_codec_all_rates;
+	else if (scodec->sysclk_rate == 22579200)
+		list = &sun8i_codec_22M_rates;
+	else if (scodec->sysclk_rate == 24576000)
+		list = &sun8i_codec_24M_rates;
+	else
+		return -EINVAL;
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE, list);
+}
+
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
 };
 
 static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 1,	.val = 0 },
 	{ .div = 2,	.val = 1 },
@@ -341,22 +384,21 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 32,	.val = 8 },
 	{ .div = 48,	.val = 9 },
 	{ .div = 64,	.val = 10 },
 	{ .div = 96,	.val = 11 },
 	{ .div = 128,	.val = 12 },
 	{ .div = 192,	.val = 13 },
 };
 
-static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
+static u8 sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
 				   unsigned int lrck_div_order,
 				   unsigned int sample_rate)
 {
-	unsigned long clk_rate = clk_get_rate(scodec->clk_module);
-	unsigned int div = clk_rate / sample_rate >> lrck_div_order;
+	unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
 	unsigned int best_val = 0, best_diff = ~0;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
 		unsigned int diff = abs(bdiv->div - div);
 
 		if (diff < best_diff) {
@@ -383,16 +425,17 @@ 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_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
+	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
 	int lrck_div_order, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
@@ -418,46 +461,54 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
-	bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, sample_rate);
+	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
+	if (!aif->open_streams) {
+		scodec->sysclk_rate = sysclk_rate;
+		scodec->sysclk_refcnt++;
+	}
+
 	aif->sample_rate = sample_rate;
 	aif->open_streams |= BIT(substream->stream);
 
 	return sun8i_codec_update_sample_rate(scodec);
 }
 
 static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
 	if (aif->open_streams != BIT(substream->stream))
 		goto done;
 
+	scodec->sysclk_refcnt--;
+
 	aif->sample_rate = 0;
 
 done:
 	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
 	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
+	.startup	= sun8i_codec_startup,
 	.hw_params	= sun8i_codec_hw_params,
 	.hw_free	= sun8i_codec_hw_free,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 	{
 		.name	= "sun8i-codec-aif1",
 		.id	= AIF1,
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

The codec's clock input is shared among all AIFs, and shared with other
audio-related hardware in the SoC, including I2S and SPDIF controllers.
To ensure sample rates selected by userspace or by codec2codec DAI links
are maintained, the clock rate must be protected while it is in use.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 501af64d43a0..86065bee7cd3 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
 		return -EINVAL;
 
 	return order_base_2(div);
 }
 
+static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
+{
+	return sample_rate % 4000 ? 22579200 : 24576000;
+}
+
 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_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
-	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
-	int lrck_div_order, word_size;
+	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
+	int lrck_div_order, ret, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
@@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
-	if (!aif->open_streams) {
+	/* SYSCLK rate */
+	if (aif->open_streams) {
+		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
+		if (ret == -EBUSY)
+			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
+				"conflicts with other audio streams.\n",
+				dai->name, sample_rate);
+		if (ret < 0)
+			return ret;
+
 		scodec->sysclk_rate = sysclk_rate;
 		scodec->sysclk_refcnt++;
 	}
 
 	aif->sample_rate = sample_rate;
 	aif->open_streams |= BIT(substream->stream);
 
 	return sun8i_codec_update_sample_rate(scodec);
@@ -487,16 +505,17 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
 	if (aif->open_streams != BIT(substream->stream))
 		goto done;
 
 	scodec->sysclk_refcnt--;
+	clk_rate_exclusive_put(scodec->clk_module);
 
 	aif->sample_rate = 0;
 
 done:
 	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The codec's clock input is shared among all AIFs, and shared with other
audio-related hardware in the SoC, including I2S and SPDIF controllers.
To ensure sample rates selected by userspace or by codec2codec DAI links
are maintained, the clock rate must be protected while it is in use.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 501af64d43a0..86065bee7cd3 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
 		return -EINVAL;
 
 	return order_base_2(div);
 }
 
+static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
+{
+	return sample_rate % 4000 ? 22579200 : 24576000;
+}
+
 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_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
-	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
-	int lrck_div_order, word_size;
+	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
+	int lrck_div_order, ret, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
@@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
-	if (!aif->open_streams) {
+	/* SYSCLK rate */
+	if (aif->open_streams) {
+		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
+		if (ret == -EBUSY)
+			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
+				"conflicts with other audio streams.\n",
+				dai->name, sample_rate);
+		if (ret < 0)
+			return ret;
+
 		scodec->sysclk_rate = sysclk_rate;
 		scodec->sysclk_refcnt++;
 	}
 
 	aif->sample_rate = sample_rate;
 	aif->open_streams |= BIT(substream->stream);
 
 	return sun8i_codec_update_sample_rate(scodec);
@@ -487,16 +505,17 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
 	if (aif->open_streams != BIT(substream->stream))
 		goto done;
 
 	scodec->sysclk_refcnt--;
+	clk_rate_exclusive_put(scodec->clk_module);
 
 	aif->sample_rate = 0;
 
 done:
 	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The codec's clock input is shared among all AIFs, and shared with other
audio-related hardware in the SoC, including I2S and SPDIF controllers.
To ensure sample rates selected by userspace or by codec2codec DAI links
are maintained, the clock rate must be protected while it is in use.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 501af64d43a0..86065bee7cd3 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
 		return -EINVAL;
 
 	return order_base_2(div);
 }
 
+static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
+{
+	return sample_rate % 4000 ? 22579200 : 24576000;
+}
+
 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_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
-	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
-	int lrck_div_order, word_size;
+	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
+	int lrck_div_order, ret, word_size;
 	u8 bclk_div;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
@@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
-	if (!aif->open_streams) {
+	/* SYSCLK rate */
+	if (aif->open_streams) {
+		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
+		if (ret == -EBUSY)
+			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
+				"conflicts with other audio streams.\n",
+				dai->name, sample_rate);
+		if (ret < 0)
+			return ret;
+
 		scodec->sysclk_rate = sysclk_rate;
 		scodec->sysclk_refcnt++;
 	}
 
 	aif->sample_rate = sample_rate;
 	aif->open_streams |= BIT(substream->stream);
 
 	return sun8i_codec_update_sample_rate(scodec);
@@ -487,16 +505,17 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
 	if (aif->open_streams != BIT(substream->stream))
 		goto done;
 
 	scodec->sysclk_refcnt--;
+	clk_rate_exclusive_put(scodec->clk_module);
 
 	aif->sample_rate = 0;
 
 done:
 	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 21/25] ASoC: sun8i-codec: Require an exact BCLK divisor match
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

Now that we guarantee that SYSCLK is running at the optimal rate when
hw_params succeeds, and that it will continue running at that rate,
SYSCLK will always be an integer multiple of BCLK. So we can always
pick the exact divider, not just the closest divider.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 86065bee7cd3..d8ce84533ddb 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -384,35 +384,31 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 32,	.val = 8 },
 	{ .div = 48,	.val = 9 },
 	{ .div = 64,	.val = 10 },
 	{ .div = 96,	.val = 11 },
 	{ .div = 128,	.val = 12 },
 	{ .div = 192,	.val = 13 },
 };
 
-static u8 sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
-				   unsigned int lrck_div_order,
-				   unsigned int sample_rate)
+static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
+				    unsigned int lrck_div_order,
+				    unsigned int sample_rate)
 {
 	unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
-	unsigned int best_val = 0, best_diff = ~0;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
-		unsigned int diff = abs(bdiv->div - div);
 
-		if (diff < best_diff) {
-			best_diff = diff;
-			best_val = bdiv->val;
-		}
+		if (bdiv->div == div)
+			return bdiv->val;
 	}
 
-	return best_val;
+	return -EINVAL;
 }
 
 static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 					  unsigned int slot_width)
 {
 	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
@@ -431,18 +427,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
-	int lrck_div_order, ret, word_size;
-	u8 bclk_div;
+	int bclk_div, lrck_div_order, ret, word_size;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
 		word_size = 0x1;
@@ -467,16 +462,19 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
+	if (bclk_div < 0)
+		return bclk_div;
+
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
 	/* SYSCLK rate */
 	if (aif->open_streams) {
 		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
 		if (ret < 0)
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 21/25] ASoC: sun8i-codec: Require an exact BCLK divisor match
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Now that we guarantee that SYSCLK is running at the optimal rate when
hw_params succeeds, and that it will continue running at that rate,
SYSCLK will always be an integer multiple of BCLK. So we can always
pick the exact divider, not just the closest divider.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 86065bee7cd3..d8ce84533ddb 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -384,35 +384,31 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 32,	.val = 8 },
 	{ .div = 48,	.val = 9 },
 	{ .div = 64,	.val = 10 },
 	{ .div = 96,	.val = 11 },
 	{ .div = 128,	.val = 12 },
 	{ .div = 192,	.val = 13 },
 };
 
-static u8 sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
-				   unsigned int lrck_div_order,
-				   unsigned int sample_rate)
+static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
+				    unsigned int lrck_div_order,
+				    unsigned int sample_rate)
 {
 	unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
-	unsigned int best_val = 0, best_diff = ~0;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
-		unsigned int diff = abs(bdiv->div - div);
 
-		if (diff < best_diff) {
-			best_diff = diff;
-			best_val = bdiv->val;
-		}
+		if (bdiv->div == div)
+			return bdiv->val;
 	}
 
-	return best_val;
+	return -EINVAL;
 }
 
 static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 					  unsigned int slot_width)
 {
 	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
@@ -431,18 +427,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
-	int lrck_div_order, ret, word_size;
-	u8 bclk_div;
+	int bclk_div, lrck_div_order, ret, word_size;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
 		word_size = 0x1;
@@ -467,16 +462,19 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
+	if (bclk_div < 0)
+		return bclk_div;
+
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
 	/* SYSCLK rate */
 	if (aif->open_streams) {
 		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
 		if (ret < 0)
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 21/25] ASoC: sun8i-codec: Require an exact BCLK divisor match
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Now that we guarantee that SYSCLK is running at the optimal rate when
hw_params succeeds, and that it will continue running at that rate,
SYSCLK will always be an integer multiple of BCLK. So we can always
pick the exact divider, not just the closest divider.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 86065bee7cd3..d8ce84533ddb 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -384,35 +384,31 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 32,	.val = 8 },
 	{ .div = 48,	.val = 9 },
 	{ .div = 64,	.val = 10 },
 	{ .div = 96,	.val = 11 },
 	{ .div = 128,	.val = 12 },
 	{ .div = 192,	.val = 13 },
 };
 
-static u8 sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
-				   unsigned int lrck_div_order,
-				   unsigned int sample_rate)
+static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
+				    unsigned int lrck_div_order,
+				    unsigned int sample_rate)
 {
 	unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
-	unsigned int best_val = 0, best_diff = ~0;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
-		unsigned int diff = abs(bdiv->div - div);
 
-		if (diff < best_diff) {
-			best_diff = diff;
-			best_val = bdiv->val;
-		}
+		if (bdiv->div == div)
+			return bdiv->val;
 	}
 
-	return best_val;
+	return -EINVAL;
 }
 
 static int sun8i_codec_get_lrck_div_order(unsigned int slots,
 					  unsigned int slot_width)
 {
 	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
@@ -431,18 +427,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
-	int lrck_div_order, ret, word_size;
-	u8 bclk_div;
+	int bclk_div, lrck_div_order, ret, word_size;
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
 		word_size = 0x1;
@@ -467,16 +462,19 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 		return lrck_div_order;
 
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
+	if (bclk_div < 0)
+		return bclk_div;
+
 	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 
 	/* SYSCLK rate */
 	if (aif->open_streams) {
 		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
 		if (ret < 0)
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 22/25] ASoC: sun8i-codec: Enable all supported PCM formats
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

Now that the DAI clock setup is correct for all hardware-supported PCM
formats, we can enable them in the driver. With the appropriate support
in the CPU DAI driver, this allows userspace to access the additional
formats.

Since this codec is connected to the CPU via a DAI, not directly, we do
not care if the CPU DAI is using 3-byte or 4-byte formats, so we can
support them both.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index d8ce84533ddb..032a3f714dbb 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -91,16 +91,23 @@
 #define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
 
+#define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
+				 SNDRV_PCM_FMTBIT_S16_LE |\
+				 SNDRV_PCM_FMTBIT_S20_LE |\
+				 SNDRV_PCM_FMTBIT_S24_LE |\
+				 SNDRV_PCM_FMTBIT_S20_3LE|\
+				 SNDRV_PCM_FMTBIT_S24_3LE)
+
 #define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
 				 SNDRV_PCM_RATE_88200     |\
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
@@ -531,26 +538,26 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
 		/* capture capabilities */
 		.capture = {
 			.stream_name	= "AIF1 Capture",
 			.channels_min	= 1,
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
-			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
 			.sig_bits	= 24,
 		},
 		/* playback capabilities */
 		.playback = {
 			.stream_name	= "AIF1 Playback",
 			.channels_min	= 1,
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
-			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
 };
 
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 22/25] ASoC: sun8i-codec: Enable all supported PCM formats
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Now that the DAI clock setup is correct for all hardware-supported PCM
formats, we can enable them in the driver. With the appropriate support
in the CPU DAI driver, this allows userspace to access the additional
formats.

Since this codec is connected to the CPU via a DAI, not directly, we do
not care if the CPU DAI is using 3-byte or 4-byte formats, so we can
support them both.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index d8ce84533ddb..032a3f714dbb 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -91,16 +91,23 @@
 #define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
 
+#define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
+				 SNDRV_PCM_FMTBIT_S16_LE |\
+				 SNDRV_PCM_FMTBIT_S20_LE |\
+				 SNDRV_PCM_FMTBIT_S24_LE |\
+				 SNDRV_PCM_FMTBIT_S20_3LE|\
+				 SNDRV_PCM_FMTBIT_S24_3LE)
+
 #define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
 				 SNDRV_PCM_RATE_88200     |\
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
@@ -531,26 +538,26 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
 		/* capture capabilities */
 		.capture = {
 			.stream_name	= "AIF1 Capture",
 			.channels_min	= 1,
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
-			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
 			.sig_bits	= 24,
 		},
 		/* playback capabilities */
 		.playback = {
 			.stream_name	= "AIF1 Playback",
 			.channels_min	= 1,
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
-			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
 };
 
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 22/25] ASoC: sun8i-codec: Enable all supported PCM formats
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

Now that the DAI clock setup is correct for all hardware-supported PCM
formats, we can enable them in the driver. With the appropriate support
in the CPU DAI driver, this allows userspace to access the additional
formats.

Since this codec is connected to the CPU via a DAI, not directly, we do
not care if the CPU DAI is using 3-byte or 4-byte formats, so we can
support them both.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index d8ce84533ddb..032a3f714dbb 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -91,16 +91,23 @@
 #define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK	GENMASK(14, 13)
 #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)
 
 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
 
+#define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
+				 SNDRV_PCM_FMTBIT_S16_LE |\
+				 SNDRV_PCM_FMTBIT_S20_LE |\
+				 SNDRV_PCM_FMTBIT_S24_LE |\
+				 SNDRV_PCM_FMTBIT_S20_3LE|\
+				 SNDRV_PCM_FMTBIT_S24_3LE)
+
 #define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
 				 SNDRV_PCM_RATE_88200     |\
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
@@ -531,26 +538,26 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 		.id	= AIF1,
 		.ops	= &sun8i_codec_dai_ops,
 		/* capture capabilities */
 		.capture = {
 			.stream_name	= "AIF1 Capture",
 			.channels_min	= 1,
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
-			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
 			.sig_bits	= 24,
 		},
 		/* playback capabilities */
 		.playback = {
 			.stream_name	= "AIF1 Playback",
 			.channels_min	= 1,
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
-			.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
 };
 
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

The AIF clock control register has the same layout for all three AIFs.
The only difference between them is that AIF3 is missing some fields. We
can reuse the same register field definitions for all three registers,
and use the DAI ID to select the correct register address.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 032a3f714dbb..1c34502ac47a 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -37,23 +37,23 @@
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
-#define SUN8I_AIF1CLK_CTRL				0x040
-#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
-#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
-#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
+#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
+#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
+#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
 #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
@@ -83,21 +83,21 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
-#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)
+#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
 
 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
 
 #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
 				 SNDRV_PCM_FMTBIT_S16_LE |\
 				 SNDRV_PCM_FMTBIT_S20_LE |\
 				 SNDRV_PCM_FMTBIT_S24_LE |\
 				 SNDRV_PCM_FMTBIT_S20_3LE|\
@@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
 			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 
 	return 0;
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
 	u32 format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
 		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
+
+	regmap_update_bits(scodec->regmap, reg,
+			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
+			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
 
 	/* DAI format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		format = 0x0;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		format = 0x1;
@@ -262,19 +264,20 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
 		format = 0x3;
 		invert = 0x1; /* Set LRCK_INV to 1 */
 		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
-			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
+
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
+			   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
 
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
 	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
 		value = 0x1;
@@ -305,19 +308,19 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		 * 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,
-			   SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
+			   value << SUN8I_AIF_CLK_CTRL_CLK_INV);
 
 	return 0;
 }
 
 static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
 				    unsigned int tx_mask, unsigned int rx_mask,
 				    int slots, int slot_width)
 {
@@ -435,16 +438,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
 	int bclk_div, lrck_div_order, ret, word_size;
+	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
 		word_size = 0x1;
@@ -454,37 +458,37 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 		break;
 	case 24:
 		word_size = 0x3;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
-			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
+			   word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
 
 	/* LRCK divider (BCLK/LRCK ratio) */
 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
-			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
+			   (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	if (bclk_div < 0)
 		return bclk_div;
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
-			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
+			   bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
 
 	/* SYSCLK rate */
 	if (aif->open_streams) {
 		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
 		if (ret < 0)
 			return ret;
 	} else {
 		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The AIF clock control register has the same layout for all three AIFs.
The only difference between them is that AIF3 is missing some fields. We
can reuse the same register field definitions for all three registers,
and use the DAI ID to select the correct register address.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 032a3f714dbb..1c34502ac47a 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -37,23 +37,23 @@
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
-#define SUN8I_AIF1CLK_CTRL				0x040
-#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
-#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
-#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
+#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
+#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
+#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
 #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
@@ -83,21 +83,21 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
-#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)
+#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
 
 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
 
 #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
 				 SNDRV_PCM_FMTBIT_S16_LE |\
 				 SNDRV_PCM_FMTBIT_S20_LE |\
 				 SNDRV_PCM_FMTBIT_S24_LE |\
 				 SNDRV_PCM_FMTBIT_S20_3LE|\
@@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
 			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 
 	return 0;
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
 	u32 format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
 		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
+
+	regmap_update_bits(scodec->regmap, reg,
+			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
+			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
 
 	/* DAI format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		format = 0x0;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		format = 0x1;
@@ -262,19 +264,20 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
 		format = 0x3;
 		invert = 0x1; /* Set LRCK_INV to 1 */
 		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
-			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
+
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
+			   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
 
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
 	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
 		value = 0x1;
@@ -305,19 +308,19 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		 * 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,
-			   SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
+			   value << SUN8I_AIF_CLK_CTRL_CLK_INV);
 
 	return 0;
 }
 
 static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
 				    unsigned int tx_mask, unsigned int rx_mask,
 				    int slots, int slot_width)
 {
@@ -435,16 +438,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
 	int bclk_div, lrck_div_order, ret, word_size;
+	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
 		word_size = 0x1;
@@ -454,37 +458,37 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 		break;
 	case 24:
 		word_size = 0x3;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
-			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
+			   word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
 
 	/* LRCK divider (BCLK/LRCK ratio) */
 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
-			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
+			   (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	if (bclk_div < 0)
 		return bclk_div;
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
-			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
+			   bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
 
 	/* SYSCLK rate */
 	if (aif->open_streams) {
 		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
 		if (ret < 0)
 			return ret;
 	} else {
 		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

The AIF clock control register has the same layout for all three AIFs.
The only difference between them is that AIF3 is missing some fields. We
can reuse the same register field definitions for all three registers,
and use the DAI ID to select the correct register address.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 032a3f714dbb..1c34502ac47a 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -37,23 +37,23 @@
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
-#define SUN8I_AIF1CLK_CTRL				0x040
-#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
-#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
-#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
+#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
+#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
+#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
 #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
@@ -83,21 +83,21 @@
 #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_CLK_INV_MASK	GENMASK(14, 13)
-#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)
+#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
 
 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
 
 #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
 				 SNDRV_PCM_FMTBIT_S16_LE |\
 				 SNDRV_PCM_FMTBIT_S20_LE |\
 				 SNDRV_PCM_FMTBIT_S24_LE |\
 				 SNDRV_PCM_FMTBIT_S20_3LE|\
@@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
 			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 
 	return 0;
 }
 
 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
 	u32 format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 		value = 0x1;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
 		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
+
+	regmap_update_bits(scodec->regmap, reg,
+			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
+			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
 
 	/* DAI format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		format = 0x0;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		format = 0x1;
@@ -262,19 +264,20 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
 		format = 0x3;
 		invert = 0x1; /* Set LRCK_INV to 1 */
 		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
-			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
+
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
+			   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
 
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
 	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
 		value = 0x1;
@@ -305,19 +308,19 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		 * 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,
-			   SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK,
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
+			   value << SUN8I_AIF_CLK_CTRL_CLK_INV);
 
 	return 0;
 }
 
 static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
 				    unsigned int tx_mask, unsigned int rx_mask,
 				    int slots, int slot_width)
 {
@@ -435,16 +438,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
 	int bclk_div, lrck_div_order, ret, word_size;
+	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
 		word_size = 0x1;
@@ -454,37 +458,37 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 		break;
 	case 24:
 		word_size = 0x3;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
-			   word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
+			   word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
 
 	/* LRCK divider (BCLK/LRCK ratio) */
 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
-			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
+			   (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	if (bclk_div < 0)
 		return bclk_div;
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
-			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
+	regmap_update_bits(scodec->regmap, reg,
+			   SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
+			   bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
 
 	/* SYSCLK rate */
 	if (aif->open_streams) {
 		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
 		if (ret < 0)
 			return ret;
 	} else {
 		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 24/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

This adds support for AIF2, which is stereo and has full clocking
capability, making it very similar to AIF1.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 1c34502ac47a..9fa4eca501df 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -28,20 +28,22 @@
 #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_AIF2				14
 #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_AIF2				14
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
 #define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
 #define SUN8I_AIF_CLK_CTRL_CLK_INV			13
@@ -63,16 +65,39 @@
 #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_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
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR	13
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL		12
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R	11
+#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_AIF3_PATH_CTRL				0x0cc
+#define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC		10
+#define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC		8
+#define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI		7
 #define SUN8I_ADC_DIG_CTRL				0x100
 #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_MXR_SRC				0x130
 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L		15
@@ -107,16 +132,17 @@
 				 SNDRV_PCM_RATE_88200     |\
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
 	AIF1,
+	AIF2,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
 	unsigned int	sample_rate;
 	unsigned int	slots;
 	unsigned int	slot_width;
 	unsigned int	active_streams	: 2;
@@ -359,16 +385,20 @@ static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
 };
 
 static int sun8i_codec_startup(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	const struct snd_pcm_hw_constraint_list *list;
 
+	/* hw_constraints is not relevant for codec2codec DAIs. */
+	if (dai->id != AIF1)
+		return 0;
+
 	if (!scodec->sysclk_refcnt)
 		list = &sun8i_codec_all_rates;
 	else if (scodec->sysclk_rate == 22579200)
 		list = &sun8i_codec_22M_rates;
 	else if (scodec->sysclk_rate == 24576000)
 		list = &sun8i_codec_24M_rates;
 	else
 		return -EINVAL;
@@ -557,16 +587,41 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
+	{
+		.name	= "sun8i-codec-aif2",
+		.id	= AIF2,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF2 Capture",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF2 Playback",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
+	},
 };
 
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
 	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
@@ -589,16 +644,26 @@ static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
 			    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 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_values);
+
+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 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,
@@ -608,26 +673,68 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
 			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 const struct snd_kcontrol_new sun8i_aif2_adc_mixer_controls[] = {
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR, 1, 0),
+};
+
+static const char *const sun8i_aif2_dac_mux_enum_values[] = {
+	"AIF2", "AIF3+2", "AIF2+3"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif2_dac_mux_enum,
+			    SUN8I_AIF3_PATH_CTRL,
+			    SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC,
+			    sun8i_aif2_dac_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif2_dac_mux_control =
+	SOC_DAPM_ENUM("AIF2 DAC Source Playback Route",
+		      sun8i_aif2_dac_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_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 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_values);
+
+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 struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
@@ -642,35 +749,44 @@ static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 
 static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	/* 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("AIF2CLK",
+			    SUN8I_SYSCLK_CTL,
+			    SUN8I_SYSCLK_CTL_AIF2CLK_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 AIF2",
+			    SUN8I_MOD_CLK_ENA,
+			    SUN8I_MOD_CLK_ENA_AIF2, 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 AIF2",
+			    SUN8I_MOD_RST_CTL,
+			    SUN8I_MOD_RST_CTL_AIF2, 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 */
@@ -686,44 +802,83 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			       SUN8I_AIF1_ADCDAT_CTRL,
 			       SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
 			       sun8i_codec_aif_event,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
+	SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0,
+			       SUN8I_AIF2_ADCDAT_CTRL,
+			       SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
+			     SUN8I_AIF2_ADCDAT_CTRL,
+			     SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_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),
 
+	SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_adc_stereo_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_adc_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),
 
+	SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif2_adc_mixer_controls),
+	SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif2_adc_mixer_controls),
+
+	/* AIF "DAC" Input Muxes */
+	SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_mux_control),
+
 	/* 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),
 
+	SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_stereo_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_stereo_mux_control),
+
 	/* AIF "DAC" Inputs */
 	SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
 			      SUN8I_AIF1_DACDAT_CTRL,
 			      SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
 			      sun8i_codec_aif_event,
 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
 
+	SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0,
+			      SUN8I_AIF2_DACDAT_CTRL,
+			      SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
+			    SUN8I_AIF2_DACDAT_CTRL,
+			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_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),
 
@@ -743,78 +898,138 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "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 AIF2", NULL, "AIF2CLK" },
+	{ "CLK AIF2", NULL, "SYSCLK" },
+	{ "RST AIF2", NULL, "CLK AIF2" },
+	{ "AIF2 ADCL", NULL, "RST AIF2" },
+	{ "AIF2 ADCR", NULL, "RST AIF2" },
+	{ "AIF2 DACL", NULL, "RST AIF2" },
+	{ "AIF2 DACR", NULL, "RST AIF2" },
+
 	{ "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" },
 
+	{ "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
+	{ "AIF2 ADCR", NULL, "AIF2 ADCR 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" },
 
+	{ "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
+	{ "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
 	/* AIF "ADC" Mixer Routes */
 	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
+	{ "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
 	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+	{ "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
 
 	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
+	{ "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
 	{ "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+	{ "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" },
+
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" },
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" },
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
+
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
+
+	/* AIF "DAC" Input Mux Routes */
+	{ "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
+	{ "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
+
+	{ "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
+	{ "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
 
 	/* 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" },
 
+	{ "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" },
+	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" },
+	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
+	{ "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" },
+	{ "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" },
+	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
 	/* DAC Output Routes */
 	{ "DACL", NULL, "DACL Mixer" },
 	{ "DACR", NULL, "DACR Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
+	{ "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" },
 	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
 	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
+	{ "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" },
 	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
 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),
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 24/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

This adds support for AIF2, which is stereo and has full clocking
capability, making it very similar to AIF1.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 1c34502ac47a..9fa4eca501df 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -28,20 +28,22 @@
 #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_AIF2				14
 #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_AIF2				14
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
 #define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
 #define SUN8I_AIF_CLK_CTRL_CLK_INV			13
@@ -63,16 +65,39 @@
 #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_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
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR	13
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL		12
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R	11
+#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_AIF3_PATH_CTRL				0x0cc
+#define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC		10
+#define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC		8
+#define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI		7
 #define SUN8I_ADC_DIG_CTRL				0x100
 #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_MXR_SRC				0x130
 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L		15
@@ -107,16 +132,17 @@
 				 SNDRV_PCM_RATE_88200     |\
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
 	AIF1,
+	AIF2,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
 	unsigned int	sample_rate;
 	unsigned int	slots;
 	unsigned int	slot_width;
 	unsigned int	active_streams	: 2;
@@ -359,16 +385,20 @@ static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
 };
 
 static int sun8i_codec_startup(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	const struct snd_pcm_hw_constraint_list *list;
 
+	/* hw_constraints is not relevant for codec2codec DAIs. */
+	if (dai->id != AIF1)
+		return 0;
+
 	if (!scodec->sysclk_refcnt)
 		list = &sun8i_codec_all_rates;
 	else if (scodec->sysclk_rate == 22579200)
 		list = &sun8i_codec_22M_rates;
 	else if (scodec->sysclk_rate == 24576000)
 		list = &sun8i_codec_24M_rates;
 	else
 		return -EINVAL;
@@ -557,16 +587,41 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
+	{
+		.name	= "sun8i-codec-aif2",
+		.id	= AIF2,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF2 Capture",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF2 Playback",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
+	},
 };
 
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
 	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
@@ -589,16 +644,26 @@ static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
 			    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 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_values);
+
+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 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,
@@ -608,26 +673,68 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
 			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 const struct snd_kcontrol_new sun8i_aif2_adc_mixer_controls[] = {
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR, 1, 0),
+};
+
+static const char *const sun8i_aif2_dac_mux_enum_values[] = {
+	"AIF2", "AIF3+2", "AIF2+3"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif2_dac_mux_enum,
+			    SUN8I_AIF3_PATH_CTRL,
+			    SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC,
+			    sun8i_aif2_dac_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif2_dac_mux_control =
+	SOC_DAPM_ENUM("AIF2 DAC Source Playback Route",
+		      sun8i_aif2_dac_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_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 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_values);
+
+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 struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
@@ -642,35 +749,44 @@ static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 
 static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	/* 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("AIF2CLK",
+			    SUN8I_SYSCLK_CTL,
+			    SUN8I_SYSCLK_CTL_AIF2CLK_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 AIF2",
+			    SUN8I_MOD_CLK_ENA,
+			    SUN8I_MOD_CLK_ENA_AIF2, 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 AIF2",
+			    SUN8I_MOD_RST_CTL,
+			    SUN8I_MOD_RST_CTL_AIF2, 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 */
@@ -686,44 +802,83 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			       SUN8I_AIF1_ADCDAT_CTRL,
 			       SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
 			       sun8i_codec_aif_event,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
+	SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0,
+			       SUN8I_AIF2_ADCDAT_CTRL,
+			       SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
+			     SUN8I_AIF2_ADCDAT_CTRL,
+			     SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_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),
 
+	SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_adc_stereo_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_adc_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),
 
+	SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif2_adc_mixer_controls),
+	SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif2_adc_mixer_controls),
+
+	/* AIF "DAC" Input Muxes */
+	SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_mux_control),
+
 	/* 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),
 
+	SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_stereo_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_stereo_mux_control),
+
 	/* AIF "DAC" Inputs */
 	SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
 			      SUN8I_AIF1_DACDAT_CTRL,
 			      SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
 			      sun8i_codec_aif_event,
 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
 
+	SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0,
+			      SUN8I_AIF2_DACDAT_CTRL,
+			      SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
+			    SUN8I_AIF2_DACDAT_CTRL,
+			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_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),
 
@@ -743,78 +898,138 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "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 AIF2", NULL, "AIF2CLK" },
+	{ "CLK AIF2", NULL, "SYSCLK" },
+	{ "RST AIF2", NULL, "CLK AIF2" },
+	{ "AIF2 ADCL", NULL, "RST AIF2" },
+	{ "AIF2 ADCR", NULL, "RST AIF2" },
+	{ "AIF2 DACL", NULL, "RST AIF2" },
+	{ "AIF2 DACR", NULL, "RST AIF2" },
+
 	{ "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" },
 
+	{ "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
+	{ "AIF2 ADCR", NULL, "AIF2 ADCR 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" },
 
+	{ "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
+	{ "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
 	/* AIF "ADC" Mixer Routes */
 	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
+	{ "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
 	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+	{ "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
 
 	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
+	{ "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
 	{ "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+	{ "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" },
+
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" },
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" },
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
+
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
+
+	/* AIF "DAC" Input Mux Routes */
+	{ "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
+	{ "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
+
+	{ "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
+	{ "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
 
 	/* 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" },
 
+	{ "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" },
+	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" },
+	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
+	{ "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" },
+	{ "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" },
+	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
 	/* DAC Output Routes */
 	{ "DACL", NULL, "DACL Mixer" },
 	{ "DACR", NULL, "DACR Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
+	{ "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" },
 	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
 	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
+	{ "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" },
 	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
 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),
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 24/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

This adds support for AIF2, which is stereo and has full clocking
capability, making it very similar to AIF1.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 1c34502ac47a..9fa4eca501df 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -28,20 +28,22 @@
 #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_AIF2				14
 #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_AIF2				14
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
 #define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
 #define SUN8I_AIF_CLK_CTRL_CLK_INV			13
@@ -63,16 +65,39 @@
 #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_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
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR	13
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL		12
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R	11
+#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_AIF3_PATH_CTRL				0x0cc
+#define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC		10
+#define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC		8
+#define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI		7
 #define SUN8I_ADC_DIG_CTRL				0x100
 #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_MXR_SRC				0x130
 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L		15
@@ -107,16 +132,17 @@
 				 SNDRV_PCM_RATE_88200     |\
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
 	AIF1,
+	AIF2,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
 	unsigned int	sample_rate;
 	unsigned int	slots;
 	unsigned int	slot_width;
 	unsigned int	active_streams	: 2;
@@ -359,16 +385,20 @@ static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
 };
 
 static int sun8i_codec_startup(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	const struct snd_pcm_hw_constraint_list *list;
 
+	/* hw_constraints is not relevant for codec2codec DAIs. */
+	if (dai->id != AIF1)
+		return 0;
+
 	if (!scodec->sysclk_refcnt)
 		list = &sun8i_codec_all_rates;
 	else if (scodec->sysclk_rate == 22579200)
 		list = &sun8i_codec_22M_rates;
 	else if (scodec->sysclk_rate == 24576000)
 		list = &sun8i_codec_24M_rates;
 	else
 		return -EINVAL;
@@ -557,16 +587,41 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
+	{
+		.name	= "sun8i-codec-aif2",
+		.id	= AIF2,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF2 Capture",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF2 Playback",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
+	},
 };
 
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
 	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
@@ -589,16 +644,26 @@ static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
 			    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 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_values);
+
+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 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,
@@ -608,26 +673,68 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
 			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 const struct snd_kcontrol_new sun8i_aif2_adc_mixer_controls[] = {
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR, 1, 0),
+};
+
+static const char *const sun8i_aif2_dac_mux_enum_values[] = {
+	"AIF2", "AIF3+2", "AIF2+3"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif2_dac_mux_enum,
+			    SUN8I_AIF3_PATH_CTRL,
+			    SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC,
+			    sun8i_aif2_dac_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif2_dac_mux_control =
+	SOC_DAPM_ENUM("AIF2 DAC Source Playback Route",
+		      sun8i_aif2_dac_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_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 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_values);
+
+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 struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
@@ -642,35 +749,44 @@ static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 
 static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	/* 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("AIF2CLK",
+			    SUN8I_SYSCLK_CTL,
+			    SUN8I_SYSCLK_CTL_AIF2CLK_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 AIF2",
+			    SUN8I_MOD_CLK_ENA,
+			    SUN8I_MOD_CLK_ENA_AIF2, 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 AIF2",
+			    SUN8I_MOD_RST_CTL,
+			    SUN8I_MOD_RST_CTL_AIF2, 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 */
@@ -686,44 +802,83 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			       SUN8I_AIF1_ADCDAT_CTRL,
 			       SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
 			       sun8i_codec_aif_event,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
+	SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0,
+			       SUN8I_AIF2_ADCDAT_CTRL,
+			       SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
+			     SUN8I_AIF2_ADCDAT_CTRL,
+			     SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_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),
 
+	SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_adc_stereo_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_adc_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),
 
+	SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif2_adc_mixer_controls),
+	SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif2_adc_mixer_controls),
+
+	/* AIF "DAC" Input Muxes */
+	SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_mux_control),
+
 	/* 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),
 
+	SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_stereo_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_stereo_mux_control),
+
 	/* AIF "DAC" Inputs */
 	SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
 			      SUN8I_AIF1_DACDAT_CTRL,
 			      SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
 			      sun8i_codec_aif_event,
 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
 
+	SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0,
+			      SUN8I_AIF2_DACDAT_CTRL,
+			      SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
+			    SUN8I_AIF2_DACDAT_CTRL,
+			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_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),
 
@@ -743,78 +898,138 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "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 AIF2", NULL, "AIF2CLK" },
+	{ "CLK AIF2", NULL, "SYSCLK" },
+	{ "RST AIF2", NULL, "CLK AIF2" },
+	{ "AIF2 ADCL", NULL, "RST AIF2" },
+	{ "AIF2 ADCR", NULL, "RST AIF2" },
+	{ "AIF2 DACL", NULL, "RST AIF2" },
+	{ "AIF2 DACR", NULL, "RST AIF2" },
+
 	{ "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" },
 
+	{ "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
+	{ "AIF2 ADCR", NULL, "AIF2 ADCR 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" },
 
+	{ "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
+	{ "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
 	/* AIF "ADC" Mixer Routes */
 	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
+	{ "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
 	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+	{ "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
 
 	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
+	{ "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
 	{ "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+	{ "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" },
+
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" },
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" },
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
+
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
+
+	/* AIF "DAC" Input Mux Routes */
+	{ "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
+	{ "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
+
+	{ "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
+	{ "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
 
 	/* 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" },
 
+	{ "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" },
+	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" },
+	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
+	{ "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" },
+	{ "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" },
+	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
 	/* DAC Output Routes */
 	{ "DACL", NULL, "DACL Mixer" },
 	{ "DACR", NULL, "DACR Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
+	{ "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" },
 	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
 	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
+	{ "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" },
 	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
 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),
 
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 25/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF3
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-01  2:11   ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel,
	Samuel Holland

AIF3 has some differences from AIF1 and AIF2:
 - It supports mono only
 - It supports master mode only
 - It is not directly connected to any of the mixers; instead all audio
   goes through a mux with AIF2.
 - It does not have its own clock dividers; instead it reuses AIF2 BCLK.
   This means that when both AIF2 and AIF3 are active, they must run at
   the same sample rate and total frame width. Since AIF2 and AIF3 are
   only used for codec2codec DAI links, constraints are not applicable
   here; the only thing we can do when the rates don't match is report
   an error.

Make the necessary adjustments to support this AIF.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 9fa4eca501df..344d9ad85fa6 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -29,21 +29,23 @@
 #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_AIF2				14
+#define SUN8I_MOD_CLK_ENA_AIF3				13
 #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_AIF2				14
+#define SUN8I_MOD_RST_CTL_AIF3				13
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
 #define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
 #define SUN8I_AIF_CLK_CTRL_CLK_INV			13
@@ -84,16 +86,19 @@
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L	15
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L	14
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR	13
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL		12
 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R	11
 #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_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_AIF3_PATH_CTRL				0x0cc
 #define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC		10
 #define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC		8
 #define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI		7
 #define SUN8I_ADC_DIG_CTRL				0x100
 #define SUN8I_ADC_DIG_CTRL_ENAD				15
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS			2
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY			1
@@ -113,16 +118,17 @@
 #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_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
 #define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
 #define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
 #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
 #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK	GENMASK(1, 0)
 
 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
 
 #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
 				 SNDRV_PCM_FMTBIT_S16_LE |\
 				 SNDRV_PCM_FMTBIT_S20_LE |\
 				 SNDRV_PCM_FMTBIT_S24_LE |\
 				 SNDRV_PCM_FMTBIT_S20_3LE|\
@@ -133,20 +139,22 @@
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
 	AIF1,
 	AIF2,
+	AIF3,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
+	unsigned int	lrck_div_order;
 	unsigned int	sample_rate;
 	unsigned int	slots;
 	unsigned int	slot_width;
 	unsigned int	active_streams	: 2;
 	unsigned int	open_streams	: 2;
 };
 
 struct sun8i_codec_quirks {
@@ -264,19 +272,30 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	regmap_update_bits(scodec->regmap, reg,
-			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
-			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
+	if (dai->id == AIF3) {
+		/* AIF3 only supports master mode. */
+		if (value)
+			return -EINVAL;
+
+		/* Use the AIF2 BCLK and LRCK for AIF3. */
+		regmap_update_bits(scodec->regmap, reg,
+				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
+				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
+	} else {
+		regmap_update_bits(scodec->regmap, reg,
+				   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
+				   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
+	}
 
 	/* DAI format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		format = 0x0;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		format = 0x1;
@@ -291,19 +310,25 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	case SND_SOC_DAIFMT_DSP_B:
 		format = 0x3;
 		invert = 0x1; /* Set LRCK_INV to 1 */
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	regmap_update_bits(scodec->regmap, reg,
-			   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
-			   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
+	if (dai->id == AIF3) {
+		/* AIF3 only supports DSP formats. */
+		if (format != 3)
+			return -EINVAL;
+	} else {
+		regmap_update_bits(scodec->regmap, reg,
+				   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
+				   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
+	}
 
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
 	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
 		value = 0x1;
@@ -468,17 +493,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
 	int bclk_div, lrck_div_order, ret, word_size;
-	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
+	u32 div_reg, reg = SUN8I_AIF_CLK_CTRL(dai->id);
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
 		word_size = 0x1;
@@ -497,26 +522,45 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
 			   word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
 
 	/* LRCK divider (BCLK/LRCK ratio) */
 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
-	regmap_update_bits(scodec->regmap, reg,
+	if (dai->id != AIF1) {
+		/* AIF2 and AIF3 share BCLK and LRCK generation circuitry. */
+		int partner = (AIF2 + AIF3) - dai->id;
+		struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner];
+
+		if (partner_aif->open_streams &&
+		    (lrck_div_order != partner_aif->lrck_div_order ||
+		     sample_rate != partner_aif->sample_rate)) {
+			dev_err(dai->dev, "Cannot enable %s: clock rate mismatch! "
+				"AIF2 and AIF3 must use the same sample and bit rates.\n",
+				dai->name);
+			return -EBUSY;
+		}
+
+		div_reg = SUN8I_AIF_CLK_CTRL(AIF2);
+	} else {
+		div_reg = reg;
+	}
+
+	regmap_update_bits(scodec->regmap, div_reg,
 			   SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	if (bclk_div < 0)
 		return bclk_div;
 
-	regmap_update_bits(scodec->regmap, reg,
+	regmap_update_bits(scodec->regmap, div_reg,
 			   SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
 
 	/* SYSCLK rate */
 	if (aif->open_streams) {
 		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
 		if (ret < 0)
 			return ret;
@@ -528,16 +572,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 				dai->name, sample_rate);
 		if (ret < 0)
 			return ret;
 
 		scodec->sysclk_rate = sysclk_rate;
 		scodec->sysclk_refcnt++;
 	}
 
+	aif->lrck_div_order = lrck_div_order;
 	aif->sample_rate = sample_rate;
 	aif->open_streams |= BIT(substream->stream);
 
 	return sun8i_codec_update_sample_rate(scodec);
 }
 
 static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
@@ -546,16 +591,17 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
 	if (aif->open_streams != BIT(substream->stream))
 		goto done;
 
 	scodec->sysclk_refcnt--;
 	clk_rate_exclusive_put(scodec->clk_module);
 
+	aif->lrck_div_order = 0;
 	aif->sample_rate = 0;
 
 done:
 	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
@@ -612,16 +658,41 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
+	{
+		.name	= "sun8i-codec-aif3",
+		.id	= AIF3,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF3 Capture",
+			.channels_min	= 1,
+			.channels_max	= 1,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF3 Playback",
+			.channels_min	= 1,
+			.channels_max	= 1,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
+	},
 };
 
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
 	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
@@ -654,16 +725,29 @@ static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum,
 			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC,
 			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC,
 			    sun8i_aif_stereo_mux_enum_values);
 
 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 const char *const sun8i_aif3_adc_mux_enum_values[] = {
+	"None", "AIF2 ADCL", "AIF2 ADCR"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif3_adc_mux_enum,
+			    SUN8I_AIF3_PATH_CTRL,
+			    SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC,
+			    sun8i_aif3_adc_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif3_adc_mux_control =
+	SOC_DAPM_ENUM("AIF3 ADC Source Capture Route",
+		      sun8i_aif3_adc_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,
@@ -763,30 +847,36 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* 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 AIF2",
 			    SUN8I_MOD_CLK_ENA,
 			    SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLK AIF3",
+			    SUN8I_MOD_CLK_ENA,
+			    SUN8I_MOD_CLK_ENA_AIF3, 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 AIF2",
 			    SUN8I_MOD_RST_CTL,
 			    SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RST AIF3",
+			    SUN8I_MOD_RST_CTL,
+			    SUN8I_MOD_RST_CTL_AIF3, 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 */
@@ -811,27 +901,36 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			       SUN8I_AIF2_ADCDAT_CTRL,
 			       SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
 			       sun8i_codec_aif_event,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
 			     SUN8I_AIF2_ADCDAT_CTRL,
 			     SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0),
 
+	SND_SOC_DAPM_AIF_OUT_E("AIF3 ADC", "AIF3 Capture", 0,
+			       SND_SOC_NOPM, 0, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
 	/* 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),
 
 	SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif2_adc_stereo_mux_control),
 	SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif2_adc_stereo_mux_control),
 
+	/* AIF "ADC" Output Muxes */
+	SND_SOC_DAPM_MUX("AIF3 ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif3_adc_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),
 
 	SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif2_adc_mixer_controls),
@@ -869,16 +968,21 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			      SUN8I_AIF2_DACDAT_CTRL,
 			      SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
 			      sun8i_codec_aif_event,
 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
 			    SUN8I_AIF2_DACDAT_CTRL,
 			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0),
 
+	SND_SOC_DAPM_AIF_IN_E("AIF3 DAC", "AIF3 Playback", 0,
+			      SND_SOC_NOPM, 0, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
 	/* 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),
 
@@ -906,16 +1010,22 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "CLK AIF2", NULL, "AIF2CLK" },
 	{ "CLK AIF2", NULL, "SYSCLK" },
 	{ "RST AIF2", NULL, "CLK AIF2" },
 	{ "AIF2 ADCL", NULL, "RST AIF2" },
 	{ "AIF2 ADCR", NULL, "RST AIF2" },
 	{ "AIF2 DACL", NULL, "RST AIF2" },
 	{ "AIF2 DACR", NULL, "RST AIF2" },
 
+	{ "CLK AIF3", NULL, "AIF1CLK" },
+	{ "CLK AIF3", NULL, "SYSCLK" },
+	{ "RST AIF3", NULL, "CLK AIF3" },
+	{ "AIF3 ADC", NULL, "RST AIF3" },
+	{ "AIF3 DAC", NULL, "RST AIF3" },
+
 	{ "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" },
@@ -925,16 +1035,18 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	/* AIF "ADC" Output Routes */
 	{ "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
 	{ "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
 
 	{ "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
 	{ "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" },
 
+	{ "AIF3 ADC", NULL, "AIF3 ADC Source Capture Route" },
+
 	/* 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" },
 
@@ -954,16 +1066,20 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	{ "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
 
+	/* AIF "ADC" Output Mux Routes */
+	{ "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" },
+	{ "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" },
+
 	/* AIF "ADC" Mixer Routes */
 	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
 	{ "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
 	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
 	{ "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
 
 	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
 	{ "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
@@ -975,20 +1091,22 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
 
 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
 
 	/* AIF "DAC" Input Mux Routes */
 	{ "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
+	{ "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" },
 	{ "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
 
 	{ "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
 	{ "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
+	{ "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" },
 
 	/* 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" },
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 25/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF3
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

AIF3 has some differences from AIF1 and AIF2:
 - It supports mono only
 - It supports master mode only
 - It is not directly connected to any of the mixers; instead all audio
   goes through a mux with AIF2.
 - It does not have its own clock dividers; instead it reuses AIF2 BCLK.
   This means that when both AIF2 and AIF3 are active, they must run at
   the same sample rate and total frame width. Since AIF2 and AIF3 are
   only used for codec2codec DAI links, constraints are not applicable
   here; the only thing we can do when the rates don't match is report
   an error.

Make the necessary adjustments to support this AIF.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 9fa4eca501df..344d9ad85fa6 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -29,21 +29,23 @@
 #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_AIF2				14
+#define SUN8I_MOD_CLK_ENA_AIF3				13
 #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_AIF2				14
+#define SUN8I_MOD_RST_CTL_AIF3				13
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
 #define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
 #define SUN8I_AIF_CLK_CTRL_CLK_INV			13
@@ -84,16 +86,19 @@
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L	15
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L	14
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR	13
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL		12
 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R	11
 #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_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_AIF3_PATH_CTRL				0x0cc
 #define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC		10
 #define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC		8
 #define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI		7
 #define SUN8I_ADC_DIG_CTRL				0x100
 #define SUN8I_ADC_DIG_CTRL_ENAD				15
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS			2
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY			1
@@ -113,16 +118,17 @@
 #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_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
 #define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
 #define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
 #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
 #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK	GENMASK(1, 0)
 
 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
 
 #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
 				 SNDRV_PCM_FMTBIT_S16_LE |\
 				 SNDRV_PCM_FMTBIT_S20_LE |\
 				 SNDRV_PCM_FMTBIT_S24_LE |\
 				 SNDRV_PCM_FMTBIT_S20_3LE|\
@@ -133,20 +139,22 @@
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
 	AIF1,
 	AIF2,
+	AIF3,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
+	unsigned int	lrck_div_order;
 	unsigned int	sample_rate;
 	unsigned int	slots;
 	unsigned int	slot_width;
 	unsigned int	active_streams	: 2;
 	unsigned int	open_streams	: 2;
 };
 
 struct sun8i_codec_quirks {
@@ -264,19 +272,30 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	regmap_update_bits(scodec->regmap, reg,
-			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
-			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
+	if (dai->id == AIF3) {
+		/* AIF3 only supports master mode. */
+		if (value)
+			return -EINVAL;
+
+		/* Use the AIF2 BCLK and LRCK for AIF3. */
+		regmap_update_bits(scodec->regmap, reg,
+				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
+				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
+	} else {
+		regmap_update_bits(scodec->regmap, reg,
+				   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
+				   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
+	}
 
 	/* DAI format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		format = 0x0;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		format = 0x1;
@@ -291,19 +310,25 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	case SND_SOC_DAIFMT_DSP_B:
 		format = 0x3;
 		invert = 0x1; /* Set LRCK_INV to 1 */
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	regmap_update_bits(scodec->regmap, reg,
-			   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
-			   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
+	if (dai->id == AIF3) {
+		/* AIF3 only supports DSP formats. */
+		if (format != 3)
+			return -EINVAL;
+	} else {
+		regmap_update_bits(scodec->regmap, reg,
+				   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
+				   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
+	}
 
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
 	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
 		value = 0x1;
@@ -468,17 +493,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
 	int bclk_div, lrck_div_order, ret, word_size;
-	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
+	u32 div_reg, reg = SUN8I_AIF_CLK_CTRL(dai->id);
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
 		word_size = 0x1;
@@ -497,26 +522,45 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
 			   word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
 
 	/* LRCK divider (BCLK/LRCK ratio) */
 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
-	regmap_update_bits(scodec->regmap, reg,
+	if (dai->id != AIF1) {
+		/* AIF2 and AIF3 share BCLK and LRCK generation circuitry. */
+		int partner = (AIF2 + AIF3) - dai->id;
+		struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner];
+
+		if (partner_aif->open_streams &&
+		    (lrck_div_order != partner_aif->lrck_div_order ||
+		     sample_rate != partner_aif->sample_rate)) {
+			dev_err(dai->dev, "Cannot enable %s: clock rate mismatch! "
+				"AIF2 and AIF3 must use the same sample and bit rates.\n",
+				dai->name);
+			return -EBUSY;
+		}
+
+		div_reg = SUN8I_AIF_CLK_CTRL(AIF2);
+	} else {
+		div_reg = reg;
+	}
+
+	regmap_update_bits(scodec->regmap, div_reg,
 			   SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	if (bclk_div < 0)
 		return bclk_div;
 
-	regmap_update_bits(scodec->regmap, reg,
+	regmap_update_bits(scodec->regmap, div_reg,
 			   SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
 
 	/* SYSCLK rate */
 	if (aif->open_streams) {
 		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
 		if (ret < 0)
 			return ret;
@@ -528,16 +572,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 				dai->name, sample_rate);
 		if (ret < 0)
 			return ret;
 
 		scodec->sysclk_rate = sysclk_rate;
 		scodec->sysclk_refcnt++;
 	}
 
+	aif->lrck_div_order = lrck_div_order;
 	aif->sample_rate = sample_rate;
 	aif->open_streams |= BIT(substream->stream);
 
 	return sun8i_codec_update_sample_rate(scodec);
 }
 
 static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
@@ -546,16 +591,17 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
 	if (aif->open_streams != BIT(substream->stream))
 		goto done;
 
 	scodec->sysclk_refcnt--;
 	clk_rate_exclusive_put(scodec->clk_module);
 
+	aif->lrck_div_order = 0;
 	aif->sample_rate = 0;
 
 done:
 	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
@@ -612,16 +658,41 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
+	{
+		.name	= "sun8i-codec-aif3",
+		.id	= AIF3,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF3 Capture",
+			.channels_min	= 1,
+			.channels_max	= 1,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF3 Playback",
+			.channels_min	= 1,
+			.channels_max	= 1,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
+	},
 };
 
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
 	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
@@ -654,16 +725,29 @@ static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum,
 			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC,
 			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC,
 			    sun8i_aif_stereo_mux_enum_values);
 
 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 const char *const sun8i_aif3_adc_mux_enum_values[] = {
+	"None", "AIF2 ADCL", "AIF2 ADCR"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif3_adc_mux_enum,
+			    SUN8I_AIF3_PATH_CTRL,
+			    SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC,
+			    sun8i_aif3_adc_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif3_adc_mux_control =
+	SOC_DAPM_ENUM("AIF3 ADC Source Capture Route",
+		      sun8i_aif3_adc_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,
@@ -763,30 +847,36 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* 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 AIF2",
 			    SUN8I_MOD_CLK_ENA,
 			    SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLK AIF3",
+			    SUN8I_MOD_CLK_ENA,
+			    SUN8I_MOD_CLK_ENA_AIF3, 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 AIF2",
 			    SUN8I_MOD_RST_CTL,
 			    SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RST AIF3",
+			    SUN8I_MOD_RST_CTL,
+			    SUN8I_MOD_RST_CTL_AIF3, 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 */
@@ -811,27 +901,36 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			       SUN8I_AIF2_ADCDAT_CTRL,
 			       SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
 			       sun8i_codec_aif_event,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
 			     SUN8I_AIF2_ADCDAT_CTRL,
 			     SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0),
 
+	SND_SOC_DAPM_AIF_OUT_E("AIF3 ADC", "AIF3 Capture", 0,
+			       SND_SOC_NOPM, 0, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
 	/* 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),
 
 	SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif2_adc_stereo_mux_control),
 	SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif2_adc_stereo_mux_control),
 
+	/* AIF "ADC" Output Muxes */
+	SND_SOC_DAPM_MUX("AIF3 ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif3_adc_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),
 
 	SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif2_adc_mixer_controls),
@@ -869,16 +968,21 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			      SUN8I_AIF2_DACDAT_CTRL,
 			      SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
 			      sun8i_codec_aif_event,
 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
 			    SUN8I_AIF2_DACDAT_CTRL,
 			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0),
 
+	SND_SOC_DAPM_AIF_IN_E("AIF3 DAC", "AIF3 Playback", 0,
+			      SND_SOC_NOPM, 0, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
 	/* 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),
 
@@ -906,16 +1010,22 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "CLK AIF2", NULL, "AIF2CLK" },
 	{ "CLK AIF2", NULL, "SYSCLK" },
 	{ "RST AIF2", NULL, "CLK AIF2" },
 	{ "AIF2 ADCL", NULL, "RST AIF2" },
 	{ "AIF2 ADCR", NULL, "RST AIF2" },
 	{ "AIF2 DACL", NULL, "RST AIF2" },
 	{ "AIF2 DACR", NULL, "RST AIF2" },
 
+	{ "CLK AIF3", NULL, "AIF1CLK" },
+	{ "CLK AIF3", NULL, "SYSCLK" },
+	{ "RST AIF3", NULL, "CLK AIF3" },
+	{ "AIF3 ADC", NULL, "RST AIF3" },
+	{ "AIF3 DAC", NULL, "RST AIF3" },
+
 	{ "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" },
@@ -925,16 +1035,18 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	/* AIF "ADC" Output Routes */
 	{ "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
 	{ "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
 
 	{ "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
 	{ "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" },
 
+	{ "AIF3 ADC", NULL, "AIF3 ADC Source Capture Route" },
+
 	/* 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" },
 
@@ -954,16 +1066,20 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	{ "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
 
+	/* AIF "ADC" Output Mux Routes */
+	{ "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" },
+	{ "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" },
+
 	/* AIF "ADC" Mixer Routes */
 	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
 	{ "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
 	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
 	{ "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
 
 	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
 	{ "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
@@ -975,20 +1091,22 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
 
 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
 
 	/* AIF "DAC" Input Mux Routes */
 	{ "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
+	{ "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" },
 	{ "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
 
 	{ "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
 	{ "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
+	{ "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" },
 
 	/* 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" },
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH 25/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF3
@ 2020-10-01  2:11   ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-01  2:11 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Maxime Ripard, Chen-Yu Tsai,
	Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel,
	Samuel Holland

AIF3 has some differences from AIF1 and AIF2:
 - It supports mono only
 - It supports master mode only
 - It is not directly connected to any of the mixers; instead all audio
   goes through a mux with AIF2.
 - It does not have its own clock dividers; instead it reuses AIF2 BCLK.
   This means that when both AIF2 and AIF3 are active, they must run at
   the same sample rate and total frame width. Since AIF2 and AIF3 are
   only used for codec2codec DAI links, constraints are not applicable
   here; the only thing we can do when the rates don't match is report
   an error.

Make the necessary adjustments to support this AIF.

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

diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 9fa4eca501df..344d9ad85fa6 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -29,21 +29,23 @@
 #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_AIF2				14
+#define SUN8I_MOD_CLK_ENA_AIF3				13
 #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_AIF2				14
+#define SUN8I_MOD_RST_CTL_AIF3				13
 #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
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
 #define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
 #define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
 #define SUN8I_AIF_CLK_CTRL_CLK_INV			13
@@ -84,16 +86,19 @@
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L	15
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L	14
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR	13
 #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL		12
 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R	11
 #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_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_AIF3_PATH_CTRL				0x0cc
 #define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC		10
 #define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC		8
 #define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI		7
 #define SUN8I_ADC_DIG_CTRL				0x100
 #define SUN8I_ADC_DIG_CTRL_ENAD				15
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS			2
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY			1
@@ -113,16 +118,17 @@
 #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_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
 #define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
 #define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
 #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
 #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK	GENMASK(1, 0)
 
 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
 
 #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
 				 SNDRV_PCM_FMTBIT_S16_LE |\
 				 SNDRV_PCM_FMTBIT_S20_LE |\
 				 SNDRV_PCM_FMTBIT_S24_LE |\
 				 SNDRV_PCM_FMTBIT_S20_3LE|\
@@ -133,20 +139,22 @@
 				 SNDRV_PCM_RATE_96000     |\
 				 SNDRV_PCM_RATE_176400    |\
 				 SNDRV_PCM_RATE_192000    |\
 				 SNDRV_PCM_RATE_KNOT)
 
 enum {
 	AIF1,
 	AIF2,
+	AIF3,
 	NAIFS
 };
 
 struct sun8i_codec_aif {
+	unsigned int	lrck_div_order;
 	unsigned int	sample_rate;
 	unsigned int	slots;
 	unsigned int	slot_width;
 	unsigned int	active_streams	: 2;
 	unsigned int	open_streams	: 2;
 };
 
 struct sun8i_codec_quirks {
@@ -264,19 +272,30 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 		value = 0x0;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	regmap_update_bits(scodec->regmap, reg,
-			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
-			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
+	if (dai->id == AIF3) {
+		/* AIF3 only supports master mode. */
+		if (value)
+			return -EINVAL;
+
+		/* Use the AIF2 BCLK and LRCK for AIF3. */
+		regmap_update_bits(scodec->regmap, reg,
+				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
+				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
+	} else {
+		regmap_update_bits(scodec->regmap, reg,
+				   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
+				   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
+	}
 
 	/* DAI format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		format = 0x0;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		format = 0x1;
@@ -291,19 +310,25 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	case SND_SOC_DAIFMT_DSP_B:
 		format = 0x3;
 		invert = 0x1; /* Set LRCK_INV to 1 */
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	regmap_update_bits(scodec->regmap, reg,
-			   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
-			   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
+	if (dai->id == AIF3) {
+		/* AIF3 only supports DSP formats. */
+		if (format != 3)
+			return -EINVAL;
+	} else {
+		regmap_update_bits(scodec->regmap, reg,
+				   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
+				   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
+	}
 
 	/* clock inversion */
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
 		value = 0x0;
 		break;
 	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
 		value = 0x1;
@@ -468,17 +493,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 	unsigned int sample_rate = params_rate(params);
 	unsigned int slots = aif->slots ?: params_channels(params);
 	unsigned int slot_width = aif->slot_width ?: params_width(params);
 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
 	int bclk_div, lrck_div_order, ret, word_size;
-	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
+	u32 div_reg, reg = SUN8I_AIF_CLK_CTRL(dai->id);
 
 	/* word size */
 	switch (params_width(params)) {
 	case 8:
 		word_size = 0x0;
 		break;
 	case 16:
 		word_size = 0x1;
@@ -497,26 +522,45 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 			   SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
 			   word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
 
 	/* LRCK divider (BCLK/LRCK ratio) */
 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
 	if (lrck_div_order < 0)
 		return lrck_div_order;
 
-	regmap_update_bits(scodec->regmap, reg,
+	if (dai->id != AIF1) {
+		/* AIF2 and AIF3 share BCLK and LRCK generation circuitry. */
+		int partner = (AIF2 + AIF3) - dai->id;
+		struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner];
+
+		if (partner_aif->open_streams &&
+		    (lrck_div_order != partner_aif->lrck_div_order ||
+		     sample_rate != partner_aif->sample_rate)) {
+			dev_err(dai->dev, "Cannot enable %s: clock rate mismatch! "
+				"AIF2 and AIF3 must use the same sample and bit rates.\n",
+				dai->name);
+			return -EBUSY;
+		}
+
+		div_reg = SUN8I_AIF_CLK_CTRL(AIF2);
+	} else {
+		div_reg = reg;
+	}
+
+	regmap_update_bits(scodec->regmap, div_reg,
 			   SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
 			   (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
 
 	/* BCLK divider (SYSCLK/BCLK ratio) */
 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
 	if (bclk_div < 0)
 		return bclk_div;
 
-	regmap_update_bits(scodec->regmap, reg,
+	regmap_update_bits(scodec->regmap, div_reg,
 			   SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
 			   bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
 
 	/* SYSCLK rate */
 	if (aif->open_streams) {
 		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
 		if (ret < 0)
 			return ret;
@@ -528,16 +572,17 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 				dai->name, sample_rate);
 		if (ret < 0)
 			return ret;
 
 		scodec->sysclk_rate = sysclk_rate;
 		scodec->sysclk_refcnt++;
 	}
 
+	aif->lrck_div_order = lrck_div_order;
 	aif->sample_rate = sample_rate;
 	aif->open_streams |= BIT(substream->stream);
 
 	return sun8i_codec_update_sample_rate(scodec);
 }
 
 static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
@@ -546,16 +591,17 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
 	if (aif->open_streams != BIT(substream->stream))
 		goto done;
 
 	scodec->sysclk_refcnt--;
 	clk_rate_exclusive_put(scodec->clk_module);
 
+	aif->lrck_div_order = 0;
 	aif->sample_rate = 0;
 
 done:
 	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
@@ -612,16 +658,41 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.channels_max	= 2,
 			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
 		.symmetric_rates	= true,
 		.symmetric_channels	= true,
 		.symmetric_samplebits	= true,
 	},
+	{
+		.name	= "sun8i-codec-aif3",
+		.id	= AIF3,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF3 Capture",
+			.channels_min	= 1,
+			.channels_max	= 1,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF3 Playback",
+			.channels_min	= 1,
+			.channels_max	= 1,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
+	},
 };
 
 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
 	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
@@ -654,16 +725,29 @@ static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum,
 			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC,
 			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC,
 			    sun8i_aif_stereo_mux_enum_values);
 
 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 const char *const sun8i_aif3_adc_mux_enum_values[] = {
+	"None", "AIF2 ADCL", "AIF2 ADCR"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif3_adc_mux_enum,
+			    SUN8I_AIF3_PATH_CTRL,
+			    SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC,
+			    sun8i_aif3_adc_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif3_adc_mux_control =
+	SOC_DAPM_ENUM("AIF3 ADC Source Capture Route",
+		      sun8i_aif3_adc_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,
@@ -763,30 +847,36 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 
 	/* 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 AIF2",
 			    SUN8I_MOD_CLK_ENA,
 			    SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLK AIF3",
+			    SUN8I_MOD_CLK_ENA,
+			    SUN8I_MOD_CLK_ENA_AIF3, 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 AIF2",
 			    SUN8I_MOD_RST_CTL,
 			    SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RST AIF3",
+			    SUN8I_MOD_RST_CTL,
+			    SUN8I_MOD_RST_CTL_AIF3, 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 */
@@ -811,27 +901,36 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			       SUN8I_AIF2_ADCDAT_CTRL,
 			       SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
 			       sun8i_codec_aif_event,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
 			     SUN8I_AIF2_ADCDAT_CTRL,
 			     SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0),
 
+	SND_SOC_DAPM_AIF_OUT_E("AIF3 ADC", "AIF3 Capture", 0,
+			       SND_SOC_NOPM, 0, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
 	/* 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),
 
 	SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif2_adc_stereo_mux_control),
 	SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif2_adc_stereo_mux_control),
 
+	/* AIF "ADC" Output Muxes */
+	SND_SOC_DAPM_MUX("AIF3 ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif3_adc_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),
 
 	SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif2_adc_mixer_controls),
@@ -869,16 +968,21 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			      SUN8I_AIF2_DACDAT_CTRL,
 			      SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
 			      sun8i_codec_aif_event,
 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
 			    SUN8I_AIF2_DACDAT_CTRL,
 			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0),
 
+	SND_SOC_DAPM_AIF_IN_E("AIF3 DAC", "AIF3 Playback", 0,
+			      SND_SOC_NOPM, 0, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
 	/* 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),
 
@@ -906,16 +1010,22 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "CLK AIF2", NULL, "AIF2CLK" },
 	{ "CLK AIF2", NULL, "SYSCLK" },
 	{ "RST AIF2", NULL, "CLK AIF2" },
 	{ "AIF2 ADCL", NULL, "RST AIF2" },
 	{ "AIF2 ADCR", NULL, "RST AIF2" },
 	{ "AIF2 DACL", NULL, "RST AIF2" },
 	{ "AIF2 DACR", NULL, "RST AIF2" },
 
+	{ "CLK AIF3", NULL, "AIF1CLK" },
+	{ "CLK AIF3", NULL, "SYSCLK" },
+	{ "RST AIF3", NULL, "CLK AIF3" },
+	{ "AIF3 ADC", NULL, "RST AIF3" },
+	{ "AIF3 DAC", NULL, "RST AIF3" },
+
 	{ "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" },
@@ -925,16 +1035,18 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	/* AIF "ADC" Output Routes */
 	{ "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
 	{ "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
 
 	{ "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
 	{ "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" },
 
+	{ "AIF3 ADC", NULL, "AIF3 ADC Source Capture Route" },
+
 	/* 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" },
 
@@ -954,16 +1066,20 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 
 	{ "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
 	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
 
+	/* AIF "ADC" Output Mux Routes */
+	{ "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" },
+	{ "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" },
+
 	/* AIF "ADC" Mixer Routes */
 	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
 	{ "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
 	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
 	{ "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
 
 	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
 	{ "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
@@ -975,20 +1091,22 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
 
 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
 
 	/* AIF "DAC" Input Mux Routes */
 	{ "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
+	{ "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" },
 	{ "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
 
 	{ "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
 	{ "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
+	{ "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" },
 
 	/* 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" },
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
  2020-10-01  2:11   ` Samuel Holland
  (?)
  (?)
@ 2020-10-01 13:27     ` kernel test robot
  -1 siblings, 0 replies; 181+ messages in thread
From: kernel test robot @ 2020-10-01 13:27 UTC (permalink / raw)
  To: Samuel Holland, Mark Brown, Liam Girdwood, Maxime Ripard,
	Chen-Yu Tsai, Jaroslav Kysela, Takashi Iwai
  Cc: kbuild-all, Ondrej Jirman, alsa-devel, linux-arm-kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2030 bytes --]

Hi Samuel,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on asoc/for-next]
[also build test ERROR on next-20200930]
[cannot apply to sunxi/sunxi/for-next v5.9-rc7]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Samuel-Holland/ASoC-sun8i-codec-support-for-AIF2-and-AIF3/20201001-101451
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/6a43c578b796aed3cd013c065ef444fa82b24fce
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Samuel-Holland/ASoC-sun8i-codec-support-for-AIF2-and-AIF3/20201001-101451
        git checkout 6a43c578b796aed3cd013c065ef444fa82b24fce
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=sh 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "clk_set_rate_exclusive" [sound/soc/sunxi/sun8i-codec.ko] undefined!
>> ERROR: modpost: "clk_rate_exclusive_put" [sound/soc/sunxi/sun8i-codec.ko] undefined!
ERROR: modpost: "of_clk_add_hw_provider" [sound/soc/qcom/qdsp6/q6afe-clocks.ko] undefined!
ERROR: modpost: "devm_clk_hw_register" [sound/soc/qcom/qdsp6/q6afe-clocks.ko] undefined!
ERROR: modpost: "__delay" [drivers/net/phy/mdio-cavium.ko] undefined!

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 52745 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-01 13:27     ` kernel test robot
  0 siblings, 0 replies; 181+ messages in thread
From: kernel test robot @ 2020-10-01 13:27 UTC (permalink / raw)
  To: Samuel Holland, Mark Brown, Liam Girdwood, Maxime Ripard,
	Chen-Yu Tsai, Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, kbuild-all, linux-kernel, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 2030 bytes --]

Hi Samuel,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on asoc/for-next]
[also build test ERROR on next-20200930]
[cannot apply to sunxi/sunxi/for-next v5.9-rc7]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Samuel-Holland/ASoC-sun8i-codec-support-for-AIF2-and-AIF3/20201001-101451
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/6a43c578b796aed3cd013c065ef444fa82b24fce
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Samuel-Holland/ASoC-sun8i-codec-support-for-AIF2-and-AIF3/20201001-101451
        git checkout 6a43c578b796aed3cd013c065ef444fa82b24fce
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=sh 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "clk_set_rate_exclusive" [sound/soc/sunxi/sun8i-codec.ko] undefined!
>> ERROR: modpost: "clk_rate_exclusive_put" [sound/soc/sunxi/sun8i-codec.ko] undefined!
ERROR: modpost: "of_clk_add_hw_provider" [sound/soc/qcom/qdsp6/q6afe-clocks.ko] undefined!
ERROR: modpost: "devm_clk_hw_register" [sound/soc/qcom/qdsp6/q6afe-clocks.ko] undefined!
ERROR: modpost: "__delay" [drivers/net/phy/mdio-cavium.ko] undefined!

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 52745 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-01 13:27     ` kernel test robot
  0 siblings, 0 replies; 181+ messages in thread
From: kernel test robot @ 2020-10-01 13:27 UTC (permalink / raw)
  To: Samuel Holland, Mark Brown, Liam Girdwood, Maxime Ripard,
	Chen-Yu Tsai, Jaroslav Kysela, Takashi Iwai
  Cc: Ondrej Jirman, alsa-devel, kbuild-all, linux-kernel, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 2030 bytes --]

Hi Samuel,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on asoc/for-next]
[also build test ERROR on next-20200930]
[cannot apply to sunxi/sunxi/for-next v5.9-rc7]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Samuel-Holland/ASoC-sun8i-codec-support-for-AIF2-and-AIF3/20201001-101451
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/6a43c578b796aed3cd013c065ef444fa82b24fce
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Samuel-Holland/ASoC-sun8i-codec-support-for-AIF2-and-AIF3/20201001-101451
        git checkout 6a43c578b796aed3cd013c065ef444fa82b24fce
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=sh 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "clk_set_rate_exclusive" [sound/soc/sunxi/sun8i-codec.ko] undefined!
>> ERROR: modpost: "clk_rate_exclusive_put" [sound/soc/sunxi/sun8i-codec.ko] undefined!
ERROR: modpost: "of_clk_add_hw_provider" [sound/soc/qcom/qdsp6/q6afe-clocks.ko] undefined!
ERROR: modpost: "devm_clk_hw_register" [sound/soc/qcom/qdsp6/q6afe-clocks.ko] undefined!
ERROR: modpost: "__delay" [drivers/net/phy/mdio-cavium.ko] undefined!

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 52745 bytes --]

[-- Attachment #3: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-01 13:27     ` kernel test robot
  0 siblings, 0 replies; 181+ messages in thread
From: kernel test robot @ 2020-10-01 13:27 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2071 bytes --]

Hi Samuel,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on asoc/for-next]
[also build test ERROR on next-20200930]
[cannot apply to sunxi/sunxi/for-next v5.9-rc7]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Samuel-Holland/ASoC-sun8i-codec-support-for-AIF2-and-AIF3/20201001-101451
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/6a43c578b796aed3cd013c065ef444fa82b24fce
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Samuel-Holland/ASoC-sun8i-codec-support-for-AIF2-and-AIF3/20201001-101451
        git checkout 6a43c578b796aed3cd013c065ef444fa82b24fce
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=sh 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "clk_set_rate_exclusive" [sound/soc/sunxi/sun8i-codec.ko] undefined!
>> ERROR: modpost: "clk_rate_exclusive_put" [sound/soc/sunxi/sun8i-codec.ko] undefined!
ERROR: modpost: "of_clk_add_hw_provider" [sound/soc/qcom/qdsp6/q6afe-clocks.ko] undefined!
ERROR: modpost: "devm_clk_hw_register" [sound/soc/qcom/qdsp6/q6afe-clocks.ko] undefined!
ERROR: modpost: "__delay" [drivers/net/phy/mdio-cavium.ko] undefined!

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 52745 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 01/25] ASoC: sun8i-codec: Set up clock tree at probe time
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05  9:53     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:53 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1431 bytes --]

On Wed, Sep 30, 2020 at 09:11:24PM -0500, Samuel Holland wrote:
> The sun8i codec is effectively an on-die variant of the X-Powers AC100
> codec. The AC100 can derive its clocks from either of two I2S master
> clocks or an internal PLL. For the on-die variant, Allwinner replaced
> the codec's own PLL with a connection to SoC's existing PLL_AUDIO, and
> they connected both I2S MCLK inputs to the same source -- which happens
> to be an integer divider from the same PLL_AUDIO.
> 
> So there's actually no clocking flexibility. To run SYSCLK at the
> required rate, it must be run straight from the PLL. The only choice is
> whether it goes through AIF1CLK or AIF2CLK. Since both run at the same
> rate, the only effect of that choice is which field in SYS_SR_CTRL
> (AIF1_FS or AIF2_FS) controls the system sample rate.
> 
> Since AIFnCLK is required to bring up the corresponding DAI, and AIF1
> (connected to the CPU) is used most often, let's use AIF1CLK as the
> SYSCLK parent. That means we no longer need to set AIF2_FS.
> 
> Since this clock tree never changes, we can program it from the
> component probe function, instead of using DAPM widgets. The DAPM
> widgets unnecessarily change clock parents when the codec goes in/out
> of idle and the supply widgets are powered up/down.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 01/25] ASoC: sun8i-codec: Set up clock tree at probe time
@ 2020-10-05  9:53     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:53 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 1431 bytes --]

On Wed, Sep 30, 2020 at 09:11:24PM -0500, Samuel Holland wrote:
> The sun8i codec is effectively an on-die variant of the X-Powers AC100
> codec. The AC100 can derive its clocks from either of two I2S master
> clocks or an internal PLL. For the on-die variant, Allwinner replaced
> the codec's own PLL with a connection to SoC's existing PLL_AUDIO, and
> they connected both I2S MCLK inputs to the same source -- which happens
> to be an integer divider from the same PLL_AUDIO.
> 
> So there's actually no clocking flexibility. To run SYSCLK at the
> required rate, it must be run straight from the PLL. The only choice is
> whether it goes through AIF1CLK or AIF2CLK. Since both run at the same
> rate, the only effect of that choice is which field in SYS_SR_CTRL
> (AIF1_FS or AIF2_FS) controls the system sample rate.
> 
> Since AIFnCLK is required to bring up the corresponding DAI, and AIF1
> (connected to the CPU) is used most often, let's use AIF1CLK as the
> SYSCLK parent. That means we no longer need to set AIF2_FS.
> 
> Since this clock tree never changes, we can program it from the
> component probe function, instead of using DAPM widgets. The DAPM
> widgets unnecessarily change clock parents when the codec goes in/out
> of idle and the supply widgets are powered up/down.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 01/25] ASoC: sun8i-codec: Set up clock tree at probe time
@ 2020-10-05  9:53     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:53 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 1431 bytes --]

On Wed, Sep 30, 2020 at 09:11:24PM -0500, Samuel Holland wrote:
> The sun8i codec is effectively an on-die variant of the X-Powers AC100
> codec. The AC100 can derive its clocks from either of two I2S master
> clocks or an internal PLL. For the on-die variant, Allwinner replaced
> the codec's own PLL with a connection to SoC's existing PLL_AUDIO, and
> they connected both I2S MCLK inputs to the same source -- which happens
> to be an integer divider from the same PLL_AUDIO.
> 
> So there's actually no clocking flexibility. To run SYSCLK at the
> required rate, it must be run straight from the PLL. The only choice is
> whether it goes through AIF1CLK or AIF2CLK. Since both run at the same
> rate, the only effect of that choice is which field in SYS_SR_CTRL
> (AIF1_FS or AIF2_FS) controls the system sample rate.
> 
> Since AIFnCLK is required to bring up the corresponding DAI, and AIF1
> (connected to the CPU) is used most often, let's use AIF1CLK as the
> SYSCLK parent. That means we no longer need to set AIF2_FS.
> 
> Since this clock tree never changes, we can program it from the
> component probe function, instead of using DAPM widgets. The DAPM
> widgets unnecessarily change clock parents when the codec goes in/out
> of idle and the supply widgets are powered up/down.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 02/25] ASoC: sun8i-codec: Swap module clock/reset dependencies
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05  9:54     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:54 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 563 bytes --]

On Wed, Sep 30, 2020 at 09:11:25PM -0500, Samuel Holland wrote:
> This matches the module power-up/down sequence from the vendor's driver.
> 
> While updating these widgets/routes, reorder them to match the register
> and bit layout of the hardware. This puts them in the same place in the
> widget and route arrays (previously they were at opposite ends), and it
> makes it easier to track which parts of which registers are implemented.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 02/25] ASoC: sun8i-codec: Swap module clock/reset dependencies
@ 2020-10-05  9:54     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:54 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 563 bytes --]

On Wed, Sep 30, 2020 at 09:11:25PM -0500, Samuel Holland wrote:
> This matches the module power-up/down sequence from the vendor's driver.
> 
> While updating these widgets/routes, reorder them to match the register
> and bit layout of the hardware. This puts them in the same place in the
> widget and route arrays (previously they were at opposite ends), and it
> makes it easier to track which parts of which registers are implemented.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 02/25] ASoC: sun8i-codec: Swap module clock/reset dependencies
@ 2020-10-05  9:54     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:54 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 563 bytes --]

On Wed, Sep 30, 2020 at 09:11:25PM -0500, Samuel Holland wrote:
> This matches the module power-up/down sequence from the vendor's driver.
> 
> While updating these widgets/routes, reorder them to match the register
> and bit layout of the hardware. This puts them in the same place in the
> widget and route arrays (previously they were at opposite ends), and it
> makes it easier to track which parts of which registers are implemented.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 03/25] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05  9:54     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:54 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 653 bytes --]

On Wed, Sep 30, 2020 at 09:11:26PM -0500, Samuel Holland wrote:
> Sort the remaining pieces of the DAPM driver so that they are all in the
> same order among controls/widgets/routes, and so they roughly match the
> register word and bit order of the hardware. This nicely separates the
> AIF-related widgets from the ADC/DAC widgets, which allows the AIF
> widgets to stay in a logical order as more AIFs are added to the driver.
> 
> No widgets are renamed, to ease verification that this commit makes no
> functional change.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 03/25] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
@ 2020-10-05  9:54     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:54 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 653 bytes --]

On Wed, Sep 30, 2020 at 09:11:26PM -0500, Samuel Holland wrote:
> Sort the remaining pieces of the DAPM driver so that they are all in the
> same order among controls/widgets/routes, and so they roughly match the
> register word and bit order of the hardware. This nicely separates the
> AIF-related widgets from the ADC/DAC widgets, which allows the AIF
> widgets to stay in a logical order as more AIFs are added to the driver.
> 
> No widgets are renamed, to ease verification that this commit makes no
> functional change.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 03/25] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
@ 2020-10-05  9:54     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:54 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 653 bytes --]

On Wed, Sep 30, 2020 at 09:11:26PM -0500, Samuel Holland wrote:
> Sort the remaining pieces of the DAPM driver so that they are all in the
> same order among controls/widgets/routes, and so they roughly match the
> register word and bit order of the hardware. This nicely separates the
> AIF-related widgets from the ADC/DAC widgets, which allows the AIF
> widgets to stay in a logical order as more AIFs are added to the driver.
> 
> No widgets are renamed, to ease verification that this commit makes no
> functional change.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 04/25] ASoC: sun8i-codec: Consistently name DAPM widgets and routes
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05  9:57     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:57 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 534 bytes --]

On Wed, Sep 30, 2020 at 09:11:27PM -0500, Samuel Holland wrote:
> This cleans up the mixer widget names. The AIF1 AD0 Mixer names were
> previously wrong -- they do not control the digital side of the ADC. The
> DAC mixer widgets were not wrong, but they were verbose and did not
> match the naming scheme of the other widgets.
> 
> The mixer controls are not renamed because they are exposed to
> userspace.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 04/25] ASoC: sun8i-codec: Consistently name DAPM widgets and routes
@ 2020-10-05  9:57     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:57 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 534 bytes --]

On Wed, Sep 30, 2020 at 09:11:27PM -0500, Samuel Holland wrote:
> This cleans up the mixer widget names. The AIF1 AD0 Mixer names were
> previously wrong -- they do not control the digital side of the ADC. The
> DAC mixer widgets were not wrong, but they were verbose and did not
> match the naming scheme of the other widgets.
> 
> The mixer controls are not renamed because they are exposed to
> userspace.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 04/25] ASoC: sun8i-codec: Consistently name DAPM widgets and routes
@ 2020-10-05  9:57     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:57 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 534 bytes --]

On Wed, Sep 30, 2020 at 09:11:27PM -0500, Samuel Holland wrote:
> This cleans up the mixer widget names. The AIF1 AD0 Mixer names were
> previously wrong -- they do not control the digital side of the ADC. The
> DAC mixer widgets were not wrong, but they were verbose and did not
> match the naming scheme of the other widgets.
> 
> The mixer controls are not renamed because they are exposed to
> userspace.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 05/25] ASoC: sun8i-codec: Correct DAPM widget types
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05  9:57     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:57 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

On Wed, Sep 30, 2020 at 09:11:28PM -0500, Samuel Holland wrote:
> Whie the aif_in and aif_out widget types are handled exactly the same in
> the core DAPM code, a future widget event hook will need the correct
> widget type to derive the associated substream. Clean up the widget type
> for that reason, and so these widgets will match newly-added widgets for
> the other AIFs.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 05/25] ASoC: sun8i-codec: Correct DAPM widget types
@ 2020-10-05  9:57     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:57 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

On Wed, Sep 30, 2020 at 09:11:28PM -0500, Samuel Holland wrote:
> Whie the aif_in and aif_out widget types are handled exactly the same in
> the core DAPM code, a future widget event hook will need the correct
> widget type to derive the associated substream. Clean up the widget type
> for that reason, and so these widgets will match newly-added widgets for
> the other AIFs.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 05/25] ASoC: sun8i-codec: Correct DAPM widget types
@ 2020-10-05  9:57     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05  9:57 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 501 bytes --]

On Wed, Sep 30, 2020 at 09:11:28PM -0500, Samuel Holland wrote:
> Whie the aif_in and aif_out widget types are handled exactly the same in
> the core DAPM code, a future widget event hook will need the correct
> widget type to derive the associated substream. Clean up the widget type
> for that reason, and so these widgets will match newly-added widgets for
> the other AIFs.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 07/25] ASoC: sun8i-codec: Enable AIF mono/stereo control
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 10:00     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 10:00 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 453 bytes --]

On Wed, Sep 30, 2020 at 09:11:30PM -0500, Samuel Holland wrote:
> Each left/right pair of AIF input/output channels can be swapped or
> combined. This is useful for sending a mono audio source to both sides
> of a stereo sink, or for creating complex mixing scenarios.
> 
> Add the support to control this feature from userspace.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 07/25] ASoC: sun8i-codec: Enable AIF mono/stereo control
@ 2020-10-05 10:00     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 10:00 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 453 bytes --]

On Wed, Sep 30, 2020 at 09:11:30PM -0500, Samuel Holland wrote:
> Each left/right pair of AIF input/output channels can be swapped or
> combined. This is useful for sending a mono audio source to both sides
> of a stereo sink, or for creating complex mixing scenarios.
> 
> Add the support to control this feature from userspace.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 07/25] ASoC: sun8i-codec: Enable AIF mono/stereo control
@ 2020-10-05 10:00     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 10:00 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 453 bytes --]

On Wed, Sep 30, 2020 at 09:11:30PM -0500, Samuel Holland wrote:
> Each left/right pair of AIF input/output channels can be swapped or
> combined. This is useful for sending a mono audio source to both sides
> of a stereo sink, or for creating complex mixing scenarios.
> 
> Add the support to control this feature from userspace.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 06/25] ASoC: sun8i-codec: Fix AIF widget channel references
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 10:00     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 10:00 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 363 bytes --]

On Wed, Sep 30, 2020 at 09:11:29PM -0500, Samuel Holland wrote:
> Both the left and right side widgets referenced channel 0. This would
> unnecessarily power on the right side widget (and its associated path)
> when a mono stream was active.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 06/25] ASoC: sun8i-codec: Fix AIF widget channel references
@ 2020-10-05 10:00     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 10:00 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 363 bytes --]

On Wed, Sep 30, 2020 at 09:11:29PM -0500, Samuel Holland wrote:
> Both the left and right side widgets referenced channel 0. This would
> unnecessarily power on the right side widget (and its associated path)
> when a mono stream was active.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 06/25] ASoC: sun8i-codec: Fix AIF widget channel references
@ 2020-10-05 10:00     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 10:00 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 363 bytes --]

On Wed, Sep 30, 2020 at 09:11:29PM -0500, Samuel Holland wrote:
> Both the left and right side widgets referenced channel 0. This would
> unnecessarily power on the right side widget (and its associated path)
> when a mono stream was active.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 08/25] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 10:01     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 10:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 328 bytes --]

On Wed, Sep 30, 2020 at 09:11:31PM -0500, Samuel Holland wrote:
> Remove a level of indirection by getting the device directly from the
> passed-in struct snd_soc_dai, instead of going through its component.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 08/25] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
@ 2020-10-05 10:01     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 10:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 328 bytes --]

On Wed, Sep 30, 2020 at 09:11:31PM -0500, Samuel Holland wrote:
> Remove a level of indirection by getting the device directly from the
> passed-in struct snd_soc_dai, instead of going through its component.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 08/25] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
@ 2020-10-05 10:01     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 10:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 328 bytes --]

On Wed, Sep 30, 2020 at 09:11:31PM -0500, Samuel Holland wrote:
> Remove a level of indirection by getting the device directly from the
> passed-in struct snd_soc_dai, instead of going through its component.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 09/25] ASoC: sun8i-codec: Prepare to extend the DAI driver
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:24     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:24 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1765 bytes --]

Hi,

On Wed, Sep 30, 2020 at 09:11:32PM -0500, Samuel Holland wrote:
> In preparation for adding additional DAIs to this component, convert the
> DAI driver definition to an array. Since this changes all of the lines
> in the definition anyway, let's move it closer to the ops function
> definitions, instead of on the far side of the DAPM arrays. And while
> moving the DAI driver ops, rename the set_fmt hook to match the usual
> naming scheme.
> 
> Give the existing DAI an explicit ID and more meaningful stream names,
> so it will remain unique as more DAIs are added. The AIF widget streams
> must be updated to match.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 76 +++++++++++++++++++----------------
>  1 file changed, 42 insertions(+), 34 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 7590c4b04d14..346f699c2e86 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -90,16 +90,21 @@
>  #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_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)
>  
> +enum {
> +	AIF1,
> +	NAIFS
> +};
> +

It's a bit of a nitpick, but we should have less generic names for the
enums here, maybe prefix it with sun8i_codec like the rest of the driver?

Once fixed,
Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 09/25] ASoC: sun8i-codec: Prepare to extend the DAI driver
@ 2020-10-05 11:24     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:24 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 1765 bytes --]

Hi,

On Wed, Sep 30, 2020 at 09:11:32PM -0500, Samuel Holland wrote:
> In preparation for adding additional DAIs to this component, convert the
> DAI driver definition to an array. Since this changes all of the lines
> in the definition anyway, let's move it closer to the ops function
> definitions, instead of on the far side of the DAPM arrays. And while
> moving the DAI driver ops, rename the set_fmt hook to match the usual
> naming scheme.
> 
> Give the existing DAI an explicit ID and more meaningful stream names,
> so it will remain unique as more DAIs are added. The AIF widget streams
> must be updated to match.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 76 +++++++++++++++++++----------------
>  1 file changed, 42 insertions(+), 34 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 7590c4b04d14..346f699c2e86 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -90,16 +90,21 @@
>  #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_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)
>  
> +enum {
> +	AIF1,
> +	NAIFS
> +};
> +

It's a bit of a nitpick, but we should have less generic names for the
enums here, maybe prefix it with sun8i_codec like the rest of the driver?

Once fixed,
Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 09/25] ASoC: sun8i-codec: Prepare to extend the DAI driver
@ 2020-10-05 11:24     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:24 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 1765 bytes --]

Hi,

On Wed, Sep 30, 2020 at 09:11:32PM -0500, Samuel Holland wrote:
> In preparation for adding additional DAIs to this component, convert the
> DAI driver definition to an array. Since this changes all of the lines
> in the definition anyway, let's move it closer to the ops function
> definitions, instead of on the far side of the DAPM arrays. And while
> moving the DAI driver ops, rename the set_fmt hook to match the usual
> naming scheme.
> 
> Give the existing DAI an explicit ID and more meaningful stream names,
> so it will remain unique as more DAIs are added. The AIF widget streams
> must be updated to match.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 76 +++++++++++++++++++----------------
>  1 file changed, 42 insertions(+), 34 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 7590c4b04d14..346f699c2e86 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -90,16 +90,21 @@
>  #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_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)
>  
> +enum {
> +	AIF1,
> +	NAIFS
> +};
> +

It's a bit of a nitpick, but we should have less generic names for the
enums here, maybe prefix it with sun8i_codec like the rest of the driver?

Once fixed,
Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 10/25] ASoC: sun8i-codec: Program format before clock inversion
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:26     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:26 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 451 bytes --]

On Wed, Sep 30, 2020 at 09:11:33PM -0500, Samuel Holland wrote:
> The LRCK inversion bit has a different meaning in DSP mode: it selects
> between DSP A and DSP B formats. To support this, we need to know if
> the selected format is a DSP format. One easy way to do this is to set
> the format field before the inversion fields.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 10/25] ASoC: sun8i-codec: Program format before clock inversion
@ 2020-10-05 11:26     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:26 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 451 bytes --]

On Wed, Sep 30, 2020 at 09:11:33PM -0500, Samuel Holland wrote:
> The LRCK inversion bit has a different meaning in DSP mode: it selects
> between DSP A and DSP B formats. To support this, we need to know if
> the selected format is a DSP format. One easy way to do this is to set
> the format field before the inversion fields.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 10/25] ASoC: sun8i-codec: Program format before clock inversion
@ 2020-10-05 11:26     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:26 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 451 bytes --]

On Wed, Sep 30, 2020 at 09:11:33PM -0500, Samuel Holland wrote:
> The LRCK inversion bit has a different meaning in DSP mode: it selects
> between DSP A and DSP B formats. To support this, we need to know if
> the selected format is a DSP format. One easy way to do this is to set
> the format field before the inversion fields.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:30     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:30 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 5237 bytes --]

On Wed, Sep 30, 2020 at 09:11:34PM -0500, Samuel Holland wrote:
> When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
> independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
> LRCK inversion is not supported. The register bit is repurposed to
> select between DSP_A and DSP_B. Extend the driver to support this.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 57 +++++++++++++++++++++++------------
>  1 file changed, 37 insertions(+), 20 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 0b713b2a2028..506420fb355c 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -39,18 +39,17 @@
>  #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
>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
>  #define SUN8I_AIF1CLK_CTRL				0x040
>  #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
> +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
>  #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
>  #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
>  #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_AD0L_ENA		15
>  #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
> @@ -85,16 +84,17 @@
>  #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_CLK_INV_MASK	GENMASK(14, 13)
>  #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)
>  
>  enum {
>  	AIF1,
>  	NAIFS
> @@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
>  	default:
>  		return -EINVAL;
>  	}
>  }
>  
>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>  {
>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> -	u32 format, value;
> +	u32 format, invert, value;
>  
>  	/* clock masters */
>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>  		value = 0x1;
>  		break;
>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>  		value = 0x0;
> @@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>  		break;
>  	case SND_SOC_DAIFMT_LEFT_J:
>  		format = 0x1;
>  		break;
>  	case SND_SOC_DAIFMT_RIGHT_J:
>  		format = 0x2;
>  		break;
>  	case SND_SOC_DAIFMT_DSP_A:
> +		format = 0x3;
> +		invert = 0x0; /* Set LRCK_INV to 0 */
> +		break;
>  	case SND_SOC_DAIFMT_DSP_B:
>  		format = 0x3;
> +		invert = 0x1; /* Set LRCK_INV to 1 */
>  		break;
>  	default:
>  		return -EINVAL;
>  	}
>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>  			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
>  			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
>  
>  	/* clock inversion */
>  	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
>  	case SND_SOC_DAIFMT_NB_NF: /* Normal */
>  		value = 0x0;
>  		break;
> -	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
> +	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
>  		value = 0x1;
>  		break;
> +	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
> +		value = 0x2;
> +		break;
> +	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
> +		value = 0x3;
> +		break;
>  	default:
>  		return -EINVAL;
>  	}
> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
>  
> -	/*
> -	 * 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;
> +	if (format == 0x3) {

Could we use a define here? That would be more readable

> +		/* Inverted LRCK is not available in DSP mode. */
> +		if (value & BIT(0))
> +			return -EINVAL;

And same thing here, explicitly testing both for DSP_A and DSP_B would
be more readable.

(And I guess value isn't such a great variable name anymore either)

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
@ 2020-10-05 11:30     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:30 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 5237 bytes --]

On Wed, Sep 30, 2020 at 09:11:34PM -0500, Samuel Holland wrote:
> When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
> independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
> LRCK inversion is not supported. The register bit is repurposed to
> select between DSP_A and DSP_B. Extend the driver to support this.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 57 +++++++++++++++++++++++------------
>  1 file changed, 37 insertions(+), 20 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 0b713b2a2028..506420fb355c 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -39,18 +39,17 @@
>  #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
>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
>  #define SUN8I_AIF1CLK_CTRL				0x040
>  #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
> +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
>  #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
>  #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
>  #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_AD0L_ENA		15
>  #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
> @@ -85,16 +84,17 @@
>  #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_CLK_INV_MASK	GENMASK(14, 13)
>  #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)
>  
>  enum {
>  	AIF1,
>  	NAIFS
> @@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
>  	default:
>  		return -EINVAL;
>  	}
>  }
>  
>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>  {
>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> -	u32 format, value;
> +	u32 format, invert, value;
>  
>  	/* clock masters */
>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>  		value = 0x1;
>  		break;
>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>  		value = 0x0;
> @@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>  		break;
>  	case SND_SOC_DAIFMT_LEFT_J:
>  		format = 0x1;
>  		break;
>  	case SND_SOC_DAIFMT_RIGHT_J:
>  		format = 0x2;
>  		break;
>  	case SND_SOC_DAIFMT_DSP_A:
> +		format = 0x3;
> +		invert = 0x0; /* Set LRCK_INV to 0 */
> +		break;
>  	case SND_SOC_DAIFMT_DSP_B:
>  		format = 0x3;
> +		invert = 0x1; /* Set LRCK_INV to 1 */
>  		break;
>  	default:
>  		return -EINVAL;
>  	}
>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>  			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
>  			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
>  
>  	/* clock inversion */
>  	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
>  	case SND_SOC_DAIFMT_NB_NF: /* Normal */
>  		value = 0x0;
>  		break;
> -	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
> +	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
>  		value = 0x1;
>  		break;
> +	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
> +		value = 0x2;
> +		break;
> +	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
> +		value = 0x3;
> +		break;
>  	default:
>  		return -EINVAL;
>  	}
> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
>  
> -	/*
> -	 * 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;
> +	if (format == 0x3) {

Could we use a define here? That would be more readable

> +		/* Inverted LRCK is not available in DSP mode. */
> +		if (value & BIT(0))
> +			return -EINVAL;

And same thing here, explicitly testing both for DSP_A and DSP_B would
be more readable.

(And I guess value isn't such a great variable name anymore either)

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
@ 2020-10-05 11:30     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:30 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 5237 bytes --]

On Wed, Sep 30, 2020 at 09:11:34PM -0500, Samuel Holland wrote:
> When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
> independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
> LRCK inversion is not supported. The register bit is repurposed to
> select between DSP_A and DSP_B. Extend the driver to support this.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 57 +++++++++++++++++++++++------------
>  1 file changed, 37 insertions(+), 20 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 0b713b2a2028..506420fb355c 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -39,18 +39,17 @@
>  #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
>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
>  #define SUN8I_AIF1CLK_CTRL				0x040
>  #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
> +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
>  #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
>  #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
>  #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_AD0L_ENA		15
>  #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
> @@ -85,16 +84,17 @@
>  #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_CLK_INV_MASK	GENMASK(14, 13)
>  #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)
>  
>  enum {
>  	AIF1,
>  	NAIFS
> @@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
>  	default:
>  		return -EINVAL;
>  	}
>  }
>  
>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>  {
>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> -	u32 format, value;
> +	u32 format, invert, value;
>  
>  	/* clock masters */
>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>  		value = 0x1;
>  		break;
>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>  		value = 0x0;
> @@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>  		break;
>  	case SND_SOC_DAIFMT_LEFT_J:
>  		format = 0x1;
>  		break;
>  	case SND_SOC_DAIFMT_RIGHT_J:
>  		format = 0x2;
>  		break;
>  	case SND_SOC_DAIFMT_DSP_A:
> +		format = 0x3;
> +		invert = 0x0; /* Set LRCK_INV to 0 */
> +		break;
>  	case SND_SOC_DAIFMT_DSP_B:
>  		format = 0x3;
> +		invert = 0x1; /* Set LRCK_INV to 1 */
>  		break;
>  	default:
>  		return -EINVAL;
>  	}
>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>  			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
>  			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
>  
>  	/* clock inversion */
>  	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
>  	case SND_SOC_DAIFMT_NB_NF: /* Normal */
>  		value = 0x0;
>  		break;
> -	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
> +	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
>  		value = 0x1;
>  		break;
> +	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
> +		value = 0x2;
> +		break;
> +	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
> +		value = 0x3;
> +		break;
>  	default:
>  		return -EINVAL;
>  	}
> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
>  
> -	/*
> -	 * 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;
> +	if (format == 0x3) {

Could we use a define here? That would be more readable

> +		/* Inverted LRCK is not available in DSP mode. */
> +		if (value & BIT(0))
> +			return -EINVAL;

And same thing here, explicitly testing both for DSP_A and DSP_B would
be more readable.

(And I guess value isn't such a great variable name anymore either)

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 12/25] ASoC: sun8i-codec: Program the correct word size
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:30     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:30 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 496 bytes --]

On Wed, Sep 30, 2020 at 09:11:35PM -0500, Samuel Holland wrote:
> The hardware supports 8 to 24-bit word sizes on all three of its DAIs,
> only one of which is connected to the CPU DAI. Program the word size
> based on the actual selected format, instead of relying on limitations
> in another driver (which, incedentally, has patches pending to remove
> that limitation).
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 12/25] ASoC: sun8i-codec: Program the correct word size
@ 2020-10-05 11:30     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:30 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 496 bytes --]

On Wed, Sep 30, 2020 at 09:11:35PM -0500, Samuel Holland wrote:
> The hardware supports 8 to 24-bit word sizes on all three of its DAIs,
> only one of which is connected to the CPU DAI. Program the word size
> based on the actual selected format, instead of relying on limitations
> in another driver (which, incedentally, has patches pending to remove
> that limitation).
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 12/25] ASoC: sun8i-codec: Program the correct word size
@ 2020-10-05 11:30     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:30 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 496 bytes --]

On Wed, Sep 30, 2020 at 09:11:35PM -0500, Samuel Holland wrote:
> The hardware supports 8 to 24-bit word sizes on all three of its DAIs,
> only one of which is connected to the CPU DAI. Program the word size
> based on the actual selected format, instead of relying on limitations
> in another driver (which, incedentally, has patches pending to remove
> that limitation).
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 13/25] ASoC: sun8i-codec: Round up the LRCK divisor
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:31     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:31 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 627 bytes --]

On Wed, Sep 30, 2020 at 09:11:36PM -0500, Samuel Holland wrote:
> The codec supports only power-of-two BCLK/LRCK divisors. If either the
> slot width or the number of slots is not a power of two, the LRCK
> divisor must be rounded up to provide enough space. To do that, use
> order_base_2 (instead of ilog2, which rounds down).
> 
> Since the rounded divisor is also needed for setting the SYSCLK/BCLK
> divisor, return the order base 2 instead of fully calculating the
> hardware register encoding.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 13/25] ASoC: sun8i-codec: Round up the LRCK divisor
@ 2020-10-05 11:31     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:31 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 627 bytes --]

On Wed, Sep 30, 2020 at 09:11:36PM -0500, Samuel Holland wrote:
> The codec supports only power-of-two BCLK/LRCK divisors. If either the
> slot width or the number of slots is not a power of two, the LRCK
> divisor must be rounded up to provide enough space. To do that, use
> order_base_2 (instead of ilog2, which rounds down).
> 
> Since the rounded divisor is also needed for setting the SYSCLK/BCLK
> divisor, return the order base 2 instead of fully calculating the
> hardware register encoding.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 13/25] ASoC: sun8i-codec: Round up the LRCK divisor
@ 2020-10-05 11:31     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:31 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 627 bytes --]

On Wed, Sep 30, 2020 at 09:11:36PM -0500, Samuel Holland wrote:
> The codec supports only power-of-two BCLK/LRCK divisors. If either the
> slot width or the number of slots is not a power of two, the LRCK
> divisor must be rounded up to provide enough space. To do that, use
> order_base_2 (instead of ilog2, which rounds down).
> 
> Since the rounded divisor is also needed for setting the SYSCLK/BCLK
> divisor, return the order base 2 instead of fully calculating the
> hardware register encoding.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 14/25] ASoC: sun8i-codec: Correct the BCLK divisor calculation
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:34     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:34 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 690 bytes --]

On Wed, Sep 30, 2020 at 09:11:37PM -0500, Samuel Holland wrote:
> Previously, the BCLK divisor calculation assumed a power-of-two slot
> width and exactly two slots. In order to support the TDM slot binding
> and 20/24-bit word sizes, those assumptions must be removed.
> 
> Due to hardware limitations, the BCLK/LRCK ratio is not as simple as
> "slot_width * slots". However, the correct value is already calculated
> elsewhere in this function, since it must also be programmed into the
> hardware. Reuse that value to calculate the correct SYSCLK/BCLK divisor.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 14/25] ASoC: sun8i-codec: Correct the BCLK divisor calculation
@ 2020-10-05 11:34     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:34 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 690 bytes --]

On Wed, Sep 30, 2020 at 09:11:37PM -0500, Samuel Holland wrote:
> Previously, the BCLK divisor calculation assumed a power-of-two slot
> width and exactly two slots. In order to support the TDM slot binding
> and 20/24-bit word sizes, those assumptions must be removed.
> 
> Due to hardware limitations, the BCLK/LRCK ratio is not as simple as
> "slot_width * slots". However, the correct value is already calculated
> elsewhere in this function, since it must also be programmed into the
> hardware. Reuse that value to calculate the correct SYSCLK/BCLK divisor.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 14/25] ASoC: sun8i-codec: Correct the BCLK divisor calculation
@ 2020-10-05 11:34     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:34 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 690 bytes --]

On Wed, Sep 30, 2020 at 09:11:37PM -0500, Samuel Holland wrote:
> Previously, the BCLK divisor calculation assumed a power-of-two slot
> width and exactly two slots. In order to support the TDM slot binding
> and 20/24-bit word sizes, those assumptions must be removed.
> 
> Due to hardware limitations, the BCLK/LRCK ratio is not as simple as
> "slot_width * slots". However, the correct value is already calculated
> elsewhere in this function, since it must also be programmed into the
> hardware. Reuse that value to calculate the correct SYSCLK/BCLK divisor.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 15/25] ASoC: sun8i-codec: Support the TDM slot binding
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:34     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:34 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 367 bytes --]

On Wed, Sep 30, 2020 at 09:11:38PM -0500, Samuel Holland wrote:
> Now that BCLK and LRCK rate calculations can handle any
> hardware-supported slot width and number of slots, enable
> support for overriding these parameters from the device tree.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 15/25] ASoC: sun8i-codec: Support the TDM slot binding
@ 2020-10-05 11:34     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:34 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 367 bytes --]

On Wed, Sep 30, 2020 at 09:11:38PM -0500, Samuel Holland wrote:
> Now that BCLK and LRCK rate calculations can handle any
> hardware-supported slot width and number of slots, enable
> support for overriding these parameters from the device tree.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 15/25] ASoC: sun8i-codec: Support the TDM slot binding
@ 2020-10-05 11:34     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:34 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 367 bytes --]

On Wed, Sep 30, 2020 at 09:11:38PM -0500, Samuel Holland wrote:
> Now that BCLK and LRCK rate calculations can handle any
> hardware-supported slot width and number of slots, enable
> support for overriding these parameters from the device tree.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 16/25] ASoC: sun8i-codec: Enforce symmetric DAI parameters
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:39     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:39 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 518 bytes --]

On Wed, Sep 30, 2020 at 09:11:39PM -0500, Samuel Holland wrote:
> The AIFs have a single register controlling DAI parameters in both
> directions, including BCLK/LRCK divisor word size. The DAIs produce only
> noise or silence if any of these parameters is wrong. Therefore, we need
> to enforce symmetry for these parameters, so starting a new substream
> will not break an existing substream.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 16/25] ASoC: sun8i-codec: Enforce symmetric DAI parameters
@ 2020-10-05 11:39     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:39 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 518 bytes --]

On Wed, Sep 30, 2020 at 09:11:39PM -0500, Samuel Holland wrote:
> The AIFs have a single register controlling DAI parameters in both
> directions, including BCLK/LRCK divisor word size. The DAIs produce only
> noise or silence if any of these parameters is wrong. Therefore, we need
> to enforce symmetry for these parameters, so starting a new substream
> will not break an existing substream.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 16/25] ASoC: sun8i-codec: Enforce symmetric DAI parameters
@ 2020-10-05 11:39     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:39 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 518 bytes --]

On Wed, Sep 30, 2020 at 09:11:39PM -0500, Samuel Holland wrote:
> The AIFs have a single register controlling DAI parameters in both
> directions, including BCLK/LRCK divisor word size. The DAIs produce only
> noise or silence if any of these parameters is wrong. Therefore, we need
> to enforce symmetry for these parameters, so starting a new substream
> will not break an existing substream.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 17/25] ASoC: sun8i-codec: Enable all supported sample rates
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:39     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:39 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 595 bytes --]

On Wed, Sep 30, 2020 at 09:11:40PM -0500, Samuel Holland wrote:
> The system sample rate programmed into the hardware is really a clock
> divider from SYSCLK to the ADC and DAC. Since we support two SYSCLK
> frequencies, we can use all sample rates corresponding to one of those
> frequencies divided by any available divisor.
> 
> This commit enables support for those sample rates. It also stops
> advertising support for a 64 kHz sample rate, which is not supported.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 17/25] ASoC: sun8i-codec: Enable all supported sample rates
@ 2020-10-05 11:39     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:39 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 595 bytes --]

On Wed, Sep 30, 2020 at 09:11:40PM -0500, Samuel Holland wrote:
> The system sample rate programmed into the hardware is really a clock
> divider from SYSCLK to the ADC and DAC. Since we support two SYSCLK
> frequencies, we can use all sample rates corresponding to one of those
> frequencies divided by any available divisor.
> 
> This commit enables support for those sample rates. It also stops
> advertising support for a 64 kHz sample rate, which is not supported.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 17/25] ASoC: sun8i-codec: Enable all supported sample rates
@ 2020-10-05 11:39     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:39 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 595 bytes --]

On Wed, Sep 30, 2020 at 09:11:40PM -0500, Samuel Holland wrote:
> The system sample rate programmed into the hardware is really a clock
> divider from SYSCLK to the ADC and DAC. Since we support two SYSCLK
> frequencies, we can use all sample rates corresponding to one of those
> frequencies divided by any available divisor.
> 
> This commit enables support for those sample rates. It also stops
> advertising support for a 64 kHz sample rate, which is not supported.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 18/25] ASoC: sun8i-codec: Automatically set the system sample rate
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:58     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:58 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1743 bytes --]

On Wed, Sep 30, 2020 at 09:11:41PM -0500, Samuel Holland wrote:
> The sun8i codec has three clock/sample rate domains:
>  - The AIF1 domain, with a sample rate equal to AIF1 LRCK
>  - The AIF2 domain, with a sample rate equal to AIF2 LRCK
>  - The SYSCLK domain, containing the ADC, DAC, and effects (AGC/DRC),
>    with a sample rate given by a divisor from SYSCLK. The divisor is
>    controlled by the AIF1_FS or AIF2_FS field in SYS_SR_CTRL, depending
>    on if SYSCLK's source is AIF1CLK or AIF2CLK, respectively. The exact
>    sample rate depends on if SYSCLK is running at 22.6 MHz or 24.6 MHz.
> 
> When an AIF (currently only AIF1) is active, the ADC and DAC should run
> at that sample rate to avoid artifacting. Sample rate conversion is only
> available when multiple AIFs are active and are routed to each other;
> this means the sample rate conversion hardware usually cannot be used.
> 
> Only attach the event hook to the channel 0 AIF widgets, since we only
> need one event when a DAI stream starts or stops. Channel 0 is always
> brought up with a DAI stream, regardless of the number of channels in
> the stream.
> 
> The ADC and DAC (along with their effects blocks) can be used even if
> no AIFs are in use. In that case, we should select an appropriate sample
> rate divisor, instead of keeping the last-used AIF sample rate.
> 44.1/48 kHz was chosen to balance audio quality and power consumption.
> 
> Since the sample rate is tied to active AIF paths, disabling pmdown_time
> allows switching to the optimal sample rate immediately, instead of
> after a 5 second delay.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 18/25] ASoC: sun8i-codec: Automatically set the system sample rate
@ 2020-10-05 11:58     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:58 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 1743 bytes --]

On Wed, Sep 30, 2020 at 09:11:41PM -0500, Samuel Holland wrote:
> The sun8i codec has three clock/sample rate domains:
>  - The AIF1 domain, with a sample rate equal to AIF1 LRCK
>  - The AIF2 domain, with a sample rate equal to AIF2 LRCK
>  - The SYSCLK domain, containing the ADC, DAC, and effects (AGC/DRC),
>    with a sample rate given by a divisor from SYSCLK. The divisor is
>    controlled by the AIF1_FS or AIF2_FS field in SYS_SR_CTRL, depending
>    on if SYSCLK's source is AIF1CLK or AIF2CLK, respectively. The exact
>    sample rate depends on if SYSCLK is running at 22.6 MHz or 24.6 MHz.
> 
> When an AIF (currently only AIF1) is active, the ADC and DAC should run
> at that sample rate to avoid artifacting. Sample rate conversion is only
> available when multiple AIFs are active and are routed to each other;
> this means the sample rate conversion hardware usually cannot be used.
> 
> Only attach the event hook to the channel 0 AIF widgets, since we only
> need one event when a DAI stream starts or stops. Channel 0 is always
> brought up with a DAI stream, regardless of the number of channels in
> the stream.
> 
> The ADC and DAC (along with their effects blocks) can be used even if
> no AIFs are in use. In that case, we should select an appropriate sample
> rate divisor, instead of keeping the last-used AIF sample rate.
> 44.1/48 kHz was chosen to balance audio quality and power consumption.
> 
> Since the sample rate is tied to active AIF paths, disabling pmdown_time
> allows switching to the optimal sample rate immediately, instead of
> after a 5 second delay.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 18/25] ASoC: sun8i-codec: Automatically set the system sample rate
@ 2020-10-05 11:58     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:58 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 1743 bytes --]

On Wed, Sep 30, 2020 at 09:11:41PM -0500, Samuel Holland wrote:
> The sun8i codec has three clock/sample rate domains:
>  - The AIF1 domain, with a sample rate equal to AIF1 LRCK
>  - The AIF2 domain, with a sample rate equal to AIF2 LRCK
>  - The SYSCLK domain, containing the ADC, DAC, and effects (AGC/DRC),
>    with a sample rate given by a divisor from SYSCLK. The divisor is
>    controlled by the AIF1_FS or AIF2_FS field in SYS_SR_CTRL, depending
>    on if SYSCLK's source is AIF1CLK or AIF2CLK, respectively. The exact
>    sample rate depends on if SYSCLK is running at 22.6 MHz or 24.6 MHz.
> 
> When an AIF (currently only AIF1) is active, the ADC and DAC should run
> at that sample rate to avoid artifacting. Sample rate conversion is only
> available when multiple AIFs are active and are routed to each other;
> this means the sample rate conversion hardware usually cannot be used.
> 
> Only attach the event hook to the channel 0 AIF widgets, since we only
> need one event when a DAI stream starts or stops. Channel 0 is always
> brought up with a DAI stream, regardless of the number of channels in
> the stream.
> 
> The ADC and DAC (along with their effects blocks) can be used even if
> no AIFs are in use. In that case, we should select an appropriate sample
> rate divisor, instead of keeping the last-used AIF sample rate.
> 44.1/48 kHz was chosen to balance audio quality and power consumption.
> 
> Since the sample rate is tied to active AIF paths, disabling pmdown_time
> allows switching to the optimal sample rate immediately, instead of
> after a 5 second delay.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 19/25] ASoC: sun8i-codec: Constrain to compatible sample rates
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 11:59     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:59 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 401 bytes --]

On Wed, Sep 30, 2020 at 09:11:42PM -0500, Samuel Holland wrote:
> While another stream is active, only allow userspace to use sample rates
> that are compatible with the current SYSCLK frequency. This ensures the
> actual sample rate will always match what is given in hw_params.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 19/25] ASoC: sun8i-codec: Constrain to compatible sample rates
@ 2020-10-05 11:59     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:59 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 401 bytes --]

On Wed, Sep 30, 2020 at 09:11:42PM -0500, Samuel Holland wrote:
> While another stream is active, only allow userspace to use sample rates
> that are compatible with the current SYSCLK frequency. This ensures the
> actual sample rate will always match what is given in hw_params.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 19/25] ASoC: sun8i-codec: Constrain to compatible sample rates
@ 2020-10-05 11:59     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 11:59 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 401 bytes --]

On Wed, Sep 30, 2020 at 09:11:42PM -0500, Samuel Holland wrote:
> While another stream is active, only allow userspace to use sample rates
> that are compatible with the current SYSCLK frequency. This ensures the
> actual sample rate will always match what is given in hw_params.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 12:01     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2987 bytes --]

On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
> The codec's clock input is shared among all AIFs, and shared with other
> audio-related hardware in the SoC, including I2S and SPDIF controllers.
> To ensure sample rates selected by userspace or by codec2codec DAI links
> are maintained, the clock rate must be protected while it is in use.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
>  1 file changed, 22 insertions(+), 3 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 501af64d43a0..86065bee7cd3 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
>  	unsigned int div = slots * slot_width;
>  
>  	if (div < 16 || div > 256)
>  		return -EINVAL;
>  
>  	return order_base_2(div);
>  }
>  
> +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
> +{
> +	return sample_rate % 4000 ? 22579200 : 24576000;
> +}
> +
>  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_dai_get_drvdata(dai);
>  	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
>  	unsigned int sample_rate = params_rate(params);
>  	unsigned int slots = aif->slots ?: params_channels(params);
>  	unsigned int slot_width = aif->slot_width ?: params_width(params);
> -	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
> -	int lrck_div_order, word_size;
> +	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
> +	int lrck_div_order, ret, word_size;
>  	u8 bclk_div;
>  
>  	/* word size */
>  	switch (params_width(params)) {
>  	case 8:
>  		word_size = 0x0;
>  		break;
>  	case 16:
> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>  			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
>  
>  	/* BCLK divider (SYSCLK/BCLK ratio) */
>  	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>  			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
>  			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
>  
> -	if (!aif->open_streams) {
> +	/* SYSCLK rate */
> +	if (aif->open_streams) {
> +		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);

It's not really clear to me why we wouldn't want to always protect the
clock rate here?

> +		if (ret == -EBUSY)
> +			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
> +				"conflicts with other audio streams.\n",

This string creates a checkpatch warning.

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-05 12:01     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 2987 bytes --]

On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
> The codec's clock input is shared among all AIFs, and shared with other
> audio-related hardware in the SoC, including I2S and SPDIF controllers.
> To ensure sample rates selected by userspace or by codec2codec DAI links
> are maintained, the clock rate must be protected while it is in use.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
>  1 file changed, 22 insertions(+), 3 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 501af64d43a0..86065bee7cd3 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
>  	unsigned int div = slots * slot_width;
>  
>  	if (div < 16 || div > 256)
>  		return -EINVAL;
>  
>  	return order_base_2(div);
>  }
>  
> +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
> +{
> +	return sample_rate % 4000 ? 22579200 : 24576000;
> +}
> +
>  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_dai_get_drvdata(dai);
>  	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
>  	unsigned int sample_rate = params_rate(params);
>  	unsigned int slots = aif->slots ?: params_channels(params);
>  	unsigned int slot_width = aif->slot_width ?: params_width(params);
> -	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
> -	int lrck_div_order, word_size;
> +	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
> +	int lrck_div_order, ret, word_size;
>  	u8 bclk_div;
>  
>  	/* word size */
>  	switch (params_width(params)) {
>  	case 8:
>  		word_size = 0x0;
>  		break;
>  	case 16:
> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>  			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
>  
>  	/* BCLK divider (SYSCLK/BCLK ratio) */
>  	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>  			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
>  			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
>  
> -	if (!aif->open_streams) {
> +	/* SYSCLK rate */
> +	if (aif->open_streams) {
> +		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);

It's not really clear to me why we wouldn't want to always protect the
clock rate here?

> +		if (ret == -EBUSY)
> +			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
> +				"conflicts with other audio streams.\n",

This string creates a checkpatch warning.

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-05 12:01     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 2987 bytes --]

On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
> The codec's clock input is shared among all AIFs, and shared with other
> audio-related hardware in the SoC, including I2S and SPDIF controllers.
> To ensure sample rates selected by userspace or by codec2codec DAI links
> are maintained, the clock rate must be protected while it is in use.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
>  1 file changed, 22 insertions(+), 3 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 501af64d43a0..86065bee7cd3 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
>  	unsigned int div = slots * slot_width;
>  
>  	if (div < 16 || div > 256)
>  		return -EINVAL;
>  
>  	return order_base_2(div);
>  }
>  
> +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
> +{
> +	return sample_rate % 4000 ? 22579200 : 24576000;
> +}
> +
>  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_dai_get_drvdata(dai);
>  	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
>  	unsigned int sample_rate = params_rate(params);
>  	unsigned int slots = aif->slots ?: params_channels(params);
>  	unsigned int slot_width = aif->slot_width ?: params_width(params);
> -	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
> -	int lrck_div_order, word_size;
> +	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
> +	int lrck_div_order, ret, word_size;
>  	u8 bclk_div;
>  
>  	/* word size */
>  	switch (params_width(params)) {
>  	case 8:
>  		word_size = 0x0;
>  		break;
>  	case 16:
> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>  			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
>  
>  	/* BCLK divider (SYSCLK/BCLK ratio) */
>  	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>  			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
>  			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
>  
> -	if (!aif->open_streams) {
> +	/* SYSCLK rate */
> +	if (aif->open_streams) {
> +		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);

It's not really clear to me why we wouldn't want to always protect the
clock rate here?

> +		if (ret == -EBUSY)
> +			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
> +				"conflicts with other audio streams.\n",

This string creates a checkpatch warning.

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 21/25] ASoC: sun8i-codec: Require an exact BCLK divisor match
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 12:01     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 454 bytes --]

On Wed, Sep 30, 2020 at 09:11:44PM -0500, Samuel Holland wrote:
> Now that we guarantee that SYSCLK is running at the optimal rate when
> hw_params succeeds, and that it will continue running at that rate,
> SYSCLK will always be an integer multiple of BCLK. So we can always
> pick the exact divider, not just the closest divider.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 21/25] ASoC: sun8i-codec: Require an exact BCLK divisor match
@ 2020-10-05 12:01     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 454 bytes --]

On Wed, Sep 30, 2020 at 09:11:44PM -0500, Samuel Holland wrote:
> Now that we guarantee that SYSCLK is running at the optimal rate when
> hw_params succeeds, and that it will continue running at that rate,
> SYSCLK will always be an integer multiple of BCLK. So we can always
> pick the exact divider, not just the closest divider.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 21/25] ASoC: sun8i-codec: Require an exact BCLK divisor match
@ 2020-10-05 12:01     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 454 bytes --]

On Wed, Sep 30, 2020 at 09:11:44PM -0500, Samuel Holland wrote:
> Now that we guarantee that SYSCLK is running at the optimal rate when
> hw_params succeeds, and that it will continue running at that rate,
> SYSCLK will always be an integer multiple of BCLK. So we can always
> pick the exact divider, not just the closest divider.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 22/25] ASoC: sun8i-codec: Enable all supported PCM formats
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 12:02     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:02 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 589 bytes --]

On Wed, Sep 30, 2020 at 09:11:45PM -0500, Samuel Holland wrote:
> Now that the DAI clock setup is correct for all hardware-supported PCM
> formats, we can enable them in the driver. With the appropriate support
> in the CPU DAI driver, this allows userspace to access the additional
> formats.
> 
> Since this codec is connected to the CPU via a DAI, not directly, we do
> not care if the CPU DAI is using 3-byte or 4-byte formats, so we can
> support them both.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 22/25] ASoC: sun8i-codec: Enable all supported PCM formats
@ 2020-10-05 12:02     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:02 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 589 bytes --]

On Wed, Sep 30, 2020 at 09:11:45PM -0500, Samuel Holland wrote:
> Now that the DAI clock setup is correct for all hardware-supported PCM
> formats, we can enable them in the driver. With the appropriate support
> in the CPU DAI driver, this allows userspace to access the additional
> formats.
> 
> Since this codec is connected to the CPU via a DAI, not directly, we do
> not care if the CPU DAI is using 3-byte or 4-byte formats, so we can
> support them both.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 22/25] ASoC: sun8i-codec: Enable all supported PCM formats
@ 2020-10-05 12:02     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:02 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 589 bytes --]

On Wed, Sep 30, 2020 at 09:11:45PM -0500, Samuel Holland wrote:
> Now that the DAI clock setup is correct for all hardware-supported PCM
> formats, we can enable them in the driver. With the appropriate support
> in the CPU DAI driver, this allows userspace to access the additional
> formats.
> 
> Since this codec is connected to the CPU via a DAI, not directly, we do
> not care if the CPU DAI is using 3-byte or 4-byte formats, so we can
> support them both.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 12:04     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:04 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4668 bytes --]

Hi,

On Wed, Sep 30, 2020 at 09:11:46PM -0500, Samuel Holland wrote:
> The AIF clock control register has the same layout for all three AIFs.
> The only difference between them is that AIF3 is missing some fields. We
> can reuse the same register field definitions for all three registers,
> and use the DAI ID to select the correct register address.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 64 +++++++++++++++++++----------------
>  1 file changed, 34 insertions(+), 30 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 032a3f714dbb..1c34502ac47a 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -37,23 +37,23 @@
>  #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
>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
> -#define SUN8I_AIF1CLK_CTRL				0x040
> -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
> -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
> -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
> +#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
> +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
> +#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
>  #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
> @@ -83,21 +83,21 @@
>  #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_CLK_INV_MASK	GENMASK(14, 13)
> -#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)
> +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
>  
>  #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
>  
>  #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
>  				 SNDRV_PCM_FMTBIT_S16_LE |\
>  				 SNDRV_PCM_FMTBIT_S20_LE |\
>  				 SNDRV_PCM_FMTBIT_S24_LE |\
>  				 SNDRV_PCM_FMTBIT_S20_3LE|\
> @@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
>  			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
>  
>  	return 0;
>  }
>  
>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>  {
>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> +	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
>  	u32 format, invert, value;
>  
>  	/* clock masters */
>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>  		value = 0x1;
>  		break;
>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>  		value = 0x0;
>  		break;
>  	default:
>  		return -EINVAL;
>  	}
> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
> +
> +	regmap_update_bits(scodec->regmap, reg,
> +			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
> +			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);

I guess it would be more readable without the intermediate variable to
store the register.

With that fixed,
Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
@ 2020-10-05 12:04     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:04 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 4668 bytes --]

Hi,

On Wed, Sep 30, 2020 at 09:11:46PM -0500, Samuel Holland wrote:
> The AIF clock control register has the same layout for all three AIFs.
> The only difference between them is that AIF3 is missing some fields. We
> can reuse the same register field definitions for all three registers,
> and use the DAI ID to select the correct register address.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 64 +++++++++++++++++++----------------
>  1 file changed, 34 insertions(+), 30 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 032a3f714dbb..1c34502ac47a 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -37,23 +37,23 @@
>  #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
>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
> -#define SUN8I_AIF1CLK_CTRL				0x040
> -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
> -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
> -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
> +#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
> +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
> +#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
>  #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
> @@ -83,21 +83,21 @@
>  #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_CLK_INV_MASK	GENMASK(14, 13)
> -#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)
> +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
>  
>  #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
>  
>  #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
>  				 SNDRV_PCM_FMTBIT_S16_LE |\
>  				 SNDRV_PCM_FMTBIT_S20_LE |\
>  				 SNDRV_PCM_FMTBIT_S24_LE |\
>  				 SNDRV_PCM_FMTBIT_S20_3LE|\
> @@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
>  			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
>  
>  	return 0;
>  }
>  
>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>  {
>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> +	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
>  	u32 format, invert, value;
>  
>  	/* clock masters */
>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>  		value = 0x1;
>  		break;
>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>  		value = 0x0;
>  		break;
>  	default:
>  		return -EINVAL;
>  	}
> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
> +
> +	regmap_update_bits(scodec->regmap, reg,
> +			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
> +			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);

I guess it would be more readable without the intermediate variable to
store the register.

With that fixed,
Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
@ 2020-10-05 12:04     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:04 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 4668 bytes --]

Hi,

On Wed, Sep 30, 2020 at 09:11:46PM -0500, Samuel Holland wrote:
> The AIF clock control register has the same layout for all three AIFs.
> The only difference between them is that AIF3 is missing some fields. We
> can reuse the same register field definitions for all three registers,
> and use the DAI ID to select the correct register address.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  sound/soc/sunxi/sun8i-codec.c | 64 +++++++++++++++++++----------------
>  1 file changed, 34 insertions(+), 30 deletions(-)
> 
> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> index 032a3f714dbb..1c34502ac47a 100644
> --- a/sound/soc/sunxi/sun8i-codec.c
> +++ b/sound/soc/sunxi/sun8i-codec.c
> @@ -37,23 +37,23 @@
>  #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
>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
> -#define SUN8I_AIF1CLK_CTRL				0x040
> -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
> -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
> -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
> +#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
> +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
> +#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
>  #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
> @@ -83,21 +83,21 @@
>  #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_CLK_INV_MASK	GENMASK(14, 13)
> -#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)
> +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
>  
>  #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
>  
>  #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
>  				 SNDRV_PCM_FMTBIT_S16_LE |\
>  				 SNDRV_PCM_FMTBIT_S20_LE |\
>  				 SNDRV_PCM_FMTBIT_S24_LE |\
>  				 SNDRV_PCM_FMTBIT_S20_3LE|\
> @@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
>  			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
>  
>  	return 0;
>  }
>  
>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>  {
>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> +	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
>  	u32 format, invert, value;
>  
>  	/* clock masters */
>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>  		value = 0x1;
>  		break;
>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>  		value = 0x0;
>  		break;
>  	default:
>  		return -EINVAL;
>  	}
> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
> +
> +	regmap_update_bits(scodec->regmap, reg,
> +			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
> +			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);

I guess it would be more readable without the intermediate variable to
store the register.

With that fixed,
Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 24/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2
  2020-10-01  2:11   ` Samuel Holland
  (?)
@ 2020-10-05 12:05     ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:05 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 298 bytes --]

On Wed, Sep 30, 2020 at 09:11:47PM -0500, Samuel Holland wrote:
> This adds support for AIF2, which is stereo and has full clocking
> capability, making it very similar to AIF1.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 24/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2
@ 2020-10-05 12:05     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:05 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 298 bytes --]

On Wed, Sep 30, 2020 at 09:11:47PM -0500, Samuel Holland wrote:
> This adds support for AIF2, which is stereo and has full clocking
> capability, making it very similar to AIF1.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 24/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2
@ 2020-10-05 12:05     ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-05 12:05 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 298 bytes --]

On Wed, Sep 30, 2020 at 09:11:47PM -0500, Samuel Holland wrote:
> This adds support for AIF2, which is stereo and has full clocking
> capability, making it very similar to AIF1.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
  2020-10-05 12:01     ` Maxime Ripard
  (?)
@ 2020-10-05 13:15       ` Chen-Yu Tsai
  -1 siblings, 0 replies; 181+ messages in thread
From: Chen-Yu Tsai @ 2020-10-05 13:15 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Samuel Holland, Mark Brown, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, Linux-ALSA, linux-arm-kernel,
	linux-kernel

On Mon, Oct 5, 2020 at 8:01 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
> > The codec's clock input is shared among all AIFs, and shared with other
> > audio-related hardware in the SoC, including I2S and SPDIF controllers.
> > To ensure sample rates selected by userspace or by codec2codec DAI links
> > are maintained, the clock rate must be protected while it is in use.
> >
> > Signed-off-by: Samuel Holland <samuel@sholland.org>
> > ---
> >  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
> >  1 file changed, 22 insertions(+), 3 deletions(-)
> >
> > diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> > index 501af64d43a0..86065bee7cd3 100644
> > --- a/sound/soc/sunxi/sun8i-codec.c
> > +++ b/sound/soc/sunxi/sun8i-codec.c
> > @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
> >       unsigned int div = slots * slot_width;
> >
> >       if (div < 16 || div > 256)
> >               return -EINVAL;
> >
> >       return order_base_2(div);
> >  }
> >
> > +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
> > +{
> > +     return sample_rate % 4000 ? 22579200 : 24576000;
> > +}
> > +
> >  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_dai_get_drvdata(dai);
> >       struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
> >       unsigned int sample_rate = params_rate(params);
> >       unsigned int slots = aif->slots ?: params_channels(params);
> >       unsigned int slot_width = aif->slot_width ?: params_width(params);
> > -     unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
> > -     int lrck_div_order, word_size;
> > +     unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
> > +     int lrck_div_order, ret, word_size;
> >       u8 bclk_div;
> >
> >       /* word size */
> >       switch (params_width(params)) {
> >       case 8:
> >               word_size = 0x0;
> >               break;
> >       case 16:
> > @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
> >                          (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
> >
> >       /* BCLK divider (SYSCLK/BCLK ratio) */
> >       bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
> >       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> >                          SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
> >                          bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
> >
> > -     if (!aif->open_streams) {
> > +     /* SYSCLK rate */
> > +     if (aif->open_streams) {
> > +             ret = clk_set_rate(scodec->clk_module, sysclk_rate);
> > +             if (ret < 0)
> > +                     return ret;
> > +     } else {
> > +             ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
>
> It's not really clear to me why we wouldn't want to always protect the
> clock rate here?

I believe the intention is to allow a window, i.e. when no audio
blocks are running,
when it is possible to switch between sample rate families?

ChenYu

> > +             if (ret == -EBUSY)
> > +                     dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
> > +                             "conflicts with other audio streams.\n",
>
> This string creates a checkpatch warning.
>
> Maxime

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-05 13:15       ` Chen-Yu Tsai
  0 siblings, 0 replies; 181+ messages in thread
From: Chen-Yu Tsai @ 2020-10-05 13:15 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ondrej Jirman, Linux-ALSA, Liam Girdwood, linux-kernel,
	Samuel Holland, Takashi Iwai, Mark Brown, linux-arm-kernel

On Mon, Oct 5, 2020 at 8:01 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
> > The codec's clock input is shared among all AIFs, and shared with other
> > audio-related hardware in the SoC, including I2S and SPDIF controllers.
> > To ensure sample rates selected by userspace or by codec2codec DAI links
> > are maintained, the clock rate must be protected while it is in use.
> >
> > Signed-off-by: Samuel Holland <samuel@sholland.org>
> > ---
> >  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
> >  1 file changed, 22 insertions(+), 3 deletions(-)
> >
> > diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> > index 501af64d43a0..86065bee7cd3 100644
> > --- a/sound/soc/sunxi/sun8i-codec.c
> > +++ b/sound/soc/sunxi/sun8i-codec.c
> > @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
> >       unsigned int div = slots * slot_width;
> >
> >       if (div < 16 || div > 256)
> >               return -EINVAL;
> >
> >       return order_base_2(div);
> >  }
> >
> > +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
> > +{
> > +     return sample_rate % 4000 ? 22579200 : 24576000;
> > +}
> > +
> >  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_dai_get_drvdata(dai);
> >       struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
> >       unsigned int sample_rate = params_rate(params);
> >       unsigned int slots = aif->slots ?: params_channels(params);
> >       unsigned int slot_width = aif->slot_width ?: params_width(params);
> > -     unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
> > -     int lrck_div_order, word_size;
> > +     unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
> > +     int lrck_div_order, ret, word_size;
> >       u8 bclk_div;
> >
> >       /* word size */
> >       switch (params_width(params)) {
> >       case 8:
> >               word_size = 0x0;
> >               break;
> >       case 16:
> > @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
> >                          (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
> >
> >       /* BCLK divider (SYSCLK/BCLK ratio) */
> >       bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
> >       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> >                          SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
> >                          bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
> >
> > -     if (!aif->open_streams) {
> > +     /* SYSCLK rate */
> > +     if (aif->open_streams) {
> > +             ret = clk_set_rate(scodec->clk_module, sysclk_rate);
> > +             if (ret < 0)
> > +                     return ret;
> > +     } else {
> > +             ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
>
> It's not really clear to me why we wouldn't want to always protect the
> clock rate here?

I believe the intention is to allow a window, i.e. when no audio
blocks are running,
when it is possible to switch between sample rate families?

ChenYu

> > +             if (ret == -EBUSY)
> > +                     dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
> > +                             "conflicts with other audio streams.\n",
>
> This string creates a checkpatch warning.
>
> Maxime

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-05 13:15       ` Chen-Yu Tsai
  0 siblings, 0 replies; 181+ messages in thread
From: Chen-Yu Tsai @ 2020-10-05 13:15 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ondrej Jirman, Linux-ALSA, Liam Girdwood, linux-kernel,
	Samuel Holland, Takashi Iwai, Jaroslav Kysela, Mark Brown,
	linux-arm-kernel

On Mon, Oct 5, 2020 at 8:01 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
> > The codec's clock input is shared among all AIFs, and shared with other
> > audio-related hardware in the SoC, including I2S and SPDIF controllers.
> > To ensure sample rates selected by userspace or by codec2codec DAI links
> > are maintained, the clock rate must be protected while it is in use.
> >
> > Signed-off-by: Samuel Holland <samuel@sholland.org>
> > ---
> >  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
> >  1 file changed, 22 insertions(+), 3 deletions(-)
> >
> > diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> > index 501af64d43a0..86065bee7cd3 100644
> > --- a/sound/soc/sunxi/sun8i-codec.c
> > +++ b/sound/soc/sunxi/sun8i-codec.c
> > @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
> >       unsigned int div = slots * slot_width;
> >
> >       if (div < 16 || div > 256)
> >               return -EINVAL;
> >
> >       return order_base_2(div);
> >  }
> >
> > +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
> > +{
> > +     return sample_rate % 4000 ? 22579200 : 24576000;
> > +}
> > +
> >  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_dai_get_drvdata(dai);
> >       struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
> >       unsigned int sample_rate = params_rate(params);
> >       unsigned int slots = aif->slots ?: params_channels(params);
> >       unsigned int slot_width = aif->slot_width ?: params_width(params);
> > -     unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
> > -     int lrck_div_order, word_size;
> > +     unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
> > +     int lrck_div_order, ret, word_size;
> >       u8 bclk_div;
> >
> >       /* word size */
> >       switch (params_width(params)) {
> >       case 8:
> >               word_size = 0x0;
> >               break;
> >       case 16:
> > @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
> >                          (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
> >
> >       /* BCLK divider (SYSCLK/BCLK ratio) */
> >       bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
> >       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> >                          SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
> >                          bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
> >
> > -     if (!aif->open_streams) {
> > +     /* SYSCLK rate */
> > +     if (aif->open_streams) {
> > +             ret = clk_set_rate(scodec->clk_module, sysclk_rate);
> > +             if (ret < 0)
> > +                     return ret;
> > +     } else {
> > +             ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
>
> It's not really clear to me why we wouldn't want to always protect the
> clock rate here?

I believe the intention is to allow a window, i.e. when no audio
blocks are running,
when it is possible to switch between sample rate families?

ChenYu

> > +             if (ret == -EBUSY)
> > +                     dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
> > +                             "conflicts with other audio streams.\n",
>
> This string creates a checkpatch warning.
>
> Maxime

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 00/25] ASoC: sun8i-codec: support for AIF2 and AIF3
  2020-10-01  2:11 ` Samuel Holland
  (?)
@ 2020-10-05 17:54   ` Mark Brown
  -1 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-10-05 17:54 UTC (permalink / raw)
  To: Chen-Yu Tsai, Takashi Iwai, Liam Girdwood, Samuel Holland,
	Jaroslav Kysela, Maxime Ripard
  Cc: alsa-devel, Ondrej Jirman, linux-arm-kernel, linux-kernel

On Wed, 30 Sep 2020 21:11:23 -0500, Samuel Holland wrote:
> This series adds support the other two AIFs present in the sun8i codec,
> which can be used for codec2codec DAI links.
> 
> This series first cleans up the DAPM component driver so there is an
> organized place to put the new widgets. Then it fills out the DAI
> driver, removing assumptions that were made for AIF1 (16 bits, 2
> channels, certain clock inversions). Some new logic is required to
> handle 3 DAIs and the ADC/DAC sharing the same clock. Finally, it adds
> the new DAIs, and hooks them up with DAPM widgets and routes per the
> hardware topology.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/8] ASoC: sun8i-codec: Set up clock tree at probe time
      commit: d8f006825ac57e34f7ed5e63a1e16d889dc1508e
[2/8] ASoC: sun8i-codec: Swap module clock/reset dependencies
      commit: ed3caa3bd44c9ae1cebeb32d787adc5ed35e29fa
[3/8] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
      commit: d58b7247087900414aa3e988e70ecba85e06f412
[4/8] ASoC: sun8i-codec: Consistently name DAPM widgets and routes
      commit: 7b51f3c7029fab706e7d9ac99f67cbcf8f29beca
[5/8] ASoC: sun8i-codec: Correct DAPM widget types
      commit: fc5668f62d089ba69b343f0e80146f5a3bc6fa71
[6/8] ASoC: sun8i-codec: Fix AIF widget channel references
      commit: 4ab60cef3149d57fe56add8c60ee7e6d45816f27
[7/8] ASoC: sun8i-codec: Enable AIF mono/stereo control
      commit: 18ebd62c30f0380da11d6c86e20b56c771ac1e18
[8/8] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
      commit: a886990c9525e83146829c7711ce444ff652c98a

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 00/25] ASoC: sun8i-codec: support for AIF2 and AIF3
@ 2020-10-05 17:54   ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-10-05 17:54 UTC (permalink / raw)
  To: Chen-Yu Tsai, Takashi Iwai, Liam Girdwood, Samuel Holland,
	Jaroslav Kysela, Maxime Ripard
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel

On Wed, 30 Sep 2020 21:11:23 -0500, Samuel Holland wrote:
> This series adds support the other two AIFs present in the sun8i codec,
> which can be used for codec2codec DAI links.
> 
> This series first cleans up the DAPM component driver so there is an
> organized place to put the new widgets. Then it fills out the DAI
> driver, removing assumptions that were made for AIF1 (16 bits, 2
> channels, certain clock inversions). Some new logic is required to
> handle 3 DAIs and the ADC/DAC sharing the same clock. Finally, it adds
> the new DAIs, and hooks them up with DAPM widgets and routes per the
> hardware topology.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/8] ASoC: sun8i-codec: Set up clock tree at probe time
      commit: d8f006825ac57e34f7ed5e63a1e16d889dc1508e
[2/8] ASoC: sun8i-codec: Swap module clock/reset dependencies
      commit: ed3caa3bd44c9ae1cebeb32d787adc5ed35e29fa
[3/8] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
      commit: d58b7247087900414aa3e988e70ecba85e06f412
[4/8] ASoC: sun8i-codec: Consistently name DAPM widgets and routes
      commit: 7b51f3c7029fab706e7d9ac99f67cbcf8f29beca
[5/8] ASoC: sun8i-codec: Correct DAPM widget types
      commit: fc5668f62d089ba69b343f0e80146f5a3bc6fa71
[6/8] ASoC: sun8i-codec: Fix AIF widget channel references
      commit: 4ab60cef3149d57fe56add8c60ee7e6d45816f27
[7/8] ASoC: sun8i-codec: Enable AIF mono/stereo control
      commit: 18ebd62c30f0380da11d6c86e20b56c771ac1e18
[8/8] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
      commit: a886990c9525e83146829c7711ce444ff652c98a

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 00/25] ASoC: sun8i-codec: support for AIF2 and AIF3
@ 2020-10-05 17:54   ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-10-05 17:54 UTC (permalink / raw)
  To: Chen-Yu Tsai, Takashi Iwai, Liam Girdwood, Samuel Holland,
	Jaroslav Kysela, Maxime Ripard
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, linux-arm-kernel

On Wed, 30 Sep 2020 21:11:23 -0500, Samuel Holland wrote:
> This series adds support the other two AIFs present in the sun8i codec,
> which can be used for codec2codec DAI links.
> 
> This series first cleans up the DAPM component driver so there is an
> organized place to put the new widgets. Then it fills out the DAI
> driver, removing assumptions that were made for AIF1 (16 bits, 2
> channels, certain clock inversions). Some new logic is required to
> handle 3 DAIs and the ADC/DAC sharing the same clock. Finally, it adds
> the new DAIs, and hooks them up with DAPM widgets and routes per the
> hardware topology.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/8] ASoC: sun8i-codec: Set up clock tree at probe time
      commit: d8f006825ac57e34f7ed5e63a1e16d889dc1508e
[2/8] ASoC: sun8i-codec: Swap module clock/reset dependencies
      commit: ed3caa3bd44c9ae1cebeb32d787adc5ed35e29fa
[3/8] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes
      commit: d58b7247087900414aa3e988e70ecba85e06f412
[4/8] ASoC: sun8i-codec: Consistently name DAPM widgets and routes
      commit: 7b51f3c7029fab706e7d9ac99f67cbcf8f29beca
[5/8] ASoC: sun8i-codec: Correct DAPM widget types
      commit: fc5668f62d089ba69b343f0e80146f5a3bc6fa71
[6/8] ASoC: sun8i-codec: Fix AIF widget channel references
      commit: 4ab60cef3149d57fe56add8c60ee7e6d45816f27
[7/8] ASoC: sun8i-codec: Enable AIF mono/stereo control
      commit: 18ebd62c30f0380da11d6c86e20b56c771ac1e18
[8/8] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata
      commit: a886990c9525e83146829c7711ce444ff652c98a

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
  2020-10-05 11:30     ` Maxime Ripard
  (?)
@ 2020-10-06  4:29       ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:29 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel


On 10/5/20 6:30 AM, Maxime Ripard wrote:
> On Wed, Sep 30, 2020 at 09:11:34PM -0500, Samuel Holland wrote:
>> When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
>> independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
>> LRCK inversion is not supported. The register bit is repurposed to
>> select between DSP_A and DSP_B. Extend the driver to support this.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>   sound/soc/sunxi/sun8i-codec.c | 57 +++++++++++++++++++++++------------
>>   1 file changed, 37 insertions(+), 20 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 0b713b2a2028..506420fb355c 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -39,18 +39,17 @@
>>   #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
>>   #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
>>   #define SUN8I_AIF1CLK_CTRL				0x040
>>   #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
>> +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
>>   #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
>>   #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
>>   #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_AD0L_ENA		15
>>   #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
>> @@ -85,16 +84,17 @@
>>   #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_CLK_INV_MASK	GENMASK(14, 13)
>>   #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)
>>   
>>   enum {
>>   	AIF1,
>>   	NAIFS
>> @@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
>>   	default:
>>   		return -EINVAL;
>>   	}
>>   }
>>   
>>   static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>>   {
>>   	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
>> -	u32 format, value;
>> +	u32 format, invert, value;
>>   
>>   	/* clock masters */
>>   	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>>   	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>>   		value = 0x1;
>>   		break;
>>   	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>>   		value = 0x0;
>> @@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>>   		break;
>>   	case SND_SOC_DAIFMT_LEFT_J:
>>   		format = 0x1;
>>   		break;
>>   	case SND_SOC_DAIFMT_RIGHT_J:
>>   		format = 0x2;
>>   		break;
>>   	case SND_SOC_DAIFMT_DSP_A:
>> +		format = 0x3;
>> +		invert = 0x0; /* Set LRCK_INV to 0 */
>> +		break;
>>   	case SND_SOC_DAIFMT_DSP_B:
>>   		format = 0x3;
>> +		invert = 0x1; /* Set LRCK_INV to 1 */
>>   		break;
>>   	default:
>>   		return -EINVAL;
>>   	}
>>   	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>>   			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
>>   			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
>>   
>>   	/* clock inversion */
>>   	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
>>   	case SND_SOC_DAIFMT_NB_NF: /* Normal */
>>   		value = 0x0;
>>   		break;
>> -	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
>> +	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
>>   		value = 0x1;
>>   		break;
>> +	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
>> +		value = 0x2;
>> +		break;
>> +	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
>> +		value = 0x3;
>> +		break;
>>   	default:
>>   		return -EINVAL;
>>   	}
>> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
>> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
>>   
>> -	/*
>> -	 * 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;
>> +	if (format == 0x3) {
> 
> Could we use a define here? That would be more readable

Yes, I can do that.

>> +		/* Inverted LRCK is not available in DSP mode. */
>> +		if (value & BIT(0))
>> +			return -EINVAL;
> 
> And same thing here, explicitly testing both for DSP_A and DSP_B would
> be more readable.

Here, `value & BIT(0)` means SND_SOC_DAIFMT_NB_IF ||
SND_SOC_DAIFMT_IB_IF, not selecting the DSP format.

> (And I guess value isn't such a great variable name anymore either)

If I rename `invert` to `dsp_format`, and replace `value` here with
`invert`, I think that would be more clear.

> Maxime

Cheers,
Samuel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
@ 2020-10-06  4:29       ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:29 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel


On 10/5/20 6:30 AM, Maxime Ripard wrote:
> On Wed, Sep 30, 2020 at 09:11:34PM -0500, Samuel Holland wrote:
>> When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
>> independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
>> LRCK inversion is not supported. The register bit is repurposed to
>> select between DSP_A and DSP_B. Extend the driver to support this.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>   sound/soc/sunxi/sun8i-codec.c | 57 +++++++++++++++++++++++------------
>>   1 file changed, 37 insertions(+), 20 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 0b713b2a2028..506420fb355c 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -39,18 +39,17 @@
>>   #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
>>   #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
>>   #define SUN8I_AIF1CLK_CTRL				0x040
>>   #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
>> +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
>>   #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
>>   #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
>>   #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_AD0L_ENA		15
>>   #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
>> @@ -85,16 +84,17 @@
>>   #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_CLK_INV_MASK	GENMASK(14, 13)
>>   #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)
>>   
>>   enum {
>>   	AIF1,
>>   	NAIFS
>> @@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
>>   	default:
>>   		return -EINVAL;
>>   	}
>>   }
>>   
>>   static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>>   {
>>   	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
>> -	u32 format, value;
>> +	u32 format, invert, value;
>>   
>>   	/* clock masters */
>>   	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>>   	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>>   		value = 0x1;
>>   		break;
>>   	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>>   		value = 0x0;
>> @@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>>   		break;
>>   	case SND_SOC_DAIFMT_LEFT_J:
>>   		format = 0x1;
>>   		break;
>>   	case SND_SOC_DAIFMT_RIGHT_J:
>>   		format = 0x2;
>>   		break;
>>   	case SND_SOC_DAIFMT_DSP_A:
>> +		format = 0x3;
>> +		invert = 0x0; /* Set LRCK_INV to 0 */
>> +		break;
>>   	case SND_SOC_DAIFMT_DSP_B:
>>   		format = 0x3;
>> +		invert = 0x1; /* Set LRCK_INV to 1 */
>>   		break;
>>   	default:
>>   		return -EINVAL;
>>   	}
>>   	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>>   			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
>>   			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
>>   
>>   	/* clock inversion */
>>   	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
>>   	case SND_SOC_DAIFMT_NB_NF: /* Normal */
>>   		value = 0x0;
>>   		break;
>> -	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
>> +	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
>>   		value = 0x1;
>>   		break;
>> +	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
>> +		value = 0x2;
>> +		break;
>> +	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
>> +		value = 0x3;
>> +		break;
>>   	default:
>>   		return -EINVAL;
>>   	}
>> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
>> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
>>   
>> -	/*
>> -	 * 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;
>> +	if (format == 0x3) {
> 
> Could we use a define here? That would be more readable

Yes, I can do that.

>> +		/* Inverted LRCK is not available in DSP mode. */
>> +		if (value & BIT(0))
>> +			return -EINVAL;
> 
> And same thing here, explicitly testing both for DSP_A and DSP_B would
> be more readable.

Here, `value & BIT(0)` means SND_SOC_DAIFMT_NB_IF ||
SND_SOC_DAIFMT_IB_IF, not selecting the DSP format.

> (And I guess value isn't such a great variable name anymore either)

If I rename `invert` to `dsp_format`, and replace `value` here with
`invert`, I think that would be more clear.

> Maxime

Cheers,
Samuel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
@ 2020-10-06  4:29       ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:29 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


On 10/5/20 6:30 AM, Maxime Ripard wrote:
> On Wed, Sep 30, 2020 at 09:11:34PM -0500, Samuel Holland wrote:
>> When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
>> independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
>> LRCK inversion is not supported. The register bit is repurposed to
>> select between DSP_A and DSP_B. Extend the driver to support this.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>   sound/soc/sunxi/sun8i-codec.c | 57 +++++++++++++++++++++++------------
>>   1 file changed, 37 insertions(+), 20 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 0b713b2a2028..506420fb355c 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -39,18 +39,17 @@
>>   #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
>>   #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
>>   #define SUN8I_AIF1CLK_CTRL				0x040
>>   #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
>> +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
>>   #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
>>   #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
>>   #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_AD0L_ENA		15
>>   #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
>> @@ -85,16 +84,17 @@
>>   #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_CLK_INV_MASK	GENMASK(14, 13)
>>   #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)
>>   
>>   enum {
>>   	AIF1,
>>   	NAIFS
>> @@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
>>   	default:
>>   		return -EINVAL;
>>   	}
>>   }
>>   
>>   static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>>   {
>>   	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
>> -	u32 format, value;
>> +	u32 format, invert, value;
>>   
>>   	/* clock masters */
>>   	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>>   	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>>   		value = 0x1;
>>   		break;
>>   	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>>   		value = 0x0;
>> @@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>>   		break;
>>   	case SND_SOC_DAIFMT_LEFT_J:
>>   		format = 0x1;
>>   		break;
>>   	case SND_SOC_DAIFMT_RIGHT_J:
>>   		format = 0x2;
>>   		break;
>>   	case SND_SOC_DAIFMT_DSP_A:
>> +		format = 0x3;
>> +		invert = 0x0; /* Set LRCK_INV to 0 */
>> +		break;
>>   	case SND_SOC_DAIFMT_DSP_B:
>>   		format = 0x3;
>> +		invert = 0x1; /* Set LRCK_INV to 1 */
>>   		break;
>>   	default:
>>   		return -EINVAL;
>>   	}
>>   	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>>   			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
>>   			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
>>   
>>   	/* clock inversion */
>>   	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
>>   	case SND_SOC_DAIFMT_NB_NF: /* Normal */
>>   		value = 0x0;
>>   		break;
>> -	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
>> +	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
>>   		value = 0x1;
>>   		break;
>> +	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
>> +		value = 0x2;
>> +		break;
>> +	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
>> +		value = 0x3;
>> +		break;
>>   	default:
>>   		return -EINVAL;
>>   	}
>> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
>> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
>>   
>> -	/*
>> -	 * 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;
>> +	if (format == 0x3) {
> 
> Could we use a define here? That would be more readable

Yes, I can do that.

>> +		/* Inverted LRCK is not available in DSP mode. */
>> +		if (value & BIT(0))
>> +			return -EINVAL;
> 
> And same thing here, explicitly testing both for DSP_A and DSP_B would
> be more readable.

Here, `value & BIT(0)` means SND_SOC_DAIFMT_NB_IF ||
SND_SOC_DAIFMT_IB_IF, not selecting the DSP format.

> (And I guess value isn't such a great variable name anymore either)

If I rename `invert` to `dsp_format`, and replace `value` here with
`invert`, I think that would be more clear.

> Maxime

Cheers,
Samuel

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
  2020-10-05 12:01     ` Maxime Ripard
  (?)
@ 2020-10-06  4:43       ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:43 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

On 10/5/20 7:01 AM, Maxime Ripard wrote:
> On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
>> The codec's clock input is shared among all AIFs, and shared with other
>> audio-related hardware in the SoC, including I2S and SPDIF controllers.
>> To ensure sample rates selected by userspace or by codec2codec DAI links
>> are maintained, the clock rate must be protected while it is in use.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
>>  1 file changed, 22 insertions(+), 3 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 501af64d43a0..86065bee7cd3 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
>>  	unsigned int div = slots * slot_width;
>>  
>>  	if (div < 16 || div > 256)
>>  		return -EINVAL;
>>  
>>  	return order_base_2(div);
>>  }
>>  
>> +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
>> +{
>> +	return sample_rate % 4000 ? 22579200 : 24576000;
>> +}
>> +
>>  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_dai_get_drvdata(dai);
>>  	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
>>  	unsigned int sample_rate = params_rate(params);
>>  	unsigned int slots = aif->slots ?: params_channels(params);
>>  	unsigned int slot_width = aif->slot_width ?: params_width(params);
>> -	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
>> -	int lrck_div_order, word_size;
>> +	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
>> +	int lrck_div_order, ret, word_size;
>>  	u8 bclk_div;
>>  
>>  	/* word size */
>>  	switch (params_width(params)) {
>>  	case 8:
>>  		word_size = 0x0;
>>  		break;
>>  	case 16:
>> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>>  			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
>>  
>>  	/* BCLK divider (SYSCLK/BCLK ratio) */
>>  	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
>>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>>  			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
>>  			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
>>  
>> -	if (!aif->open_streams) {
>> +	/* SYSCLK rate */
>> +	if (aif->open_streams) {
>> +		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
>> +		if (ret < 0)
>> +			return ret;
>> +	} else {
>> +		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
> 
> It's not really clear to me why we wouldn't want to always protect the
> clock rate here?

From Documentation/sound/kernel-api/writing-an-alsa-driver.rst:

    hw_params callback
    ...
    Note that this and ``prepare`` callbacks may be called multiple
    times per initialization. For example, the OSS emulation may call
    these callbacks at each change via its ioctl.

Clock rate protection is reference counted, so we must only take one
reference (or at least a known number of references) per stream.

>> +		if (ret == -EBUSY)
>> +			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
>> +				"conflicts with other audio streams.\n",
> 
> This string creates a checkpatch warning.

I will put it on one line, though >100 columns is also a checkpatch warning.

> Maxime

Cheers,
Samuel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-06  4:43       ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:43 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

On 10/5/20 7:01 AM, Maxime Ripard wrote:
> On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
>> The codec's clock input is shared among all AIFs, and shared with other
>> audio-related hardware in the SoC, including I2S and SPDIF controllers.
>> To ensure sample rates selected by userspace or by codec2codec DAI links
>> are maintained, the clock rate must be protected while it is in use.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
>>  1 file changed, 22 insertions(+), 3 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 501af64d43a0..86065bee7cd3 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
>>  	unsigned int div = slots * slot_width;
>>  
>>  	if (div < 16 || div > 256)
>>  		return -EINVAL;
>>  
>>  	return order_base_2(div);
>>  }
>>  
>> +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
>> +{
>> +	return sample_rate % 4000 ? 22579200 : 24576000;
>> +}
>> +
>>  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_dai_get_drvdata(dai);
>>  	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
>>  	unsigned int sample_rate = params_rate(params);
>>  	unsigned int slots = aif->slots ?: params_channels(params);
>>  	unsigned int slot_width = aif->slot_width ?: params_width(params);
>> -	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
>> -	int lrck_div_order, word_size;
>> +	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
>> +	int lrck_div_order, ret, word_size;
>>  	u8 bclk_div;
>>  
>>  	/* word size */
>>  	switch (params_width(params)) {
>>  	case 8:
>>  		word_size = 0x0;
>>  		break;
>>  	case 16:
>> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>>  			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
>>  
>>  	/* BCLK divider (SYSCLK/BCLK ratio) */
>>  	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
>>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>>  			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
>>  			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
>>  
>> -	if (!aif->open_streams) {
>> +	/* SYSCLK rate */
>> +	if (aif->open_streams) {
>> +		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
>> +		if (ret < 0)
>> +			return ret;
>> +	} else {
>> +		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
> 
> It's not really clear to me why we wouldn't want to always protect the
> clock rate here?

From Documentation/sound/kernel-api/writing-an-alsa-driver.rst:

    hw_params callback
    ...
    Note that this and ``prepare`` callbacks may be called multiple
    times per initialization. For example, the OSS emulation may call
    these callbacks at each change via its ioctl.

Clock rate protection is reference counted, so we must only take one
reference (or at least a known number of references) per stream.

>> +		if (ret == -EBUSY)
>> +			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
>> +				"conflicts with other audio streams.\n",
> 
> This string creates a checkpatch warning.

I will put it on one line, though >100 columns is also a checkpatch warning.

> Maxime

Cheers,
Samuel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-06  4:43       ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:43 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel

On 10/5/20 7:01 AM, Maxime Ripard wrote:
> On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
>> The codec's clock input is shared among all AIFs, and shared with other
>> audio-related hardware in the SoC, including I2S and SPDIF controllers.
>> To ensure sample rates selected by userspace or by codec2codec DAI links
>> are maintained, the clock rate must be protected while it is in use.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
>>  1 file changed, 22 insertions(+), 3 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 501af64d43a0..86065bee7cd3 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
>>  	unsigned int div = slots * slot_width;
>>  
>>  	if (div < 16 || div > 256)
>>  		return -EINVAL;
>>  
>>  	return order_base_2(div);
>>  }
>>  
>> +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
>> +{
>> +	return sample_rate % 4000 ? 22579200 : 24576000;
>> +}
>> +
>>  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_dai_get_drvdata(dai);
>>  	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
>>  	unsigned int sample_rate = params_rate(params);
>>  	unsigned int slots = aif->slots ?: params_channels(params);
>>  	unsigned int slot_width = aif->slot_width ?: params_width(params);
>> -	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
>> -	int lrck_div_order, word_size;
>> +	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
>> +	int lrck_div_order, ret, word_size;
>>  	u8 bclk_div;
>>  
>>  	/* word size */
>>  	switch (params_width(params)) {
>>  	case 8:
>>  		word_size = 0x0;
>>  		break;
>>  	case 16:
>> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>>  			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
>>  
>>  	/* BCLK divider (SYSCLK/BCLK ratio) */
>>  	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
>>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>>  			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
>>  			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
>>  
>> -	if (!aif->open_streams) {
>> +	/* SYSCLK rate */
>> +	if (aif->open_streams) {
>> +		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
>> +		if (ret < 0)
>> +			return ret;
>> +	} else {
>> +		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
> 
> It's not really clear to me why we wouldn't want to always protect the
> clock rate here?

From Documentation/sound/kernel-api/writing-an-alsa-driver.rst:

    hw_params callback
    ...
    Note that this and ``prepare`` callbacks may be called multiple
    times per initialization. For example, the OSS emulation may call
    these callbacks at each change via its ioctl.

Clock rate protection is reference counted, so we must only take one
reference (or at least a known number of references) per stream.

>> +		if (ret == -EBUSY)
>> +			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
>> +				"conflicts with other audio streams.\n",
> 
> This string creates a checkpatch warning.

I will put it on one line, though >100 columns is also a checkpatch warning.

> Maxime

Cheers,
Samuel

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
  2020-10-05 13:15       ` Chen-Yu Tsai
  (?)
@ 2020-10-06  4:46         ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:46 UTC (permalink / raw)
  To: Chen-Yu Tsai, Maxime Ripard
  Cc: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
	Ondrej Jirman, Linux-ALSA, linux-arm-kernel, linux-kernel

On 10/5/20 8:15 AM, Chen-Yu Tsai wrote:
> On Mon, Oct 5, 2020 at 8:01 PM Maxime Ripard <maxime@cerno.tech> wrote:
>>
>> On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
>>> The codec's clock input is shared among all AIFs, and shared with other
>>> audio-related hardware in the SoC, including I2S and SPDIF controllers.
>>> To ensure sample rates selected by userspace or by codec2codec DAI links
>>> are maintained, the clock rate must be protected while it is in use.
>>>
>>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>>> ---
>>>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
>>>  1 file changed, 22 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>>> index 501af64d43a0..86065bee7cd3 100644
>>> --- a/sound/soc/sunxi/sun8i-codec.c
>>> +++ b/sound/soc/sunxi/sun8i-codec.c
...
>>> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>>>                          (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
>>>
>>>       /* BCLK divider (SYSCLK/BCLK ratio) */
>>>       bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
>>>       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>>>                          SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
>>>                          bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
>>>
>>> -     if (!aif->open_streams) {
>>> +     /* SYSCLK rate */
>>> +     if (aif->open_streams) {
>>> +             ret = clk_set_rate(scodec->clk_module, sysclk_rate);
>>> +             if (ret < 0)
>>> +                     return ret;
>>> +     } else {
>>> +             ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
>>
>> It's not really clear to me why we wouldn't want to always protect the
>> clock rate here?
> 
> I believe the intention is to allow a window, i.e. when no audio
> blocks are running,
> when it is possible to switch between sample rate families?

Yes, this is an advantage now. It would not be the case if sun4i-i2s did
something similar. It has the same problem that multiple separate sound
cards compete for one PLL.

> ChenYu

Cheers,
Samuel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-06  4:46         ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:46 UTC (permalink / raw)
  To: Chen-Yu Tsai, Maxime Ripard
  Cc: Ondrej Jirman, Linux-ALSA, linux-kernel, Takashi Iwai,
	Liam Girdwood, Mark Brown, linux-arm-kernel

On 10/5/20 8:15 AM, Chen-Yu Tsai wrote:
> On Mon, Oct 5, 2020 at 8:01 PM Maxime Ripard <maxime@cerno.tech> wrote:
>>
>> On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
>>> The codec's clock input is shared among all AIFs, and shared with other
>>> audio-related hardware in the SoC, including I2S and SPDIF controllers.
>>> To ensure sample rates selected by userspace or by codec2codec DAI links
>>> are maintained, the clock rate must be protected while it is in use.
>>>
>>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>>> ---
>>>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
>>>  1 file changed, 22 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>>> index 501af64d43a0..86065bee7cd3 100644
>>> --- a/sound/soc/sunxi/sun8i-codec.c
>>> +++ b/sound/soc/sunxi/sun8i-codec.c
...
>>> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>>>                          (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
>>>
>>>       /* BCLK divider (SYSCLK/BCLK ratio) */
>>>       bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
>>>       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>>>                          SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
>>>                          bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
>>>
>>> -     if (!aif->open_streams) {
>>> +     /* SYSCLK rate */
>>> +     if (aif->open_streams) {
>>> +             ret = clk_set_rate(scodec->clk_module, sysclk_rate);
>>> +             if (ret < 0)
>>> +                     return ret;
>>> +     } else {
>>> +             ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
>>
>> It's not really clear to me why we wouldn't want to always protect the
>> clock rate here?
> 
> I believe the intention is to allow a window, i.e. when no audio
> blocks are running,
> when it is possible to switch between sample rate families?

Yes, this is an advantage now. It would not be the case if sun4i-i2s did
something similar. It has the same problem that multiple separate sound
cards compete for one PLL.

> ChenYu

Cheers,
Samuel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-06  4:46         ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:46 UTC (permalink / raw)
  To: Chen-Yu Tsai, Maxime Ripard
  Cc: Ondrej Jirman, Linux-ALSA, linux-kernel, Takashi Iwai,
	Liam Girdwood, Mark Brown, Jaroslav Kysela, linux-arm-kernel

On 10/5/20 8:15 AM, Chen-Yu Tsai wrote:
> On Mon, Oct 5, 2020 at 8:01 PM Maxime Ripard <maxime@cerno.tech> wrote:
>>
>> On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
>>> The codec's clock input is shared among all AIFs, and shared with other
>>> audio-related hardware in the SoC, including I2S and SPDIF controllers.
>>> To ensure sample rates selected by userspace or by codec2codec DAI links
>>> are maintained, the clock rate must be protected while it is in use.
>>>
>>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>>> ---
>>>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
>>>  1 file changed, 22 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>>> index 501af64d43a0..86065bee7cd3 100644
>>> --- a/sound/soc/sunxi/sun8i-codec.c
>>> +++ b/sound/soc/sunxi/sun8i-codec.c
...
>>> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
>>>                          (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
>>>
>>>       /* BCLK divider (SYSCLK/BCLK ratio) */
>>>       bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
>>>       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>>>                          SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
>>>                          bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
>>>
>>> -     if (!aif->open_streams) {
>>> +     /* SYSCLK rate */
>>> +     if (aif->open_streams) {
>>> +             ret = clk_set_rate(scodec->clk_module, sysclk_rate);
>>> +             if (ret < 0)
>>> +                     return ret;
>>> +     } else {
>>> +             ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
>>
>> It's not really clear to me why we wouldn't want to always protect the
>> clock rate here?
> 
> I believe the intention is to allow a window, i.e. when no audio
> blocks are running,
> when it is possible to switch between sample rate families?

Yes, this is an advantage now. It would not be the case if sun4i-i2s did
something similar. It has the same problem that multiple separate sound
cards compete for one PLL.

> ChenYu

Cheers,
Samuel

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
  2020-10-05 12:04     ` Maxime Ripard
  (?)
@ 2020-10-06  4:51       ` Samuel Holland
  -1 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:51 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

On 10/5/20 7:04 AM, Maxime Ripard wrote:
> Hi,
> 
> On Wed, Sep 30, 2020 at 09:11:46PM -0500, Samuel Holland wrote:
>> The AIF clock control register has the same layout for all three AIFs.
>> The only difference between them is that AIF3 is missing some fields. We
>> can reuse the same register field definitions for all three registers,
>> and use the DAI ID to select the correct register address.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>  sound/soc/sunxi/sun8i-codec.c | 64 +++++++++++++++++++----------------
>>  1 file changed, 34 insertions(+), 30 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 032a3f714dbb..1c34502ac47a 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -37,23 +37,23 @@
>>  #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
>>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
>> -#define SUN8I_AIF1CLK_CTRL				0x040
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
>> +#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
>> +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
>> +#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
>> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
>> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
>> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
>> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
>>  #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
>> @@ -83,21 +83,21 @@
>>  #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_CLK_INV_MASK	GENMASK(14, 13)
>> -#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)
>> +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
>> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
>> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
>> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
>> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
>>  
>>  #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
>>  
>>  #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
>>  				 SNDRV_PCM_FMTBIT_S16_LE |\
>>  				 SNDRV_PCM_FMTBIT_S20_LE |\
>>  				 SNDRV_PCM_FMTBIT_S24_LE |\
>>  				 SNDRV_PCM_FMTBIT_S20_3LE|\
>> @@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
>>  			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
>>  
>>  	return 0;
>>  }
>>  
>>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>>  {
>>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
>> +	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
>>  	u32 format, invert, value;
>>  
>>  	/* clock masters */
>>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>>  		value = 0x1;
>>  		break;
>>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>>  		value = 0x0;
>>  		break;
>>  	default:
>>  		return -EINVAL;
>>  	}
>> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
>> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
>> +
>> +	regmap_update_bits(scodec->regmap, reg,
>> +			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
>> +			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
> 
> I guess it would be more readable without the intermediate variable to
> store the register.

You mean you want me to call `SUN8I_AIF_CLK_CTRL(dai->id)` in each
regmap_update_bits call? I don't know that the compiler could optimize
that due to the pointer read. And how would you suggest handling patch
25, where sometimes AIF3 needs to write to AIF2's clock register?

Cheers,
Samuel

> With that fixed,
> Acked-by: Maxime Ripard <mripard@kernel.org>
> 
> Maxime
> 


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
@ 2020-10-06  4:51       ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:51 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

On 10/5/20 7:04 AM, Maxime Ripard wrote:
> Hi,
> 
> On Wed, Sep 30, 2020 at 09:11:46PM -0500, Samuel Holland wrote:
>> The AIF clock control register has the same layout for all three AIFs.
>> The only difference between them is that AIF3 is missing some fields. We
>> can reuse the same register field definitions for all three registers,
>> and use the DAI ID to select the correct register address.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>  sound/soc/sunxi/sun8i-codec.c | 64 +++++++++++++++++++----------------
>>  1 file changed, 34 insertions(+), 30 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 032a3f714dbb..1c34502ac47a 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -37,23 +37,23 @@
>>  #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
>>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
>> -#define SUN8I_AIF1CLK_CTRL				0x040
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
>> +#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
>> +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
>> +#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
>> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
>> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
>> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
>> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
>>  #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
>> @@ -83,21 +83,21 @@
>>  #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_CLK_INV_MASK	GENMASK(14, 13)
>> -#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)
>> +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
>> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
>> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
>> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
>> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
>>  
>>  #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
>>  
>>  #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
>>  				 SNDRV_PCM_FMTBIT_S16_LE |\
>>  				 SNDRV_PCM_FMTBIT_S20_LE |\
>>  				 SNDRV_PCM_FMTBIT_S24_LE |\
>>  				 SNDRV_PCM_FMTBIT_S20_3LE|\
>> @@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
>>  			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
>>  
>>  	return 0;
>>  }
>>  
>>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>>  {
>>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
>> +	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
>>  	u32 format, invert, value;
>>  
>>  	/* clock masters */
>>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>>  		value = 0x1;
>>  		break;
>>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>>  		value = 0x0;
>>  		break;
>>  	default:
>>  		return -EINVAL;
>>  	}
>> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
>> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
>> +
>> +	regmap_update_bits(scodec->regmap, reg,
>> +			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
>> +			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
> 
> I guess it would be more readable without the intermediate variable to
> store the register.

You mean you want me to call `SUN8I_AIF_CLK_CTRL(dai->id)` in each
regmap_update_bits call? I don't know that the compiler could optimize
that due to the pointer read. And how would you suggest handling patch
25, where sometimes AIF3 needs to write to AIF2's clock register?

Cheers,
Samuel

> With that fixed,
> Acked-by: Maxime Ripard <mripard@kernel.org>
> 
> Maxime
> 


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
@ 2020-10-06  4:51       ` Samuel Holland
  0 siblings, 0 replies; 181+ messages in thread
From: Samuel Holland @ 2020-10-06  4:51 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel

On 10/5/20 7:04 AM, Maxime Ripard wrote:
> Hi,
> 
> On Wed, Sep 30, 2020 at 09:11:46PM -0500, Samuel Holland wrote:
>> The AIF clock control register has the same layout for all three AIFs.
>> The only difference between them is that AIF3 is missing some fields. We
>> can reuse the same register field definitions for all three registers,
>> and use the DAI ID to select the correct register address.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>  sound/soc/sunxi/sun8i-codec.c | 64 +++++++++++++++++++----------------
>>  1 file changed, 34 insertions(+), 30 deletions(-)
>>
>> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
>> index 032a3f714dbb..1c34502ac47a 100644
>> --- a/sound/soc/sunxi/sun8i-codec.c
>> +++ b/sound/soc/sunxi/sun8i-codec.c
>> @@ -37,23 +37,23 @@
>>  #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
>>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
>> -#define SUN8I_AIF1CLK_CTRL				0x040
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
>> -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
>> +#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
>> +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
>> +#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
>> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
>> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
>> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
>> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
>>  #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
>> @@ -83,21 +83,21 @@
>>  #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_CLK_INV_MASK	GENMASK(14, 13)
>> -#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)
>> +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
>> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
>> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
>> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
>> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
>>  
>>  #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
>>  
>>  #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
>>  				 SNDRV_PCM_FMTBIT_S16_LE |\
>>  				 SNDRV_PCM_FMTBIT_S20_LE |\
>>  				 SNDRV_PCM_FMTBIT_S24_LE |\
>>  				 SNDRV_PCM_FMTBIT_S20_3LE|\
>> @@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
>>  			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
>>  
>>  	return 0;
>>  }
>>  
>>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
>>  {
>>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
>> +	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
>>  	u32 format, invert, value;
>>  
>>  	/* clock masters */
>>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
>>  		value = 0x1;
>>  		break;
>>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
>>  		value = 0x0;
>>  		break;
>>  	default:
>>  		return -EINVAL;
>>  	}
>> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
>> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
>> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
>> +
>> +	regmap_update_bits(scodec->regmap, reg,
>> +			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
>> +			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
> 
> I guess it would be more readable without the intermediate variable to
> store the register.

You mean you want me to call `SUN8I_AIF_CLK_CTRL(dai->id)` in each
regmap_update_bits call? I don't know that the compiler could optimize
that due to the pointer read. And how would you suggest handling patch
25, where sometimes AIF3 needs to write to AIF2's clock register?

Cheers,
Samuel

> With that fixed,
> Acked-by: Maxime Ripard <mripard@kernel.org>
> 
> Maxime
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
  2020-10-06  4:29       ` Samuel Holland
  (?)
@ 2020-10-08 12:59         ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-08 12:59 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 6211 bytes --]

On Mon, Oct 05, 2020 at 11:29:51PM -0500, Samuel Holland wrote:
> 
> On 10/5/20 6:30 AM, Maxime Ripard wrote:
> > On Wed, Sep 30, 2020 at 09:11:34PM -0500, Samuel Holland wrote:
> > > When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
> > > independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
> > > LRCK inversion is not supported. The register bit is repurposed to
> > > select between DSP_A and DSP_B. Extend the driver to support this.
> > > 
> > > Signed-off-by: Samuel Holland <samuel@sholland.org>
> > > ---
> > >   sound/soc/sunxi/sun8i-codec.c | 57 +++++++++++++++++++++++------------
> > >   1 file changed, 37 insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> > > index 0b713b2a2028..506420fb355c 100644
> > > --- a/sound/soc/sunxi/sun8i-codec.c
> > > +++ b/sound/soc/sunxi/sun8i-codec.c
> > > @@ -39,18 +39,17 @@
> > >   #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
> > >   #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
> > >   #define SUN8I_AIF1CLK_CTRL				0x040
> > >   #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> > > -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
> > > -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
> > > +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
> > >   #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
> > >   #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
> > >   #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_AD0L_ENA		15
> > >   #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
> > > @@ -85,16 +84,17 @@
> > >   #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_CLK_INV_MASK	GENMASK(14, 13)
> > >   #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)
> > >   enum {
> > >   	AIF1,
> > >   	NAIFS
> > > @@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > >   }
> > >   static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> > >   {
> > >   	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> > > -	u32 format, value;
> > > +	u32 format, invert, value;
> > >   	/* clock masters */
> > >   	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> > >   	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
> > >   		value = 0x1;
> > >   		break;
> > >   	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
> > >   		value = 0x0;
> > > @@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> > >   		break;
> > >   	case SND_SOC_DAIFMT_LEFT_J:
> > >   		format = 0x1;
> > >   		break;
> > >   	case SND_SOC_DAIFMT_RIGHT_J:
> > >   		format = 0x2;
> > >   		break;
> > >   	case SND_SOC_DAIFMT_DSP_A:
> > > +		format = 0x3;
> > > +		invert = 0x0; /* Set LRCK_INV to 0 */
> > > +		break;
> > >   	case SND_SOC_DAIFMT_DSP_B:
> > >   		format = 0x3;
> > > +		invert = 0x1; /* Set LRCK_INV to 1 */
> > >   		break;
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > >   	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> > >   			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
> > >   			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
> > >   	/* clock inversion */
> > >   	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> > >   	case SND_SOC_DAIFMT_NB_NF: /* Normal */
> > >   		value = 0x0;
> > >   		break;
> > > -	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
> > > +	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
> > >   		value = 0x1;
> > >   		break;
> > > +	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
> > > +		value = 0x2;
> > > +		break;
> > > +	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
> > > +		value = 0x3;
> > > +		break;
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > > -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> > > -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
> > > -			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
> > > -	/*
> > > -	 * 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;
> > > +	if (format == 0x3) {
> > 
> > Could we use a define here? That would be more readable
> 
> Yes, I can do that.
> 
> > > +		/* Inverted LRCK is not available in DSP mode. */
> > > +		if (value & BIT(0))
> > > +			return -EINVAL;
> > 
> > And same thing here, explicitly testing both for DSP_A and DSP_B would
> > be more readable.
> 
> Here, `value & BIT(0)` means SND_SOC_DAIFMT_NB_IF ||
> SND_SOC_DAIFMT_IB_IF, not selecting the DSP format.
> 
> > (And I guess value isn't such a great variable name anymore either)
> 
> If I rename `invert` to `dsp_format`, and replace `value` here with
> `invert`, I think that would be more clear.

Yep, definitely :)

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
@ 2020-10-08 12:59         ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-08 12:59 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 6211 bytes --]

On Mon, Oct 05, 2020 at 11:29:51PM -0500, Samuel Holland wrote:
> 
> On 10/5/20 6:30 AM, Maxime Ripard wrote:
> > On Wed, Sep 30, 2020 at 09:11:34PM -0500, Samuel Holland wrote:
> > > When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
> > > independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
> > > LRCK inversion is not supported. The register bit is repurposed to
> > > select between DSP_A and DSP_B. Extend the driver to support this.
> > > 
> > > Signed-off-by: Samuel Holland <samuel@sholland.org>
> > > ---
> > >   sound/soc/sunxi/sun8i-codec.c | 57 +++++++++++++++++++++++------------
> > >   1 file changed, 37 insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> > > index 0b713b2a2028..506420fb355c 100644
> > > --- a/sound/soc/sunxi/sun8i-codec.c
> > > +++ b/sound/soc/sunxi/sun8i-codec.c
> > > @@ -39,18 +39,17 @@
> > >   #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
> > >   #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
> > >   #define SUN8I_AIF1CLK_CTRL				0x040
> > >   #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> > > -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
> > > -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
> > > +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
> > >   #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
> > >   #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
> > >   #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_AD0L_ENA		15
> > >   #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
> > > @@ -85,16 +84,17 @@
> > >   #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_CLK_INV_MASK	GENMASK(14, 13)
> > >   #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)
> > >   enum {
> > >   	AIF1,
> > >   	NAIFS
> > > @@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > >   }
> > >   static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> > >   {
> > >   	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> > > -	u32 format, value;
> > > +	u32 format, invert, value;
> > >   	/* clock masters */
> > >   	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> > >   	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
> > >   		value = 0x1;
> > >   		break;
> > >   	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
> > >   		value = 0x0;
> > > @@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> > >   		break;
> > >   	case SND_SOC_DAIFMT_LEFT_J:
> > >   		format = 0x1;
> > >   		break;
> > >   	case SND_SOC_DAIFMT_RIGHT_J:
> > >   		format = 0x2;
> > >   		break;
> > >   	case SND_SOC_DAIFMT_DSP_A:
> > > +		format = 0x3;
> > > +		invert = 0x0; /* Set LRCK_INV to 0 */
> > > +		break;
> > >   	case SND_SOC_DAIFMT_DSP_B:
> > >   		format = 0x3;
> > > +		invert = 0x1; /* Set LRCK_INV to 1 */
> > >   		break;
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > >   	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> > >   			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
> > >   			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
> > >   	/* clock inversion */
> > >   	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> > >   	case SND_SOC_DAIFMT_NB_NF: /* Normal */
> > >   		value = 0x0;
> > >   		break;
> > > -	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
> > > +	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
> > >   		value = 0x1;
> > >   		break;
> > > +	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
> > > +		value = 0x2;
> > > +		break;
> > > +	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
> > > +		value = 0x3;
> > > +		break;
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > > -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> > > -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
> > > -			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
> > > -	/*
> > > -	 * 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;
> > > +	if (format == 0x3) {
> > 
> > Could we use a define here? That would be more readable
> 
> Yes, I can do that.
> 
> > > +		/* Inverted LRCK is not available in DSP mode. */
> > > +		if (value & BIT(0))
> > > +			return -EINVAL;
> > 
> > And same thing here, explicitly testing both for DSP_A and DSP_B would
> > be more readable.
> 
> Here, `value & BIT(0)` means SND_SOC_DAIFMT_NB_IF ||
> SND_SOC_DAIFMT_IB_IF, not selecting the DSP format.
> 
> > (And I guess value isn't such a great variable name anymore either)
> 
> If I rename `invert` to `dsp_format`, and replace `value` here with
> `invert`, I think that would be more clear.

Yep, definitely :)

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions
@ 2020-10-08 12:59         ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-08 12:59 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 6211 bytes --]

On Mon, Oct 05, 2020 at 11:29:51PM -0500, Samuel Holland wrote:
> 
> On 10/5/20 6:30 AM, Maxime Ripard wrote:
> > On Wed, Sep 30, 2020 at 09:11:34PM -0500, Samuel Holland wrote:
> > > When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports
> > > independent BCLK and LRCK inversion control. When using DSP_A or DSP_B,
> > > LRCK inversion is not supported. The register bit is repurposed to
> > > select between DSP_A and DSP_B. Extend the driver to support this.
> > > 
> > > Signed-off-by: Samuel Holland <samuel@sholland.org>
> > > ---
> > >   sound/soc/sunxi/sun8i-codec.c | 57 +++++++++++++++++++++++------------
> > >   1 file changed, 37 insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> > > index 0b713b2a2028..506420fb355c 100644
> > > --- a/sound/soc/sunxi/sun8i-codec.c
> > > +++ b/sound/soc/sunxi/sun8i-codec.c
> > > @@ -39,18 +39,17 @@
> > >   #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
> > >   #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
> > >   #define SUN8I_AIF1CLK_CTRL				0x040
> > >   #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> > > -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
> > > -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
> > > +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
> > >   #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
> > >   #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
> > >   #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_AD0L_ENA		15
> > >   #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
> > > @@ -85,16 +84,17 @@
> > >   #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_CLK_INV_MASK	GENMASK(14, 13)
> > >   #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)
> > >   enum {
> > >   	AIF1,
> > >   	NAIFS
> > > @@ -168,17 +168,17 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > >   }
> > >   static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> > >   {
> > >   	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> > > -	u32 format, value;
> > > +	u32 format, invert, value;
> > >   	/* clock masters */
> > >   	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> > >   	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
> > >   		value = 0x1;
> > >   		break;
> > >   	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
> > >   		value = 0x0;
> > > @@ -197,55 +197,72 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> > >   		break;
> > >   	case SND_SOC_DAIFMT_LEFT_J:
> > >   		format = 0x1;
> > >   		break;
> > >   	case SND_SOC_DAIFMT_RIGHT_J:
> > >   		format = 0x2;
> > >   		break;
> > >   	case SND_SOC_DAIFMT_DSP_A:
> > > +		format = 0x3;
> > > +		invert = 0x0; /* Set LRCK_INV to 0 */
> > > +		break;
> > >   	case SND_SOC_DAIFMT_DSP_B:
> > >   		format = 0x3;
> > > +		invert = 0x1; /* Set LRCK_INV to 1 */
> > >   		break;
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > >   	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> > >   			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
> > >   			   format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
> > >   	/* clock inversion */
> > >   	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> > >   	case SND_SOC_DAIFMT_NB_NF: /* Normal */
> > >   		value = 0x0;
> > >   		break;
> > > -	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
> > > +	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
> > >   		value = 0x1;
> > >   		break;
> > > +	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
> > > +		value = 0x2;
> > > +		break;
> > > +	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
> > > +		value = 0x3;
> > > +		break;
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > > -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> > > -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
> > > -			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
> > > -	/*
> > > -	 * 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;
> > > +	if (format == 0x3) {
> > 
> > Could we use a define here? That would be more readable
> 
> Yes, I can do that.
> 
> > > +		/* Inverted LRCK is not available in DSP mode. */
> > > +		if (value & BIT(0))
> > > +			return -EINVAL;
> > 
> > And same thing here, explicitly testing both for DSP_A and DSP_B would
> > be more readable.
> 
> Here, `value & BIT(0)` means SND_SOC_DAIFMT_NB_IF ||
> SND_SOC_DAIFMT_IB_IF, not selecting the DSP format.
> 
> > (And I guess value isn't such a great variable name anymore either)
> 
> If I rename `invert` to `dsp_format`, and replace `value` here with
> `invert`, I think that would be more clear.

Yep, definitely :)

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
  2020-10-06  4:43       ` Samuel Holland
  (?)
@ 2020-10-08 13:02         ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-08 13:02 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4055 bytes --]

On Mon, Oct 05, 2020 at 11:43:51PM -0500, Samuel Holland wrote:
> On 10/5/20 7:01 AM, Maxime Ripard wrote:
> > On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
> >> The codec's clock input is shared among all AIFs, and shared with other
> >> audio-related hardware in the SoC, including I2S and SPDIF controllers.
> >> To ensure sample rates selected by userspace or by codec2codec DAI links
> >> are maintained, the clock rate must be protected while it is in use.
> >>
> >> Signed-off-by: Samuel Holland <samuel@sholland.org>
> >> ---
> >>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
> >>  1 file changed, 22 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> >> index 501af64d43a0..86065bee7cd3 100644
> >> --- a/sound/soc/sunxi/sun8i-codec.c
> >> +++ b/sound/soc/sunxi/sun8i-codec.c
> >> @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
> >>  	unsigned int div = slots * slot_width;
> >>  
> >>  	if (div < 16 || div > 256)
> >>  		return -EINVAL;
> >>  
> >>  	return order_base_2(div);
> >>  }
> >>  
> >> +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
> >> +{
> >> +	return sample_rate % 4000 ? 22579200 : 24576000;
> >> +}
> >> +
> >>  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_dai_get_drvdata(dai);
> >>  	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
> >>  	unsigned int sample_rate = params_rate(params);
> >>  	unsigned int slots = aif->slots ?: params_channels(params);
> >>  	unsigned int slot_width = aif->slot_width ?: params_width(params);
> >> -	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
> >> -	int lrck_div_order, word_size;
> >> +	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
> >> +	int lrck_div_order, ret, word_size;
> >>  	u8 bclk_div;
> >>  
> >>  	/* word size */
> >>  	switch (params_width(params)) {
> >>  	case 8:
> >>  		word_size = 0x0;
> >>  		break;
> >>  	case 16:
> >> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
> >>  			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
> >>  
> >>  	/* BCLK divider (SYSCLK/BCLK ratio) */
> >>  	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
> >>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> >>  			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
> >>  			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
> >>  
> >> -	if (!aif->open_streams) {
> >> +	/* SYSCLK rate */
> >> +	if (aif->open_streams) {
> >> +		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
> >> +		if (ret < 0)
> >> +			return ret;
> >> +	} else {
> >> +		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
> > 
> > It's not really clear to me why we wouldn't want to always protect the
> > clock rate here?
> 
> From Documentation/sound/kernel-api/writing-an-alsa-driver.rst:
> 
>     hw_params callback
>     ...
>     Note that this and ``prepare`` callbacks may be called multiple
>     times per initialization. For example, the OSS emulation may call
>     these callbacks at each change via its ioctl.
> 
> Clock rate protection is reference counted, so we must only take one
> reference (or at least a known number of references) per stream.

Ah, right.

Can you add a comment to make that more obvious?

> >> +		if (ret == -EBUSY)
> >> +			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
> >> +				"conflicts with other audio streams.\n",
> > 
> > This string creates a checkpatch warning.
> 
> I will put it on one line, though >100 columns is also a checkpatch warning.

Yeah, but in general having an error on a single line is more important.
That way you can then grep for that error message

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-08 13:02         ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-08 13:02 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 4055 bytes --]

On Mon, Oct 05, 2020 at 11:43:51PM -0500, Samuel Holland wrote:
> On 10/5/20 7:01 AM, Maxime Ripard wrote:
> > On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
> >> The codec's clock input is shared among all AIFs, and shared with other
> >> audio-related hardware in the SoC, including I2S and SPDIF controllers.
> >> To ensure sample rates selected by userspace or by codec2codec DAI links
> >> are maintained, the clock rate must be protected while it is in use.
> >>
> >> Signed-off-by: Samuel Holland <samuel@sholland.org>
> >> ---
> >>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
> >>  1 file changed, 22 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> >> index 501af64d43a0..86065bee7cd3 100644
> >> --- a/sound/soc/sunxi/sun8i-codec.c
> >> +++ b/sound/soc/sunxi/sun8i-codec.c
> >> @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
> >>  	unsigned int div = slots * slot_width;
> >>  
> >>  	if (div < 16 || div > 256)
> >>  		return -EINVAL;
> >>  
> >>  	return order_base_2(div);
> >>  }
> >>  
> >> +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
> >> +{
> >> +	return sample_rate % 4000 ? 22579200 : 24576000;
> >> +}
> >> +
> >>  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_dai_get_drvdata(dai);
> >>  	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
> >>  	unsigned int sample_rate = params_rate(params);
> >>  	unsigned int slots = aif->slots ?: params_channels(params);
> >>  	unsigned int slot_width = aif->slot_width ?: params_width(params);
> >> -	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
> >> -	int lrck_div_order, word_size;
> >> +	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
> >> +	int lrck_div_order, ret, word_size;
> >>  	u8 bclk_div;
> >>  
> >>  	/* word size */
> >>  	switch (params_width(params)) {
> >>  	case 8:
> >>  		word_size = 0x0;
> >>  		break;
> >>  	case 16:
> >> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
> >>  			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
> >>  
> >>  	/* BCLK divider (SYSCLK/BCLK ratio) */
> >>  	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
> >>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> >>  			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
> >>  			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
> >>  
> >> -	if (!aif->open_streams) {
> >> +	/* SYSCLK rate */
> >> +	if (aif->open_streams) {
> >> +		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
> >> +		if (ret < 0)
> >> +			return ret;
> >> +	} else {
> >> +		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
> > 
> > It's not really clear to me why we wouldn't want to always protect the
> > clock rate here?
> 
> From Documentation/sound/kernel-api/writing-an-alsa-driver.rst:
> 
>     hw_params callback
>     ...
>     Note that this and ``prepare`` callbacks may be called multiple
>     times per initialization. For example, the OSS emulation may call
>     these callbacks at each change via its ioctl.
> 
> Clock rate protection is reference counted, so we must only take one
> reference (or at least a known number of references) per stream.

Ah, right.

Can you add a comment to make that more obvious?

> >> +		if (ret == -EBUSY)
> >> +			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
> >> +				"conflicts with other audio streams.\n",
> > 
> > This string creates a checkpatch warning.
> 
> I will put it on one line, though >100 columns is also a checkpatch warning.

Yeah, but in general having an error on a single line is more important.
That way you can then grep for that error message

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open
@ 2020-10-08 13:02         ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-08 13:02 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 4055 bytes --]

On Mon, Oct 05, 2020 at 11:43:51PM -0500, Samuel Holland wrote:
> On 10/5/20 7:01 AM, Maxime Ripard wrote:
> > On Wed, Sep 30, 2020 at 09:11:43PM -0500, Samuel Holland wrote:
> >> The codec's clock input is shared among all AIFs, and shared with other
> >> audio-related hardware in the SoC, including I2S and SPDIF controllers.
> >> To ensure sample rates selected by userspace or by codec2codec DAI links
> >> are maintained, the clock rate must be protected while it is in use.
> >>
> >> Signed-off-by: Samuel Holland <samuel@sholland.org>
> >> ---
> >>  sound/soc/sunxi/sun8i-codec.c | 25 ++++++++++++++++++++++---
> >>  1 file changed, 22 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> >> index 501af64d43a0..86065bee7cd3 100644
> >> --- a/sound/soc/sunxi/sun8i-codec.c
> >> +++ b/sound/soc/sunxi/sun8i-codec.c
> >> @@ -416,27 +416,32 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots,
> >>  	unsigned int div = slots * slot_width;
> >>  
> >>  	if (div < 16 || div > 256)
> >>  		return -EINVAL;
> >>  
> >>  	return order_base_2(div);
> >>  }
> >>  
> >> +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
> >> +{
> >> +	return sample_rate % 4000 ? 22579200 : 24576000;
> >> +}
> >> +
> >>  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_dai_get_drvdata(dai);
> >>  	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
> >>  	unsigned int sample_rate = params_rate(params);
> >>  	unsigned int slots = aif->slots ?: params_channels(params);
> >>  	unsigned int slot_width = aif->slot_width ?: params_width(params);
> >> -	unsigned int sysclk_rate = clk_get_rate(scodec->clk_module);
> >> -	int lrck_div_order, word_size;
> >> +	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
> >> +	int lrck_div_order, ret, word_size;
> >>  	u8 bclk_div;
> >>  
> >>  	/* word size */
> >>  	switch (params_width(params)) {
> >>  	case 8:
> >>  		word_size = 0x0;
> >>  		break;
> >>  	case 16:
> >> @@ -466,17 +471,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
> >>  			   (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
> >>  
> >>  	/* BCLK divider (SYSCLK/BCLK ratio) */
> >>  	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
> >>  	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> >>  			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
> >>  			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
> >>  
> >> -	if (!aif->open_streams) {
> >> +	/* SYSCLK rate */
> >> +	if (aif->open_streams) {
> >> +		ret = clk_set_rate(scodec->clk_module, sysclk_rate);
> >> +		if (ret < 0)
> >> +			return ret;
> >> +	} else {
> >> +		ret = clk_set_rate_exclusive(scodec->clk_module, sysclk_rate);
> > 
> > It's not really clear to me why we wouldn't want to always protect the
> > clock rate here?
> 
> From Documentation/sound/kernel-api/writing-an-alsa-driver.rst:
> 
>     hw_params callback
>     ...
>     Note that this and ``prepare`` callbacks may be called multiple
>     times per initialization. For example, the OSS emulation may call
>     these callbacks at each change via its ioctl.
> 
> Clock rate protection is reference counted, so we must only take one
> reference (or at least a known number of references) per stream.

Ah, right.

Can you add a comment to make that more obvious?

> >> +		if (ret == -EBUSY)
> >> +			dev_err(dai->dev, "%s: clock is busy! Sample rate %u Hz "
> >> +				"conflicts with other audio streams.\n",
> > 
> > This string creates a checkpatch warning.
> 
> I will put it on one line, though >100 columns is also a checkpatch warning.

Yeah, but in general having an error on a single line is more important.
That way you can then grep for that error message

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
  2020-10-06  4:51       ` Samuel Holland
  (?)
@ 2020-10-12 11:17         ` Maxime Ripard
  -1 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-12 11:17 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Mark Brown, Liam Girdwood, Chen-Yu Tsai, Jaroslav Kysela,
	Takashi Iwai, Ondrej Jirman, alsa-devel, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 5617 bytes --]

On Mon, Oct 05, 2020 at 11:51:08PM -0500, Samuel Holland wrote:
> On 10/5/20 7:04 AM, Maxime Ripard wrote:
> > Hi,
> > 
> > On Wed, Sep 30, 2020 at 09:11:46PM -0500, Samuel Holland wrote:
> >> The AIF clock control register has the same layout for all three AIFs.
> >> The only difference between them is that AIF3 is missing some fields. We
> >> can reuse the same register field definitions for all three registers,
> >> and use the DAI ID to select the correct register address.
> >>
> >> Signed-off-by: Samuel Holland <samuel@sholland.org>
> >> ---
> >>  sound/soc/sunxi/sun8i-codec.c | 64 +++++++++++++++++++----------------
> >>  1 file changed, 34 insertions(+), 30 deletions(-)
> >>
> >> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> >> index 032a3f714dbb..1c34502ac47a 100644
> >> --- a/sound/soc/sunxi/sun8i-codec.c
> >> +++ b/sound/soc/sunxi/sun8i-codec.c
> >> @@ -37,23 +37,23 @@
> >>  #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
> >>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
> >> -#define SUN8I_AIF1CLK_CTRL				0x040
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
> >> +#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
> >> +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
> >> +#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
> >> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
> >> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
> >> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
> >> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
> >>  #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
> >> @@ -83,21 +83,21 @@
> >>  #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_CLK_INV_MASK	GENMASK(14, 13)
> >> -#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)
> >> +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
> >> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
> >> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
> >> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
> >> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
> >>  
> >>  #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
> >>  
> >>  #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
> >>  				 SNDRV_PCM_FMTBIT_S16_LE |\
> >>  				 SNDRV_PCM_FMTBIT_S20_LE |\
> >>  				 SNDRV_PCM_FMTBIT_S24_LE |\
> >>  				 SNDRV_PCM_FMTBIT_S20_3LE|\
> >> @@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
> >>  			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
> >>  
> >>  	return 0;
> >>  }
> >>  
> >>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> >>  {
> >>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> >> +	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
> >>  	u32 format, invert, value;
> >>  
> >>  	/* clock masters */
> >>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> >>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
> >>  		value = 0x1;
> >>  		break;
> >>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
> >>  		value = 0x0;
> >>  		break;
> >>  	default:
> >>  		return -EINVAL;
> >>  	}
> >> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> >> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
> >> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
> >> +
> >> +	regmap_update_bits(scodec->regmap, reg,
> >> +			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
> >> +			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
> > 
> > I guess it would be more readable without the intermediate variable to
> > store the register.
> 
> You mean you want me to call `SUN8I_AIF_CLK_CTRL(dai->id)` in each
> regmap_update_bits call?

Yep

> I don't know that the compiler could optimize that due to the pointer
> read. And how would you suggest handling patch 25, where sometimes
> AIF3 needs to write to AIF2's clock register?

I'm not sure the compiler optimisation really matters anyway. It's not
really a fast path, and assuming it does the multiplication every time,
it will still be completely negligible compared to other operations done
in that function (starting with regmap_update_bits).

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
@ 2020-10-12 11:17         ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-12 11:17 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 5617 bytes --]

On Mon, Oct 05, 2020 at 11:51:08PM -0500, Samuel Holland wrote:
> On 10/5/20 7:04 AM, Maxime Ripard wrote:
> > Hi,
> > 
> > On Wed, Sep 30, 2020 at 09:11:46PM -0500, Samuel Holland wrote:
> >> The AIF clock control register has the same layout for all three AIFs.
> >> The only difference between them is that AIF3 is missing some fields. We
> >> can reuse the same register field definitions for all three registers,
> >> and use the DAI ID to select the correct register address.
> >>
> >> Signed-off-by: Samuel Holland <samuel@sholland.org>
> >> ---
> >>  sound/soc/sunxi/sun8i-codec.c | 64 +++++++++++++++++++----------------
> >>  1 file changed, 34 insertions(+), 30 deletions(-)
> >>
> >> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> >> index 032a3f714dbb..1c34502ac47a 100644
> >> --- a/sound/soc/sunxi/sun8i-codec.c
> >> +++ b/sound/soc/sunxi/sun8i-codec.c
> >> @@ -37,23 +37,23 @@
> >>  #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
> >>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
> >> -#define SUN8I_AIF1CLK_CTRL				0x040
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
> >> +#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
> >> +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
> >> +#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
> >> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
> >> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
> >> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
> >> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
> >>  #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
> >> @@ -83,21 +83,21 @@
> >>  #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_CLK_INV_MASK	GENMASK(14, 13)
> >> -#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)
> >> +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
> >> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
> >> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
> >> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
> >> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
> >>  
> >>  #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
> >>  
> >>  #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
> >>  				 SNDRV_PCM_FMTBIT_S16_LE |\
> >>  				 SNDRV_PCM_FMTBIT_S20_LE |\
> >>  				 SNDRV_PCM_FMTBIT_S24_LE |\
> >>  				 SNDRV_PCM_FMTBIT_S20_3LE|\
> >> @@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
> >>  			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
> >>  
> >>  	return 0;
> >>  }
> >>  
> >>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> >>  {
> >>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> >> +	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
> >>  	u32 format, invert, value;
> >>  
> >>  	/* clock masters */
> >>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> >>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
> >>  		value = 0x1;
> >>  		break;
> >>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
> >>  		value = 0x0;
> >>  		break;
> >>  	default:
> >>  		return -EINVAL;
> >>  	}
> >> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> >> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
> >> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
> >> +
> >> +	regmap_update_bits(scodec->regmap, reg,
> >> +			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
> >> +			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
> > 
> > I guess it would be more readable without the intermediate variable to
> > store the register.
> 
> You mean you want me to call `SUN8I_AIF_CLK_CTRL(dai->id)` in each
> regmap_update_bits call?

Yep

> I don't know that the compiler could optimize that due to the pointer
> read. And how would you suggest handling patch 25, where sometimes
> AIF3 needs to write to AIF2's clock register?

I'm not sure the compiler optimisation really matters anyway. It's not
really a fast path, and assuming it does the multiplication every time,
it will still be completely negligible compared to other operations done
in that function (starting with regmap_update_bits).

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control
@ 2020-10-12 11:17         ` Maxime Ripard
  0 siblings, 0 replies; 181+ messages in thread
From: Maxime Ripard @ 2020-10-12 11:17 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, alsa-devel, linux-kernel, Takashi Iwai,
	Liam Girdwood, Chen-Yu Tsai, Mark Brown, Jaroslav Kysela,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 5617 bytes --]

On Mon, Oct 05, 2020 at 11:51:08PM -0500, Samuel Holland wrote:
> On 10/5/20 7:04 AM, Maxime Ripard wrote:
> > Hi,
> > 
> > On Wed, Sep 30, 2020 at 09:11:46PM -0500, Samuel Holland wrote:
> >> The AIF clock control register has the same layout for all three AIFs.
> >> The only difference between them is that AIF3 is missing some fields. We
> >> can reuse the same register field definitions for all three registers,
> >> and use the DAI ID to select the correct register address.
> >>
> >> Signed-off-by: Samuel Holland <samuel@sholland.org>
> >> ---
> >>  sound/soc/sunxi/sun8i-codec.c | 64 +++++++++++++++++++----------------
> >>  1 file changed, 34 insertions(+), 30 deletions(-)
> >>
> >> diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
> >> index 032a3f714dbb..1c34502ac47a 100644
> >> --- a/sound/soc/sunxi/sun8i-codec.c
> >> +++ b/sound/soc/sunxi/sun8i-codec.c
> >> @@ -37,23 +37,23 @@
> >>  #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
> >>  #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
> >> -#define SUN8I_AIF1CLK_CTRL				0x040
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV			13
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
> >> -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
> >> +#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
> >> +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
> >> +#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
> >> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
> >> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
> >> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
> >> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
> >>  #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
> >> @@ -83,21 +83,21 @@
> >>  #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_CLK_INV_MASK	GENMASK(14, 13)
> >> -#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)
> >> +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
> >> +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
> >> +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
> >> +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
> >> +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
> >>  
> >>  #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
> >>  
> >>  #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
> >>  				 SNDRV_PCM_FMTBIT_S16_LE |\
> >>  				 SNDRV_PCM_FMTBIT_S20_LE |\
> >>  				 SNDRV_PCM_FMTBIT_S24_LE |\
> >>  				 SNDRV_PCM_FMTBIT_S20_3LE|\
> >> @@ -223,32 +223,34 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
> >>  			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
> >>  
> >>  	return 0;
> >>  }
> >>  
> >>  static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> >>  {
> >>  	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
> >> +	u32 reg = SUN8I_AIF_CLK_CTRL(dai->id);
> >>  	u32 format, invert, value;
> >>  
> >>  	/* clock masters */
> >>  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> >>  	case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
> >>  		value = 0x1;
> >>  		break;
> >>  	case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
> >>  		value = 0x0;
> >>  		break;
> >>  	default:
> >>  		return -EINVAL;
> >>  	}
> >> -	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
> >> -			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
> >> -			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
> >> +
> >> +	regmap_update_bits(scodec->regmap, reg,
> >> +			   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
> >> +			   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
> > 
> > I guess it would be more readable without the intermediate variable to
> > store the register.
> 
> You mean you want me to call `SUN8I_AIF_CLK_CTRL(dai->id)` in each
> regmap_update_bits call?

Yep

> I don't know that the compiler could optimize that due to the pointer
> read. And how would you suggest handling patch 25, where sometimes
> AIF3 needs to write to AIF2's clock register?

I'm not sure the compiler optimisation really matters anyway. It's not
really a fast path, and assuming it does the multiplication every time,
it will still be completely negligible compared to other operations done
in that function (starting with regmap_update_bits).

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 181+ messages in thread

end of thread, other threads:[~2020-10-12 11:19 UTC | newest]

Thread overview: 181+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-01  2:11 [PATCH 00/25] ASoC: sun8i-codec: support for AIF2 and AIF3 Samuel Holland
2020-10-01  2:11 ` Samuel Holland
2020-10-01  2:11 ` Samuel Holland
2020-10-01  2:11 ` [PATCH 01/25] ASoC: sun8i-codec: Set up clock tree at probe time Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05  9:53   ` Maxime Ripard
2020-10-05  9:53     ` Maxime Ripard
2020-10-05  9:53     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 02/25] ASoC: sun8i-codec: Swap module clock/reset dependencies Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05  9:54   ` Maxime Ripard
2020-10-05  9:54     ` Maxime Ripard
2020-10-05  9:54     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 03/25] ASoC: sun8i-codec: Sort DAPM controls, widgets, and routes Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05  9:54   ` Maxime Ripard
2020-10-05  9:54     ` Maxime Ripard
2020-10-05  9:54     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 04/25] ASoC: sun8i-codec: Consistently name DAPM widgets " Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05  9:57   ` Maxime Ripard
2020-10-05  9:57     ` Maxime Ripard
2020-10-05  9:57     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 05/25] ASoC: sun8i-codec: Correct DAPM widget types Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05  9:57   ` Maxime Ripard
2020-10-05  9:57     ` Maxime Ripard
2020-10-05  9:57     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 06/25] ASoC: sun8i-codec: Fix AIF widget channel references Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 10:00   ` Maxime Ripard
2020-10-05 10:00     ` Maxime Ripard
2020-10-05 10:00     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 07/25] ASoC: sun8i-codec: Enable AIF mono/stereo control Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 10:00   ` Maxime Ripard
2020-10-05 10:00     ` Maxime Ripard
2020-10-05 10:00     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 08/25] ASoC: sun8i-codec: Use snd_soc_dai_get_drvdata Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 10:01   ` Maxime Ripard
2020-10-05 10:01     ` Maxime Ripard
2020-10-05 10:01     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 09/25] ASoC: sun8i-codec: Prepare to extend the DAI driver Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:24   ` Maxime Ripard
2020-10-05 11:24     ` Maxime Ripard
2020-10-05 11:24     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 10/25] ASoC: sun8i-codec: Program format before clock inversion Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:26   ` Maxime Ripard
2020-10-05 11:26     ` Maxime Ripard
2020-10-05 11:26     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 11/25] ASoC: sun8i-codec: Enable all supported clock inversions Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:30   ` Maxime Ripard
2020-10-05 11:30     ` Maxime Ripard
2020-10-05 11:30     ` Maxime Ripard
2020-10-06  4:29     ` Samuel Holland
2020-10-06  4:29       ` Samuel Holland
2020-10-06  4:29       ` Samuel Holland
2020-10-08 12:59       ` Maxime Ripard
2020-10-08 12:59         ` Maxime Ripard
2020-10-08 12:59         ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 12/25] ASoC: sun8i-codec: Program the correct word size Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:30   ` Maxime Ripard
2020-10-05 11:30     ` Maxime Ripard
2020-10-05 11:30     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 13/25] ASoC: sun8i-codec: Round up the LRCK divisor Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:31   ` Maxime Ripard
2020-10-05 11:31     ` Maxime Ripard
2020-10-05 11:31     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 14/25] ASoC: sun8i-codec: Correct the BCLK divisor calculation Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:34   ` Maxime Ripard
2020-10-05 11:34     ` Maxime Ripard
2020-10-05 11:34     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 15/25] ASoC: sun8i-codec: Support the TDM slot binding Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:34   ` Maxime Ripard
2020-10-05 11:34     ` Maxime Ripard
2020-10-05 11:34     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 16/25] ASoC: sun8i-codec: Enforce symmetric DAI parameters Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:39   ` Maxime Ripard
2020-10-05 11:39     ` Maxime Ripard
2020-10-05 11:39     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 17/25] ASoC: sun8i-codec: Enable all supported sample rates Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:39   ` Maxime Ripard
2020-10-05 11:39     ` Maxime Ripard
2020-10-05 11:39     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 18/25] ASoC: sun8i-codec: Automatically set the system sample rate Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:58   ` Maxime Ripard
2020-10-05 11:58     ` Maxime Ripard
2020-10-05 11:58     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 19/25] ASoC: sun8i-codec: Constrain to compatible sample rates Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 11:59   ` Maxime Ripard
2020-10-05 11:59     ` Maxime Ripard
2020-10-05 11:59     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 20/25] ASoC: sun8i-codec: Protect the clock rate while streams are open Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01 13:27   ` kernel test robot
2020-10-01 13:27     ` kernel test robot
2020-10-01 13:27     ` kernel test robot
2020-10-01 13:27     ` kernel test robot
2020-10-05 12:01   ` Maxime Ripard
2020-10-05 12:01     ` Maxime Ripard
2020-10-05 12:01     ` Maxime Ripard
2020-10-05 13:15     ` Chen-Yu Tsai
2020-10-05 13:15       ` Chen-Yu Tsai
2020-10-05 13:15       ` Chen-Yu Tsai
2020-10-06  4:46       ` Samuel Holland
2020-10-06  4:46         ` Samuel Holland
2020-10-06  4:46         ` Samuel Holland
2020-10-06  4:43     ` Samuel Holland
2020-10-06  4:43       ` Samuel Holland
2020-10-06  4:43       ` Samuel Holland
2020-10-08 13:02       ` Maxime Ripard
2020-10-08 13:02         ` Maxime Ripard
2020-10-08 13:02         ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 21/25] ASoC: sun8i-codec: Require an exact BCLK divisor match Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 12:01   ` Maxime Ripard
2020-10-05 12:01     ` Maxime Ripard
2020-10-05 12:01     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 22/25] ASoC: sun8i-codec: Enable all supported PCM formats Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 12:02   ` Maxime Ripard
2020-10-05 12:02     ` Maxime Ripard
2020-10-05 12:02     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 23/25] ASoC: sun8i-codec: Generalize AIF clock control Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 12:04   ` Maxime Ripard
2020-10-05 12:04     ` Maxime Ripard
2020-10-05 12:04     ` Maxime Ripard
2020-10-06  4:51     ` Samuel Holland
2020-10-06  4:51       ` Samuel Holland
2020-10-06  4:51       ` Samuel Holland
2020-10-12 11:17       ` Maxime Ripard
2020-10-12 11:17         ` Maxime Ripard
2020-10-12 11:17         ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 24/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF2 Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 12:05   ` Maxime Ripard
2020-10-05 12:05     ` Maxime Ripard
2020-10-05 12:05     ` Maxime Ripard
2020-10-01  2:11 ` [PATCH 25/25] ASoC: sun8i-codec: Add a DAI, widgets, and routes for AIF3 Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-01  2:11   ` Samuel Holland
2020-10-05 17:54 ` [PATCH 00/25] ASoC: sun8i-codec: support for AIF2 and AIF3 Mark Brown
2020-10-05 17:54   ` Mark Brown
2020-10-05 17:54   ` Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.