diff options
Diffstat (limited to 'sound/soc/qcom')
42 files changed, 814 insertions, 281 deletions
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index e7b00d1d9e99..ca7a30ebd26a 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -157,6 +157,7 @@ config SND_SOC_SDM845 depends on COMMON_CLK select SND_SOC_QDSP6 select SND_SOC_QCOM_COMMON + select SND_SOC_QCOM_SDW select SND_SOC_RT5663 select SND_SOC_MAX98927 imply SND_SOC_CROS_EC_CODEC @@ -208,6 +209,7 @@ config SND_SOC_SC7280 tristate "SoC Machine driver for SC7280 boards" depends on I2C && SOUNDWIRE select SND_SOC_QCOM_COMMON + select SND_SOC_QCOM_SDW select SND_SOC_LPASS_SC7280 select SND_SOC_MAX98357A select SND_SOC_WCD938X_SDW @@ -221,4 +223,16 @@ config SND_SOC_SC7280 SC7280 SoC-based systems. Say Y or M if you want to use audio device on this SoCs. +config SND_SOC_X1E80100 + tristate "SoC Machine driver for X1E80100 boards" + depends on QCOM_APR && SOUNDWIRE + depends on COMMON_CLK + select SND_SOC_QDSP6 + select SND_SOC_QCOM_COMMON + select SND_SOC_QCOM_SDW + help + Add support for audio on Qualcomm Technologies Inc. + X1E80100 SoC-based systems. + Say Y or M if you want to use audio device on this SoCs. + endif #SND_SOC_QCOM diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index 254350d9dc06..16db7b53ddac 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -1,13 +1,13 @@ # SPDX-License-Identifier: GPL-2.0 # Platform -snd-soc-lpass-cpu-objs := lpass-cpu.o -snd-soc-lpass-cdc-dma-objs := lpass-cdc-dma.o -snd-soc-lpass-hdmi-objs := lpass-hdmi.o -snd-soc-lpass-platform-objs := lpass-platform.o -snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o -snd-soc-lpass-apq8016-objs := lpass-apq8016.o -snd-soc-lpass-sc7180-objs := lpass-sc7180.o -snd-soc-lpass-sc7280-objs := lpass-sc7280.o +snd-soc-lpass-cpu-y := lpass-cpu.o +snd-soc-lpass-cdc-dma-y := lpass-cdc-dma.o +snd-soc-lpass-hdmi-y := lpass-hdmi.o +snd-soc-lpass-platform-y := lpass-platform.o +snd-soc-lpass-ipq806x-y := lpass-ipq806x.o +snd-soc-lpass-apq8016-y := lpass-apq8016.o +snd-soc-lpass-sc7180-y := lpass-sc7180.o +snd-soc-lpass-sc7280-y := lpass-sc7280.o obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o obj-$(CONFIG_SND_SOC_LPASS_CDC_DMA) += snd-soc-lpass-cdc-dma.o @@ -19,16 +19,17 @@ obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o obj-$(CONFIG_SND_SOC_LPASS_SC7280) += snd-soc-lpass-sc7280.o # Machine -snd-soc-storm-objs := storm.o -snd-soc-apq8016-sbc-objs := apq8016_sbc.o -snd-soc-apq8096-objs := apq8096.o -snd-soc-sc7180-objs := sc7180.o -snd-soc-sc7280-objs := sc7280.o -snd-soc-sdm845-objs := sdm845.o -snd-soc-sm8250-objs := sm8250.o -snd-soc-sc8280xp-objs := sc8280xp.o -snd-soc-qcom-common-objs := common.o -snd-soc-qcom-sdw-objs := sdw.o +snd-soc-storm-y := storm.o +snd-soc-apq8016-sbc-y := apq8016_sbc.o +snd-soc-apq8096-y := apq8096.o +snd-soc-sc7180-y := sc7180.o +snd-soc-sc7280-y := sc7280.o +snd-soc-sdm845-y := sdm845.o +snd-soc-sm8250-y := sm8250.o +snd-soc-sc8280xp-y := sc8280xp.o +snd-soc-qcom-common-y := common.o +snd-soc-qcom-sdw-y := sdw.o +snd-soc-x1e80100-y := x1e80100.o obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o @@ -40,6 +41,7 @@ obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o obj-$(CONFIG_SND_SOC_QCOM_SDW) += snd-soc-qcom-sdw.o +obj-$(CONFIG_SND_SOC_X1E80100) += snd-soc-x1e80100.o #DSP lib obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/ diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index ff9f6a1c95df..3023cf180a75 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -16,6 +16,7 @@ #include <sound/soc.h> #include <uapi/linux/input-event-codes.h> #include <dt-bindings/sound/apq8016-lpass.h> +#include <dt-bindings/sound/qcom,q6afe.h> #include "common.h" #include "qdsp6/q6afe.h" @@ -191,7 +192,7 @@ static int msm8916_qdsp6_dai_init(struct snd_soc_pcm_runtime *rtd) static int msm8916_qdsp6_startup(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct apq8016_sbc_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); @@ -212,7 +213,7 @@ static int msm8916_qdsp6_startup(struct snd_pcm_substream *substream) static void msm8916_qdsp6_shutdown(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct apq8016_sbc_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); @@ -343,4 +344,4 @@ module_platform_driver(apq8016_sbc_platform_driver); MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); MODULE_DESCRIPTION("APQ8016 ASoC Machine Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index cddeb47dbcf2..4f6594cc723c 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2018, Linaro Limited +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/of_device.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/pcm.h> @@ -142,4 +142,4 @@ static struct platform_driver msm_snd_apq8096_driver = { module_platform_driver(msm_snd_apq8096_driver); MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); MODULE_DESCRIPTION("APQ8096 ASoC Machine Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index f2d1e3009cd2..928cf5cb5999 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -2,15 +2,25 @@ // Copyright (c) 2018, Linaro Limited. // Copyright (c) 2018, The Linux Foundation. All rights reserved. +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/module.h> #include <sound/jack.h> #include <linux/input-event-codes.h> -#include "qdsp6/q6afe.h" #include "common.h" +#define NAME_SIZE 32 + static const struct snd_soc_dapm_widget qcom_jack_snd_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("DP0 Jack", NULL), + SND_SOC_DAPM_SPK("DP1 Jack", NULL), + SND_SOC_DAPM_SPK("DP2 Jack", NULL), + SND_SOC_DAPM_SPK("DP3 Jack", NULL), + SND_SOC_DAPM_SPK("DP4 Jack", NULL), + SND_SOC_DAPM_SPK("DP5 Jack", NULL), + SND_SOC_DAPM_SPK("DP6 Jack", NULL), + SND_SOC_DAPM_SPK("DP7 Jack", NULL), }; int qcom_snd_parse_of(struct snd_soc_card *card) @@ -73,7 +83,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) link = card->dai_link; for_each_available_child_of_node(dev->of_node, np) { - dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL); + dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL); if (!dlc) { ret = -ENOMEM; goto err_put_np; @@ -145,7 +155,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card) if (platform || !codec) { /* DPCM */ - snd_soc_dai_link_set_capabilities(link); link->ignore_suspend = 1; link->nonatomic = 1; } @@ -239,4 +248,31 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, return 0; } EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup); -MODULE_LICENSE("GPL v2"); + +int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_jack *dp_jack, int dp_pcm_id) +{ + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_card *card = rtd->card; + char jack_name[NAME_SIZE]; + int rval, i; + + snprintf(jack_name, sizeof(jack_name), "DP%d Jack", dp_pcm_id); + rval = snd_soc_card_jack_new(card, jack_name, SND_JACK_AVOUT, dp_jack); + if (rval) + return rval; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + rval = snd_soc_component_set_jack(codec_dai->component, dp_jack, NULL); + if (rval != 0 && rval != -ENOTSUPP) { + dev_warn(card->dev, "Failed to set jack: %d\n", rval); + return rval; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_snd_dp_jack_setup); + +MODULE_DESCRIPTION("ASoC Qualcomm helper functions"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h index d7f80ee5ae26..1b8d3f90bffa 100644 --- a/sound/soc/qcom/common.h +++ b/sound/soc/qcom/common.h @@ -9,5 +9,8 @@ int qcom_snd_parse_of(struct snd_soc_card *card); int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_jack *jack, bool *jack_setup); +int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_jack *dp_jack, int id); + #endif diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index f919d46e18ca..b8f23414eb77 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -123,7 +123,7 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata, int direction, unsigned int dai_id) { - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int chan = 0; if (direction == SNDRV_PCM_STREAM_PLAYBACK) { @@ -157,7 +157,7 @@ static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, static int apq8016_lpass_init(struct platform_device *pdev) { struct lpass_data *drvdata = platform_get_drvdata(pdev); - struct lpass_variant *variant = drvdata->variant; + const struct lpass_variant *variant = drvdata->variant; struct device *dev = &pdev->dev; int ret, i; @@ -223,7 +223,7 @@ static int apq8016_lpass_exit(struct platform_device *pdev) } -static struct lpass_variant apq8016_data = { +static const struct lpass_variant apq8016_data = { .i2sctrl_reg_base = 0x1000, .i2sctrl_reg_stride = 0x1000, .i2s_ports = 4, @@ -300,10 +300,10 @@ static struct platform_driver apq8016_lpass_cpu_platform_driver = { .of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id), }, .probe = asoc_qcom_lpass_cpu_platform_probe, - .remove = asoc_qcom_lpass_cpu_platform_remove, + .remove = asoc_qcom_lpass_cpu_platform_remove, }; module_platform_driver(apq8016_lpass_cpu_platform_driver); MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/lpass-cdc-dma.c b/sound/soc/qcom/lpass-cdc-dma.c index 4d5d147b47db..8106c586f68a 100644 --- a/sound/soc/qcom/lpass-cdc-dma.c +++ b/sound/soc/qcom/lpass-cdc-dma.c @@ -5,6 +5,7 @@ * lpass-cdc-dma.c -- ALSA SoC CDC DMA CPU DAI driver for QTi LPASS */ +#include <dt-bindings/sound/qcom,lpass.h> #include <linux/clk.h> #include <linux/module.h> #include <linux/export.h> @@ -37,7 +38,7 @@ static void __lpass_get_dmactl_handle(struct snd_pcm_substream *substream, struc struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); struct snd_pcm_runtime *rt = substream->runtime; struct lpass_pcm_data *pcm_data = rt->private_data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; unsigned int dai_id = cpu_dai->driver->id; switch (dai_id) { diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index e587455dc40a..242bc16da36d 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -5,11 +5,11 @@ * lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS */ +#include <dt-bindings/sound/qcom,lpass.h> #include <linux/clk.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -44,7 +44,7 @@ static int lpass_cpu_init_i2sctl_bitfields(struct device *dev, struct lpaif_i2sctl *i2sctl, struct regmap *map) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; i2sctl->loopback = devm_regmap_field_alloc(dev, map, v->loopback); i2sctl->spken = devm_regmap_field_alloc(dev, map, v->spken); @@ -463,7 +463,7 @@ static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component, const char **dai_name) { struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); - struct lpass_variant *variant = drvdata->variant; + const struct lpass_variant *variant = drvdata->variant; int id = args->args[0]; int ret = -EINVAL; int i; @@ -488,7 +488,7 @@ static const struct snd_soc_component_driver lpass_cpu_comp_driver = { static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; for (i = 0; i < v->i2s_ports; ++i) @@ -530,7 +530,7 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; for (i = 0; i < v->i2s_ports; ++i) @@ -578,7 +578,7 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; for (i = 0; i < v->irq_ports; ++i) { @@ -613,7 +613,7 @@ static struct regmap_config lpass_cpu_regmap_config = { static int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; unsigned int i; struct lpass_hdmi_tx_ctl *tx_ctl; struct regmap_field *legacy_en; @@ -691,7 +691,7 @@ static int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map) static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; if (reg == LPASS_HDMI_TX_CTL_ADDR(v)) @@ -736,7 +736,7 @@ static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg) static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; if (reg == LPASS_HDMI_TX_CTL_ADDR(v)) @@ -785,7 +785,7 @@ static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg) static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v)) @@ -824,7 +824,7 @@ static struct regmap_config lpass_hdmi_regmap_config = { static bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; for (i = 0; i < v->rxtx_irq_ports; ++i) { @@ -890,7 +890,7 @@ static bool lpass_rxtx_regmap_readable(struct device *dev, unsigned int reg) static bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; for (i = 0; i < v->rxtx_irq_ports; ++i) { @@ -915,7 +915,7 @@ static bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg) static bool __lpass_va_regmap_accessible(struct device *dev, unsigned int reg, bool rw) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; for (i = 0; i < v->va_irq_ports; ++i) { @@ -965,7 +965,7 @@ static bool lpass_va_regmap_readable(struct device *dev, unsigned int reg) static bool lpass_va_regmap_volatile(struct device *dev, unsigned int reg) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int i; for (i = 0; i < v->va_irq_ports; ++i) { @@ -1104,9 +1104,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) struct lpass_data *drvdata; struct device_node *dsp_of_node; struct resource *res; - struct lpass_variant *variant; + const struct lpass_variant *variant; struct device *dev = &pdev->dev; - const struct of_device_id *match; int ret, i, dai_id; dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0); @@ -1121,17 +1120,14 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, drvdata); - match = of_match_device(dev->driver->of_match_table, dev); - if (!match || !match->data) + variant = device_get_match_data(dev); + if (!variant) return -EINVAL; - if (of_device_is_compatible(dev->of_node, "qcom,lpass-cpu-apq8016")) { - dev_warn(dev, "%s compatible is deprecated\n", - match->compatible); - } + if (of_device_is_compatible(dev->of_node, "qcom,lpass-cpu-apq8016")) + dev_warn(dev, "qcom,lpass-cpu-apq8016 compatible is deprecated\n"); - drvdata->variant = (struct lpass_variant *)match->data; - variant = drvdata->variant; + drvdata->variant = variant; of_lpass_cpu_parse_dai_data(dev, drvdata); @@ -1284,15 +1280,12 @@ err: } EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe); -int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) +void asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) { struct lpass_data *drvdata = platform_get_drvdata(pdev); if (drvdata->variant->exit) drvdata->variant->exit(pdev); - - - return 0; } EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); @@ -1307,4 +1300,4 @@ void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev) EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown); MODULE_DESCRIPTION("QTi LPASS CPU Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c index 24b1a7523adb..ce753ebc0894 100644 --- a/sound/soc/qcom/lpass-hdmi.c +++ b/sound/soc/qcom/lpass-hdmi.c @@ -251,4 +251,4 @@ const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = { EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops); MODULE_DESCRIPTION("QTi LPASS HDMI Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 2c97f295e394..e57d29ea4ce7 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -108,7 +108,7 @@ static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, return 0; } -static struct lpass_variant ipq806x_data = { +static const struct lpass_variant ipq806x_data = { .i2sctrl_reg_base = 0x0010, .i2sctrl_reg_stride = 0x04, .i2s_ports = 5, @@ -172,9 +172,9 @@ static struct platform_driver ipq806x_lpass_cpu_platform_driver = { .of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id), }, .probe = asoc_qcom_lpass_cpu_platform_probe, - .remove = asoc_qcom_lpass_cpu_platform_remove, + .remove = asoc_qcom_lpass_cpu_platform_remove, }; module_platform_driver(ipq806x_lpass_cpu_platform_driver); MODULE_DESCRIPTION("QTi LPASS CPU Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 73e3d39bd24c..addd2c4bdd3e 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -5,6 +5,7 @@ * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS */ +#include <dt-bindings/sound/qcom,lpass.h> #include <linux/dma-mapping.h> #include <linux/export.h> #include <linux/kernel.h> @@ -100,7 +101,7 @@ static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev, struct regmap *map) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; struct lpaif_dmactl *rd_dmactl, *wr_dmactl; int rval; @@ -128,7 +129,7 @@ static int lpass_platform_alloc_va_dmactl_fields(struct device *dev, struct regmap *map) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; struct lpaif_dmactl *wr_dmactl; wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL); @@ -145,7 +146,7 @@ static int lpass_platform_alloc_dmactl_fields(struct device *dev, struct regmap *map) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; struct lpaif_dmactl *rd_dmactl, *wr_dmactl; int rval; @@ -175,7 +176,7 @@ static int lpass_platform_alloc_hdmidmactl_fields(struct device *dev, struct regmap *map) { struct lpass_data *drvdata = dev_get_drvdata(dev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; struct lpaif_dmactl *rd_dmactl; rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), GFP_KERNEL); @@ -195,7 +196,7 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component, struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int ret, dma_ch, dir = substream->stream; struct lpass_pcm_data *data; struct regmap *map; @@ -287,7 +288,7 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component, struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; struct lpass_pcm_data *data; unsigned int dai_id = cpu_dai->driver->id; @@ -358,7 +359,7 @@ static int __lpass_get_id(const struct snd_pcm_substream *substream, struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct snd_pcm_runtime *rt = substream->runtime; struct lpass_pcm_data *pcm_data = rt->private_data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int id; switch (cpu_dai->driver->id) { @@ -421,7 +422,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component, struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct snd_pcm_runtime *rt = substream->runtime; struct lpass_pcm_data *pcm_data = rt->private_data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); unsigned int regval; @@ -574,7 +575,7 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component, struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct snd_pcm_runtime *rt = substream->runtime; struct lpass_pcm_data *pcm_data = rt->private_data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; unsigned int reg; int ret; struct regmap *map; @@ -602,7 +603,7 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component, struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct snd_pcm_runtime *rt = substream->runtime; struct lpass_pcm_data *pcm_data = rt->private_data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; struct lpaif_dmactl *dmactl; struct regmap *map; int ret, id, ch, dir = substream->stream; @@ -665,7 +666,7 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct snd_pcm_runtime *rt = substream->runtime; struct lpass_pcm_data *pcm_data = rt->private_data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; struct lpaif_dmactl *dmactl; struct regmap *map; int ret, ch, id; @@ -864,7 +865,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct snd_pcm_runtime *rt = substream->runtime; struct lpass_pcm_data *pcm_data = rt->private_data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; unsigned int base_addr, curr_addr; int ret, ch, dir = substream->stream; struct regmap *map; @@ -928,7 +929,7 @@ static irqreturn_t lpass_dma_interrupt_handler( { struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; irqreturn_t ret = IRQ_NONE; int rv; unsigned int reg, val, mask; @@ -1020,7 +1021,7 @@ static irqreturn_t lpass_dma_interrupt_handler( static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) { struct lpass_data *drvdata = data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; unsigned int irqs; int rv, chan; @@ -1048,7 +1049,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data) { struct lpass_data *drvdata = data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; unsigned int irqs; int rv, chan; @@ -1078,7 +1079,7 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data) static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data) { struct lpass_data *drvdata = data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; unsigned int irqs; irqreturn_t rv; int chan; @@ -1103,7 +1104,7 @@ static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data) static irqreturn_t lpass_platform_vaif_irq(int irq, void *data) { struct lpass_data *drvdata = data; - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; unsigned int irqs; irqreturn_t rv; int chan; @@ -1268,7 +1269,7 @@ static const struct snd_soc_component_driver lpass_component_driver = { int asoc_qcom_lpass_platform_register(struct platform_device *pdev) { struct lpass_data *drvdata = platform_get_drvdata(pdev); - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int ret; drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); @@ -1383,4 +1384,4 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev) EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register); MODULE_DESCRIPTION("QTi LPASS Platform Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index d16c0d83aaad..fbead6af3d95 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -76,7 +76,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { static int sc7180_lpass_alloc_dma_channel(struct lpass_data *drvdata, int direction, unsigned int dai_id) { - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int chan = 0; if (dai_id == LPASS_DP_RX) { @@ -123,7 +123,7 @@ static int sc7180_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, u static int sc7180_lpass_init(struct platform_device *pdev) { struct lpass_data *drvdata = platform_get_drvdata(pdev); - struct lpass_variant *variant = drvdata->variant; + const struct lpass_variant *variant = drvdata->variant; struct device *dev = &pdev->dev; int ret, i; @@ -179,7 +179,7 @@ static const struct dev_pm_ops sc7180_lpass_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(sc7180_lpass_dev_suspend, sc7180_lpass_dev_resume) }; -static struct lpass_variant sc7180_data = { +static const struct lpass_variant sc7180_data = { .i2sctrl_reg_base = 0x1000, .i2sctrl_reg_stride = 0x1000, .i2s_ports = 3, @@ -322,4 +322,4 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = { module_platform_driver(sc7180_lpass_cpu_platform_driver); MODULE_DESCRIPTION("SC7180 LPASS CPU DRIVER"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c index 6b2eb25ed939..7cd3e291382a 100644 --- a/sound/soc/qcom/lpass-sc7280.c +++ b/sound/soc/qcom/lpass-sc7280.c @@ -110,7 +110,7 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { static int sc7280_lpass_alloc_dma_channel(struct lpass_data *drvdata, int direction, unsigned int dai_id) { - struct lpass_variant *v = drvdata->variant; + const struct lpass_variant *v = drvdata->variant; int chan = 0; switch (dai_id) { @@ -196,7 +196,7 @@ static int sc7280_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, u static int sc7280_lpass_init(struct platform_device *pdev) { struct lpass_data *drvdata = platform_get_drvdata(pdev); - struct lpass_variant *variant = drvdata->variant; + const struct lpass_variant *variant = drvdata->variant; struct device *dev = &pdev->dev; int ret, i; @@ -252,7 +252,7 @@ static const struct dev_pm_ops sc7280_lpass_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(sc7280_lpass_dev_suspend, sc7280_lpass_dev_resume) }; -static struct lpass_variant sc7280_data = { +static const struct lpass_variant sc7280_data = { .i2sctrl_reg_base = 0x1000, .i2sctrl_reg_stride = 0x1000, .i2s_ports = 3, diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index bdfe66ec3314..27a2bf9a6613 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -139,7 +139,7 @@ struct lpass_data { int vaif_irq; /* SOC specific variations in the LPASS IP integration */ - struct lpass_variant *variant; + const struct lpass_variant *variant; /* bit map to keep track of static channel allocations */ unsigned long dma_ch_bit_map; @@ -398,8 +398,8 @@ struct lpass_pcm_data { }; /* register the platform driver from the CPU DAI driver */ -int asoc_qcom_lpass_platform_register(struct platform_device *); -int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); +int asoc_qcom_lpass_platform_register(struct platform_device *pdev); +void asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 3963bf234664..26b7c55c9c11 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-q6dsp-common-objs := q6dsp-common.o q6dsp-lpass-ports.o q6dsp-lpass-clocks.o -snd-q6apm-objs := q6apm.o audioreach.o topology.o +snd-q6dsp-common-y := q6dsp-common.o q6dsp-lpass-ports.o q6dsp-lpass-clocks.o +snd-q6apm-y := q6apm.o audioreach.o topology.o obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += snd-q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index 5974c7929dd3..4ebaaf736fb9 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -267,6 +267,22 @@ void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token } EXPORT_SYMBOL_GPL(audioreach_alloc_apm_cmd_pkt); +void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels) +{ + if (num_channels == 1) { + ch_map[0] = PCM_CHANNEL_FL; + } else if (num_channels == 2) { + ch_map[0] = PCM_CHANNEL_FL; + ch_map[1] = PCM_CHANNEL_FR; + } else if (num_channels == 4) { + ch_map[0] = PCM_CHANNEL_FL; + ch_map[1] = PCM_CHANNEL_FR; + ch_map[2] = PCM_CHANNEL_LS; + ch_map[3] = PCM_CHANNEL_RS; + } +} +EXPORT_SYMBOL_GPL(audioreach_set_default_channel_mapping); + static void apm_populate_container_config(struct apm_container_obj *cfg, struct audioreach_container *cont) { @@ -804,7 +820,7 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, uint32_t num_channels = cfg->num_channels; int payload_size; struct gpr_pkt *pkt; - int rc; + int rc, i; void *p; payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) + @@ -827,13 +843,8 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, media_format->sample_rate = cfg->sample_rate; media_format->bit_width = cfg->bit_width; media_format->num_channels = cfg->num_channels; - - if (num_channels == 1) { - media_format->channel_mapping[0] = PCM_CHANNEL_L; - } else if (num_channels == 2) { - media_format->channel_mapping[0] = PCM_CHANNEL_L; - media_format->channel_mapping[1] = PCM_CHANNEL_R; - } + for (i = 0; i < num_channels; i++) + media_format->channel_mapping[i] = cfg->channel_map[i]; rc = q6apm_send_cmd_sync(graph->apm, pkt, 0); @@ -863,13 +874,6 @@ static int audioreach_set_compr_media_format(struct media_format *media_fmt_hdr, mp3_cfg->q_factor = mcfg->bit_width - 1; mp3_cfg->endianness = PCM_LITTLE_ENDIAN; mp3_cfg->num_channels = mcfg->num_channels; - - if (mcfg->num_channels == 1) { - mp3_cfg->channel_mapping[0] = PCM_CHANNEL_L; - } else if (mcfg->num_channels == 2) { - mp3_cfg->channel_mapping[0] = PCM_CHANNEL_L; - mp3_cfg->channel_mapping[1] = PCM_CHANNEL_R; - } break; case SND_AUDIOCODEC_AAC: media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED; @@ -1057,7 +1061,7 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, int rc, payload_size; struct gpr_pkt *pkt; - if (num_channels > 2) { + if (num_channels > 4) { dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels); return -EINVAL; } @@ -1088,14 +1092,7 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, media_cfg->num_channels = mcfg->num_channels; media_cfg->q_factor = mcfg->bit_width - 1; media_cfg->bits_per_sample = mcfg->bit_width; - - if (num_channels == 1) { - media_cfg->channel_mapping[0] = PCM_CHANNEL_L; - } else if (num_channels == 2) { - media_cfg->channel_mapping[0] = PCM_CHANNEL_L; - media_cfg->channel_mapping[1] = PCM_CHANNEL_R; - - } + memcpy(media_cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); rc = q6apm_send_cmd_sync(graph->apm, pkt, 0); @@ -1116,7 +1113,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, struct gpr_pkt *pkt; void *p; - if (num_channels > 2) { + if (num_channels > 4) { dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels); return -EINVAL; } @@ -1152,13 +1149,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, cfg->q_factor = mcfg->bit_width - 1; cfg->endianness = PCM_LITTLE_ENDIAN; cfg->num_channels = mcfg->num_channels; - - if (mcfg->num_channels == 1) - cfg->channel_mapping[0] = PCM_CHANNEL_L; - else if (num_channels == 2) { - cfg->channel_mapping[0] = PCM_CHANNEL_L; - cfg->channel_mapping[1] = PCM_CHANNEL_R; - } + memcpy(cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); } else { rc = audioreach_set_compr_media_format(header, p, mcfg); if (rc) { diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index e38111ffd7b9..61a69df4f50f 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -158,8 +158,6 @@ struct param_id_enc_bitrate_param { #define MEDIA_FMT_ID_PCM 0x09001000 #define MEDIA_FMT_ID_MP3 0x09001009 -#define PCM_CHANNEL_L 1 -#define PCM_CHANNEL_R 2 #define SAMPLE_RATE_48K 48000 #define BIT_WIDTH_16 16 @@ -757,7 +755,6 @@ struct audioreach_module_config { u16 data_format; u16 num_channels; - u16 active_channels_mask; u16 dp_idx; u32 channel_allocation; u32 sd_line_mask; @@ -769,6 +766,7 @@ struct audioreach_module_config { /* Packet Allocation routines */ void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token); +void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels); void *audioreach_alloc_cmd_pkt(int payload_size, uint32_t opcode, uint32_t token, uint32_t src_port, uint32_t dest_port); diff --git a/sound/soc/qcom/qdsp6/q6afe-clocks.c b/sound/soc/qcom/qdsp6/q6afe-clocks.c index 1ccab64ff00b..84b9018c36ba 100644 --- a/sound/soc/qcom/qdsp6/q6afe-clocks.c +++ b/sound/soc/qcom/qdsp6/q6afe-clocks.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2020, Linaro Limited +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/err.h> #include <linux/init.h> #include <linux/clk-provider.h> diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index 3faa7e0eb0dd..7d9628cda875 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -2,6 +2,7 @@ // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. // Copyright (c) 2018, Linaro Limited +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/err.h> #include <linux/init.h> #include <linux/module.h> @@ -171,8 +172,8 @@ static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai, } static int q6tdm_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -249,8 +250,10 @@ static int q6tdm_hw_params(struct snd_pcm_substream *substream, } static int q6dma_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_ch_mask, - unsigned int rx_num, unsigned int *rx_ch_mask) + unsigned int tx_num, + const unsigned int *tx_ch_mask, + unsigned int rx_num, + const unsigned int *rx_ch_mask) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -406,8 +409,10 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream, } static int q6slim_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) + unsigned int tx_num, + const unsigned int *tx_slot, + unsigned int rx_num, + const unsigned int *rx_slot) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id]; diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 919e326b9462..ef7557be5d66 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -2,6 +2,7 @@ // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. // Copyright (c) 2018, Linaro Limited +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/uaccess.h> @@ -552,13 +553,13 @@ struct q6afe_port { }; struct afe_cmd_remote_lpass_core_hw_vote_request { - uint32_t hw_block_id; - char client_name[8]; + uint32_t hw_block_id; + char client_name[8]; } __packed; struct afe_cmd_remote_lpass_core_hw_devote_request { - uint32_t hw_block_id; - uint32_t client_handle; + uint32_t hw_block_id; + uint32_t client_handle; } __packed; diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index 30fd77e2f458..65d0676075e1 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -3,8 +3,6 @@ #ifndef __Q6AFE_H__ #define __Q6AFE_H__ -#include <dt-bindings/sound/qcom,q6afe.h> - #define AFE_PORT_MAX 129 #define MSM_AFE_PORT_TYPE_RX 0 diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index 739856a00017..c9404b5934c7 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -4,6 +4,7 @@ #include <linux/init.h> #include <linux/err.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <sound/soc.h> @@ -12,7 +13,6 @@ #include <sound/pcm.h> #include <asm/dma.h> #include <linux/dma-mapping.h> -#include <linux/of_device.h> #include <sound/pcm_params.h> #include "q6apm.h" @@ -70,14 +70,10 @@ struct q6apm_dai_rtd { unsigned int bytes_received; unsigned int copied_total; uint16_t bits_per_sample; - uint16_t source; /* Encoding source bit mask */ - uint16_t session_id; bool next_track; enum stream_state state; struct q6apm_graph *graph; spinlock_t lock; - uint32_t initial_samples_drop; - uint32_t trailing_samples_drop; bool notify_on_drain; }; @@ -85,7 +81,7 @@ struct q6apm_dai_data { long long sid; }; -static struct snd_pcm_hardware q6apm_dai_hardware_capture = { +static const struct snd_pcm_hardware q6apm_dai_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | @@ -104,7 +100,7 @@ static struct snd_pcm_hardware q6apm_dai_hardware_capture = { .fifo_size = 0, }; -static struct snd_pcm_hardware q6apm_dai_hardware_playback = { +static const struct snd_pcm_hardware q6apm_dai_hardware_playback = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | @@ -123,7 +119,7 @@ static struct snd_pcm_hardware q6apm_dai_hardware_playback = { .fifo_size = 0, }; -static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) +static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *priv) { struct q6apm_dai_rtd *prtd = priv; struct snd_pcm_substream *substream = prtd->substream; @@ -134,7 +130,7 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo prtd->state = Q6APM_STREAM_STOPPED; break; case APM_CLIENT_EVENT_DATA_WRITE_DONE: - spin_lock_irqsave(&prtd->lock, flags); + spin_lock_irqsave(&prtd->lock, flags); prtd->pos += prtd->pcm_count; spin_unlock_irqrestore(&prtd->lock, flags); snd_pcm_period_elapsed(substream); @@ -143,7 +139,7 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo break; case APM_CLIENT_EVENT_DATA_READ_DONE: - spin_lock_irqsave(&prtd->lock, flags); + spin_lock_irqsave(&prtd->lock, flags); prtd->pos += prtd->pcm_count; spin_unlock_irqrestore(&prtd->lock, flags); snd_pcm_period_elapsed(substream); @@ -157,7 +153,7 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo } static void event_handler_compr(uint32_t opcode, uint32_t token, - uint32_t *payload, void *priv) + void *payload, void *priv) { struct q6apm_dai_rtd *prtd = priv; struct snd_compr_stream *substream = prtd->cstream; @@ -243,6 +239,7 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, cfg.num_channels = runtime->channels; cfg.bit_width = prtd->bits_per_sample; cfg.fmt = SND_AUDIOCODEC_PCM; + audioreach_set_default_channel_mapping(cfg.channel_map, runtime->channels); if (prtd->state) { /* clear the previous setup if any */ @@ -331,7 +328,7 @@ static int q6apm_dai_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; + struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0); struct device *dev = component->dev; struct q6apm_dai_data *pdata; @@ -352,7 +349,7 @@ static int q6apm_dai_open(struct snd_soc_component *component, spin_lock_init(&prtd->lock); prtd->substream = substream; - prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler, prtd, graph_id); + prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id); if (IS_ERR(prtd->graph)) { dev_err(dev, "%s: Could not allocate memory\n", __func__); ret = PTR_ERR(prtd->graph); @@ -496,7 +493,7 @@ static int q6apm_dai_compr_open(struct snd_soc_component *component, return -ENOMEM; prtd->cstream = stream; - prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler_compr, prtd, graph_id); + prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id); if (IS_ERR(prtd->graph)) { ret = PTR_ERR(prtd->graph); kfree(prtd); @@ -669,6 +666,8 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component, cfg.num_channels = 2; cfg.bit_width = prtd->bits_per_sample; cfg.fmt = codec->id; + audioreach_set_default_channel_mapping(cfg.channel_map, + cfg.num_channels); memcpy(&cfg.codec, codec, sizeof(*codec)); ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); @@ -720,14 +719,12 @@ static int q6apm_dai_compr_set_metadata(struct snd_soc_component *component, switch (metadata->key) { case SNDRV_COMPRESS_ENCODER_PADDING: - prtd->trailing_samples_drop = metadata->value[0]; q6apm_remove_trailing_silence(component->dev, prtd->graph, - prtd->trailing_samples_drop); + metadata->value[0]); break; case SNDRV_COMPRESS_ENCODER_DELAY: - prtd->initial_samples_drop = metadata->value[0]; q6apm_remove_initial_silence(component->dev, prtd->graph, - prtd->initial_samples_drop); + metadata->value[0]); break; default: ret = -EINVAL; diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index 6511f0a08de1..9c98a35ad099 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2021, Linaro Limited +#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h> #include <linux/err.h> #include <linux/init.h> #include <linux/module.h> @@ -24,13 +25,15 @@ struct q6apm_lpass_dai_data { }; static int q6dma_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_ch_mask, - unsigned int rx_num, unsigned int *rx_ch_mask) + unsigned int tx_num, + const unsigned int *tx_ch_mask, + unsigned int rx_num, + const unsigned int *rx_ch_mask) { struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); struct audioreach_module_config *cfg = &dai_data->module_config[dai->id]; - int ch_mask; + int i; switch (dai->id) { case WSA_CODEC_DMA_TX_0: @@ -55,7 +58,8 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai, tx_num); return -EINVAL; } - ch_mask = *tx_ch_mask; + for (i = 0; i < tx_num; i++) + cfg->channel_map[i] = tx_ch_mask[i]; break; case WSA_CODEC_DMA_RX_0: @@ -78,7 +82,8 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai, rx_num); return -EINVAL; } - ch_mask = *rx_ch_mask; + for (i = 0; i < rx_num; i++) + cfg->channel_map[i] = rx_ch_mask[i]; break; default: @@ -87,8 +92,6 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai, return -EINVAL; } - cfg->active_channels_mask = ch_mask; - return 0; } @@ -97,12 +100,13 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream, { struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); struct audioreach_module_config *cfg = &dai_data->module_config[dai->id]; - int channels = params_channels(params); + int channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max; int ret; cfg->bit_width = params_width(params); cfg->sample_rate = params_rate(params); cfg->num_channels = channels; + audioreach_set_default_channel_mapping(cfg->channel_map, channels); switch (dai->id) { case DISPLAY_PORT_RX_0: @@ -127,10 +131,12 @@ static int q6dma_hw_params(struct snd_pcm_substream *substream, { struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); struct audioreach_module_config *cfg = &dai_data->module_config[dai->id]; + int channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max; cfg->bit_width = params_width(params); cfg->sample_rate = params_rate(params); - cfg->num_channels = params_channels(params); + cfg->num_channels = channels; + audioreach_set_default_channel_mapping(cfg->channel_map, channels); return 0; } diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h index f486bd639b9f..c248c8d2b1ab 100644 --- a/sound/soc/qcom/qdsp6/q6apm.h +++ b/sound/soc/qcom/qdsp6/q6apm.h @@ -13,7 +13,6 @@ #include <linux/of_platform.h> #include <linux/jiffies.h> #include <linux/soc/qcom/apr.h> -#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h> #include "audioreach.h" #define APM_PORT_MAX 127 diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 5e14cd0a38de..045100c94352 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -2,9 +2,11 @@ // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. // Copyright (c) 2018, Linaro Limited +#include <dt-bindings/sound/qcom,q6asm.h> #include <linux/init.h> #include <linux/err.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <sound/soc.h> @@ -14,7 +16,6 @@ #include <sound/compress_driver.h> #include <asm/dma.h> #include <linux/dma-mapping.h> -#include <linux/of_device.h> #include <sound/pcm_params.h> #include "q6asm.h" #include "q6routing.h" @@ -102,7 +103,7 @@ static const struct snd_pcm_hardware q6asm_dai_hardware_capture = { .fifo_size = 0, }; -static struct snd_pcm_hardware q6asm_dai_hardware_playback = { +static const struct snd_pcm_hardware q6asm_dai_hardware_playback = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | @@ -127,8 +128,13 @@ static struct snd_pcm_hardware q6asm_dai_hardware_playback = { #define Q6ASM_FEDAI_DRIVER(num) { \ .playback = { \ .stream_name = "MultiMedia"#num" Playback", \ - .rates = (SNDRV_PCM_RATE_8000_192000| \ - SNDRV_PCM_RATE_KNOT), \ + .rates = (SNDRV_PCM_RATE_8000_48000 | \ + SNDRV_PCM_RATE_12000 | \ + SNDRV_PCM_RATE_24000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000), \ .formats = (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE), \ .channels_min = 1, \ @@ -138,8 +144,9 @@ static struct snd_pcm_hardware q6asm_dai_hardware_playback = { }, \ .capture = { \ .stream_name = "MultiMedia"#num" Capture", \ - .rates = (SNDRV_PCM_RATE_8000_48000| \ - SNDRV_PCM_RATE_KNOT), \ + .rates = (SNDRV_PCM_RATE_8000_48000 | \ + SNDRV_PCM_RATE_12000 | \ + SNDRV_PCM_RATE_24000), \ .formats = (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE), \ .channels_min = 1, \ @@ -151,18 +158,6 @@ static struct snd_pcm_hardware q6asm_dai_hardware_playback = { .id = MSM_FRONTEND_DAI_MULTIMEDIA##num, \ } -/* Conventional and unconventional sample rate supported */ -static unsigned int supported_sample_rates[] = { - 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, - 88200, 96000, 176400, 192000 -}; - -static struct snd_pcm_hw_constraint_list constraints_sample_rates = { - .count = ARRAY_SIZE(supported_sample_rates), - .list = supported_sample_rates, - .mask = 0, -}; - static const struct snd_compr_codec_caps q6asm_compr_caps = { .num_descriptors = 1, .descriptor[0].max_ch = 2, @@ -389,11 +384,6 @@ static int q6asm_dai_open(struct snd_soc_component *component, else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) runtime->hw = q6asm_dai_hardware_capture; - ret = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_sample_rates); - if (ret < 0) - dev_info(dev, "snd_pcm_hw_constraint_list failed\n"); /* Ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index 195780f75d05..06a802f9dba5 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -2,6 +2,7 @@ // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. // Copyright (c) 2018, Linaro Limited +#include <dt-bindings/sound/qcom,q6asm.h> #include <linux/mutex.h> #include <linux/wait.h> #include <linux/module.h> diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h index 394604c34943..519e1b3a3f7c 100644 --- a/sound/soc/qcom/qdsp6/q6asm.h +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -2,7 +2,6 @@ #ifndef __Q6_ASM_H__ #define __Q6_ASM_H__ #include "q6dsp-common.h" -#include <dt-bindings/sound/qcom,q6asm.h> /* ASM client callback events */ #define CMD_PAUSE 0x0001 @@ -36,16 +35,16 @@ enum { #define ASM_LAST_BUFFER_FLAG BIT(30) struct q6asm_flac_cfg { - u32 sample_rate; - u32 ext_sample_rate; - u32 min_frame_size; - u32 max_frame_size; - u16 stream_info_present; - u16 min_blk_size; - u16 max_blk_size; - u16 ch_cfg; - u16 sample_size; - u16 md5_sum; + u32 sample_rate; + u32 ext_sample_rate; + u32 min_frame_size; + u32 max_frame_size; + u16 stream_info_present; + u16 min_blk_size; + u16 max_blk_size; + u16 ch_cfg; + u16 sample_size; + u16 md5_sum; }; struct q6asm_wma_cfg { diff --git a/sound/soc/qcom/qdsp6/q6dsp-common.c b/sound/soc/qcom/qdsp6/q6dsp-common.c index 95585dea2b36..f74585d88bd6 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-common.c +++ b/sound/soc/qcom/qdsp6/q6dsp-common.c @@ -98,4 +98,6 @@ int q6dsp_get_channel_allocation(int channels) return channel_allocation; } EXPORT_SYMBOL_GPL(q6dsp_get_channel_allocation); + +MODULE_DESCRIPTION("ASoC MSM QDSP6 helper functions"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c index 4613867d1133..e758411603be 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c @@ -8,7 +8,6 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/slab.h> #include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h> #include "q6dsp-lpass-clocks.h" diff --git a/sound/soc/qcom/qdsp6/q6prm-clocks.c b/sound/soc/qcom/qdsp6/q6prm-clocks.c index 73b0cbac73d4..4c574b48ab00 100644 --- a/sound/soc/qcom/qdsp6/q6prm-clocks.c +++ b/sound/soc/qcom/qdsp6/q6prm-clocks.c @@ -1,13 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2021, Linaro Limited +#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h> #include <linux/err.h> #include <linux/init.h> #include <linux/clk-provider.h> #include <linux/module.h> #include <linux/device.h> #include <linux/platform_device.h> -#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h> #include "q6dsp-lpass-clocks.h" #include "q6prm.h" diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index c583faae3a3e..90228699ba7d 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -2,14 +2,15 @@ // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. // Copyright (c) 2018, Linaro Limited +#include <dt-bindings/sound/qcom,q6asm.h> +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/init.h> #include <linux/err.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> -#include <linux/of_platform.h> #include <linux/bitops.h> #include <linux/mutex.h> -#include <linux/of_device.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/soc.h> @@ -1160,7 +1161,7 @@ static struct platform_driver q6pcm_routing_platform_driver = { .of_match_table = of_match_ptr(q6pcm_routing_device_id), }, .probe = q6pcm_routing_probe, - .remove_new = q6pcm_routing_remove, + .remove = q6pcm_routing_remove, }; module_platform_driver(q6pcm_routing_platform_driver); diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c index 130b22a34fb3..83319a928f29 100644 --- a/sound/soc/qcom/qdsp6/topology.c +++ b/sound/soc/qcom/qdsp6/topology.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2020, Linaro Limited +#include <linux/cleanup.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/pcm.h> @@ -545,6 +546,7 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap if (mod) { int pn, id = 0; + mod->module_id = module_id; mod->max_ip_port = max_ip_port; mod->max_op_port = max_op_port; @@ -729,6 +731,29 @@ static int audioreach_widget_i2s_module_load(struct audioreach_module *mod, return 0; } +static int audioreach_widget_dp_module_load(struct audioreach_module *mod, + struct snd_soc_tplg_vendor_array *mod_array) +{ + struct snd_soc_tplg_vendor_value_elem *mod_elem; + int tkn_count = 0; + + mod_elem = mod_array->value; + + while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { + switch (le32_to_cpu(mod_elem->token)) { + case AR_TKN_U32_MODULE_FMT_DATA: + mod->data_format = le32_to_cpu(mod_elem->value); + break; + default: + break; + } + tkn_count++; + mod_elem++; + } + + return 0; +} + static int audioreach_widget_load_buffer(struct snd_soc_component *component, int index, struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w) @@ -759,6 +784,9 @@ static int audioreach_widget_load_buffer(struct snd_soc_component *component, case MODULE_ID_I2S_SOURCE: audioreach_widget_i2s_module_load(mod, mod_array); break; + case MODULE_ID_DISPLAY_PORT_SINK: + audioreach_widget_dp_module_load(mod, mod_array); + break; default: return -EINVAL; } @@ -1239,7 +1267,7 @@ static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = { audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw}, }; -static struct snd_soc_tplg_ops audioreach_tplg_ops = { +static const struct snd_soc_tplg_ops audioreach_tplg_ops = { .io_ops = audioreach_io_ops, .io_ops_count = ARRAY_SIZE(audioreach_io_ops), @@ -1261,18 +1289,19 @@ int audioreach_tplg_init(struct snd_soc_component *component) struct snd_soc_card *card = component->card; struct device *dev = component->dev; const struct firmware *fw; - char *tplg_fw_name; int ret; /* Inline with Qualcomm UCM configs and linux-firmware path */ - tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name); + char *tplg_fw_name __free(kfree) = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", + card->driver_name, + card->name); if (!tplg_fw_name) return -ENOMEM; ret = request_firmware(&fw, tplg_fw_name, dev); if (ret < 0) { - dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret); - goto err; + dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret); + return ret; } ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw); @@ -1282,8 +1311,6 @@ int audioreach_tplg_init(struct snd_soc_component *component) } release_firmware(fw); -err: - kfree(tplg_fw_name); return ret; } diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index d1fd40e3f7a9..bc030ce29680 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -5,10 +5,10 @@ // sc7180.c -- ALSA SoC Machine driver for SC7180 #include <dt-bindings/sound/sc7180-lpass.h> -#include <linux/gpio.h> +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/gpio/consumer.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <sound/core.h> #include <sound/jack.h> @@ -19,9 +19,10 @@ #include "../codecs/rt5682.h" #include "../codecs/rt5682s.h" #include "common.h" -#include "lpass.h" +#include "qdsp6/q6afe.h" #define DEFAULT_MCLK_RATE 19200000 +#define MI2S_BCLK_RATE 1536000 #define RT5682_PLL1_FREQ (48000 * 512) #define DRIVER_NAME "SC7180" @@ -134,12 +135,28 @@ static int sc7180_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int sc7180_snd_startup(struct snd_pcm_substream *substream) +static int sc7180_qdsp_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_card *card = rtd->card; - struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + return sc7180_headset_init(rtd); + case PRIMARY_MI2S_TX: + case TERTIARY_MI2S_RX: + return 0; + case DISPLAY_PORT_RX: + return sc7180_hdmi_init(rtd); + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + return -EINVAL; + } + return 0; +} + +static int sc7180_startup_realtek_codec(struct snd_soc_pcm_runtime *rtd) +{ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int pll_id, pll_source, pll_in, pll_out, clk_id, ret; @@ -155,8 +172,40 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) clk_id = RT5682S_SCLK_S_PLL2; pll_out = RT5682_PLL1_FREQ; pll_in = DEFAULT_MCLK_RATE; + } else { + return 0; + } + snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_BC_FC | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S); + + /* Configure PLL1 for codec */ + ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, + pll_in, pll_out); + if (ret) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; } + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out, + SND_SOC_CLOCK_IN); + if (ret) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", + ret); + + return ret; +} + +static int sc7180_snd_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + int ret; + switch (cpu_dai->id) { case MI2S_PRIMARY: if (++data->pri_mi2s_clk_count == 1) { @@ -166,30 +215,66 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) SNDRV_PCM_STREAM_PLAYBACK); } - snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_BC_FC | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_I2S); - - /* Configure PLL1 for codec */ - ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, - pll_in, pll_out); - if (ret) { - dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + ret = sc7180_startup_realtek_codec(rtd); + if (ret) return ret; + + break; + case MI2S_SECONDARY: + break; + case LPASS_DP_RX: + break; + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + return -EINVAL; + } + return 0; +} + +static int sc7180_qdsp_snd_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int ret; + + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + case PRIMARY_MI2S_TX: + if (++data->pri_mi2s_clk_count == 1) { + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_MCLK_1, + DEFAULT_MCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + MI2S_BCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); } - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out, - SND_SOC_CLOCK_IN); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); + + ret = sc7180_startup_realtek_codec(rtd); if (ret) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", - ret); + return ret; break; - case MI2S_SECONDARY: + case TERTIARY_MI2S_RX: + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, + MI2S_BCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); + + snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_BC_FC | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); break; - case LPASS_DP_RX: + case DISPLAY_PORT_RX: break; default: dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, @@ -222,7 +307,7 @@ static int dmic_set(struct snd_kcontrol *kcontrol, static void sc7180_snd_shutdown(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); @@ -247,6 +332,42 @@ static void sc7180_snd_shutdown(struct snd_pcm_substream *substream) } } +static void sc7180_qdsp_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + case PRIMARY_MI2S_TX: + if (--data->pri_mi2s_clk_count == 0) { + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_MCLK_1, + 0, + SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + 0, + SNDRV_PCM_STREAM_PLAYBACK); + } + break; + case TERTIARY_MI2S_RX: + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, + 0, + SNDRV_PCM_STREAM_PLAYBACK); + break; + case DISPLAY_PORT_RX: + break; + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + break; + } +} + static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); @@ -268,7 +389,7 @@ static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd) static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct snd_pcm_runtime *runtime = substream->runtime; @@ -295,11 +416,30 @@ static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream) return 0; } +static int sc7180_qdsp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + return 0; +} + static const struct snd_soc_ops sc7180_ops = { .startup = sc7180_snd_startup, .shutdown = sc7180_snd_shutdown, }; +static const struct snd_soc_ops sc7180_qdsp_ops = { + .startup = sc7180_qdsp_snd_startup, + .shutdown = sc7180_qdsp_snd_shutdown, +}; + static const struct snd_soc_ops sc7180_adau7002_ops = { .startup = sc7180_adau7002_snd_startup, }; @@ -355,7 +495,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) struct snd_soc_dai_link *link; int ret; int i; - bool no_headphone = false; + bool qdsp = false, no_headphone = false; /* Allocate the private data */ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); @@ -391,6 +531,8 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) no_headphone = true; card->dapm_widgets = sc7180_adau7002_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sc7180_adau7002_snd_widgets); + } else if (of_device_is_compatible(dev->of_node, "qcom,sc7180-qdsp6-sndcard")) { + qdsp = true; } ret = qcom_snd_parse_of(card); @@ -401,6 +543,12 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) if (no_headphone) { link->ops = &sc7180_adau7002_ops; link->init = sc7180_adau7002_init; + } else if (qdsp) { + if (link->no_pcm == 1) { + link->ops = &sc7180_qdsp_ops; + link->be_hw_params_fixup = sc7180_qdsp_be_hw_params_fixup; + link->init = sc7180_qdsp_init; + } } else { link->ops = &sc7180_ops; link->init = sc7180_init; @@ -413,6 +561,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) static const struct of_device_id sc7180_snd_device_id[] = { {.compatible = "google,sc7180-trogdor"}, {.compatible = "google,sc7180-coachz"}, + {.compatible = "qcom,sc7180-qdsp6-sndcard"}, {}, }; MODULE_DEVICE_TABLE(of, sc7180_snd_device_id); @@ -428,4 +577,4 @@ static struct platform_driver sc7180_snd_driver = { module_platform_driver(sc7180_snd_driver); MODULE_DESCRIPTION("sc7180 ASoC Machine Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c index c23df4c8f341..230af8d7b205 100644 --- a/sound/soc/qcom/sc7280.c +++ b/sound/soc/qcom/sc7280.c @@ -4,9 +4,11 @@ // // ALSA SoC Machine driver for sc7280 +#include <dt-bindings/sound/qcom,lpass.h> +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/input.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <sound/core.h> #include <sound/jack.h> @@ -21,6 +23,7 @@ #include "common.h" #include "lpass.h" #include "qdsp6/q6afe.h" +#include "sdw.h" #define DEFAULT_MCLK_RATE 19200000 #define RT5682_PLL_FREQ (48000 * 512) @@ -203,7 +206,7 @@ static int sc7280_snd_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); @@ -235,7 +238,7 @@ static int sc7280_snd_hw_params(struct snd_pcm_substream *substream, static int sc7280_snd_swr_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -266,7 +269,7 @@ static int sc7280_snd_swr_prepare(struct snd_pcm_substream *substream) static int sc7280_snd_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); switch (cpu_dai->id) { @@ -285,7 +288,7 @@ static int sc7280_snd_prepare(struct snd_pcm_substream *substream) static int sc7280_snd_hw_free(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card); const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -310,10 +313,11 @@ static int sc7280_snd_hw_free(struct snd_pcm_substream *substream) static void sc7280_snd_shutdown(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; switch (cpu_dai->id) { case MI2S_PRIMARY: @@ -331,13 +335,16 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream) default: break; } + + data->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); } static int sc7280_snd_startup(struct snd_pcm_substream *substream) { unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret = 0; @@ -345,6 +352,8 @@ static int sc7280_snd_startup(struct snd_pcm_substream *substream) switch (cpu_dai->id) { case MI2S_PRIMARY: ret = sc7280_rt5682_init(rtd); + if (ret) + return ret; break; case SECONDARY_MI2S_RX: codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; @@ -358,7 +367,8 @@ static int sc7280_snd_startup(struct snd_pcm_substream *substream) default: break; } - return ret; + + return qcom_snd_sdw_startup(substream); } static const struct snd_soc_ops sc7280_ops = { diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 6e5f194bc34b..922ecada1cd8 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022, Linaro Limited +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/of_device.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/pcm.h> @@ -14,21 +14,22 @@ #include "common.h" #include "sdw.h" -#define DRIVER_NAME "sc8280xp" - struct sc8280xp_snd_data { bool stream_prepared[AFE_PORT_MAX]; struct snd_soc_card *card; struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; struct snd_soc_jack jack; + struct snd_soc_jack dp_jack[8]; bool jack_setup; }; static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) { struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_card *card = rtd->card; + struct snd_soc_jack *dp_jack = NULL; + int dp_pcm_id = 0; switch (cpu_dai->id) { case WSA_CODEC_DMA_RX_0: @@ -43,13 +44,36 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) snd_soc_limit_volume(card, "SpkrLeft PA Volume", 17); snd_soc_limit_volume(card, "SpkrRight PA Volume", 17); break; + case DISPLAY_PORT_RX_0: + /* DISPLAY_PORT dai ids are not contiguous */ + dp_pcm_id = 0; + dp_jack = &data->dp_jack[dp_pcm_id]; + break; + case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7: + dp_pcm_id = cpu_dai->id - DISPLAY_PORT_RX_1 + 1; + dp_jack = &data->dp_jack[dp_pcm_id]; + break; default: break; } + if (dp_jack) + return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id); + return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); } +static void sc8280xp_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = pdata->sruntime[cpu_dai->id]; + + pdata->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); +} + static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -80,7 +104,7 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static int sc8280xp_snd_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_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); @@ -89,7 +113,7 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -100,7 +124,7 @@ static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream) static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -110,6 +134,8 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream) } static const struct snd_soc_ops sc8280xp_be_ops = { + .startup = qcom_snd_sdw_startup, + .shutdown = sc8280xp_snd_shutdown, .hw_params = sc8280xp_snd_hw_params, .hw_free = sc8280xp_snd_hw_free, .prepare = sc8280xp_snd_prepare, @@ -152,13 +178,18 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) if (ret) return ret; - card->driver_name = DRIVER_NAME; + card->driver_name = of_device_get_match_data(dev); sc8280xp_add_be_ops(card); return devm_snd_soc_register_card(dev, card); } static const struct of_device_id snd_sc8280xp_dt_match[] = { - {.compatible = "qcom,sc8280xp-sndcard",}, + {.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"}, + {.compatible = "qcom,qcs6490-rb3gen2-sndcard", "qcs6490"}, + {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"}, + {.compatible = "qcom,sm8450-sndcard", "sm8450"}, + {.compatible = "qcom,sm8550-sndcard", "sm8550"}, + {.compatible = "qcom,sm8650-sndcard", "sm8650"}, {} }; @@ -174,4 +205,4 @@ static struct platform_driver snd_sc8280xp_driver = { module_platform_driver(snd_sc8280xp_driver); MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); MODULE_DESCRIPTION("SC8280XP ASoC Machine Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 25b964dea6c5..a479d7e5b7fb 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -3,9 +3,9 @@ * Copyright (c) 2018, The Linux Foundation. All rights reserved. */ +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/of_device.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -15,6 +15,7 @@ #include <uapi/linux/input-event-codes.h> #include "common.h" #include "qdsp6/q6afe.h" +#include "sdw.h" #include "../codecs/rt5663.h" #define DRIVER_NAME "sdm845" @@ -416,7 +417,7 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); break; } - return 0; + return qcom_snd_sdw_startup(substream); } static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) @@ -425,6 +426,7 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) struct snd_soc_card *card = rtd->card; struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; switch (cpu_dai->id) { case PRIMARY_MI2S_RX: @@ -463,6 +465,9 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); break; } + + data->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); } static int sdm845_snd_prepare(struct snd_pcm_substream *substream) @@ -625,4 +630,4 @@ static struct platform_driver sdm845_snd_driver = { module_platform_driver(sdm845_snd_driver); MODULE_DESCRIPTION("sdm845 ASoC Machine Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c index ce89c0a33ef0..f2eda2ff46c0 100644 --- a/sound/soc/qcom/sdw.c +++ b/sound/soc/qcom/sdw.c @@ -1,17 +1,60 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018, Linaro Limited. +// Copyright (c) 2018-2023, Linaro Limited. // Copyright (c) 2018, The Linux Foundation. All rights reserved. +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/module.h> #include <sound/soc.h> -#include "qdsp6/q6afe.h" #include "sdw.h" +/** + * qcom_snd_sdw_startup() - Helper to start Soundwire stream for SoC audio card + * @substream: The PCM substream from audio, as passed to snd_soc_ops->startup() + * + * Helper for the SoC audio card (snd_soc_ops->startup()) to allocate and set + * Soundwire stream runtime to each codec DAI. + * + * The shutdown() callback should call sdw_release_stream() on the same + * sdw_stream_runtime. + * + * Return: 0 or errno + */ +int qcom_snd_sdw_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime; + struct snd_soc_dai *codec_dai; + int ret, i; + + sruntime = sdw_alloc_stream(cpu_dai->name); + if (!sruntime) + return -ENOMEM; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + ret = snd_soc_dai_set_stream(codec_dai, sruntime, + substream->stream); + if (ret < 0 && ret != -ENOTSUPP) { + dev_err(rtd->dev, "Failed to set sdw stream on %s\n", + codec_dai->name); + goto err_set_stream; + } + } + + return 0; + +err_set_stream: + sdw_release_stream(sruntime); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_snd_sdw_startup); + int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, struct sdw_stream_runtime *sruntime, bool *stream_prepared) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); int ret; @@ -62,7 +105,7 @@ int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct sdw_stream_runtime **psruntime) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime; @@ -92,7 +135,7 @@ EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params); int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, struct sdw_stream_runtime *sruntime, bool *stream_prepared) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); switch (cpu_dai->id) { @@ -117,4 +160,5 @@ int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, return 0; } EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free); -MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm ASoC SoundWire helper functions"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/sdw.h b/sound/soc/qcom/sdw.h index d74cbb84da13..392e3455f1b1 100644 --- a/sound/soc/qcom/sdw.h +++ b/sound/soc/qcom/sdw.h @@ -6,6 +6,7 @@ #include <linux/soundwire/sdw.h> +int qcom_snd_sdw_startup(struct snd_pcm_substream *substream); int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, struct sdw_stream_runtime *runtime, bool *stream_prepared); diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 9eb8ae0196d9..19adadedc88a 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2020, Linaro Limited +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/of_device.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/pcm.h> @@ -50,11 +50,19 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) { unsigned int fmt = SND_SOC_DAIFMT_BP_FP; unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC; - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + break; case TERTIARY_MI2S_RX: codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; snd_soc_dai_set_sysclk(cpu_dai, @@ -66,13 +74,25 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) default: break; } - return 0; + + return qcom_snd_sdw_startup(substream); +} + +static void sm2450_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + + data->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); } static int sm8250_snd_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_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); @@ -81,7 +101,7 @@ static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, static int sm8250_snd_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -92,7 +112,7 @@ static int sm8250_snd_prepare(struct snd_pcm_substream *substream) static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -103,6 +123,7 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) static const struct snd_soc_ops sm8250_be_ops = { .startup = sm8250_snd_startup, + .shutdown = sm2450_snd_shutdown, .hw_params = sm8250_snd_hw_params, .hw_free = sm8250_snd_hw_free, .prepare = sm8250_snd_prepare, @@ -170,4 +191,4 @@ static struct platform_driver snd_sm8250_driver = { module_platform_driver(snd_sm8250_driver); MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); MODULE_DESCRIPTION("SM8250 ASoC Machine Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c index 553165f11d30..c8d5ac43a176 100644 --- a/sound/soc/qcom/storm.c +++ b/sound/soc/qcom/storm.c @@ -140,4 +140,4 @@ static struct platform_driver storm_platform_driver = { module_platform_driver(storm_platform_driver); MODULE_DESCRIPTION("QTi IPQ806x-based Storm Machine Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c new file mode 100644 index 000000000000..898b5c26bf1e --- /dev/null +++ b/sound/soc/qcom/x1e80100.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2023, Linaro Limited + +#include <dt-bindings/sound/qcom,q6afe.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/soundwire/sdw.h> +#include <sound/pcm.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include "common.h" +#include "qdsp6/q6afe.h" +#include "qdsp6/q6dsp-common.h" +#include "sdw.h" + +struct x1e80100_snd_data { + bool stream_prepared[AFE_PORT_MAX]; + struct snd_soc_card *card; + struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; + struct snd_soc_jack jack; + struct snd_soc_jack dp_jack[8]; + bool jack_setup; +}; + +static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_jack *dp_jack = NULL; + int dp_pcm_id = 0; + + switch (cpu_dai->id) { + case DISPLAY_PORT_RX_0: + dp_pcm_id = 0; + dp_jack = &data->dp_jack[dp_pcm_id]; + break; + case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7: + dp_pcm_id = cpu_dai->id - DISPLAY_PORT_RX_1 + 1; + dp_jack = &data->dp_jack[dp_pcm_id]; + break; + default: + break; + } + + if (dp_jack) + return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id); + + return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); +} + +static void x1e80100_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + + data->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); +} + +static int x1e80100_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = 48000; + switch (cpu_dai->id) { + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + channels->min = 1; + break; + default: + break; + } + + return 0; +} + +static int x1e80100_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + + return qcom_snd_sdw_hw_params(substream, params, &data->sruntime[cpu_dai->id]); +} + +static int x1e80100_snd_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + const unsigned int rx_slot[4] = { PCM_CHANNEL_FL, + PCM_CHANNEL_LB, + PCM_CHANNEL_FR, + PCM_CHANNEL_RB }; + int ret; + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_RX_1: + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, + ARRAY_SIZE(rx_slot), rx_slot); + if (ret) + return ret; + break; + default: + break; + } + + return qcom_snd_sdw_prepare(substream, sruntime, + &data->stream_prepared[cpu_dai->id]); +} + +static int x1e80100_snd_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + + return qcom_snd_sdw_hw_free(substream, sruntime, + &data->stream_prepared[cpu_dai->id]); +} + +static const struct snd_soc_ops x1e80100_be_ops = { + .startup = qcom_snd_sdw_startup, + .shutdown = x1e80100_snd_shutdown, + .hw_params = x1e80100_snd_hw_params, + .hw_free = x1e80100_snd_hw_free, + .prepare = x1e80100_snd_prepare, +}; + +static void x1e80100_add_be_ops(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + + for_each_card_prelinks(card, i, link) { + if (link->no_pcm == 1) { + link->init = x1e80100_snd_init; + link->be_hw_params_fixup = x1e80100_be_hw_params_fixup; + link->ops = &x1e80100_be_ops; + } + } +} + +static int x1e80100_platform_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct x1e80100_snd_data *data; + struct device *dev = &pdev->dev; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + /* Allocate the private data */ + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + card->owner = THIS_MODULE; + card->dev = dev; + dev_set_drvdata(dev, card); + snd_soc_card_set_drvdata(card, data); + + ret = qcom_snd_parse_of(card); + if (ret) + return ret; + + card->driver_name = "x1e80100"; + x1e80100_add_be_ops(card); + + return devm_snd_soc_register_card(dev, card); +} + +static const struct of_device_id snd_x1e80100_dt_match[] = { + { .compatible = "qcom,x1e80100-sndcard", }, + {} +}; +MODULE_DEVICE_TABLE(of, snd_x1e80100_dt_match); + +static struct platform_driver snd_x1e80100_driver = { + .probe = x1e80100_platform_probe, + .driver = { + .name = "snd-x1e80100", + .of_match_table = snd_x1e80100_dt_match, + }, +}; +module_platform_driver(snd_x1e80100_driver); +MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); +MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>"); +MODULE_DESCRIPTION("Qualcomm X1E80100 ASoC Machine Driver"); +MODULE_LICENSE("GPL"); |