[Letux-kernel] [Internal RFC 07/16] ASoC: pcm1773-codec: write a driver for the PCM1773 chip from TI

H. Nikolaus Schaller hns at goldelico.com
Wed Sep 7 20:01:46 CEST 2022


From: Grond <grond66 at riseup.net>

This chip is used in the OpenPandora.

Signed-off-by: Grond <grond66 at riseup.net>
Signed-off-by: H. Nikolaus Schaller <hns at goldelico.com>
---
 sound/soc/codecs/Kconfig   |   5 ++
 sound/soc/codecs/Makefile  |   2 +
 sound/soc/codecs/pcm1773.c | 177 +++++++++++++++++++++++++++++++++++++
 3 files changed, 184 insertions(+)
 create mode 100644 sound/soc/codecs/pcm1773.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index d16b4efb88a77..fc7e6971c6801 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -150,6 +150,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_NAU8825
 	imply SND_SOC_HDMI_CODEC
 	imply SND_SOC_PCM1681
+	imply SND_SOC_PCM1773
 	imply SND_SOC_PCM1789_I2C
 	imply SND_SOC_PCM179X_I2C
 	imply SND_SOC_PCM179X_SPI
@@ -2012,6 +2013,10 @@ config SND_SOC_ZL38060
 	  which consists of a Digital Signal Processor (DSP), several Digital
 	  Audio Interfaces (DAIs), analog outputs, and a block of 14 GPIOs.
 
+config SND_SOC_PCM1773
+	tristate "TI PCM1773 audio output codec"
+	select GPIOLIB
+
 # Amp
 config SND_SOC_LM4857
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 92fd441d426a8..5d6bfadcd9ea0 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -161,6 +161,7 @@ snd-soc-nau8824-objs := nau8824.o
 snd-soc-nau8825-objs := nau8825.o
 snd-soc-hdmi-codec-objs := hdmi-codec.o
 snd-soc-pcm1681-objs := pcm1681.o
+snd-soc-pcm1773-objs := pcm1773.o
 snd-soc-pcm1789-codec-objs := pcm1789.o
 snd-soc-pcm1789-i2c-objs := pcm1789-i2c.o
 snd-soc-pcm179x-codec-objs := pcm179x.o
@@ -695,6 +696,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
 obj-$(CONFIG_SND_SOC_WSA881X)	+= snd-soc-wsa881x.o
 obj-$(CONFIG_SND_SOC_WSA883X)	+= snd-soc-wsa883x.o
 obj-$(CONFIG_SND_SOC_ZL38060)	+= snd-soc-zl38060.o
+obj-$(CONFIG_SND_SOC_PCM1773)	+= snd-soc-pcm1773.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
diff --git a/sound/soc/codecs/pcm1773.c b/sound/soc/codecs/pcm1773.c
new file mode 100644
index 0000000000000..20f8bf3302e56
--- /dev/null
+++ b/sound/soc/codecs/pcm1773.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * pcm1773.c -- codec for the simple PCM1773 output codec from TI
+ *
+ * Shamelessly cobbled together from sound/soc/ti/omap3pandora.c and a few
+ * other codec drivers in sound/soc/codecs/
+ *
+ * Author: Grond <grond66 at riseup.net>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+
+struct pcm1773 {
+	struct regulator *regulator;
+	bool has_enable_gpio;
+	int enable_gpio;
+};
+
+static int pcm1773_dac_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *k, int event)
+{
+	struct snd_soc_component *component = w->dapm->component;
+	struct pcm1773 *ctx = snd_soc_component_get_drvdata(component);
+	struct device *dev = component->dev;
+	int ret;
+
+	/*
+	 * The PCM1773 DAC datasheet requires 1ms delay between switching
+	 * VCC power on/off and /PD pin high/low
+	 */
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (ctx->regulator) {
+			ret = regulator_enable(ctx->regulator);
+			if (ret) {
+				dev_err(dev, "Failed to power DAC: %d\n", ret);
+				return ret;
+			}
+			mdelay(1);
+		}
+
+		if (ctx->has_enable_gpio)
+			gpio_set_value(ctx->enable_gpio, 1);
+	} else {
+		if (ctx->has_enable_gpio)
+			gpio_set_value(ctx->enable_gpio, 0);
+
+		if (ctx->regulator) {
+			mdelay(1);
+			regulator_disable(ctx->regulator);
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget pcm1773_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC_E("PCM1773 DAC", "HiFi Playback", SND_SOC_NOPM,
+			   0, 0, pcm1773_dac_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+};
+
+static const struct snd_soc_dapm_route pcm1773_dapm_routes[] = {
+	/* tell DAPM that the main stream flows to the PCM1773 */
+	{"PCM1773 DAC", NULL, "PCM1773 IN"},
+};
+
+static struct snd_soc_dai_driver pcm1773_dai = {
+	.name = "pcm1773-hifi",
+	.playback = {
+		.stream_name = "PCM1773 IN",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		// [TODO] these really should be BE, per the data sheet but for
+		// some reason the omap-mcbsp driver claims only to support LE.
+		// investigate
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+};
+
+static int pcm1773_probe(struct snd_soc_component *component)
+{
+	struct pcm1773 *ctx = NULL;
+	struct device *dev = component->dev;
+	struct device_node *of_node = dev->of_node;
+	int ret;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+	snd_soc_component_set_drvdata(component, ctx);
+
+	if (!of_node) {
+		dev_dbg(dev, "DT data not present for pcm1773-codec; assuming hardware handles regulators and chip enable appropriately");
+		return 0;
+	}
+
+	ctx->enable_gpio = of_get_named_gpio(of_node, "enable-gpio", 0);
+	if (ctx->enable_gpio <= 0) {
+		ctx->enable_gpio = 0;
+		dev_warn(dev, "invalid GPIO specification for enable-gpio");
+	} else {
+		ctx->has_enable_gpio = true;
+		dev_dbg(dev, "got enable-gpio %d", ctx->enable_gpio);
+
+		ret = gpio_request(ctx->enable_gpio, "dac_enable");
+		if (ret >= 0)
+			ret = gpio_direction_output(ctx->enable_gpio, 0);
+		if (ret < 0)
+			dev_err(dev, "failed to reserve GPIO %d as an output",
+				ctx->enable_gpio);
+			return ret;
+		}
+	}
+
+	ctx->regulator = regulator_get(dev, "vcc");
+	if (IS_ERR(ctx->regulator)) {
+		ctx->regulator = NULL;
+		dev_warn(dev, "cannot get regulator 'vcc'");
+	}
+
+	return 0;
+}
+
+static void pcm1773_remove(struct snd_soc_component *component)
+{
+	struct pcm1773 *ctx = snd_soc_component_get_drvdata(component);
+
+	if (ctx->regulator)
+		regulator_put(ctx->regulator);
+
+	if (ctx->has_enable_gpio)
+		gpio_free(ctx->enable_gpio);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_pcm1773 = {
+	.probe = pcm1773_probe,
+	.remove = pcm1773_remove,
+	.dapm_widgets = pcm1773_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(pcm1773_dapm_widgets),
+	.dapm_routes = pcm1773_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(pcm1773_dapm_routes),
+};
+
+static int pcm1773_codec_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+		&soc_component_dev_pcm1773,
+		&pcm1773_dai, 1);
+}
+
+static const struct of_device_id pcm1773_of_match[] = {
+	{
+		.compatible = "ti,pcm1773",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, pcm1773_of_match);
+
+static struct platform_driver pcm1773_codec_driver = {
+	.probe = pcm1773_codec_probe,
+	.driver = {
+		.name = "pcm1773-codec",
+		.of_match_table = pcm1773_of_match,
+	},
+};
+
+module_platform_driver(pcm1773_codec_driver);
+
+MODULE_DESCRIPTION("ASoC codec driver PCM1773");
+MODULE_AUTHOR("Grond");
+MODULE_LICENSE("GPL");
-- 
2.33.0



More information about the Letux-kernel mailing list