* [PATCH] ALSA: hda - Add new driver for HDA controllers listed via ACPI
@ 2025-05-15 13:31 Daniel Dadap
2025-05-15 14:45 ` Takashi Iwai
0 siblings, 1 reply; 15+ messages in thread
From: Daniel Dadap @ 2025-05-15 13:31 UTC (permalink / raw)
To: alsa-devel, linux-sound
Some systems expose HD-Audio controllers via objects in the ACPI tables
which encapsulate the controller's interrupt and the base address for the
HDA registers in an ACPI _CRS object, for example, as listed in this ACPI
table dump excerpt:
Device (HDA0)
{
Name (_HID, "NVDA2014") // _HID: Hardware ID
...
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
Memory32Fixed (ReadWrite,
0x36078000, // Address Base
0x00008000, // Address Length
)
Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, )
{
0x0000021E,
}
})
}
Add support for HDA controllers discovered through ACPI, including support
for some platforms which expose such HDA controllers on NVIDIA SoCs. This
is done with a new driver which uses existing infrastructure for extracting
resource information from _CRS objects and plumbs the parsed resource
information through to the existing HDA infrastructure to enable HD-Audio
functionality on such devices.
Although this driver is in the sound/pci/hda/ directory, it targets devices
which are not actually enumerated on the PCI bus. This is because it depends
upon the Intel "Azalia" infrastructure which has traditionally been used for
PCI-based devices.
Signed-off-by: Daniel Dadap <ddadap@nvidia.com>
---
sound/pci/hda/Kconfig | 11 ++
sound/pci/hda/Makefile | 2 +
sound/pci/hda/hda_acpi.c | 316 +++++++++++++++++++++++++++++++++++++++
3 files changed, 329 insertions(+)
create mode 100644 sound/pci/hda/hda_acpi.c
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 9c427270ff4f..436dfd182a09 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -42,6 +42,17 @@ config SND_HDA_TEGRA
To compile this driver as a module, choose M here: the module
will be called snd-hda-tegra.
+config SND_HDA_ACPI
+ tristate "HD Audio ACPI"
+ depends on ACPI
+ select SND_HDA
+ help
+ Say Y here to include support for Azalia-compatible HDA controllers
+ which are advertised via ACPI objects.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-hda-acpi.
+
if SND_HDA
config SND_HDA_HWDEP
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 210c406dfbc5..7a7c16d705dd 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
snd-hda-intel-y := hda_intel.o
snd-hda-tegra-y := hda_tegra.o
+snd-hda-acpi-y := hda_acpi.o
snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
snd-hda-codec-y += hda_controller.o
@@ -80,3 +81,4 @@ obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o
# when built in kernel
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o
+obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o
diff --git a/sound/pci/hda/hda_acpi.c b/sound/pci/hda/hda_acpi.c
new file mode 100644
index 000000000000..736eac59eaa0
--- /dev/null
+++ b/sound/pci/hda/hda_acpi.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ALSA driver for ACPI-based HDA Controllers.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+
+#include <sound/hda_codec.h>
+
+#include "hda_controller.h"
+
+struct hda_acpi {
+ struct azx azx;
+ struct snd_card *card;
+ struct platform_device *pdev;
+ void __iomem *regs;
+ struct work_struct probe_work;
+ const struct hda_data *data;
+};
+
+/**
+ * struct hda_data - Optional device-specific data
+ * @short_name: Used for the ALSA card name; defaults to KBUILD_MODNAME
+ * @long_name: Used for longer description; defaults to short_name
+ * @flags: Passed to &azx->driver_caps
+ *
+ * A pointer to a record of this type may be stored in the
+ * &acpi_device_id->driver_data field of an ACPI match table entry in order to
+ * customize the naming and behavior of a particular device. All fields are
+ * optional and sensible defaults will be selected in their absence.
+ */
+struct hda_data {
+ const char *short_name;
+ const char *long_name;
+ unsigned long flags;
+};
+
+static int hda_acpi_dev_disconnect(struct snd_device *device)
+{
+ struct azx *chip = device->device_data;
+
+ chip->bus.shutdown = 1;
+ return 0;
+}
+
+static int hda_acpi_dev_free(struct snd_device *device)
+{
+ struct azx *azx = device->device_data;
+ struct hda_acpi *hda = container_of(azx, struct hda_acpi, azx);
+
+ cancel_work_sync(&hda->probe_work);
+ if (azx_bus(azx)->chip_init) {
+ azx_stop_all_streams(azx);
+ azx_stop_chip(azx);
+ }
+
+ azx_free_stream_pages(azx);
+ azx_free_streams(azx);
+ snd_hdac_bus_exit(azx_bus(azx));
+
+ return 0;
+}
+
+static int hda_acpi_init(struct hda_acpi *hda)
+{
+ struct hdac_bus *bus = azx_bus(&hda->azx);
+ struct snd_card *card = hda->azx.card;
+ struct device *dev = &hda->pdev->dev;
+ struct azx *azx = &hda->azx;
+ struct resource *res;
+ unsigned short gcap;
+ const char *sname, *lname;
+ int err, irq;
+
+ /* The base address for the HDA registers and the interrupt are wrapped
+ * in an ACPI _CRS object which can be parsed by platform_get_irq() and
+ * devm_platform_get_and_ioremap_resource() */
+
+ irq = platform_get_irq(hda->pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ hda->regs = devm_platform_get_and_ioremap_resource(hda->pdev, 0, &res);
+ if (IS_ERR(hda->regs))
+ return PTR_ERR(hda->regs);
+
+ bus->remap_addr = hda->regs;
+ bus->addr = res->start;
+
+ err = devm_request_irq(dev, irq, azx_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, azx);
+ if (err) {
+ dev_err(dev, "unable to request IRQ %d, disabling device\n", irq);
+ return err;
+ }
+ bus->irq = irq;
+ bus->dma_stop_delay = 100;
+ card->sync_irq = bus->irq;
+
+ gcap = azx_readw(azx, GCAP);
+ dev_dbg(dev, "chipset global capabilities = 0x%x\n", gcap);
+
+ azx->align_buffer_size = 1;
+
+ azx->capture_streams = (gcap >> 8) & 0x0f;
+ azx->playback_streams = (gcap >> 12) & 0x0f;
+
+ azx->capture_index_offset = 0;
+ azx->playback_index_offset = azx->capture_streams;
+ azx->num_streams = azx->playback_streams + azx->capture_streams;
+
+ err = azx_init_streams(azx);
+ if (err < 0) {
+ dev_err(dev, "failed to initialize streams: %d\n", err);
+ return err;
+ }
+
+ err = azx_alloc_stream_pages(azx);
+ if (err < 0) {
+ dev_err(dev, "failed to allocate stream pages: %d\n", err);
+ return err;
+ }
+
+ azx_init_chip(azx, 1);
+
+ if (!bus->codec_mask) {
+ dev_err(dev, "no codecs found!\n");
+ return -ENODEV;
+ }
+
+ strscpy(card->driver, "hda-acpi", sizeof(card->driver));
+
+ sname = hda->data->short_name ? hda->data->short_name : KBUILD_MODNAME;
+
+ if (strlen(sname) > sizeof(card->shortname))
+ dev_info(dev, "truncating shortname for card %s\n", sname);
+ strscpy(card->shortname, sname, sizeof(card->shortname));
+
+ lname = hda->data->long_name ? hda->data->long_name : sname;
+
+ snprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx irq %i", lname, bus->addr, bus->irq);
+
+ return 0;
+}
+
+static void hda_acpi_probe_work(struct work_struct *work)
+{
+ struct hda_acpi *hda = container_of(work, struct hda_acpi, probe_work);
+ struct azx *chip = &hda->azx;
+ int err;
+
+ err = hda_acpi_init(hda);
+ if (err < 0)
+ return;
+
+ err = azx_probe_codecs(chip, 8);
+ if (err < 0)
+ return;
+
+ err = azx_codec_configure(chip);
+ if (err < 0)
+ return;
+
+ err = snd_card_register(chip->card);
+ if (err < 0)
+ return;
+
+ chip->running = 1;
+}
+
+static int hda_acpi_create(struct hda_acpi *hda)
+{
+ static const struct snd_device_ops ops = {
+ .dev_disconnect = hda_acpi_dev_disconnect,
+ .dev_free = hda_acpi_dev_free,
+ };
+ static const struct hda_controller_ops null_ops;
+ struct azx *azx = &hda->azx;
+ int err;
+
+ mutex_init(&azx->open_mutex);
+ azx->card = hda->card;
+ INIT_LIST_HEAD(&azx->pcm_list);
+
+ azx->ops = &null_ops;
+ azx->driver_caps = hda->data->flags;
+ azx->driver_type = hda->data->flags & 0xff;
+ azx->codec_probe_mask = -1;
+
+ err = azx_bus_init(azx, NULL);
+ if (err < 0)
+ return err;
+
+ err = snd_device_new(hda->card, SNDRV_DEV_LOWLEVEL, &hda->azx, &ops);
+ if (err < 0) {
+ dev_err(&hda->pdev->dev, "Error creating device\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int hda_acpi_probe(struct platform_device *pdev)
+{
+ struct hda_acpi *hda;
+ int err;
+
+ hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL);
+ if (!hda)
+ return -ENOMEM;
+
+ hda->pdev = pdev;
+ hda->data = acpi_device_get_match_data(&pdev->dev);
+
+ err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &hda->card);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Error creating card!\n");
+ return err;
+ }
+
+ INIT_WORK(&hda->probe_work, hda_acpi_probe_work);
+
+ err = hda_acpi_create(hda);
+ if (err < 0)
+ goto out_free;
+ hda->card->private_data = &hda->azx;
+
+ dev_set_drvdata(&pdev->dev, hda->card);
+
+ schedule_work(&hda->probe_work);
+
+ return 0;
+
+out_free:
+ snd_card_free(hda->card);
+ return err;
+}
+
+static void hda_acpi_remove(struct platform_device *pdev)
+{
+ snd_card_free(dev_get_drvdata(&pdev->dev));
+}
+
+static void hda_acpi_shutdown(struct platform_device *pdev)
+{
+ struct snd_card *card = dev_get_drvdata(&pdev->dev);
+ struct azx *chip;
+
+ if (!card)
+ return;
+ chip = card->private_data;
+ if (chip && chip->running)
+ azx_stop_chip(chip);
+}
+
+static int __maybe_unused hda_acpi_suspend(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ int rc;
+
+ rc = pm_runtime_force_suspend(dev);
+ if (rc < 0)
+ return rc;
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+ return 0;
+}
+
+static int __maybe_unused hda_acpi_resume(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ int rc;
+
+ rc = pm_runtime_force_resume(dev);
+ if (rc < 0)
+ return rc;
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+ return 0;
+}
+
+static const struct dev_pm_ops hda_acpi_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume)
+};
+
+struct hda_data nvidia_hda_data = {
+ .short_name = "NVIDIA",
+ .long_name = "NVIDIA HDA Controller",
+ .flags = AZX_DCAPS_CORBRP_SELF_CLEAR,
+};
+
+static const struct acpi_device_id hda_acpi_match[] = {
+ { .id = "NVDA2014", .driver_data = (uintptr_t) &nvidia_hda_data },
+ { .id = "NVDA2015", .driver_data = (uintptr_t) &nvidia_hda_data },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, hda_acpi_match);
+
+static struct platform_driver hda_acpi_platform_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .pm = &hda_acpi_pm,
+ .acpi_match_table = hda_acpi_match,
+ },
+ .probe = hda_acpi_probe,
+ .remove = hda_acpi_remove,
+ .shutdown = hda_acpi_shutdown,
+};
+module_platform_driver(hda_acpi_platform_driver);
+
+MODULE_DESCRIPTION("Driver for ACPI-based HDA Controllers");
+MODULE_LICENSE("GPL v2");
--
2.39.5
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-15 13:31 [PATCH] ALSA: hda - Add new driver for HDA controllers listed via ACPI Daniel Dadap @ 2025-05-15 14:45 ` Takashi Iwai 2025-05-15 14:54 ` Takashi Iwai ` (2 more replies) 0 siblings, 3 replies; 15+ messages in thread From: Takashi Iwai @ 2025-05-15 14:45 UTC (permalink / raw) To: Daniel Dadap; +Cc: alsa-devel, linux-sound On Thu, 15 May 2025 15:31:46 +0200, Daniel Dadap wrote: > > Some systems expose HD-Audio controllers via objects in the ACPI tables > which encapsulate the controller's interrupt and the base address for the > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > table dump excerpt: > > Device (HDA0) > { > Name (_HID, "NVDA2014") // _HID: Hardware ID > ... > Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings > { > Memory32Fixed (ReadWrite, > 0x36078000, // Address Base > 0x00008000, // Address Length > ) > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) > { > 0x0000021E, > } > }) > } > > Add support for HDA controllers discovered through ACPI, including support > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > is done with a new driver which uses existing infrastructure for extracting > resource information from _CRS objects and plumbs the parsed resource > information through to the existing HDA infrastructure to enable HD-Audio > functionality on such devices. > > Although this driver is in the sound/pci/hda/ directory, it targets devices > which are not actually enumerated on the PCI bus. This is because it depends > upon the Intel "Azalia" infrastructure which has traditionally been used for > PCI-based devices. > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> Thanks for the patch. The code looks fine. Just a nitpicking: > +static int __maybe_unused hda_acpi_suspend(struct device *dev) .... > +static int __maybe_unused hda_acpi_resume(struct device *dev) The __maybe_unused is superfluous when you set up SYSTEM_SLEEP_PM_OPS() macro instead in the below: > +static const struct dev_pm_ops hda_acpi_pm = { > + SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) thanks, Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-15 14:45 ` Takashi Iwai @ 2025-05-15 14:54 ` Takashi Iwai 2025-05-15 15:49 ` Daniel Dadap 2025-05-15 15:45 ` Daniel Dadap 2025-05-15 15:47 ` [PATCH v2] " Daniel Dadap 2 siblings, 1 reply; 15+ messages in thread From: Takashi Iwai @ 2025-05-15 14:54 UTC (permalink / raw) To: Daniel Dadap; +Cc: alsa-devel, linux-sound On Thu, 15 May 2025 16:45:52 +0200, Takashi Iwai wrote: > > On Thu, 15 May 2025 15:31:46 +0200, > Daniel Dadap wrote: > > > > Some systems expose HD-Audio controllers via objects in the ACPI tables > > which encapsulate the controller's interrupt and the base address for the > > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > > table dump excerpt: > > > > Device (HDA0) > > { > > Name (_HID, "NVDA2014") // _HID: Hardware ID > > ... > > Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings > > { > > Memory32Fixed (ReadWrite, > > 0x36078000, // Address Base > > 0x00008000, // Address Length > > ) > > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) > > { > > 0x0000021E, > > } > > }) > > } > > > > Add support for HDA controllers discovered through ACPI, including support > > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > > is done with a new driver which uses existing infrastructure for extracting > > resource information from _CRS objects and plumbs the parsed resource > > information through to the existing HDA infrastructure to enable HD-Audio > > functionality on such devices. > > > > Although this driver is in the sound/pci/hda/ directory, it targets devices > > which are not actually enumerated on the PCI bus. This is because it depends > > upon the Intel "Azalia" infrastructure which has traditionally been used for > > PCI-based devices. > > > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> > > Thanks for the patch. > The code looks fine. Just a nitpicking: > > > +static int __maybe_unused hda_acpi_suspend(struct device *dev) > .... > > +static int __maybe_unused hda_acpi_resume(struct device *dev) > > The __maybe_unused is superfluous when you set up > SYSTEM_SLEEP_PM_OPS() macro instead in the below: > > > +static const struct dev_pm_ops hda_acpi_pm = { > > + SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) Also, at the next time, please put the maintainer (me) to Cc. thanks, Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-15 14:54 ` Takashi Iwai @ 2025-05-15 15:49 ` Daniel Dadap 2025-05-15 15:51 ` Daniel Dadap 0 siblings, 1 reply; 15+ messages in thread From: Daniel Dadap @ 2025-05-15 15:49 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, linux-sound On Thu, May 15, 2025 at 04:54:25PM +0200, Takashi Iwai wrote: > On Thu, 15 May 2025 16:45:52 +0200, > Takashi Iwai wrote: > > > > On Thu, 15 May 2025 15:31:46 +0200, > > Daniel Dadap wrote: > > > > > > Some systems expose HD-Audio controllers via objects in the ACPI tables > > > which encapsulate the controller's interrupt and the base address for the > > > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > > > table dump excerpt: > > > > > > Device (HDA0) > > > { > > > Name (_HID, "NVDA2014") // _HID: Hardware ID > > > ... > > > Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings > > > { > > > Memory32Fixed (ReadWrite, > > > 0x36078000, // Address Base > > > 0x00008000, // Address Length > > > ) > > > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) > > > { > > > 0x0000021E, > > > } > > > }) > > > } > > > > > > Add support for HDA controllers discovered through ACPI, including support > > > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > > > is done with a new driver which uses existing infrastructure for extracting > > > resource information from _CRS objects and plumbs the parsed resource > > > information through to the existing HDA infrastructure to enable HD-Audio > > > functionality on such devices. > > > > > > Although this driver is in the sound/pci/hda/ directory, it targets devices > > > which are not actually enumerated on the PCI bus. This is because it depends > > > upon the Intel "Azalia" infrastructure which has traditionally been used for > > > PCI-based devices. > > > > > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> > > > > Thanks for the patch. > > The code looks fine. Just a nitpicking: > > > > > +static int __maybe_unused hda_acpi_suspend(struct device *dev) > > .... > > > +static int __maybe_unused hda_acpi_resume(struct device *dev) > > > > The __maybe_unused is superfluous when you set up > > SYSTEM_SLEEP_PM_OPS() macro instead in the below: > > > > > +static const struct dev_pm_ops hda_acpi_pm = { > > > + SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) > > Also, at the next time, please put the maintainer (me) to Cc. > Sure, already sent it with you on To: as a reply to the last message. I was wrong about hda_tegra having __maybe_unused, you already cleaned that up. > > thanks, > > Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-15 15:49 ` Daniel Dadap @ 2025-05-15 15:51 ` Daniel Dadap 0 siblings, 0 replies; 15+ messages in thread From: Daniel Dadap @ 2025-05-15 15:51 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, linux-sound On Thu, May 15, 2025 at 10:49:13AM -0500, Daniel Dadap wrote: > On Thu, May 15, 2025 at 04:54:25PM +0200, Takashi Iwai wrote: > > On Thu, 15 May 2025 16:45:52 +0200, > > Takashi Iwai wrote: > > > > > > On Thu, 15 May 2025 15:31:46 +0200, > > > Daniel Dadap wrote: > > > > > > > > Some systems expose HD-Audio controllers via objects in the ACPI tables > > > > which encapsulate the controller's interrupt and the base address for the > > > > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > > > > table dump excerpt: > > > > > > > > Device (HDA0) > > > > { > > > > Name (_HID, "NVDA2014") // _HID: Hardware ID > > > > ... > > > > Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings > > > > { > > > > Memory32Fixed (ReadWrite, > > > > 0x36078000, // Address Base > > > > 0x00008000, // Address Length > > > > ) > > > > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) > > > > { > > > > 0x0000021E, > > > > } > > > > }) > > > > } > > > > > > > > Add support for HDA controllers discovered through ACPI, including support > > > > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > > > > is done with a new driver which uses existing infrastructure for extracting > > > > resource information from _CRS objects and plumbs the parsed resource > > > > information through to the existing HDA infrastructure to enable HD-Audio > > > > functionality on such devices. > > > > > > > > Although this driver is in the sound/pci/hda/ directory, it targets devices > > > > which are not actually enumerated on the PCI bus. This is because it depends > > > > upon the Intel "Azalia" infrastructure which has traditionally been used for > > > > PCI-based devices. > > > > > > > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> > > > > > > Thanks for the patch. > > > The code looks fine. Just a nitpicking: > > > > > > > +static int __maybe_unused hda_acpi_suspend(struct device *dev) > > > .... > > > > +static int __maybe_unused hda_acpi_resume(struct device *dev) > > > > > > The __maybe_unused is superfluous when you set up > > > SYSTEM_SLEEP_PM_OPS() macro instead in the below: > > > > > > > +static const struct dev_pm_ops hda_acpi_pm = { > > > > + SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) > > > > Also, at the next time, please put the maintainer (me) to Cc. > > > > Sure, already sent it with you on To: as a reply to the last message. I was > wrong about hda_tegra having __maybe_unused, you already cleaned that up. Oops, sorry for the churn, I did not notice the difference between the SYSTEM_SLEEP_PM_OPS() and SET_SYSTEM_SLEEP_PM_OPS() macros. I think I got it right, now. > > > > > thanks, > > > > Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-15 14:45 ` Takashi Iwai 2025-05-15 14:54 ` Takashi Iwai @ 2025-05-15 15:45 ` Daniel Dadap 2025-05-15 15:49 ` Takashi Iwai 2025-05-15 15:47 ` [PATCH v2] " Daniel Dadap 2 siblings, 1 reply; 15+ messages in thread From: Daniel Dadap @ 2025-05-15 15:45 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, linux-sound On Thu, May 15, 2025 at 04:45:52PM +0200, Takashi Iwai wrote: > On Thu, 15 May 2025 15:31:46 +0200, > Daniel Dadap wrote: > > > > Some systems expose HD-Audio controllers via objects in the ACPI tables > > which encapsulate the controller's interrupt and the base address for the > > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > > table dump excerpt: > > > > Device (HDA0) > > { > > Name (_HID, "NVDA2014") // _HID: Hardware ID > > ... > > Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings > > { > > Memory32Fixed (ReadWrite, > > 0x36078000, // Address Base > > 0x00008000, // Address Length > > ) > > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) > > { > > 0x0000021E, > > } > > }) > > } > > > > Add support for HDA controllers discovered through ACPI, including support > > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > > is done with a new driver which uses existing infrastructure for extracting > > resource information from _CRS objects and plumbs the parsed resource > > information through to the existing HDA infrastructure to enable HD-Audio > > functionality on such devices. > > > > Although this driver is in the sound/pci/hda/ directory, it targets devices > > which are not actually enumerated on the PCI bus. This is because it depends > > upon the Intel "Azalia" infrastructure which has traditionally been used for > > PCI-based devices. > > > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> > > Thanks for the patch. > The code looks fine. Just a nitpicking: > > > +static int __maybe_unused hda_acpi_suspend(struct device *dev) > .... > > +static int __maybe_unused hda_acpi_resume(struct device *dev) > > The __maybe_unused is superfluous when you set up > SYSTEM_SLEEP_PM_OPS() macro instead in the below: > > > +static const struct dev_pm_ops hda_acpi_pm = { > > + SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) > Thanks, I'll send an updated patch. The hda_tegra driver has these as well so I presume it can be cleaned up from that driver as well? > > thanks, > > Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-15 15:45 ` Daniel Dadap @ 2025-05-15 15:49 ` Takashi Iwai 0 siblings, 0 replies; 15+ messages in thread From: Takashi Iwai @ 2025-05-15 15:49 UTC (permalink / raw) To: Daniel Dadap; +Cc: alsa-devel, linux-sound On Thu, 15 May 2025 17:45:08 +0200, Daniel Dadap wrote: > > On Thu, May 15, 2025 at 04:45:52PM +0200, Takashi Iwai wrote: > > On Thu, 15 May 2025 15:31:46 +0200, > > Daniel Dadap wrote: > > > > > > Some systems expose HD-Audio controllers via objects in the ACPI tables > > > which encapsulate the controller's interrupt and the base address for the > > > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > > > table dump excerpt: > > > > > > Device (HDA0) > > > { > > > Name (_HID, "NVDA2014") // _HID: Hardware ID > > > ... > > > Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings > > > { > > > Memory32Fixed (ReadWrite, > > > 0x36078000, // Address Base > > > 0x00008000, // Address Length > > > ) > > > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) > > > { > > > 0x0000021E, > > > } > > > }) > > > } > > > > > > Add support for HDA controllers discovered through ACPI, including support > > > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > > > is done with a new driver which uses existing infrastructure for extracting > > > resource information from _CRS objects and plumbs the parsed resource > > > information through to the existing HDA infrastructure to enable HD-Audio > > > functionality on such devices. > > > > > > Although this driver is in the sound/pci/hda/ directory, it targets devices > > > which are not actually enumerated on the PCI bus. This is because it depends > > > upon the Intel "Azalia" infrastructure which has traditionally been used for > > > PCI-based devices. > > > > > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> > > > > Thanks for the patch. > > The code looks fine. Just a nitpicking: > > > > > +static int __maybe_unused hda_acpi_suspend(struct device *dev) > > .... > > > +static int __maybe_unused hda_acpi_resume(struct device *dev) > > > > The __maybe_unused is superfluous when you set up > > SYSTEM_SLEEP_PM_OPS() macro instead in the below: > > > > > +static const struct dev_pm_ops hda_acpi_pm = { > > > + SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) > > > > Thanks, I'll send an updated patch. The hda_tegra driver has these as well > so I presume it can be cleaned up from that driver as well? It's been already cleaned up on 6.15-rc1 :) Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-15 14:45 ` Takashi Iwai 2025-05-15 14:54 ` Takashi Iwai 2025-05-15 15:45 ` Daniel Dadap @ 2025-05-15 15:47 ` Daniel Dadap 2025-05-15 15:50 ` [PATCH v3] " Daniel Dadap 2025-05-16 7:56 ` [PATCH v2] " Takashi Iwai 2 siblings, 2 replies; 15+ messages in thread From: Daniel Dadap @ 2025-05-15 15:47 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, linux-sound Some systems expose HD-Audio controllers via objects in the ACPI tables which encapsulate the controller's interrupt and the base address for the HDA registers in an ACPI _CRS object, for example, as listed in this ACPI table dump excerpt: Device (HDA0) { Name (_HID, "NVDA2014") // _HID: Hardware ID ... Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x36078000, // Address Base 0x00008000, // Address Length ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x0000021E, } }) } Add support for HDA controllers discovered through ACPI, including support for some platforms which expose such HDA controllers on NVIDIA SoCs. This is done with a new driver which uses existing infrastructure for extracting resource information from _CRS objects and plumbs the parsed resource information through to the existing HDA infrastructure to enable HD-Audio functionality on such devices. Although this driver is in the sound/pci/hda/ directory, it targets devices which are not actually enumerated on the PCI bus. This is because it depends upon the Intel "Azalia" infrastructure which has traditionally been used for PCI-based devices. Signed-off-by: Daniel Dadap <ddadap@nvidia.com> --- sound/pci/hda/Kconfig | 11 ++ sound/pci/hda/Makefile | 2 + sound/pci/hda/hda_acpi.c | 316 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 329 insertions(+) create mode 100644 sound/pci/hda/hda_acpi.c diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 9c427270ff4f..436dfd182a09 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -42,6 +42,17 @@ config SND_HDA_TEGRA To compile this driver as a module, choose M here: the module will be called snd-hda-tegra. +config SND_HDA_ACPI + tristate "HD Audio ACPI" + depends on ACPI + select SND_HDA + help + Say Y here to include support for Azalia-compatible HDA controllers + which are advertised via ACPI objects. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-acpi. + if SND_HDA config SND_HDA_HWDEP diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 210c406dfbc5..7a7c16d705dd 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 snd-hda-intel-y := hda_intel.o snd-hda-tegra-y := hda_tegra.o +snd-hda-acpi-y := hda_acpi.o snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o snd-hda-codec-y += hda_controller.o @@ -80,3 +81,4 @@ obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o # when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o +obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o diff --git a/sound/pci/hda/hda_acpi.c b/sound/pci/hda/hda_acpi.c new file mode 100644 index 000000000000..83b5a5d3baa8 --- /dev/null +++ b/sound/pci/hda/hda_acpi.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ALSA driver for ACPI-based HDA Controllers. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/acpi.h> + +#include <sound/hda_codec.h> + +#include "hda_controller.h" + +struct hda_acpi { + struct azx azx; + struct snd_card *card; + struct platform_device *pdev; + void __iomem *regs; + struct work_struct probe_work; + const struct hda_data *data; +}; + +/** + * struct hda_data - Optional device-specific data + * @short_name: Used for the ALSA card name; defaults to KBUILD_MODNAME + * @long_name: Used for longer description; defaults to short_name + * @flags: Passed to &azx->driver_caps + * + * A pointer to a record of this type may be stored in the + * &acpi_device_id->driver_data field of an ACPI match table entry in order to + * customize the naming and behavior of a particular device. All fields are + * optional and sensible defaults will be selected in their absence. + */ +struct hda_data { + const char *short_name; + const char *long_name; + unsigned long flags; +}; + +static int hda_acpi_dev_disconnect(struct snd_device *device) +{ + struct azx *chip = device->device_data; + + chip->bus.shutdown = 1; + return 0; +} + +static int hda_acpi_dev_free(struct snd_device *device) +{ + struct azx *azx = device->device_data; + struct hda_acpi *hda = container_of(azx, struct hda_acpi, azx); + + cancel_work_sync(&hda->probe_work); + if (azx_bus(azx)->chip_init) { + azx_stop_all_streams(azx); + azx_stop_chip(azx); + } + + azx_free_stream_pages(azx); + azx_free_streams(azx); + snd_hdac_bus_exit(azx_bus(azx)); + + return 0; +} + +static int hda_acpi_init(struct hda_acpi *hda) +{ + struct hdac_bus *bus = azx_bus(&hda->azx); + struct snd_card *card = hda->azx.card; + struct device *dev = &hda->pdev->dev; + struct azx *azx = &hda->azx; + struct resource *res; + unsigned short gcap; + const char *sname, *lname; + int err, irq; + + /* The base address for the HDA registers and the interrupt are wrapped + * in an ACPI _CRS object which can be parsed by platform_get_irq() and + * devm_platform_get_and_ioremap_resource() */ + + irq = platform_get_irq(hda->pdev, 0); + if (irq < 0) + return irq; + + hda->regs = devm_platform_get_and_ioremap_resource(hda->pdev, 0, &res); + if (IS_ERR(hda->regs)) + return PTR_ERR(hda->regs); + + bus->remap_addr = hda->regs; + bus->addr = res->start; + + err = devm_request_irq(dev, irq, azx_interrupt, + IRQF_SHARED, KBUILD_MODNAME, azx); + if (err) { + dev_err(dev, "unable to request IRQ %d, disabling device\n", irq); + return err; + } + bus->irq = irq; + bus->dma_stop_delay = 100; + card->sync_irq = bus->irq; + + gcap = azx_readw(azx, GCAP); + dev_dbg(dev, "chipset global capabilities = 0x%x\n", gcap); + + azx->align_buffer_size = 1; + + azx->capture_streams = (gcap >> 8) & 0x0f; + azx->playback_streams = (gcap >> 12) & 0x0f; + + azx->capture_index_offset = 0; + azx->playback_index_offset = azx->capture_streams; + azx->num_streams = azx->playback_streams + azx->capture_streams; + + err = azx_init_streams(azx); + if (err < 0) { + dev_err(dev, "failed to initialize streams: %d\n", err); + return err; + } + + err = azx_alloc_stream_pages(azx); + if (err < 0) { + dev_err(dev, "failed to allocate stream pages: %d\n", err); + return err; + } + + azx_init_chip(azx, 1); + + if (!bus->codec_mask) { + dev_err(dev, "no codecs found!\n"); + return -ENODEV; + } + + strscpy(card->driver, "hda-acpi", sizeof(card->driver)); + + sname = hda->data->short_name ? hda->data->short_name : KBUILD_MODNAME; + + if (strlen(sname) > sizeof(card->shortname)) + dev_info(dev, "truncating shortname for card %s\n", sname); + strscpy(card->shortname, sname, sizeof(card->shortname)); + + lname = hda->data->long_name ? hda->data->long_name : sname; + + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", lname, bus->addr, bus->irq); + + return 0; +} + +static void hda_acpi_probe_work(struct work_struct *work) +{ + struct hda_acpi *hda = container_of(work, struct hda_acpi, probe_work); + struct azx *chip = &hda->azx; + int err; + + err = hda_acpi_init(hda); + if (err < 0) + return; + + err = azx_probe_codecs(chip, 8); + if (err < 0) + return; + + err = azx_codec_configure(chip); + if (err < 0) + return; + + err = snd_card_register(chip->card); + if (err < 0) + return; + + chip->running = 1; +} + +static int hda_acpi_create(struct hda_acpi *hda) +{ + static const struct snd_device_ops ops = { + .dev_disconnect = hda_acpi_dev_disconnect, + .dev_free = hda_acpi_dev_free, + }; + static const struct hda_controller_ops null_ops; + struct azx *azx = &hda->azx; + int err; + + mutex_init(&azx->open_mutex); + azx->card = hda->card; + INIT_LIST_HEAD(&azx->pcm_list); + + azx->ops = &null_ops; + azx->driver_caps = hda->data->flags; + azx->driver_type = hda->data->flags & 0xff; + azx->codec_probe_mask = -1; + + err = azx_bus_init(azx, NULL); + if (err < 0) + return err; + + err = snd_device_new(hda->card, SNDRV_DEV_LOWLEVEL, &hda->azx, &ops); + if (err < 0) { + dev_err(&hda->pdev->dev, "Error creating device\n"); + return err; + } + + return 0; +} + +static int hda_acpi_probe(struct platform_device *pdev) +{ + struct hda_acpi *hda; + int err; + + hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); + if (!hda) + return -ENOMEM; + + hda->pdev = pdev; + hda->data = acpi_device_get_match_data(&pdev->dev); + + err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &hda->card); + if (err < 0) { + dev_err(&pdev->dev, "Error creating card!\n"); + return err; + } + + INIT_WORK(&hda->probe_work, hda_acpi_probe_work); + + err = hda_acpi_create(hda); + if (err < 0) + goto out_free; + hda->card->private_data = &hda->azx; + + dev_set_drvdata(&pdev->dev, hda->card); + + schedule_work(&hda->probe_work); + + return 0; + +out_free: + snd_card_free(hda->card); + return err; +} + +static void hda_acpi_remove(struct platform_device *pdev) +{ + snd_card_free(dev_get_drvdata(&pdev->dev)); +} + +static void hda_acpi_shutdown(struct platform_device *pdev) +{ + struct snd_card *card = dev_get_drvdata(&pdev->dev); + struct azx *chip; + + if (!card) + return; + chip = card->private_data; + if (chip && chip->running) + azx_stop_chip(chip); +} + +static int hda_acpi_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_suspend(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + + return 0; +} + +static int hda_acpi_resume(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_resume(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + return 0; +} + +static const struct dev_pm_ops hda_acpi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) +}; + +struct hda_data nvidia_hda_data = { + .short_name = "NVIDIA", + .long_name = "NVIDIA HDA Controller", + .flags = AZX_DCAPS_CORBRP_SELF_CLEAR, +}; + +static const struct acpi_device_id hda_acpi_match[] = { + { .id = "NVDA2014", .driver_data = (uintptr_t) &nvidia_hda_data }, + { .id = "NVDA2015", .driver_data = (uintptr_t) &nvidia_hda_data }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, hda_acpi_match); + +static struct platform_driver hda_acpi_platform_driver = { + .driver = { + .name = KBUILD_MODNAME, + .pm = &hda_acpi_pm, + .acpi_match_table = hda_acpi_match, + }, + .probe = hda_acpi_probe, + .remove = hda_acpi_remove, + .shutdown = hda_acpi_shutdown, +}; +module_platform_driver(hda_acpi_platform_driver); + +MODULE_DESCRIPTION("Driver for ACPI-based HDA Controllers"); +MODULE_LICENSE("GPL v2"); -- 2.39.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-15 15:47 ` [PATCH v2] " Daniel Dadap @ 2025-05-15 15:50 ` Daniel Dadap 2025-05-16 7:56 ` [PATCH v2] " Takashi Iwai 1 sibling, 0 replies; 15+ messages in thread From: Daniel Dadap @ 2025-05-15 15:50 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, linux-sound Some systems expose HD-Audio controllers via objects in the ACPI tables which encapsulate the controller's interrupt and the base address for the HDA registers in an ACPI _CRS object, for example, as listed in this ACPI table dump excerpt: Device (HDA0) { Name (_HID, "NVDA2014") // _HID: Hardware ID ... Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x36078000, // Address Base 0x00008000, // Address Length ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x0000021E, } }) } Add support for HDA controllers discovered through ACPI, including support for some platforms which expose such HDA controllers on NVIDIA SoCs. This is done with a new driver which uses existing infrastructure for extracting resource information from _CRS objects and plumbs the parsed resource information through to the existing HDA infrastructure to enable HD-Audio functionality on such devices. Although this driver is in the sound/pci/hda/ directory, it targets devices which are not actually enumerated on the PCI bus. This is because it depends upon the Intel "Azalia" infrastructure which has traditionally been used for PCI-based devices. Signed-off-by: Daniel Dadap <ddadap@nvidia.com> --- sound/pci/hda/Kconfig | 11 ++ sound/pci/hda/Makefile | 2 + sound/pci/hda/hda_acpi.c | 316 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 329 insertions(+) create mode 100644 sound/pci/hda/hda_acpi.c diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 9c427270ff4f..436dfd182a09 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -42,6 +42,17 @@ config SND_HDA_TEGRA To compile this driver as a module, choose M here: the module will be called snd-hda-tegra. +config SND_HDA_ACPI + tristate "HD Audio ACPI" + depends on ACPI + select SND_HDA + help + Say Y here to include support for Azalia-compatible HDA controllers + which are advertised via ACPI objects. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-acpi. + if SND_HDA config SND_HDA_HWDEP diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 210c406dfbc5..7a7c16d705dd 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 snd-hda-intel-y := hda_intel.o snd-hda-tegra-y := hda_tegra.o +snd-hda-acpi-y := hda_acpi.o snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o snd-hda-codec-y += hda_controller.o @@ -80,3 +81,4 @@ obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o # when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o +obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o diff --git a/sound/pci/hda/hda_acpi.c b/sound/pci/hda/hda_acpi.c new file mode 100644 index 000000000000..83b5a5d3baa8 --- /dev/null +++ b/sound/pci/hda/hda_acpi.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ALSA driver for ACPI-based HDA Controllers. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/acpi.h> + +#include <sound/hda_codec.h> + +#include "hda_controller.h" + +struct hda_acpi { + struct azx azx; + struct snd_card *card; + struct platform_device *pdev; + void __iomem *regs; + struct work_struct probe_work; + const struct hda_data *data; +}; + +/** + * struct hda_data - Optional device-specific data + * @short_name: Used for the ALSA card name; defaults to KBUILD_MODNAME + * @long_name: Used for longer description; defaults to short_name + * @flags: Passed to &azx->driver_caps + * + * A pointer to a record of this type may be stored in the + * &acpi_device_id->driver_data field of an ACPI match table entry in order to + * customize the naming and behavior of a particular device. All fields are + * optional and sensible defaults will be selected in their absence. + */ +struct hda_data { + const char *short_name; + const char *long_name; + unsigned long flags; +}; + +static int hda_acpi_dev_disconnect(struct snd_device *device) +{ + struct azx *chip = device->device_data; + + chip->bus.shutdown = 1; + return 0; +} + +static int hda_acpi_dev_free(struct snd_device *device) +{ + struct azx *azx = device->device_data; + struct hda_acpi *hda = container_of(azx, struct hda_acpi, azx); + + cancel_work_sync(&hda->probe_work); + if (azx_bus(azx)->chip_init) { + azx_stop_all_streams(azx); + azx_stop_chip(azx); + } + + azx_free_stream_pages(azx); + azx_free_streams(azx); + snd_hdac_bus_exit(azx_bus(azx)); + + return 0; +} + +static int hda_acpi_init(struct hda_acpi *hda) +{ + struct hdac_bus *bus = azx_bus(&hda->azx); + struct snd_card *card = hda->azx.card; + struct device *dev = &hda->pdev->dev; + struct azx *azx = &hda->azx; + struct resource *res; + unsigned short gcap; + const char *sname, *lname; + int err, irq; + + /* The base address for the HDA registers and the interrupt are wrapped + * in an ACPI _CRS object which can be parsed by platform_get_irq() and + * devm_platform_get_and_ioremap_resource() */ + + irq = platform_get_irq(hda->pdev, 0); + if (irq < 0) + return irq; + + hda->regs = devm_platform_get_and_ioremap_resource(hda->pdev, 0, &res); + if (IS_ERR(hda->regs)) + return PTR_ERR(hda->regs); + + bus->remap_addr = hda->regs; + bus->addr = res->start; + + err = devm_request_irq(dev, irq, azx_interrupt, + IRQF_SHARED, KBUILD_MODNAME, azx); + if (err) { + dev_err(dev, "unable to request IRQ %d, disabling device\n", irq); + return err; + } + bus->irq = irq; + bus->dma_stop_delay = 100; + card->sync_irq = bus->irq; + + gcap = azx_readw(azx, GCAP); + dev_dbg(dev, "chipset global capabilities = 0x%x\n", gcap); + + azx->align_buffer_size = 1; + + azx->capture_streams = (gcap >> 8) & 0x0f; + azx->playback_streams = (gcap >> 12) & 0x0f; + + azx->capture_index_offset = 0; + azx->playback_index_offset = azx->capture_streams; + azx->num_streams = azx->playback_streams + azx->capture_streams; + + err = azx_init_streams(azx); + if (err < 0) { + dev_err(dev, "failed to initialize streams: %d\n", err); + return err; + } + + err = azx_alloc_stream_pages(azx); + if (err < 0) { + dev_err(dev, "failed to allocate stream pages: %d\n", err); + return err; + } + + azx_init_chip(azx, 1); + + if (!bus->codec_mask) { + dev_err(dev, "no codecs found!\n"); + return -ENODEV; + } + + strscpy(card->driver, "hda-acpi", sizeof(card->driver)); + + sname = hda->data->short_name ? hda->data->short_name : KBUILD_MODNAME; + + if (strlen(sname) > sizeof(card->shortname)) + dev_info(dev, "truncating shortname for card %s\n", sname); + strscpy(card->shortname, sname, sizeof(card->shortname)); + + lname = hda->data->long_name ? hda->data->long_name : sname; + + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", lname, bus->addr, bus->irq); + + return 0; +} + +static void hda_acpi_probe_work(struct work_struct *work) +{ + struct hda_acpi *hda = container_of(work, struct hda_acpi, probe_work); + struct azx *chip = &hda->azx; + int err; + + err = hda_acpi_init(hda); + if (err < 0) + return; + + err = azx_probe_codecs(chip, 8); + if (err < 0) + return; + + err = azx_codec_configure(chip); + if (err < 0) + return; + + err = snd_card_register(chip->card); + if (err < 0) + return; + + chip->running = 1; +} + +static int hda_acpi_create(struct hda_acpi *hda) +{ + static const struct snd_device_ops ops = { + .dev_disconnect = hda_acpi_dev_disconnect, + .dev_free = hda_acpi_dev_free, + }; + static const struct hda_controller_ops null_ops; + struct azx *azx = &hda->azx; + int err; + + mutex_init(&azx->open_mutex); + azx->card = hda->card; + INIT_LIST_HEAD(&azx->pcm_list); + + azx->ops = &null_ops; + azx->driver_caps = hda->data->flags; + azx->driver_type = hda->data->flags & 0xff; + azx->codec_probe_mask = -1; + + err = azx_bus_init(azx, NULL); + if (err < 0) + return err; + + err = snd_device_new(hda->card, SNDRV_DEV_LOWLEVEL, &hda->azx, &ops); + if (err < 0) { + dev_err(&hda->pdev->dev, "Error creating device\n"); + return err; + } + + return 0; +} + +static int hda_acpi_probe(struct platform_device *pdev) +{ + struct hda_acpi *hda; + int err; + + hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); + if (!hda) + return -ENOMEM; + + hda->pdev = pdev; + hda->data = acpi_device_get_match_data(&pdev->dev); + + err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &hda->card); + if (err < 0) { + dev_err(&pdev->dev, "Error creating card!\n"); + return err; + } + + INIT_WORK(&hda->probe_work, hda_acpi_probe_work); + + err = hda_acpi_create(hda); + if (err < 0) + goto out_free; + hda->card->private_data = &hda->azx; + + dev_set_drvdata(&pdev->dev, hda->card); + + schedule_work(&hda->probe_work); + + return 0; + +out_free: + snd_card_free(hda->card); + return err; +} + +static void hda_acpi_remove(struct platform_device *pdev) +{ + snd_card_free(dev_get_drvdata(&pdev->dev)); +} + +static void hda_acpi_shutdown(struct platform_device *pdev) +{ + struct snd_card *card = dev_get_drvdata(&pdev->dev); + struct azx *chip; + + if (!card) + return; + chip = card->private_data; + if (chip && chip->running) + azx_stop_chip(chip); +} + +static int hda_acpi_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_suspend(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + + return 0; +} + +static int hda_acpi_resume(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_resume(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + return 0; +} + +static const struct dev_pm_ops hda_acpi_pm = { + SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) +}; + +struct hda_data nvidia_hda_data = { + .short_name = "NVIDIA", + .long_name = "NVIDIA HDA Controller", + .flags = AZX_DCAPS_CORBRP_SELF_CLEAR, +}; + +static const struct acpi_device_id hda_acpi_match[] = { + { .id = "NVDA2014", .driver_data = (uintptr_t) &nvidia_hda_data }, + { .id = "NVDA2015", .driver_data = (uintptr_t) &nvidia_hda_data }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, hda_acpi_match); + +static struct platform_driver hda_acpi_platform_driver = { + .driver = { + .name = KBUILD_MODNAME, + .pm = &hda_acpi_pm, + .acpi_match_table = hda_acpi_match, + }, + .probe = hda_acpi_probe, + .remove = hda_acpi_remove, + .shutdown = hda_acpi_shutdown, +}; +module_platform_driver(hda_acpi_platform_driver); + +MODULE_DESCRIPTION("Driver for ACPI-based HDA Controllers"); +MODULE_LICENSE("GPL v2"); -- 2.39.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-15 15:47 ` [PATCH v2] " Daniel Dadap 2025-05-15 15:50 ` [PATCH v3] " Daniel Dadap @ 2025-05-16 7:56 ` Takashi Iwai 2025-05-16 11:37 ` Daniel Dadap ` (2 more replies) 1 sibling, 3 replies; 15+ messages in thread From: Takashi Iwai @ 2025-05-16 7:56 UTC (permalink / raw) To: Daniel Dadap; +Cc: alsa-devel, linux-sound On Thu, 15 May 2025 17:47:25 +0200, Daniel Dadap wrote: > > Some systems expose HD-Audio controllers via objects in the ACPI tables > which encapsulate the controller's interrupt and the base address for the > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > table dump excerpt: > > Device (HDA0) > { > Name (_HID, "NVDA2014") // _HID: Hardware ID > ... > Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings > { > Memory32Fixed (ReadWrite, > 0x36078000, // Address Base > 0x00008000, // Address Length > ) > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) > { > 0x0000021E, > } > }) > } > > Add support for HDA controllers discovered through ACPI, including support > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > is done with a new driver which uses existing infrastructure for extracting > resource information from _CRS objects and plumbs the parsed resource > information through to the existing HDA infrastructure to enable HD-Audio > functionality on such devices. > > Although this driver is in the sound/pci/hda/ directory, it targets devices > which are not actually enumerated on the PCI bus. This is because it depends > upon the Intel "Azalia" infrastructure which has traditionally been used for > PCI-based devices. > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> Thanks. Now I checked with checkpatch, and it complained a few things: WARNING: Block comments use a trailing */ on a separate line #168: FILE: sound/pci/hda/hda_acpi.c:79: + * devm_platform_get_and_ioremap_resource() */ ERROR: code indent should use tabs where possible #182: FILE: sound/pci/hda/hda_acpi.c:93: +^I IRQF_SHARED, KBUILD_MODNAME, azx);$ ERROR: code indent should use tabs where possible #308: FILE: sound/pci/hda/hda_acpi.c:219: +^I THIS_MODULE, 0, &hda->card);$ WARNING: Prefer "GPL" over "GPL v2" - see commit bf7fbeeae6db ("module: Cure th) #405: FILE: sound/pci/hda/hda_acpi.c:316: +MODULE_LICENSE("GPL v2"); Care to address those and resubmit? thanks, Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-16 7:56 ` [PATCH v2] " Takashi Iwai @ 2025-05-16 11:37 ` Daniel Dadap 2025-05-21 14:46 ` Daniel Dadap 2025-05-16 11:43 ` [PATCH v4] " Daniel Dadap 2025-05-21 14:35 ` [PATCH v5] " Daniel Dadap 2 siblings, 1 reply; 15+ messages in thread From: Daniel Dadap @ 2025-05-16 11:37 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, linux-sound On Fri, May 16, 2025 at 09:56:13AM +0200, Takashi Iwai wrote: > On Thu, 15 May 2025 17:47:25 +0200, > Daniel Dadap wrote: > > > > Some systems expose HD-Audio controllers via objects in the ACPI tables > > which encapsulate the controller's interrupt and the base address for the > > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > > table dump excerpt: > > > > Device (HDA0) > > { > > Name (_HID, "NVDA2014") // _HID: Hardware ID > > ... > > Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings > > { > > Memory32Fixed (ReadWrite, > > 0x36078000, // Address Base > > 0x00008000, // Address Length > > ) > > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) > > { > > 0x0000021E, > > } > > }) > > } > > > > Add support for HDA controllers discovered through ACPI, including support > > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > > is done with a new driver which uses existing infrastructure for extracting > > resource information from _CRS objects and plumbs the parsed resource > > information through to the existing HDA infrastructure to enable HD-Audio > > functionality on such devices. > > > > Although this driver is in the sound/pci/hda/ directory, it targets devices > > which are not actually enumerated on the PCI bus. This is because it depends > > upon the Intel "Azalia" infrastructure which has traditionally been used for > > PCI-based devices. > > > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> > > Thanks. Now I checked with checkpatch, and it complained a few > things: > Thanks, Takashi. I forgot to ran checkpatch. I addressed the ones you called out, and a few more that you ignored (I think on purpose), except for this: > WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? I can add myself as maintainer for this file if you like, but figured it could also just fall into the default maintainership of the directory (you). Let me know if you think it's worth changing it. > WARNING: Block comments use a trailing */ on a separate line > #168: FILE: sound/pci/hda/hda_acpi.c:79: > + * devm_platform_get_and_ioremap_resource() */ > > ERROR: code indent should use tabs where possible > #182: FILE: sound/pci/hda/hda_acpi.c:93: > +^I IRQF_SHARED, KBUILD_MODNAME, azx);$ > > ERROR: code indent should use tabs where possible > #308: FILE: sound/pci/hda/hda_acpi.c:219: > +^I THIS_MODULE, 0, &hda->card);$ I disagree with the above two, but I changed it anyway because it's easier to do that than to argue with checkpatch. These are both continuations of long lines, and the single hard tab matches the actual indentation level of the code itself, with the subsequent spaces serving to aesthetically align the continuation. If someone is viewing the file with the tabstop set to anything other than 8, using hard tabs for the alignment portion will break the intended alignment, whereas using spaces will keep things aligned well regardless of the tabstop size, since the single initial tab will resize consistently with the tabstop. Perhaps this style point has been discussed before, and the policy that is enforced by checkpatch is intentional for reasons I don't understand (I did not check), but if this behavior is unintentional, and using spaces for aligning continuations of long lines is supposed to be okay, I can look at updating checkpatch to allow it. But for now I'll go with the recommended indentation since that seems to be the style followed by other files here. > > WARNING: Prefer "GPL" over "GPL v2" - see commit bf7fbeeae6db ("module: Cure th) > #405: FILE: sound/pci/hda/hda_acpi.c:316: > +MODULE_LICENSE("GPL v2"); > > Care to address those and resubmit? > Sure, I'll send a v4 shortly. I also took the opportunity to address an issue I noticed while cleaning up, by adding the following: hda->data = acpi_device_get_match_data(&pdev->dev); + + /* Fall back to defaults if the table didn't have a *struct hda_data */ + if (!hda->data) + hda->data = devm_kzalloc(&pdev->dev, sizeof(*hda->data), + GFP_KERNEL); + if (!hda->data) + return -ENOMEM; + err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, My intention was to allow entries in the match table to omit supplying the pointer to a struct hda_data if they were fine with the defaults (hence use of the language "may be stored" in the comment describing the struct), but without the above the driver will dereference NULL if this is actually done. > > thanks, > > Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-16 11:37 ` Daniel Dadap @ 2025-05-21 14:46 ` Daniel Dadap 0 siblings, 0 replies; 15+ messages in thread From: Daniel Dadap @ 2025-05-21 14:46 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, linux-sound On Fri, May 16, 2025 at 06:37:21AM -0500, Daniel Dadap wrote: > On Fri, May 16, 2025 at 09:56:13AM +0200, Takashi Iwai wrote: > > On Thu, 15 May 2025 17:47:25 +0200, > > Daniel Dadap wrote: > > > > > > Some systems expose HD-Audio controllers via objects in the ACPI tables > > > which encapsulate the controller's interrupt and the base address for the > > > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > > > table dump excerpt: > > > > > > Device (HDA0) > > > { > > > Name (_HID, "NVDA2014") // _HID: Hardware ID > > > ... > > > Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings > > > { > > > Memory32Fixed (ReadWrite, > > > 0x36078000, // Address Base > > > 0x00008000, // Address Length > > > ) > > > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) > > > { > > > 0x0000021E, > > > } > > > }) > > > } > > > > > > Add support for HDA controllers discovered through ACPI, including support > > > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > > > is done with a new driver which uses existing infrastructure for extracting > > > resource information from _CRS objects and plumbs the parsed resource > > > information through to the existing HDA infrastructure to enable HD-Audio > > > functionality on such devices. > > > > > > Although this driver is in the sound/pci/hda/ directory, it targets devices > > > which are not actually enumerated on the PCI bus. This is because it depends > > > upon the Intel "Azalia" infrastructure which has traditionally been used for > > > PCI-based devices. > > > > > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> > > > > Thanks. Now I checked with checkpatch, and it complained a few > > things: > > > > Thanks, Takashi. I forgot to ran checkpatch. I addressed the ones you called > out, and a few more that you ignored (I think on purpose), except for this: > > > WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? > > I can add myself as maintainer for this file if you like, but figured it > could also just fall into the default maintainership of the directory (you). > Let me know if you think it's worth changing it. > > > WARNING: Block comments use a trailing */ on a separate line > > #168: FILE: sound/pci/hda/hda_acpi.c:79: > > + * devm_platform_get_and_ioremap_resource() */ > > > > ERROR: code indent should use tabs where possible > > #182: FILE: sound/pci/hda/hda_acpi.c:93: > > +^I IRQF_SHARED, KBUILD_MODNAME, azx);$ > > > > ERROR: code indent should use tabs where possible > > #308: FILE: sound/pci/hda/hda_acpi.c:219: > > +^I THIS_MODULE, 0, &hda->card);$ > > I disagree with the above two, but I changed it anyway because it's easier > to do that than to argue with checkpatch. These are both continuations of > long lines, and the single hard tab matches the actual indentation level of > the code itself, with the subsequent spaces serving to aesthetically align > the continuation. If someone is viewing the file with the tabstop set to > anything other than 8, using hard tabs for the alignment portion will break > the intended alignment, whereas using spaces will keep things aligned well > regardless of the tabstop size, since the single initial tab will resize > consistently with the tabstop. > > Perhaps this style point has been discussed before, and the policy that is > enforced by checkpatch is intentional for reasons I don't understand (I did > not check), but if this behavior is unintentional, and using spaces for > aligning continuations of long lines is supposed to be okay, I can look at > updating checkpatch to allow it. But for now I'll go with the recommended > indentation since that seems to be the style followed by other files here. > > > > > WARNING: Prefer "GPL" over "GPL v2" - see commit bf7fbeeae6db ("module: Cure th) > > #405: FILE: sound/pci/hda/hda_acpi.c:316: > > +MODULE_LICENSE("GPL v2"); > > > > Care to address those and resubmit? > > > > Sure, I'll send a v4 shortly. I also took the opportunity to address an > issue I noticed while cleaning up, by adding the following: Hi Takashi, In the meantime I noticed the recent commits in the sound tree to convert some string copies to use strscpy() with two arguments, so I sent a patch v5 to also use the two-argument variant in the new driver. I also sent a separate patch to update hda_tegra to use the new signature. > > hda->data = acpi_device_get_match_data(&pdev->dev); > + > + /* Fall back to defaults if the table didn't have a *struct hda_data */ > + if (!hda->data) > + hda->data = devm_kzalloc(&pdev->dev, sizeof(*hda->data), > + GFP_KERNEL); > + if (!hda->data) > + return -ENOMEM; > + > err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, > > My intention was to allow entries in the match table to omit supplying the > pointer to a struct hda_data if they were fine with the defaults (hence use > of the language "may be stored" in the comment describing the struct), but > without the above the driver will dereference NULL if this is actually done. > > > > > thanks, > > > > Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-16 7:56 ` [PATCH v2] " Takashi Iwai 2025-05-16 11:37 ` Daniel Dadap @ 2025-05-16 11:43 ` Daniel Dadap 2025-05-21 14:35 ` [PATCH v5] " Daniel Dadap 2 siblings, 0 replies; 15+ messages in thread From: Daniel Dadap @ 2025-05-16 11:43 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, linux-sound Some systems expose HD-Audio controllers via objects in the ACPI tables which encapsulate the controller's interrupt and the base address for the HDA registers in an ACPI _CRS object, for example, as listed in this ACPI table dump excerpt: Device (HDA0) { Name (_HID, "NVDA2014") // _HID: Hardware ID ... Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x36078000, // Address Base 0x00008000, // Address Length ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x0000021E, } }) } Add support for HDA controllers discovered through ACPI, including support for some platforms which expose such HDA controllers on NVIDIA SoCs. This is done with a new driver which uses existing infrastructure for extracting resource information from _CRS objects and plumbs the parsed resource information through to the existing HDA infrastructure to enable HD-Audio functionality on such devices. Although this driver is in the sound/pci/hda/ directory, it targets devices which are not actually enumerated on the PCI bus. This is because it depends upon the Intel "Azalia" infrastructure which has traditionally been usedvfor PCI-based devices. Signed-off-by: Daniel Dadap <ddadap@nvidia.com> --- Patch history: v2,3: Remove __maybe_unused, use SYSTEM_SLEEP_PM_OPS (Takashi Iwai) v4: Address checkpatch issues (Takashi Iwai), allow NULL match data sound/pci/hda/Kconfig | 11 ++ sound/pci/hda/Makefile | 2 + sound/pci/hda/hda_acpi.c | 325 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 338 insertions(+) create mode 100644 sound/pci/hda/hda_acpi.c diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 9c427270ff4f..436dfd182a09 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -42,6 +42,17 @@ config SND_HDA_TEGRA To compile this driver as a module, choose M here: the module will be called snd-hda-tegra. +config SND_HDA_ACPI + tristate "HD Audio ACPI" + depends on ACPI + select SND_HDA + help + Say Y here to include support for Azalia-compatible HDA controllers + which are advertised via ACPI objects. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-acpi. + if SND_HDA config SND_HDA_HWDEP diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 210c406dfbc5..7a7c16d705dd 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 snd-hda-intel-y := hda_intel.o snd-hda-tegra-y := hda_tegra.o +snd-hda-acpi-y := hda_acpi.o snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o snd-hda-codec-y += hda_controller.o @@ -80,3 +81,4 @@ obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o # when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o +obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o diff --git a/sound/pci/hda/hda_acpi.c b/sound/pci/hda/hda_acpi.c new file mode 100644 index 000000000000..3303cecddd94 --- /dev/null +++ b/sound/pci/hda/hda_acpi.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ALSA driver for ACPI-based HDA Controllers. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/acpi.h> + +#include <sound/hda_codec.h> + +#include "hda_controller.h" + +struct hda_acpi { + struct azx azx; + struct snd_card *card; + struct platform_device *pdev; + void __iomem *regs; + struct work_struct probe_work; + const struct hda_data *data; +}; + +/** + * struct hda_data - Optional device-specific data + * @short_name: Used for the ALSA card name; defaults to KBUILD_MODNAME + * @long_name: Used for longer description; defaults to short_name + * @flags: Passed to &azx->driver_caps + * + * A pointer to a record of this type may be stored in the + * &acpi_device_id->driver_data field of an ACPI match table entry in order to + * customize the naming and behavior of a particular device. All fields are + * optional and sensible defaults will be selected in their absence. + */ +struct hda_data { + const char *short_name; + const char *long_name; + unsigned long flags; +}; + +static int hda_acpi_dev_disconnect(struct snd_device *device) +{ + struct azx *chip = device->device_data; + + chip->bus.shutdown = 1; + return 0; +} + +static int hda_acpi_dev_free(struct snd_device *device) +{ + struct azx *azx = device->device_data; + struct hda_acpi *hda = container_of(azx, struct hda_acpi, azx); + + cancel_work_sync(&hda->probe_work); + if (azx_bus(azx)->chip_init) { + azx_stop_all_streams(azx); + azx_stop_chip(azx); + } + + azx_free_stream_pages(azx); + azx_free_streams(azx); + snd_hdac_bus_exit(azx_bus(azx)); + + return 0; +} + +static int hda_acpi_init(struct hda_acpi *hda) +{ + struct hdac_bus *bus = azx_bus(&hda->azx); + struct snd_card *card = hda->azx.card; + struct device *dev = &hda->pdev->dev; + struct azx *azx = &hda->azx; + struct resource *res; + unsigned short gcap; + const char *sname, *lname; + int err, irq; + + /* The base address for the HDA registers and the interrupt are wrapped + * in an ACPI _CRS object which can be parsed by platform_get_irq() and + * devm_platform_get_and_ioremap_resource() + */ + + irq = platform_get_irq(hda->pdev, 0); + if (irq < 0) + return irq; + + hda->regs = devm_platform_get_and_ioremap_resource(hda->pdev, 0, &res); + if (IS_ERR(hda->regs)) + return PTR_ERR(hda->regs); + + bus->remap_addr = hda->regs; + bus->addr = res->start; + + err = devm_request_irq(dev, irq, azx_interrupt, + IRQF_SHARED, KBUILD_MODNAME, azx); + if (err) { + dev_err(dev, "unable to request IRQ %d, disabling device\n", + irq); + return err; + } + bus->irq = irq; + bus->dma_stop_delay = 100; + card->sync_irq = bus->irq; + + gcap = azx_readw(azx, GCAP); + dev_dbg(dev, "chipset global capabilities = 0x%x\n", gcap); + + azx->align_buffer_size = 1; + + azx->capture_streams = (gcap >> 8) & 0x0f; + azx->playback_streams = (gcap >> 12) & 0x0f; + + azx->capture_index_offset = 0; + azx->playback_index_offset = azx->capture_streams; + azx->num_streams = azx->playback_streams + azx->capture_streams; + + err = azx_init_streams(azx); + if (err < 0) { + dev_err(dev, "failed to initialize streams: %d\n", err); + return err; + } + + err = azx_alloc_stream_pages(azx); + if (err < 0) { + dev_err(dev, "failed to allocate stream pages: %d\n", err); + return err; + } + + azx_init_chip(azx, 1); + + if (!bus->codec_mask) { + dev_err(dev, "no codecs found!\n"); + return -ENODEV; + } + + strscpy(card->driver, "hda-acpi", sizeof(card->driver)); + + sname = hda->data->short_name ? hda->data->short_name : KBUILD_MODNAME; + + if (strlen(sname) > sizeof(card->shortname)) + dev_info(dev, "truncating shortname for card %s\n", sname); + strscpy(card->shortname, sname, sizeof(card->shortname)); + + lname = hda->data->long_name ? hda->data->long_name : sname; + + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", lname, bus->addr, bus->irq); + + return 0; +} + +static void hda_acpi_probe_work(struct work_struct *work) +{ + struct hda_acpi *hda = container_of(work, struct hda_acpi, probe_work); + struct azx *chip = &hda->azx; + int err; + + err = hda_acpi_init(hda); + if (err < 0) + return; + + err = azx_probe_codecs(chip, 8); + if (err < 0) + return; + + err = azx_codec_configure(chip); + if (err < 0) + return; + + err = snd_card_register(chip->card); + if (err < 0) + return; + + chip->running = 1; +} + +static int hda_acpi_create(struct hda_acpi *hda) +{ + static const struct snd_device_ops ops = { + .dev_disconnect = hda_acpi_dev_disconnect, + .dev_free = hda_acpi_dev_free, + }; + static const struct hda_controller_ops null_ops; + struct azx *azx = &hda->azx; + int err; + + mutex_init(&azx->open_mutex); + azx->card = hda->card; + INIT_LIST_HEAD(&azx->pcm_list); + + azx->ops = &null_ops; + azx->driver_caps = hda->data->flags; + azx->driver_type = hda->data->flags & 0xff; + azx->codec_probe_mask = -1; + + err = azx_bus_init(azx, NULL); + if (err < 0) + return err; + + err = snd_device_new(hda->card, SNDRV_DEV_LOWLEVEL, &hda->azx, &ops); + if (err < 0) { + dev_err(&hda->pdev->dev, "Error creating device\n"); + return err; + } + + return 0; +} + +static int hda_acpi_probe(struct platform_device *pdev) +{ + struct hda_acpi *hda; + int err; + + hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); + if (!hda) + return -ENOMEM; + + hda->pdev = pdev; + hda->data = acpi_device_get_match_data(&pdev->dev); + + /* Fall back to defaults if the table didn't have a *struct hda_data */ + if (!hda->data) + hda->data = devm_kzalloc(&pdev->dev, sizeof(*hda->data), + GFP_KERNEL); + if (!hda->data) + return -ENOMEM; + + err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &hda->card); + if (err < 0) { + dev_err(&pdev->dev, "Error creating card!\n"); + return err; + } + + INIT_WORK(&hda->probe_work, hda_acpi_probe_work); + + err = hda_acpi_create(hda); + if (err < 0) + goto out_free; + hda->card->private_data = &hda->azx; + + dev_set_drvdata(&pdev->dev, hda->card); + + schedule_work(&hda->probe_work); + + return 0; + +out_free: + snd_card_free(hda->card); + return err; +} + +static void hda_acpi_remove(struct platform_device *pdev) +{ + snd_card_free(dev_get_drvdata(&pdev->dev)); +} + +static void hda_acpi_shutdown(struct platform_device *pdev) +{ + struct snd_card *card = dev_get_drvdata(&pdev->dev); + struct azx *chip; + + if (!card) + return; + chip = card->private_data; + if (chip && chip->running) + azx_stop_chip(chip); +} + +static int hda_acpi_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_suspend(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + + return 0; +} + +static int hda_acpi_resume(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_resume(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + return 0; +} + +static const struct dev_pm_ops hda_acpi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) +}; + +struct hda_data nvidia_hda_data = { + .short_name = "NVIDIA", + .long_name = "NVIDIA HDA Controller", + .flags = AZX_DCAPS_CORBRP_SELF_CLEAR, +}; + +static const struct acpi_device_id hda_acpi_match[] = { + { .id = "NVDA2014", .driver_data = (uintptr_t) &nvidia_hda_data }, + { .id = "NVDA2015", .driver_data = (uintptr_t) &nvidia_hda_data }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, hda_acpi_match); + +static struct platform_driver hda_acpi_platform_driver = { + .driver = { + .name = KBUILD_MODNAME, + .pm = &hda_acpi_pm, + .acpi_match_table = hda_acpi_match, + }, + .probe = hda_acpi_probe, + .remove = hda_acpi_remove, + .shutdown = hda_acpi_shutdown, +}; +module_platform_driver(hda_acpi_platform_driver); + +MODULE_DESCRIPTION("Driver for ACPI-based HDA Controllers"); +MODULE_LICENSE("GPL"); -- 2.39.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v5] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-16 7:56 ` [PATCH v2] " Takashi Iwai 2025-05-16 11:37 ` Daniel Dadap 2025-05-16 11:43 ` [PATCH v4] " Daniel Dadap @ 2025-05-21 14:35 ` Daniel Dadap 2025-05-21 20:17 ` Takashi Iwai 2 siblings, 1 reply; 15+ messages in thread From: Daniel Dadap @ 2025-05-21 14:35 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, linux-sound Some systems expose HD-Audio controllers via objects in the ACPI tables which encapsulate the controller's interrupt and the base address for the HDA registers in an ACPI _CRS object, for example, as listed in this ACPI table dump excerpt: Device (HDA0) { Name (_HID, "NVDA2014") // _HID: Hardware ID ... Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { Memory32Fixed (ReadWrite, 0x36078000, // Address Base 0x00008000, // Address Length ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x0000021E, } }) } Add support for HDA controllers discovered through ACPI, including support for some platforms which expose such HDA controllers on NVIDIA SoCs. This is done with a new driver which uses existing infrastructure for extracting resource information from _CRS objects and plumbs the parsed resource information through to the existing HDA infrastructure to enable HD-Audio functionality on such devices. Although this driver is in the sound/pci/hda/ directory, it targets devices which are not actually enumerated on the PCI bus. This is because it depends upon the Intel "Azalia" infrastructure which has traditionally been usedvfor PCI-based devices. Signed-off-by: Daniel Dadap <ddadap@nvidia.com> --- Patch history: v2,3: Remove __maybe_unused, use SYSTEM_SLEEP_PM_OPS (Takashi Iwai) v4: Address checkpatch issues (Takashi Iwai), allow NULL match data v5: Use two-argument strscpy() sound/pci/hda/Kconfig | 11 ++ sound/pci/hda/Makefile | 2 + sound/pci/hda/hda_acpi.c | 325 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 338 insertions(+) create mode 100644 sound/pci/hda/hda_acpi.c diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 9c427270ff4f..436dfd182a09 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -42,6 +42,17 @@ config SND_HDA_TEGRA To compile this driver as a module, choose M here: the module will be called snd-hda-tegra. +config SND_HDA_ACPI + tristate "HD Audio ACPI" + depends on ACPI + select SND_HDA + help + Say Y here to include support for Azalia-compatible HDA controllers + which are advertised via ACPI objects. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-acpi. + if SND_HDA config SND_HDA_HWDEP diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 210c406dfbc5..7a7c16d705dd 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 snd-hda-intel-y := hda_intel.o snd-hda-tegra-y := hda_tegra.o +snd-hda-acpi-y := hda_acpi.o snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o snd-hda-codec-y += hda_controller.o @@ -80,3 +81,4 @@ obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o # when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o +obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o diff --git a/sound/pci/hda/hda_acpi.c b/sound/pci/hda/hda_acpi.c new file mode 100644 index 000000000000..3303cecddd94 --- /dev/null +++ b/sound/pci/hda/hda_acpi.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ALSA driver for ACPI-based HDA Controllers. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/acpi.h> + +#include <sound/hda_codec.h> + +#include "hda_controller.h" + +struct hda_acpi { + struct azx azx; + struct snd_card *card; + struct platform_device *pdev; + void __iomem *regs; + struct work_struct probe_work; + const struct hda_data *data; +}; + +/** + * struct hda_data - Optional device-specific data + * @short_name: Used for the ALSA card name; defaults to KBUILD_MODNAME + * @long_name: Used for longer description; defaults to short_name + * @flags: Passed to &azx->driver_caps + * + * A pointer to a record of this type may be stored in the + * &acpi_device_id->driver_data field of an ACPI match table entry in order to + * customize the naming and behavior of a particular device. All fields are + * optional and sensible defaults will be selected in their absence. + */ +struct hda_data { + const char *short_name; + const char *long_name; + unsigned long flags; +}; + +static int hda_acpi_dev_disconnect(struct snd_device *device) +{ + struct azx *chip = device->device_data; + + chip->bus.shutdown = 1; + return 0; +} + +static int hda_acpi_dev_free(struct snd_device *device) +{ + struct azx *azx = device->device_data; + struct hda_acpi *hda = container_of(azx, struct hda_acpi, azx); + + cancel_work_sync(&hda->probe_work); + if (azx_bus(azx)->chip_init) { + azx_stop_all_streams(azx); + azx_stop_chip(azx); + } + + azx_free_stream_pages(azx); + azx_free_streams(azx); + snd_hdac_bus_exit(azx_bus(azx)); + + return 0; +} + +static int hda_acpi_init(struct hda_acpi *hda) +{ + struct hdac_bus *bus = azx_bus(&hda->azx); + struct snd_card *card = hda->azx.card; + struct device *dev = &hda->pdev->dev; + struct azx *azx = &hda->azx; + struct resource *res; + unsigned short gcap; + const char *sname, *lname; + int err, irq; + + /* The base address for the HDA registers and the interrupt are wrapped + * in an ACPI _CRS object which can be parsed by platform_get_irq() and + * devm_platform_get_and_ioremap_resource() + */ + + irq = platform_get_irq(hda->pdev, 0); + if (irq < 0) + return irq; + + hda->regs = devm_platform_get_and_ioremap_resource(hda->pdev, 0, &res); + if (IS_ERR(hda->regs)) + return PTR_ERR(hda->regs); + + bus->remap_addr = hda->regs; + bus->addr = res->start; + + err = devm_request_irq(dev, irq, azx_interrupt, + IRQF_SHARED, KBUILD_MODNAME, azx); + if (err) { + dev_err(dev, "unable to request IRQ %d, disabling device\n", + irq); + return err; + } + bus->irq = irq; + bus->dma_stop_delay = 100; + card->sync_irq = bus->irq; + + gcap = azx_readw(azx, GCAP); + dev_dbg(dev, "chipset global capabilities = 0x%x\n", gcap); + + azx->align_buffer_size = 1; + + azx->capture_streams = (gcap >> 8) & 0x0f; + azx->playback_streams = (gcap >> 12) & 0x0f; + + azx->capture_index_offset = 0; + azx->playback_index_offset = azx->capture_streams; + azx->num_streams = azx->playback_streams + azx->capture_streams; + + err = azx_init_streams(azx); + if (err < 0) { + dev_err(dev, "failed to initialize streams: %d\n", err); + return err; + } + + err = azx_alloc_stream_pages(azx); + if (err < 0) { + dev_err(dev, "failed to allocate stream pages: %d\n", err); + return err; + } + + azx_init_chip(azx, 1); + + if (!bus->codec_mask) { + dev_err(dev, "no codecs found!\n"); + return -ENODEV; + } + + strscpy(card->driver, "hda-acpi"); + + sname = hda->data->short_name ? hda->data->short_name : KBUILD_MODNAME; + + if (strlen(sname) > sizeof(card->shortname)) + dev_info(dev, "truncating shortname for card %s\n", sname); + strscpy(card->shortname, sname); + + lname = hda->data->long_name ? hda->data->long_name : sname; + + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", lname, bus->addr, bus->irq); + + return 0; +} + +static void hda_acpi_probe_work(struct work_struct *work) +{ + struct hda_acpi *hda = container_of(work, struct hda_acpi, probe_work); + struct azx *chip = &hda->azx; + int err; + + err = hda_acpi_init(hda); + if (err < 0) + return; + + err = azx_probe_codecs(chip, 8); + if (err < 0) + return; + + err = azx_codec_configure(chip); + if (err < 0) + return; + + err = snd_card_register(chip->card); + if (err < 0) + return; + + chip->running = 1; +} + +static int hda_acpi_create(struct hda_acpi *hda) +{ + static const struct snd_device_ops ops = { + .dev_disconnect = hda_acpi_dev_disconnect, + .dev_free = hda_acpi_dev_free, + }; + static const struct hda_controller_ops null_ops; + struct azx *azx = &hda->azx; + int err; + + mutex_init(&azx->open_mutex); + azx->card = hda->card; + INIT_LIST_HEAD(&azx->pcm_list); + + azx->ops = &null_ops; + azx->driver_caps = hda->data->flags; + azx->driver_type = hda->data->flags & 0xff; + azx->codec_probe_mask = -1; + + err = azx_bus_init(azx, NULL); + if (err < 0) + return err; + + err = snd_device_new(hda->card, SNDRV_DEV_LOWLEVEL, &hda->azx, &ops); + if (err < 0) { + dev_err(&hda->pdev->dev, "Error creating device\n"); + return err; + } + + return 0; +} + +static int hda_acpi_probe(struct platform_device *pdev) +{ + struct hda_acpi *hda; + int err; + + hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); + if (!hda) + return -ENOMEM; + + hda->pdev = pdev; + hda->data = acpi_device_get_match_data(&pdev->dev); + + /* Fall back to defaults if the table didn't have a *struct hda_data */ + if (!hda->data) + hda->data = devm_kzalloc(&pdev->dev, sizeof(*hda->data), + GFP_KERNEL); + if (!hda->data) + return -ENOMEM; + + err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &hda->card); + if (err < 0) { + dev_err(&pdev->dev, "Error creating card!\n"); + return err; + } + + INIT_WORK(&hda->probe_work, hda_acpi_probe_work); + + err = hda_acpi_create(hda); + if (err < 0) + goto out_free; + hda->card->private_data = &hda->azx; + + dev_set_drvdata(&pdev->dev, hda->card); + + schedule_work(&hda->probe_work); + + return 0; + +out_free: + snd_card_free(hda->card); + return err; +} + +static void hda_acpi_remove(struct platform_device *pdev) +{ + snd_card_free(dev_get_drvdata(&pdev->dev)); +} + +static void hda_acpi_shutdown(struct platform_device *pdev) +{ + struct snd_card *card = dev_get_drvdata(&pdev->dev); + struct azx *chip; + + if (!card) + return; + chip = card->private_data; + if (chip && chip->running) + azx_stop_chip(chip); +} + +static int hda_acpi_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_suspend(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + + return 0; +} + +static int hda_acpi_resume(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_resume(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + return 0; +} + +static const struct dev_pm_ops hda_acpi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) +}; + +struct hda_data nvidia_hda_data = { + .short_name = "NVIDIA", + .long_name = "NVIDIA HDA Controller", + .flags = AZX_DCAPS_CORBRP_SELF_CLEAR, +}; + +static const struct acpi_device_id hda_acpi_match[] = { + { .id = "NVDA2014", .driver_data = (uintptr_t) &nvidia_hda_data }, + { .id = "NVDA2015", .driver_data = (uintptr_t) &nvidia_hda_data }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, hda_acpi_match); + +static struct platform_driver hda_acpi_platform_driver = { + .driver = { + .name = KBUILD_MODNAME, + .pm = &hda_acpi_pm, + .acpi_match_table = hda_acpi_match, + }, + .probe = hda_acpi_probe, + .remove = hda_acpi_remove, + .shutdown = hda_acpi_shutdown, +}; +module_platform_driver(hda_acpi_platform_driver); + +MODULE_DESCRIPTION("Driver for ACPI-based HDA Controllers"); +MODULE_LICENSE("GPL"); -- 2.39.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v5] ALSA: hda - Add new driver for HDA controllers listed via ACPI 2025-05-21 14:35 ` [PATCH v5] " Daniel Dadap @ 2025-05-21 20:17 ` Takashi Iwai 0 siblings, 0 replies; 15+ messages in thread From: Takashi Iwai @ 2025-05-21 20:17 UTC (permalink / raw) To: Daniel Dadap; +Cc: alsa-devel, linux-sound On Wed, 21 May 2025 16:35:29 +0200, Daniel Dadap wrote: > > Some systems expose HD-Audio controllers via objects in the ACPI tables > which encapsulate the controller's interrupt and the base address for the > HDA registers in an ACPI _CRS object, for example, as listed in this ACPI > table dump excerpt: > > Device (HDA0) > { > Name (_HID, "NVDA2014") // _HID: Hardware ID > ... > Name (_CRS, ResourceTemplate () > // _CRS: Current Resource Settings > { > Memory32Fixed (ReadWrite, > 0x36078000, // Address Base > 0x00008000, // Address Length > ) > Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, > ,, ) > { > 0x0000021E, > } > }) > } > > Add support for HDA controllers discovered through ACPI, including support > for some platforms which expose such HDA controllers on NVIDIA SoCs. This > is done with a new driver which uses existing infrastructure for extracting > resource information from _CRS objects and plumbs the parsed resource > information through to the existing HDA infrastructure to enable HD-Audio > functionality on such devices. > > Although this driver is in the sound/pci/hda/ directory, it targets devices > which are not actually enumerated on the PCI bus. This is because it > depends upon the Intel "Azalia" infrastructure which has traditionally been > usedvfor PCI-based devices. > > Signed-off-by: Daniel Dadap <ddadap@nvidia.com> > --- > > Patch history: > v2,3: Remove __maybe_unused, use SYSTEM_SLEEP_PM_OPS (Takashi Iwai) > v4: Address checkpatch issues (Takashi Iwai), allow NULL match data > v5: Use two-argument strscpy() Applied now to for-next branch. Thanks. Takashi ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2025-05-21 20:17 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-05-15 13:31 [PATCH] ALSA: hda - Add new driver for HDA controllers listed via ACPI Daniel Dadap 2025-05-15 14:45 ` Takashi Iwai 2025-05-15 14:54 ` Takashi Iwai 2025-05-15 15:49 ` Daniel Dadap 2025-05-15 15:51 ` Daniel Dadap 2025-05-15 15:45 ` Daniel Dadap 2025-05-15 15:49 ` Takashi Iwai 2025-05-15 15:47 ` [PATCH v2] " Daniel Dadap 2025-05-15 15:50 ` [PATCH v3] " Daniel Dadap 2025-05-16 7:56 ` [PATCH v2] " Takashi Iwai 2025-05-16 11:37 ` Daniel Dadap 2025-05-21 14:46 ` Daniel Dadap 2025-05-16 11:43 ` [PATCH v4] " Daniel Dadap 2025-05-21 14:35 ` [PATCH v5] " Daniel Dadap 2025-05-21 20:17 ` Takashi Iwai
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox