diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-06 20:19:51 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-06 20:19:51 +0300 |
commit | 668c3c237f5ddc2889879b08f26d2374231f3287 (patch) | |
tree | c8db84c82cba2c0a9dd7a28c5c8bad99d7ffda3d /sound/soc/amd/rpl/rpl-pci-acp6x.c | |
parent | f20c95b46b8fa3ad34b3ea2e134337f88591468b (diff) | |
parent | 24df5428ef9d1ca1edd54eca7eb667110f2dfae3 (diff) | |
download | linux-668c3c237f5ddc2889879b08f26d2374231f3287.tar.xz |
Merge tag 'sound-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"As the diffstat shows, we've had lots of developments in a wide range
at this time; the majority of changes are about ASoC, including
subsystem-wide cleanups, continued SOF / Intel updates and a bunch of
new drivers (as usual), while there have been some significant (but
almost invisible) improvements in ALSA core side, too.
Below are some highlights:
Core:
- Faster lookups of control elements with Xarray; normal user won't
notice, but on the devices with tons of control elements, it can be
visibly faster
- Support for input validation for controls; this will harden for
badly written drivers in general with a slight overhead
- Deferred async signal handling for working around the potential
deadlocks
- Cleanup / refactoring raw MIDI locking code
ASoC:
- Restructing of the set_fmt() callbacks for making things clearer in
situations like CODEC to CODEC links
- Clean up and modernizing the DAI naming scheme setups
- Merge of more of the Intel AVS driver stack, including some board
integrations
- New version 4 mechanism for communication with SOF DSPs
- Suppoort for dynamically selecting the PLL to use at runtime on
i.MX platforms
- Improvements for CODEC to CODEC support in the generic cards
- Support for AMD Jadeite and various machines, AMD RPL, Intel
MetorLake DSPs, Mediatek MT8186 DSPs and MT6366, nVidia Tegra
MDDRC, OPE and PEQ, NXP TFA9890, Qualcomm SDM845, WCD9335 and
WAS883x, and Texas Instruments TAS2780
HD- and USB-audio:
- Continued improvement for CS35L41 (sub)codec support
- More quirks for various devices (HP, Lenovo, Dell, Clevo)"
* tag 'sound-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (778 commits)
ALSA: hda/realtek: Add quirk for HP Spectre x360 15-eb0xxx
ALSA: line6: Replace sprintf() with sysfs_emit()
ALSA: hda: Replace sprintf() with sysfs_emit()
ALSA: pcm: Replace sprintf() with sysfs_emit()
ALSA: core: Replace scnprintf() with sysfs_emit()
ALSA: control-led: Replace sprintf() with sysfs_emit()
ALSA: aoa: Replace sprintf() with sysfs_emit()
ALSA: ac97: Replace sprintf() with sysfs_emit()
ALSA: hda/realtek: Add quirk for Clevo NV45PZ
ALSA: hda/realtek: Add quirk for Lenovo Yoga9 14IAP7
ALSA: control: Use deferred fasync helper
ALSA: pcm: Use deferred fasync helper
ALSA: timer: Use deferred fasync helper
ALSA: core: Add async signal helpers
ASoC: q6asm: use kcalloc() instead of kzalloc()
ACPI: scan: Add CLSA0101 Laptop Support
ALSA: hda: cs35l41: Support CLSA0101
ALSA: hda: cs35l41: Use the CS35L41 HDA internal define
ASoC: dt-bindings: use spi-peripheral-props.yaml
ASoC: codecs: va-macro: use fsgen as clock
...
Diffstat (limited to 'sound/soc/amd/rpl/rpl-pci-acp6x.c')
-rw-r--r-- | sound/soc/amd/rpl/rpl-pci-acp6x.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/sound/soc/amd/rpl/rpl-pci-acp6x.c b/sound/soc/amd/rpl/rpl-pci-acp6x.c new file mode 100644 index 000000000000..a8e548ed991b --- /dev/null +++ b/sound/soc/amd/rpl/rpl-pci-acp6x.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AMD RPL ACP PCI Driver + * + * Copyright 2022 Advanced Micro Devices, Inc. + */ + +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#include "rpl_acp6x.h" + +struct rpl_dev_data { + void __iomem *acp6x_base; +}; + +static int rpl_power_on(void __iomem *acp_base) +{ + u32 val; + int timeout; + + val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS); + + if (!val) + return val; + + if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) + rpl_acp_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); + timeout = 0; + while (++timeout < 500) { + val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS); + if (!val) + return 0; + udelay(1); + } + return -ETIMEDOUT; +} + +static int rpl_reset(void __iomem *acp_base) +{ + u32 val; + int timeout; + + rpl_acp_writel(1, acp_base + ACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rpl_acp_readl(acp_base + ACP_SOFT_RESET); + if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) + break; + cpu_relax(); + } + rpl_acp_writel(0, acp_base + ACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rpl_acp_readl(acp_base + ACP_SOFT_RESET); + if (!val) + return 0; + cpu_relax(); + } + return -ETIMEDOUT; +} + +static int rpl_init(void __iomem *acp_base) +{ + int ret; + + /* power on */ + ret = rpl_power_on(acp_base); + if (ret) { + pr_err("ACP power on failed\n"); + return ret; + } + rpl_acp_writel(0x01, acp_base + ACP_CONTROL); + /* Reset */ + ret = rpl_reset(acp_base); + if (ret) { + pr_err("ACP reset failed\n"); + return ret; + } + rpl_acp_writel(0x03, acp_base + ACP_CLKMUX_SEL); + return 0; +} + +static int rpl_deinit(void __iomem *acp_base) +{ + int ret; + + /* Reset */ + ret = rpl_reset(acp_base); + if (ret) { + pr_err("ACP reset failed\n"); + return ret; + } + rpl_acp_writel(0x00, acp_base + ACP_CLKMUX_SEL); + rpl_acp_writel(0x00, acp_base + ACP_CONTROL); + return 0; +} + +static int snd_rpl_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct rpl_dev_data *adata; + u32 addr; + int ret; + + /* RPL device check */ + switch (pci->revision) { + case 0x62: + break; + default: + dev_dbg(&pci->dev, "acp6x pci device not found\n"); + return -ENODEV; + } + if (pci_enable_device(pci)) { + dev_err(&pci->dev, "pci_enable_device failed\n"); + return -ENODEV; + } + + ret = pci_request_regions(pci, "AMD ACP6x audio"); + if (ret < 0) { + dev_err(&pci->dev, "pci_request_regions failed\n"); + goto disable_pci; + } + + adata = devm_kzalloc(&pci->dev, sizeof(struct rpl_dev_data), + GFP_KERNEL); + if (!adata) { + ret = -ENOMEM; + goto release_regions; + } + + addr = pci_resource_start(pci, 0); + adata->acp6x_base = devm_ioremap(&pci->dev, addr, + pci_resource_len(pci, 0)); + if (!adata->acp6x_base) { + ret = -ENOMEM; + goto release_regions; + } + pci_set_master(pci); + pci_set_drvdata(pci, adata); + ret = rpl_init(adata->acp6x_base); + if (ret) + goto release_regions; + pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pci->dev); + pm_runtime_put_noidle(&pci->dev); + pm_runtime_allow(&pci->dev); + + return 0; +release_regions: + pci_release_regions(pci); +disable_pci: + pci_disable_device(pci); + + return ret; +} + +static int __maybe_unused snd_rpl_suspend(struct device *dev) +{ + struct rpl_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + ret = rpl_deinit(adata->acp6x_base); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + return ret; +} + +static int __maybe_unused snd_rpl_resume(struct device *dev) +{ + struct rpl_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + ret = rpl_init(adata->acp6x_base); + if (ret) + dev_err(dev, "ACP init failed\n"); + return ret; +} + +static const struct dev_pm_ops rpl_pm = { + SET_RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume) +}; + +static void snd_rpl_remove(struct pci_dev *pci) +{ + struct rpl_dev_data *adata; + int ret; + + adata = pci_get_drvdata(pci); + ret = rpl_deinit(adata->acp6x_base); + if (ret) + dev_err(&pci->dev, "ACP de-init failed\n"); + pm_runtime_forbid(&pci->dev); + pm_runtime_get_noresume(&pci->dev); + pci_release_regions(pci); + pci_disable_device(pci); +} + +static const struct pci_device_id snd_rpl_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID), + .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, + .class_mask = 0xffffff }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, snd_rpl_ids); + +static struct pci_driver rpl_acp6x_driver = { + .name = KBUILD_MODNAME, + .id_table = snd_rpl_ids, + .probe = snd_rpl_probe, + .remove = snd_rpl_remove, + .driver = { + .pm = &rpl_pm, + } +}; + +module_pci_driver(rpl_acp6x_driver); + +MODULE_DESCRIPTION("AMD ACP RPL PCI driver"); +MODULE_LICENSE("GPL v2"); |