[alsa-devel] [PATCH][ASoC]Add DT bindings for generic ASoC AC97 CODEC driver

Maciej S. Szmigiero mail at maciej.szmigiero.name
Fri Mar 6 19:55:26 CET 2015


Add and document DT bindings for generic ASoC AC97 CODEC driver,
make it selectable in config.

Signed-off-by: Maciej Szmigiero <mail at maciej.szmigiero.name>

diff --git a/Documentation/devicetree/bindings/sound/ac97-generic-codec.txt b/Documentation/devicetree/bindings/sound/ac97-generic-codec.txt
new file mode 100644
index 0000000..ce98698
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ac97-generic-codec.txt
@@ -0,0 +1,24 @@
+Generic ASoC AC97 CODEC driver
+
+Allows using codecs supported by generic ALSA AC97 code as codecs in ASoC.
+
+Required properties:
+
+  - compatible : "linux,ac97-codec"
+
+Optional properties:
+
+  - playback-rates : A list of supported playback rates.
+
+  - capture-rates : A list of supported capture rates.
+
+In case one or both of above properties are missing the relevant rate(s) are assumed
+to be 8000, 11025, 22050, 44100, 48000.
+
+Example:
+
+ac97codec: ac97-hifi {
+	compatible = "linux,ac97-codec";
+	playback-rates = <48000 44100 32000 24000 22050 16000 12000 11025 8000>;
+	capture-rates = <48000>;
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0bddd92..92d6d39 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -16,7 +16,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_88PM860X if MFD_88PM860X
 	select SND_SOC_L3
 	select SND_SOC_AB8500_CODEC if ABX500_CORE
-	select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
+	select SND_SOC_AC97_CODEC
 	select SND_SOC_AD1836 if SPI_MASTER
 	select SND_SOC_AD193X_SPI if SPI_MASTER
 	select SND_SOC_AD193X_I2C if I2C
@@ -210,8 +210,9 @@ config SND_SOC_AB8500_CODEC
 	tristate
 
 config SND_SOC_AC97_CODEC
-	tristate
+	tristate "Build generic ASoC AC97 CODEC driver"
 	select SND_AC97_CODEC
+	select SND_SOC_AC97_BUS
 
 config SND_SOC_AD1836
 	tristate
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index d0ac723..25125bf 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -23,6 +23,12 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
+struct ac97_private {
+	struct snd_ac97 *ac97;
+	struct snd_pcm_hw_constraint_list playback_rate_constraints;
+	struct snd_pcm_hw_constraint_list capture_rate_constraints;
+};
+
 static const struct snd_soc_dapm_widget ac97_widgets[] = {
 	SND_SOC_DAPM_INPUT("RX"),
 	SND_SOC_DAPM_OUTPUT("TX"),
@@ -33,22 +39,41 @@ static const struct snd_soc_dapm_route ac97_routes[] = {
 	{ "TX", NULL, "AC97 Playback" },
 };
 
+static const unsigned int default_rates[] = {
+	8000, 11025, 22050, 44100, 48000
+};
+
+static int ac97_startup(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ac97_private *ac97 = snd_soc_codec_get_drvdata(codec);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE,
+			&ac97->playback_rate_constraints);
+	else
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE,
+			&ac97->capture_rate_constraints);
+
+	return 0;
+}
+
 static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+	struct ac97_private *ac97 = snd_soc_codec_get_drvdata(codec);
 
 	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
-	return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
+	return snd_ac97_set_rate(ac97->ac97, reg, substream->runtime->rate);
 }
 
-#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
-		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
-		SNDRV_PCM_RATE_48000)
-
 static const struct snd_soc_dai_ops ac97_dai_ops = {
+	.startup	= ac97_startup,
 	.prepare	= ac97_prepare,
 };
 
@@ -58,20 +83,21 @@ static struct snd_soc_dai_driver ac97_dai = {
 		.stream_name = "AC97 Playback",
 		.channels_min = 1,
 		.channels_max = 2,
-		.rates = STD_AC97_RATES,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SND_SOC_STD_AC97_FMTS,},
 	.capture = {
 		.stream_name = "AC97 Capture",
 		.channels_min = 1,
 		.channels_max = 2,
-		.rates = STD_AC97_RATES,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SND_SOC_STD_AC97_FMTS,},
 	.ops = &ac97_dai_ops,
 };
 
 static int ac97_soc_probe(struct snd_soc_codec *codec)
 {
-	struct snd_ac97 *ac97;
+	struct ac97_private *ac97 = snd_soc_codec_get_drvdata(codec);
+
 	struct snd_ac97_bus *ac97_bus;
 	struct snd_ac97_template ac97_template;
 	int ret;
@@ -83,31 +109,28 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
 		return ret;
 
 	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
-	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
+	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97->ac97);
 	if (ret < 0)
 		return ret;
 
-	snd_soc_codec_set_drvdata(codec, ac97);
-
 	return 0;
 }
 
 #ifdef CONFIG_PM
 static int ac97_soc_suspend(struct snd_soc_codec *codec)
 {
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+	struct ac97_private *ac97 = snd_soc_codec_get_drvdata(codec);
 
-	snd_ac97_suspend(ac97);
+	snd_ac97_suspend(ac97->ac97);
 
 	return 0;
 }
 
 static int ac97_soc_resume(struct snd_soc_codec *codec)
 {
+	struct ac97_private *ac97 = snd_soc_codec_get_drvdata(codec);
 
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
-
-	snd_ac97_resume(ac97);
+	snd_ac97_resume(ac97->ac97);
 
 	return 0;
 }
@@ -127,8 +150,89 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
 	.num_dapm_routes = ARRAY_SIZE(ac97_routes),
 };
 
+#ifdef CONFIG_OF
+static int ac97_of_read_rates(struct platform_device *pdev,
+			const char *name,
+			struct snd_pcm_hw_constraint_list *cons)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct property *prop;
+	int len, count, ctr;
+	unsigned int *clist;
+
+	prop = of_find_property(np, name, &len);
+	if (!prop)
+		return 0;
+
+	count = len / sizeof(u32);
+	if (count <= 0)
+		return 0;
+
+	clist = devm_kzalloc(&pdev->dev, count * sizeof(unsigned int),
+				GFP_KERNEL);
+	if (!clist)
+		return -ENOMEM;
+
+	for (ctr = 0; ctr < count; ctr++) {
+		int ret;
+		u32 val;
+
+		ret = of_property_read_u32_index(np, name, ctr, &val);
+		if (ret)
+			return ret;
+
+		clist[ctr] = val;
+	}
+
+	cons->list = clist;
+	cons->count = ctr;
+
+	return 0;
+}
+#endif
+
 static int ac97_probe(struct platform_device *pdev)
 {
+	struct ac97_private *ac97 =
+		devm_kzalloc(&pdev->dev, sizeof(struct ac97_private),
+				GFP_KERNEL);
+#ifdef CONFIG_OF
+	struct device_node *np = pdev->dev.of_node;
+#endif
+
+	if (!ac97)
+		return -ENOMEM;
+
+#ifdef CONFIG_OF
+	if (np) {
+		int ret;
+
+		ret = ac97_of_read_rates(pdev, "playback-rates",
+			&ac97->playback_rate_constraints);
+		if (ret)
+			return ret;
+
+		ret = ac97_of_read_rates(pdev, "capture-rates",
+			&ac97->capture_rate_constraints);
+		if (ret)
+			return ret;
+	}
+#endif
+
+	if (!ac97->playback_rate_constraints.list) {
+		ac97->playback_rate_constraints.list = default_rates;
+		ac97->playback_rate_constraints.count =
+			ARRAY_SIZE(default_rates);
+	}
+
+	if (!ac97->capture_rate_constraints.list) {
+		ac97->capture_rate_constraints.list = default_rates;
+		ac97->capture_rate_constraints.count =
+			ARRAY_SIZE(default_rates);
+	}
+
+	platform_set_drvdata(pdev, ac97);
+
 	return snd_soc_register_codec(&pdev->dev,
 			&soc_codec_dev_ac97, &ac97_dai, 1);
 }
@@ -139,9 +243,16 @@ static int ac97_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id ac97_codec_dt_ids[] = {
+	{ .compatible = "linux,ac97-codec", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ac97_codec_dt_ids);
+
 static struct platform_driver ac97_codec_driver = {
 	.driver = {
 		.name = "ac97-codec",
+		.of_match_table = of_match_ptr(ac97_codec_dt_ids),
 	},
 
 	.probe = ac97_probe,



More information about the Alsa-devel mailing list