Add a UCLASS_SOUND driver for Texas Instruments SoCs which ties together
the tlv320aic3106 audio codec and MCASP I2S controller. Enable audio
playback functionality by taking a data pointer and data size as the
sound data. The uboot sound play command takes time and frequency as
input and creates the data for a beep sound with the given parameters,
which is then passed to the sound play function.

The code is based on the samsung sound driver[1] in uboot.

Link: 
https://gitlab.com/u-boot/u-boot/-/blob/master/drivers/sound/samsung_sound.c [1]

Signed-off-by: Scaria Kochidanadu <s-kochidan...@ti.com>
---
 MAINTAINERS              |   1 +
 drivers/sound/Kconfig    |  10 ++++
 drivers/sound/Makefile   |   1 +
 drivers/sound/ti_sound.c | 119 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 131 insertions(+)
 create mode 100644 drivers/sound/ti_sound.c

diff --git a/MAINTAINERS b/MAINTAINERS
index f8afd7d51e..785afff1a7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -738,6 +738,7 @@ F:  drivers/reset/reset-ti-sci.c
 F:     drivers/rtc/davinci.c
 F:     drivers/serial/serial_omap.c
 F:     drivers/soc/ti/
+F:     drivers/sound/ti_sound.c
 F:     drivers/sysreset/sysreset-ti-sci.c
 F:     drivers/thermal/ti-bandgap.c
 F:     drivers/timer/omap-timer.c
diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
index 0948d8caab..be9f18b6c7 100644
--- a/drivers/sound/Kconfig
+++ b/drivers/sound/Kconfig
@@ -148,4 +148,14 @@ config SOUND_WM8994
          audio data and I2C for codec control. At present it only works
          with the Samsung I2S driver.
 
+config I2S_TI
+        bool "Enable I2S support for AM62x SoCs"
+        depends on I2S
+        help
+          TI AM62x SoCs support an I2S interface for sending audio
+          data to an audio codec. This option enables support for this,
+          using one of the available audio codec drivers. Enabling this
+          option provides an implementation for sound_init() and
+          sound_play().
+
 endmenu
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 9b40c8012f..95aaa8521c 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_SOUND_I8254)     += i8254_beep.o
 obj-$(CONFIG_SOUND_RT5677)     += rt5677.o
 obj-$(CONFIG_INTEL_BROADWELL)  += broadwell_i2s.o broadwell_sound.o
 obj-$(CONFIG_SOUND_IVYBRIDGE)  += ivybridge_sound.o
+obj-$(CONFIG_I2S_TI)    += ti_sound.o
diff --git a/drivers/sound/ti_sound.c b/drivers/sound/ti_sound.c
new file mode 100644
index 0000000000..a424a99b72
--- /dev/null
+++ b/drivers/sound/ti_sound.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2024 Texas Instruments Incorporated - https://www.ti.com/
+ * Scaria M Kochidanadu, s-kochidan...@ti.com
+ *
+ * based on the uboot samsung sound driver, which is
+ *
+ * Copyright 2018 Google, LLC
+ * Written by Simon Glass <s...@chromium.org>
+ */
+
+#include <asm/u-boot.h> /* boot information for Linux kernel */
+/* Pull in stuff for the build system */
+#ifdef DO_DEPS_ONLY
+#include <env_internal.h>
+#endif
+#include <audio_codec.h>
+#include <dm.h>
+#include <i2s.h>
+#include <log.h>
+#include <sound.h>
+#include <asm/gpio.h>
+
+static int ti_sound_setup(struct udevice *dev)
+{
+       struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct i2s_uc_priv *i2s_priv = dev_get_uclass_priv(uc_priv->i2s);
+       int ret;
+
+       if (uc_priv->setup_done)
+               return -EALREADY;
+
+       ret = audio_codec_set_params(uc_priv->codec, i2s_priv->id,
+                                    i2s_priv->samplingrate,
+                                    i2s_priv->samplingrate * i2s_priv->rfs,
+                                    i2s_priv->bitspersample,
+                                    i2s_priv->channels);
+
+       if (ret) {
+               return ret;
+               printf("failed in set_params\n");
+       }
+       uc_priv->setup_done = true;
+
+       return 0;
+}
+
+static int ti_sound_play(struct udevice *dev, void *data, uint data_size)
+{
+       struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+       return i2s_tx_data(uc_priv->i2s, data, data_size);
+}
+
+static int ti_sound_stop_play(struct udevice *dev)
+{
+       /* This function is necassary to satisfy the function calls
+        * in the Uboot command: sound play
+        */
+       return 0;
+}
+
+static int ti_sound_probe(struct udevice *dev)
+{
+       struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct ofnode_phandle_args args;
+       ofnode node;
+       int ret;
+
+       ret = uclass_get_device_by_phandle(UCLASS_AUDIO_CODEC, dev,
+                                          "ti,codec",
+                                          &uc_priv->codec);
+       if (ret) {
+               debug("Failed to probe audio codec\n");
+               return ret;
+       }
+
+       node = ofnode_find_subnode(dev_ofnode(dev), "simple-audio-card,cpu");
+       if (!ofnode_valid(node)) {
+               debug("Failed to find /cpu subnode\n");
+               return -EINVAL;
+       }
+
+       ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+                                            "#sound-dai-cells", 0, 0, &args);
+       if (ret) {
+               debug("Cannot find phandle: %d\n", ret);
+               return ret;
+       }
+
+       ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
+       if (ret) {
+               debug("Cannot find i2s: %d\n", ret);
+               return ret;
+       }
+       debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
+             uc_priv->codec->name, uc_priv->i2s->name);
+
+       return 0;
+}
+
+static const struct sound_ops ti_sound_ops = {
+       .setup  = ti_sound_setup,
+       .play   = ti_sound_play,
+       .stop_play      = ti_sound_stop_play,
+};
+
+static const struct udevice_id ti_sound_ids[] = {
+       { .compatible = "simple-audio-card" },
+       { }
+};
+
+U_BOOT_DRIVER(ti_sound) = {
+       .name           = "ti_sound",
+       .id             = UCLASS_SOUND,
+       .of_match       = ti_sound_ids,
+       .probe          = ti_sound_probe,
+       .ops            = &ti_sound_ops,
+};
-- 
2.34.1

Reply via email to