diff options
author | Takashi Iwai <tiwai@suse.de> | 2022-08-01 15:26:40 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2022-08-01 15:26:40 +0200 |
commit | a3b5d4715fd5a839857f8b7be78dff258a8d5a47 (patch) | |
tree | b70d6f050f4831eaba82a60fb443659dc9dfca1c /sound | |
parent | 9769e44d41a1359b9000ff8458f0f2f66080ebf4 (diff) | |
parent | 40d060b8158e26438398bf1132925f666e3b6480 (diff) | |
download | linux-stable-a3b5d4715fd5a839857f8b7be78dff258a8d5a47.tar.gz linux-stable-a3b5d4715fd5a839857f8b7be78dff258a8d5a47.tar.bz2 linux-stable-a3b5d4715fd5a839857f8b7be78dff258a8d5a47.zip |
Merge tag 'asoc-v5.20-2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: More updates for v5.20
More updates that came in since the last pull request I sent, a series
of driver specific changes:
- Support for AMD RPL, some Intel platforms and Mediatek MT8186.
Diffstat (limited to 'sound')
77 files changed, 6880 insertions, 605 deletions
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index ec9cbb219bc1..d84ffdf47210 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -414,6 +414,11 @@ static const struct config_entry config_table[] = { }, /* Alderlake-P */ { + .flags = FLAG_SOF, + .device = 0x51c8, + .codec_hid = &essx_83x6, + }, + { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = 0x51c8, }, diff --git a/sound/soc/Makefile b/sound/soc/Makefile index d4528962ac34..453181ef6c94 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -9,12 +9,12 @@ endif ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),) # snd-soc-test-objs := soc-topology-test.o -obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) := soc-topology-test.o +obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) += soc-topology-test.o endif ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),) # snd-soc-test-objs := soc-utils-test.o -obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) := soc-utils-test.o +obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) += soc-utils-test.o endif ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 9c2fef2ce89f..08f5289dac54 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -117,3 +117,13 @@ config SND_AMD_ACP_CONFIG driver modules to use source "sound/soc/amd/acp/Kconfig" + +config SND_SOC_AMD_RPL_ACP6x + tristate "AMD Audio Coprocessor-v6.2 RPL support" + depends on X86 && PCI + help + This option enables Audio Coprocessor i.e ACP v6.2 support on + AMD RPL platform. By enabling this flag build will be + triggered for ACP PCI driver. + Say m if you have such a device. + If unsure select "N". diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index 8823f6f28611..0592e7c5c407 100644 --- a/sound/soc/amd/Makefile +++ b/sound/soc/amd/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/ obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/ obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/ obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o +obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/ diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index c03bcd31fc95..2c8e960cc9a6 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -29,7 +29,7 @@ static struct platform_device *dmic_dev; static struct platform_device *pdev; -static const struct resource acp3x_res[] = { +static const struct resource acp_res[] = { { .start = 0, .end = ACP3x_REG_END - ACP3x_REG_START, @@ -70,42 +70,49 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id ret = pci_request_regions(pci, "AMD ACP3x audio"); if (ret < 0) { dev_err(&pci->dev, "pci_request_regions failed\n"); - return -ENOMEM; + ret = -ENOMEM; + goto disable_pci; } pci_set_master(pci); + res_acp = acp_res; + num_res = ARRAY_SIZE(acp_res); + switch (pci->revision) { case 0x01: - res_acp = acp3x_res; - num_res = ARRAY_SIZE(acp3x_res); chip->name = "acp_asoc_renoir"; chip->acp_rev = ACP3X_DEV; break; case 0x6f: - res_acp = acp3x_res; - num_res = ARRAY_SIZE(acp3x_res); chip->name = "acp_asoc_rembrandt"; chip->acp_rev = ACP6X_DEV; break; default: dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); - return -EINVAL; + ret = -EINVAL; + goto release_regions; } dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(dmic_dev)) { dev_err(dev, "failed to create DMIC device\n"); - return PTR_ERR(dmic_dev); + ret = PTR_ERR(dmic_dev); + goto release_regions; } addr = pci_resource_start(pci, 0); chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0)); + if (!chip->base) { + ret = -ENOMEM; + goto release_regions; + } res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL); if (!res) { platform_device_unregister(dmic_dev); - return -ENOMEM; + ret = -ENOMEM; + goto release_regions; } for (i = 0; i < num_res; i++, res_acp++) { @@ -134,9 +141,17 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name); platform_device_unregister(dmic_dev); ret = PTR_ERR(pdev); + goto release_regions; } return ret; + +release_regions: + pci_release_regions(pci); +disable_pci: + pci_disable_device(pci); + + return ret; }; static void acp_pci_remove(struct pci_dev *pci) diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index 327e17736dbd..f561d39b33e2 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -94,19 +94,19 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) struct acp_resource *rsrc = adata->rsrc; struct acp_stream *stream; u16 i2s_flag = 0; - u32 val, val1, i; + u32 ext_intr_stat, ext_intr_stat1, i; if (!adata) return IRQ_NONE; if (adata->rsrc->no_of_ctrls == 2) - val1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1))); + ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1))); - val = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); + ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); for (i = 0; i < ACP_MAX_STREAM; i++) { stream = adata->stream[i]; - if (stream && (val & stream->irq_bit)) { + if (stream && (ext_intr_stat & stream->irq_bit)) { writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); snd_pcm_period_elapsed(stream->substream); @@ -114,7 +114,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) break; } if (adata->rsrc->no_of_ctrls == 2) { - if (stream && (val1 & stream->irq_bit)) { + if (stream && (ext_intr_stat1 & stream->irq_bit)) { writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1))); snd_pcm_period_elapsed(stream->substream); @@ -258,13 +258,6 @@ static int acp_dma_new(struct snd_soc_component *component, return 0; } -static int acp_dma_mmap(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - return snd_pcm_lib_default_mmap(substream, vma); -} - static int acp_dma_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -288,7 +281,6 @@ static const struct snd_soc_component_driver acp_pcm_component = { .close = acp_dma_close, .hw_params = acp_dma_hw_params, .pointer = acp_dma_pointer, - .mmap = acp_dma_mmap, .pcm_construct = acp_dma_new, .legacy_dai_naming = 1, }; diff --git a/sound/soc/amd/rpl/Makefile b/sound/soc/amd/rpl/Makefile new file mode 100644 index 000000000000..11a33a05e94b --- /dev/null +++ b/sound/soc/amd/rpl/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# RPL platform Support +snd-rpl-pci-acp6x-objs := rpl-pci-acp6x.o + +obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += snd-rpl-pci-acp6x.o 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"); diff --git a/sound/soc/amd/rpl/rpl_acp6x.h b/sound/soc/amd/rpl/rpl_acp6x.h new file mode 100644 index 000000000000..f5816a33632e --- /dev/null +++ b/sound/soc/amd/rpl/rpl_acp6x.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ACP Driver + * + * Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved. + */ + +#include "rpl_acp6x_chip_offset_byte.h" + +#define ACP_DEVICE_ID 0x15E2 +#define ACP6x_PHY_BASE_ADDRESS 0x1240000 + +#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 +#define ACP_PGFSM_CNTL_POWER_ON_MASK 1 +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0 +#define ACP_PGFSM_STATUS_MASK 3 +#define ACP_POWERED_ON 0 +#define ACP_POWER_ON_IN_PROGRESS 1 +#define ACP_POWERED_OFF 2 +#define ACP_POWER_OFF_IN_PROGRESS 3 + +#define DELAY_US 5 +#define ACP_COUNTER 20000 + +/* time in ms for runtime suspend delay */ +#define ACP_SUSPEND_DELAY_MS 2000 + +static inline u32 rpl_acp_readl(void __iomem *base_addr) +{ + return readl(base_addr - ACP6x_PHY_BASE_ADDRESS); +} + +static inline void rpl_acp_writel(u32 val, void __iomem *base_addr) +{ + writel(val, base_addr - ACP6x_PHY_BASE_ADDRESS); +} diff --git a/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h b/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h new file mode 100644 index 000000000000..456498f5396d --- /dev/null +++ b/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ACP 6.2 Register Documentation + * + * Copyright 2022 Advanced Micro Devices, Inc. + */ + +#ifndef _rpl_acp6x_OFFSET_HEADER +#define _rpl_acp6x_OFFSET_HEADER + +/* Registers from ACP_CLKRST block */ +#define ACP_SOFT_RESET 0x1241000 +#define ACP_CONTROL 0x1241004 +#define ACP_STATUS 0x1241008 +#define ACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010 +#define ACP_PGFSM_CONTROL 0x124101C +#define ACP_PGFSM_STATUS 0x1241020 +#define ACP_CLKMUX_SEL 0x1241024 + +/* Registers from ACP_AON block */ +#define ACP_PME_EN 0x1241400 +#define ACP_DEVICE_STATE 0x1241404 +#define AZ_DEVICE_STATE 0x1241408 +#define ACP_PIN_CONFIG 0x1241440 +#define ACP_PAD_PULLUP_CTRL 0x1241444 +#define ACP_PAD_PULLDOWN_CTRL 0x1241448 +#define ACP_PAD_DRIVE_STRENGTH_CTRL 0x124144C +#define ACP_PAD_SCHMEN_CTRL 0x1241450 + +#endif diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index 727de46860b1..af3737ef9707 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -178,8 +178,7 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream, ret = 0; for (i = 0; i < num_codecs; i++) { codec_dai = asoc_rtd_to_codec(rtd, i); - if ((strcmp(codec_dai->name, "spi-VLV1776:00") == 0) || - (strcmp(codec_dai->name, "spi-VLV1776:01") == 0)) { + if (strcmp(codec_dai->name, "cs35l41-pcm") == 0) { switch (params_rate(params)) { case 48000: bclk_val = 1536000; diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index f06e6c1a7799..ecfe7a790790 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -105,28 +105,14 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21AW"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CM"), } }, { .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21AX"), - } - }, - { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21BN"), - } - }, - { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21BQ"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CN"), } }, { @@ -157,20 +143,6 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "21CL"), } }, - { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21D8"), - } - }, - { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21D9"), - } - }, {} }; diff --git a/sound/soc/amd/yc/pci-acp6x.c b/sound/soc/amd/yc/pci-acp6x.c index 20f7a99783f2..77c5fa1f7af1 100644 --- a/sound/soc/amd/yc/pci-acp6x.c +++ b/sound/soc/amd/yc/pci-acp6x.c @@ -159,7 +159,7 @@ static int snd_acp6x_probe(struct pci_dev *pci, case 0x6f: break; default: - dev_err(&pci->dev, "acp6x pci device not found\n"); + dev_dbg(&pci->dev, "acp6x pci device not found\n"); return -ENODEV; } if (pci_enable_device(pci)) { diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 8aae0beadcfe..e868b7e028d6 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -762,7 +762,6 @@ static int atmel_ssc_trigger(struct snd_pcm_substream *substream, return 0; } -#ifdef CONFIG_PM static int atmel_ssc_suspend(struct snd_soc_component *component) { struct atmel_ssc_info *ssc_p; @@ -821,10 +820,6 @@ static int atmel_ssc_resume(struct snd_soc_component *component) return 0; } -#else /* CONFIG_PM */ -# define atmel_ssc_suspend NULL -# define atmel_ssc_resume NULL -#endif /* CONFIG_PM */ #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) @@ -859,8 +854,8 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { static const struct snd_soc_component_driver atmel_ssc_component = { .name = "atmel-ssc", - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, + .suspend = pm_ptr(atmel_ssc_suspend), + .resume = pm_ptr(atmel_ssc_resume), .legacy_dai_naming = 1, }; diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index 0d37b78b94a0..ec0705cc40fa 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -221,11 +221,11 @@ struct mchp_spdifrx_user_data { }; struct mchp_spdifrx_mixer_control { - struct mchp_spdifrx_ch_stat ch_stat[SPDIFRX_CHANNELS]; - struct mchp_spdifrx_user_data user_data[SPDIFRX_CHANNELS]; - bool ulock; - bool badf; - bool signal; + struct mchp_spdifrx_ch_stat ch_stat[SPDIFRX_CHANNELS]; + struct mchp_spdifrx_user_data user_data[SPDIFRX_CHANNELS]; + bool ulock; + bool badf; + bool signal; }; struct mchp_spdifrx_dev { @@ -288,15 +288,17 @@ static void mchp_spdifrx_isr_blockend_en(struct mchp_spdifrx_dev *dev) spin_unlock_irqrestore(&dev->blockend_lock, flags); } -/* called from atomic context only */ +/* called from atomic/non-atomic context */ static void mchp_spdifrx_isr_blockend_dis(struct mchp_spdifrx_dev *dev) { - spin_lock(&dev->blockend_lock); + unsigned long flags; + + spin_lock_irqsave(&dev->blockend_lock, flags); dev->blockend_refcount--; /* don't enable BLOCKEND interrupt if it's already enabled */ if (dev->blockend_refcount == 0) regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_BLOCKEND); - spin_unlock(&dev->blockend_lock); + spin_unlock_irqrestore(&dev->blockend_lock, flags); } static irqreturn_t mchp_spdif_interrupt(int irq, void *dev_id) @@ -575,6 +577,7 @@ static int mchp_spdifrx_subcode_ch_get(struct mchp_spdifrx_dev *dev, if (ret <= 0) { dev_dbg(dev->dev, "user data for channel %d timeout\n", channel); + mchp_spdifrx_isr_blockend_dis(dev); return ret; } diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index 78d5bcf0819a..4850a177803d 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -196,7 +196,6 @@ struct mchp_spdiftx_dev { struct clk *pclk; struct clk *gclk; unsigned int fmt; - const struct mchp_i2s_caps *caps; int gclk_enabled:1; }; @@ -341,12 +340,10 @@ static int mchp_spdiftx_trigger(struct snd_pcm_substream *substream, int cmd, ret = regmap_write(dev->regmap, SPDIFTX_MR, mr); spin_unlock(&ctrl->lock); - if (ret) { + if (ret) dev_err(dev->dev, "unable to disable TX: %d\n", ret); - return ret; - } - return 0; + return ret; } static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream, @@ -763,12 +760,10 @@ static const struct of_device_id mchp_spdiftx_dt_ids[] = { }, { /* sentinel */ } }; - MODULE_DEVICE_TABLE(of, mchp_spdiftx_dt_ids); + static int mchp_spdiftx_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; struct mchp_spdiftx_dev *dev; struct resource *mem; struct regmap *regmap; @@ -782,11 +777,6 @@ static int mchp_spdiftx_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - /* Get hardware capabilities. */ - match = of_match_node(mchp_spdiftx_dt_ids, np); - if (match) - dev->caps = match->data; - /* Map I/O registers. */ base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(base)) @@ -848,12 +838,10 @@ static int mchp_spdiftx_probe(struct platform_device *pdev) err = devm_snd_soc_register_component(&pdev->dev, &mchp_spdiftx_component, &mchp_spdiftx_dai, 1); - if (err) { + if (err) dev_err(&pdev->dev, "failed to register component: %d\n", err); - return err; - } - return 0; + return err; } static struct platform_driver mchp_spdiftx_driver = { diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 8766e19d85f1..c223d83e02cf 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -6,6 +6,7 @@ // // Author: David Rhodes <david.rhodes@cirrus.com> +#include <linux/acpi.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/init.h> @@ -1142,6 +1143,30 @@ err_dsp: return ret; } +static int cs35l41_acpi_get_name(struct cs35l41_private *cs35l41) +{ + acpi_handle handle = ACPI_HANDLE(cs35l41->dev); + const char *sub; + + /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */ + if (!handle) + return 0; + + sub = acpi_get_subsystem_id(handle); + if (IS_ERR(sub)) { + /* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */ + if (PTR_ERR(sub) == -ENODATA) + return 0; + else + return PTR_ERR(sub); + } + + cs35l41->dsp.system_name = sub; + dev_dbg(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name); + + return 0; +} + int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg) { u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match; @@ -1270,6 +1295,10 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * goto err; } + ret = cs35l41_acpi_get_name(cs35l41); + if (ret < 0) + goto err; + ret = cs35l41_dsp_init(cs35l41); if (ret < 0) goto err; @@ -1316,6 +1345,7 @@ void cs35l41_remove(struct cs35l41_private *cs35l41) pm_runtime_disable(cs35l41->dev); regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); + kfree(cs35l41->dsp.system_name); wm_adsp2_remove(&cs35l41->dsp); cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index 2600be250a3c..2d21339932e6 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -36,6 +36,7 @@ static int nau8821_configure_sysclk(struct nau8821 *nau8821, int clk_id, unsigned int freq); +static bool nau8821_is_jack_inserted(struct regmap *regmap); struct nau8821_fll { int mclk_src; @@ -495,7 +496,33 @@ static int nau8821_output_dac_event(struct snd_soc_dapm_widget *w, return 0; } +static int system_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + dev_dbg(nau8821->dev, "system clock control : POWER OFF\n"); + /* Set clock source to disable or internal clock before the + * playback or capture end. Codec needs clock for Jack + * detection and button press if jack inserted; otherwise, + * the clock should be closed. + */ + if (nau8821_is_jack_inserted(nau8821->regmap)) { + nau8821_configure_sysclk(nau8821, + NAU8821_CLK_INTERNAL, 0); + } else { + nau8821_configure_sysclk(nau8821, NAU8821_CLK_DIS, 0); + } + } + return 0; +} + static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0, + system_clock_control, SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("MICBIAS", NAU8821_R74_MIC_BIAS, NAU8821_MICBIAS_POWERUP_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DMIC Clock", SND_SOC_NOPM, 0, 0, @@ -607,6 +634,9 @@ static const struct snd_soc_dapm_route nau8821_dapm_routes[] = { {"AIFTX", NULL, "ADCL Digital path"}, {"AIFTX", NULL, "ADCR Digital path"}, + {"AIFTX", NULL, "System Clock"}, + {"AIFRX", NULL, "System Clock"}, + {"DDACL", NULL, "AIFRX"}, {"DDACR", NULL, "AIFRX"}, @@ -1699,15 +1729,6 @@ static int nau8821_i2c_probe(struct i2c_client *i2c) return ret; } -static int nau8821_i2c_remove(struct i2c_client *i2c_client) -{ - struct nau8821 *nau8821 = i2c_get_clientdata(i2c_client); - - devm_free_irq(nau8821->dev, nau8821->irq, nau8821); - - return 0; -} - static const struct i2c_device_id nau8821_i2c_ids[] = { { "nau8821", 0 }, { } @@ -1737,7 +1758,6 @@ static struct i2c_driver nau8821_driver = { .acpi_match_table = ACPI_PTR(nau8821_acpi_match), }, .probe_new = nau8821_i2c_probe, - .remove = nau8821_i2c_remove, .id_table = nau8821_i2c_ids, }; module_i2c_driver(nau8821_driver); diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index d9a0d4768c4d..c836848ef0a6 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -537,6 +537,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) struct device *codec_dev = NULL; const char *codec_dai_name; const char *codec_dev_name; + u32 asrc_fmt = 0; u32 width; int ret; @@ -829,8 +830,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) goto asrc_fail; } - ret = of_property_read_u32(asrc_np, "fsl,asrc-format", - &priv->asrc_format); + ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt); + priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { /* Fallback to old binding; translate to asrc_format */ ret = of_property_read_u32(asrc_np, "fsl,asrc-width", diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 20a9f8e924b3..aa5edf32d988 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1066,6 +1066,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) struct resource *res; void __iomem *regs; int irq, ret, i; + u32 asrc_fmt = 0; u32 map_idx; char tmp[16]; u32 width; @@ -1174,7 +1175,8 @@ static int fsl_asrc_probe(struct platform_device *pdev) return ret; } - ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format); + ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); + asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { ret = of_property_read_u32(np, "fsl,asrc-width", &width); if (ret) { @@ -1197,7 +1199,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) } } - if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) { + if (!(FSL_ASRC_FORMATS & pcm_format_to_bits(asrc->asrc_format))) { dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n"); asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; } diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index ea96b0fb6b20..3153d19136b2 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -476,7 +476,8 @@ static int fsl_easrc_prefilter_config(struct fsl_asrc *easrc, struct fsl_asrc_pair *ctx; struct device *dev; u32 inrate, outrate, offset = 0; - u32 in_s_rate, out_s_rate, in_s_fmt, out_s_fmt; + u32 in_s_rate, out_s_rate; + snd_pcm_format_t in_s_fmt, out_s_fmt; int ret, i; if (!easrc) @@ -1874,6 +1875,7 @@ static int fsl_easrc_probe(struct platform_device *pdev) struct resource *res; struct device_node *np; void __iomem *regs; + u32 asrc_fmt = 0; int ret, irq; easrc = devm_kzalloc(dev, sizeof(*easrc), GFP_KERNEL); @@ -1934,13 +1936,14 @@ static int fsl_easrc_probe(struct platform_device *pdev) return ret; } - ret = of_property_read_u32(np, "fsl,asrc-format", &easrc->asrc_format); + ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); + easrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { dev_err(dev, "failed to asrc format\n"); return ret; } - if (!(FSL_EASRC_FORMATS & (1ULL << easrc->asrc_format))) { + if (!(FSL_EASRC_FORMATS & (pcm_format_to_bits(easrc->asrc_format)))) { dev_warn(dev, "unsupported format, switching to S24_LE\n"); easrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; } diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h index 86d5c360d4f5..7c70dac52713 100644 --- a/sound/soc/fsl/fsl_easrc.h +++ b/sound/soc/fsl/fsl_easrc.h @@ -569,7 +569,7 @@ struct fsl_easrc_io_params { unsigned int access_len; unsigned int fifo_wtmk; unsigned int sample_rate; - unsigned int sample_format; + snd_pcm_format_t sample_format; unsigned int norm_rate; }; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 974ba0780b19..7523bb944b21 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -61,7 +61,7 @@ static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir) static struct pinctrl_state *fsl_sai_get_pins_state(struct fsl_sai *sai, u32 bclk) { - struct pinctrl_state *state = 0; + struct pinctrl_state *state = NULL; if (sai->is_pdm_mode) { /* DSD512@44.1kHz, DSD512@48kHz */ diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index ccc4194dc5e7..14be29530fb5 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -118,7 +118,7 @@ struct imx_card_data { struct snd_soc_card card; int num_dapm_routes; u32 asrc_rate; - u32 asrc_format; + snd_pcm_format_t asrc_format; }; static struct imx_akcodec_fs_mul ak4458_fs_mul[] = { @@ -474,7 +474,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); snd_mask_none(mask); - snd_mask_set(mask, data->asrc_format); + snd_mask_set(mask, (__force unsigned int)data->asrc_format); return 0; } @@ -493,6 +493,7 @@ static int imx_card_parse_of(struct imx_card_data *data) struct dai_link_data *link_data; struct of_phandle_args args; int ret, num_links; + u32 asrc_fmt = 0; u32 width; ret = snd_soc_of_parse_card_name(card, "model"); @@ -639,7 +640,8 @@ static int imx_card_parse_of(struct imx_card_data *data) goto err; } - ret = of_property_read_u32(args.np, "fsl,asrc-format", &data->asrc_format); + ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt); + data->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { /* Fallback to old binding; translate to asrc_format */ ret = of_property_read_u32(args.np, "fsl,asrc-width", &width); diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 2b598af8feef..b327372f2e4a 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -158,8 +158,10 @@ static int asoc_simple_parse_dai(struct device_node *ep, * if he unbinded CPU or Codec. */ ret = snd_soc_get_dai_name(&args, &dlc->dai_name); - if (ret < 0) + if (ret < 0) { + of_node_put(node); return ret; + } dlc->of_node = node; diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 18d053a0d05c..8ac6df645ee6 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -445,8 +445,10 @@ static int asoc_simple_parse_dai(struct device_node *ep, * if he unbinded CPU or Codec. */ ret = snd_soc_get_dai_name(&args, &dlc->dai_name); - if (ret < 0) + if (ret < 0) { + of_node_put(node); return ret; + } dlc->of_node = node; diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index 3d46dd5e5bc4..ce157a8d6552 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -449,35 +449,39 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod) return ret; } +static int avs_probe_create(struct avs_dev *adev, struct avs_path_module *mod) +{ + dev_err(adev->dev, "Probe module can't be instantiated by topology"); + return -EINVAL; +} + +struct avs_module_create { + guid_t *guid; + int (*create)(struct avs_dev *adev, struct avs_path_module *mod); +}; + +static struct avs_module_create avs_module_create[] = { + { &AVS_MIXIN_MOD_UUID, avs_modbase_create }, + { &AVS_MIXOUT_MOD_UUID, avs_modbase_create }, + { &AVS_KPBUFF_MOD_UUID, avs_modbase_create }, + { &AVS_COPIER_MOD_UUID, avs_copier_create }, + { &AVS_MICSEL_MOD_UUID, avs_micsel_create }, + { &AVS_MUX_MOD_UUID, avs_mux_create }, + { &AVS_UPDWMIX_MOD_UUID, avs_updown_mix_create }, + { &AVS_SRCINTC_MOD_UUID, avs_src_create }, + { &AVS_AEC_MOD_UUID, avs_aec_create }, + { &AVS_ASRC_MOD_UUID, avs_asrc_create }, + { &AVS_INTELWOV_MOD_UUID, avs_wov_create }, + { &AVS_PROBE_MOD_UUID, avs_probe_create }, +}; + static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_module *mod) { const guid_t *type = &mod->template->cfg_ext->type; - if (guid_equal(type, &AVS_MIXIN_MOD_UUID) || - guid_equal(type, &AVS_MIXOUT_MOD_UUID) || - guid_equal(type, &AVS_KPBUFF_MOD_UUID)) - return avs_modbase_create(adev, mod); - if (guid_equal(type, &AVS_COPIER_MOD_UUID)) - return avs_copier_create(adev, mod); - if (guid_equal(type, &AVS_MICSEL_MOD_UUID)) - return avs_micsel_create(adev, mod); - if (guid_equal(type, &AVS_MUX_MOD_UUID)) - return avs_mux_create(adev, mod); - if (guid_equal(type, &AVS_UPDWMIX_MOD_UUID)) - return avs_updown_mix_create(adev, mod); - if (guid_equal(type, &AVS_SRCINTC_MOD_UUID)) - return avs_src_create(adev, mod); - if (guid_equal(type, &AVS_AEC_MOD_UUID)) - return avs_aec_create(adev, mod); - if (guid_equal(type, &AVS_ASRC_MOD_UUID)) - return avs_asrc_create(adev, mod); - if (guid_equal(type, &AVS_INTELWOV_MOD_UUID)) - return avs_wov_create(adev, mod); - - if (guid_equal(type, &AVS_PROBE_MOD_UUID)) { - dev_err(adev->dev, "Probe module can't be instantiated by topology"); - return -EINVAL; - } + for (int i = 0; i < ARRAY_SIZE(avs_module_create); i++) + if (guid_equal(type, avs_module_create[i].guid)) + return avs_module_create[i].create(adev, mod); return avs_modext_create(adev, mod); } diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index aae857fdcdb8..67c3f49b924c 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -249,6 +249,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { /* SSP0 - Codec */ .name = "Codec", .id = 0, + .nonatomic = 1, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index d0ecbba2febe..31488702768e 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -349,6 +349,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { /* SSP0 - Codec */ .name = "Codec", .id = 0, + .nonatomic = 1, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c index 47eaddb00936..6b76df0e7c9b 100644 --- a/sound/soc/intel/boards/bdw_rt286.c +++ b/sound/soc/intel/boards/bdw_rt286.c @@ -162,6 +162,7 @@ static struct snd_soc_dai_link card_dai_links[] = { /* SSP0 - Codec */ .name = "Codec", .id = 0, + .nonatomic = 1, .no_pcm = 1, .init = codec_link_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, diff --git a/sound/soc/intel/boards/hsw_rt5640.c b/sound/soc/intel/boards/hsw_rt5640.c index ad747363d112..050c53ebd6ba 100644 --- a/sound/soc/intel/boards/hsw_rt5640.c +++ b/sound/soc/intel/boards/hsw_rt5640.c @@ -121,6 +121,7 @@ static struct snd_soc_dai_link card_dai_links[] = { /* SSP0 - Codec */ .name = "Codec", .id = 0, + .nonatomic = 1, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index 23d03e0f7759..c7f33c89588e 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -28,6 +28,24 @@ #define SOF_ES8336_SSP_CODEC_MASK (GENMASK(3, 0)) #define SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK BIT(4) + +/* HDMI capture*/ +#define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(14) +#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 15 +#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(16, 15)) +#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \ + (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) + +#define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7 +#define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7)) +#define SOF_HDMI_CAPTURE_1_SSP(quirk) \ + (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK) + +#define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10 +#define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10)) +#define SOF_HDMI_CAPTURE_2_SSP(quirk) \ + (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK) + #define SOF_ES8336_ENABLE_DMIC BIT(5) #define SOF_ES8336_JD_INVERTED BIT(6) #define SOF_ES8336_HEADPHONE_GPIO BIT(7) @@ -57,28 +75,26 @@ static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true }; static const struct acpi_gpio_params enable_gpio1 = { 1, 0, true }; static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = { - { "speakers-enable-gpios", &enable_gpio0, 1 }, + { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, { } }; static const struct acpi_gpio_mapping acpi_speakers_enable_gpio1[] = { - { "speakers-enable-gpios", &enable_gpio1, 1 }, + { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, }; static const struct acpi_gpio_mapping acpi_enable_both_gpios[] = { - { "speakers-enable-gpios", &enable_gpio0, 1 }, - { "headphone-enable-gpios", &enable_gpio1, 1 }, + { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { "headphone-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, { } }; static const struct acpi_gpio_mapping acpi_enable_both_gpios_rev_order[] = { - { "speakers-enable-gpios", &enable_gpio1, 1 }, - { "headphone-enable-gpios", &enable_gpio0, 1 }, + { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { "headphone-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, { } }; -static const struct acpi_gpio_mapping *gpio_mapping = acpi_speakers_enable_gpio0; - static void log_quirks(struct device *dev) { dev_info(dev, "quirk mask %#lx\n", quirk); @@ -272,15 +288,6 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id) { quirk = (unsigned long)id->driver_data; - if (quirk & SOF_ES8336_HEADPHONE_GPIO) { - if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) - gpio_mapping = acpi_enable_both_gpios; - else - gpio_mapping = acpi_enable_both_gpios_rev_order; - } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) { - gpio_mapping = acpi_speakers_enable_gpio1; - } - return 1; } @@ -356,6 +363,13 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; +static struct snd_soc_dai_link_component dummy_component[] = { + { + .name = "snd-soc-dummy", + .dai_name = "snd-soc-dummy-dai", + } +}; + static int sof_es8336_late_probe(struct snd_soc_card *card) { struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); @@ -507,6 +521,37 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, id++; } + /* HDMI-In SSP */ + if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) { + int num_of_hdmi_ssp = (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + + for (i = 1; i <= num_of_hdmi_ssp; i++) { + int port = (i == 1 ? (quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >> + SOF_HDMI_CAPTURE_1_SSP_SHIFT : + (quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >> + SOF_HDMI_CAPTURE_2_SSP_SHIFT); + + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", port); + if (!links[id].cpus->dai_name) + return NULL; + links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); + if (!links[id].name) + return NULL; + links[id].id = id + hdmi_id_offset; + links[id].codecs = dummy_component; + links[id].num_codecs = ARRAY_SIZE(dummy_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + links[id].num_cpus = 1; + id++; + } + } + return links; devm_err: @@ -529,6 +574,7 @@ static int sof_es8336_probe(struct platform_device *pdev) struct acpi_device *adev; struct snd_soc_dai_link *dai_links; struct device *codec_dev; + const struct acpi_gpio_mapping *gpio_mapping; unsigned int cnt = 0; int dmic_be_num = 0; int hdmi_num = 3; @@ -541,29 +587,34 @@ static int sof_es8336_probe(struct platform_device *pdev) card = &sof_es8336_card; card->dev = dev; + if (pdev->id_entry && pdev->id_entry->driver_data) + quirk = (unsigned long)pdev->id_entry->driver_data; + /* check GPIO DMI quirks */ dmi_check_system(sof_es8336_quirk_table); - if (!mach->mach_params.i2s_link_mask) { - dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n"); - } else { - /* - * Set configuration based on platform NHLT. - * In this machine driver, we can only support one SSP for the - * ES8336 link, the else-if below are intentional. - * In some cases multiple SSPs can be reported by NHLT, starting MSB-first - * seems to pick the right connection. - */ - unsigned long ssp = 0; - - if (mach->mach_params.i2s_link_mask & BIT(2)) - ssp = SOF_ES8336_SSP_CODEC(2); - else if (mach->mach_params.i2s_link_mask & BIT(1)) - ssp = SOF_ES8336_SSP_CODEC(1); - else if (mach->mach_params.i2s_link_mask & BIT(0)) - ssp = SOF_ES8336_SSP_CODEC(0); - - quirk |= ssp; + /* Use NHLT configuration only for Non-HDMI capture use case. + * Because more than one SSP will be enabled for HDMI capture hence wrong codec + * SSP will be set. + */ + if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER) { + if (!mach->mach_params.i2s_link_mask) { + dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n"); + } else { + /* + * Set configuration based on platform NHLT. + * In this machine driver, we can only support one SSP for the + * ES8336 link. + * In some cases multiple SSPs can be reported by NHLT, starting MSB-first + * seems to pick the right connection. + */ + unsigned long ssp; + + /* fls returns 1-based results, SSPs indices are 0-based */ + ssp = fls(mach->mach_params.i2s_link_mask) - 1; + + quirk |= ssp; + } } if (mach->mach_params.dmic_num) @@ -579,7 +630,13 @@ static int sof_es8336_probe(struct platform_device *pdev) if (quirk & SOF_ES8336_ENABLE_DMIC) dmic_be_num = 2; - sof_es8336_card.num_links += dmic_be_num + hdmi_num; + /* compute number of dai links */ + sof_es8336_card.num_links = 1 + dmic_be_num + hdmi_num; + + if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) + sof_es8336_card.num_links += (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + dai_links = sof_card_dai_links_create(dev, SOF_ES8336_SSP_CODEC(quirk), dmic_be_num, hdmi_num); @@ -635,6 +692,17 @@ static int sof_es8336_probe(struct platform_device *pdev) } /* get speaker enable GPIO */ + if (quirk & SOF_ES8336_HEADPHONE_GPIO) { + if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) + gpio_mapping = acpi_enable_both_gpios; + else + gpio_mapping = acpi_enable_both_gpios_rev_order; + } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) { + gpio_mapping = acpi_speakers_enable_gpio1; + } else { + gpio_mapping = acpi_speakers_enable_gpio0; + } + ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping); if (ret) dev_warn(codec_dev, "unable to add GPIO mapping table\n"); @@ -690,6 +758,21 @@ static int sof_es8336_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id board_ids[] = { + { + .name = "adl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, + { } +}; +MODULE_DEVICE_TABLE(platform, board_ids); + static struct platform_driver sof_es8336_driver = { .driver = { .name = "sof-essx8336", @@ -697,6 +780,7 @@ static struct platform_driver sof_es8336_driver = { }, .probe = sof_es8336_probe, .remove = sof_es8336_remove, + .id_table = board_ids, }; module_platform_driver(sof_es8336_driver); diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index f49700eb721b..8d7e5ba9e516 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -190,11 +190,6 @@ static int sof_card_late_probe(struct snd_soc_card *card) struct sof_hdmi_pcm *pcm; int err; - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head); - if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { /* Disable Left and Right Spk pin after boot */ snd_soc_dapm_disable_pin(dapm, "Left Spk"); @@ -204,6 +199,11 @@ static int sof_card_late_probe(struct snd_soc_card *card) return err; } + if (list_empty(&ctx->hdmi_pcm_list)) + return -EINVAL; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head); + return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component); } diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 1384716c6360..045965312245 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -447,6 +447,15 @@ static int sof_card_late_probe(struct snd_soc_card *card) struct sof_hdmi_pcm *pcm; int err; + if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { + /* Disable Left and Right Spk pin after boot */ + snd_soc_dapm_disable_pin(dapm, "Left Spk"); + snd_soc_dapm_disable_pin(dapm, "Right Spk"); + err = snd_soc_dapm_sync(dapm); + if (err < 0) + return err; + } + /* HDMI is not supported by SOF on Baytrail/CherryTrail */ if (is_legacy_cpu || !ctx->idisp_codec) return 0; @@ -477,15 +486,6 @@ static int sof_card_late_probe(struct snd_soc_card *card) return err; } - if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { - /* Disable Left and Right Spk pin after boot */ - snd_soc_dapm_disable_pin(dapm, "Left Spk"); - snd_soc_dapm_disable_pin(dapm, "Right Spk"); - err = snd_soc_dapm_sync(dapm); - if (err < 0) - return err; - } - return hdac_hdmi_jack_port_init(component, &card->dapm); } @@ -1092,6 +1092,14 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_AMP(1) | SOF_RT5682_NUM_HDMIDEV(4)), }, + { + .name = "mtl_mx98357_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 0c47d76a79e2..a49bfaab6b21 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -250,6 +250,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .callback = sof_sdw_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2 | + SOF_SDW_FOUR_SPK), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"), }, /* No Jack */ @@ -315,6 +325,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { RT711_JD2 | SOF_SDW_FOUR_SPK), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, /* MeteorLake devices */ { .callback = sof_sdw_quirk_cb, diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c index 49ff0871e9e7..8291967f23f3 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ b/sound/soc/intel/boards/sof_sdw_rt711.c @@ -139,6 +139,9 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l { struct mc_private *ctx = snd_soc_card_get_drvdata(card); + if (!ctx->headset_codec_dev) + return 0; + device_remove_software_node(ctx->headset_codec_dev); put_device(ctx->headset_codec_dev); diff --git a/sound/soc/intel/boards/sof_sdw_rt711_sdca.c b/sound/soc/intel/boards/sof_sdw_rt711_sdca.c index b3fc32bacfa8..7f16304d025b 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711_sdca.c +++ b/sound/soc/intel/boards/sof_sdw_rt711_sdca.c @@ -140,6 +140,9 @@ int sof_sdw_rt711_sdca_exit(struct snd_soc_card *card, struct snd_soc_dai_link * { struct mc_private *ctx = snd_soc_card_get_drvdata(card); + if (!ctx->headset_codec_dev) + return 0; + device_remove_software_node(ctx->headset_codec_dev); put_device(ctx->headset_codec_dev); diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index fea087d3fa15..9990d5502d26 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -8,6 +8,11 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +static const struct snd_soc_acpi_codecs essx_83x6 = { + .num_codecs = 3, + .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + static const struct snd_soc_acpi_endpoint single_endpoint = { .num = 0, .aggregated = 0, @@ -137,6 +142,15 @@ static const struct snd_soc_acpi_adr_device rt1316_2_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = { + { + .adr = 0x000330025D131601ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1316-1" + } +}; + static const struct snd_soc_acpi_adr_device rt714_0_adr[] = { { .adr = 0x000030025D071401ull, @@ -326,6 +340,20 @@ static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link2_rt714_link0[] = { {} }; +static const struct snd_soc_acpi_link_adr adl_sdw_rt711_link0_rt1316_link3[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1316_3_single_adr), + .adr_d = rt1316_3_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_adr_device mx8373_2_adr[] = { { .adr = 0x000223019F837300ull, @@ -412,6 +440,11 @@ static const struct snd_soc_acpi_codecs adl_max98390_amp = { .codecs = {"MX98390"} }; +static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = { + .num_codecs = 1, + .codecs = {"INTC10B0"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { { .comp_ids = &adl_rt5682_rt5682s_hp, @@ -492,6 +525,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .drv_name = "adl_cs35l41", .sof_tplg_filename = "sof-adl-cs35l41.tplg", }, + { + .comp_ids = &essx_83x6, + .drv_name = "adl_es83x6_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_lt6911_hdmi, + .sof_tplg_filename = "sof-adl-es83x6-ssp1-hdmi-ssp02.tplg", + }, + { + .comp_ids = &essx_83x6, + .drv_name = "sof-essx8336", + .sof_tplg_filename = "sof-adl-es83x6", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | + SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | + SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines); @@ -547,6 +595,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { .sof_tplg_filename = "sof-adl-rt1316-l2-mono-rt714-l0.tplg", }, { + .link_mask = 0x9, /* 2 active links required */ + .links = adl_sdw_rt711_link0_rt1316_link3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l3.tplg", + }, + { .link_mask = 0x1, /* link0 required */ .links = adl_rvp, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index 74d3b82f8d35..36c361fb28a4 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -10,7 +10,24 @@ #include <sound/soc-acpi-intel-match.h> #include "soc-acpi-intel-sdw-mockup-match.h" +static const struct snd_soc_acpi_codecs mtl_max98357a_amp = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + +static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = { + .num_codecs = 2, + .codecs = {"10EC5682", "RTL5682"}, +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { + { + .comp_ids = &mtl_rt5682_rt5682s_hp, + .drv_name = "mtl_mx98357_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &mtl_max98357a_amp, + .sof_tplg_filename = "sof-mtl-max98357a-rt5682.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_machines); diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index ecd8df70d39c..c4c1e89b47c1 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -93,7 +93,6 @@ struct i2s_soc_info { }; struct jz4740_i2s { - struct resource *mem; void __iomem *base; struct clk *clk_aic; diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 9e5ce1a82639..363fa4d47680 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -152,6 +152,51 @@ config SND_SOC_MT8183_DA7219_MAX98357A Select Y if you have such device. If unsure select "N". +config SND_SOC_MT8186 + tristate "ASoC support for Mediatek MT8186 chip" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on COMMON_CLK + select SND_SOC_MEDIATEK + select SND_SOC_MT6358 + select MFD_SYSCON if SND_SOC_MT6358 + help + This adds ASoC driver for Mediatek MT8186 boards + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". + +config SND_SOC_MT8186_MT6366_DA7219_MAX98357 + tristate "ASoC Audio driver for MT8186 with DA7219 MAX98357A codec" + depends on I2C && GPIOLIB + depends on SND_SOC_MT8186 && MTK_PMIC_WRAP + select SND_SOC_MT6358 + select SND_SOC_MAX98357A + select SND_SOC_DA7219 + select SND_SOC_BT_SCO + select SND_SOC_DMIC + select SND_SOC_HDMI_CODEC + help + This adds ASoC driver for Mediatek MT8186 boards + with the MT6366(MT6358) DA7219 MAX98357A codecs. + Select Y if you have such device. + If unsure select "N". + +config SND_SOC_MT8186_MT6366_RT1019_RT5682S + tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S codec" + depends on I2C && GPIOLIB + depends on SND_SOC_MT8186 && MTK_PMIC_WRAP + select SND_SOC_MT6358 + select SND_SOC_RT1015P + select SND_SOC_RT5682S + select SND_SOC_BT_SCO + select SND_SOC_DMIC + select SND_SOC_HDMI_CODEC + help + This adds ASoC driver for Mediatek MT8186 boards + with the MT6366(MT6358) RT1019 RT5682S codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MTK_BTCVSD tristate "ALSA BT SCO CVSD/MSBC Driver" help diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 34778ca12106..5571c640a288 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/ +obj-$(CONFIG_SND_SOC_MT8186) += mt8186/ obj-$(CONFIG_SND_SOC_MT8192) += mt8192/ obj-$(CONFIG_SND_SOC_MT8195) += mt8195/ diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile index acbe01e9e928..576deb7f8cce 100644 --- a/sound/soc/mediatek/common/Makefile +++ b/sound/soc/mediatek/common/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # platform driver -snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o +snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.c b/sound/soc/mediatek/common/mtk-dsp-sof-common.c new file mode 100644 index 000000000000..8b1b623207be --- /dev/null +++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mtk-dsp-sof-common.c -- MediaTek dsp sof common ctrl + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Chunxu Li <chunxu.li@mediatek.com> + */ + +#include "mtk-dsp-sof-common.h" +#include "mtk-soc-card.h" + +/* fixup the BE DAI link to match any values from topology */ +int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_card *card = rtd->card; + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); + struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + int i, j, ret = 0; + + for (i = 0; i < sof_priv->num_streams; i++) { + struct snd_soc_dai *cpu_dai; + struct snd_soc_pcm_runtime *runtime; + struct snd_soc_dai_link *sof_dai_link = NULL; + const struct sof_conn_stream *conn = &sof_priv->conn_streams[i]; + + if (strcmp(rtd->dai_link->name, conn->normal_link)) + continue; + + for_each_card_rtds(card, runtime) { + if (strcmp(runtime->dai_link->name, conn->sof_link)) + continue; + + for_each_rtd_cpu_dais(runtime, j, cpu_dai) { + if (cpu_dai->stream_active[conn->stream_dir] > 0) { + sof_dai_link = runtime->dai_link; + break; + } + } + break; + } + + if (sof_dai_link && sof_dai_link->be_hw_params_fixup) + ret = sof_dai_link->be_hw_params_fixup(runtime, params); + + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(mtk_sof_dai_link_fixup); + +int mtk_sof_card_probe(struct snd_soc_card *card) +{ + int i; + struct snd_soc_dai_link *dai_link; + + /* Set stream_name to help sof bind widgets */ + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->no_pcm && !dai_link->stream_name && dai_link->name) + dai_link->stream_name = dai_link->name; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_sof_card_probe); + +int mtk_sof_card_late_probe(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_component *sof_comp = NULL; + struct mtk_soc_card_data *soc_card_data = + snd_soc_card_get_drvdata(card); + struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + int i; + + /* 1. find sof component */ + for_each_card_rtds(card, rtd) { + sof_comp = snd_soc_rtdcom_lookup(rtd, "sof-audio-component"); + if (sof_comp) + break; + } + + if (!sof_comp) { + dev_info(card->dev, "probe without sof-audio-component\n"); + return 0; + } + + /* 2. add route path and fixup callback */ + for (i = 0; i < sof_priv->num_streams; i++) { + const struct sof_conn_stream *conn = &sof_priv->conn_streams[i]; + struct snd_soc_pcm_runtime *sof_rtd = NULL; + struct snd_soc_pcm_runtime *normal_rtd = NULL; + + for_each_card_rtds(card, rtd) { + if (!strcmp(rtd->dai_link->name, conn->sof_link)) { + sof_rtd = rtd; + continue; + } + if (!strcmp(rtd->dai_link->name, conn->normal_link)) { + normal_rtd = rtd; + continue; + } + if (normal_rtd && sof_rtd) + break; + } + if (normal_rtd && sof_rtd) { + int j; + struct snd_soc_dai *cpu_dai; + + for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) { + struct snd_soc_dapm_route route; + struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_widget *play_widget = + cpu_dai->playback_widget; + struct snd_soc_dapm_widget *cap_widget = + cpu_dai->capture_widget; + memset(&route, 0, sizeof(route)); + if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE && + cap_widget) { + snd_soc_dapm_widget_for_each_sink_path(cap_widget, p) { + route.source = conn->sof_dma; + route.sink = p->sink->name; + snd_soc_dapm_add_routes(&card->dapm, &route, 1); + } + } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK && + play_widget) { + snd_soc_dapm_widget_for_each_source_path(play_widget, p) { + route.source = p->source->name; + route.sink = conn->sof_dma; + snd_soc_dapm_add_routes(&card->dapm, &route, 1); + } + } else { + dev_err(cpu_dai->dev, "stream dir and widget not pair\n"); + } + } + + sof_rtd->dai_link->be_hw_params_fixup = + sof_comp->driver->be_hw_params_fixup; + if (sof_priv->sof_dai_link_fixup) + normal_rtd->dai_link->be_hw_params_fixup = + sof_priv->sof_dai_link_fixup; + else + normal_rtd->dai_link->be_hw_params_fixup = mtk_sof_dai_link_fixup; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_sof_card_late_probe); + +int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, + const char *propname, struct snd_soc_dai_link *pre_dai_links, + int pre_num_links) +{ + struct device *dev = card->dev; + struct snd_soc_dai_link *parsed_dai_link; + const char *dai_name = NULL; + int i, j, ret, num_links, parsed_num_links = 0; + + num_links = of_property_count_strings(np, "mediatek,dai-link"); + if (num_links < 0 || num_links > card->num_links) { + dev_dbg(dev, "number of dai-link is invalid\n"); + return -EINVAL; + } + + parsed_dai_link = devm_kcalloc(dev, num_links, sizeof(*parsed_dai_link), GFP_KERNEL); + if (!parsed_dai_link) + return -ENOMEM; + + for (i = 0; i < num_links; i++) { + ret = of_property_read_string_index(np, propname, i, &dai_name); + if (ret) { + dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n", + propname, i, ret); + return ret; + } + dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name); + for (j = 0; j < pre_num_links; j++) { + if (!strcmp(dai_name, pre_dai_links[j].name)) { + memcpy(&parsed_dai_link[parsed_num_links++], &pre_dai_links[j], + sizeof(struct snd_soc_dai_link)); + break; + } + } + } + + if (parsed_num_links != num_links) + return -EINVAL; + + card->dai_link = parsed_dai_link; + card->num_links = parsed_num_links; + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_sof_dailink_parse_of); diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.h b/sound/soc/mediatek/common/mtk-dsp-sof-common.h new file mode 100644 index 000000000000..dd38c4a93574 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mtk-dsp-sof-common.h -- MediaTek dsp sof common definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Chunxu Li <chunxu.li@mediatek.com> + */ + +#ifndef _MTK_DSP_SOF_COMMON_H_ +#define _MTK_DSP_SOF_COMMON_H_ + +#include <sound/soc.h> + +struct sof_conn_stream { + const char *normal_link; + const char *sof_link; + const char *sof_dma; + int stream_dir; +}; + +struct mtk_sof_priv { + const struct sof_conn_stream *conn_streams; + int num_streams; + int (*sof_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +}; + +int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int mtk_sof_card_probe(struct snd_soc_card *card); +int mtk_sof_card_late_probe(struct snd_soc_card *card); +int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, + const char *propname, struct snd_soc_dai_link *pre_dai_links, + int pre_num_links); + +#endif diff --git a/sound/soc/mediatek/common/mtk-soc-card.h b/sound/soc/mediatek/common/mtk-soc-card.h new file mode 100644 index 000000000000..eeda79370049 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-soc-card.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mtk-soc-card.h -- MediaTek soc card data definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Chunxu Li <chunxu.li@mediatek.com> + */ + +#ifndef _MTK_SOC_CARD_H_ +#define _MTK_SOC_CARD_H_ + +struct mtk_soc_card_data { + void *mach_priv; + void *sof_priv; +}; + +#endif diff --git a/sound/soc/mediatek/mt8186/Makefile b/sound/soc/mediatek/mt8186/Makefile new file mode 100644 index 000000000000..49b0026628a0 --- /dev/null +++ b/sound/soc/mediatek/mt8186/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0 + +# platform driver +snd-soc-mt8186-afe-objs := \ + mt8186-afe-pcm.o \ + mt8186-audsys-clk.o \ + mt8186-afe-clk.o \ + mt8186-afe-gpio.o \ + mt8186-dai-adda.o \ + mt8186-afe-control.o \ + mt8186-dai-i2s.o \ + mt8186-dai-hw-gain.o \ + mt8186-dai-pcm.o \ + mt8186-dai-src.o \ + mt8186-dai-hostless.o \ + mt8186-dai-tdm.o \ + mt8186-misc-control.o \ + mt8186-mt6366-common.o + +obj-$(CONFIG_SND_SOC_MT8186) += snd-soc-mt8186-afe.o +obj-$(CONFIG_SND_SOC_MT8186_MT6366_DA7219_MAX98357) += mt8186-mt6366-da7219-max98357.o +obj-$(CONFIG_SND_SOC_MT8186_MT6366_RT1019_RT5682S) += mt8186-mt6366-rt1019-rt5682s.o diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c index 0275f66ddc18..a6b4f29049bb 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c @@ -645,7 +645,8 @@ int mt8186_init_clock(struct mtk_base_afe *afe) return 0; } -void mt8186_deinit_clock(struct mtk_base_afe *afe) +void mt8186_deinit_clock(void *priv) { + struct mtk_base_afe *afe = priv; mt8186_audsys_clk_unregister(afe); } diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h index c539557d7c78..d5988717d8f2 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h @@ -81,7 +81,7 @@ enum { struct mtk_base_afe; int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe, int clk_id); int mt8186_init_clock(struct mtk_base_afe *afe); -void mt8186_deinit_clock(struct mtk_base_afe *afe); +void mt8186_deinit_clock(void *priv); int mt8186_afe_enable_cgs(struct mtk_base_afe *afe); void mt8186_afe_disable_cgs(struct mtk_base_afe *afe); int mt8186_afe_enable_clock(struct mtk_base_afe *afe); diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-common.h b/sound/soc/mediatek/mt8186/mt8186-afe-common.h new file mode 100644 index 000000000000..b8f03e1b7e49 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-common.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt8186-afe-common.h -- Mediatek 8186 audio driver definitions + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + */ + +#ifndef _MT_8186_AFE_COMMON_H_ +#define _MT_8186_AFE_COMMON_H_ +#include <sound/soc.h> +#include <linux/list.h> +#include <linux/regmap.h> +#include "mt8186-reg.h" +#include "../common/mtk-base-afe.h" + +enum { + MT8186_MEMIF_DL1, + MT8186_MEMIF_DL12, + MT8186_MEMIF_DL2, + MT8186_MEMIF_DL3, + MT8186_MEMIF_DL4, + MT8186_MEMIF_DL5, + MT8186_MEMIF_DL6, + MT8186_MEMIF_DL7, + MT8186_MEMIF_DL8, + MT8186_MEMIF_VUL12, + MT8186_MEMIF_VUL2, + MT8186_MEMIF_VUL3, + MT8186_MEMIF_VUL4, + MT8186_MEMIF_VUL5, + MT8186_MEMIF_VUL6, + MT8186_MEMIF_AWB, + MT8186_MEMIF_AWB2, + MT8186_MEMIF_NUM, + MT8186_DAI_ADDA = MT8186_MEMIF_NUM, + MT8186_DAI_AP_DMIC, + MT8186_DAI_CONNSYS_I2S, + MT8186_DAI_I2S_0, + MT8186_DAI_I2S_1, + MT8186_DAI_I2S_2, + MT8186_DAI_I2S_3, + MT8186_DAI_HW_GAIN_1, + MT8186_DAI_HW_GAIN_2, + MT8186_DAI_SRC_1, + MT8186_DAI_SRC_2, + MT8186_DAI_PCM, + MT8186_DAI_TDM_IN, + MT8186_DAI_HOSTLESS_LPBK, + MT8186_DAI_HOSTLESS_FM, + MT8186_DAI_HOSTLESS_HW_GAIN_AAUDIO, + MT8186_DAI_HOSTLESS_SRC_AAUDIO, + MT8186_DAI_HOSTLESS_SRC_1, + MT8186_DAI_HOSTLESS_SRC_BARGEIN, + MT8186_DAI_HOSTLESS_UL1, + MT8186_DAI_HOSTLESS_UL2, + MT8186_DAI_HOSTLESS_UL3, + MT8186_DAI_HOSTLESS_UL5, + MT8186_DAI_HOSTLESS_UL6, + MT8186_DAI_NUM, +}; + +#define MT8186_RECORD_MEMIF MT8186_MEMIF_VUL12 +#define MT8186_ECHO_REF_MEMIF MT8186_MEMIF_AWB +#define MT8186_PRIMARY_MEMIF MT8186_MEMIF_DL1 +#define MT8186_FAST_MEMIF MT8186_MEMIF_DL2 +#define MT8186_DEEP_MEMIF MT8186_MEMIF_DL3 +#define MT8186_VOIP_MEMIF MT8186_MEMIF_DL12 +#define MT8186_MMAP_DL_MEMIF MT8186_MEMIF_DL5 +#define MT8186_MMAP_UL_MEMIF MT8186_MEMIF_VUL5 +#define MT8186_BARGEIN_MEMIF MT8186_MEMIF_AWB + +enum { + MT8186_IRQ_0, + MT8186_IRQ_1, + MT8186_IRQ_2, + MT8186_IRQ_3, + MT8186_IRQ_4, + MT8186_IRQ_5, + MT8186_IRQ_6, + MT8186_IRQ_7, + MT8186_IRQ_8, + MT8186_IRQ_9, + MT8186_IRQ_10, + MT8186_IRQ_11, + MT8186_IRQ_12, + MT8186_IRQ_13, + MT8186_IRQ_14, + MT8186_IRQ_15, + MT8186_IRQ_16, + MT8186_IRQ_17, + MT8186_IRQ_18, + MT8186_IRQ_19, + MT8186_IRQ_20, + MT8186_IRQ_21, + MT8186_IRQ_22, + MT8186_IRQ_23, + MT8186_IRQ_24, + MT8186_IRQ_25, + MT8186_IRQ_26, + MT8186_IRQ_NUM, +}; + +enum { + MT8186_AFE_IRQ_DIR_MCU = 0, + MT8186_AFE_IRQ_DIR_DSP, + MT8186_AFE_IRQ_DIR_BOTH, +}; + +enum { + MTKAIF_PROTOCOL_1 = 0, + MTKAIF_PROTOCOL_2, + MTKAIF_PROTOCOL_2_CLK_P2, +}; + +enum { + MTK_AFE_ADDA_DL_GAIN_MUTE = 0, + MTK_AFE_ADDA_DL_GAIN_NORMAL = 0xf74f, + /* SA suggest apply -0.3db to audio/speech path */ +}; + +#define MTK_SPK_I2S_0_STR "MTK_SPK_I2S_0" +#define MTK_SPK_I2S_1_STR "MTK_SPK_I2S_1" +#define MTK_SPK_I2S_2_STR "MTK_SPK_I2S_2" +#define MTK_SPK_I2S_3_STR "MTK_SPK_I2S_3" + +/* MCLK */ +enum { + MT8186_I2S0_MCK = 0, + MT8186_I2S1_MCK, + MT8186_I2S2_MCK, + MT8186_I2S4_MCK, + MT8186_TDM_MCK, + MT8186_MCK_NUM, +}; + +struct snd_pcm_substream; +struct mtk_base_irq_data; +struct clk; + +struct mt8186_afe_private { + struct clk **clk; + struct clk_lookup **lookup; + struct regmap *topckgen; + struct regmap *apmixedsys; + struct regmap *infracfg; + int irq_cnt[MT8186_MEMIF_NUM]; + int stf_positive_gain_db; + int pm_runtime_bypass_reg_ctl; + int sgen_mode; + int sgen_rate; + int sgen_amplitude; + + /* xrun assert */ + int xrun_assert[MT8186_MEMIF_NUM]; + + /* dai */ + bool dai_on[MT8186_DAI_NUM]; + void *dai_priv[MT8186_DAI_NUM]; + + /* adda */ + bool mtkaif_calibration_ok; + int mtkaif_protocol; + int mtkaif_chosen_phase[4]; + int mtkaif_phase_cycle[4]; + int mtkaif_calibration_num_phase; + int mtkaif_dmic; + int mtkaif_looback0; + int mtkaif_looback1; + + /* mck */ + int mck_rate[MT8186_MCK_NUM]; +}; + +int mt8186_dai_adda_register(struct mtk_base_afe *afe); +int mt8186_dai_i2s_register(struct mtk_base_afe *afe); +int mt8186_dai_tdm_register(struct mtk_base_afe *afe); +int mt8186_dai_hw_gain_register(struct mtk_base_afe *afe); +int mt8186_dai_src_register(struct mtk_base_afe *afe); +int mt8186_dai_pcm_register(struct mtk_base_afe *afe); +int mt8186_dai_hostless_register(struct mtk_base_afe *afe); + +int mt8186_add_misc_control(struct snd_soc_component *component); + +unsigned int mt8186_general_rate_transform(struct device *dev, + unsigned int rate); +unsigned int mt8186_rate_transform(struct device *dev, + unsigned int rate, int aud_blk); +unsigned int mt8186_tdm_relatch_rate_transform(struct device *dev, + unsigned int rate); + +int mt8186_dai_set_priv(struct mtk_base_afe *afe, int id, + int priv_size, const void *priv_data); + +#endif diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-control.c b/sound/soc/mediatek/mt8186/mt8186-afe-control.c new file mode 100644 index 000000000000..d714e9641571 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-control.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include "mt8186-afe-common.h" +#include <linux/pm_runtime.h> + +enum { + MTK_AFE_RATE_8K = 0, + MTK_AFE_RATE_11K, + MTK_AFE_RATE_12K, + MTK_AFE_RATE_384K, + MTK_AFE_RATE_16K, + MTK_AFE_RATE_22K, + MTK_AFE_RATE_24K, + MTK_AFE_RATE_352K, + MTK_AFE_RATE_32K, + MTK_AFE_RATE_44K, + MTK_AFE_RATE_48K, + MTK_AFE_RATE_88K, + MTK_AFE_RATE_96K, + MTK_AFE_RATE_176K, + MTK_AFE_RATE_192K, + MTK_AFE_RATE_260K, +}; + +enum { + MTK_AFE_PCM_RATE_8K = 0, + MTK_AFE_PCM_RATE_16K, + MTK_AFE_PCM_RATE_32K, + MTK_AFE_PCM_RATE_48K, +}; + +enum { + MTK_AFE_TDM_RATE_8K = 0, + MTK_AFE_TDM_RATE_12K, + MTK_AFE_TDM_RATE_16K, + MTK_AFE_TDM_RATE_24K, + MTK_AFE_TDM_RATE_32K, + MTK_AFE_TDM_RATE_48K, + MTK_AFE_TDM_RATE_64K, + MTK_AFE_TDM_RATE_96K, + MTK_AFE_TDM_RATE_128K, + MTK_AFE_TDM_RATE_192K, + MTK_AFE_TDM_RATE_256K, + MTK_AFE_TDM_RATE_384K, + MTK_AFE_TDM_RATE_11K, + MTK_AFE_TDM_RATE_22K, + MTK_AFE_TDM_RATE_44K, + MTK_AFE_TDM_RATE_88K, + MTK_AFE_TDM_RATE_176K, + MTK_AFE_TDM_RATE_352K, +}; + +enum { + MTK_AFE_TDM_RELATCH_RATE_8K = 0, + MTK_AFE_TDM_RELATCH_RATE_11K, + MTK_AFE_TDM_RELATCH_RATE_12K, + MTK_AFE_TDM_RELATCH_RATE_16K, + MTK_AFE_TDM_RELATCH_RATE_22K, + MTK_AFE_TDM_RELATCH_RATE_24K, + MTK_AFE_TDM_RELATCH_RATE_32K, + MTK_AFE_TDM_RELATCH_RATE_44K, + MTK_AFE_TDM_RELATCH_RATE_48K, + MTK_AFE_TDM_RELATCH_RATE_88K, + MTK_AFE_TDM_RELATCH_RATE_96K, + MTK_AFE_TDM_RELATCH_RATE_176K, + MTK_AFE_TDM_RELATCH_RATE_192K, + MTK_AFE_TDM_RELATCH_RATE_352K, + MTK_AFE_TDM_RELATCH_RATE_384K, +}; + +unsigned int mt8186_general_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_RATE_8K; + case 11025: + return MTK_AFE_RATE_11K; + case 12000: + return MTK_AFE_RATE_12K; + case 16000: + return MTK_AFE_RATE_16K; + case 22050: + return MTK_AFE_RATE_22K; + case 24000: + return MTK_AFE_RATE_24K; + case 32000: + return MTK_AFE_RATE_32K; + case 44100: + return MTK_AFE_RATE_44K; + case 48000: + return MTK_AFE_RATE_48K; + case 88200: + return MTK_AFE_RATE_88K; + case 96000: + return MTK_AFE_RATE_96K; + case 176400: + return MTK_AFE_RATE_176K; + case 192000: + return MTK_AFE_RATE_192K; + case 260000: + return MTK_AFE_RATE_260K; + case 352800: + return MTK_AFE_RATE_352K; + case 384000: + return MTK_AFE_RATE_384K; + default: + dev_err(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, rate, MTK_AFE_RATE_48K); + } + + return MTK_AFE_RATE_48K; +} + +static unsigned int tdm_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_TDM_RATE_8K; + case 11025: + return MTK_AFE_TDM_RATE_11K; + case 12000: + return MTK_AFE_TDM_RATE_12K; + case 16000: + return MTK_AFE_TDM_RATE_16K; + case 22050: + return MTK_AFE_TDM_RATE_22K; + case 24000: + return MTK_AFE_TDM_RATE_24K; + case 32000: + return MTK_AFE_TDM_RATE_32K; + case 44100: + return MTK_AFE_TDM_RATE_44K; + case 48000: + return MTK_AFE_TDM_RATE_48K; + case 64000: + return MTK_AFE_TDM_RATE_64K; + case 88200: + return MTK_AFE_TDM_RATE_88K; + case 96000: + return MTK_AFE_TDM_RATE_96K; + case 128000: + return MTK_AFE_TDM_RATE_128K; + case 176400: + return MTK_AFE_TDM_RATE_176K; + case 192000: + return MTK_AFE_TDM_RATE_192K; + case 256000: + return MTK_AFE_TDM_RATE_256K; + case 352800: + return MTK_AFE_TDM_RATE_352K; + case 384000: + return MTK_AFE_TDM_RATE_384K; + default: + dev_err(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, rate, MTK_AFE_TDM_RATE_48K); + } + + return MTK_AFE_TDM_RATE_48K; +} + +static unsigned int pcm_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_PCM_RATE_8K; + case 16000: + return MTK_AFE_PCM_RATE_16K; + case 32000: + return MTK_AFE_PCM_RATE_32K; + case 48000: + return MTK_AFE_PCM_RATE_48K; + default: + dev_err(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, rate, MTK_AFE_PCM_RATE_48K); + } + + return MTK_AFE_PCM_RATE_48K; +} + +unsigned int mt8186_tdm_relatch_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_TDM_RELATCH_RATE_8K; + case 11025: + return MTK_AFE_TDM_RELATCH_RATE_11K; + case 12000: + return MTK_AFE_TDM_RELATCH_RATE_12K; + case 16000: + return MTK_AFE_TDM_RELATCH_RATE_16K; + case 22050: + return MTK_AFE_TDM_RELATCH_RATE_22K; + case 24000: + return MTK_AFE_TDM_RELATCH_RATE_24K; + case 32000: + return MTK_AFE_TDM_RELATCH_RATE_32K; + case 44100: + return MTK_AFE_TDM_RELATCH_RATE_44K; + case 48000: + return MTK_AFE_TDM_RELATCH_RATE_48K; + case 88200: + return MTK_AFE_TDM_RELATCH_RATE_88K; + case 96000: + return MTK_AFE_TDM_RELATCH_RATE_96K; + case 176400: + return MTK_AFE_TDM_RELATCH_RATE_176K; + case 192000: + return MTK_AFE_TDM_RELATCH_RATE_192K; + case 352800: + return MTK_AFE_TDM_RELATCH_RATE_352K; + case 384000: + return MTK_AFE_TDM_RELATCH_RATE_384K; + default: + dev_err(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, rate, MTK_AFE_TDM_RELATCH_RATE_48K); + } + + return MTK_AFE_TDM_RELATCH_RATE_48K; +} + +unsigned int mt8186_rate_transform(struct device *dev, unsigned int rate, int aud_blk) +{ + switch (aud_blk) { + case MT8186_DAI_PCM: + return pcm_rate_transform(dev, rate); + case MT8186_DAI_TDM_IN: + return tdm_rate_transform(dev, rate); + default: + return mt8186_general_rate_transform(dev, rate); + } +} + +int mt8186_dai_set_priv(struct mtk_base_afe *afe, int id, int priv_size, const void *priv_data) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + void *temp_data; + + temp_data = devm_kzalloc(afe->dev, + priv_size, + GFP_KERNEL); + if (!temp_data) + return -ENOMEM; + + if (priv_data) + memcpy(temp_data, priv_data, priv_size); + + afe_priv->dai_priv[id] = temp_data; + + return 0; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c new file mode 100644 index 000000000000..eb729ab00f5a --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c @@ -0,0 +1,3000 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Mediatek ALSA SoC AFE platform driver for 8186 +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <sound/soc.h> + +#include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-afe-fe-dai.h" + +#include "mt8186-afe-common.h" +#include "mt8186-afe-clk.h" +#include "mt8186-afe-gpio.h" +#include "mt8186-interconnection.h" + +static const struct snd_pcm_hardware mt8186_afe_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + .period_bytes_min = 96, + .period_bytes_max = 4 * 48 * 1024, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 4 * 48 * 1024, + .fifo_size = 0, +}; + +static int mt8186_fe_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct snd_pcm_runtime *runtime = substream->runtime; + int id = asoc_rtd_to_cpu(rtd, 0)->id; + struct mtk_base_afe_memif *memif = &afe->memif[id]; + const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware; + int ret; + + memif->substream = substream; + + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); + + snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware); + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); + return ret; + } + + /* dynamic allocate irq to memif */ + if (memif->irq_usage < 0) { + int irq_id = mtk_dynamic_irq_acquire(afe); + + if (irq_id != afe->irqs_size) { + /* link */ + memif->irq_usage = irq_id; + } else { + dev_err(afe->dev, "%s() error: no more asys irq\n", + __func__); + return -EBUSY; + } + } + + return 0; +} + +static void mt8186_fe_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int id = asoc_rtd_to_cpu(rtd, 0)->id; + struct mtk_base_afe_memif *memif = &afe->memif[id]; + int irq_id = memif->irq_usage; + + memif->substream = NULL; + afe_priv->irq_cnt[id] = 0; + afe_priv->xrun_assert[id] = 0; + + if (!memif->const_irq) { + mtk_dynamic_irq_release(afe, irq_id); + memif->irq_usage = -1; + memif->substream = NULL; + } +} + +static int mt8186_fe_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + int id = asoc_rtd_to_cpu(rtd, 0)->id; + unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); + int ret; + + ret = mtk_afe_fe_hw_params(substream, params, dai); + if (ret) + return ret; + + /* channel merge configuration, enable control is in UL5_IN_MUX */ + if (id == MT8186_MEMIF_VUL3) { + int update_cnt = 8; + unsigned int val = 0; + unsigned int mask = 0; + int fs_mode = mt8186_rate_transform(afe->dev, rate, id); + + /* set rate, channel, update cnt, disable sgen */ + val = fs_mode << CM1_FS_SELECT_SFT | + (channels - 1) << CHANNEL_MERGE0_CHNUM_SFT | + update_cnt << CHANNEL_MERGE0_UPDATE_CNT_SFT; + mask = CM1_FS_SELECT_MASK_SFT | + CHANNEL_MERGE0_CHNUM_MASK_SFT | + CHANNEL_MERGE0_UPDATE_CNT_MASK_SFT; + regmap_update_bits(afe->regmap, AFE_CM1_CON, mask, val); + } + + return 0; +} + +static int mt8186_fe_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = mtk_afe_fe_hw_free(substream, dai); + if (ret) { + dev_err(afe->dev, "%s failed\n", __func__); + return ret; + } + + return 0; +} + +static int mt8186_fe_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime * const runtime = substream->runtime; + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int id = asoc_rtd_to_cpu(rtd, 0)->id; + struct mtk_base_afe_memif *memif = &afe->memif[id]; + int irq_id = memif->irq_usage; + struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id]; + const struct mtk_base_irq_data *irq_data = irqs->irq_data; + unsigned int rate = runtime->rate; + unsigned int counter; + int fs; + int ret; + + dev_dbg(afe->dev, "%s(), %s cmd %d, irq_id %d\n", + __func__, memif->data->name, cmd, irq_id); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + ret = mtk_memif_set_enable(afe, id); + if (ret) { + dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n", + __func__, id, ret); + return ret; + } + + /* + * for small latency record + * ul memif need read some data before irq enable + */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + ((runtime->period_size * 1000) / rate <= 10)) + udelay(300); + + /* set irq counter */ + if (afe_priv->irq_cnt[id] > 0) + counter = afe_priv->irq_cnt[id]; + else + counter = runtime->period_size; + + regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, + irq_data->irq_cnt_maskbit + << irq_data->irq_cnt_shift, + counter << irq_data->irq_cnt_shift); + + /* set irq fs */ + fs = afe->irq_fs(substream, runtime->rate); + if (fs < 0) + return -EINVAL; + + regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, + irq_data->irq_fs_maskbit + << irq_data->irq_fs_shift, + fs << irq_data->irq_fs_shift); + + /* enable interrupt */ + if (runtime->stop_threshold != ~(0U)) + regmap_update_bits(afe->regmap, + irq_data->irq_en_reg, + 1 << irq_data->irq_en_shift, + 1 << irq_data->irq_en_shift); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + if (afe_priv->xrun_assert[id] > 0) { + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + int avail = snd_pcm_capture_avail(runtime); + /* alsa can trigger stop/start when occur xrun */ + if (avail >= runtime->buffer_size) + dev_dbg(afe->dev, "%s(), id %d, xrun assert\n", + __func__, id); + } + } + + ret = mtk_memif_set_disable(afe, id); + if (ret) + dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n", + __func__, id, ret); + + /* disable interrupt */ + if (runtime->stop_threshold != ~(0U)) + regmap_update_bits(afe->regmap, + irq_data->irq_en_reg, + 1 << irq_data->irq_en_shift, + 0 << irq_data->irq_en_shift); + + /* clear pending IRQ */ + regmap_write(afe->regmap, irq_data->irq_clr_reg, + 1 << irq_data->irq_clr_shift); + return ret; + default: + return -EINVAL; + } +} + +static int mt8186_memif_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + int id = asoc_rtd_to_cpu(rtd, 0)->id; + + return mt8186_rate_transform(afe->dev, rate, id); +} + +static int mt8186_get_dai_fs(struct mtk_base_afe *afe, + int dai_id, unsigned int rate) +{ + return mt8186_rate_transform(afe->dev, rate, dai_id); +} + +static int mt8186_irq_fs(struct snd_pcm_substream *substream, unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt8186_general_rate_transform(afe->dev, rate); +} + +static int mt8186_get_memif_pbuf_size(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + if ((runtime->period_size * 1000) / runtime->rate > 10) + return MT8186_MEMIF_PBUF_SIZE_256_BYTES; + + return MT8186_MEMIF_PBUF_SIZE_32_BYTES; +} + +static int mt8186_fe_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime * const runtime = substream->runtime; + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + int id = asoc_rtd_to_cpu(rtd, 0)->id; + struct mtk_base_afe_memif *memif = &afe->memif[id]; + int irq_id = memif->irq_usage; + struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id]; + const struct mtk_base_irq_data *irq_data = irqs->irq_data; + unsigned int counter = runtime->period_size; + int fs; + int ret; + + ret = mtk_afe_fe_prepare(substream, dai); + if (ret) + return ret; + + /* set irq counter */ + regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, + irq_data->irq_cnt_maskbit + << irq_data->irq_cnt_shift, + counter << irq_data->irq_cnt_shift); + + /* set irq fs */ + fs = afe->irq_fs(substream, runtime->rate); + + if (fs < 0) + return -EINVAL; + + regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, + irq_data->irq_fs_maskbit + << irq_data->irq_fs_shift, + fs << irq_data->irq_fs_shift); + + return 0; +} + +/* FE DAIs */ +static const struct snd_soc_dai_ops mt8186_memif_dai_ops = { + .startup = mt8186_fe_startup, + .shutdown = mt8186_fe_shutdown, + .hw_params = mt8186_fe_hw_params, + .hw_free = mt8186_fe_hw_free, + .prepare = mt8186_fe_prepare, + .trigger = mt8186_fe_trigger, +}; + +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mt8186_memif_dai_driver[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "DL1", + .id = MT8186_MEMIF_DL1, + .playback = { + .stream_name = "DL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "DL12", + .id = MT8186_MEMIF_DL12, + .playback = { + .stream_name = "DL12", + .channels_min = 1, + .channels_max = 4, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "DL2", + .id = MT8186_MEMIF_DL2, + .playback = { + .stream_name = "DL2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "DL3", + .id = MT8186_MEMIF_DL3, + .playback = { + .stream_name = "DL3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "DL4", + .id = MT8186_MEMIF_DL4, + .playback = { + .stream_name = "DL4", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "DL5", + .id = MT8186_MEMIF_DL5, + .playback = { + .stream_name = "DL5", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "DL6", + .id = MT8186_MEMIF_DL6, + .playback = { + .stream_name = "DL6", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "DL7", + .id = MT8186_MEMIF_DL7, + .playback = { + .stream_name = "DL7", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "DL8", + .id = MT8186_MEMIF_DL8, + .playback = { + .stream_name = "DL8", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "UL1", + .id = MT8186_MEMIF_VUL12, + .capture = { + .stream_name = "UL1", + .channels_min = 1, + .channels_max = 4, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "UL2", + .id = MT8186_MEMIF_AWB, + .capture = { + .stream_name = "UL2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "UL3", + .id = MT8186_MEMIF_VUL2, + .capture = { + .stream_name = "UL3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "UL4", + .id = MT8186_MEMIF_AWB2, + .capture = { + .stream_name = "UL4", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "UL5", + .id = MT8186_MEMIF_VUL3, + .capture = { + .stream_name = "UL5", + .channels_min = 1, + .channels_max = 12, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "UL6", + .id = MT8186_MEMIF_VUL4, + .capture = { + .stream_name = "UL6", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "UL7", + .id = MT8186_MEMIF_VUL5, + .capture = { + .stream_name = "UL7", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + }, + { + .name = "UL8", + .id = MT8186_MEMIF_VUL6, + .capture = { + .stream_name = "UL8", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mt8186_memif_dai_ops, + } +}; + +/* kcontrol */ +static int mt8186_irq_cnt1_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = + afe_priv->irq_cnt[MT8186_PRIMARY_MEMIF]; + + return 0; +} + +static int mt8186_irq_cnt1_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int memif_num = MT8186_PRIMARY_MEMIF; + struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; + int irq_id = memif->irq_usage; + int irq_cnt = afe_priv->irq_cnt[memif_num]; + + dev_dbg(afe->dev, "%s(), irq_id %d, irq_cnt = %d, value = %ld\n", + __func__, irq_id, irq_cnt, ucontrol->value.integer.value[0]); + + if (irq_cnt == ucontrol->value.integer.value[0]) + return 0; + + irq_cnt = ucontrol->value.integer.value[0]; + afe_priv->irq_cnt[memif_num] = irq_cnt; + + if (!pm_runtime_status_suspended(afe->dev) && irq_id >= 0) { + struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id]; + const struct mtk_base_irq_data *irq_data = irqs->irq_data; + + regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, + irq_data->irq_cnt_maskbit + << irq_data->irq_cnt_shift, + irq_cnt << irq_data->irq_cnt_shift); + } else { + dev_dbg(afe->dev, "%s(), suspended || irq_id %d, not set\n", + __func__, irq_id); + } + + return 1; +} + +static int mt8186_irq_cnt2_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = + afe_priv->irq_cnt[MT8186_RECORD_MEMIF]; + + return 0; +} + +static int mt8186_irq_cnt2_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int memif_num = MT8186_RECORD_MEMIF; + struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; + int irq_id = memif->irq_usage; + int irq_cnt = afe_priv->irq_cnt[memif_num]; + + dev_dbg(afe->dev, "%s(), irq_id %d, irq_cnt = %d, value = %ld\n", + __func__, irq_id, irq_cnt, ucontrol->value.integer.value[0]); + + if (irq_cnt == ucontrol->value.integer.value[0]) + return 0; + + irq_cnt = ucontrol->value.integer.value[0]; + afe_priv->irq_cnt[memif_num] = irq_cnt; + + if (!pm_runtime_status_suspended(afe->dev) && irq_id >= 0) { + struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id]; + const struct mtk_base_irq_data *irq_data = irqs->irq_data; + + regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, + irq_data->irq_cnt_maskbit + << irq_data->irq_cnt_shift, + irq_cnt << irq_data->irq_cnt_shift); + } else { + dev_dbg(afe->dev, "%s(), suspended || irq_id %d, not set\n", + __func__, irq_id); + } + + return 1; +} + +static int mt8186_record_xrun_assert_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int xrun_assert = afe_priv->xrun_assert[MT8186_RECORD_MEMIF]; + + ucontrol->value.integer.value[0] = xrun_assert; + + return 0; +} + +static int mt8186_record_xrun_assert_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int xrun_assert = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), xrun_assert %d\n", __func__, xrun_assert); + + if (xrun_assert == afe_priv->xrun_assert[MT8186_RECORD_MEMIF]) + return 0; + + afe_priv->xrun_assert[MT8186_RECORD_MEMIF] = xrun_assert; + + return 1; +} + +static const struct snd_kcontrol_new mt8186_pcm_kcontrols[] = { + SOC_SINGLE_EXT("Audio IRQ1 CNT", SND_SOC_NOPM, 0, 0x3ffff, 0, + mt8186_irq_cnt1_get, mt8186_irq_cnt1_set), + SOC_SINGLE_EXT("Audio IRQ2 CNT", SND_SOC_NOPM, 0, 0x3ffff, 0, + mt8186_irq_cnt2_get, mt8186_irq_cnt2_set), + SOC_SINGLE_EXT("record_xrun_assert", SND_SOC_NOPM, 0, 0x1, 0, + mt8186_record_xrun_assert_get, + mt8186_record_xrun_assert_set), +}; + +/* dma widget & routes*/ +static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN21, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN21, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN21, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH1 Switch", AFE_CONN21_1, + I_TDM_IN_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN22, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN22, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN22, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4 Switch", AFE_CONN22, + I_ADDA_UL_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH2 Switch", AFE_CONN22_1, + I_TDM_IN_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul1_ch3_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN9, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN9, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN9, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH3 Switch", AFE_CONN9_1, + I_TDM_IN_CH3, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul1_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN10, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN10, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN10, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4 Switch", AFE_CONN10, + I_ADDA_UL_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH4 Switch", AFE_CONN10_1, + I_TDM_IN_CH4, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN5, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN5, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN5, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN5, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN5, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN5_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN5_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN5_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN5, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN5, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN5_1, + I_CONNSYS_I2S_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN5_1, + I_SRC_1_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN6, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN6, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN6, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN6, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN6, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN6_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN6_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN6_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN6, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN6, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN6_1, + I_CONNSYS_I2S_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN6_1, + I_SRC_1_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN32_1, + I_CONNSYS_I2S_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN32, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN32, + I_DL2_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN33_1, + I_CONNSYS_I2S_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN38, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN38, + I_I2S0_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul4_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN39, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN39, + I_I2S0_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul5_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN44, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul5_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN45, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul6_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN46, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN46, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN46, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN46_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN46, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN46, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN46_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN46, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN46, + I_GAIN1_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul6_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN47, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN47, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN47, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN47_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN47, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN47, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN47_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN47, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN47, + I_GAIN1_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul7_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN48, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH1 Switch", AFE_CONN48, + I_GAIN2_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1 Switch", AFE_CONN48_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul7_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN49, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH2 Switch", AFE_CONN49, + I_GAIN2_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2 Switch", AFE_CONN49_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul8_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN50, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul8_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN51, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH1 Switch", AFE_CONN58_1, + I_TDM_IN_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN58, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN58, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN58, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN58, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN58, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN58, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN58, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN58, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN58_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN58_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN58_1, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN58_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH2 Switch", AFE_CONN59_1, + I_TDM_IN_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN59, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN59, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN59, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN59, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN59, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN59, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN59, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN59, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN59_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN59_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN59_1, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN59_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch3_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH3 Switch", AFE_CONN60_1, + I_TDM_IN_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN60, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN60, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN60, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN60, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN60, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN60, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN60, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN60, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN60_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN60_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN60_1, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN60_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH4 Switch", AFE_CONN61_1, + I_TDM_IN_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN61, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN61, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN61, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN61, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN61, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN61, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN61, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN61, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN61_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN61_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN61_1, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN61_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch5_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH5 Switch", AFE_CONN62_1, + I_TDM_IN_CH5, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN62, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN62, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN62, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN62, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN62, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN62, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN62, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN62, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN62_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN62_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN62_1, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN62_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch6_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH6 Switch", AFE_CONN63_1, + I_TDM_IN_CH6, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN63, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN63, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN63, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN63, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN63, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN63, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN63, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN63, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN63_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN63_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN63_1, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN63_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch7_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH7 Switch", AFE_CONN64_1, + I_TDM_IN_CH7, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN64, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN64, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN64, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN64, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1v", AFE_CONN64, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN64, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN64, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN64, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN64_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN64_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN64_1, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN64_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch8_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH8 Switch", AFE_CONN65_1, + I_TDM_IN_CH8, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN65, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN65, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN65, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN65, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN65, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN65, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN65, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN65, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN65_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN65_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN65_1, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN65_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch9_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN66, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN66, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN66, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN66, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN66, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN66, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN66, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN66, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN66_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN66_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN66_1, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN66_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch10_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN67, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN67, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN67, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN67, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN67, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN67, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN67, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN67, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN67_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN67_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN67_1, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN67_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch11_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN68, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN68, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN68, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN68, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN68, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN68, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN68, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN68, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN68_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN68_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN68_1, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN68_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new hw_cm1_ch12_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN69, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN69, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN69, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN69, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN69, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN69, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN69, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN69, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN69_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN69_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN69_1, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN69_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +/* ADDA UL MUX */ +enum { + UL5_IN_MUX_CM1 = 0, + UL5_IN_MUX_NORMAL, + UL5_IN_MUX_MASK = 0x1, +}; + +static const char * const ul5_in_mux_map[] = { + "UL5_IN_FROM_CM1", "UL5_IN_FROM_Normal" +}; + +static int ul5_in_map_value[] = { + UL5_IN_MUX_CM1, + UL5_IN_MUX_NORMAL, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(ul5_in_mux_map_enum, + AFE_CM1_CON, + VUL3_BYPASS_CM_SFT, + VUL3_BYPASS_CM_MASK, + ul5_in_mux_map, + ul5_in_map_value); + +static const struct snd_kcontrol_new ul5_in_mux_control = + SOC_DAPM_ENUM("UL5_IN_MUX Select", ul5_in_mux_map_enum); + +static const struct snd_soc_dapm_widget mt8186_memif_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0, + memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)), + SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0, + memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)), + SND_SOC_DAPM_MIXER("UL1_CH3", SND_SOC_NOPM, 0, 0, + memif_ul1_ch3_mix, ARRAY_SIZE(memif_ul1_ch3_mix)), + SND_SOC_DAPM_MIXER("UL1_CH4", SND_SOC_NOPM, 0, 0, + memif_ul1_ch4_mix, ARRAY_SIZE(memif_ul1_ch4_mix)), + + SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0, + memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)), + SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0, + memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0, + memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)), + SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0, + memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL4_CH1", SND_SOC_NOPM, 0, 0, + memif_ul4_ch1_mix, ARRAY_SIZE(memif_ul4_ch1_mix)), + SND_SOC_DAPM_MIXER("UL4_CH2", SND_SOC_NOPM, 0, 0, + memif_ul4_ch2_mix, ARRAY_SIZE(memif_ul4_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL5_CH1", SND_SOC_NOPM, 0, 0, + memif_ul5_ch1_mix, ARRAY_SIZE(memif_ul5_ch1_mix)), + SND_SOC_DAPM_MIXER("UL5_CH2", SND_SOC_NOPM, 0, 0, + memif_ul5_ch2_mix, ARRAY_SIZE(memif_ul5_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL6_CH1", SND_SOC_NOPM, 0, 0, + memif_ul6_ch1_mix, ARRAY_SIZE(memif_ul6_ch1_mix)), + SND_SOC_DAPM_MIXER("UL6_CH2", SND_SOC_NOPM, 0, 0, + memif_ul6_ch2_mix, ARRAY_SIZE(memif_ul6_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL7_CH1", SND_SOC_NOPM, 0, 0, + memif_ul7_ch1_mix, ARRAY_SIZE(memif_ul7_ch1_mix)), + SND_SOC_DAPM_MIXER("UL7_CH2", SND_SOC_NOPM, 0, 0, + memif_ul7_ch2_mix, ARRAY_SIZE(memif_ul7_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL8_CH1", SND_SOC_NOPM, 0, 0, + memif_ul8_ch1_mix, ARRAY_SIZE(memif_ul8_ch1_mix)), + SND_SOC_DAPM_MIXER("UL8_CH2", SND_SOC_NOPM, 0, 0, + memif_ul8_ch2_mix, ARRAY_SIZE(memif_ul8_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL5_2CH", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("HW_CM1", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* CM1 en*/ + SND_SOC_DAPM_SUPPLY_S("CM1_EN", 0, AFE_CM1_CON, + CHANNEL_MERGE0_EN_SFT, 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("HW_CM1_CH1", SND_SOC_NOPM, 0, 0, + hw_cm1_ch1_mix, ARRAY_SIZE(hw_cm1_ch1_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH2", SND_SOC_NOPM, 0, 0, + hw_cm1_ch2_mix, ARRAY_SIZE(hw_cm1_ch2_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH3", SND_SOC_NOPM, 0, 0, + hw_cm1_ch3_mix, ARRAY_SIZE(hw_cm1_ch3_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH4", SND_SOC_NOPM, 0, 0, + hw_cm1_ch4_mix, ARRAY_SIZE(hw_cm1_ch4_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH5", SND_SOC_NOPM, 0, 0, + hw_cm1_ch5_mix, ARRAY_SIZE(hw_cm1_ch5_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH6", SND_SOC_NOPM, 0, 0, + hw_cm1_ch6_mix, ARRAY_SIZE(hw_cm1_ch6_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH7", SND_SOC_NOPM, 0, 0, + hw_cm1_ch7_mix, ARRAY_SIZE(hw_cm1_ch7_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH8", SND_SOC_NOPM, 0, 0, + hw_cm1_ch8_mix, ARRAY_SIZE(hw_cm1_ch8_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH9", SND_SOC_NOPM, 0, 0, + hw_cm1_ch9_mix, ARRAY_SIZE(hw_cm1_ch9_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH10", SND_SOC_NOPM, 0, 0, + hw_cm1_ch10_mix, ARRAY_SIZE(hw_cm1_ch10_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH11", SND_SOC_NOPM, 0, 0, + hw_cm1_ch11_mix, ARRAY_SIZE(hw_cm1_ch11_mix)), + SND_SOC_DAPM_MIXER("HW_CM1_CH12", SND_SOC_NOPM, 0, 0, + hw_cm1_ch12_mix, ARRAY_SIZE(hw_cm1_ch12_mix)), + + SND_SOC_DAPM_MUX("UL5_IN_MUX", SND_SOC_NOPM, 0, 0, + &ul5_in_mux_control), + + SND_SOC_DAPM_INPUT("UL1_VIRTUAL_INPUT"), + SND_SOC_DAPM_INPUT("UL2_VIRTUAL_INPUT"), + SND_SOC_DAPM_INPUT("UL3_VIRTUAL_INPUT"), + SND_SOC_DAPM_INPUT("UL4_VIRTUAL_INPUT"), + SND_SOC_DAPM_INPUT("UL5_VIRTUAL_INPUT"), + SND_SOC_DAPM_INPUT("UL6_VIRTUAL_INPUT"), +}; + +static const struct snd_soc_dapm_route mt8186_memif_routes[] = { + {"UL1", NULL, "UL1_CH1"}, + {"UL1", NULL, "UL1_CH2"}, + {"UL1", NULL, "UL1_CH3"}, + {"UL1", NULL, "UL1_CH4"}, + {"UL1_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"UL1_CH1", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, + {"UL1_CH2", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"UL1_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, + {"UL1_CH3", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"UL1_CH3", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, + {"UL1_CH4", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"UL1_CH4", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, + {"UL1_CH1", "TDM_IN_CH1 Switch", "TDM IN"}, + {"UL1_CH2", "TDM_IN_CH2 Switch", "TDM IN"}, + {"UL1_CH3", "TDM_IN_CH3 Switch", "TDM IN"}, + {"UL1_CH4", "TDM_IN_CH4 Switch", "TDM IN"}, + + {"UL2", NULL, "UL2_CH1"}, + {"UL2", NULL, "UL2_CH2"}, + + /* cannot connect FE to FE directly */ + {"UL2_CH1", "DL1_CH1 Switch", "Hostless_UL2 UL"}, + {"UL2_CH2", "DL1_CH2 Switch", "Hostless_UL2 UL"}, + {"UL2_CH1", "DL12_CH1 Switch", "Hostless_UL2 UL"}, + {"UL2_CH2", "DL12_CH2 Switch", "Hostless_UL2 UL"}, + {"UL2_CH1", "DL6_CH1 Switch", "Hostless_UL2 UL"}, + {"UL2_CH2", "DL6_CH2 Switch", "Hostless_UL2 UL"}, + {"UL2_CH1", "DL2_CH1 Switch", "Hostless_UL2 UL"}, + {"UL2_CH2", "DL2_CH2 Switch", "Hostless_UL2 UL"}, + {"UL2_CH1", "DL3_CH1 Switch", "Hostless_UL2 UL"}, + {"UL2_CH2", "DL3_CH2 Switch", "Hostless_UL2 UL"}, + {"UL2_CH1", "DL4_CH1 Switch", "Hostless_UL2 UL"}, + {"UL2_CH2", "DL4_CH2 Switch", "Hostless_UL2 UL"}, + {"UL2_CH1", "DL5_CH1 Switch", "Hostless_UL2 UL"}, + {"UL2_CH2", "DL5_CH2 Switch", "Hostless_UL2 UL"}, + + {"Hostless_UL2 UL", NULL, "UL2_VIRTUAL_INPUT"}, + + {"UL2_CH1", "I2S0_CH1 Switch", "I2S0"}, + {"UL2_CH2", "I2S0_CH2 Switch", "I2S0"}, + {"UL2_CH1", "I2S2_CH1 Switch", "I2S2"}, + {"UL2_CH2", "I2S2_CH2 Switch", "I2S2"}, + + {"UL2_CH1", "PCM_1_CAP_CH1 Switch", "PCM 1 Capture"}, + {"UL2_CH2", "PCM_1_CAP_CH2 Switch", "PCM 1 Capture"}, + + {"UL2_CH1", "CONNSYS_I2S_CH1 Switch", "Connsys I2S"}, + {"UL2_CH2", "CONNSYS_I2S_CH2 Switch", "Connsys I2S"}, + + {"UL2_CH1", "SRC_1_OUT_CH1 Switch", "HW_SRC_1_Out"}, + {"UL2_CH2", "SRC_1_OUT_CH2 Switch", "HW_SRC_1_Out"}, + + {"UL3", NULL, "UL3_CH1"}, + {"UL3", NULL, "UL3_CH2"}, + {"UL3_CH1", "CONNSYS_I2S_CH1 Switch", "Connsys I2S"}, + {"UL3_CH2", "CONNSYS_I2S_CH2 Switch", "Connsys I2S"}, + + {"UL4", NULL, "UL4_CH1"}, + {"UL4", NULL, "UL4_CH2"}, + {"UL4_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"UL4_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, + {"UL4_CH1", "I2S0_CH1 Switch", "I2S0"}, + {"UL4_CH2", "I2S0_CH2 Switch", "I2S0"}, + + {"UL5", NULL, "UL5_IN_MUX"}, + {"UL5_IN_MUX", "UL5_IN_FROM_Normal", "UL5_2CH"}, + {"UL5_IN_MUX", "UL5_IN_FROM_CM1", "HW_CM1"}, + {"UL5_2CH", NULL, "UL5_CH1"}, + {"UL5_2CH", NULL, "UL5_CH2"}, + {"UL5_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"UL5_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, + {"HW_CM1", NULL, "CM1_EN"}, + {"HW_CM1", NULL, "HW_CM1_CH1"}, + {"HW_CM1", NULL, "HW_CM1_CH2"}, + {"HW_CM1", NULL, "HW_CM1_CH3"}, + {"HW_CM1", NULL, "HW_CM1_CH4"}, + {"HW_CM1", NULL, "HW_CM1_CH5"}, + {"HW_CM1", NULL, "HW_CM1_CH6"}, + {"HW_CM1", NULL, "HW_CM1_CH7"}, + {"HW_CM1", NULL, "HW_CM1_CH8"}, + {"HW_CM1", NULL, "HW_CM1_CH9"}, + {"HW_CM1", NULL, "HW_CM1_CH10"}, + {"HW_CM1", NULL, "HW_CM1_CH11"}, + {"HW_CM1", NULL, "HW_CM1_CH12"}, + {"HW_CM1_CH1", "TDM_IN_CH1 Switch", "TDM IN"}, + {"HW_CM1_CH2", "TDM_IN_CH2 Switch", "TDM IN"}, + {"HW_CM1_CH3", "TDM_IN_CH3 Switch", "TDM IN"}, + {"HW_CM1_CH4", "TDM_IN_CH4 Switch", "TDM IN"}, + {"HW_CM1_CH5", "TDM_IN_CH5 Switch", "TDM IN"}, + {"HW_CM1_CH6", "TDM_IN_CH6 Switch", "TDM IN"}, + {"HW_CM1_CH7", "TDM_IN_CH7 Switch", "TDM IN"}, + {"HW_CM1_CH8", "TDM_IN_CH8 Switch", "TDM IN"}, + {"HW_CM1_CH9", "DL1_CH1 Switch", "Hostless_UL5 UL"}, + {"HW_CM1_CH10", "DL1_CH2 Switch", "Hostless_UL5 UL"}, + + {"HW_CM1_CH3", "DL1_CH1 Switch", "Hostless_UL5 UL"}, + {"HW_CM1_CH4", "DL1_CH2 Switch", "Hostless_UL5 UL"}, + + {"HW_CM1_CH3", "DL3_CH1 Switch", "Hostless_UL5 UL"}, + {"HW_CM1_CH4", "DL3_CH2 Switch", "Hostless_UL5 UL"}, + + {"HW_CM1_CH5", "HW_SRC1_OUT_CH1 Switch", "HW_SRC_1_Out"}, + {"HW_CM1_CH6", "HW_SRC1_OUT_CH2 Switch", "HW_SRC_1_Out"}, + + {"HW_CM1_CH9", "DL12_CH1 Switch", "Hostless_UL5 UL"}, + {"HW_CM1_CH10", "DL12_CH2 Switch", "Hostless_UL5 UL"}, + {"HW_CM1_CH11", "DL12_CH3 Switch", "Hostless_UL5 UL"}, + {"HW_CM1_CH12", "DL12_CH4 Switch", "Hostless_UL5 UL"}, + + {"Hostless_UL5 UL", NULL, "UL5_VIRTUAL_INPUT"}, + + {"UL6", NULL, "UL6_CH1"}, + {"UL6", NULL, "UL6_CH2"}, + + {"UL6_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"UL6_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, + {"UL6_CH1", "DL1_CH1 Switch", "Hostless_UL6 UL"}, + {"UL6_CH2", "DL1_CH2 Switch", "Hostless_UL6 UL"}, + {"UL6_CH1", "DL2_CH1 Switch", "Hostless_UL6 UL"}, + {"UL6_CH2", "DL2_CH2 Switch", "Hostless_UL6 UL"}, + {"UL6_CH1", "DL12_CH1 Switch", "Hostless_UL6 UL"}, + {"UL6_CH2", "DL12_CH2 Switch", "Hostless_UL6 UL"}, + {"UL6_CH1", "DL6_CH1 Switch", "Hostless_UL6 UL"}, + {"UL6_CH2", "DL6_CH2 Switch", "Hostless_UL6 UL"}, + {"UL6_CH1", "DL3_CH1 Switch", "Hostless_UL6 UL"}, + {"UL6_CH2", "DL3_CH2 Switch", "Hostless_UL6 UL"}, + {"UL6_CH1", "DL4_CH1 Switch", "Hostless_UL6 UL"}, + {"UL6_CH2", "DL4_CH2 Switch", "Hostless_UL6 UL"}, + {"Hostless_UL6 UL", NULL, "UL6_VIRTUAL_INPUT"}, + {"UL6_CH1", "PCM_1_CAP_CH1 Switch", "PCM 1 Capture"}, + {"UL6_CH2", "PCM_1_CAP_CH2 Switch", "PCM 1 Capture"}, + {"UL6_CH1", "GAIN1_OUT_CH1 Switch", "HW Gain 1 Out"}, + {"UL6_CH2", "GAIN1_OUT_CH2 Switch", "HW Gain 1 Out"}, + + {"UL7", NULL, "UL7_CH1"}, + {"UL7", NULL, "UL7_CH2"}, + {"UL7_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"UL7_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, + {"UL7_CH1", "HW_GAIN2_OUT_CH1 Switch", "HW Gain 2 Out"}, + {"UL7_CH2", "HW_GAIN2_OUT_CH2 Switch", "HW Gain 2 Out"}, + {"UL7_CH1", "HW_SRC_2_OUT_CH1 Switch", "HW_SRC_2_Out"}, + {"UL7_CH2", "HW_SRC_2_OUT_CH2 Switch", "HW_SRC_2_Out"}, + + {"UL8", NULL, "UL8_CH1"}, + {"UL8", NULL, "UL8_CH2"}, + {"UL8_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"UL8_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, + + {"HW_GAIN2_IN_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"}, + {"HW_GAIN2_IN_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"}, +}; + +static const struct mtk_base_memif_data memif_data[MT8186_MEMIF_NUM] = { + [MT8186_MEMIF_DL1] = { + .name = "DL1", + .id = MT8186_MEMIF_DL1, + .reg_ofs_base = AFE_DL1_BASE, + .reg_ofs_cur = AFE_DL1_CUR, + .reg_ofs_end = AFE_DL1_END, + .reg_ofs_base_msb = AFE_DL1_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL1_CUR_MSB, + .reg_ofs_end_msb = AFE_DL1_END_MSB, + .fs_reg = AFE_DL1_CON0, + .fs_shift = DL1_MODE_SFT, + .fs_maskbit = DL1_MODE_MASK, + .mono_reg = AFE_DL1_CON0, + .mono_shift = DL1_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL1_ON_SFT, + .hd_reg = AFE_DL1_CON0, + .hd_shift = DL1_HD_MODE_SFT, + .hd_align_reg = AFE_DL1_CON0, + .hd_align_mshift = DL1_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL1_CON0, + .pbuf_mask = DL1_PBUF_SIZE_MASK, + .pbuf_shift = DL1_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL1_CON0, + .minlen_mask = DL1_MINLEN_MASK, + .minlen_shift = DL1_MINLEN_SFT, + }, + [MT8186_MEMIF_DL12] = { + .name = "DL12", + .id = MT8186_MEMIF_DL12, + .reg_ofs_base = AFE_DL12_BASE, + .reg_ofs_cur = AFE_DL12_CUR, + .reg_ofs_end = AFE_DL12_END, + .reg_ofs_base_msb = AFE_DL12_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL12_CUR_MSB, + .reg_ofs_end_msb = AFE_DL12_END_MSB, + .fs_reg = AFE_DL12_CON0, + .fs_shift = DL12_MODE_SFT, + .fs_maskbit = DL12_MODE_MASK, + .mono_reg = AFE_DL12_CON0, + .mono_shift = DL12_MONO_SFT, + .quad_ch_reg = AFE_DL12_CON0, + .quad_ch_mask = DL12_4CH_EN_MASK, + .quad_ch_shift = DL12_4CH_EN_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL12_ON_SFT, + .hd_reg = AFE_DL12_CON0, + .hd_shift = DL12_HD_MODE_SFT, + .hd_align_reg = AFE_DL12_CON0, + .hd_align_mshift = DL12_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL12_CON0, + .pbuf_mask = DL12_PBUF_SIZE_MASK, + .pbuf_shift = DL12_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL12_CON0, + .minlen_mask = DL12_MINLEN_MASK, + .minlen_shift = DL12_MINLEN_SFT, + }, + [MT8186_MEMIF_DL2] = { + .name = "DL2", + .id = MT8186_MEMIF_DL2, + .reg_ofs_base = AFE_DL2_BASE, + .reg_ofs_cur = AFE_DL2_CUR, + .reg_ofs_end = AFE_DL2_END, + .reg_ofs_base_msb = AFE_DL2_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL2_CUR_MSB, + .reg_ofs_end_msb = AFE_DL2_END_MSB, + .fs_reg = AFE_DL2_CON0, + .fs_shift = DL2_MODE_SFT, + .fs_maskbit = DL2_MODE_MASK, + .mono_reg = AFE_DL2_CON0, + .mono_shift = DL2_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL2_ON_SFT, + .hd_reg = AFE_DL2_CON0, + .hd_shift = DL2_HD_MODE_SFT, + .hd_align_reg = AFE_DL2_CON0, + .hd_align_mshift = DL2_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL2_CON0, + .pbuf_mask = DL2_PBUF_SIZE_MASK, + .pbuf_shift = DL2_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL2_CON0, + .minlen_mask = DL2_MINLEN_MASK, + .minlen_shift = DL2_MINLEN_SFT, + }, + [MT8186_MEMIF_DL3] = { + .name = "DL3", + .id = MT8186_MEMIF_DL3, + .reg_ofs_base = AFE_DL3_BASE, + .reg_ofs_cur = AFE_DL3_CUR, + .reg_ofs_end = AFE_DL3_END, + .reg_ofs_base_msb = AFE_DL3_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL3_CUR_MSB, + .reg_ofs_end_msb = AFE_DL3_END_MSB, + .fs_reg = AFE_DL3_CON0, + .fs_shift = DL3_MODE_SFT, + .fs_maskbit = DL3_MODE_MASK, + .mono_reg = AFE_DL3_CON0, + .mono_shift = DL3_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL3_ON_SFT, + .hd_reg = AFE_DL3_CON0, + .hd_shift = DL3_HD_MODE_SFT, + .hd_align_reg = AFE_DL3_CON0, + .hd_align_mshift = DL3_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL3_CON0, + .pbuf_mask = DL3_PBUF_SIZE_MASK, + .pbuf_shift = DL3_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL3_CON0, + .minlen_mask = DL3_MINLEN_MASK, + .minlen_shift = DL3_MINLEN_SFT, + }, + [MT8186_MEMIF_DL4] = { + .name = "DL4", + .id = MT8186_MEMIF_DL4, + .reg_ofs_base = AFE_DL4_BASE, + .reg_ofs_cur = AFE_DL4_CUR, + .reg_ofs_end = AFE_DL4_END, + .reg_ofs_base_msb = AFE_DL4_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL4_CUR_MSB, + .reg_ofs_end_msb = AFE_DL4_END_MSB, + .fs_reg = AFE_DL4_CON0, + .fs_shift = DL4_MODE_SFT, + .fs_maskbit = DL4_MODE_MASK, + .mono_reg = AFE_DL4_CON0, + .mono_shift = DL4_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL4_ON_SFT, + .hd_reg = AFE_DL4_CON0, + .hd_shift = DL4_HD_MODE_SFT, + .hd_align_reg = AFE_DL4_CON0, + .hd_align_mshift = DL4_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL4_CON0, + .pbuf_mask = DL4_PBUF_SIZE_MASK, + .pbuf_shift = DL4_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL4_CON0, + .minlen_mask = DL4_MINLEN_MASK, + .minlen_shift = DL4_MINLEN_SFT, + }, + [MT8186_MEMIF_DL5] = { + .name = "DL5", + .id = MT8186_MEMIF_DL5, + .reg_ofs_base = AFE_DL5_BASE, + .reg_ofs_cur = AFE_DL5_CUR, + .reg_ofs_end = AFE_DL5_END, + .reg_ofs_base_msb = AFE_DL5_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL5_CUR_MSB, + .reg_ofs_end_msb = AFE_DL5_END_MSB, + .fs_reg = AFE_DL5_CON0, + .fs_shift = DL5_MODE_SFT, + .fs_maskbit = DL5_MODE_MASK, + .mono_reg = AFE_DL5_CON0, + .mono_shift = DL5_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL5_ON_SFT, + .hd_reg = AFE_DL5_CON0, + .hd_shift = DL5_HD_MODE_SFT, + .hd_align_reg = AFE_DL5_CON0, + .hd_align_mshift = DL5_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL5_CON0, + .pbuf_mask = DL5_PBUF_SIZE_MASK, + .pbuf_shift = DL5_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL5_CON0, + .minlen_mask = DL5_MINLEN_MASK, + .minlen_shift = DL5_MINLEN_SFT, + }, + [MT8186_MEMIF_DL6] = { + .name = "DL6", + .id = MT8186_MEMIF_DL6, + .reg_ofs_base = AFE_DL6_BASE, + .reg_ofs_cur = AFE_DL6_CUR, + .reg_ofs_end = AFE_DL6_END, + .reg_ofs_base_msb = AFE_DL6_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL6_CUR_MSB, + .reg_ofs_end_msb = AFE_DL6_END_MSB, + .fs_reg = AFE_DL6_CON0, + .fs_shift = DL6_MODE_SFT, + .fs_maskbit = DL6_MODE_MASK, + .mono_reg = AFE_DL6_CON0, + .mono_shift = DL6_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL6_ON_SFT, + .hd_reg = AFE_DL6_CON0, + .hd_shift = DL6_HD_MODE_SFT, + .hd_align_reg = AFE_DL6_CON0, + .hd_align_mshift = DL6_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL6_CON0, + .pbuf_mask = DL6_PBUF_SIZE_MASK, + .pbuf_shift = DL6_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL6_CON0, + .minlen_mask = DL6_MINLEN_MASK, + .minlen_shift = DL6_MINLEN_SFT, + }, + [MT8186_MEMIF_DL7] = { + .name = "DL7", + .id = MT8186_MEMIF_DL7, + .reg_ofs_base = AFE_DL7_BASE, + .reg_ofs_cur = AFE_DL7_CUR, + .reg_ofs_end = AFE_DL7_END, + .reg_ofs_base_msb = AFE_DL7_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL7_CUR_MSB, + .reg_ofs_end_msb = AFE_DL7_END_MSB, + .fs_reg = AFE_DL7_CON0, + .fs_shift = DL7_MODE_SFT, + .fs_maskbit = DL7_MODE_MASK, + .mono_reg = AFE_DL7_CON0, + .mono_shift = DL7_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL7_ON_SFT, + .hd_reg = AFE_DL7_CON0, + .hd_shift = DL7_HD_MODE_SFT, + .hd_align_reg = AFE_DL7_CON0, + .hd_align_mshift = DL7_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL7_CON0, + .pbuf_mask = DL7_PBUF_SIZE_MASK, + .pbuf_shift = DL7_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL7_CON0, + .minlen_mask = DL7_MINLEN_MASK, + .minlen_shift = DL7_MINLEN_SFT, + }, + [MT8186_MEMIF_DL8] = { + .name = "DL8", + .id = MT8186_MEMIF_DL8, + .reg_ofs_base = AFE_DL8_BASE, + .reg_ofs_cur = AFE_DL8_CUR, + .reg_ofs_end = AFE_DL8_END, + .reg_ofs_base_msb = AFE_DL8_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL8_CUR_MSB, + .reg_ofs_end_msb = AFE_DL8_END_MSB, + .fs_reg = AFE_DL8_CON0, + .fs_shift = DL8_MODE_SFT, + .fs_maskbit = DL8_MODE_MASK, + .mono_reg = AFE_DL8_CON0, + .mono_shift = DL8_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL8_ON_SFT, + .hd_reg = AFE_DL8_CON0, + .hd_shift = DL8_HD_MODE_SFT, + .hd_align_reg = AFE_DL8_CON0, + .hd_align_mshift = DL8_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL8_CON0, + .pbuf_mask = DL8_PBUF_SIZE_MASK, + .pbuf_shift = DL8_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL8_CON0, + .minlen_mask = DL8_MINLEN_MASK, + .minlen_shift = DL8_MINLEN_SFT, + }, + [MT8186_MEMIF_VUL12] = { + .name = "VUL12", + .id = MT8186_MEMIF_VUL12, + .reg_ofs_base = AFE_VUL12_BASE, + .reg_ofs_cur = AFE_VUL12_CUR, + .reg_ofs_end = AFE_VUL12_END, + .reg_ofs_base_msb = AFE_VUL12_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL12_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL12_END_MSB, + .fs_reg = AFE_VUL12_CON0, + .fs_shift = VUL12_MODE_SFT, + .fs_maskbit = VUL12_MODE_MASK, + .mono_reg = AFE_VUL12_CON0, + .mono_shift = VUL12_MONO_SFT, + .quad_ch_reg = AFE_VUL12_CON0, + .quad_ch_mask = VUL12_4CH_EN_MASK, + .quad_ch_shift = VUL12_4CH_EN_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL12_ON_SFT, + .hd_reg = AFE_VUL12_CON0, + .hd_shift = VUL12_HD_MODE_SFT, + .hd_align_reg = AFE_VUL12_CON0, + .hd_align_mshift = VUL12_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8186_MEMIF_VUL2] = { + .name = "VUL2", + .id = MT8186_MEMIF_VUL2, + .reg_ofs_base = AFE_VUL2_BASE, + .reg_ofs_cur = AFE_VUL2_CUR, + .reg_ofs_end = AFE_VUL2_END, + .reg_ofs_base_msb = AFE_VUL2_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL2_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL2_END_MSB, + .fs_reg = AFE_VUL2_CON0, + .fs_shift = VUL2_MODE_SFT, + .fs_maskbit = VUL2_MODE_MASK, + .mono_reg = AFE_VUL2_CON0, + .mono_shift = VUL2_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL2_ON_SFT, + .hd_reg = AFE_VUL2_CON0, + .hd_shift = VUL2_HD_MODE_SFT, + .hd_align_reg = AFE_VUL2_CON0, + .hd_align_mshift = VUL2_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8186_MEMIF_AWB] = { + .name = "AWB", + .id = MT8186_MEMIF_AWB, + .reg_ofs_base = AFE_AWB_BASE, + .reg_ofs_cur = AFE_AWB_CUR, + .reg_ofs_end = AFE_AWB_END, + .reg_ofs_base_msb = AFE_AWB_BASE_MSB, + .reg_ofs_cur_msb = AFE_AWB_CUR_MSB, + .reg_ofs_end_msb = AFE_AWB_END_MSB, + .fs_reg = AFE_AWB_CON0, + .fs_shift = AWB_MODE_SFT, + .fs_maskbit = AWB_MODE_MASK, + .mono_reg = AFE_AWB_CON0, + .mono_shift = AWB_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = AWB_ON_SFT, + .hd_reg = AFE_AWB_CON0, + .hd_shift = AWB_HD_MODE_SFT, + .hd_align_reg = AFE_AWB_CON0, + .hd_align_mshift = AWB_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8186_MEMIF_AWB2] = { + .name = "AWB2", + .id = MT8186_MEMIF_AWB2, + .reg_ofs_base = AFE_AWB2_BASE, + .reg_ofs_cur = AFE_AWB2_CUR, + .reg_ofs_end = AFE_AWB2_END, + .reg_ofs_base_msb = AFE_AWB2_BASE_MSB, + .reg_ofs_cur_msb = AFE_AWB2_CUR_MSB, + .reg_ofs_end_msb = AFE_AWB2_END_MSB, + .fs_reg = AFE_AWB2_CON0, + .fs_shift = AWB2_MODE_SFT, + .fs_maskbit = AWB2_MODE_MASK, + .mono_reg = AFE_AWB2_CON0, + .mono_shift = AWB2_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = AWB2_ON_SFT, + .hd_reg = AFE_AWB2_CON0, + .hd_shift = AWB2_HD_MODE_SFT, + .hd_align_reg = AFE_AWB2_CON0, + .hd_align_mshift = AWB2_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8186_MEMIF_VUL3] = { + .name = "VUL3", + .id = MT8186_MEMIF_VUL3, + .reg_ofs_base = AFE_VUL3_BASE, + .reg_ofs_cur = AFE_VUL3_CUR, + .reg_ofs_end = AFE_VUL3_END, + .reg_ofs_base_msb = AFE_VUL3_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL3_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL3_END_MSB, + .fs_reg = AFE_VUL3_CON0, + .fs_shift = VUL3_MODE_SFT, + .fs_maskbit = VUL3_MODE_MASK, + .mono_reg = AFE_VUL3_CON0, + .mono_shift = VUL3_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL3_ON_SFT, + .hd_reg = AFE_VUL3_CON0, + .hd_shift = VUL3_HD_MODE_SFT, + .hd_align_reg = AFE_VUL3_CON0, + .hd_align_mshift = VUL3_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8186_MEMIF_VUL4] = { + .name = "VUL4", + .id = MT8186_MEMIF_VUL4, + .reg_ofs_base = AFE_VUL4_BASE, + .reg_ofs_cur = AFE_VUL4_CUR, + .reg_ofs_end = AFE_VUL4_END, + .reg_ofs_base_msb = AFE_VUL4_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL4_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL4_END_MSB, + .fs_reg = AFE_VUL4_CON0, + .fs_shift = VUL4_MODE_SFT, + .fs_maskbit = VUL4_MODE_MASK, + .mono_reg = AFE_VUL4_CON0, + .mono_shift = VUL4_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL4_ON_SFT, + .hd_reg = AFE_VUL4_CON0, + .hd_shift = VUL4_HD_MODE_SFT, + .hd_align_reg = AFE_VUL4_CON0, + .hd_align_mshift = VUL4_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8186_MEMIF_VUL5] = { + .name = "VUL5", + .id = MT8186_MEMIF_VUL5, + .reg_ofs_base = AFE_VUL5_BASE, + .reg_ofs_cur = AFE_VUL5_CUR, + .reg_ofs_end = AFE_VUL5_END, + .reg_ofs_base_msb = AFE_VUL5_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL5_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL5_END_MSB, + .fs_reg = AFE_VUL5_CON0, + .fs_shift = VUL5_MODE_SFT, + .fs_maskbit = VUL5_MODE_MASK, + .mono_reg = AFE_VUL5_CON0, + .mono_shift = VUL5_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL5_ON_SFT, + .hd_reg = AFE_VUL5_CON0, + .hd_shift = VUL5_HD_MODE_SFT, + .hd_align_reg = AFE_VUL5_CON0, + .hd_align_mshift = VUL5_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8186_MEMIF_VUL6] = { + .name = "VUL6", + .id = MT8186_MEMIF_VUL6, + .reg_ofs_base = AFE_VUL6_BASE, + .reg_ofs_cur = AFE_VUL6_CUR, + .reg_ofs_end = AFE_VUL6_END, + .reg_ofs_base_msb = AFE_VUL6_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL6_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL6_END_MSB, + .fs_reg = AFE_VUL6_CON0, + .fs_shift = VUL6_MODE_SFT, + .fs_maskbit = VUL6_MODE_MASK, + .mono_reg = AFE_VUL6_CON0, + .mono_shift = VUL6_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL6_ON_SFT, + .hd_reg = AFE_VUL6_CON0, + .hd_shift = VUL6_HD_MODE_SFT, + .hd_align_reg = AFE_VUL6_CON0, + .hd_align_mshift = VUL6_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, +}; + +static const struct mtk_base_irq_data irq_data[MT8186_IRQ_NUM] = { + [MT8186_IRQ_0] = { + .id = MT8186_IRQ_0, + .irq_cnt_reg = AFE_IRQ_MCU_CNT0, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ0_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ0_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ0_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ0_MCU_CLR_SFT, + }, + [MT8186_IRQ_1] = { + .id = MT8186_IRQ_1, + .irq_cnt_reg = AFE_IRQ_MCU_CNT1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ1_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ1_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ1_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ1_MCU_CLR_SFT, + }, + [MT8186_IRQ_2] = { + .id = MT8186_IRQ_2, + .irq_cnt_reg = AFE_IRQ_MCU_CNT2, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ2_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ2_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ2_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ2_MCU_CLR_SFT, + }, + [MT8186_IRQ_3] = { + .id = MT8186_IRQ_3, + .irq_cnt_reg = AFE_IRQ_MCU_CNT3, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ3_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ3_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ3_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ3_MCU_CLR_SFT, + }, + [MT8186_IRQ_4] = { + .id = MT8186_IRQ_4, + .irq_cnt_reg = AFE_IRQ_MCU_CNT4, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ4_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ4_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ4_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ4_MCU_CLR_SFT, + }, + [MT8186_IRQ_5] = { + .id = MT8186_IRQ_5, + .irq_cnt_reg = AFE_IRQ_MCU_CNT5, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ5_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ5_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ5_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ5_MCU_CLR_SFT, + }, + [MT8186_IRQ_6] = { + .id = MT8186_IRQ_6, + .irq_cnt_reg = AFE_IRQ_MCU_CNT6, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ6_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ6_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ6_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ6_MCU_CLR_SFT, + }, + [MT8186_IRQ_7] = { + .id = MT8186_IRQ_7, + .irq_cnt_reg = AFE_IRQ_MCU_CNT7, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ7_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ7_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ7_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ7_MCU_CLR_SFT, + }, + [MT8186_IRQ_8] = { + .id = MT8186_IRQ_8, + .irq_cnt_reg = AFE_IRQ_MCU_CNT8, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ8_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ8_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ8_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ8_MCU_CLR_SFT, + }, + [MT8186_IRQ_9] = { + .id = MT8186_IRQ_9, + .irq_cnt_reg = AFE_IRQ_MCU_CNT9, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ9_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ9_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ9_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ9_MCU_CLR_SFT, + }, + [MT8186_IRQ_10] = { + .id = MT8186_IRQ_10, + .irq_cnt_reg = AFE_IRQ_MCU_CNT10, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ10_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ10_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ10_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ10_MCU_CLR_SFT, + }, + [MT8186_IRQ_11] = { + .id = MT8186_IRQ_11, + .irq_cnt_reg = AFE_IRQ_MCU_CNT11, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ11_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ11_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ11_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ11_MCU_CLR_SFT, + }, + [MT8186_IRQ_12] = { + .id = MT8186_IRQ_12, + .irq_cnt_reg = AFE_IRQ_MCU_CNT12, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ12_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ12_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ12_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ12_MCU_CLR_SFT, + }, + [MT8186_IRQ_13] = { + .id = MT8186_IRQ_13, + .irq_cnt_reg = AFE_IRQ_MCU_CNT13, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ13_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ13_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ13_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ13_MCU_CLR_SFT, + }, + [MT8186_IRQ_14] = { + .id = MT8186_IRQ_14, + .irq_cnt_reg = AFE_IRQ_MCU_CNT14, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ14_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ14_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ14_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ14_MCU_CLR_SFT, + }, + [MT8186_IRQ_15] = { + .id = MT8186_IRQ_15, + .irq_cnt_reg = AFE_IRQ_MCU_CNT15, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ15_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ15_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ15_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ15_MCU_CLR_SFT, + }, + [MT8186_IRQ_16] = { + .id = MT8186_IRQ_16, + .irq_cnt_reg = AFE_IRQ_MCU_CNT16, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ16_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ16_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ16_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ16_MCU_CLR_SFT, + }, + [MT8186_IRQ_17] = { + .id = MT8186_IRQ_17, + .irq_cnt_reg = AFE_IRQ_MCU_CNT17, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ17_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ17_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ17_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ17_MCU_CLR_SFT, + }, + [MT8186_IRQ_18] = { + .id = MT8186_IRQ_18, + .irq_cnt_reg = AFE_IRQ_MCU_CNT18, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ18_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ18_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ18_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ18_MCU_CLR_SFT, + }, + [MT8186_IRQ_19] = { + .id = MT8186_IRQ_19, + .irq_cnt_reg = AFE_IRQ_MCU_CNT19, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ19_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ19_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ19_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ19_MCU_CLR_SFT, + }, + [MT8186_IRQ_20] = { + .id = MT8186_IRQ_20, + .irq_cnt_reg = AFE_IRQ_MCU_CNT20, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ20_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ20_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ20_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ20_MCU_CLR_SFT, + }, + [MT8186_IRQ_21] = { + .id = MT8186_IRQ_21, + .irq_cnt_reg = AFE_IRQ_MCU_CNT21, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ21_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ21_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ21_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ21_MCU_CLR_SFT, + }, + [MT8186_IRQ_22] = { + .id = MT8186_IRQ_22, + .irq_cnt_reg = AFE_IRQ_MCU_CNT22, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ22_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ22_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ22_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ22_MCU_CLR_SFT, + }, + [MT8186_IRQ_23] = { + .id = MT8186_IRQ_23, + .irq_cnt_reg = AFE_IRQ_MCU_CNT23, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ23_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ23_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ23_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ23_MCU_CLR_SFT, + }, + [MT8186_IRQ_24] = { + .id = MT8186_IRQ_24, + .irq_cnt_reg = AFE_IRQ_MCU_CNT24, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON4, + .irq_fs_shift = IRQ24_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ24_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ24_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ24_MCU_CLR_SFT, + }, + [MT8186_IRQ_25] = { + .id = MT8186_IRQ_25, + .irq_cnt_reg = AFE_IRQ_MCU_CNT25, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON4, + .irq_fs_shift = IRQ25_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ25_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ25_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ25_MCU_CLR_SFT, + }, + [MT8186_IRQ_26] = { + .id = MT8186_IRQ_26, + .irq_cnt_reg = AFE_IRQ_MCU_CNT26, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON4, + .irq_fs_shift = IRQ26_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ26_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ26_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ26_MCU_CLR_SFT, + }, +}; + +static const int memif_irq_usage[MT8186_MEMIF_NUM] = { + /* TODO: verify each memif & irq */ + [MT8186_MEMIF_DL1] = MT8186_IRQ_0, + [MT8186_MEMIF_DL2] = MT8186_IRQ_1, + [MT8186_MEMIF_DL3] = MT8186_IRQ_2, + [MT8186_MEMIF_DL4] = MT8186_IRQ_3, + [MT8186_MEMIF_DL5] = MT8186_IRQ_4, + [MT8186_MEMIF_DL6] = MT8186_IRQ_5, + [MT8186_MEMIF_DL7] = MT8186_IRQ_6, + [MT8186_MEMIF_DL8] = MT8186_IRQ_7, + [MT8186_MEMIF_DL12] = MT8186_IRQ_9, + [MT8186_MEMIF_VUL12] = MT8186_IRQ_10, + [MT8186_MEMIF_VUL2] = MT8186_IRQ_11, + [MT8186_MEMIF_AWB] = MT8186_IRQ_12, + [MT8186_MEMIF_AWB2] = MT8186_IRQ_13, + [MT8186_MEMIF_VUL3] = MT8186_IRQ_14, + [MT8186_MEMIF_VUL4] = MT8186_IRQ_15, + [MT8186_MEMIF_VUL5] = MT8186_IRQ_16, + [MT8186_MEMIF_VUL6] = MT8186_IRQ_17, +}; + +static bool mt8186_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* these auto-gen reg has read-only bit, so put it as volatile */ + /* volatile reg cannot be cached, so cannot be set when power off */ + switch (reg) { + case AUDIO_TOP_CON0: /* reg bit controlled by CCF */ + case AUDIO_TOP_CON1: /* reg bit controlled by CCF */ + case AUDIO_TOP_CON2: + case AUDIO_TOP_CON3: + case AFE_DL1_CUR_MSB: + case AFE_DL1_CUR: + case AFE_DL1_END: + case AFE_DL2_CUR_MSB: + case AFE_DL2_CUR: + case AFE_DL2_END: + case AFE_DL3_CUR_MSB: + case AFE_DL3_CUR: + case AFE_DL3_END: + case AFE_DL4_CUR_MSB: + case AFE_DL4_CUR: + case AFE_DL4_END: + case AFE_DL12_CUR_MSB: + case AFE_DL12_CUR: + case AFE_DL12_END: + case AFE_ADDA_SRC_DEBUG_MON0: + case AFE_ADDA_SRC_DEBUG_MON1: + case AFE_ADDA_UL_SRC_MON0: + case AFE_ADDA_UL_SRC_MON1: + case AFE_SECURE_CON0: + case AFE_SRAM_BOUND: + case AFE_SECURE_CON1: + case AFE_VUL_CUR_MSB: + case AFE_VUL_CUR: + case AFE_VUL_END: + case AFE_SIDETONE_MON: + case AFE_SIDETONE_CON0: + case AFE_SIDETONE_COEFF: + case AFE_VUL2_CUR_MSB: + case AFE_VUL2_CUR: + case AFE_VUL2_END: + case AFE_VUL3_CUR_MSB: + case AFE_VUL3_CUR: + case AFE_VUL3_END: + case AFE_I2S_MON: + case AFE_DAC_MON: + case AFE_IRQ0_MCU_CNT_MON: + case AFE_IRQ6_MCU_CNT_MON: + case AFE_VUL4_CUR_MSB: + case AFE_VUL4_CUR: + case AFE_VUL4_END: + case AFE_VUL12_CUR_MSB: + case AFE_VUL12_CUR: + case AFE_VUL12_END: + case AFE_IRQ3_MCU_CNT_MON: + case AFE_IRQ4_MCU_CNT_MON: + case AFE_IRQ_MCU_STATUS: + case AFE_IRQ_MCU_CLR: + case AFE_IRQ_MCU_MON2: + case AFE_IRQ1_MCU_CNT_MON: + case AFE_IRQ2_MCU_CNT_MON: + case AFE_IRQ5_MCU_CNT_MON: + case AFE_IRQ7_MCU_CNT_MON: + case AFE_IRQ_MCU_MISS_CLR: + case AFE_GAIN1_CUR: + case AFE_GAIN2_CUR: + case AFE_SRAM_DELSEL_CON1: + case PCM_INTF_CON2: + case FPGA_CFG0: + case FPGA_CFG1: + case FPGA_CFG2: + case FPGA_CFG3: + case AUDIO_TOP_DBG_MON0: + case AUDIO_TOP_DBG_MON1: + case AFE_IRQ8_MCU_CNT_MON: + case AFE_IRQ11_MCU_CNT_MON: + case AFE_IRQ12_MCU_CNT_MON: + case AFE_IRQ9_MCU_CNT_MON: + case AFE_IRQ10_MCU_CNT_MON: + case AFE_IRQ13_MCU_CNT_MON: + case AFE_IRQ14_MCU_CNT_MON: + case AFE_IRQ15_MCU_CNT_MON: + case AFE_IRQ16_MCU_CNT_MON: + case AFE_IRQ17_MCU_CNT_MON: + case AFE_IRQ18_MCU_CNT_MON: + case AFE_IRQ19_MCU_CNT_MON: + case AFE_IRQ20_MCU_CNT_MON: + case AFE_IRQ21_MCU_CNT_MON: + case AFE_IRQ22_MCU_CNT_MON: + case AFE_IRQ23_MCU_CNT_MON: + case AFE_IRQ24_MCU_CNT_MON: + case AFE_IRQ25_MCU_CNT_MON: + case AFE_IRQ26_MCU_CNT_MON: + case AFE_IRQ31_MCU_CNT_MON: + case AFE_CBIP_MON0: + case AFE_CBIP_SLV_MUX_MON0: + case AFE_CBIP_SLV_DECODER_MON0: + case AFE_ADDA6_MTKAIF_MON0: + case AFE_ADDA6_MTKAIF_MON1: + case AFE_AWB_CUR_MSB: + case AFE_AWB_CUR: + case AFE_AWB_END: + case AFE_AWB2_CUR_MSB: + case AFE_AWB2_CUR: + case AFE_AWB2_END: + case AFE_DAI_CUR_MSB: + case AFE_DAI_CUR: + case AFE_DAI_END: + case AFE_DAI2_CUR_MSB: + case AFE_DAI2_CUR: + case AFE_DAI2_END: + case AFE_ADDA6_SRC_DEBUG_MON0: + case AFE_ADD6A_UL_SRC_MON0: + case AFE_ADDA6_UL_SRC_MON1: + case AFE_MOD_DAI_CUR_MSB: + case AFE_MOD_DAI_CUR: + case AFE_MOD_DAI_END: + case AFE_AWB_RCH_MON: + case AFE_AWB_LCH_MON: + case AFE_VUL_RCH_MON: + case AFE_VUL_LCH_MON: + case AFE_VUL12_RCH_MON: + case AFE_VUL12_LCH_MON: + case AFE_VUL2_RCH_MON: + case AFE_VUL2_LCH_MON: + case AFE_DAI_DATA_MON: + case AFE_MOD_DAI_DATA_MON: + case AFE_DAI2_DATA_MON: + case AFE_AWB2_RCH_MON: + case AFE_AWB2_LCH_MON: + case AFE_VUL3_RCH_MON: + case AFE_VUL3_LCH_MON: + case AFE_VUL4_RCH_MON: + case AFE_VUL4_LCH_MON: + case AFE_VUL5_RCH_MON: + case AFE_VUL5_LCH_MON: + case AFE_VUL6_RCH_MON: + case AFE_VUL6_LCH_MON: + case AFE_DL1_RCH_MON: + case AFE_DL1_LCH_MON: + case AFE_DL2_RCH_MON: + case AFE_DL2_LCH_MON: + case AFE_DL12_RCH1_MON: + case AFE_DL12_LCH1_MON: + case AFE_DL12_RCH2_MON: + case AFE_DL12_LCH2_MON: + case AFE_DL3_RCH_MON: + case AFE_DL3_LCH_MON: + case AFE_DL4_RCH_MON: + case AFE_DL4_LCH_MON: + case AFE_DL5_RCH_MON: + case AFE_DL5_LCH_MON: + case AFE_DL6_RCH_MON: + case AFE_DL6_LCH_MON: + case AFE_DL7_RCH_MON: + case AFE_DL7_LCH_MON: + case AFE_DL8_RCH_MON: + case AFE_DL8_LCH_MON: + case AFE_VUL5_CUR_MSB: + case AFE_VUL5_CUR: + case AFE_VUL5_END: + case AFE_VUL6_CUR_MSB: + case AFE_VUL6_CUR: + case AFE_VUL6_END: + case AFE_ADDA_DL_SDM_FIFO_MON: + case AFE_ADDA_DL_SRC_LCH_MON: + case AFE_ADDA_DL_SRC_RCH_MON: + case AFE_ADDA_DL_SDM_OUT_MON: + case AFE_CONNSYS_I2S_MON: + case AFE_ASRC_2CH_CON0: + case AFE_ASRC_2CH_CON2: + case AFE_ASRC_2CH_CON3: + case AFE_ASRC_2CH_CON4: + case AFE_ASRC_2CH_CON5: + case AFE_ASRC_2CH_CON7: + case AFE_ASRC_2CH_CON8: + case AFE_ASRC_2CH_CON12: + case AFE_ASRC_2CH_CON13: + case AFE_ADDA_MTKAIF_MON0: + case AFE_ADDA_MTKAIF_MON1: + case AFE_AUD_PAD_TOP: + case AFE_DL_NLE_R_MON0: + case AFE_DL_NLE_R_MON1: + case AFE_DL_NLE_R_MON2: + case AFE_DL_NLE_L_MON0: + case AFE_DL_NLE_L_MON1: + case AFE_DL_NLE_L_MON2: + case AFE_GENERAL1_ASRC_2CH_CON0: + case AFE_GENERAL1_ASRC_2CH_CON2: + case AFE_GENERAL1_ASRC_2CH_CON3: + case AFE_GENERAL1_ASRC_2CH_CON4: + case AFE_GENERAL1_ASRC_2CH_CON5: + case AFE_GENERAL1_ASRC_2CH_CON7: + case AFE_GENERAL1_ASRC_2CH_CON8: + case AFE_GENERAL1_ASRC_2CH_CON12: + case AFE_GENERAL1_ASRC_2CH_CON13: + case AFE_GENERAL2_ASRC_2CH_CON0: + case AFE_GENERAL2_ASRC_2CH_CON2: + case AFE_GENERAL2_ASRC_2CH_CON3: + case AFE_GENERAL2_ASRC_2CH_CON4: + case AFE_GENERAL2_ASRC_2CH_CON5: + case AFE_GENERAL2_ASRC_2CH_CON7: + case AFE_GENERAL2_ASRC_2CH_CON8: + case AFE_GENERAL2_ASRC_2CH_CON12: + case AFE_GENERAL2_ASRC_2CH_CON13: + case AFE_DL5_CUR_MSB: + case AFE_DL5_CUR: + case AFE_DL5_END: + case AFE_DL6_CUR_MSB: + case AFE_DL6_CUR: + case AFE_DL6_END: + case AFE_DL7_CUR_MSB: + case AFE_DL7_CUR: + case AFE_DL7_END: + case AFE_DL8_CUR_MSB: + case AFE_DL8_CUR: + case AFE_DL8_END: + case AFE_PROT_SIDEBAND_MON: + case AFE_DOMAIN_SIDEBAND0_MON: + case AFE_DOMAIN_SIDEBAND1_MON: + case AFE_DOMAIN_SIDEBAND2_MON: + case AFE_DOMAIN_SIDEBAND3_MON: + case AFE_APLL1_TUNER_CFG: /* [20:31] is monitor */ + case AFE_APLL2_TUNER_CFG: /* [20:31] is monitor */ + return true; + default: + return false; + }; +} + +static const struct regmap_config mt8186_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .volatile_reg = mt8186_is_volatile_reg, + + .max_register = AFE_MAX_REGISTER, + .num_reg_defaults_raw = AFE_MAX_REGISTER, + + .cache_type = REGCACHE_FLAT, +}; + +static irqreturn_t mt8186_afe_irq_handler(int irq_id, void *dev) +{ + struct mtk_base_afe *afe = dev; + struct mtk_base_afe_irq *irq; + unsigned int status; + unsigned int status_mcu; + unsigned int mcu_en; + int ret; + int i; + + /* get irq that is sent to MCU */ + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en); + if (ret) { + dev_err(afe->dev, "%s, get irq direction fail, ret %d", __func__, ret); + return ret; + } + + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status); + /* only care IRQ which is sent to MCU */ + status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS; + + if (ret || status_mcu == 0) { + dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n", + __func__, ret, status, mcu_en); + + goto err_irq; + } + + for (i = 0; i < MT8186_MEMIF_NUM; i++) { + struct mtk_base_afe_memif *memif = &afe->memif[i]; + + if (!memif->substream) + continue; + + if (memif->irq_usage < 0) + continue; + + irq = &afe->irqs[memif->irq_usage]; + + if (status_mcu & (1 << irq->irq_data->irq_en_shift)) + snd_pcm_period_elapsed(memif->substream); + } + +err_irq: + /* clear irq */ + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu); + + return IRQ_HANDLED; +} + +static int mt8186_afe_runtime_suspend(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + unsigned int value = 0; + int ret; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + /* disable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x0); + + ret = regmap_read_poll_timeout(afe->regmap, + AFE_DAC_MON, + value, + (value & AFE_ON_RETM_MASK_SFT) == 0, + 20, + 1 * 1000 * 1000); + if (ret) { + dev_err(afe->dev, "%s(), ret %d\n", __func__, ret); + return ret; + } + + /* make sure all irq status are cleared */ + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff); + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff); + + /* reset sgen */ + regmap_write(afe->regmap, AFE_SINEGEN_CON0, 0x0); + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2, + INNER_LOOP_BACK_MODE_MASK_SFT, + 0x3f << INNER_LOOP_BACK_MODE_SFT); + + /* cache only */ + regcache_cache_only(afe->regmap, true); + regcache_mark_dirty(afe->regmap); + +skip_regmap: + mt8186_afe_disable_cgs(afe); + mt8186_afe_disable_clock(afe); + + return 0; +} + +static int mt8186_afe_runtime_resume(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = mt8186_afe_enable_clock(afe); + if (ret) + return ret; + + ret = mt8186_afe_enable_cgs(afe); + if (ret) + return ret; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + regcache_cache_only(afe->regmap, false); + regcache_sync(afe->regmap); + + /* enable audio sys DCM for power saving */ + regmap_update_bits(afe_priv->infracfg, PERI_BUS_DCM_CTRL, BIT(29), BIT(29)); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, BIT(29), BIT(29)); + + /* force cpu use 8_24 format when writing 32bit data */ + regmap_update_bits(afe->regmap, AFE_MEMIF_CON0, CPU_HD_ALIGN_MASK_SFT, 0); + + /* set all output port to 24bit */ + regmap_write(afe->regmap, AFE_CONN_24BIT, 0xffffffff); + regmap_write(afe->regmap, AFE_CONN_24BIT_1, 0xffffffff); + + /* enable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, AUDIO_AFE_ON_MASK_SFT, BIT(0)); + +skip_regmap: + return 0; +} + +static int mt8186_afe_component_probe(struct snd_soc_component *component) +{ + mtk_afe_add_sub_dai_control(component); + mt8186_add_misc_control(component); + + return 0; +} + +static const struct snd_soc_component_driver mt8186_afe_component = { + .name = AFE_PCM_NAME, + .pcm_construct = mtk_afe_pcm_new, + .pointer = mtk_afe_pcm_pointer, + .probe = mt8186_afe_component_probe, +}; + +static int mt8186_dai_memif_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mt8186_memif_dai_driver; + dai->num_dai_drivers = ARRAY_SIZE(mt8186_memif_dai_driver); + + dai->controls = mt8186_pcm_kcontrols; + dai->num_controls = ARRAY_SIZE(mt8186_pcm_kcontrols); + dai->dapm_widgets = mt8186_memif_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mt8186_memif_widgets); + dai->dapm_routes = mt8186_memif_routes; + dai->num_dapm_routes = ARRAY_SIZE(mt8186_memif_routes); + return 0; +} + +typedef int (*dai_register_cb)(struct mtk_base_afe *); +static const dai_register_cb dai_register_cbs[] = { + mt8186_dai_adda_register, + mt8186_dai_i2s_register, + mt8186_dai_tdm_register, + mt8186_dai_hw_gain_register, + mt8186_dai_src_register, + mt8186_dai_pcm_register, + mt8186_dai_hostless_register, + mt8186_dai_memif_register, +}; + +static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev) +{ + struct mtk_base_afe *afe; + struct mt8186_afe_private *afe_priv; + struct resource *res; + struct reset_control *rstc; + struct device *dev = &pdev->dev; + int i, ret, irq_id; + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); + if (ret) + return ret; + + afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + platform_set_drvdata(pdev, afe); + + afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv), GFP_KERNEL); + if (!afe->platform_priv) + return -ENOMEM; + + afe_priv = afe->platform_priv; + afe->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + afe->base_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(afe->base_addr)) + return PTR_ERR(afe->base_addr); + + /* init audio related clock */ + ret = mt8186_init_clock(afe); + if (ret) { + dev_err(dev, "init clock error, ret %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(dev, mt8186_deinit_clock, (void *)afe); + if (ret) + return ret; + + /* init memif */ + afe->memif_32bit_supported = 0; + afe->memif_size = MT8186_MEMIF_NUM; + afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), GFP_KERNEL); + if (!afe->memif) + return -ENOMEM; + + for (i = 0; i < afe->memif_size; i++) { + afe->memif[i].data = &memif_data[i]; + afe->memif[i].irq_usage = memif_irq_usage[i]; + afe->memif[i].const_irq = 1; + } + + mutex_init(&afe->irq_alloc_lock); /* needed when dynamic irq */ + + /* init irq */ + afe->irqs_size = MT8186_IRQ_NUM; + afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), + GFP_KERNEL); + + if (!afe->irqs) + return -ENOMEM; + + for (i = 0; i < afe->irqs_size; i++) + afe->irqs[i].irq_data = &irq_data[i]; + + /* request irq */ + irq_id = platform_get_irq(pdev, 0); + if (irq_id <= 0) + return dev_err_probe(dev, irq_id < 0 ? irq_id : -ENXIO, + "no irq found"); + + ret = devm_request_irq(dev, irq_id, mt8186_afe_irq_handler, + IRQF_TRIGGER_NONE, + "Afe_ISR_Handle", (void *)afe); + if (ret) + return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n"); + + ret = enable_irq_wake(irq_id); + if (ret < 0) + return dev_err_probe(dev, ret, "enable_irq_wake %d\n", irq_id); + + /* init sub_dais */ + INIT_LIST_HEAD(&afe->sub_dais); + + for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { + ret = dai_register_cbs[i](afe); + if (ret) + return dev_err_probe(dev, ret, "dai register i %d fail\n", i); + } + + /* init dai_driver and component_driver */ + ret = mtk_afe_combine_sub_dai(afe); + if (ret) + return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n"); + + /* reset controller to reset audio regs before regmap cache */ + rstc = devm_reset_control_get_exclusive(dev, "audiosys"); + if (IS_ERR(rstc)) + return dev_err_probe(dev, PTR_ERR(rstc), "could not get audiosys reset\n"); + + ret = reset_control_reset(rstc); + if (ret) + return dev_err_probe(dev, ret, "failed to trigger audio reset\n"); + + /* enable clock for regcache get default value from hw */ + afe_priv->pm_runtime_bypass_reg_ctl = true; + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return dev_err_probe(dev, ret, "failed to resume device\n"); + + afe->regmap = devm_regmap_init_mmio(dev, afe->base_addr, + &mt8186_afe_regmap_config); + if (IS_ERR(afe->regmap)) { + ret = PTR_ERR(afe->regmap); + goto err_pm_disable; + } + + /* others */ + afe->mtk_afe_hardware = &mt8186_afe_hardware; + afe->memif_fs = mt8186_memif_fs; + afe->irq_fs = mt8186_irq_fs; + afe->get_dai_fs = mt8186_get_dai_fs; + afe->get_memif_pbuf_size = mt8186_get_memif_pbuf_size; + + afe->runtime_resume = mt8186_afe_runtime_resume; + afe->runtime_suspend = mt8186_afe_runtime_suspend; + + /* register platform */ + dev_dbg(dev, "%s(), devm_snd_soc_register_component\n", __func__); + + ret = devm_snd_soc_register_component(dev, + &mt8186_afe_component, + afe->dai_drivers, + afe->num_dai_drivers); + if (ret) { + dev_err(dev, "err_dai_component\n"); + goto err_pm_disable; + } + + ret = pm_runtime_put_sync(dev); + if (ret) { + pm_runtime_get_noresume(dev); + dev_err(dev, "failed to suspend device: %d\n", ret); + goto err_pm_disable; + } + afe_priv->pm_runtime_bypass_reg_ctl = false; + + regcache_cache_only(afe->regmap, true); + regcache_mark_dirty(afe->regmap); + + return 0; + +err_pm_disable: + pm_runtime_put_noidle(dev); + pm_runtime_set_suspended(dev); + + return ret; +} + +static const struct of_device_id mt8186_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt8186-sound", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt8186_afe_pcm_dt_match); + +static const struct dev_pm_ops mt8186_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt8186_afe_runtime_suspend, + mt8186_afe_runtime_resume, NULL) +}; + +static struct platform_driver mt8186_afe_pcm_driver = { + .driver = { + .name = "mt8186-audio", + .of_match_table = mt8186_afe_pcm_dt_match, + .pm = &mt8186_afe_pm_ops, + }, + .probe = mt8186_afe_pcm_dev_probe, +}; + +module_platform_driver(mt8186_afe_pcm_driver); + +MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8186"); +MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c index 6be6d4f3b585..266704556f37 100644 --- a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c +++ b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c @@ -75,8 +75,7 @@ static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe, struct mt8186_afe_private *afe_priv = afe->platform_priv; int dai_id; - if (strncmp(name, "aud_dac_hires_clk", 7) == 0 || - strncmp(name, "aud_adc_hires_clk", 7) == 0) + if (strncmp(name, "aud_dac", 7) == 0 || strncmp(name, "aud_adc", 7) == 0) dai_id = MT8186_DAI_ADDA; else return NULL; @@ -655,11 +654,6 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", __func__, id, substream->stream, rate); - if (!adda_priv) { - dev_err(afe->dev, "%s(), adda_priv == NULL", __func__); - return -EINVAL; - } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { unsigned int dl_src2_con0; unsigned int dl_src2_con1; diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c index 5c1290b950e8..ec79e2f2a54d 100644 --- a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c +++ b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c @@ -119,12 +119,6 @@ static int mt8186_i2s_hd_get(struct snd_kcontrol *kcontrol, struct mtk_afe_i2s_priv *i2s_priv; i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); - - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return -EINVAL; - } - ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en; return 0; @@ -148,12 +142,6 @@ static int mt8186_i2s_hd_set(struct snd_kcontrol *kcontrol, __func__, kcontrol->id.name, hd_en); i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); - - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return -EINVAL; - } - if (i2s_priv->low_jitter_en == hd_en) return 0; @@ -377,11 +365,6 @@ static int mtk_i2s_en_event(struct snd_soc_dapm_widget *w, i2s_priv = get_i2s_priv_by_name(afe, w->name); - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return -EINVAL; - } - dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", __func__, w->name, event); @@ -442,11 +425,6 @@ static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w, i2s_priv = get_i2s_priv_by_name(afe, w->name); - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return -EINVAL; - } - switch (event) { case SND_SOC_DAPM_PRE_PMU: mt8186_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate); @@ -566,12 +544,6 @@ static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source, struct mtk_afe_i2s_priv *i2s_priv; i2s_priv = get_i2s_priv_by_name(afe, sink->name); - - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return 0; - } - if (i2s_priv->share_i2s_id < 0) return 0; @@ -587,12 +559,6 @@ static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source, struct mtk_afe_i2s_priv *i2s_priv; i2s_priv = get_i2s_priv_by_name(afe, sink->name); - - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return 0; - } - if (get_i2s_id_by_name(afe, sink->name) == get_i2s_id_by_name(afe, source->name)) return i2s_priv->low_jitter_en; @@ -618,15 +584,8 @@ static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source, int i2s_need_apll; i2s_priv = get_i2s_priv_by_name(afe, w->name); - - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return 0; - } - /* which apll */ cur_apll = mt8186_get_apll_by_name(afe, source->name); - /* choose APLL from i2s rate */ i2s_need_apll = mt8186_get_apll_by_rate(afe, i2s_priv->rate); @@ -642,12 +601,6 @@ static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source, struct mtk_afe_i2s_priv *i2s_priv; i2s_priv = get_i2s_priv_by_name(afe, sink->name); - - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return 0; - } - if (get_i2s_id_by_name(afe, sink->name) == get_i2s_id_by_name(afe, source->name)) return (i2s_priv->mclk_rate > 0) ? 1 : 0; @@ -672,12 +625,6 @@ static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source, int cur_apll; i2s_priv = get_i2s_priv_by_name(afe, w->name); - - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return 0; - } - /* which apll */ cur_apll = mt8186_get_apll_by_name(afe, source->name); @@ -980,11 +927,6 @@ static int mtk_dai_i2s_config(struct mtk_base_afe *afe, dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n", __func__, i2s_id, rate, format); - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return -EINVAL; - } - i2s_priv->rate = rate; switch (i2s_id) { @@ -1053,11 +995,6 @@ static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai, int apll; int apll_rate; - if (!i2s_priv) { - dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); - return -EINVAL; - } - if (dir != SND_SOC_CLOCK_OUT) { dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); return -EINVAL; diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c b/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c index 0b0032ecfe6d..41221a66111c 100644 --- a/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c +++ b/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c @@ -287,11 +287,6 @@ static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct mt8186_afe_private *afe_priv = afe->platform_priv; struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[dai->id]; - if (!pcm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return -EINVAL; - } - /* DAI mode*/ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c b/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c index c6ead7c252f0..4148dceb3a4c 100644 --- a/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c +++ b/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c @@ -106,11 +106,6 @@ static int mtk_tdm_en_event(struct snd_soc_dapm_widget *w, int dai_id = get_tdm_id_by_name(w->name); struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return -EINVAL; - } - dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", __func__, w->name, event); @@ -138,11 +133,6 @@ static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w, int dai_id = get_tdm_id_by_name(w->name); struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return -EINVAL; - } - dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n", __func__, w->name, event, dai_id); @@ -215,11 +205,6 @@ static int mtk_afe_tdm_mclk_connect(struct snd_soc_dapm_widget *source, int dai_id = get_tdm_id_by_name(w->name); struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return 0; - } - return (tdm_priv->mclk_rate > 0) ? 1 : 0; } @@ -250,11 +235,6 @@ static int mtk_afe_tdm_hd_connect(struct snd_soc_dapm_widget *source, int dai_id = get_tdm_id_by_name(w->name); struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return 0; - } - return tdm_priv->low_jitter_en; } @@ -270,11 +250,6 @@ static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source, int cur_apll; int tdm_need_apll; - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return 0; - } - /* which apll */ cur_apll = mt8186_get_apll_by_name(afe, source->name); @@ -303,11 +278,6 @@ static int mt8186_tdm_hd_get(struct snd_kcontrol *kcontrol, int dai_id = get_tdm_id_by_name(kcontrol->id.name); struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return -EINVAL; - } - ucontrol->value.integer.value[0] = tdm_priv->low_jitter_en; return 0; @@ -332,11 +302,6 @@ static int mt8186_tdm_hd_set(struct snd_kcontrol *kcontrol, dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n", __func__, kcontrol->id.name, hd_en); - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return -EINVAL; - } - if (tdm_priv->low_jitter_en == hd_en) return 0; @@ -421,22 +386,14 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, unsigned int tran_rate; unsigned int tran_relatch_rate; - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return -EINVAL; - } - tdm_priv->rate = rate; - tran_rate = mt8186_rate_transform(afe->dev, rate, dai->id); tran_relatch_rate = mt8186_tdm_relatch_rate_transform(afe->dev, rate); /* calculate mclk_rate, if not set explicitly */ if (!tdm_priv->mclk_rate) { tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple; - mtk_dai_tdm_cal_mclk(afe, - tdm_priv, - tdm_priv->mclk_rate); + mtk_dai_tdm_cal_mclk(afe, tdm_priv, tdm_priv->mclk_rate); } /* ETDM_IN1_CON0 */ @@ -508,11 +465,6 @@ static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, struct mt8186_afe_private *afe_priv = afe->platform_priv; struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return -EINVAL; - } - if (dir != SND_SOC_CLOCK_IN) { dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); return -EINVAL; @@ -529,11 +481,6 @@ static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct mt8186_afe_private *afe_priv = afe->platform_priv; struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; - if (!tdm_priv) { - dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); - return -EINVAL; - } - /* DAI mode*/ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c new file mode 100644 index 000000000000..4e66603d4cdb --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-mt6366-common.c +// -- MT8186 MT6366 ALSA common driver +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> +// +#include <sound/soc.h> + +#include "../../codecs/mt6358.h" +#include "../common/mtk-afe-platform-driver.h" +#include "mt8186-afe-common.h" +#include "mt8186-mt6366-common.h" + +int mt8186_mt6366_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *cmpnt_afe = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct snd_soc_dapm_context *dapm = &rtd->card->dapm; + int ret; + + /* set mtkaif protocol */ + mt6358_set_mtkaif_protocol(cmpnt_codec, + MT6358_MTKAIF_PROTOCOL_1); + afe_priv->mtkaif_protocol = MT6358_MTKAIF_PROTOCOL_1; + + ret = snd_soc_dapm_sync(dapm); + if (ret) { + dev_err(rtd->dev, "failed to snd_soc_dapm_sync\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt8186_mt6366_init); + +int mt8186_mt6366_card_set_be_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link, + struct device_node *node, + char *link_name) +{ + int ret; + + if (node && strcmp(link->name, link_name) == 0) { + ret = snd_soc_of_get_dai_link_codecs(card->dev, node, link); + if (ret < 0) + return dev_err_probe(card->dev, ret, "get dai link codecs fail\n"); + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt8186_mt6366_card_set_be_link); diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-common.h b/sound/soc/mediatek/mt8186/mt8186-mt6366-common.h new file mode 100644 index 000000000000..907d8f5e46b1 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-common.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8186-mt6366-common.h + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + */ + +#ifndef _MT8186_MT6366_COMMON_H_ +#define _MT8186_MT6366_COMMON_H_ + +int mt8186_mt6366_init(struct snd_soc_pcm_runtime *rtd); +int mt8186_mt6366_card_set_be_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link, + struct device_node *node, + char *link_name); +#endif diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c new file mode 100644 index 000000000000..387f25cad809 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -0,0 +1,1002 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-mt6366-da7219-max98357.c +// -- MT8186-MT6366-DA7219-MAX98357 ALSA SoC machine driver +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> +// + +#include <linux/input.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "../../codecs/da7219-aad.h" +#include "../../codecs/da7219.h" +#include "../../codecs/mt6358.h" +#include "../common/mtk-afe-platform-driver.h" +#include "mt8186-afe-common.h" +#include "mt8186-afe-clk.h" +#include "mt8186-afe-gpio.h" +#include "mt8186-mt6366-common.h" + +#define DA7219_CODEC_DAI "da7219-hifi" +#define DA7219_DEV_NAME "da7219.5-001a" + +struct mt8186_mt6366_da7219_max98357_priv { + struct snd_soc_jack headset_jack, hdmi_jack; +}; + +static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF("mt6358-sound"), + .name_prefix = "Mt6366", + }, + { + .dlc = COMP_CODEC_CONF("bt-sco"), + .name_prefix = "Mt8186 bt", + }, + { + .dlc = COMP_CODEC_CONF("hdmi-audio-codec"), + .name_prefix = "Mt8186 hdmi", + }, +}; + +static int mt8186_da7219_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mt8186_mt6366_da7219_max98357_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_jack *jack = &priv->headset_jack; + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + int ret; + + /* Enable Headset and 4 Buttons Jack detection */ + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_LINEOUT, + jack); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + da7219_aad_jack_det(cmpnt_codec, &priv->headset_jack); + + return 0; +} + +static int mt8186_da7219_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + unsigned int rate = params_rate(params); + unsigned int mclk_fs_ratio = 256; + unsigned int mclk_fs = rate * mclk_fs_ratio; + unsigned int freq; + int ret, j; + + ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, + mclk_fs, SND_SOC_CLOCK_OUT); + if (ret < 0) { + dev_err(rtd->dev, "failed to set cpu dai sysclk: %d\n", ret); + return ret; + } + + for_each_rtd_codec_dais(rtd, j, codec_dai) { + if (!strcmp(codec_dai->component->name, DA7219_DEV_NAME)) { + ret = snd_soc_dai_set_sysclk(codec_dai, + DA7219_CLKSRC_MCLK, + mclk_fs, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "failed to set sysclk: %d\n", + ret); + return ret; + } + + if ((rate % 8000) == 0) + freq = DA7219_PLL_FREQ_OUT_98304; + else + freq = DA7219_PLL_FREQ_OUT_90316; + + ret = snd_soc_dai_set_pll(codec_dai, 0, + DA7219_SYSCLK_PLL_SRM, + 0, freq); + if (ret) { + dev_err(rtd->dev, "failed to start PLL: %d\n", + ret); + return ret; + } + } + } + + return 0; +} + +static int mt8186_da7219_i2s_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + int ret = 0, j; + + for_each_rtd_codec_dais(rtd, j, codec_dai) { + if (!strcmp(codec_dai->component->name, DA7219_DEV_NAME)) { + ret = snd_soc_dai_set_pll(codec_dai, + 0, DA7219_SYSCLK_MCLK, 0, 0); + if (ret < 0) { + dev_err(rtd->dev, "failed to stop PLL: %d\n", + ret); + return ret; + } + } + } + + return 0; +} + +static const struct snd_soc_ops mt8186_da7219_i2s_ops = { + .hw_params = mt8186_da7219_i2s_hw_params, + .hw_free = mt8186_da7219_i2s_hw_free, +}; + +static int mt8186_mt6366_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + struct mt8186_mt6366_da7219_max98357_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + int ret; + + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack); + if (ret) { + dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret); + return ret; + } + + return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL); +} + +static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params, + snd_pcm_format_t fmt) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + dev_dbg(rtd->dev, "%s(), fix format to %d\n", __func__, fmt); + + /* fix BE i2s channel to 2 channel */ + channels->min = 2; + channels->max = 2; + + /* clean param mask first */ + snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), + 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); + + params_set_format(params, fmt); + + return 0; +} + +static int mt8186_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S32_LE); +} + +static int mt8186_anx7625_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE); +} + +static int mt8186_mt6366_da7219_max98357_playback_startup(struct snd_pcm_substream *substream) +{ + static const unsigned int rates[] = { + 48000 + }; + static const unsigned int channels[] = { + 2 + }; + static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, + }; + static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, + }; + + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list rate failed\n"); + return ret; + } + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list channel failed\n"); + return ret; + } + + return 0; +} + +static const struct snd_soc_ops mt8186_mt6366_da7219_max98357_playback_ops = { + .startup = mt8186_mt6366_da7219_max98357_playback_startup, +}; + +static int mt8186_mt6366_da7219_max98357_capture_startup(struct snd_pcm_substream *substream) +{ + static const unsigned int rates[] = { + 48000 + }; + static const unsigned int channels[] = { + 1, 2 + }; + static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, + }; + static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, + }; + + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list rate failed\n"); + return ret; + } + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list channel failed\n"); + return ret; + } + + return 0; +} + +static const struct snd_soc_ops mt8186_mt6366_da7219_max98357_capture_ops = { + .startup = mt8186_mt6366_da7219_max98357_capture_startup, +}; + +/* FE */ +SND_SOC_DAILINK_DEFS(playback1, + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback12, + DAILINK_COMP_ARRAY(COMP_CPU("DL12")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback2, + DAILINK_COMP_ARRAY(COMP_CPU("DL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback3, + DAILINK_COMP_ARRAY(COMP_CPU("DL3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback4, + DAILINK_COMP_ARRAY(COMP_CPU("DL4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback5, + DAILINK_COMP_ARRAY(COMP_CPU("DL5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback6, + DAILINK_COMP_ARRAY(COMP_CPU("DL6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback7, + DAILINK_COMP_ARRAY(COMP_CPU("DL7")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback8, + DAILINK_COMP_ARRAY(COMP_CPU("DL8")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture1, + DAILINK_COMP_ARRAY(COMP_CPU("UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture2, + DAILINK_COMP_ARRAY(COMP_CPU("UL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture3, + DAILINK_COMP_ARRAY(COMP_CPU("UL3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture4, + DAILINK_COMP_ARRAY(COMP_CPU("UL4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture5, + DAILINK_COMP_ARRAY(COMP_CPU("UL5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture6, + DAILINK_COMP_ARRAY(COMP_CPU("UL6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture7, + DAILINK_COMP_ARRAY(COMP_CPU("UL7")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* hostless */ +SND_SOC_DAILINK_DEFS(hostless_lpbk, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless LPBK DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_fm, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless FM DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_src1, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_1_DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_src_bargein, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_Bargein_DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* BE */ +SND_SOC_DAILINK_DEFS(adda, + DAILINK_COMP_ARRAY(COMP_CPU("ADDA")), + DAILINK_COMP_ARRAY(COMP_CODEC("mt6358-sound", + "mt6358-snd-codec-aif1"), + COMP_CODEC("dmic-codec", + "dmic-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s0, + DAILINK_COMP_ARRAY(COMP_CPU("I2S0")), + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s1, + DAILINK_COMP_ARRAY(COMP_CPU("I2S1")), + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s2, + DAILINK_COMP_ARRAY(COMP_CPU("I2S2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s3, + DAILINK_COMP_ARRAY(COMP_CPU("I2S3")), + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_gain1, + DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_gain2, + DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_src1, + DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_src2, + DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(connsys_i2s, + DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(pcm1, + DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")), + DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm-wb")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(tdm_in, + DAILINK_COMP_ARRAY(COMP_CPU("TDM IN")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* hostless */ +SND_SOC_DAILINK_DEFS(hostless_ul1, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL1 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul2, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL2 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul3, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL3 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul5, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL5 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul6, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL6 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_hw_gain_aaudio, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless HW Gain AAudio DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_src_aaudio, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless SRC AAudio DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +static struct snd_soc_dai_link mt8186_mt6366_da7219_max98357_dai_links[] = { + /* Front End DAI links */ + { + .name = "Playback_1", + .stream_name = "Playback_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .ops = &mt8186_mt6366_da7219_max98357_playback_ops, + SND_SOC_DAILINK_REG(playback1), + }, + { + .name = "Playback_12", + .stream_name = "Playback_12", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback12), + }, + { + .name = "Playback_2", + .stream_name = "Playback_2", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(playback2), + }, + { + .name = "Playback_3", + .stream_name = "Playback_3", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .ops = &mt8186_mt6366_da7219_max98357_playback_ops, + SND_SOC_DAILINK_REG(playback3), + }, + { + .name = "Playback_4", + .stream_name = "Playback_4", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback4), + }, + { + .name = "Playback_5", + .stream_name = "Playback_5", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback5), + }, + { + .name = "Playback_6", + .stream_name = "Playback_6", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback6), + }, + { + .name = "Playback_7", + .stream_name = "Playback_7", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback7), + }, + { + .name = "Playback_8", + .stream_name = "Playback_8", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback8), + }, + { + .name = "Capture_1", + .stream_name = "Capture_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture1), + }, + { + .name = "Capture_2", + .stream_name = "Capture_2", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .ops = &mt8186_mt6366_da7219_max98357_capture_ops, + SND_SOC_DAILINK_REG(capture2), + }, + { + .name = "Capture_3", + .stream_name = "Capture_3", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture3), + }, + { + .name = "Capture_4", + .stream_name = "Capture_4", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .ops = &mt8186_mt6366_da7219_max98357_capture_ops, + SND_SOC_DAILINK_REG(capture4), + }, + { + .name = "Capture_5", + .stream_name = "Capture_5", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture5), + }, + { + .name = "Capture_6", + .stream_name = "Capture_6", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(capture6), + }, + { + .name = "Capture_7", + .stream_name = "Capture_7", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture7), + }, + { + .name = "Hostless_LPBK", + .stream_name = "Hostless_LPBK", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_lpbk), + }, + { + .name = "Hostless_FM", + .stream_name = "Hostless_FM", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_fm), + }, + { + .name = "Hostless_SRC_1", + .stream_name = "Hostless_SRC_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_src1), + }, + { + .name = "Hostless_SRC_Bargein", + .stream_name = "Hostless_SRC_Bargein", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_src_bargein), + }, + { + .name = "Hostless_HW_Gain_AAudio", + .stream_name = "Hostless_HW_Gain_AAudio", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio), + }, + { + .name = "Hostless_SRC_AAudio", + .stream_name = "Hostless_SRC_AAudio", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_src_aaudio), + }, + /* Back End DAI links */ + { + .name = "Primary Codec", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .init = mt8186_mt6366_init, + SND_SOC_DAILINK_REG(adda), + }, + { + .name = "I2S3", + .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_IB_IF | + SND_SOC_DAIFMT_CBM_CFM, + .dpcm_playback = 1, + .ignore_suspend = 1, + .init = mt8186_mt6366_da7219_max98357_hdmi_init, + .be_hw_params_fixup = mt8186_anx7625_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s3), + }, + { + .name = "I2S0", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, + .ops = &mt8186_da7219_i2s_ops, + SND_SOC_DAILINK_REG(i2s0), + }, + { + .name = "I2S1", + .no_pcm = 1, + .dpcm_playback = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, + .init = mt8186_da7219_init, + .ops = &mt8186_da7219_i2s_ops, + SND_SOC_DAILINK_REG(i2s1), + }, + { + .name = "I2S2", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s2), + }, + { + .name = "HW Gain 1", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_gain1), + }, + { + .name = "HW Gain 2", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_gain2), + }, + { + .name = "HW_SRC_1", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_src1), + }, + { + .name = "HW_SRC_2", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_src2), + }, + { + .name = "CONNSYS_I2S", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(connsys_i2s), + }, + { + .name = "PCM 1", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF, + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(pcm1), + }, + { + .name = "TDM IN", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tdm_in), + }, + /* dummy BE for ul memif to record from dl memif */ + { + .name = "Hostless_UL1", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul1), + }, + { + .name = "Hostless_UL2", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul2), + }, + { + .name = "Hostless_UL3", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul3), + }, + { + .name = "Hostless_UL5", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul5), + }, + { + .name = "Hostless_UL6", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul6), + }, +}; + +static const struct snd_soc_dapm_widget +mt8186_mt6366_da7219_max98357_widgets[] = { + SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_OUTPUT("HDMI1"), +}; + +static const struct snd_soc_dapm_route +mt8186_mt6366_da7219_max98357_routes[] = { + /* SPK */ + { "Speakers", NULL, "Speaker"}, + /* HDMI */ + { "HDMI1", NULL, "TX"}, +}; + +static const struct snd_kcontrol_new +mt8186_mt6366_da7219_max98357_controls[] = { + SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("HDMI1"), +}; + +static struct snd_soc_card mt8186_mt6366_da7219_max98357_soc_card = { + .name = "mt8186_mt6366_da7219_max98357", + .owner = THIS_MODULE, + .dai_link = mt8186_mt6366_da7219_max98357_dai_links, + .num_links = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_dai_links), + .controls = mt8186_mt6366_da7219_max98357_controls, + .num_controls = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_controls), + .dapm_widgets = mt8186_mt6366_da7219_max98357_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_widgets), + .dapm_routes = mt8186_mt6366_da7219_max98357_routes, + .num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_routes), + .codec_conf = mt8186_mt6366_da7219_max98357_codec_conf, + .num_configs = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_codec_conf), +}; + +static int mt8186_mt6366_da7219_max98357_dev_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct snd_soc_dai_link *dai_link; + struct mt8186_mt6366_da7219_max98357_priv *priv; + struct device_node *platform_node, *headset_codec, *playback_codec; + int ret, i; + + card = (struct snd_soc_card *)device_get_match_data(&pdev->dev); + if (!card) + return -EINVAL; + card->dev = &pdev->dev; + + platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); + if (!platform_node) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n"); + return ret; + } + + playback_codec = of_get_child_by_name(pdev->dev.of_node, "playback-codecs"); + if (!playback_codec) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'speaker-codecs' missing or invalid\n"); + goto err_playback_codec; + } + + headset_codec = of_get_child_by_name(pdev->dev.of_node, "headset-codec"); + if (!headset_codec) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'headset-codec' missing or invalid\n"); + goto err_headset_codec; + } + + for_each_card_prelinks(card, i, dai_link) { + ret = mt8186_mt6366_card_set_be_link(card, dai_link, playback_codec, "I2S3"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s set speaker_codec fail\n", + dai_link->name); + goto err_probe; + } + + ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S0"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n", + dai_link->name); + goto err_probe; + } + + ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S1"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n", + dai_link->name); + goto err_probe; + } + + if (!dai_link->platforms->name) + dai_link->platforms->of_node = platform_node; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto err_probe; + } + + snd_soc_card_set_drvdata(card, priv); + + ret = mt8186_afe_gpio_init(&pdev->dev); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__); + goto err_probe; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__); + +err_probe: + of_node_put(headset_codec); +err_headset_codec: + of_node_put(playback_codec); +err_playback_codec: + of_node_put(platform_node); + + return ret; +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id mt8186_mt6366_da7219_max98357_dt_match[] = { + { .compatible = "mediatek,mt8186-mt6366-da7219-max98357-sound", + .data = &mt8186_mt6366_da7219_max98357_soc_card, + }, + {} +}; +#endif + +static struct platform_driver mt8186_mt6366_da7219_max98357_driver = { + .driver = { + .name = "mt8186_mt6366_da7219_max98357", +#if IS_ENABLED(CONFIG_OF) + .of_match_table = mt8186_mt6366_da7219_max98357_dt_match, +#endif + .pm = &snd_soc_pm_ops, + }, + .probe = mt8186_mt6366_da7219_max98357_dev_probe, +}; + +module_platform_driver(mt8186_mt6366_da7219_max98357_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8186-MT6366-DA7219-MAX98357 ALSA SoC machine driver"); +MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("mt8186_mt6366_da7219_max98357 soc card"); diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c new file mode 100644 index 000000000000..891146fd6c2b --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c @@ -0,0 +1,978 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-mt6366-rt1019-rt5682s.c +// -- MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> +// + +#include <linux/input.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <sound/jack.h> +#include <sound/pcm_params.h> +#include <sound/rt5682.h> +#include <sound/soc.h> + +#include "../../codecs/mt6358.h" +#include "../../codecs/rt5682.h" +#include "../common/mtk-afe-platform-driver.h" +#include "mt8186-afe-common.h" +#include "mt8186-afe-clk.h" +#include "mt8186-afe-gpio.h" +#include "mt8186-mt6366-common.h" + +#define RT1019_CODEC_DAI "HiFi" +#define RT1019_DEV0_NAME "rt1019p" + +#define RT5682S_CODEC_DAI "rt5682s-aif1" +#define RT5682S_DEV0_NAME "rt5682s.5-001a" + +struct mt8186_mt6366_rt1019_rt5682s_priv { + struct snd_soc_jack headset_jack, hdmi_jack; +}; + +static struct snd_soc_codec_conf mt8186_mt6366_rt1019_rt5682s_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF("mt6358-sound"), + .name_prefix = "Mt6366", + }, + { + .dlc = COMP_CODEC_CONF("bt-sco"), + .name_prefix = "Mt8186 bt", + }, + { + .dlc = COMP_CODEC_CONF("hdmi-audio-codec"), + .name_prefix = "Mt8186 hdmi", + }, +}; + +static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mt8186_mt6366_rt1019_rt5682s_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_jack *jack = &priv->headset_jack; + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + int ret; + + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + return snd_soc_component_set_jack(cmpnt_codec, jack, NULL); +} + +static int mt8186_rt5682s_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + unsigned int rate = params_rate(params); + unsigned int mclk_fs_ratio = 128; + unsigned int mclk_fs = rate * mclk_fs_ratio; + int bitwidth; + int ret; + + bitwidth = snd_pcm_format_width(params_format(params)); + if (bitwidth < 0) { + dev_err(card->dev, "invalid bit width: %d\n", bitwidth); + return bitwidth; + } + + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth); + if (ret) { + dev_err(card->dev, "failed to set tdm slot\n"); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, + RT5682_PLL1_S_BCLK1, + params_rate(params) * 64, + params_rate(params) * 512); + if (ret) { + dev_err(card->dev, "failed to set pll\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT5682_SCLK_S_PLL1, + params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(card->dev, "failed to set sysclk\n"); + return ret; + } + + return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT); +} + +static const struct snd_soc_ops mt8186_rt5682s_i2s_ops = { + .hw_params = mt8186_rt5682s_i2s_hw_params, +}; + +static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + struct mt8186_mt6366_rt1019_rt5682s_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + int ret; + + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack); + if (ret) { + dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret); + return ret; + } + + return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL); +} + +static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params, + snd_pcm_format_t fmt) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + dev_dbg(rtd->dev, "%s(), fix format to %d\n", __func__, fmt); + + /* fix BE i2s channel to 2 channel */ + channels->min = 2; + channels->max = 2; + + /* clean param mask first */ + snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), + 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); + + params_set_format(params, fmt); + + return 0; +} + +static int mt8186_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE); +} + +static int mt8186_it6505_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S32_LE); +} + +static int mt8186_mt6366_rt1019_rt5682s_playback_startup(struct snd_pcm_substream *substream) +{ + static const unsigned int rates[] = { + 48000 + }; + static const unsigned int channels[] = { + 2 + }; + static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, + }; + static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, + }; + + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list rate failed\n"); + return ret; + } + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list channel failed\n"); + return ret; + } + + return 0; +} + +static const struct snd_soc_ops mt8186_mt6366_rt1019_rt5682s_playback_ops = { + .startup = mt8186_mt6366_rt1019_rt5682s_playback_startup, +}; + +static int mt8186_mt6366_rt1019_rt5682s_capture_startup(struct snd_pcm_substream *substream) +{ + static const unsigned int rates[] = { + 48000 + }; + static const unsigned int channels[] = { + 1, 2 + }; + static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, + }; + static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, + }; + + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list rate failed\n"); + return ret; + } + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list channel failed\n"); + return ret; + } + + return 0; +} + +static const struct snd_soc_ops mt8186_mt6366_rt1019_rt5682s_capture_ops = { + .startup = mt8186_mt6366_rt1019_rt5682s_capture_startup, +}; + +/* FE */ +SND_SOC_DAILINK_DEFS(playback1, + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback12, + DAILINK_COMP_ARRAY(COMP_CPU("DL12")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback2, + DAILINK_COMP_ARRAY(COMP_CPU("DL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback3, + DAILINK_COMP_ARRAY(COMP_CPU("DL3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback4, + DAILINK_COMP_ARRAY(COMP_CPU("DL4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback5, + DAILINK_COMP_ARRAY(COMP_CPU("DL5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback6, + DAILINK_COMP_ARRAY(COMP_CPU("DL6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback7, + DAILINK_COMP_ARRAY(COMP_CPU("DL7")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback8, + DAILINK_COMP_ARRAY(COMP_CPU("DL8")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture1, + DAILINK_COMP_ARRAY(COMP_CPU("UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture2, + DAILINK_COMP_ARRAY(COMP_CPU("UL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture3, + DAILINK_COMP_ARRAY(COMP_CPU("UL3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture4, + DAILINK_COMP_ARRAY(COMP_CPU("UL4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture5, + DAILINK_COMP_ARRAY(COMP_CPU("UL5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture6, + DAILINK_COMP_ARRAY(COMP_CPU("UL6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture7, + DAILINK_COMP_ARRAY(COMP_CPU("UL7")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* hostless */ +SND_SOC_DAILINK_DEFS(hostless_lpbk, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless LPBK DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_fm, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless FM DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_src1, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_1_DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_src_bargein, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_Bargein_DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* BE */ +SND_SOC_DAILINK_DEFS(adda, + DAILINK_COMP_ARRAY(COMP_CPU("ADDA")), + DAILINK_COMP_ARRAY(COMP_CODEC("mt6358-sound", + "mt6358-snd-codec-aif1"), + COMP_CODEC("dmic-codec", + "dmic-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s0, + DAILINK_COMP_ARRAY(COMP_CPU("I2S0")), + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s1, + DAILINK_COMP_ARRAY(COMP_CPU("I2S1")), + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s2, + DAILINK_COMP_ARRAY(COMP_CPU("I2S2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s3, + DAILINK_COMP_ARRAY(COMP_CPU("I2S3")), + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_gain1, + DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_gain2, + DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_src1, + DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_src2, + DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(connsys_i2s, + DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(pcm1, + DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")), + DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm-wb")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(tdm_in, + DAILINK_COMP_ARRAY(COMP_CPU("TDM IN")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* hostless */ +SND_SOC_DAILINK_DEFS(hostless_ul1, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL1 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul2, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL2 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul3, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL3 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul5, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL5 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul6, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL6 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_hw_gain_aaudio, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless HW Gain AAudio DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_src_aaudio, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless SRC AAudio DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { + /* Front End DAI links */ + { + .name = "Playback_1", + .stream_name = "Playback_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .ops = &mt8186_mt6366_rt1019_rt5682s_playback_ops, + SND_SOC_DAILINK_REG(playback1), + }, + { + .name = "Playback_12", + .stream_name = "Playback_12", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback12), + }, + { + .name = "Playback_2", + .stream_name = "Playback_2", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(playback2), + }, + { + .name = "Playback_3", + .stream_name = "Playback_3", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .ops = &mt8186_mt6366_rt1019_rt5682s_playback_ops, + SND_SOC_DAILINK_REG(playback3), + }, + { + .name = "Playback_4", + .stream_name = "Playback_4", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback4), + }, + { + .name = "Playback_5", + .stream_name = "Playback_5", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback5), + }, + { + .name = "Playback_6", + .stream_name = "Playback_6", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback6), + }, + { + .name = "Playback_7", + .stream_name = "Playback_7", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback7), + }, + { + .name = "Playback_8", + .stream_name = "Playback_8", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback8), + }, + { + .name = "Capture_1", + .stream_name = "Capture_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture1), + }, + { + .name = "Capture_2", + .stream_name = "Capture_2", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .ops = &mt8186_mt6366_rt1019_rt5682s_capture_ops, + SND_SOC_DAILINK_REG(capture2), + }, + { + .name = "Capture_3", + .stream_name = "Capture_3", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture3), + }, + { + .name = "Capture_4", + .stream_name = "Capture_4", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .ops = &mt8186_mt6366_rt1019_rt5682s_capture_ops, + SND_SOC_DAILINK_REG(capture4), + }, + { + .name = "Capture_5", + .stream_name = "Capture_5", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture5), + }, + { + .name = "Capture_6", + .stream_name = "Capture_6", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(capture6), + }, + { + .name = "Capture_7", + .stream_name = "Capture_7", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture7), + }, + { + .name = "Hostless_LPBK", + .stream_name = "Hostless_LPBK", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_lpbk), + }, + { + .name = "Hostless_FM", + .stream_name = "Hostless_FM", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_fm), + }, + { + .name = "Hostless_SRC_1", + .stream_name = "Hostless_SRC_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_src1), + }, + { + .name = "Hostless_SRC_Bargein", + .stream_name = "Hostless_SRC_Bargein", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_src_bargein), + }, + { + .name = "Hostless_HW_Gain_AAudio", + .stream_name = "Hostless_HW_Gain_AAudio", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio), + }, + { + .name = "Hostless_SRC_AAudio", + .stream_name = "Hostless_SRC_AAudio", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_src_aaudio), + }, + /* Back End DAI links */ + { + .name = "Primary Codec", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .init = mt8186_mt6366_init, + SND_SOC_DAILINK_REG(adda), + }, + { + .name = "I2S3", + .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_IB_IF | + SND_SOC_DAIFMT_CBM_CFM, + .dpcm_playback = 1, + .ignore_suspend = 1, + .init = mt8186_mt6366_rt1019_rt5682s_hdmi_init, + .be_hw_params_fixup = mt8186_it6505_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s3), + }, + { + .name = "I2S0", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, + .ops = &mt8186_rt5682s_i2s_ops, + SND_SOC_DAILINK_REG(i2s0), + }, + { + .name = "I2S1", + .no_pcm = 1, + .dpcm_playback = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, + .init = mt8186_rt5682s_init, + .ops = &mt8186_rt5682s_i2s_ops, + SND_SOC_DAILINK_REG(i2s1), + }, + { + .name = "I2S2", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s2), + }, + { + .name = "HW Gain 1", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_gain1), + }, + { + .name = "HW Gain 2", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_gain2), + }, + { + .name = "HW_SRC_1", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_src1), + }, + { + .name = "HW_SRC_2", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_src2), + }, + { + .name = "CONNSYS_I2S", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(connsys_i2s), + }, + { + .name = "PCM 1", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF, + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(pcm1), + }, + { + .name = "TDM IN", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tdm_in), + }, + /* dummy BE for ul memif to record from dl memif */ + { + .name = "Hostless_UL1", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul1), + }, + { + .name = "Hostless_UL2", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul2), + }, + { + .name = "Hostless_UL3", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul3), + }, + { + .name = "Hostless_UL5", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul5), + }, + { + .name = "Hostless_UL6", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul6), + }, +}; + +static const struct snd_soc_dapm_widget +mt8186_mt6366_rt1019_rt5682s_widgets[] = { + SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_OUTPUT("HDMI1"), +}; + +static const struct snd_soc_dapm_route +mt8186_mt6366_rt1019_rt5682s_routes[] = { + /* SPK */ + { "Speakers", NULL, "Speaker" }, + /* HDMI */ + { "HDMI1", NULL, "TX" }, +}; + +static const struct snd_kcontrol_new +mt8186_mt6366_rt1019_rt5682s_controls[] = { + SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("HDMI1"), +}; + +static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = { + .name = "mt8186_mt6366_rt1019_rt5682s", + .owner = THIS_MODULE, + .dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links, + .num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links), + .controls = mt8186_mt6366_rt1019_rt5682s_controls, + .num_controls = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_controls), + .dapm_widgets = mt8186_mt6366_rt1019_rt5682s_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_widgets), + .dapm_routes = mt8186_mt6366_rt1019_rt5682s_routes, + .num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_routes), + .codec_conf = mt8186_mt6366_rt1019_rt5682s_codec_conf, + .num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf), +}; + +static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct snd_soc_dai_link *dai_link; + struct mt8186_mt6366_rt1019_rt5682s_priv *priv; + struct device_node *platform_node, *headset_codec, *playback_codec; + int ret, i; + + card = (struct snd_soc_card *)device_get_match_data(&pdev->dev); + if (!card) + return -EINVAL; + card->dev = &pdev->dev; + + platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); + if (!platform_node) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n"); + return ret; + } + + playback_codec = of_get_child_by_name(pdev->dev.of_node, "playback-codecs"); + if (!playback_codec) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'speaker-codecs' missing or invalid\n"); + goto err_playback_codec; + } + + headset_codec = of_get_child_by_name(pdev->dev.of_node, "headset-codec"); + if (!headset_codec) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'headset-codec' missing or invalid\n"); + goto err_headset_codec; + } + + for_each_card_prelinks(card, i, dai_link) { + ret = mt8186_mt6366_card_set_be_link(card, dai_link, playback_codec, "I2S3"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s set speaker_codec fail\n", + dai_link->name); + goto err_probe; + } + + ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S0"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n", + dai_link->name); + goto err_probe; + } + + ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S1"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n", + dai_link->name); + goto err_probe; + } + + if (!dai_link->platforms->name) + dai_link->platforms->of_node = platform_node; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto err_probe; + } + + snd_soc_card_set_drvdata(card, priv); + + ret = mt8186_afe_gpio_init(&pdev->dev); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__); + goto err_probe; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__); + +err_probe: + of_node_put(headset_codec); +err_headset_codec: + of_node_put(playback_codec); +err_playback_codec: + of_node_put(platform_node); + + return ret; +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = { + { .compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound", + .data = &mt8186_mt6366_rt1019_rt5682s_soc_card, + }, + {} +}; +#endif + +static struct platform_driver mt8186_mt6366_rt1019_rt5682s_driver = { + .driver = { + .name = "mt8186_mt6366_rt1019_rt5682s", +#if IS_ENABLED(CONFIG_OF) + .of_match_table = mt8186_mt6366_rt1019_rt5682s_dt_match, +#endif + .pm = &snd_soc_pm_ops, + }, + .probe = mt8186_mt6366_rt1019_rt5682s_dev_probe, +}; + +module_platform_driver(mt8186_mt6366_rt1019_rt5682s_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver"); +MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("mt8186_mt6366_rt1019_rt5682s soc card"); diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index 54a00b0699b1..c530e3fc27e4 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -20,6 +20,8 @@ #include "../../codecs/rt1011.h" #include "../../codecs/rt5682.h" #include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-dsp-sof-common.h" +#include "../common/mtk-soc-card.h" #include "mt8195-afe-clk.h" #include "mt8195-afe-common.h" @@ -54,13 +56,6 @@ struct mt8195_card_data { unsigned long quirk; }; -struct sof_conn_stream { - const char *normal_link; - const char *sof_link; - const char *sof_dma; - int stream_dir; -}; - struct mt8195_mt6359_priv { struct snd_soc_jack headset_jack; struct snd_soc_jack dp_jack; @@ -374,7 +369,8 @@ static const struct snd_soc_ops mt8195_dptx_ops = { static int mt8195_dptx_codec_init(struct snd_soc_pcm_runtime *rtd) { - struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv; struct snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; int ret; @@ -389,7 +385,8 @@ static int mt8195_dptx_codec_init(struct snd_soc_pcm_runtime *rtd) static int mt8195_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd) { - struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv; struct snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; int ret; @@ -555,7 +552,8 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; - struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv; struct snd_soc_jack *jack = &priv->headset_jack; struct snd_soc_component *cmpnt_afe = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); @@ -722,7 +720,8 @@ static int mt8195_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { struct snd_soc_component *component = dapm->component; - struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(card); + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); + struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv; int ret; /* @@ -1321,175 +1320,24 @@ static struct snd_soc_card mt8195_mt6359_soc_card = { static int mt8195_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai_link *sof_dai_link = NULL; - struct snd_soc_pcm_runtime *runtime; - struct snd_soc_dai *cpu_dai; - int i, j, ret = 0; - - for (i = 0; i < ARRAY_SIZE(g_sof_conn_streams); i++) { - const struct sof_conn_stream *conn = &g_sof_conn_streams[i]; - - if (strcmp(rtd->dai_link->name, conn->normal_link)) - continue; - - for_each_card_rtds(card, runtime) { - if (strcmp(runtime->dai_link->name, conn->sof_link)) - continue; - - for_each_rtd_cpu_dais(runtime, j, cpu_dai) { - if (cpu_dai->stream_active[conn->stream_dir] > 0) { - sof_dai_link = runtime->dai_link; - break; - } - } - break; - } + int ret; - if (sof_dai_link && sof_dai_link->be_hw_params_fixup) - ret = sof_dai_link->be_hw_params_fixup(runtime, params); - - break; - } + ret = mtk_sof_dai_link_fixup(rtd, params); if (!strcmp(rtd->dai_link->name, "ETDM2_IN_BE") || !strcmp(rtd->dai_link->name, "ETDM1_OUT_BE")) { - mt8195_etdm_hw_params_fixup(runtime, params); + mt8195_etdm_hw_params_fixup(rtd, params); } return ret; } -static int mt8195_mt6359_card_late_probe(struct snd_soc_card *card) -{ - struct snd_soc_pcm_runtime *runtime; - struct snd_soc_component *sof_comp = NULL; - int i; - - /* 1. find sof component */ - for_each_card_rtds(card, runtime) { - for (i = 0; i < runtime->num_components; i++) { - if (!runtime->components[i]->driver->name) - continue; - if (!strcmp(runtime->components[i]->driver->name, "sof-audio-component")) { - sof_comp = runtime->components[i]; - break; - } - } - } - - if (!sof_comp) { - dev_info(card->dev, " probe without component\n"); - return 0; - } - /* 2. add route path and fixup callback */ - for (i = 0; i < ARRAY_SIZE(g_sof_conn_streams); i++) { - const struct sof_conn_stream *conn = &g_sof_conn_streams[i]; - struct snd_soc_pcm_runtime *sof_rtd = NULL; - struct snd_soc_pcm_runtime *normal_rtd = NULL; - struct snd_soc_pcm_runtime *rtd = NULL; - - for_each_card_rtds(card, rtd) { - if (!strcmp(rtd->dai_link->name, conn->sof_link)) { - sof_rtd = rtd; - continue; - } - if (!strcmp(rtd->dai_link->name, conn->normal_link)) { - normal_rtd = rtd; - continue; - } - if (normal_rtd && sof_rtd) - break; - } - if (normal_rtd && sof_rtd) { - int j; - struct snd_soc_dai *cpu_dai; - - for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) { - struct snd_soc_dapm_route route; - struct snd_soc_dapm_path *p = NULL; - struct snd_soc_dapm_widget *play_widget = - cpu_dai->playback_widget; - struct snd_soc_dapm_widget *cap_widget = - cpu_dai->capture_widget; - memset(&route, 0, sizeof(route)); - if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE && - cap_widget) { - snd_soc_dapm_widget_for_each_sink_path(cap_widget, p) { - route.source = conn->sof_dma; - route.sink = p->sink->name; - snd_soc_dapm_add_routes(&card->dapm, &route, 1); - } - } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK && - play_widget){ - snd_soc_dapm_widget_for_each_source_path(play_widget, p) { - route.source = p->source->name; - route.sink = conn->sof_dma; - snd_soc_dapm_add_routes(&card->dapm, &route, 1); - } - } else { - dev_err(cpu_dai->dev, "stream dir and widget not pair\n"); - } - } - normal_rtd->dai_link->be_hw_params_fixup = mt8195_dai_link_fixup; - } - } - - return 0; -} - -static int mt8195_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, - const char *propname) -{ - struct device *dev = card->dev; - struct snd_soc_dai_link *link; - const char *dai_name = NULL; - int i, j, ret, num_links; - - num_links = of_property_count_strings(np, "mediatek,dai-link"); - - if (num_links < 0 || num_links > ARRAY_SIZE(mt8195_mt6359_dai_links)) { - dev_dbg(dev, "number of dai-link is invalid\n"); - return -EINVAL; - } - - card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); - if (!card->dai_link) - return -ENOMEM; - - card->num_links = 0; - link = card->dai_link; - - for (i = 0; i < num_links; i++) { - ret = of_property_read_string_index(np, propname, i, &dai_name); - if (ret) { - dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n", - propname, i, ret); - return -EINVAL; - } - - for (j = 0; j < ARRAY_SIZE(mt8195_mt6359_dai_links); j++) { - if (!strcmp(dai_name, mt8195_mt6359_dai_links[j].name)) { - memcpy(link, &mt8195_mt6359_dai_links[j], - sizeof(struct snd_soc_dai_link)); - link++; - card->num_links++; - break; - } - } - } - - if (card->num_links != num_links) - return -EINVAL; - - return 0; -} - static int mt8195_mt6359_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8195_mt6359_soc_card; struct snd_soc_dai_link *dai_link; - struct mt8195_mt6359_priv *priv; + struct mtk_soc_card_data *soc_card_data; + struct mt8195_mt6359_priv *mach_priv; struct device_node *platform_node, *adsp_node, *dp_node, *hdmi_node; struct mt8195_card_data *card_data; int is5682s = 0; @@ -1512,17 +1360,41 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev) if (strstr(card->name, "_5682s")) is5682s = 1; + soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*card_data), GFP_KERNEL); + if (!soc_card_data) + return -ENOMEM; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) + mach_priv = devm_kzalloc(&pdev->dev, sizeof(*mach_priv), GFP_KERNEL); + if (!mach_priv) return -ENOMEM; + soc_card_data->mach_priv = mach_priv; + + adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0); + if (adsp_node) { + struct mtk_sof_priv *sof_priv; + + sof_priv = devm_kzalloc(&pdev->dev, sizeof(*sof_priv), GFP_KERNEL); + if (!sof_priv) { + ret = -ENOMEM; + goto err_kzalloc; + } + sof_priv->conn_streams = g_sof_conn_streams; + sof_priv->num_streams = ARRAY_SIZE(g_sof_conn_streams); + sof_priv->sof_dai_link_fixup = mt8195_dai_link_fixup; + soc_card_data->sof_priv = sof_priv; + card->late_probe = mtk_sof_card_late_probe; + sof_on = 1; + } + if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) { - ret = mt8195_dailink_parse_of(card, pdev->dev.of_node, - "mediatek,dai-link"); + ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node, + "mediatek,dai-link", + mt8195_mt6359_dai_links, + ARRAY_SIZE(mt8195_mt6359_dai_links)); if (ret) { dev_dbg(&pdev->dev, "Parse dai-link fail\n"); - return -EINVAL; + goto err_parse_of; } } else { if (!sof_on) @@ -1533,13 +1405,10 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev) "mediatek,platform", 0); if (!platform_node) { dev_dbg(&pdev->dev, "Property 'platform' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto err_platform_node; } - adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0); - if (adsp_node) - sof_on = 1; - dp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,dptx-codec", 0); hdmi_node = of_parse_phandle(pdev->dev.of_node, "mediatek,hdmi-codec", 0); @@ -1612,17 +1481,17 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev) } } - if (sof_on) - card->late_probe = mt8195_mt6359_card_late_probe; - - snd_soc_card_set_drvdata(card, priv); + snd_soc_card_set_drvdata(card, soc_card_data); ret = devm_snd_soc_register_card(&pdev->dev, card); of_node_put(platform_node); - of_node_put(adsp_node); of_node_put(dp_node); of_node_put(hdmi_node); +err_kzalloc: +err_parse_of: +err_platform_node: + of_node_put(adsp_node); return ret; } diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c index 01f383888b62..1530e98df165 100644 --- a/sound/soc/qcom/qdsp6/q6adm.c +++ b/sound/soc/qcom/qdsp6/q6adm.c @@ -217,7 +217,7 @@ static struct q6copp *q6adm_alloc_copp(struct q6adm *adm, int port_idx) idx = find_first_zero_bit(&adm->copp_bitmap[port_idx], MAX_COPPS_PER_PORT); - if (idx > MAX_COPPS_PER_PORT) + if (idx >= MAX_COPPS_PER_PORT) return ERR_PTR(-EBUSY); c = kzalloc(sizeof(*c), GFP_ATOMIC); diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index 9251d8548965..195780f75d05 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -513,7 +513,7 @@ int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac, return 0; } - buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC); + buf = kcalloc(periods, sizeof(*buf), GFP_ATOMIC); if (!buf) { spin_unlock_irqrestore(&ac->lock, flags); return -ENOMEM; diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c index ff5900b155dc..bd9789b483b1 100644 --- a/sound/soc/sof/intel/atom.c +++ b/sound/soc/sof/intel/atom.c @@ -274,22 +274,22 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, const char *ssp_str) { const char *tplg_filename = NULL; - char *filename; - char *split_ext; + const char *split_ext; + char *filename, *tmp; - filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL); + filename = kstrdup(sof_tplg_filename, GFP_KERNEL); if (!filename) return NULL; /* this assumes a .tplg extension */ - split_ext = strsep(&filename, "."); - if (split_ext) { + tmp = filename; + split_ext = strsep(&tmp, "."); + if (split_ext) tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s-%s.tplg", split_ext, ssp_str); - if (!tplg_filename) - return NULL; - } + kfree(filename); + return tplg_filename; } diff --git a/sound/soc/sof/intel/hda-probes.c b/sound/soc/sof/intel/hda-probes.c index 31e85d4aae8c..56a533c63cb0 100644 --- a/sound/soc/sof/intel/hda-probes.c +++ b/sound/soc/sof/intel/hda-probes.c @@ -25,9 +25,9 @@ hda_compr_get_stream(struct snd_compr_stream *cstream) return cstream->runtime->private_data; } -static int hda_probes_compr_assign(struct sof_client_dev *cdev, - struct snd_compr_stream *cstream, - struct snd_soc_dai *dai, u32 *stream_id) +static int hda_probes_compr_startup(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai, u32 *stream_id) { struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); struct hdac_ext_stream *hext_stream; @@ -45,9 +45,9 @@ static int hda_probes_compr_assign(struct sof_client_dev *cdev, return 0; } -static int hda_probes_compr_free(struct sof_client_dev *cdev, - struct snd_compr_stream *cstream, - struct snd_soc_dai *dai) +static int hda_probes_compr_shutdown(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) { struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); @@ -127,8 +127,8 @@ static int hda_probes_compr_pointer(struct sof_client_dev *cdev, /* SOF client implementation */ static const struct sof_probes_host_ops hda_probes_ops = { - .assign = hda_probes_compr_assign, - .free = hda_probes_compr_free, + .startup = hda_probes_compr_startup, + .shutdown = hda_probes_compr_shutdown, .set_params = hda_probes_compr_set_params, .trigger = hda_probes_compr_trigger, .pointer = hda_probes_compr_pointer, diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 4531e1ee5ed0..b58662faa4aa 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -411,6 +411,11 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st return -ENODEV; } + if (!dmab) { + dev_err(sdev->dev, "error: no dma buffer allocated!\n"); + return -ENODEV; + } + if (hstream->posbuf) *hstream->posbuf = 0; @@ -485,16 +490,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, return -ENODEV; } - /* decouple host and link DMA */ - mask = 0x1 << hstream->index; - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - mask, mask); - if (!dmab) { dev_err(sdev->dev, "error: no dma buffer allocated!\n"); return -ENODEV; } + /* decouple host and link DMA */ + mask = 0x1 << hstream->index; + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, mask); + /* clear stream status */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_DMA_SD_INT_MASK | diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b7fa95ea1090..8639ea63a10d 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -776,13 +776,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, return tplg_filename; } -static int dmic_topology_fixup(struct snd_sof_dev *sdev, - const char **tplg_filename, - const char *idisp_str, - int *dmic_found) +static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev, + const char **tplg_filename, + const char *idisp_str, + int *dmic_found, + bool tplg_fixup) { - const char *default_tplg_filename = *tplg_filename; - const char *fixed_tplg_filename; const char *dmic_str; int dmic_num; @@ -808,14 +807,19 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev, break; } - fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename, - idisp_str, dmic_str); - if (!fixed_tplg_filename) - return -ENOMEM; + if (tplg_fixup) { + const char *default_tplg_filename = *tplg_filename; + const char *fixed_tplg_filename; + + fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename, + idisp_str, dmic_str); + if (!fixed_tplg_filename) + return -ENOMEM; + *tplg_filename = fixed_tplg_filename; + } dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num); *dmic_found = dmic_num; - *tplg_filename = fixed_tplg_filename; return 0; } @@ -1221,6 +1225,8 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, * - one external HDAudio codec */ if (!*mach && codec_num <= 2) { + bool tplg_fixup; + hda_mach = snd_soc_acpi_intel_hda_machines; dev_info(bus->dev, "using HDA machine driver %s now\n", @@ -1232,8 +1238,15 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, idisp_str = ""; /* topology: use the info from hda_machines */ - tplg_filename = hda_mach->sof_tplg_filename; - ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num); + if (pdata->tplg_filename) { + tplg_fixup = false; + tplg_filename = pdata->tplg_filename; + } else { + tplg_fixup = true; + tplg_filename = hda_mach->sof_tplg_filename; + } + ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num, + tplg_fixup); if (ret < 0) return; @@ -1397,30 +1410,37 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev } if (mach && mach->link_mask) { int dmic_num = 0; + bool tplg_fixup; + const char *tplg_filename; mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; mach->mach_params.platform = dev_name(sdev->dev); - pdata->fw_filename = pdata->desc->default_fw_filename[pdata->ipc_type]; - pdata->tplg_filename = mach->sof_tplg_filename; + + if (pdata->tplg_filename) { + tplg_fixup = false; + } else { + tplg_fixup = true; + tplg_filename = mach->sof_tplg_filename; + } /* * DMICs use up to 4 pins and are typically pin-muxed with SoundWire - * link 2 and 3, thus we only try to enable dmics if all conditions - * are true: - * a) link 2 and 3 are not used by SoundWire + * link 2 and 3, or link 1 and 2, thus we only try to enable dmics + * if all conditions are true: + * a) 2 or fewer links are used by SoundWire * b) the NHLT table reports the presence of microphones */ - if (!(mach->link_mask & GENMASK(3, 2))) { - const char *tplg_filename = mach->sof_tplg_filename; + if (hweight_long(mach->link_mask) <= 2) { int ret; - ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num); + ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "", + &dmic_num, tplg_fixup); if (ret < 0) return NULL; - - pdata->tplg_filename = tplg_filename; } + if (tplg_fixup) + pdata->tplg_filename = tplg_filename; mach->mach_params.dmic_num = dmic_num; dev_dbg(sdev->dev, @@ -1466,18 +1486,22 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) mach = snd_soc_acpi_find_machine(desc->machines); if (mach) { bool add_extension = false; + bool tplg_fixup = false; /* * If tplg file name is overridden, use it instead of * the one set in mach table */ - if (!sof_pdata->tplg_filename) + if (!sof_pdata->tplg_filename) { sof_pdata->tplg_filename = mach->sof_tplg_filename; + tplg_fixup = true; + } /* report to machine driver if any DMICs are found */ mach->mach_params.dmic_num = check_dmic_num(sdev); - if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER && + if (tplg_fixup && + mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER && mach->mach_params.dmic_num) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s%s%d%s", @@ -1500,8 +1524,10 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) /* report SSP link mask to machine driver */ mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev); - if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER && + if (tplg_fixup && + mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER && mach->mach_params.i2s_link_mask) { + const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata); int ssp_num; if (hweight_long(mach->mach_params.i2s_link_mask) > 1 && @@ -1511,6 +1537,12 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) /* fls returns 1-based results, SSPs indices are 0-based */ ssp_num = fls(mach->mach_params.i2s_link_mask) - 1; + if (ssp_num >= chip->ssp_count) { + dev_err(sdev->dev, "Invalid SSP %d, max on this platform is %d\n", + ssp_num, chip->ssp_count); + return NULL; + } + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s%s%d", sof_pdata->tplg_filename, @@ -1523,7 +1555,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) add_extension = true; } - if (add_extension) { + if (tplg_fixup && add_extension) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s%s", sof_pdata->tplg_filename, diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index a5e244ea0688..96239ebb1eed 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -372,20 +372,9 @@ static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core) ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl, (dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); - if (ret < 0) { + if (ret < 0) dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n", __func__); - return ret; - } - - /* did core power up ? */ - dspcxctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE); - if ((dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) - != MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) { - dev_err(sdev->dev, "power up core failed core %d adspcs %#x\n", - core, dspcxctl); - ret = -EIO; - } return ret; } diff --git a/sound/soc/sof/ipc3-loader.c b/sound/soc/sof/ipc3-loader.c index c573e7593808..bf423ca4e97b 100644 --- a/sound/soc/sof/ipc3-loader.c +++ b/sound/soc/sof/ipc3-loader.c @@ -109,7 +109,7 @@ static int ipc3_fw_ext_man_get_config_data(struct snd_sof_dev *sdev, return 0; } -static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw) +static ssize_t ipc3_fw_ext_man_size(struct snd_sof_dev *sdev, const struct firmware *fw) { const struct sof_ext_man_header *head; @@ -131,6 +131,8 @@ static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw) return head->full_size; /* otherwise given fw don't have an extended manifest */ + dev_dbg(sdev->dev, "Unexpected extended manifest magic number: %#x\n", + head->magic); return 0; } @@ -147,7 +149,7 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev) head = (struct sof_ext_man_header *)fw->data; remaining = head->full_size - head->header_size; - ext_man_size = ipc3_fw_ext_man_size(fw); + ext_man_size = ipc3_fw_ext_man_size(sdev, fw); /* Assert firmware starts with extended manifest */ if (ext_man_size <= 0) diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index b97e63d3724a..9c6a84bdeca7 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -115,6 +115,9 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component, pcm.params.no_stream_position = 1; } + if (platform_params->cont_update_posn) + pcm.params.cont_update_posn = 1; + dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag); /* send hw_params IPC to the DSP */ diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 6a702f9dc065..732872395980 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -179,6 +179,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); + struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct sof_ipc4_copier *ipc4_copier; @@ -201,6 +202,9 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, snd_mask_none(fmt); snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + rate->min = ipc4_copier->available_fmt.base_config->audio_fmt.sampling_frequency; + rate->max = rate->min; + /* * Set trigger order for capture to SND_SOC_DPCM_TRIGGER_PRE. This is required * to ensure that the BE DAI pipeline gets stopped/suspended before the FE DAI diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 22ea628d78d0..af072b484a60 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -111,6 +111,12 @@ static const struct sof_topology_token gain_tokens[] = { get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, }; +/* SRC */ +static const struct sof_topology_token src_tokens[] = { + {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_src, sink_rate)}, +}; + static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, @@ -134,6 +140,7 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens", ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)}, [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)}, + [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, }; static void sof_ipc4_dbg_audio_format(struct device *dev, @@ -307,6 +314,7 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg) { struct sof_ipc4_fw_module *fw_module; + uint32_t type; int ret; ret = sof_ipc4_widget_set_module_info(swidget); @@ -323,6 +331,9 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id); msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); + type = fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP ? 1 : 0; + msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type); + return 0; } @@ -740,6 +751,58 @@ err: return ret; } +static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc4_src *src; + int ret; + + dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); + + src = kzalloc(sizeof(*src), GFP_KERNEL); + if (!src) + return -ENOMEM; + + swidget->private = src; + + /* The out_audio_fmt in topology is ignored as it is not required by SRC */ + ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false); + if (ret) + goto err; + + ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(src), 1); + if (ret) { + dev_err(scomp->dev, "Parsing SRC tokens failed\n"); + goto err; + } + + dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate); + + ret = sof_ipc4_widget_setup_msg(swidget, &src->msg); + if (ret) + goto err; + + return 0; +err: + sof_ipc4_free_audio_fmt(&src->available_fmt); + kfree(src); + swidget->private = NULL; + return ret; +} + +static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget) +{ + struct sof_ipc4_src *src = swidget->private; + + if (!src) + return; + + sof_ipc4_free_audio_fmt(&src->available_fmt); + kfree(swidget->private); + swidget->private = NULL; +} + static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget) { struct sof_ipc4_mixer *mixer = swidget->private; @@ -891,7 +954,6 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) { - struct sof_ipc4_fw_module *fw_module = swidget->module_info; struct sof_ipc4_copier *ipc4_copier = NULL; struct snd_sof_widget *pipe_widget; struct sof_ipc4_pipeline *pipeline; @@ -925,8 +987,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) ipc4_copier->ipc_config_data = NULL; ipc4_copier->ipc_config_size = 0; } - - ida_free(&fw_module->m_ida, swidget->instance_id); } #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) @@ -1254,15 +1314,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, /* update pipeline memory usage */ sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config); - /* assign instance ID */ - return sof_ipc4_widget_assign_instance_id(sdev, swidget); -} - -static void sof_ipc4_unprepare_generic_module(struct snd_sof_widget *swidget) -{ - struct sof_ipc4_fw_module *fw_module = swidget->module_info; - - ida_free(&fw_module->m_ida, swidget->instance_id); + return 0; } static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, @@ -1287,8 +1339,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, /* update pipeline memory usage */ sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config); - /* assign instance ID */ - return sof_ipc4_widget_assign_instance_id(sdev, swidget); + return 0; } static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, @@ -1314,8 +1365,38 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, /* update pipeline memory usage */ sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config); - /* assign instance ID */ - return sof_ipc4_widget_assign_instance_id(sdev, swidget); + return 0; +} + +static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *pipeline_params, int dir) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_src *src = swidget->private; + struct snd_interval *rate; + int ret; + + src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt; + + /* output format is not required to be sent to the FW for SRC */ + ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, + NULL, pipeline_params, &src->available_fmt, + sizeof(src->base_config)); + if (ret < 0) + return ret; + + /* update pipeline memory usage */ + sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config); + + /* update pipeline_params for sink widgets */ + rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); + rate->min = src->sink_rate; + rate->max = rate->min; + + return 0; } static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) @@ -1373,9 +1454,6 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget u32 ipc_size = 0; int ret; - dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", - swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); - switch (swidget->id) { case snd_soc_dapm_scheduler: pipeline = swidget->private; @@ -1430,21 +1508,37 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg = &mixer->msg; break; } + case snd_soc_dapm_src: + { + struct sof_ipc4_src *src = swidget->private; + + ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate); + ipc_data = src; + + msg = &src->msg; + break; + } default: dev_err(sdev->dev, "widget type %d not supported", swidget->id); return -EINVAL; } if (swidget->id != snd_soc_dapm_scheduler) { + ret = sof_ipc4_widget_assign_instance_id(sdev, swidget); + if (ret < 0) { + dev_err(sdev->dev, "failed to assign instance id for %s\n", + swidget->widget->name); + return ret; + } pipeline = pipe_widget->private; msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; msg->extension |= ipc_size >> 2; - msg->extension &= ~SOF_IPC4_MOD_EXT_DOMAIN_MASK; - msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(pipeline->lp_mode); } + dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", + swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); msg->data_size = ipc_size; msg->data_ptr = ipc_data; @@ -1458,6 +1552,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { + struct sof_ipc4_fw_module *fw_module = swidget->module_info; int ret = 0; /* freeing a pipeline frees all the widgets associated with it */ @@ -1480,6 +1575,8 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget pipeline->mem_usage = 0; pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; + } else { + ida_free(&fw_module->m_ida, swidget->instance_id); } return ret; @@ -1766,6 +1863,15 @@ static enum sof_tokens mixer_token_list[] = { SOF_COMP_EXT_TOKENS, }; +static enum sof_tokens src_token_list[] = { + SOF_COMP_TOKENS, + SOF_SRC_TOKENS, + SOF_AUDIO_FMT_NUM_TOKENS, + SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_COMP_EXT_TOKENS, +}; + static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, host_token_list, ARRAY_SIZE(host_token_list), NULL, @@ -1789,11 +1895,15 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga, pga_token_list, ARRAY_SIZE(pga_token_list), NULL, sof_ipc4_prepare_gain_module, - sof_ipc4_unprepare_generic_module}, + NULL}, [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer, mixer_token_list, ARRAY_SIZE(mixer_token_list), NULL, sof_ipc4_prepare_mixer_module, - sof_ipc4_unprepare_generic_module}, + NULL}, + [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src, + src_token_list, ARRAY_SIZE(src_token_list), + NULL, sof_ipc4_prepare_src_module, + NULL}, }; const struct sof_ipc_tplg_ops ipc4_tplg_ops = { diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 3bc2fe38c733..0aa87a8add5d 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -15,7 +15,18 @@ #define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12) #define SOF_IPC4_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1))) -#define SOF_IPC4_MODULE_LL BIT(5) +#define SOF_IPC4_MODULE_LOAD_TYPE GENMASK(3, 0) +#define SOF_IPC4_MODULE_AUTO_START BIT(4) +/* + * Two module schedule domains in fw : + * LL domain - Low latency domain + * DP domain - Data processing domain + * The LL setting should be equal to !DP setting + */ +#define SOF_IPC4_MODULE_LL BIT(5) +#define SOF_IPC4_MODULE_DP BIT(6) +#define SOF_IPC4_MODULE_LIB_CODE BIT(7) + #define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12 #define SOF_IPC4_PIPELINE_OBJECT_SIZE 448 #define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128 @@ -242,4 +253,18 @@ struct sof_ipc4_mixer { struct sof_ipc4_msg msg; }; +/** + * struct sof_ipc4_src SRC config data + * @base_config: IPC base config data + * @sink_rate: Output rate for sink module + * @available_fmt: Available audio format + * @msg: IPC4 message struct containing header and data info + */ +struct sof_ipc4_src { + struct sof_ipc4_base_module_cfg base_config; + uint32_t sink_rate; + struct sof_ipc4_available_audio_format available_fmt; + struct sof_ipc4_msg msg; +}; + #endif diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-loader.c b/sound/soc/sof/mediatek/mt8195/mt8195-loader.c index ed18d6379e92..4be99ff4ebd3 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195-loader.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195-loader.c @@ -21,7 +21,7 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr) /* pull high StatVectorSel to use AltResetVec (set bit4 to 1) */ snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, - DSP_RESET_SW, DSP_RESET_SW); + STATVECTOR_SEL, STATVECTOR_SEL); /* toggle DReset & BReset */ /* pull high DReset & BReset */ @@ -29,6 +29,9 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr) ADSP_BRESET_SW | ADSP_DRESET_SW, ADSP_BRESET_SW | ADSP_DRESET_SW); + /* delay 10 DSP cycles at 26M about 1us by IP vendor's suggestion */ + udelay(1); + /* pull low DReset & BReset */ snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, ADSP_BRESET_SW | ADSP_DRESET_SW, @@ -46,11 +49,13 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr) void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev) { - /* Clear to 0 firstly */ - snd_sof_dsp_write(sdev, DSP_REG_BAR, DSP_RESET_SW, 0x0); - /* RUN_STALL pull high again to reset */ snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, ADSP_RUNSTALL, ADSP_RUNSTALL); + + /* pull high DReset & BReset */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_BRESET_SW | ADSP_DRESET_SW, + ADSP_BRESET_SW | ADSP_DRESET_SW); } diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index e7e78d1a8ec3..eb246b823461 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -270,9 +270,9 @@ static int sof_probes_compr_startup(struct snd_compr_stream *cstream, if (ret) return ret; - ret = ops->assign(cdev, cstream, dai, &priv->extractor_stream_tag); + ret = ops->startup(cdev, cstream, dai, &priv->extractor_stream_tag); if (ret) { - dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret); + dev_err(dai->dev, "Failed to startup probe stream: %d\n", ret); priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID; sof_client_core_module_put(cdev); } @@ -310,7 +310,7 @@ exit: priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID; snd_compr_free_pages(cstream); - ret = ops->free(cdev, cstream, dai); + ret = ops->shutdown(cdev, cstream, dai); sof_client_core_module_put(cdev); @@ -709,7 +709,7 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev, ops = dev->platform_data; - if (!ops->assign || !ops->free || !ops->set_params || !ops->trigger || + if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger || !ops->pointer) { dev_err(dev, "missing platform callback(s)\n"); return -ENODEV; diff --git a/sound/soc/sof/sof-client-probes.h b/sound/soc/sof/sof-client-probes.h index 0f9ed4569fd3..9e43f3c444f8 100644 --- a/sound/soc/sof/sof-client-probes.h +++ b/sound/soc/sof/sof-client-probes.h @@ -14,10 +14,10 @@ struct snd_soc_dai; * DSP and host, like HDA. */ struct sof_probes_host_ops { - int (*assign)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - struct snd_soc_dai *dai, u32 *stream_id); - int (*free)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - struct snd_soc_dai *dai); + int (*startup)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, + struct snd_soc_dai *dai, u32 *stream_id); + int (*shutdown)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, + struct snd_soc_dai *dai); int (*set_params)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, struct snd_compr_params *params, struct snd_soc_dai *dai); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 8bbc94907c62..823583086279 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -126,6 +126,7 @@ struct snd_sof_platform_stream_params { bool use_phy_address; u32 phy_addr; bool no_ipc_position; + bool cont_update_posn; }; /* |