[PATCH 08/16] ASoC: pcm1773-codec: write a driver for the PCM1773 chip from TI
From: H. Nikolaus Schaller <hidden>
Date: 2026-07-11 06:02:49
Also in:
dri-devel, linux-arm-kernel, linux-devicetree, linux-omap, linux-sound, lkml
Subsystem:
sound, sound - soc layer / dynamic audio power management (asoc), the rest · Maintainers:
Jaroslav Kysela, Takashi Iwai, Liam Girdwood, Mark Brown, Linus Torvalds
From: Grond <redacted> This chip is used in the OpenPandora. Signed-off-by: Grond <redacted> Signed-off-by: H. Nikolaus Schaller <redacted> --- sound/soc/codecs/Kconfig | 5 ++ sound/soc/codecs/pcm1773.c | 149 +++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 sound/soc/codecs/pcm1773.c
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 252f683be3c18..3e186652fa06d 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig@@ -182,6 +182,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_HDMI_CODEC imply SND_SOC_PCM1681 imply SND_SOC_PCM1754 + imply SND_SOC_PCM1773 imply SND_SOC_PCM1789_I2C imply SND_SOC_PCM179X_I2C imply SND_SOC_PCM179X_SPI
@@ -1541,6 +1542,10 @@ config SND_SOC_PCM1754 tristate "Texas Instruments PCM1754 CODEC" depends on GPIOLIB +config SND_SOC_PCM1773 + tristate "Texas Instruments PCM1773 CODEC" + select GPIOLIB + config SND_SOC_PCM1789 tristate
diff --git a/sound/soc/codecs/pcm1773.c b/sound/soc/codecs/pcm1773.c
new file mode 100644
index 0000000000000..75f9fe40a89d5
--- /dev/null
+++ b/sound/soc/codecs/pcm1773.c@@ -0,0 +1,149 @@ +// 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@riseup.net> + */ + +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <sound/soc.h> + +struct pcm1773 { + struct regulator *regulator; + struct gpio_desc *enable_gpio; +}; + +static int pcm1773_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + 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->enable_gpio) + gpiod_set_value_cansleep(ctx->enable_gpio, 1); + } else { + if (ctx->enable_gpio) + gpiod_set_value_cansleep(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; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + snd_soc_component_set_drvdata(component, ctx); + + ctx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(ctx->enable_gpio)) { + return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio), + "invalid GPIO specification for enable"); + } + if (ctx->enable_gpio) + dev_dbg(dev, "got enable-gpio\n"); + else + dev_warn(dev, "enable-gpio not specified\n"); + + ctx->regulator = devm_regulator_get(dev, "vcc"); + if (IS_ERR(ctx->regulator)) { + dev_warn(dev, "cannot get regulator 'vcc'"); + ctx->regulator = NULL; + } + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_pcm1773 = { + .probe = pcm1773_probe, + .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.50.1 (Apple Git-155)