From 9e28f6532c611c0c3fa759d2101aba9f0d41e860 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 13 Sep 2019 17:42:14 +0800 Subject: ASoC: fsl_mqs: Add MQS component driver MQS (medium quality sound), is used to generate medium quality audio via a standard digital output pin. It can be used to connect stereo speakers or headphones simply via power amplifier stages without an additional DAC chip. It only accepts 2-channel, LSB-valid 16bit, MSB shift-out first, frame sync asserting with the first bit of the frame, data shifted with the posedge of bit clock, 44.1 kHz or 48 kHz signals from SAI1 in left justified format; and it provides the SNR target as no more than 20dB for the signals below 10 kHz. The signals above 10 kHz will have worse THD+N values. MQS provides only simple audio reproduction. No internal pop, click or distortion artifact reduction methods are provided. The MQS receives the audio data from the SAI1 Tx section. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/74dfc73a92d2df4213225abe7d2a3db82672fe0f.1568367274.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 10 ++ sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_mqs.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 sound/soc/fsl/fsl_mqs.c (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index aa99c008a925..65e8cd4be930 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -25,6 +25,16 @@ config SND_SOC_FSL_SAI This option is only useful for out-of-tree drivers since in-tree drivers select it automatically. +config SND_SOC_FSL_MQS + tristate "Medium Quality Sound (MQS) module support" + depends on SND_SOC_FSL_SAI + select REGMAP_MMIO + help + Say Y if you want to add Medium Quality Sound (MQS) + support for the Freescale CPUs. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. + config SND_SOC_FSL_AUDMIX tristate "Audio Mixer (AUDMIX) module support" select REGMAP_MMIO diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index c0dd04422fe9..8cde88c72d93 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -23,6 +23,7 @@ snd-soc-fsl-esai-objs := fsl_esai.o snd-soc-fsl-micfil-objs := fsl_micfil.o snd-soc-fsl-utils-objs := fsl_utils.o snd-soc-fsl-dma-objs := fsl_dma.o +snd-soc-fsl-mqs-objs := fsl_mqs.o obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o @@ -33,6 +34,7 @@ obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o +obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o # MPC5200 Platform Support diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c new file mode 100644 index 000000000000..c1619a553514 --- /dev/null +++ b/sound/soc/fsl/fsl_mqs.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// ALSA SoC IMX MQS driver +// +// Copyright (C) 2014-2015 Freescale Semiconductor, Inc. +// Copyright 2019 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_MQS_CTRL 0x00 + +#define MQS_EN_MASK (0x1 << 28) +#define MQS_EN_SHIFT (28) +#define MQS_SW_RST_MASK (0x1 << 24) +#define MQS_SW_RST_SHIFT (24) +#define MQS_OVERSAMPLE_MASK (0x1 << 20) +#define MQS_OVERSAMPLE_SHIFT (20) +#define MQS_CLK_DIV_MASK (0xFF << 0) +#define MQS_CLK_DIV_SHIFT (0) + +/* codec private data */ +struct fsl_mqs { + struct regmap *regmap; + struct clk *mclk; + struct clk *ipg; + + unsigned int reg_iomuxc_gpr2; + unsigned int reg_mqs_ctrl; + bool use_gpr; +}; + +#define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define FSL_MQS_FORMATS SNDRV_PCM_FMTBIT_S16_LE + +static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); + unsigned long mclk_rate; + int div, res; + int bclk, lrclk; + + mclk_rate = clk_get_rate(mqs_priv->mclk); + bclk = snd_soc_params_to_bclk(params); + lrclk = params_rate(params); + + /* + * mclk_rate / (oversample(32,64) * FS * 2 * divider ) = repeat_rate; + * if repeat_rate is 8, mqs can achieve better quality. + * oversample rate is fix to 32 currently. + */ + div = mclk_rate / (32 * lrclk * 2 * 8); + res = mclk_rate % (32 * lrclk * 2 * 8); + + if (res == 0 && div > 0 && div <= 256) { + if (mqs_priv->use_gpr) { + regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, + IMX6SX_GPR2_MQS_CLK_DIV_MASK, + (div - 1) << IMX6SX_GPR2_MQS_CLK_DIV_SHIFT); + regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, + IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, 0); + } else { + regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, + MQS_CLK_DIV_MASK, + (div - 1) << MQS_CLK_DIV_SHIFT); + regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, + MQS_OVERSAMPLE_MASK, 0); + } + } else { + dev_err(component->dev, "can't get proper divider\n"); + } + + return 0; +} + +static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + /* Only LEFT_J & SLAVE mode is supported. */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int fsl_mqs_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); + + if (mqs_priv->use_gpr) + regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, + IMX6SX_GPR2_MQS_EN_MASK, + 1 << IMX6SX_GPR2_MQS_EN_SHIFT); + else + regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, + MQS_EN_MASK, + 1 << MQS_EN_SHIFT); + return 0; +} + +static void fsl_mqs_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); + + if (mqs_priv->use_gpr) + regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, + IMX6SX_GPR2_MQS_EN_MASK, 0); + else + regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, + MQS_EN_MASK, 0); +} + +const static struct snd_soc_component_driver soc_codec_fsl_mqs = { + .idle_bias_on = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct snd_soc_dai_ops fsl_mqs_dai_ops = { + .startup = fsl_mqs_startup, + .shutdown = fsl_mqs_shutdown, + .hw_params = fsl_mqs_hw_params, + .set_fmt = fsl_mqs_set_dai_fmt, +}; + +static struct snd_soc_dai_driver fsl_mqs_dai = { + .name = "fsl-mqs-dai", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = FSL_MQS_RATES, + .formats = FSL_MQS_FORMATS, + }, + .ops = &fsl_mqs_dai_ops, +}; + +static const struct regmap_config fsl_mqs_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = REG_MQS_CTRL, + .cache_type = REGCACHE_NONE, +}; + +static int fsl_mqs_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *gpr_np = 0; + struct fsl_mqs *mqs_priv; + void __iomem *regs; + int ret = 0; + + mqs_priv = devm_kzalloc(&pdev->dev, sizeof(*mqs_priv), GFP_KERNEL); + if (!mqs_priv) + return -ENOMEM; + + /* On i.MX6sx the MQS control register is in GPR domain + * But in i.MX8QM/i.MX8QXP the control register is moved + * to its own domain. + */ + if (of_device_is_compatible(np, "fsl,imx8qm-mqs")) + mqs_priv->use_gpr = false; + else + mqs_priv->use_gpr = true; + + if (mqs_priv->use_gpr) { + gpr_np = of_parse_phandle(np, "gpr", 0); + if (IS_ERR(gpr_np)) { + dev_err(&pdev->dev, "failed to get gpr node by phandle\n"); + ret = PTR_ERR(gpr_np); + goto out; + } + + mqs_priv->regmap = syscon_node_to_regmap(gpr_np); + if (IS_ERR(mqs_priv->regmap)) { + dev_err(&pdev->dev, "failed to get gpr regmap\n"); + ret = PTR_ERR(mqs_priv->regmap); + goto out; + } + } else { + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + mqs_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, + "core", + regs, + &fsl_mqs_regmap_config); + if (IS_ERR(mqs_priv->regmap)) { + dev_err(&pdev->dev, "failed to init regmap: %ld\n", + PTR_ERR(mqs_priv->regmap)); + return PTR_ERR(mqs_priv->regmap); + } + + mqs_priv->ipg = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(mqs_priv->ipg)) { + dev_err(&pdev->dev, "failed to get the clock: %ld\n", + PTR_ERR(mqs_priv->ipg)); + goto out; + } + } + + mqs_priv->mclk = devm_clk_get(&pdev->dev, "mclk"); + if (IS_ERR(mqs_priv->mclk)) { + dev_err(&pdev->dev, "failed to get the clock: %ld\n", + PTR_ERR(mqs_priv->mclk)); + goto out; + } + + dev_set_drvdata(&pdev->dev, mqs_priv); + pm_runtime_enable(&pdev->dev); + + return devm_snd_soc_register_component(&pdev->dev, &soc_codec_fsl_mqs, + &fsl_mqs_dai, 1); +out: + if (!IS_ERR(gpr_np)) + of_node_put(gpr_np); + + return ret; +} + +static int fsl_mqs_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + return 0; +} + +#ifdef CONFIG_PM +static int fsl_mqs_runtime_resume(struct device *dev) +{ + struct fsl_mqs *mqs_priv = dev_get_drvdata(dev); + + if (mqs_priv->ipg) + clk_prepare_enable(mqs_priv->ipg); + + if (mqs_priv->mclk) + clk_prepare_enable(mqs_priv->mclk); + + if (mqs_priv->use_gpr) + regmap_write(mqs_priv->regmap, IOMUXC_GPR2, + mqs_priv->reg_iomuxc_gpr2); + else + regmap_write(mqs_priv->regmap, REG_MQS_CTRL, + mqs_priv->reg_mqs_ctrl); + return 0; +} + +static int fsl_mqs_runtime_suspend(struct device *dev) +{ + struct fsl_mqs *mqs_priv = dev_get_drvdata(dev); + + if (mqs_priv->use_gpr) + regmap_read(mqs_priv->regmap, IOMUXC_GPR2, + &mqs_priv->reg_iomuxc_gpr2); + else + regmap_read(mqs_priv->regmap, REG_MQS_CTRL, + &mqs_priv->reg_mqs_ctrl); + + if (mqs_priv->mclk) + clk_disable_unprepare(mqs_priv->mclk); + + if (mqs_priv->ipg) + clk_disable_unprepare(mqs_priv->ipg); + + return 0; +} +#endif + +static const struct dev_pm_ops fsl_mqs_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_mqs_runtime_suspend, + fsl_mqs_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static const struct of_device_id fsl_mqs_dt_ids[] = { + { .compatible = "fsl,imx8qm-mqs", }, + { .compatible = "fsl,imx6sx-mqs", }, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids); + +static struct platform_driver fsl_mqs_driver = { + .probe = fsl_mqs_probe, + .remove = fsl_mqs_remove, + .driver = { + .name = "fsl-mqs", + .of_match_table = fsl_mqs_dt_ids, + .pm = &fsl_mqs_pm_ops, + }, +}; + +module_platform_driver(fsl_mqs_driver); + +MODULE_AUTHOR("Shengjiu Wang "); +MODULE_DESCRIPTION("MQS codec driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform: fsl-mqs"); -- cgit From adebb11139029ddf1fba6f796c4a476f17eacddc Mon Sep 17 00:00:00 2001 From: Sam McNally Date: Tue, 17 Sep 2019 15:49:33 +1000 Subject: ASoC: Intel: cht_bsw_rt5645: Add quirk for boards using pmc_plt_clk_0 As of commit 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL"), the cht_bsw_rt5645 driver needs to enable the clock it's using for the codec's mclk. It does this from commit 7735bce05a9c ("ASoC: Intel: boards: use devm_clk_get() unconditionally"), enabling pmc_plt_clk_3. However, Strago family Chromebooks use pmc_plt_clk_0 for the codec mclk, resulting in white noise with some digital microphones. Add a DMI-based quirk for Strago family Chromebooks to use pmc_plt_clk_0 instead - mirroring the changes made to cht_bsw_max98090_ti in commit a182ecd3809c ("ASoC: intel: cht_bsw_max98090_ti: Add quirk for boards using pmc_plt_clk_0") and making use of the existing dmi_check_system() call and related infrastructure added in commit 22af29114eb4 ("ASoC: Intel: cht-bsw-rt5645: add quirks for SSP0/AIF1/AIF2 routing"). Signed-off-by: Sam McNally Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190917054933.209335-1-sammc@chromium.org Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 8879c3be29d5..c68a5b85a4a0 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -48,6 +48,7 @@ struct cht_mc_private { #define CHT_RT5645_SSP2_AIF2 BIT(16) /* default is using AIF1 */ #define CHT_RT5645_SSP0_AIF1 BIT(17) #define CHT_RT5645_SSP0_AIF2 BIT(18) +#define CHT_RT5645_PMC_PLT_CLK_0 BIT(19) static unsigned long cht_rt5645_quirk = 0; @@ -59,6 +60,8 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk SSP0_AIF1 enabled"); if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2) dev_info(dev, "quirk SSP0_AIF2 enabled"); + if (cht_rt5645_quirk & CHT_RT5645_PMC_PLT_CLK_0) + dev_info(dev, "quirk PMC_PLT_CLK_0 enabled"); } static int platform_clock_control(struct snd_soc_dapm_widget *w, @@ -226,15 +229,21 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream, return 0; } -/* uncomment when we have a real quirk static int cht_rt5645_quirk_cb(const struct dmi_system_id *id) { cht_rt5645_quirk = (unsigned long)id->driver_data; return 1; } -*/ static const struct dmi_system_id cht_rt5645_quirk_table[] = { + { + /* Strago family Chromebooks */ + .callback = cht_rt5645_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_Strago"), + }, + .driver_data = (void *)CHT_RT5645_PMC_PLT_CLK_0, + }, { }, }; @@ -526,6 +535,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int dai_index = 0; int ret_val = 0; int i; + const char *mclk_name; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) @@ -662,11 +672,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (ret_val) return ret_val; - drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (cht_rt5645_quirk & CHT_RT5645_PMC_PLT_CLK_0) + mclk_name = "pmc_plt_clk_0"; + else + mclk_name = "pmc_plt_clk_3"; + + drv->mclk = devm_clk_get(&pdev->dev, mclk_name); if (IS_ERR(drv->mclk)) { - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %ld\n", - PTR_ERR(drv->mclk)); + dev_err(&pdev->dev, "Failed to get MCLK from %s: %ld\n", + mclk_name, PTR_ERR(drv->mclk)); return PTR_ERR(drv->mclk); } -- cgit From 6cfb1cd60394c2d88c6868d147cf6882a9ca3b6c Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 19 Sep 2019 17:27:57 +0200 Subject: ASoC: xlnx: Use devm_platform_ioremap_resource() in xlnx_formatter_pcm_probe() Simplify this function implementation by using a known wrapper function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Link: https://lore.kernel.org/r/8f7cf483-6ab3-d00f-5606-863e9f5b31fc@web.de Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_formatter_pcm.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index 48970efe7838..fb652e73abeb 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -564,7 +564,6 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev) int ret; u32 val; struct xlnx_pcm_drv_data *aud_drv_data; - struct resource *res; struct device *dev = &pdev->dev; aud_drv_data = devm_kzalloc(dev, sizeof(*aud_drv_data), GFP_KERNEL); @@ -584,13 +583,7 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "audio formatter node:addr to resource failed\n"); - ret = -ENXIO; - goto clk_err; - } - aud_drv_data->mmio = devm_ioremap_resource(dev, res); + aud_drv_data->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(aud_drv_data->mmio)) { dev_err(dev, "audio formatter ioremap failed\n"); ret = PTR_ERR(aud_drv_data->mmio); -- cgit From 419e2f50833661cec15200d5ee7385daee733667 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 20 Sep 2019 15:02:12 +0200 Subject: ASoC: wm8994: Add support for setting MCLK clock rate Extend the set_sysclk() handler so we also set frequency of the MCLK1, MCLK2 clocks through clk API when those clocks are specified in DT. Reviewed-by: Charles Keepax Acked-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20190920130218.32690-4-s.nawrocki@samsung.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 48 ++++++++++++++++++++++++++++++++++++++++++----- sound/soc/codecs/wm8994.h | 10 +++++++++- 2 files changed, 52 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index c3d06e8bc54f..35fbaa0138bf 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -167,12 +167,12 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif) switch (wm8994->sysclk[aif]) { case WM8994_SYSCLK_MCLK1: - rate = wm8994->mclk[0]; + rate = wm8994->mclk_rate[0]; break; case WM8994_SYSCLK_MCLK2: reg1 |= 0x8; - rate = wm8994->mclk[1]; + rate = wm8994->mclk_rate[1]; break; case WM8994_SYSCLK_FLL1: @@ -2367,12 +2367,29 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, return _wm8994_set_fll(dai->component, id, src, freq_in, freq_out); } +static int wm8994_set_mclk_rate(struct wm8994_priv *wm8994, unsigned int id, + unsigned int *freq) +{ + int ret; + + if (!wm8994->mclk[id].clk || *freq == wm8994->mclk_rate[id]) + return 0; + + ret = clk_set_rate(wm8994->mclk[id].clk, *freq); + if (ret < 0) + return ret; + + *freq = clk_get_rate(wm8994->mclk[id].clk); + + return 0; +} + static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_component *component = dai->component; struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); - int i; + int ret, i; switch (dai->id) { case 1: @@ -2387,7 +2404,12 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, switch (clk_id) { case WM8994_SYSCLK_MCLK1: wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1; - wm8994->mclk[0] = freq; + + ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq); + if (ret < 0) + return ret; + + wm8994->mclk_rate[0] = freq; dev_dbg(dai->dev, "AIF%d using MCLK1 at %uHz\n", dai->id, freq); break; @@ -2395,7 +2417,12 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, case WM8994_SYSCLK_MCLK2: /* TODO: Set GPIO AF */ wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2; - wm8994->mclk[1] = freq; + + ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq); + if (ret < 0) + return ret; + + wm8994->mclk_rate[1] = freq; dev_dbg(dai->dev, "AIF%d using MCLK2 at %uHz\n", dai->id, freq); break; @@ -4447,6 +4474,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8994 = { static int wm8994_probe(struct platform_device *pdev) { struct wm8994_priv *wm8994; + int ret; wm8994 = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_priv), GFP_KERNEL); @@ -4458,6 +4486,16 @@ static int wm8994_probe(struct platform_device *pdev) wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); + wm8994->mclk[WM8994_MCLK1].id = "MCLK1"; + wm8994->mclk[WM8994_MCLK2].id = "MCLK2"; + + ret = devm_clk_bulk_get_optional(pdev->dev.parent, ARRAY_SIZE(wm8994->mclk), + wm8994->mclk); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get clocks: %d\n", ret); + return ret; + } + pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 1d6f2abe1c11..41c4b126114d 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -6,6 +6,7 @@ #ifndef _WM8994_H #define _WM8994_H +#include #include #include #include @@ -14,6 +15,12 @@ #include "wm_hubs.h" +enum { + WM8994_MCLK1, + WM8994_MCLK2, + WM8994_NUM_MCLK +}; + /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ #define WM8994_SYSCLK_MCLK1 1 #define WM8994_SYSCLK_MCLK2 2 @@ -73,9 +80,10 @@ struct wm8994; struct wm8994_priv { struct wm_hubs_data hubs; struct wm8994 *wm8994; + struct clk_bulk_data mclk[WM8994_NUM_MCLK]; int sysclk[2]; int sysclk_rate[2]; - int mclk[2]; + int mclk_rate[2]; int aifclk[2]; int aifdiv[2]; int channels[2]; -- cgit From 001b83d395ab2acfddc46b73376f8dbdece89af7 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 20 Sep 2019 15:02:13 +0200 Subject: ASoC: wm8994: Add support for MCLKn clock gating As an intermediate step before covering the clocking subsystem of the CODEC entirely by the clk API add handling of external CODEC's master clocks in DAPM events when the AIFn clocks are sourced directly from MCLKn; when FLLn are used we enable/disable respective MCLKn before/after FLLn is enabled/disabled. Signed-off-by: Sylwester Nawrocki Acked-by: Charles Keepax Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20190920130218.32690-5-s.nawrocki@samsung.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 108 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 35fbaa0138bf..b633093afb9d 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1033,6 +1033,45 @@ static bool wm8994_check_class_w_digital(struct snd_soc_component *component) return true; } +static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enable) +{ + struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); + unsigned int offset, val, clk_idx; + int ret; + + if (aif) + offset = 4; + else + offset = 0; + + val = snd_soc_component_read32(component, WM8994_AIF1_CLOCKING_1 + offset); + val &= WM8994_AIF1CLK_SRC_MASK; + + switch (val) { + case 0: + clk_idx = WM8994_MCLK1; + break; + case 1: + clk_idx = WM8994_MCLK2; + break; + default: + return 0; + } + + if (enable) { + ret = clk_prepare_enable(wm8994->mclk[clk_idx].clk); + if (ret < 0) { + dev_err(component->dev, "Failed to enable MCLK%d\n", + clk_idx); + return ret; + } + } else { + clk_disable_unprepare(wm8994->mclk[clk_idx].clk); + } + + return 0; +} + static int aif1clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1040,7 +1079,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w, struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); struct wm8994 *control = wm8994->wm8994; int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA; - int i; + int ret, i; int dac; int adc; int val; @@ -1056,6 +1095,10 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + ret = aif_mclk_set(component, 0, true); + if (ret < 0) + return ret; + /* Don't enable timeslot 2 if not in use */ if (wm8994->channels[0] <= 2) mask &= ~(WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA); @@ -1128,6 +1171,12 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w, break; } + switch (event) { + case SND_SOC_DAPM_POST_PMD: + aif_mclk_set(component, 0, false); + break; + } + return 0; } @@ -1135,13 +1184,17 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - int i; + int ret, i; int dac; int adc; int val; switch (event) { case SND_SOC_DAPM_PRE_PMU: + ret = aif_mclk_set(component, 1, true); + if (ret < 0) + return ret; + val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_1); if ((val & WM8994_AIF2ADCL_SRC) && (val & WM8994_AIF2ADCR_SRC)) @@ -1213,6 +1266,12 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, break; } + switch (event) { + case SND_SOC_DAPM_POST_PMD: + aif_mclk_set(component, 1, false); + break; + } + return 0; } @@ -1618,10 +1677,10 @@ SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, aif1clk_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, aif2clk_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), @@ -2136,6 +2195,7 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src, u16 reg, clk1, aif_reg, aif_src; unsigned long timeout; bool was_enabled; + struct clk *mclk; switch (id) { case WM8994_FLL1: @@ -2211,6 +2271,27 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src, snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_1 + reg_offset, WM8994_FLL1_ENA, 0); + /* Disable MCLK if needed before we possibly change to new clock parent */ + if (was_enabled) { + reg = snd_soc_component_read32(component, WM8994_FLL1_CONTROL_5 + + reg_offset); + reg = ((reg & WM8994_FLL1_REFCLK_SRC_MASK) + >> WM8994_FLL1_REFCLK_SRC_SHIFT) + 1; + + switch (reg) { + case WM8994_FLL_SRC_MCLK1: + mclk = wm8994->mclk[WM8994_MCLK1].clk; + break; + case WM8994_FLL_SRC_MCLK2: + mclk = wm8994->mclk[WM8994_MCLK2].clk; + break; + default: + mclk = NULL; + } + + clk_disable_unprepare(mclk); + } + if (wm8994->fll_byp && src == WM8994_FLL_SRC_BCLK && freq_in == freq_out && freq_out) { dev_dbg(component->dev, "Bypassing FLL%d\n", id + 1); @@ -2255,10 +2336,29 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src, /* Clear any pending completion from a previous failure */ try_wait_for_completion(&wm8994->fll_locked[id]); + switch (src) { + case WM8994_FLL_SRC_MCLK1: + mclk = wm8994->mclk[WM8994_MCLK1].clk; + break; + case WM8994_FLL_SRC_MCLK2: + mclk = wm8994->mclk[WM8994_MCLK2].clk; + break; + default: + mclk = NULL; + } + /* Enable (with fractional mode if required) */ if (freq_out) { + ret = clk_prepare_enable(mclk); + if (ret < 0) { + dev_err(component->dev, "Failed to enable MCLK for FLL%d\n", + id + 1); + return ret; + } + /* Enable VMID if we need it */ if (!was_enabled) { + active_reference(component); switch (control->type) { -- cgit From 1c93a9e00e40e3a084ebbcaa4a8f412b83f1fa0d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Sep 2019 13:38:22 +0900 Subject: ASoC: soc-core: move soc_free_pcm_runtime() This patch moves soc_free_pcm_runtime() next to soc_new_pcm_runtime(). This is prepare for soc_xxx_pcm_runtime() cleanup. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ftl2f7sx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 88978a3036c4..96d38db8b578 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -355,6 +355,13 @@ EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); static const struct snd_soc_ops null_snd_soc_ops; +static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) +{ + kfree(rtd->codec_dais); + snd_soc_rtdcom_del_all(rtd); + kfree(rtd); +} + static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -381,13 +388,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( return rtd; } -static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) -{ - kfree(rtd->codec_dais); - snd_soc_rtdcom_del_all(rtd); - kfree(rtd); -} - static void soc_add_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd) { -- cgit From a848125e320a154dfc17b9a377361b4b0df87363 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Sep 2019 13:38:34 +0900 Subject: ASoC: soc-core: merge soc_add_pcm_runtime() into soc_new_pcm_runtime() We have soc_new_pcm_runtime() which allocs rtd and its related memory, and soc_add_pcm_runtime() which connects rtd to card. But we don't need to separate these, we can alloc and connect rtd in the same time. Current implementation is just makes code complex. This patch merges these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ef0mf7sl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 96d38db8b578..cadf96bc0097 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -385,16 +385,12 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( return NULL; } - return rtd; -} - -static void soc_add_pcm_runtime(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd) -{ /* see for_each_card_rtds */ list_add_tail(&rtd->list, &card->rtd_list); rtd->num = card->num_rtd; card->num_rtd++; + + return rtd; } static void soc_remove_pcm_runtimes(struct snd_soc_card *card) @@ -930,7 +926,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, } } - soc_add_pcm_runtime(card, rtd); return 0; _err_defer: -- cgit From 753ace0a34fbd39ac2ec654c6859823db420f69e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Sep 2019 13:38:50 +0900 Subject: ASoC: soc-core: call list_del(&rtd->list) at soc_free_pcm_runtime() Current ALSA SoC is calling list_del(&rtd->list) at (1) static void soc_remove_pcm_runtimes(...) { ... for_each_card_rtds_safe(card, rtd, _rtd) { (1) list_del(&rtd->list); (2) soc_free_pcm_runtime(rtd); } ... } But, we will call soc_free_pcm_runtime() after that (2). &rtd->list is connected at soc_new_pcm_runtime(), Thus, it should be disconnected at soc_free_pcm_runtime(). This patch calls list_del(&rtd->list) at soc_free_pcm_runtime(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87d0g6f7s5.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cadf96bc0097..7a3f4783adf6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -359,6 +359,7 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) { kfree(rtd->codec_dais); snd_soc_rtdcom_del_all(rtd); + list_del(&rtd->list); kfree(rtd); } @@ -397,10 +398,8 @@ static void soc_remove_pcm_runtimes(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd, *_rtd; - for_each_card_rtds_safe(card, rtd, _rtd) { - list_del(&rtd->list); + for_each_card_rtds_safe(card, rtd, _rtd) soc_free_pcm_runtime(rtd); - } card->num_rtd = 0; } -- cgit From 929deb849b9e4319015070ead7ca976a4f16e303 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Sep 2019 13:39:32 +0900 Subject: ASoC: soc-core: create rtd->codec_dais first soc_new_pcm_runtime() allocs rtd and rtd->codec_dais. This patch allocs both first, and setup these after that. This is prepare for soc_new_pcm_runtime() cleanup. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87blvqf7qz.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7a3f4783adf6..bc45b0db05ab 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -372,12 +372,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( if (!rtd) return NULL; - INIT_LIST_HEAD(&rtd->component_list); - rtd->card = card; - rtd->dai_link = dai_link; - if (!rtd->dai_link->ops) - rtd->dai_link->ops = &null_snd_soc_ops; - rtd->codec_dais = kcalloc(dai_link->num_codecs, sizeof(struct snd_soc_dai *), GFP_KERNEL); @@ -386,6 +380,12 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( return NULL; } + INIT_LIST_HEAD(&rtd->component_list); + rtd->card = card; + rtd->dai_link = dai_link; + if (!rtd->dai_link->ops) + rtd->dai_link->ops = &null_snd_soc_ops; + /* see for_each_card_rtds */ list_add_tail(&rtd->list, &card->rtd_list); rtd->num = card->num_rtd; -- cgit From 6e864344873f19120f742c19d15a8c53e7247c6a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Sep 2019 13:40:08 +0900 Subject: ASoC: soc-core: merge soc_new_pcm_runtime() and soc_rtd_init() "rtd" is handled by soc_xxx_pcm_runtime(), and "rtd->dev" is handled by soc_rtd_xxx(). There is no reason to separate these, and it makes code complex. We can create these in the same time. This patch merges soc_rtd_init() into soc_new_pcm_runtime(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a7baf7pz.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 95 +++++++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 42 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bc45b0db05ab..6abc1bc9a236 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -355,8 +355,17 @@ EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); static const struct snd_soc_ops null_snd_soc_ops; +static void soc_release_rtd_dev(struct device *dev) +{ + /* "dev" means "rtd->dev" */ + kfree(dev); +} + static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) { + if (!rtd) + return; + kfree(rtd->codec_dais); snd_soc_rtdcom_del_all(rtd); list_del(&rtd->list); @@ -367,20 +376,54 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; + int ret; + /* + * for rtd + */ rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); if (!rtd) - return NULL; + goto free_rtd; + /* + * for rtd->codec_dais + */ rtd->codec_dais = kcalloc(dai_link->num_codecs, sizeof(struct snd_soc_dai *), GFP_KERNEL); - if (!rtd->codec_dais) { - kfree(rtd); - return NULL; + if (!rtd->codec_dais) + goto free_rtd; + + /* + * for rtd->dev + */ + rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!rtd->dev) + goto free_rtd; + + rtd->dev->parent = card->dev; + rtd->dev->release = soc_release_rtd_dev; + rtd->dev->groups = soc_dev_attr_groups; + + dev_set_name(rtd->dev, "%s", dai_link->name); + dev_set_drvdata(rtd->dev, rtd); + + ret = device_register(rtd->dev); + if (ret < 0) { + put_device(rtd->dev); /* soc_release_rtd_dev */ + rtd->dev = NULL; + goto free_rtd; } + /* + * rtd remaining settings + */ INIT_LIST_HEAD(&rtd->component_list); + INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); + INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients); + INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); + INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); + rtd->card = card; rtd->dai_link = dai_link; if (!rtd->dai_link->ops) @@ -391,7 +434,13 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( rtd->num = card->num_rtd; card->num_rtd++; + rtd->dev_registered = 1; + return rtd; + +free_rtd: + soc_free_pcm_runtime(rtd); + return NULL; } static void soc_remove_pcm_runtimes(struct snd_soc_card *card) @@ -1420,40 +1469,6 @@ static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd) } } -static void soc_rtd_release(struct device *dev) -{ - kfree(dev); -} - -static int soc_rtd_init(struct snd_soc_pcm_runtime *rtd, const char *name) -{ - int ret = 0; - - /* register the rtd device */ - rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!rtd->dev) - return -ENOMEM; - rtd->dev->parent = rtd->card->dev; - rtd->dev->release = soc_rtd_release; - rtd->dev->groups = soc_dev_attr_groups; - dev_set_name(rtd->dev, "%s", name); - dev_set_drvdata(rtd->dev, rtd); - INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); - INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients); - INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); - INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); - ret = device_register(rtd->dev); - if (ret < 0) { - /* calling put_device() here to free the rtd->dev */ - put_device(rtd->dev); - dev_err(rtd->card->dev, - "ASoC: failed to register runtime device: %d\n", ret); - return ret; - } - rtd->dev_registered = 1; - return 0; -} - static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, struct snd_soc_pcm_runtime *rtd) { @@ -1503,10 +1518,6 @@ static int soc_link_init(struct snd_soc_card *card, return ret; } - ret = soc_rtd_init(rtd, dai_link->name); - if (ret) - return ret; - /* add DPCM sysfs entries */ soc_dpcm_debugfs_add(rtd); -- cgit From b7c5bc45ee94a03a0dc45a862180e17db8ea8e9d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Sep 2019 13:41:01 +0900 Subject: ASoC: soc-core: merge soc_free_pcm_runtime() and soc_rtd_free() "rtd" is handled by soc_xxx_pcm_runtime(), and "rtd->dev" is handled by soc_rtd_xxx(). There is no reason to separate these, and it makes code complex. We can free these in the same time. Here soc_rtd_free() (A) which frees rtd->dev is called from soc_remove_link_dais() many times (1). Then, it is using dev_registered flags to avoid multi kfree() (2). This is no longer needed if we can merge these functions. static void soc_remove_link_dais(...) { ... (1) for_each_comp_order(order) { (1) for_each_card_rtds(card, rtd) { (A) soc_rtd_free(rtd); ... } } } (A) static void soc_rtd_free(...) { (2) if (rtd->dev_registered) { /* we don't need to call kfree() for rtd->dev */ device_unregister(rtd->dev); (2) rtd->dev_registered = 0; } } This patch merges soc_rtd_free() into soc_free_pcm_runtime(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878squf7oi.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6abc1bc9a236..8a37850291bd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -369,6 +369,14 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) kfree(rtd->codec_dais); snd_soc_rtdcom_del_all(rtd); list_del(&rtd->list); + + /* + * we don't need to call kfree() for rtd->dev + * see + * soc_release_rtd_dev() + */ + if (rtd->dev) + device_unregister(rtd->dev); kfree(rtd); } @@ -434,8 +442,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( rtd->num = card->num_rtd; card->num_rtd++; - rtd->dev_registered = 1; - return rtd; free_rtd: @@ -1169,7 +1175,6 @@ static int soc_probe_dai(struct snd_soc_dai *dai, int order) return 0; } -static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd); /* remove me */ static void soc_remove_link_dais(struct snd_soc_card *card) { int i; @@ -1179,10 +1184,6 @@ static void soc_remove_link_dais(struct snd_soc_card *card) for_each_comp_order(order) { for_each_card_rtds(card, rtd) { - - /* finalize rtd device */ - soc_rtd_free(rtd); - /* remove the CODEC DAI */ for_each_rtd_codec_dai(rtd, i, codec_dai) soc_remove_dai(codec_dai, order); @@ -1460,15 +1461,6 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); -static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd) -{ - if (rtd->dev_registered) { - /* we don't need to call kfree() for rtd->dev */ - device_unregister(rtd->dev); - rtd->dev_registered = 0; - } -} - static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, struct snd_soc_pcm_runtime *rtd) { -- cgit From d918a37610b1bf71faa86f589bd7604f71c1e05f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Sep 2019 13:42:30 +0900 Subject: ASoC: soc-core: tidyup soc_new_pcm_runtime() alloc order This patch allocs dev first at soc_new_pcm_runtime(). This is prepare for rtd->dev, rtd->codec_dais alloc cleanup Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/877e6ef7m1.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 55 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8a37850291bd..b72207412c73 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -125,6 +125,9 @@ static umode_t soc_dev_attr_is_visible(struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); + if (!rtd) + return 0; + if (attr == &dev_attr_pmdown_time.attr) return attr->mode; /* always visible */ return rtd->num_codecs ? attr->mode : 0; /* enabled only with codec */ @@ -374,9 +377,13 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) * we don't need to call kfree() for rtd->dev * see * soc_release_rtd_dev() + * + * We don't need rtd->dev NULL check, because + * it is alloced *before* rtd. + * see + * soc_new_pcm_runtime() */ - if (rtd->dev) - device_unregister(rtd->dev); + device_unregister(rtd->dev); kfree(rtd); } @@ -384,8 +391,28 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; + struct device *dev; int ret; + /* + * for rtd->dev + */ + dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!dev) + return NULL; + + dev->parent = card->dev; + dev->release = soc_release_rtd_dev; + dev->groups = soc_dev_attr_groups; + + dev_set_name(dev, "%s", dai_link->name); + + ret = device_register(dev); + if (ret < 0) { + put_device(dev); /* soc_release_rtd_dev */ + return NULL; + } + /* * for rtd */ @@ -393,6 +420,9 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( if (!rtd) goto free_rtd; + rtd->dev = dev; + dev_set_drvdata(dev, rtd); + /* * for rtd->codec_dais */ @@ -402,27 +432,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( if (!rtd->codec_dais) goto free_rtd; - /* - * for rtd->dev - */ - rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!rtd->dev) - goto free_rtd; - - rtd->dev->parent = card->dev; - rtd->dev->release = soc_release_rtd_dev; - rtd->dev->groups = soc_dev_attr_groups; - - dev_set_name(rtd->dev, "%s", dai_link->name); - dev_set_drvdata(rtd->dev, rtd); - - ret = device_register(rtd->dev); - if (ret < 0) { - put_device(rtd->dev); /* soc_release_rtd_dev */ - rtd->dev = NULL; - goto free_rtd; - } - /* * rtd remaining settings */ -- cgit From 353e16bf60458fae5927cf04ff668fc152fff465 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Sep 2019 13:42:44 +0900 Subject: ASoC: soc-core: remove snd_soc_rtdcom_del_all() If we can use devm_kzalloc(rtd->dev, xxx) for rtdcom, we don't need to call snd_soc_rtdcom_del_all() for kfree(). This patch uses devm_kzalloc(rtd->dev, xxx) for rtdcom, and remove snd_soc_rtdcom_del_all(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875zlyf7ln.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b72207412c73..d2842a383846 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -288,28 +288,29 @@ static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, return 0; } - rtdcom = kmalloc(sizeof(*rtdcom), GFP_KERNEL); + /* + * created rtdcom here will be freed when rtd->dev was freed. + * see + * soc_free_pcm_runtime() :: device_unregister(rtd->dev) + */ + rtdcom = devm_kzalloc(rtd->dev, sizeof(*rtdcom), GFP_KERNEL); if (!rtdcom) return -ENOMEM; rtdcom->component = component; INIT_LIST_HEAD(&rtdcom->list); + /* + * When rtd was freed, created rtdcom here will be + * also freed. + * And we don't need to call list_del(&rtdcom->list) + * when freed, because rtd is also freed. + */ list_add_tail(&rtdcom->list, &rtd->component_list); return 0; } -static void snd_soc_rtdcom_del_all(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_rtdcom_list *rtdcom1, *rtdcom2; - - for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2) - kfree(rtdcom1); - - INIT_LIST_HEAD(&rtd->component_list); -} - struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, const char *driver_name) { @@ -370,7 +371,6 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) return; kfree(rtd->codec_dais); - snd_soc_rtdcom_del_all(rtd); list_del(&rtd->list); /* -- cgit From 67f798c78242ef3051bf6bf304ddb8a09514e1c5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 25 Sep 2019 10:45:45 +0100 Subject: ASoC: amd: acp3x: clean up indentation issue There is a statement that is indented one level too deeply, remove the extraneous tab. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190925094545.19941-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/amd/raven/acp3x-pcm-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index bc4dfafdfcd1..ea57088d50ce 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -631,7 +631,7 @@ static int acp3x_audio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); - return -ENODEV; + return -ENODEV; } adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL); -- cgit From bd1468f252e85280b71a069a2255842d78133cc4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 25 Sep 2019 11:03:30 +0100 Subject: ASoC: rt5663: clean up indentation issues There are two break statements that are indented one level too deeply, remove the extraneous tabs. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190925100330.20695-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 2943692f66ed..e6c1ec6c426e 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3644,7 +3644,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_1, RT5663_LDO1_DVO_MASK | RT5663_AMP_HP_MASK, RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X); - break; + break; case CODEC_VER_0: regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC, RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN); @@ -3663,7 +3663,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5663->regmap, RT5663_TDM_2, RT5663_DATA_SWAP_ADCDAT1_MASK, RT5663_DATA_SWAP_ADCDAT1_LL); - break; + break; default: dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__); } -- cgit From 944eedd8c021893d08d02a8eec8e5161327316cd Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 25 Sep 2019 12:10:23 +0100 Subject: ASoC: wcd9335: clean up indentation issue There is an if statement that is indented one level too deeply, remove the extraneous tabs. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190925111023.7771-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index f318403133e9..f11ffa28683b 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -2837,11 +2837,11 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w, TX_HPF_CUT_OFF_FREQ_MASK) >> 5; snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x10); snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x00); - if (hpf_coff_freq != CF_MIN_3DB_150HZ) { - snd_soc_component_update_bits(comp, dec_cfg_reg, - TX_HPF_CUT_OFF_FREQ_MASK, - hpf_coff_freq << 5); - } + if (hpf_coff_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(comp, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_coff_freq << 5); + } break; case SND_SOC_DAPM_POST_PMD: snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00); -- cgit From 423013f824ab0590c229a107f21c54ac6596c4e1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 25 Sep 2019 12:26:21 +0100 Subject: ASoC: stm32: sai: clean up indentation issue There is a statement that is indented one level too deeply, remove the extraneous tab. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190925112621.9312-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index ef4273361d0d..e20267504b16 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -100,7 +100,7 @@ static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco) dev_err(&sai->pdev->dev, "%pOFn%s already set as sync provider\n", sai->pdev->dev.of_node, prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); - stm32_sai_pclk_disable(&sai->pdev->dev); + stm32_sai_pclk_disable(&sai->pdev->dev); return -EINVAL; } -- cgit From 49f9c4f2e83cf562f1a6e3f62eafa4ede5343e4a Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 25 Sep 2019 21:33:58 +0300 Subject: ASoC: core: Clarify usage of ignore_machine For a sound card ignore_machine means that existing FEs links should be ignored and existing BEs links should be overridden with some information from the matching component driver. Current code make some confusions about this so fix it! Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20190925183358.11955-1-daniel.baluta@nxp.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d2842a383846..4a47ba94559f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1859,7 +1859,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) for_each_component(component) { - /* does this component override FEs ? */ + /* does this component override BEs ? */ if (!component->driver->ignore_machine) continue; @@ -1880,7 +1880,7 @@ match: continue; } - dev_info(card->dev, "info: override FE DAI link %s\n", + dev_info(card->dev, "info: override BE DAI link %s\n", card->dai_link[i].name); /* override platform component */ -- cgit From 83078521072e95cf555d356f9e0b39021c46ac76 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 26 Sep 2019 14:50:11 +0300 Subject: ASoC: adau1761: Add PGA Slew time control The PGA Slew Time control allows to configure the rate with which the PGA gain control ramps up/down to the target setting. The PGA slew control is done via the ALC Control 0 register. There are 2 bits on that reg, that control PGA slew time, while the other bits control parts of the ALC (automatic level control) block. Signed-off-by: Lars-Peter Clausen Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926115012.24049-1-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 977f5a63be3f..a9ef735f8b4e 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -28,6 +28,7 @@ #define ADAU1761_REC_MIXER_RIGHT1 0x400d #define ADAU1761_LEFT_DIFF_INPUT_VOL 0x400e #define ADAU1761_RIGHT_DIFF_INPUT_VOL 0x400f +#define ADAU1761_ALC_CTRL0 0x4011 #define ADAU1761_PLAY_LR_MIXER_LEFT 0x4020 #define ADAU1761_PLAY_MIXER_LEFT0 0x401c #define ADAU1761_PLAY_MIXER_LEFT1 0x401d @@ -71,6 +72,7 @@ static const struct reg_default adau1761_reg_defaults[] = { { ADAU1761_REC_MIXER_RIGHT0, 0x00 }, { ADAU1761_REC_MIXER_RIGHT1, 0x00 }, { ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 }, + { ADAU1761_ALC_CTRL0, 0x00 }, { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 }, { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 }, { ADAU1761_PLAY_MIXER_LEFT0, 0x00 }, @@ -147,6 +149,21 @@ static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_capture_bias_enum, ADAU17X1_REC_POWER_MGMT, 1, 0x3, adau1761_bias_select_text, adau1761_bias_select_values); +static const unsigned int adau1761_pga_slew_time_values[] = { + 3, 0, 1, 2, +}; + +static const char * const adau1761_pga_slew_time_text[] = { + "Off", + "24 ms", + "48 ms", + "96 ms", +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_pga_slew_time_enum, + ADAU1761_ALC_CTRL0, 6, 0x3, adau1761_pga_slew_time_text, + adau1761_pga_slew_time_values); + static const struct snd_kcontrol_new adau1761_jack_detect_controls[] = { SOC_SINGLE("Speaker Auto-mute Switch", ADAU1761_DIGMIC_JACKDETECT, 4, 1, 0), @@ -161,6 +178,8 @@ static const struct snd_kcontrol_new adau1761_differential_mode_controls[] = { SOC_DOUBLE_R_TLV("PGA Boost Capture Volume", ADAU1761_REC_MIXER_LEFT1, ADAU1761_REC_MIXER_RIGHT1, 3, 2, 0, adau1761_pga_boost_tlv), + + SOC_ENUM("PGA Capture Slew Time", adau1761_pga_slew_time_enum), }; static const struct snd_kcontrol_new adau1761_single_mode_controls[] = { @@ -632,6 +651,7 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg) case ADAU1761_DEJITTER: case ADAU1761_CLK_ENABLE0: case ADAU1761_CLK_ENABLE1: + case ADAU1761_ALC_CTRL0: return true; default: break; -- cgit From 5422737192d907c6fd181479c25690e7f371e9dd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 26 Sep 2019 14:50:12 +0300 Subject: ASoC: adau1761: Add ALC controls The adau1761 has a automatic level control block that can adjust the gain for the differential input PGA. This patch adds ALSA controls for enabling and changing the parameter settings for the ALC. Signed-off-by: Lars-Peter Clausen Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20190926115012.24049-2-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761.c | 109 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index a9ef735f8b4e..5ca9b744b7d8 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -29,6 +29,9 @@ #define ADAU1761_LEFT_DIFF_INPUT_VOL 0x400e #define ADAU1761_RIGHT_DIFF_INPUT_VOL 0x400f #define ADAU1761_ALC_CTRL0 0x4011 +#define ADAU1761_ALC_CTRL1 0x4012 +#define ADAU1761_ALC_CTRL2 0x4013 +#define ADAU1761_ALC_CTRL3 0x4014 #define ADAU1761_PLAY_LR_MIXER_LEFT 0x4020 #define ADAU1761_PLAY_MIXER_LEFT0 0x401c #define ADAU1761_PLAY_MIXER_LEFT1 0x401d @@ -73,6 +76,9 @@ static const struct reg_default adau1761_reg_defaults[] = { { ADAU1761_REC_MIXER_RIGHT1, 0x00 }, { ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 }, { ADAU1761_ALC_CTRL0, 0x00 }, + { ADAU1761_ALC_CTRL1, 0x00 }, + { ADAU1761_ALC_CTRL2, 0x00 }, + { ADAU1761_ALC_CTRL3, 0x00 }, { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 }, { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 }, { ADAU1761_PLAY_MIXER_LEFT0, 0x00 }, @@ -123,6 +129,10 @@ static const DECLARE_TLV_DB_SCALE(adau1761_sidetone_tlv, -1800, 300, 1); static const DECLARE_TLV_DB_SCALE(adau1761_boost_tlv, -600, 600, 1); static const DECLARE_TLV_DB_SCALE(adau1761_pga_boost_tlv, -2000, 2000, 1); +static const DECLARE_TLV_DB_SCALE(adau1761_alc_max_gain_tlv, -1200, 600, 0); +static const DECLARE_TLV_DB_SCALE(adau1761_alc_target_tlv, -2850, 150, 0); +static const DECLARE_TLV_DB_SCALE(adau1761_alc_ng_threshold_tlv, -7650, 150, 0); + static const unsigned int adau1761_bias_select_values[] = { 0, 2, 3, }; @@ -160,9 +170,91 @@ static const char * const adau1761_pga_slew_time_text[] = { "96 ms", }; +static const char * const adau1761_alc_function_text[] = { + "Off", + "Right", + "Left", + "Stereo", + "DSP control", +}; + +static const char * const adau1761_alc_hold_time_text[] = { + "2.67 ms", + "5.34 ms", + "10.68 ms", + "21.36 ms", + "42.72 ms", + "85.44 ms", + "170.88 ms", + "341.76 ms", + "683.52 ms", + "1367 ms", + "2734.1 ms", + "5468.2 ms", + "10936 ms", + "21873 ms", + "43745 ms", + "87491 ms", +}; + +static const char * const adau1761_alc_attack_time_text[] = { + "6 ms", + "12 ms", + "24 ms", + "48 ms", + "96 ms", + "192 ms", + "384 ms", + "768 ms", + "1540 ms", + "3070 ms", + "6140 ms", + "12290 ms", + "24580 ms", + "49150 ms", + "98300 ms", + "196610 ms", +}; + +static const char * const adau1761_alc_decay_time_text[] = { + "24 ms", + "48 ms", + "96 ms", + "192 ms", + "384 ms", + "768 ms", + "15400 ms", + "30700 ms", + "61400 ms", + "12290 ms", + "24580 ms", + "49150 ms", + "98300 ms", + "196610 ms", + "393220 ms", + "786430 ms", +}; + +static const char * const adau1761_alc_ng_type_text[] = { + "Hold", + "Mute", + "Fade", + "Fade + Mute", +}; + static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_pga_slew_time_enum, ADAU1761_ALC_CTRL0, 6, 0x3, adau1761_pga_slew_time_text, adau1761_pga_slew_time_values); +static SOC_ENUM_SINGLE_DECL(adau1761_alc_function_enum, + ADAU1761_ALC_CTRL0, 0, adau1761_alc_function_text); +static SOC_ENUM_SINGLE_DECL(adau1761_alc_hold_time_enum, + ADAU1761_ALC_CTRL1, 4, adau1761_alc_hold_time_text); +static SOC_ENUM_SINGLE_DECL(adau1761_alc_attack_time_enum, + ADAU1761_ALC_CTRL2, 4, adau1761_alc_attack_time_text); +static SOC_ENUM_SINGLE_DECL(adau1761_alc_decay_time_enum, + ADAU1761_ALC_CTRL2, 0, adau1761_alc_decay_time_text); +static SOC_ENUM_SINGLE_DECL(adau1761_alc_ng_type_enum, + ADAU1761_ALC_CTRL3, 6, adau1761_alc_ng_type_text); static const struct snd_kcontrol_new adau1761_jack_detect_controls[] = { SOC_SINGLE("Speaker Auto-mute Switch", ADAU1761_DIGMIC_JACKDETECT, @@ -180,6 +272,20 @@ static const struct snd_kcontrol_new adau1761_differential_mode_controls[] = { ADAU1761_REC_MIXER_RIGHT1, 3, 2, 0, adau1761_pga_boost_tlv), SOC_ENUM("PGA Capture Slew Time", adau1761_pga_slew_time_enum), + + SOC_SINGLE_TLV("ALC Capture Max Gain Volume", ADAU1761_ALC_CTRL0, + 3, 7, 0, adau1761_alc_max_gain_tlv), + SOC_ENUM("ALC Capture Function", adau1761_alc_function_enum), + SOC_ENUM("ALC Capture Hold Time", adau1761_alc_hold_time_enum), + SOC_SINGLE_TLV("ALC Capture Target Volume", ADAU1761_ALC_CTRL1, + 0, 15, 0, adau1761_alc_target_tlv), + SOC_ENUM("ALC Capture Attack Time", adau1761_alc_decay_time_enum), + SOC_ENUM("ALC Capture Decay Time", adau1761_alc_attack_time_enum), + SOC_ENUM("ALC Capture Noise Gate Type", adau1761_alc_ng_type_enum), + SOC_SINGLE("ALC Capture Noise Gate Switch", + ADAU1761_ALC_CTRL3, 5, 1, 0), + SOC_SINGLE_TLV("ALC Capture Noise Gate Threshold Volume", + ADAU1761_ALC_CTRL3, 0, 31, 0, adau1761_alc_ng_threshold_tlv), }; static const struct snd_kcontrol_new adau1761_single_mode_controls[] = { @@ -652,6 +758,9 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg) case ADAU1761_CLK_ENABLE0: case ADAU1761_CLK_ENABLE1: case ADAU1761_ALC_CTRL0: + case ADAU1761_ALC_CTRL1: + case ADAU1761_ALC_CTRL2: + case ADAU1761_ALC_CTRL3: return true; default: break; -- cgit From 4bf62571070dd1021556e275d9221f736b2ffcf3 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 27 Sep 2019 09:46:09 +0800 Subject: ASoC: fsl_asrc: Use in(out)put_format instead of in(out)put_word_width snd_pcm_format_t is more formal than enum asrc_word_width, which has two property, width and physical width, which is more accurate than enum asrc_word_width. So it is better to use in(out)put_format instead of in(out)put_word_width. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/7937c1404ee327ce141cb03b3575b02ea01a740c.1569493933.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 56 ++++++++++++++++++++++++++++++++---------------- sound/soc/fsl/fsl_asrc.h | 4 ++-- 2 files changed, 40 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index cfa40ef6b1ca..4d3804a1ea55 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -265,6 +265,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) struct asrc_config *config = pair->config; struct fsl_asrc *asrc_priv = pair->asrc_priv; enum asrc_pair_index index = pair->index; + enum asrc_word_width input_word_width; + enum asrc_word_width output_word_width; u32 inrate, outrate, indiv, outdiv; u32 clk_index[2], div[2]; int in, out, channels; @@ -283,9 +285,32 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) return -EINVAL; } - /* Validate output width */ - if (config->output_word_width == ASRC_WIDTH_8_BIT) { - pair_err("does not support 8bit width output\n"); + switch (snd_pcm_format_width(config->input_format)) { + case 8: + input_word_width = ASRC_WIDTH_8_BIT; + break; + case 16: + input_word_width = ASRC_WIDTH_16_BIT; + break; + case 24: + input_word_width = ASRC_WIDTH_24_BIT; + break; + default: + pair_err("does not support this input format, %d\n", + config->input_format); + return -EINVAL; + } + + switch (snd_pcm_format_width(config->output_format)) { + case 16: + output_word_width = ASRC_WIDTH_16_BIT; + break; + case 24: + output_word_width = ASRC_WIDTH_24_BIT; + break; + default: + pair_err("does not support this output format, %d\n", + config->output_format); return -EINVAL; } @@ -383,8 +408,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) /* Implement word_width configurations */ regmap_update_bits(asrc_priv->regmap, REG_ASRMCR1(index), ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, - ASRMCR1i_OW16(config->output_word_width) | - ASRMCR1i_IWD(config->input_word_width)); + ASRMCR1i_OW16(output_word_width) | + ASRMCR1i_IWD(input_word_width)); /* Enable BUFFER STALL */ regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), @@ -497,13 +522,13 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); - int width = params_width(params); struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); struct asrc_config config; - int word_width, ret; + snd_pcm_format_t format; + int ret; ret = fsl_asrc_request_pair(channels, pair); if (ret) { @@ -513,15 +538,10 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, pair->config = &config; - if (width == 16) - width = ASRC_WIDTH_16_BIT; - else - width = ASRC_WIDTH_24_BIT; - if (asrc_priv->asrc_width == 16) - word_width = ASRC_WIDTH_16_BIT; + format = SNDRV_PCM_FORMAT_S16_LE; else - word_width = ASRC_WIDTH_24_BIT; + format = SNDRV_PCM_FORMAT_S24_LE; config.pair = pair->index; config.channel_num = channels; @@ -529,13 +549,13 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, config.outclk = OUTCLK_ASRCK1_CLK; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - config.input_word_width = width; - config.output_word_width = word_width; + config.input_format = params_format(params); + config.output_format = format; config.input_sample_rate = rate; config.output_sample_rate = asrc_priv->asrc_rate; } else { - config.input_word_width = word_width; - config.output_word_width = width; + config.input_format = format; + config.output_format = params_format(params); config.input_sample_rate = asrc_priv->asrc_rate; config.output_sample_rate = rate; } diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index c60075112570..38af485bdd22 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -342,8 +342,8 @@ struct asrc_config { unsigned int dma_buffer_size; unsigned int input_sample_rate; unsigned int output_sample_rate; - enum asrc_word_width input_word_width; - enum asrc_word_width output_word_width; + snd_pcm_format_t input_format; + snd_pcm_format_t output_format; enum asrc_inclk inclk; enum asrc_outclk outclk; }; -- cgit From 109539c986cee525e5ff9ae98793f23c2b29e54d Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 27 Sep 2019 09:46:10 +0800 Subject: ASoC: fsl_asrc: update supported sample format The ASRC support 24bit/16bit/8bit input width, which is data width, not slot width. For the S20_3LE format, the data with is 20bit, slot width is 24bit, if we set ASRMCR1n.IWD to be 24bits, the result is the volume is lower than expected, it likes 24bit data right shift 4 bits So replace S20_3LE with S24_3LE in supported list and add S8 format in TX supported list Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/45a7c383f43cc1dd9d0934846447aee653278c03.1569493933.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 4d3804a1ea55..584badf956d2 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -624,7 +624,7 @@ static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S20_3LE) + SNDRV_PCM_FMTBIT_S24_3LE) static struct snd_soc_dai_driver fsl_asrc_dai = { .probe = fsl_asrc_dai_probe, @@ -635,7 +635,8 @@ static struct snd_soc_dai_driver fsl_asrc_dai = { .rate_min = 5512, .rate_max = 192000, .rates = SNDRV_PCM_RATE_KNOT, - .formats = FSL_ASRC_FORMATS, + .formats = FSL_ASRC_FORMATS | + SNDRV_PCM_FMTBIT_S8, }, .capture = { .stream_name = "ASRC-Capture", -- cgit From e957204e732bc2916a241dc61dd7dd14e9a98350 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 27 Sep 2019 09:46:11 +0800 Subject: ASoC: pcm_dmaengine: Extract snd_dmaengine_pcm_refine_runtime_hwparams When set the runtime hardware parameters, we may need to query the capability of DMA to complete the parameters. This patch is to Extract this operation from dmaengine_pcm_set_runtime_hwparams function to a separate function snd_dmaengine_pcm_refine_runtime_hwparams, that other components which need this feature can call this function. Signed-off-by: Shengjiu Wang Reviewed-by: Nicolin Chen Link: https://lore.kernel.org/r/d728f65194e9978cbec4132b522d4fed420d704a.1569493933.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/core/pcm_dmaengine.c | 83 +++++++++++++++++++++++++++++++++++ sound/soc/soc-generic-dmaengine-pcm.c | 61 +++---------------------- 2 files changed, 89 insertions(+), 55 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 89a05926ac73..5749a8a49784 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -369,4 +369,87 @@ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan); +/** + * snd_dmaengine_pcm_refine_runtime_hwparams - Refine runtime hw params + * @substream: PCM substream + * @dma_data: DAI DMA data + * @hw: PCM hw params + * @chan: DMA channel to use for data transfers + * + * Returns 0 on success, a negative error code otherwise. + * + * This function will query DMA capability, then refine the pcm hardware + * parameters. + */ +int snd_dmaengine_pcm_refine_runtime_hwparams( + struct snd_pcm_substream *substream, + struct snd_dmaengine_dai_dma_data *dma_data, + struct snd_pcm_hardware *hw, + struct dma_chan *chan) +{ + struct dma_slave_caps dma_caps; + u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + snd_pcm_format_t i; + int ret = 0; + + if (!hw || !chan || !dma_data) + return -EINVAL; + + ret = dma_get_slave_caps(chan, &dma_caps); + if (ret == 0) { + if (dma_caps.cmd_pause && dma_caps.cmd_resume) + hw->info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; + if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT) + hw->info |= SNDRV_PCM_INFO_BATCH; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + addr_widths = dma_caps.dst_addr_widths; + else + addr_widths = dma_caps.src_addr_widths; + } + + /* + * If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep + * hw.formats set to 0, meaning no restrictions are in place. + * In this case it's the responsibility of the DAI driver to + * provide the supported format information. + */ + if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)) + /* + * Prepare formats mask for valid/allowed sample types. If the + * dma does not have support for the given physical word size, + * it needs to be masked out so user space can not use the + * format which produces corrupted audio. + * In case the dma driver does not implement the slave_caps the + * default assumption is that it supports 1, 2 and 4 bytes + * widths. + */ + for (i = SNDRV_PCM_FORMAT_FIRST; i <= SNDRV_PCM_FORMAT_LAST; i++) { + int bits = snd_pcm_format_physical_width(i); + + /* + * Enable only samples with DMA supported physical + * widths + */ + switch (bits) { + case 8: + case 16: + case 24: + case 32: + case 64: + if (addr_widths & (1 << (bits / 8))) + hw->formats |= pcm_format_to_bits(i); + break; + default: + /* Unsupported types */ + break; + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_refine_runtime_hwparams); + MODULE_LICENSE("GPL"); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 5552c66ca642..f2c98a9cbf75 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -118,12 +118,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea struct device *dma_dev = dmaengine_dma_dev(pcm, substream); struct dma_chan *chan = pcm->chan[substream->stream]; struct snd_dmaengine_dai_dma_data *dma_data; - struct dma_slave_caps dma_caps; struct snd_pcm_hardware hw; - u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | - BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | - BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); - snd_pcm_format_t i; int ret; if (pcm->config && pcm->config->pcm_hardware) @@ -145,56 +140,12 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) hw.info |= SNDRV_PCM_INFO_BATCH; - ret = dma_get_slave_caps(chan, &dma_caps); - if (ret == 0) { - if (dma_caps.cmd_pause && dma_caps.cmd_resume) - hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; - if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT) - hw.info |= SNDRV_PCM_INFO_BATCH; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - addr_widths = dma_caps.dst_addr_widths; - else - addr_widths = dma_caps.src_addr_widths; - } - - /* - * If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep - * hw.formats set to 0, meaning no restrictions are in place. - * In this case it's the responsibility of the DAI driver to - * provide the supported format information. - */ - if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)) - /* - * Prepare formats mask for valid/allowed sample types. If the - * dma does not have support for the given physical word size, - * it needs to be masked out so user space can not use the - * format which produces corrupted audio. - * In case the dma driver does not implement the slave_caps the - * default assumption is that it supports 1, 2 and 4 bytes - * widths. - */ - for (i = SNDRV_PCM_FORMAT_FIRST; i <= SNDRV_PCM_FORMAT_LAST; i++) { - int bits = snd_pcm_format_physical_width(i); - - /* - * Enable only samples with DMA supported physical - * widths - */ - switch (bits) { - case 8: - case 16: - case 24: - case 32: - case 64: - if (addr_widths & (1 << (bits / 8))) - hw.formats |= pcm_format_to_bits(i); - break; - default: - /* Unsupported types */ - break; - } - } + ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream, + dma_data, + &hw, + chan); + if (ret) + return ret; return snd_soc_set_runtime_hwparams(substream, &hw); } -- cgit From 703df4413ff6cf1812922522daa7c0610f087910 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 27 Sep 2019 09:46:12 +0800 Subject: ASoC: fsl_asrc: Fix error with S24_3LE format bitstream in i.MX8 There is error "aplay: pcm_write:2023: write error: Input/output error" on i.MX8QM/i.MX8QXP platform for S24_3LE format. In i.MX8QM/i.MX8QXP, the DMA is EDMA, which don't support 24bit sample, but we didn't add any constraint, that cause issues. So we need to query the caps of dma, then update the hw parameters according to the caps. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/b6a4de2bbf960ef291ee902afe4388bd0fc1d347.1569493933.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 4 +-- sound/soc/fsl/fsl_asrc.h | 3 +++ sound/soc/fsl/fsl_asrc_dma.c | 64 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 62 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 584badf956d2..0bf91a6f54b9 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -115,7 +115,7 @@ static void fsl_asrc_sel_proc(int inrate, int outrate, * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A * while pair A and pair C are comparatively independent. */ -static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) +int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) { enum asrc_pair_index index = ASRC_INVALID_PAIR; struct fsl_asrc *asrc_priv = pair->asrc_priv; @@ -158,7 +158,7 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) * * It clears the resource from asrc_priv and releases the occupied channels. */ -static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) +void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) { struct fsl_asrc *asrc_priv = pair->asrc_priv; enum asrc_pair_index index = pair->index; diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 38af485bdd22..2b57e8c53728 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -462,4 +462,7 @@ struct fsl_asrc { #define DRV_NAME "fsl-asrc-dai" extern struct snd_soc_component_driver fsl_asrc_component; struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir); +int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair); +void fsl_asrc_release_pair(struct fsl_asrc_pair *pair); + #endif /* _FSL_ASRC_H */ diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 01052a0808b0..2a60fc6142b1 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -16,13 +16,11 @@ #define FSL_ASRC_DMABUF_SIZE (256 * 1024) -static const struct snd_pcm_hardware snd_imx_hardware = { +static struct snd_pcm_hardware snd_imx_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, + SNDRV_PCM_INFO_MMAP_VALID, .buffer_bytes_max = FSL_ASRC_DMABUF_SIZE, .period_bytes_min = 128, .period_bytes_max = 65535, /* Limited by SDMA engine */ @@ -270,12 +268,25 @@ static int fsl_asrc_dma_hw_free(struct snd_pcm_substream *substream) static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream) { + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_dmaengine_dai_dma_data *dma_data; struct device *dev = component->dev; struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); struct fsl_asrc_pair *pair; + struct dma_chan *tmp_chan = NULL; + u8 dir = tx ? OUT : IN; + bool release_pair = true; + int ret = 0; + + ret = snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + dev_err(dev, "failed to set pcm hw params periods\n"); + return ret; + } pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL); if (!pair) @@ -285,11 +296,50 @@ static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream) runtime->private_data = pair; - snd_pcm_hw_constraint_integer(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIODS); + /* Request a dummy pair, which will be released later. + * Request pair function needs channel num as input, for this + * dummy pair, we just request "1" channel temporarily. + */ + ret = fsl_asrc_request_pair(1, pair); + if (ret < 0) { + dev_err(dev, "failed to request asrc pair\n"); + goto req_pair_err; + } + + /* Request a dummy dma channel, which will be released later. */ + tmp_chan = fsl_asrc_get_dma_channel(pair, dir); + if (!tmp_chan) { + dev_err(dev, "failed to get dma channel\n"); + ret = -EINVAL; + goto dma_chan_err; + } + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + /* Refine the snd_imx_hardware according to caps of DMA. */ + ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream, + dma_data, + &snd_imx_hardware, + tmp_chan); + if (ret < 0) { + dev_err(dev, "failed to refine runtime hwparams\n"); + goto out; + } + + release_pair = false; snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); - return 0; +out: + dma_release_channel(tmp_chan); + +dma_chan_err: + fsl_asrc_release_pair(pair); + +req_pair_err: + if (release_pair) + kfree(pair); + + return ret; } static int fsl_asrc_dma_shutdown(struct snd_pcm_substream *substream) -- cgit From 4378f1fbe924054a09ff0d4e39e1a581b9245252 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 27 Sep 2019 10:16:46 +0300 Subject: ASoC: soc-pcm: Use different sequence for start/stop trigger On stream stop currently we stop the DMA first followed by the CPU DAI. This can cause underflow (playback) or overflow (capture) on the DAI side as the DMA is no longer feeding data while the DAI is still active. It can be observed easily if the DAI side does not have FIFO (or it is disabled) to survive the time while the DMA is stopped, but still can happen on relatively slow CPUs when relatively high sampling rate is used: the FIFO is drained between the time the DMA is stopped and the DAI is stopped. It can only fixed by using different sequence within trigger for 'stop' and 'start': case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: Trigger order: dai_link, DMA, CPU DAI then the codec case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: Trigger order: codec, CPU DAI, DMA then dai_link Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190927071646.22319-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e163dde5eab1..e7a04c892817 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1047,7 +1047,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_component *component; @@ -1056,8 +1056,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_dai *codec_dai; int i, ret; - for_each_rtd_codec_dai(rtd, i, codec_dai) { - ret = snd_soc_dai_trigger(codec_dai, substream, cmd); + if (rtd->dai_link->ops->trigger) { + ret = rtd->dai_link->ops->trigger(substream, cmd); if (ret < 0) return ret; } @@ -1074,6 +1074,42 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (ret < 0) return ret; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + ret = snd_soc_dai_trigger(codec_dai, substream, cmd); + if (ret < 0) + return ret; + } + + return 0; +} + +static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; + int i, ret; + + for_each_rtd_codec_dai(rtd, i, codec_dai) { + ret = snd_soc_dai_trigger(codec_dai, substream, cmd); + if (ret < 0) + return ret; + } + + ret = snd_soc_dai_trigger(cpu_dai, substream, cmd); + if (ret < 0) + return ret; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + ret = snd_soc_component_trigger(component, substream, cmd); + if (ret < 0) + return ret; + } + if (rtd->dai_link->ops->trigger) { ret = rtd->dai_link->ops->trigger(substream, cmd); if (ret < 0) @@ -1083,6 +1119,28 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } +static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = soc_pcm_trigger_start(substream, cmd); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = soc_pcm_trigger_stop(substream, cmd); + break; + default: + return -EINVAL; + } + + return ret; +} + static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, int cmd) { -- cgit From 1a476abc723e644248dba975b71122fcf878703b Mon Sep 17 00:00:00 2001 From: Frank Shi Date: Fri, 20 Sep 2019 14:58:29 +0800 Subject: tas2770: add tas2770 smart PA kernel driver add tas2770 smart PA kernel driver Signed-off-by: Frank Shi Link: https://lore.kernel.org/r/1568962709-19185-2-git-send-email-shifu0704@thundersoft.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas2770.c | 808 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas2770.h | 164 +++++++++ 4 files changed, 979 insertions(+) create mode 100644 sound/soc/codecs/tas2770.c create mode 100644 sound/soc/codecs/tas2770.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 229cc89f8c5a..bcac95785493 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -179,6 +179,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_STI_SAS select SND_SOC_TAS2552 if I2C + select SND_SOC_TAS2770 if I2C select SND_SOC_TAS5086 if I2C select SND_SOC_TAS571X if I2C select SND_SOC_TAS5720 if I2C @@ -1104,6 +1105,10 @@ config SND_SOC_TAS2552 tristate "Texas Instruments TAS2552 Mono Audio amplifier" depends on I2C +config SND_SOC_TAS2770 + tristate "Texas Instruments TAS2770 speaker amplifier" + depends on I2C + config SND_SOC_TAS5086 tristate "Texas Instruments TAS5086 speaker amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index c498373dcc5f..73b2d5982dcb 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -196,6 +196,7 @@ snd-soc-tas571x-objs := tas571x.o snd-soc-tas5720-objs := tas5720.o snd-soc-tas6424-objs := tas6424.o snd-soc-tda7419-objs := tda7419.o +snd-soc-tas2770-objs := tas2770.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -479,6 +480,7 @@ obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o +obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c new file mode 100644 index 000000000000..9da88ccb1d51 --- /dev/null +++ b/sound/soc/codecs/tas2770.c @@ -0,0 +1,808 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// ALSA SoC Texas Instruments TAS2770 20-W Digital Input Mono Class-D +// Audio Amplifier with Speaker I/V Sense +// +// Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ +// Author: Tracy Yi +// Frank Shi + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tas2770.h" + +#define TAS2770_MDELAY 0xFFFFFFFE + +static void tas2770_reset(struct tas2770_priv *tas2770) +{ + if (tas2770->reset_gpio) { + gpiod_set_value_cansleep(tas2770->reset_gpio, 0); + msleep(20); + gpiod_set_value_cansleep(tas2770->reset_gpio, 1); + } + snd_soc_component_write(tas2770->component, TAS2770_SW_RST, + TAS2770_RST); +} + +static int tas2770_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct tas2770_priv *tas2770 = + snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_ON: + snd_soc_component_update_bits(component, + TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, + TAS2770_PWR_CTRL_ACTIVE); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_component_update_bits(component, + TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, + TAS2770_PWR_CTRL_SHUTDOWN); + break; + + default: + dev_err(tas2770->dev, + "wrong power level setting %d\n", level); + return -EINVAL; + } + + return 0; +} + +#ifdef CONFIG_PM +static int tas2770_codec_suspend(struct snd_soc_component *component) +{ + int ret; + + ret = snd_soc_component_update_bits(component, + TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, + TAS2770_PWR_CTRL_SHUTDOWN); + if (ret) + return ret; + + return 0; +} + +static int tas2770_codec_resume(struct snd_soc_component *component) +{ + int ret; + + ret = snd_soc_component_update_bits(component, + TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, + TAS2770_PWR_CTRL_ACTIVE); + if (ret) + return -EINVAL; + + return 0; +} +#else +#define tas2770_codec_suspend NULL +#define tas2770_codec_resume NULL +#endif + +static const char * const tas2770_ASI1_src[] = { + "I2C offset", "Left", "Right", "LeftRightDiv2", +}; + +static SOC_ENUM_SINGLE_DECL( + tas2770_ASI1_src_enum, TAS2770_TDM_CFG_REG2, + 4, tas2770_ASI1_src); + +static const struct snd_kcontrol_new tas2770_asi1_mux = + SOC_DAPM_ENUM("ASI1 Source", tas2770_ASI1_src_enum); + +static int tas2770_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tas2770_priv *tas2770 = + snd_soc_component_get_drvdata(component); + int ret; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + ret = snd_soc_component_update_bits(component, + TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, + TAS2770_PWR_CTRL_MUTE); + if (ret) + goto end; + break; + case SND_SOC_DAPM_PRE_PMD: + ret = snd_soc_component_update_bits(component, + TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, + TAS2770_PWR_CTRL_SHUTDOWN); + if (ret) + goto end; + break; + default: + dev_err(tas2770->dev, "Not supported evevt\n"); + return -EINVAL; + } + +end: + return ret; +} + +static const struct snd_kcontrol_new isense_switch = + SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 3, 1, 1); +static const struct snd_kcontrol_new vsense_switch = + SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 2, 1, 1); + +static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, + &tas2770_asi1_mux), + SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PWR_CTRL, 3, 1, + &isense_switch), + SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PWR_CTRL, 2, 1, + &vsense_switch), + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUTPUT("OUT"), + SND_SOC_DAPM_SIGGEN("VMON"), + SND_SOC_DAPM_SIGGEN("IMON") +}; + +static const struct snd_soc_dapm_route tas2770_audio_map[] = { + {"ASI1 Sel", "I2C offset", "ASI1"}, + {"ASI1 Sel", "Left", "ASI1"}, + {"ASI1 Sel", "Right", "ASI1"}, + {"ASI1 Sel", "LeftRightDiv2", "ASI1"}, + {"DAC", NULL, "ASI1 Sel"}, + {"OUT", NULL, "DAC"}, + {"ISENSE", "Switch", "IMON"}, + {"VSENSE", "Switch", "VMON"}, +}; + +static int tas2770_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + int ret; + + if (mute) + ret = snd_soc_component_update_bits(component, + TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, + TAS2770_PWR_CTRL_MUTE); + else + ret = snd_soc_component_update_bits(component, + TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, + TAS2770_PWR_CTRL_ACTIVE); + + return ret; +} + +static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth) +{ + int ret; + struct snd_soc_component *component = tas2770->component; + + switch (bitwidth) { + case SNDRV_PCM_FORMAT_S16_LE: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG2, + TAS2770_TDM_CFG_REG2_RXW_MASK, + TAS2770_TDM_CFG_REG2_RXW_16BITS); + tas2770->v_sense_slot = tas2770->i_sense_slot + 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG2, + TAS2770_TDM_CFG_REG2_RXW_MASK, + TAS2770_TDM_CFG_REG2_RXW_24BITS); + tas2770->v_sense_slot = tas2770->i_sense_slot + 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG2, + TAS2770_TDM_CFG_REG2_RXW_MASK, + TAS2770_TDM_CFG_REG2_RXW_32BITS); + tas2770->v_sense_slot = tas2770->i_sense_slot + 4; + break; + + default: + return -EINVAL; + } + + tas2770->channel_size = bitwidth; + + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG5, + TAS2770_TDM_CFG_REG5_VSNS_MASK | + TAS2770_TDM_CFG_REG5_50_MASK, + TAS2770_TDM_CFG_REG5_VSNS_ENABLE | + tas2770->v_sense_slot); + if (ret) + goto end; + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG6, + TAS2770_TDM_CFG_REG6_ISNS_MASK | + TAS2770_TDM_CFG_REG6_50_MASK, + TAS2770_TDM_CFG_REG6_ISNS_ENABLE | + tas2770->i_sense_slot); + +end: + return ret; +} + +static int tas2770_set_samplerate(struct tas2770_priv *tas2770, int samplerate) +{ + int ret; + struct snd_soc_component *component = tas2770->component; + + switch (samplerate) { + case 48000: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_SMP_MASK, + TAS2770_TDM_CFG_REG0_SMP_48KHZ); + if (ret) + goto end; + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_31_MASK, + TAS2770_TDM_CFG_REG0_31_44_1_48KHZ); + if (ret) + goto end; + break; + case 44100: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_SMP_MASK, + TAS2770_TDM_CFG_REG0_SMP_44_1KHZ); + if (ret) + goto end; + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_31_MASK, + TAS2770_TDM_CFG_REG0_31_44_1_48KHZ); + if (ret) + goto end; + break; + case 96000: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_SMP_MASK, + TAS2770_TDM_CFG_REG0_SMP_48KHZ); + if (ret) + goto end; + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_31_MASK, + TAS2770_TDM_CFG_REG0_31_88_2_96KHZ); + break; + case 88200: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_SMP_MASK, + TAS2770_TDM_CFG_REG0_SMP_44_1KHZ); + if (ret) + goto end; + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_31_MASK, + TAS2770_TDM_CFG_REG0_31_88_2_96KHZ); + break; + case 19200: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_SMP_MASK, + TAS2770_TDM_CFG_REG0_SMP_48KHZ); + if (ret) + goto end; + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_31_MASK, + TAS2770_TDM_CFG_REG0_31_176_4_192KHZ); + if (ret) + goto end; + break; + case 17640: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_SMP_MASK, + TAS2770_TDM_CFG_REG0_SMP_44_1KHZ); + if (ret) + goto end; + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_31_MASK, + TAS2770_TDM_CFG_REG0_31_176_4_192KHZ); + break; + default: + ret = -EINVAL; + } + +end: + if (!ret) + tas2770->sampling_rate = samplerate; + return ret; +} + +static int tas2770_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct tas2770_priv *tas2770 = + snd_soc_component_get_drvdata(component); + int ret; + + ret = tas2770_set_bitwidth(tas2770, params_format(params)); + if (ret < 0) + goto end; + + + ret = tas2770_set_samplerate(tas2770, params_rate(params)); + +end: + return ret; +} + +static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; + int ret; + int value = 0; + struct snd_soc_component *component = dai->component; + struct tas2770_priv *tas2770 = + snd_soc_component_get_drvdata(component); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + dev_err(tas2770->dev, "ASI format master is not found\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_RSING; + break; + case SND_SOC_DAIFMT_IB_NF: + asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_FALING; + break; + default: + dev_err(tas2770->dev, "ASI format Inverse is not found\n"); + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1, + TAS2770_TDM_CFG_REG1_RX_MASK, + asi_cfg_1); + if (ret) + return ret; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + tdm_rx_start_slot = 1; + break; + case SND_SOC_DAIFMT_DSP_A: + tdm_rx_start_slot = 0; + break; + case SND_SOC_DAIFMT_DSP_B: + tdm_rx_start_slot = 1; + break; + case SND_SOC_DAIFMT_LEFT_J: + tdm_rx_start_slot = 0; + break; + default: + dev_err(tas2770->dev, + "DAI Format is not found, fmt=0x%x\n", fmt); + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1, + TAS2770_TDM_CFG_REG1_MASK, + (tdm_rx_start_slot << TAS2770_TDM_CFG_REG1_51_SHIFT)); + if (ret) + return ret; + + value = snd_soc_component_read32(component, TAS2770_TDM_CFG_REG3); + + tas2770->asi_format = fmt; + + return 0; +} + +static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct tas2770_priv *tas2770 = + snd_soc_component_get_drvdata(component); + int left_slot, right_slot; + int ret; + + if (tx_mask == 0 || rx_mask != 0) + return -EINVAL; + + if (slots == 1) { + if (tx_mask != 1) + return -EINVAL; + left_slot = 0; + right_slot = 0; + } else { + left_slot = __ffs(tx_mask); + tx_mask &= ~(1 << left_slot); + if (tx_mask == 0) { + right_slot = left_slot; + } else { + right_slot = __ffs(tx_mask); + tx_mask &= ~(1 << right_slot); + } + } + + if (tx_mask != 0 || left_slot >= slots || right_slot >= slots) + return -EINVAL; + + ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3, + TAS2770_TDM_CFG_REG3_30_MASK, + (left_slot << TAS2770_TDM_CFG_REG3_30_SHIFT)); + if (ret) + return ret; + ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3, + TAS2770_TDM_CFG_REG3_RXS_MASK, + (right_slot << TAS2770_TDM_CFG_REG3_RXS_SHIFT)); + if (ret) + return ret; + + switch (slot_width) { + case 16: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG2, + TAS2770_TDM_CFG_REG2_RXS_MASK, + TAS2770_TDM_CFG_REG2_RXS_16BITS); + break; + + case 24: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG2, + TAS2770_TDM_CFG_REG2_RXS_MASK, + TAS2770_TDM_CFG_REG2_RXS_24BITS); + break; + + case 32: + ret = snd_soc_component_update_bits(component, + TAS2770_TDM_CFG_REG2, + TAS2770_TDM_CFG_REG2_RXS_MASK, + TAS2770_TDM_CFG_REG2_RXS_32BITS); + break; + + case 0: + /* Do not change slot width */ + ret = 0; + break; + + default: + ret = -EINVAL; + } + + if (!ret) + tas2770->slot_width = slot_width; + + return ret; +} + +static struct snd_soc_dai_ops tas2770_dai_ops = { + .digital_mute = tas2770_mute, + .hw_params = tas2770_hw_params, + .set_fmt = tas2770_set_fmt, + .set_tdm_slot = tas2770_set_dai_tdm_slot, +}; + +#define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000\ + ) + +static struct snd_soc_dai_driver tas2770_dai_driver[] = { + { + .name = "tas2770 ASI1", + .id = 0, + .playback = { + .stream_name = "ASI1 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = TAS2770_RATES, + .formats = TAS2770_FORMATS, + }, + .capture = { + .stream_name = "ASI1 Capture", + .channels_min = 0, + .channels_max = 2, + .rates = TAS2770_RATES, + .formats = TAS2770_FORMATS, + }, + .ops = &tas2770_dai_ops, + .symmetric_rates = 1, + }, +}; + +static int tas2770_codec_probe(struct snd_soc_component *component) +{ + struct tas2770_priv *tas2770 = + snd_soc_component_get_drvdata(component); + + tas2770->component = component; + + return 0; +} + +static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0); +static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -12750, 50, 0); + +static const struct snd_kcontrol_new tas2770_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Playback Volume", TAS2770_PLAY_CFG_REG2, + 0, TAS2770_PLAY_CFG_REG2_VMAX, 1, + tas2770_playback_volume), + SOC_SINGLE_TLV("Amp Gain Volume", TAS2770_PLAY_CFG_REG0, + 0, 0x14, 0, + tas2770_digital_tlv), +}; + +static const struct snd_soc_component_driver soc_component_driver_tas2770 = { + .probe = tas2770_codec_probe, + .suspend = tas2770_codec_suspend, + .resume = tas2770_codec_resume, + .set_bias_level = tas2770_set_bias_level, + .controls = tas2770_snd_controls, + .num_controls = ARRAY_SIZE(tas2770_snd_controls), + .dapm_widgets = tas2770_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas2770_dapm_widgets), + .dapm_routes = tas2770_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas2770_audio_map), + .idle_bias_on = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static int tas2770_register_codec(struct tas2770_priv *tas2770) +{ + return devm_snd_soc_register_component(tas2770->dev, + &soc_component_driver_tas2770, + tas2770_dai_driver, ARRAY_SIZE(tas2770_dai_driver)); +} + +static const struct reg_default tas2770_reg_defaults[] = { + { TAS2770_PAGE, 0x00 }, + { TAS2770_SW_RST, 0x00 }, + { TAS2770_PWR_CTRL, 0x0e }, + { TAS2770_PLAY_CFG_REG0, 0x10 }, + { TAS2770_PLAY_CFG_REG1, 0x01 }, + { TAS2770_PLAY_CFG_REG2, 0x00 }, + { TAS2770_MSC_CFG_REG0, 0x07 }, + { TAS2770_TDM_CFG_REG1, 0x02 }, + { TAS2770_TDM_CFG_REG2, 0x0a }, + { TAS2770_TDM_CFG_REG3, 0x10 }, + { TAS2770_INT_MASK_REG0, 0xfc }, + { TAS2770_INT_MASK_REG1, 0xb1 }, + { TAS2770_INT_CFG, 0x05 }, + { TAS2770_MISC_IRQ, 0x81 }, + { TAS2770_CLK_CGF, 0x0c }, + +}; + +static bool tas2770_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAS2770_PAGE: /* regmap implementation requires this */ + case TAS2770_SW_RST: /* always clears after write */ + case TAS2770_BO_PRV_REG0:/* has a self clearing bit */ + case TAS2770_LVE_INT_REG0: + case TAS2770_LVE_INT_REG1: + case TAS2770_LAT_INT_REG0:/* Sticky interrupt flags */ + case TAS2770_LAT_INT_REG1:/* Sticky interrupt flags */ + case TAS2770_VBAT_MSB: + case TAS2770_VBAT_LSB: + case TAS2770_TEMP_MSB: + case TAS2770_TEMP_LSB: + return true; + } + return false; +} + +static bool tas2770_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAS2770_LVE_INT_REG0: + case TAS2770_LVE_INT_REG1: + case TAS2770_LAT_INT_REG0: + case TAS2770_LAT_INT_REG1: + case TAS2770_VBAT_MSB: + case TAS2770_VBAT_LSB: + case TAS2770_TEMP_MSB: + case TAS2770_TEMP_LSB: + case TAS2770_TDM_CLK_DETC: + case TAS2770_REV_AND_GPID: + return false; + } + return true; +} + +static const struct regmap_range_cfg tas2770_regmap_ranges[] = { + { + .range_min = 0, + .range_max = 1 * 128, + .selector_reg = TAS2770_PAGE, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 128, + }, +}; + +static const struct regmap_config tas2770_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = tas2770_writeable, + .volatile_reg = tas2770_volatile, + .reg_defaults = tas2770_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tas2770_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .ranges = tas2770_regmap_ranges, + .num_ranges = ARRAY_SIZE(tas2770_regmap_ranges), + .max_register = 1 * 128, +}; + +static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770) +{ + int rc = 0; + + rc = fwnode_property_read_u32(dev->fwnode, "ti,asi-format", + &tas2770->asi_format); + if (rc) { + dev_err(tas2770->dev, "Looking up %s property failed %d\n", + "ti,asi-format", rc); + goto end; + } + + rc = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no", + &tas2770->i_sense_slot); + if (rc) { + dev_err(tas2770->dev, "Looking up %s property failed %d\n", + "ti,imon-slot-no", rc); + goto end; + } + + rc = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no", + &tas2770->v_sense_slot); + if (rc) { + dev_err(tas2770->dev, "Looking up %s property failed %d\n", + "ti,vmon-slot-no", rc); + goto end; + } + +end: + return rc; +} + +static int tas2770_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tas2770_priv *tas2770; + int result; + + tas2770 = devm_kzalloc(&client->dev, + sizeof(struct tas2770_priv), GFP_KERNEL); + if (!tas2770) + return -ENOMEM; + tas2770->dev = &client->dev; + + i2c_set_clientdata(client, tas2770); + dev_set_drvdata(&client->dev, tas2770); + tas2770->power_state = TAS2770_POWER_SHUTDOWN; + + tas2770->regmap = devm_regmap_init_i2c(client, &tas2770_i2c_regmap); + if (IS_ERR(tas2770->regmap)) { + result = PTR_ERR(tas2770->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + result); + goto end; + } + + if (client->dev.of_node) { + result = tas2770_parse_dt(&client->dev, tas2770); + if (result) { + dev_err(tas2770->dev, "%s: Failed to parse devicetree\n", + __func__); + goto end; + } + } + + tas2770->reset_gpio = devm_gpiod_get_optional(tas2770->dev, + "reset-gpio", + GPIOD_OUT_HIGH); + if (IS_ERR(tas2770->reset_gpio)) { + if (PTR_ERR(tas2770->reset_gpio) == -EPROBE_DEFER) { + tas2770->reset_gpio = NULL; + return -EPROBE_DEFER; + } + } + + tas2770->channel_size = 0; + tas2770->slot_width = 0; + + tas2770_reset(tas2770); + + result = tas2770_register_codec(tas2770); + if (result) + dev_err(tas2770->dev, "Register codec failed.\n"); + +end: + return result; +} + +static int tas2770_i2c_remove(struct i2c_client *client) +{ + pm_runtime_disable(&client->dev); + return 0; +} + + +static const struct i2c_device_id tas2770_i2c_id[] = { + { "tas2770", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas2770_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id tas2770_of_match[] = { + { .compatible = "ti,tas2770" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tas2770_of_match); +#endif + +static struct i2c_driver tas2770_i2c_driver = { + .driver = { + .name = "tas2770", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tas2770_of_match), + }, + .probe = tas2770_i2c_probe, + .remove = tas2770_i2c_remove, + .id_table = tas2770_i2c_id, +}; + +module_i2c_driver(tas2770_i2c_driver); + +MODULE_AUTHOR("Shi Fu "); +MODULE_DESCRIPTION("TAS2770 I2C Smart Amplifier driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/tas2770.h b/sound/soc/codecs/tas2770.h new file mode 100644 index 000000000000..d597a8280707 --- /dev/null +++ b/sound/soc/codecs/tas2770.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * ALSA SoC TAS2770 codec driver + * + * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ + */ +#ifndef __TAS2770__ +#define __TAS2770__ + +/* Book Control Register (available in page0 of each book) */ +#define TAS2770_BOOKCTL_PAGE 0 +#define TAS2770_BOOKCTL_REG 127 +#define TAS2770_REG(page, reg) ((page * 128) + reg) + /* Page */ +#define TAS2770_PAGE TAS2770_REG(0X0, 0x00) +#define TAS2770_PAGE_PAGE_MASK 255 + /* Software Reset */ +#define TAS2770_SW_RST TAS2770_REG(0X0, 0x01) +#define TAS2770_RST BIT(0) + /* Power Control */ +#define TAS2770_PWR_CTRL TAS2770_REG(0X0, 0x02) +#define TAS2770_PWR_CTRL_MASK 0x3 +#define TAS2770_PWR_CTRL_ACTIVE 0x0 +#define TAS2770_PWR_CTRL_MUTE BIT(0) +#define TAS2770_PWR_CTRL_SHUTDOWN 0x2 + /* Playback Configuration Reg0 */ +#define TAS2770_PLAY_CFG_REG0 TAS2770_REG(0X0, 0x03) + /* Playback Configuration Reg1 */ +#define TAS2770_PLAY_CFG_REG1 TAS2770_REG(0X0, 0x04) + /* Playback Configuration Reg2 */ +#define TAS2770_PLAY_CFG_REG2 TAS2770_REG(0X0, 0x05) +#define TAS2770_PLAY_CFG_REG2_VMAX 0xc9 + /* Misc Configuration Reg0 */ +#define TAS2770_MSC_CFG_REG0 TAS2770_REG(0X0, 0x07) + /* TDM Configuration Reg0 */ +#define TAS2770_TDM_CFG_REG0 TAS2770_REG(0X0, 0x0A) +#define TAS2770_TDM_CFG_REG0_SMP_MASK BIT(5) +#define TAS2770_TDM_CFG_REG0_SMP_48KHZ 0x0 +#define TAS2770_TDM_CFG_REG0_SMP_44_1KHZ BIT(5) +#define TAS2770_TDM_CFG_REG0_31_MASK 0xe +#define TAS2770_TDM_CFG_REG0_31_44_1_48KHZ 0x6 +#define TAS2770_TDM_CFG_REG0_31_88_2_96KHZ 0x8 +#define TAS2770_TDM_CFG_REG0_31_176_4_192KHZ 0xa + /* TDM Configuration Reg1 */ +#define TAS2770_TDM_CFG_REG1 TAS2770_REG(0X0, 0x0B) +#define TAS2770_TDM_CFG_REG1_MASK 0x3e +#define TAS2770_TDM_CFG_REG1_51_SHIFT 1 +#define TAS2770_TDM_CFG_REG1_RX_MASK BIT(0) +#define TAS2770_TDM_CFG_REG1_RX_RSING 0x0 +#define TAS2770_TDM_CFG_REG1_RX_FALING BIT(0) + /* TDM Configuration Reg2 */ +#define TAS2770_TDM_CFG_REG2 TAS2770_REG(0X0, 0x0C) +#define TAS2770_TDM_CFG_REG2_RXW_MASK 0xc +#define TAS2770_TDM_CFG_REG2_RXW_16BITS 0x0 +#define TAS2770_TDM_CFG_REG2_RXW_24BITS 0x8 +#define TAS2770_TDM_CFG_REG2_RXW_32BITS 0xc +#define TAS2770_TDM_CFG_REG2_RXS_MASK 0x3 +#define TAS2770_TDM_CFG_REG2_RXS_16BITS 0x0 +#define TAS2770_TDM_CFG_REG2_RXS_24BITS BIT(0) +#define TAS2770_TDM_CFG_REG2_RXS_32BITS 0x2 + /* TDM Configuration Reg3 */ +#define TAS2770_TDM_CFG_REG3 TAS2770_REG(0X0, 0x0D) +#define TAS2770_TDM_CFG_REG3_RXS_MASK 0xf0 +#define TAS2770_TDM_CFG_REG3_RXS_SHIFT 0x4 +#define TAS2770_TDM_CFG_REG3_30_MASK 0xf +#define TAS2770_TDM_CFG_REG3_30_SHIFT 0 + /* TDM Configuration Reg5 */ +#define TAS2770_TDM_CFG_REG5 TAS2770_REG(0X0, 0x0F) +#define TAS2770_TDM_CFG_REG5_VSNS_MASK BIT(6) +#define TAS2770_TDM_CFG_REG5_VSNS_ENABLE BIT(6) +#define TAS2770_TDM_CFG_REG5_50_MASK 0x3f + /* TDM Configuration Reg6 */ +#define TAS2770_TDM_CFG_REG6 TAS2770_REG(0X0, 0x10) +#define TAS2770_TDM_CFG_REG6_ISNS_MASK BIT(6) +#define TAS2770_TDM_CFG_REG6_ISNS_ENABLE BIT(6) +#define TAS2770_TDM_CFG_REG6_50_MASK 0x3f + /* Brown Out Prevention Reg0 */ +#define TAS2770_BO_PRV_REG0 TAS2770_REG(0X0, 0x1B) + /* Interrupt MASK Reg0 */ +#define TAS2770_INT_MASK_REG0 TAS2770_REG(0X0, 0x20) +#define TAS2770_INT_REG0_DEFAULT 0xfc +#define TAS2770_INT_MASK_REG0_DISABLE 0xff + /* Interrupt MASK Reg1 */ +#define TAS2770_INT_MASK_REG1 TAS2770_REG(0X0, 0x21) +#define TAS2770_INT_REG1_DEFAULT 0xb1 +#define TAS2770_INT_MASK_REG1_DISABLE 0xff + /* Live-Interrupt Reg0 */ +#define TAS2770_LVE_INT_REG0 TAS2770_REG(0X0, 0x22) + /* Live-Interrupt Reg1 */ +#define TAS2770_LVE_INT_REG1 TAS2770_REG(0X0, 0x23) + /* Latched-Interrupt Reg0 */ +#define TAS2770_LAT_INT_REG0 TAS2770_REG(0X0, 0x24) +#define TAS2770_LAT_INT_REG0_OCE_FLG BIT(1) +#define TAS2770_LAT_INT_REG0_OTE_FLG BIT(0) + /* Latched-Interrupt Reg1 */ +#define TAS2770_LAT_INT_REG1 TAS2770_REG(0X0, 0x25) +#define TAS2770_LAT_INT_REG1_VBA_TOV BIT(3) +#define TAS2770_LAT_INT_REG1_VBA_TUV BIT(2) +#define TAS2770_LAT_INT_REG1_BOUT_FLG BIT(1) + /* VBAT MSB */ +#define TAS2770_VBAT_MSB TAS2770_REG(0X0, 0x27) + /* VBAT LSB */ +#define TAS2770_VBAT_LSB TAS2770_REG(0X0, 0x28) + /* TEMP MSB */ +#define TAS2770_TEMP_MSB TAS2770_REG(0X0, 0x29) + /* TEMP LSB */ +#define TAS2770_TEMP_LSB TAS2770_REG(0X0, 0x2A) + /* Interrupt Configuration */ +#define TAS2770_INT_CFG TAS2770_REG(0X0, 0x30) + /* Misc IRQ */ +#define TAS2770_MISC_IRQ TAS2770_REG(0X0, 0x32) + /* Clock Configuration */ +#define TAS2770_CLK_CGF TAS2770_REG(0X0, 0x3C) + /* TDM Clock detection monitor */ +#define TAS2770_TDM_CLK_DETC TAS2770_REG(0X0, 0x77) + /* Revision and PG ID */ +#define TAS2770_REV_AND_GPID TAS2770_REG(0X0, 0x7D) + +#define TAS2770_POWER_ACTIVE 0 +#define TAS2770_POWER_MUTE 1 +#define TAS2770_POWER_SHUTDOWN 2 +#define ERROR_OVER_CURRENT 0x0000001 +#define ERROR_DIE_OVERTEMP 0x0000002 +#define ERROR_OVER_VOLTAGE 0x0000004 +#define ERROR_UNDER_VOLTAGE 0x0000008 +#define ERROR_BROWNOUT 0x0000010 +#define ERROR_CLASSD_PWR 0x0000020 +#define TAS2770_SLOT_16BIT 16 +#define TAS2770_SLOT_32BIT 32 +#define TAS2770_I2C_RETRY_COUNT 3 + +struct tas2770_register { + int book; + int page; + int reg; +}; + +struct tas2770_dai_cfg { + unsigned int dai_fmt; + unsigned int tdm_delay; +}; + +struct tas2770_priv { + struct device *dev; + struct regmap *regmap; + struct snd_soc_codec *codec; + struct snd_soc_component *component; + struct mutex dev_lock; + struct hrtimer mtimer; + int power_state; + int asi_format; + struct gpio_desc *reset_gpio; + int sampling_rate; + int frame_size; + int channel_size; + int slot_width; + int v_sense_slot; + int i_sense_slot; + bool runtime_suspend; + unsigned int err_code; + struct mutex codec_lock; +}; + +#endif /* __TAS2770__ */ -- cgit From 767b0bc590576cfda6e6bf2cd45fb8e1843b3ecb Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 1 Oct 2019 14:57:00 +0100 Subject: ASoC: madera: Add support for using MCLK3 Some Madera CODECs have a third MCLK pin allow this to be sourced for the FLLs and system clocks. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20191001135700.31017-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/madera.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/madera.h b/sound/soc/codecs/madera.h index 1f3e8e230cf2..6d8938a3fb64 100644 --- a/sound/soc/codecs/madera.h +++ b/sound/soc/codecs/madera.h @@ -27,6 +27,7 @@ #define MADERA_FLL_SRC_NONE -1 #define MADERA_FLL_SRC_MCLK1 0 #define MADERA_FLL_SRC_MCLK2 1 +#define MADERA_FLL_SRC_MCLK3 2 #define MADERA_FLL_SRC_SLIMCLK 3 #define MADERA_FLL_SRC_FLL1 4 #define MADERA_FLL_SRC_FLL2 5 @@ -51,6 +52,7 @@ #define MADERA_CLK_SRC_MCLK1 0x0 #define MADERA_CLK_SRC_MCLK2 0x1 +#define MADERA_CLK_SRC_MCLK3 0x2 #define MADERA_CLK_SRC_FLL1 0x4 #define MADERA_CLK_SRC_FLL2 0x5 #define MADERA_CLK_SRC_FLL3 0x6 -- cgit From 2ab4c50f6955514150f83b47b7aee3ba5fe3ac1d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 27 Sep 2019 15:05:28 -0500 Subject: ASoC: SOF: trace: move to opt-in with Kconfig and module parameter In a number of debug cases, the DMA-based trace can add problems (e.g. with HDaudio channel allocation). It also generates additional traffic on the bus and if the DMA handling is unreliable will prevent audio use-cases from working normally. Using the trace also requires tools to be installed on the target. The trace can be instead handled as dynamic debug. We can use a Kconfig to force the trace to be enabled in all cases, or use a module parameter to enable it on a need-basis, e.g. by setting "options snd_sof sof_debug=0x1" in a /etc/modprobe.d file. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190927200538.660-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 8 ++++++++ sound/soc/sof/core.c | 25 +++++++++++++++++++------ sound/soc/sof/sof-priv.h | 13 +++++++++---- sound/soc/sof/trace.c | 17 ++++++++++++++++- 4 files changed, 52 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index bb8036ae567e..cc592bcadae7 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -142,6 +142,14 @@ config SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE Say Y if you want to enable caching the memory windows. If unsure, select "N". +config SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE + bool "SOF enable firmware trace" + help + The firmware trace can be enabled either at build-time with + this option, or dynamically by setting flags in the SOF core + module parameter (similar to dynamic debug) + If unsure, select "N". + config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST bool "SOF enable IPC flood test" help diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 81f28f7ff1a0..15167b8220ed 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -16,6 +16,11 @@ #include "sof-priv.h" #include "ops.h" +/* see SOF_DBG_ flags */ +int sof_core_debug; +module_param_named(sof_debug, sof_core_debug, int, 0444); +MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); + /* SOF defaults if not provided by the platform in ms */ #define TIMEOUT_DEFAULT_IPC_MS 500 #define TIMEOUT_DEFAULT_BOOT_MS 2000 @@ -350,12 +355,20 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_run_err; } - /* init DMA trace */ - ret = snd_sof_init_trace(sdev); - if (ret < 0) { - /* non fatal */ - dev_warn(sdev->dev, - "warning: failed to initialize trace %d\n", ret); + if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) || + (sof_core_debug & SOF_DBG_ENABLE_TRACE)) { + sdev->dtrace_is_supported = true; + + /* init DMA trace */ + ret = snd_sof_init_trace(sdev); + if (ret < 0) { + /* non fatal */ + dev_warn(sdev->dev, + "warning: failed to initialize trace %d\n", + ret); + } + } else { + dev_dbg(sdev->dev, "SOF firmware trace disabled\n"); } /* hereafter all FW boot flows are for PM reasons */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 730f3259dd02..d5b1a4f895da 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -28,10 +28,14 @@ #include /* debug flags */ -#define SOF_DBG_REGS BIT(1) -#define SOF_DBG_MBOX BIT(2) -#define SOF_DBG_TEXT BIT(3) -#define SOF_DBG_PCI BIT(4) +#define SOF_DBG_ENABLE_TRACE BIT(0) +#define SOF_DBG_REGS BIT(1) +#define SOF_DBG_MBOX BIT(2) +#define SOF_DBG_TEXT BIT(3) +#define SOF_DBG_PCI BIT(4) + +/* global debug state set by SOF_DBG_ flags */ +extern int sof_core_debug; /* max BARs mmaped devices can use */ #define SND_SOF_BARS 8 @@ -434,6 +438,7 @@ struct snd_sof_dev { int dma_trace_pages; wait_queue_head_t trace_sleep; u32 host_offset; + u32 dtrace_is_supported; /* set with Kconfig or module parameter */ u32 dtrace_is_enabled; u32 dtrace_error; u32 dtrace_draining; diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 4c3cff031fd6..b0e4556c8536 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -162,6 +162,9 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) struct sof_ipc_reply ipc_reply; int ret; + if (!sdev->dtrace_is_supported) + return 0; + if (sdev->dtrace_is_enabled || !sdev->dma_trace_pages) return -EINVAL; @@ -222,6 +225,9 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) { int ret; + if (!sdev->dtrace_is_supported) + return 0; + /* set false before start initialization */ sdev->dtrace_is_enabled = false; @@ -277,6 +283,9 @@ EXPORT_SYMBOL(snd_sof_init_trace); int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, struct sof_ipc_dma_trace_posn *posn) { + if (!sdev->dtrace_is_supported) + return 0; + if (sdev->dtrace_is_enabled && sdev->host_offset != posn->host_offset) { sdev->host_offset = posn->host_offset; wake_up(&sdev->trace_sleep); @@ -293,6 +302,9 @@ int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, /* an error has occurred within the DSP that prevents further trace */ void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev) { + if (!sdev->dtrace_is_supported) + return; + if (sdev->dtrace_is_enabled) { dev_err(sdev->dev, "error: waking up any trace sleepers\n"); sdev->dtrace_error = true; @@ -305,7 +317,7 @@ void snd_sof_release_trace(struct snd_sof_dev *sdev) { int ret; - if (!sdev->dtrace_is_enabled) + if (!sdev->dtrace_is_supported || !sdev->dtrace_is_enabled) return; ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_STOP); @@ -326,6 +338,9 @@ EXPORT_SYMBOL(snd_sof_release_trace); void snd_sof_free_trace(struct snd_sof_dev *sdev) { + if (!sdev->dtrace_is_supported) + return; + snd_sof_release_trace(sdev); snd_dma_free_pages(&sdev->dmatb); -- cgit From 9a06508bf7824ba34f2e1e9e08df505ac14a44c2 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 27 Sep 2019 15:05:29 -0500 Subject: ASoC: SOF: ipc: retain DSP context after FW exception. Add config option to prevent DSP entering D3 after any FW exception. This can then be used to dump FW context for debug. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190927200538.660-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 8 ++++++++ sound/soc/sof/debug.c | 16 ++++++++++++++++ sound/soc/sof/ipc.c | 4 +--- sound/soc/sof/sof-priv.h | 2 ++ 4 files changed, 27 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index cc592bcadae7..56a3ab66b46b 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -158,6 +158,14 @@ config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST Say Y if you want to enable IPC flood test. If unsure, select "N". +config SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT + bool "SOF retain DSP context on any FW exceptions" + help + This option keeps the DSP in D0 state so that firmware debug + information can be retained and dumped to userspace. + Say Y if you want to retain DSP context for FW exceptions. + If unsure, select "N". + endif ## SND_SOC_SOF_DEBUG endif ## SND_SOC_SOF_OPTIONS diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 54cd431faab7..b8a4e899154c 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -461,3 +461,19 @@ void snd_sof_free_debug(struct snd_sof_dev *sdev) debugfs_remove_recursive(sdev->debugfs_root); } EXPORT_SYMBOL_GPL(snd_sof_free_debug); + +void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) +{ + if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) || + (sof_core_debug & SOF_DBG_RETAIN_CTX)) { + /* should we prevent DSP entering D3 ? */ + dev_info(sdev->dev, "info: preventing DSP entering D3 state to preserve context\n"); + pm_runtime_get_noresume(sdev->dev); + } + + /* dump vital information to the logs */ + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + snd_sof_ipc_dump(sdev); + snd_sof_trace_notify_for_error(sdev); +} +EXPORT_SYMBOL(snd_sof_handle_fw_exception); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index b2f359d2f7e5..b946c81197a1 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -210,9 +210,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, if (ret == 0) { dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", hdr->cmd, hdr->size); - snd_sof_dsp_dbg_dump(ipc->sdev, SOF_DBG_REGS | SOF_DBG_MBOX); - snd_sof_ipc_dump(ipc->sdev); - snd_sof_trace_notify_for_error(ipc->sdev); + snd_sof_handle_fw_exception(ipc->sdev); ret = -ETIMEDOUT; } else { /* copy the data returned from DSP */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d5b1a4f895da..348759035dd0 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -33,6 +33,7 @@ #define SOF_DBG_MBOX BIT(2) #define SOF_DBG_TEXT BIT(3) #define SOF_DBG_PCI BIT(4) +#define SOF_DBG_RETAIN_CTX BIT(5) /* prevent DSP D3 on FW exception */ /* global debug state set by SOF_DBG_ flags */ extern int sof_core_debug; @@ -580,6 +581,7 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, struct sof_ipc_panic_info *panic_info, void *stack, size_t stack_words); int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); +void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev); /* * Platform specific ops. -- cgit From 8692d498d675e2e1433274c5f03b855824f3f35d Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 27 Sep 2019 15:05:32 -0500 Subject: ASoC: SOF: core: check for mandatory fw_ready op during SOF probe fw_ready should be a mandatory op. Make sure fw_ready ops is set during probe. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190927200538.660-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 3 ++- sound/soc/sof/ipc.c | 6 ------ sound/soc/sof/sof-priv.h | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 15167b8220ed..5998861a9002 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -466,7 +466,8 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run || !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || - !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params) + !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params || + !sof_ops(sdev)->fw_ready) return -EINVAL; INIT_LIST_HEAD(&sdev->pcm_list); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index b946c81197a1..26675dfe0240 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -792,12 +792,6 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) struct snd_sof_ipc *ipc; struct snd_sof_ipc_msg *msg; - /* check if mandatory ops required for ipc are defined */ - if (!sof_ops(sdev)->fw_ready) { - dev_err(sdev->dev, "error: ipc mandatory ops not defined\n"); - return NULL; - } - ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); if (!ipc) return NULL; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 348759035dd0..44f789bf7fb0 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -133,7 +133,7 @@ struct snd_sof_dsp_ops { * FW ready checks for ABI compatibility and creates * memory windows at first boot */ - int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* optional */ + int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* mandatory */ /* connect pcm substream to a host stream */ int (*pcm_open)(struct snd_sof_dev *sdev, -- cgit From f567ff6c76f7e9b317248fcab7a0eb3ef432dc9e Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Fri, 27 Sep 2019 15:05:34 -0500 Subject: ASoC: SOF: Intel: hda: fix reset of host_period_bytes This patch prevents the reset of host period bytes and uses no_stream_position to record requests for stream position. Signed-off-by: Marcin Rajwa Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190927200538.660-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-pcm.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 9b730f183529..575f5f5877d8 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -89,6 +89,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct snd_dma_buffer *dmab; + struct sof_ipc_fw_version *v = &sdev->fw_ready.version; int ret; u32 size, rate, bits; @@ -116,9 +117,17 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, /* disable SPIB, to enable buffer wrap for stream */ hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); - /* set host_period_bytes to 0 if no IPC position */ - if (hda && hda->no_ipc_position) - ipc_params->host_period_bytes = 0; + /* update no_stream_position flag for ipc params */ + if (hda && hda->no_ipc_position) { + /* For older ABIs set host_period_bytes to zero to inform + * FW we don't want position updates. Newer versions use + * no_stream_position for this purpose. + */ + if (v->abi_version < SOF_ABI_VER(3, 10, 0)) + ipc_params->host_period_bytes = 0; + else + ipc_params->no_stream_position = 1; + } ipc_params->stream_tag = hstream->stream_tag; -- cgit From 3a9e204d4e36904a464a2e53206b053a7ffc7bad Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 27 Sep 2019 15:05:37 -0500 Subject: ASoC: SOF: Intel: Add context data to any IPC timeout. Helps with FW debug as it provides DSP IPC processing context. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190927200538.660-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/bdw.c | 22 +++++++++++++++++++++- sound/soc/sof/intel/byt.c | 23 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index e282179263e8..170c74dc13b1 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -241,7 +241,7 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[BDW_STACK_DUMP_SIZE]; - u32 status, panic; + u32 status, panic, imrx, imrd; /* now try generic SOF status messages */ status = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); @@ -250,6 +250,26 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) BDW_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, BDW_STACK_DUMP_SIZE); + + /* provide some context for firmware debug */ + imrx = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRX); + imrd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRD); + dev_err(sdev->dev, + "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n", + panic & SHIM_IPCX_BUSY ? "yes" : "no", + panic & SHIM_IPCX_DONE ? "yes" : "no", panic); + dev_err(sdev->dev, + "error: mask host: pending %s complete %s raw 0x%8.8x\n", + imrx & SHIM_IMRX_BUSY ? "yes" : "no", + imrx & SHIM_IMRX_DONE ? "yes" : "no", imrx); + dev_err(sdev->dev, + "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n", + status & SHIM_IPCD_BUSY ? "yes" : "no", + status & SHIM_IPCD_DONE ? "yes" : "no", status); + dev_err(sdev->dev, + "error: mask DSP: pending %s complete %s raw 0x%8.8x\n", + imrd & SHIM_IMRD_BUSY ? "yes" : "no", + imrd & SHIM_IMRD_DONE ? "yes" : "no", imrd); } /* diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 5e7a6aaa627a..ecbc9c79bcad 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -139,7 +139,7 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags) struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[BYT_STACK_DUMP_SIZE]; - u32 status, panic; + u32 status, panic, imrd, imrx; /* now try generic SOF status messages */ status = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCD); @@ -148,6 +148,27 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags) BYT_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, BYT_STACK_DUMP_SIZE); + + /* provide some context for firmware debug */ + imrx = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRX); + imrd = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRD); + dev_err(sdev->dev, + "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n", + panic & SHIM_IPCX_BUSY ? "yes" : "no", + panic & SHIM_IPCX_DONE ? "yes" : "no", panic); + dev_err(sdev->dev, + "error: mask host: pending %s complete %s raw 0x%8.8x\n", + imrx & SHIM_IMRX_BUSY ? "yes" : "no", + imrx & SHIM_IMRX_DONE ? "yes" : "no", imrx); + dev_err(sdev->dev, + "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n", + status & SHIM_IPCD_BUSY ? "yes" : "no", + status & SHIM_IPCD_DONE ? "yes" : "no", status); + dev_err(sdev->dev, + "error: mask DSP: pending %s complete %s raw 0x%8.8x\n", + imrd & SHIM_IMRD_BUSY ? "yes" : "no", + imrd & SHIM_IMRD_DONE ? "yes" : "no", imrd); + } /* -- cgit From aaa68472ed1fa763336335f1278d65fcddd0056e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 2 Oct 2019 12:56:50 +0200 Subject: ASoC: samsung: arndale: Simplify DAI link initialization There is only one DAI link so we can drop an unnecessary loop statement. Use card->dai_link in place of direct static arndale_rt5631_dai[] array dereference as a prerequisite for adding support for other CODECs. Unnecessary assignment of dai_link->codecs->name to NULL is removed. Reviewed-by: Charles Keepax Acked-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki Link: https://lore.kernel.org/r/20191002105652.24821-1-s.nawrocki@samsung.com Signed-off-by: Mark Brown --- sound/soc/samsung/arndale_rt5631.c | 42 ++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c index fd8c6642fb0d..004c84fafad9 100644 --- a/sound/soc/samsung/arndale_rt5631.c +++ b/sound/soc/samsung/arndale_rt5631.c @@ -88,36 +88,30 @@ static void arndale_put_of_nodes(struct snd_soc_card *card) static int arndale_audio_probe(struct platform_device *pdev) { - int n, ret; struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &arndale_rt5631; + struct snd_soc_dai_link *dai_link; + int ret; card->dev = &pdev->dev; + dai_link = card->dai_link; + + dai_link->cpus->of_node = of_parse_phandle(np, "samsung,audio-cpu", 0); + if (!dai_link->cpus->of_node) { + dev_err(&pdev->dev, + "Property 'samsung,audio-cpu' missing or invalid\n"); + return -EINVAL; + } - for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) { - if (!arndale_rt5631_dai[n].cpus->dai_name) { - arndale_rt5631_dai[n].cpus->of_node = of_parse_phandle(np, - "samsung,audio-cpu", n); - - if (!arndale_rt5631_dai[n].cpus->of_node) { - dev_err(&pdev->dev, - "Property 'samsung,audio-cpu' missing or invalid\n"); - return -EINVAL; - } - } - if (!arndale_rt5631_dai[n].platforms->name) - arndale_rt5631_dai[n].platforms->of_node = - arndale_rt5631_dai[n].cpus->of_node; - - arndale_rt5631_dai[n].codecs->name = NULL; - arndale_rt5631_dai[n].codecs->of_node = of_parse_phandle(np, - "samsung,audio-codec", n); - if (!arndale_rt5631_dai[0].codecs->of_node) { - dev_err(&pdev->dev, + if (!dai_link->platforms->name) + dai_link->platforms->of_node = dai_link->cpus->of_node; + + dai_link->codecs->of_node = of_parse_phandle(np, "samsung,audio-codec", 0); + if (!dai_link->codecs->of_node) { + dev_err(&pdev->dev, "Property 'samsung,audio-codec' missing or invalid\n"); - ret = -EINVAL; - goto err_put_of_nodes; - } + ret = -EINVAL; + goto err_put_of_nodes; } ret = devm_snd_soc_register_card(card->dev, card); -- cgit From 03081cc370b9d0d91addbb163e2f5347a7f51571 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 2 Oct 2019 12:56:51 +0200 Subject: ASoC: samsung: arndale: Add support for WM1811 CODEC The Arndale boards come with different types of the audio daughter board. In order to support the WM1811 one we add new definition of an ASoC card which will be registered when the driver matches on "samsung,arndale-wm1811" compatible. There is no runtime detection of the audio daughter board type at the moment, compatible string of the audio card needs to be adjusted in DT, e.g. by the bootloader, depending on actual audio board (CODEC) used. Reviewed-by: Charles Keepax Acked-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki Link: https://lore.kernel.org/r/20191002105652.24821-2-s.nawrocki@samsung.com Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 2 + sound/soc/samsung/arndale_rt5631.c | 85 ++++++++++++++++++++++++++++++++------ 2 files changed, 74 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 638983123d8f..6803cbfa9e46 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -199,6 +199,8 @@ config SND_SOC_ARNDALE_RT5631_ALC5631 depends on I2C select SND_SAMSUNG_I2S select SND_SOC_RT5631 + select MFD_WM8994 + select SND_SOC_WM8994 config SND_SOC_SAMSUNG_TM2_WM5110 tristate "SoC I2S Audio support for WM5110 on TM2 board" diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c index 004c84fafad9..d64602950cbd 100644 --- a/sound/soc/samsung/arndale_rt5631.c +++ b/sound/soc/samsung/arndale_rt5631.c @@ -14,10 +14,11 @@ #include #include +#include "../codecs/wm8994.h" #include "i2s.h" -static int arndale_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int arndale_rt5631_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_dai *cpu_dai = rtd->cpu_dai; @@ -47,13 +48,45 @@ static int arndale_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops arndale_ops = { - .hw_params = arndale_hw_params, +static struct snd_soc_ops arndale_rt5631_ops = { + .hw_params = arndale_rt5631_hw_params, +}; + +static int arndale_wm1811_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_dai *codec_dai = rtd->codec_dai; + unsigned int rfs, rclk; + + /* Ensure AIF1CLK is >= 3 MHz for optimal performance */ + if (params_width(params) == 24) + rfs = 384; + else if (params_rate(params) == 8000 || params_rate(params) == 11025) + rfs = 512; + else + rfs = 256; + + rclk = params_rate(params) * rfs; + + /* + * We add 1 to the frequency value to ensure proper EPLL setting + * for each audio sampling rate (see epll_24mhz_tbl in drivers/clk/ + * samsung/clk-exynos5250.c for list of available EPLL rates). + * The CODEC uses clk API and the value will be rounded hence the MCLK1 + * clock's frequency will still be exact multiple of the sample rate. + */ + return snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, + rclk + 1, SND_SOC_CLOCK_IN); +} + +static struct snd_soc_ops arndale_wm1811_ops = { + .hw_params = arndale_wm1811_hw_params, }; SND_SOC_DAILINK_DEFS(rt5631_hifi, DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-hifi")), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-aif1")), DAILINK_COMP_ARRAY(COMP_EMPTY())); static struct snd_soc_dai_link arndale_rt5631_dai[] = { @@ -63,11 +96,28 @@ static struct snd_soc_dai_link arndale_rt5631_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .ops = &arndale_ops, + .ops = &arndale_rt5631_ops, SND_SOC_DAILINK_REG(rt5631_hifi), }, }; +SND_SOC_DAILINK_DEFS(wm1811_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link arndale_wm1811_dai[] = { + { + .name = "WM1811 HiFi", + .stream_name = "Primary", + .dai_fmt = SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .ops = &arndale_wm1811_ops, + SND_SOC_DAILINK_REG(wm1811_hifi), + }, +}; + static struct snd_soc_card arndale_rt5631 = { .name = "Arndale RT5631", .owner = THIS_MODULE, @@ -75,6 +125,13 @@ static struct snd_soc_card arndale_rt5631 = { .num_links = ARRAY_SIZE(arndale_rt5631_dai), }; +static struct snd_soc_card arndale_wm1811 = { + .name = "Arndale WM1811", + .owner = THIS_MODULE, + .dai_link = arndale_wm1811_dai, + .num_links = ARRAY_SIZE(arndale_wm1811_dai), +}; + static void arndale_put_of_nodes(struct snd_soc_card *card) { struct snd_soc_dai_link *dai_link; @@ -89,10 +146,11 @@ static void arndale_put_of_nodes(struct snd_soc_card *card) static int arndale_audio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &arndale_rt5631; + struct snd_soc_card *card; struct snd_soc_dai_link *dai_link; int ret; + card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); card->dev = &pdev->dev; dai_link = card->dai_link; @@ -134,18 +192,19 @@ static int arndale_audio_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = { - { .compatible = "samsung,arndale-rt5631", }, - { .compatible = "samsung,arndale-alc5631", }, +static const struct of_device_id arndale_audio_of_match[] = { + { .compatible = "samsung,arndale-rt5631", .data = &arndale_rt5631 }, + { .compatible = "samsung,arndale-alc5631", .data = &arndale_rt5631 }, + { .compatible = "samsung,arndale-wm1811", .data = &arndale_wm1811 }, {}, }; -MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match); +MODULE_DEVICE_TABLE(of, arndale_audio_of_match); static struct platform_driver arndale_audio_driver = { .driver = { - .name = "arndale-audio", + .name = "arndale-audio", .pm = &snd_soc_pm_ops, - .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), + .of_match_table = arndale_audio_of_match, }, .probe = arndale_audio_probe, .remove = arndale_audio_remove, -- cgit From dca6408d6f7e76045b5aaec44825cb87d9d1d6ce Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 2 Oct 2019 12:56:52 +0200 Subject: ASoC: samsung: Rename Arndale card driver Rename arndale_rt5631.c to just arnddale.c as we support other CODECs than RT5631. While at it replace spaces in Kconfig with tabs. Reviewed-by: Charles Keepax Acked-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki Link: https://lore.kernel.org/r/20191002105652.24821-3-s.nawrocki@samsung.com Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 10 +- sound/soc/samsung/Makefile | 4 +- sound/soc/samsung/arndale.c | 217 +++++++++++++++++++++++++++++++++++++ sound/soc/samsung/arndale_rt5631.c | 217 ------------------------------------- 4 files changed, 224 insertions(+), 224 deletions(-) create mode 100644 sound/soc/samsung/arndale.c delete mode 100644 sound/soc/samsung/arndale_rt5631.c (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 6803cbfa9e46..1a0b163ca47b 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -194,11 +194,11 @@ config SND_SOC_ODROID help Say Y here to enable audio support for the Odroid XU3/XU4. -config SND_SOC_ARNDALE_RT5631_ALC5631 - tristate "Audio support for RT5631(ALC5631) on Arndale Board" - depends on I2C - select SND_SAMSUNG_I2S - select SND_SOC_RT5631 +config SND_SOC_ARNDALE + tristate "Audio support for Arndale Board" + depends on I2C + select SND_SAMSUNG_I2S + select SND_SOC_RT5631 select MFD_WM8994 select SND_SOC_WM8994 diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index c3b76035f69c..8f5dfe20b9f1 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -39,7 +39,7 @@ snd-soc-lowland-objs := lowland.o snd-soc-littlemill-objs := littlemill.o snd-soc-bells-objs := bells.o snd-soc-odroid-objs := odroid.o -snd-soc-arndale-rt5631-objs := arndale_rt5631.o +snd-soc-arndale-objs := arndale.o snd-soc-tm2-wm5110-objs := tm2_wm5110.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o @@ -62,5 +62,5 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o obj-$(CONFIG_SND_SOC_ODROID) += snd-soc-odroid.o -obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o +obj-$(CONFIG_SND_SOC_ARNDALE) += snd-soc-arndale.o obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o diff --git a/sound/soc/samsung/arndale.c b/sound/soc/samsung/arndale.c new file mode 100644 index 000000000000..d64602950cbd --- /dev/null +++ b/sound/soc/samsung/arndale.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2014, Insignal Co., Ltd. +// +// Author: Claude + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../codecs/wm8994.h" +#include "i2s.h" + +static int arndale_rt5631_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_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int rfs, ret; + unsigned long rclk; + + rfs = 256; + + rclk = params_rate(params) * rfs; + + ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, + 0, SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, + 0, SND_SOC_CLOCK_OUT); + + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops arndale_rt5631_ops = { + .hw_params = arndale_rt5631_hw_params, +}; + +static int arndale_wm1811_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_dai *codec_dai = rtd->codec_dai; + unsigned int rfs, rclk; + + /* Ensure AIF1CLK is >= 3 MHz for optimal performance */ + if (params_width(params) == 24) + rfs = 384; + else if (params_rate(params) == 8000 || params_rate(params) == 11025) + rfs = 512; + else + rfs = 256; + + rclk = params_rate(params) * rfs; + + /* + * We add 1 to the frequency value to ensure proper EPLL setting + * for each audio sampling rate (see epll_24mhz_tbl in drivers/clk/ + * samsung/clk-exynos5250.c for list of available EPLL rates). + * The CODEC uses clk API and the value will be rounded hence the MCLK1 + * clock's frequency will still be exact multiple of the sample rate. + */ + return snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, + rclk + 1, SND_SOC_CLOCK_IN); +} + +static struct snd_soc_ops arndale_wm1811_ops = { + .hw_params = arndale_wm1811_hw_params, +}; + +SND_SOC_DAILINK_DEFS(rt5631_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-aif1")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link arndale_rt5631_dai[] = { + { + .name = "RT5631 HiFi", + .stream_name = "Primary", + .dai_fmt = SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .ops = &arndale_rt5631_ops, + SND_SOC_DAILINK_REG(rt5631_hifi), + }, +}; + +SND_SOC_DAILINK_DEFS(wm1811_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link arndale_wm1811_dai[] = { + { + .name = "WM1811 HiFi", + .stream_name = "Primary", + .dai_fmt = SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .ops = &arndale_wm1811_ops, + SND_SOC_DAILINK_REG(wm1811_hifi), + }, +}; + +static struct snd_soc_card arndale_rt5631 = { + .name = "Arndale RT5631", + .owner = THIS_MODULE, + .dai_link = arndale_rt5631_dai, + .num_links = ARRAY_SIZE(arndale_rt5631_dai), +}; + +static struct snd_soc_card arndale_wm1811 = { + .name = "Arndale WM1811", + .owner = THIS_MODULE, + .dai_link = arndale_wm1811_dai, + .num_links = ARRAY_SIZE(arndale_wm1811_dai), +}; + +static void arndale_put_of_nodes(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link; + int i; + + for_each_card_prelinks(card, i, dai_link) { + of_node_put(dai_link->cpus->of_node); + of_node_put(dai_link->codecs->of_node); + } +} + +static int arndale_audio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct snd_soc_card *card; + struct snd_soc_dai_link *dai_link; + int ret; + + card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); + card->dev = &pdev->dev; + dai_link = card->dai_link; + + dai_link->cpus->of_node = of_parse_phandle(np, "samsung,audio-cpu", 0); + if (!dai_link->cpus->of_node) { + dev_err(&pdev->dev, + "Property 'samsung,audio-cpu' missing or invalid\n"); + return -EINVAL; + } + + if (!dai_link->platforms->name) + dai_link->platforms->of_node = dai_link->cpus->of_node; + + dai_link->codecs->of_node = of_parse_phandle(np, "samsung,audio-codec", 0); + if (!dai_link->codecs->of_node) { + dev_err(&pdev->dev, + "Property 'samsung,audio-codec' missing or invalid\n"); + ret = -EINVAL; + goto err_put_of_nodes; + } + + ret = devm_snd_soc_register_card(card->dev, card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + goto err_put_of_nodes; + } + return 0; + +err_put_of_nodes: + arndale_put_of_nodes(card); + return ret; +} + +static int arndale_audio_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + arndale_put_of_nodes(card); + return 0; +} + +static const struct of_device_id arndale_audio_of_match[] = { + { .compatible = "samsung,arndale-rt5631", .data = &arndale_rt5631 }, + { .compatible = "samsung,arndale-alc5631", .data = &arndale_rt5631 }, + { .compatible = "samsung,arndale-wm1811", .data = &arndale_wm1811 }, + {}, +}; +MODULE_DEVICE_TABLE(of, arndale_audio_of_match); + +static struct platform_driver arndale_audio_driver = { + .driver = { + .name = "arndale-audio", + .pm = &snd_soc_pm_ops, + .of_match_table = arndale_audio_of_match, + }, + .probe = arndale_audio_probe, + .remove = arndale_audio_remove, +}; + +module_platform_driver(arndale_audio_driver); + +MODULE_AUTHOR("Claude "); +MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c deleted file mode 100644 index d64602950cbd..000000000000 --- a/sound/soc/samsung/arndale_rt5631.c +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// Copyright (c) 2014, Insignal Co., Ltd. -// -// Author: Claude - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "../codecs/wm8994.h" -#include "i2s.h" - -static int arndale_rt5631_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_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int rfs, ret; - unsigned long rclk; - - rfs = 256; - - rclk = params_rate(params) * rfs; - - ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, - 0, SND_SOC_CLOCK_OUT); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, - 0, SND_SOC_CLOCK_OUT); - - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops arndale_rt5631_ops = { - .hw_params = arndale_rt5631_hw_params, -}; - -static int arndale_wm1811_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_dai *codec_dai = rtd->codec_dai; - unsigned int rfs, rclk; - - /* Ensure AIF1CLK is >= 3 MHz for optimal performance */ - if (params_width(params) == 24) - rfs = 384; - else if (params_rate(params) == 8000 || params_rate(params) == 11025) - rfs = 512; - else - rfs = 256; - - rclk = params_rate(params) * rfs; - - /* - * We add 1 to the frequency value to ensure proper EPLL setting - * for each audio sampling rate (see epll_24mhz_tbl in drivers/clk/ - * samsung/clk-exynos5250.c for list of available EPLL rates). - * The CODEC uses clk API and the value will be rounded hence the MCLK1 - * clock's frequency will still be exact multiple of the sample rate. - */ - return snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, - rclk + 1, SND_SOC_CLOCK_IN); -} - -static struct snd_soc_ops arndale_wm1811_ops = { - .hw_params = arndale_wm1811_hw_params, -}; - -SND_SOC_DAILINK_DEFS(rt5631_hifi, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-aif1")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link arndale_rt5631_dai[] = { - { - .name = "RT5631 HiFi", - .stream_name = "Primary", - .dai_fmt = SND_SOC_DAIFMT_I2S - | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, - .ops = &arndale_rt5631_ops, - SND_SOC_DAILINK_REG(rt5631_hifi), - }, -}; - -SND_SOC_DAILINK_DEFS(wm1811_hifi, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link arndale_wm1811_dai[] = { - { - .name = "WM1811 HiFi", - .stream_name = "Primary", - .dai_fmt = SND_SOC_DAIFMT_I2S - | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, - .ops = &arndale_wm1811_ops, - SND_SOC_DAILINK_REG(wm1811_hifi), - }, -}; - -static struct snd_soc_card arndale_rt5631 = { - .name = "Arndale RT5631", - .owner = THIS_MODULE, - .dai_link = arndale_rt5631_dai, - .num_links = ARRAY_SIZE(arndale_rt5631_dai), -}; - -static struct snd_soc_card arndale_wm1811 = { - .name = "Arndale WM1811", - .owner = THIS_MODULE, - .dai_link = arndale_wm1811_dai, - .num_links = ARRAY_SIZE(arndale_wm1811_dai), -}; - -static void arndale_put_of_nodes(struct snd_soc_card *card) -{ - struct snd_soc_dai_link *dai_link; - int i; - - for_each_card_prelinks(card, i, dai_link) { - of_node_put(dai_link->cpus->of_node); - of_node_put(dai_link->codecs->of_node); - } -} - -static int arndale_audio_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card; - struct snd_soc_dai_link *dai_link; - int ret; - - card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); - card->dev = &pdev->dev; - dai_link = card->dai_link; - - dai_link->cpus->of_node = of_parse_phandle(np, "samsung,audio-cpu", 0); - if (!dai_link->cpus->of_node) { - dev_err(&pdev->dev, - "Property 'samsung,audio-cpu' missing or invalid\n"); - return -EINVAL; - } - - if (!dai_link->platforms->name) - dai_link->platforms->of_node = dai_link->cpus->of_node; - - dai_link->codecs->of_node = of_parse_phandle(np, "samsung,audio-codec", 0); - if (!dai_link->codecs->of_node) { - dev_err(&pdev->dev, - "Property 'samsung,audio-codec' missing or invalid\n"); - ret = -EINVAL; - goto err_put_of_nodes; - } - - ret = devm_snd_soc_register_card(card->dev, card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - goto err_put_of_nodes; - } - return 0; - -err_put_of_nodes: - arndale_put_of_nodes(card); - return ret; -} - -static int arndale_audio_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - arndale_put_of_nodes(card); - return 0; -} - -static const struct of_device_id arndale_audio_of_match[] = { - { .compatible = "samsung,arndale-rt5631", .data = &arndale_rt5631 }, - { .compatible = "samsung,arndale-alc5631", .data = &arndale_rt5631 }, - { .compatible = "samsung,arndale-wm1811", .data = &arndale_wm1811 }, - {}, -}; -MODULE_DEVICE_TABLE(of, arndale_audio_of_match); - -static struct platform_driver arndale_audio_driver = { - .driver = { - .name = "arndale-audio", - .pm = &snd_soc_pm_ops, - .of_match_table = arndale_audio_of_match, - }, - .probe = arndale_audio_probe, - .remove = arndale_audio_remove, -}; - -module_platform_driver(arndale_audio_driver); - -MODULE_AUTHOR("Claude "); -MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board"); -MODULE_LICENSE("GPL"); -- cgit From 5a7423993007d08bfc7b982451eca0526f51744d Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 2 Oct 2019 01:55:04 +0800 Subject: tas2770: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/tas2770.c:796:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Fixes: 1a476abc723e ("tas2770: add tas2770 smart PA kernel driver") CC: Frank Shi Signed-off-by: kbuild test robot Link: https://lore.kernel.org/r/20191001175504.ufhyxh66psrht42k@332d0cec05f4 Signed-off-by: Mark Brown --- sound/soc/codecs/tas2770.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 9da88ccb1d51..dbbb21fe0548 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -793,7 +793,6 @@ MODULE_DEVICE_TABLE(of, tas2770_of_match); static struct i2c_driver tas2770_i2c_driver = { .driver = { .name = "tas2770", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tas2770_of_match), }, .probe = tas2770_i2c_probe, -- cgit From 4dc0e7df62839d052476de0f8447f29f857cecda Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:22:32 +0900 Subject: ASoC: soc-core: use devm_kzalloc() for rtd Current rtd, rtd->dev, rtd->codec_dais are created by normal kzalloc(), but we want to use devm_kzalloc() as much as possible. Created rtd->dev is registered by device_register() at soc_new_pcm_runtime(), and it will be freed at soc_free_pcm_runtime() by device_unregister(). This means, if we can use devm_kzalloc(rtd->dev, xxx) for rtd / rtd->codec_dais, all these are automatically freed via soc_free_pcm_runtime(). This patch uses devm_kzalloc(rtd->dev, xxx) for rtd / rtd->codec_dais. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/877e5nbu1z.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4a47ba94559f..b16a94228091 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -370,7 +370,6 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) if (!rtd) return; - kfree(rtd->codec_dais); list_del(&rtd->list); /* @@ -384,7 +383,6 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) * soc_new_pcm_runtime() */ device_unregister(rtd->dev); - kfree(rtd); } static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( @@ -416,7 +414,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( /* * for rtd */ - rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); + rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL); if (!rtd) goto free_rtd; @@ -426,7 +424,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( /* * for rtd->codec_dais */ - rtd->codec_dais = kcalloc(dai_link->num_codecs, + rtd->codec_dais = devm_kcalloc(dev, dai_link->num_codecs, sizeof(struct snd_soc_dai *), GFP_KERNEL); if (!rtd->codec_dais) -- cgit From 7ce6088f60624805a8d3127185e2830e299849f1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:22:40 +0900 Subject: ASoC: soc-core: remove soc_remove_dai_links() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. soc_cleanup_card_resources() (a) which is paired function of snd_soc_instantiate_card() (A) is calling soc_remove_dai_links() (*) to remove card related resources, but it is breaking add/remove balance (B)(b)(C)(c)(D)(d), in other words these should be called from soc_cleanup_card_resources() (a) from balance point of view. More headacke is that it is using original removing method for dai_link even though we already have snd_soc_remove_dai_link() which is the function for it (d). This patch removes snd_soc_remove_dai_links() and balance up code. static void soc_remove_dai_links(...) { ... (b) soc_remove_link_dais(card); (c) soc_remove_link_components(card); for_each_card_links_safe(card, link, _link) { ... /* it should use snd_soc_remove_dai_link() here */ (d) list_del(&link->list); } } (a) static int soc_cleanup_card_resources(...) { ... /* remove and free each DAI */ (*) soc_remove_dai_links(card); ... } (A) static int snd_soc_instantiate_card(struct snd_soc_card *card) { ... /* add predefined DAI links to the list */ for_each_card_prelinks(card, i, dai_link) (B) snd_soc_add_dai_link(card, dai_link); ... /* probe all components used by DAI links on this card */ (C) ret = soc_probe_link_components(card); ... /* probe all DAI links on this card */ (D) ret = soc_probe_link_dais(card); ... } Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875zl7bu1r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b16a94228091..a34000d08856 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1275,23 +1275,6 @@ static int soc_probe_link_components(struct snd_soc_card *card) return 0; } -static void soc_remove_dai_links(struct snd_soc_card *card) -{ - struct snd_soc_dai_link *link, *_link; - - soc_remove_link_dais(card); - - soc_remove_link_components(card); - - for_each_card_links_safe(card, link, _link) { - if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) - dev_warn(card->dev, "Topology forgot to remove link %s?\n", - link->name); - - list_del(&link->list); - } -} - static int soc_init_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) { @@ -1924,6 +1907,8 @@ match: static void soc_cleanup_card_resources(struct snd_soc_card *card) { + struct snd_soc_dai_link *link, *_link; + /* free the ALSA card at first; this syncs with pending operations */ if (card->snd_card) { snd_card_free(card->snd_card); @@ -1931,7 +1916,12 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) } /* remove and free each DAI */ - soc_remove_dai_links(card); + soc_remove_link_dais(card); + soc_remove_link_components(card); + + for_each_card_links_safe(card, link, _link) + snd_soc_remove_dai_link(card, link); + soc_remove_pcm_runtimes(card); /* remove auxiliary devices */ -- cgit From 0f23f718ecbc135866ac40db3424dd75f01c76ea Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:22:49 +0900 Subject: ASoC: soc-core: add soc_setup_card_name() ALSA needs to setup shortname, longname, and driver. These methods are very similar. This patch adds new soc_setup_card_name() and setup these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874l0rbu1i.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 60 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a34000d08856..f79ffc4b5b57 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1905,6 +1905,42 @@ match: } } +#define soc_setup_card_name(name, name1, name2, norm) \ + __soc_setup_card_name(name, sizeof(name), name1, name2, norm) +static void __soc_setup_card_name(char *name, int len, + const char *name1, const char *name2, + int normalization) +{ + int i; + + snprintf(name, len, "%s", name1 ? name1 : name2); + + if (!normalization) + return; + + /* + * Name normalization + * + * The driver name is somewhat special, as it's used as a key for + * searches in the user-space. + * + * ex) + * "abcd??efg" -> "abcd__efg" + */ + for (i = 0; i < len; i++) { + switch (name[i]) { + case '_': + case '-': + case '\0': + break; + default: + if (!isalnum(name[i])) + name[i] = '_'; + break; + } + } +} + static void soc_cleanup_card_resources(struct snd_soc_card *card) { struct snd_soc_dai_link *link, *_link; @@ -2070,24 +2106,12 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* try to set some sane longname if DMI is available */ snd_soc_set_dmi_name(card, NULL); - snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), - "%s", card->name); - snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), - "%s", card->long_name ? card->long_name : card->name); - snprintf(card->snd_card->driver, sizeof(card->snd_card->driver), - "%s", card->driver_name ? card->driver_name : card->name); - for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) { - switch (card->snd_card->driver[i]) { - case '_': - case '-': - case '\0': - break; - default: - if (!isalnum(card->snd_card->driver[i])) - card->snd_card->driver[i] = '_'; - break; - } - } + soc_setup_card_name(card->snd_card->shortname, + card->name, NULL, 0); + soc_setup_card_name(card->snd_card->longname, + card->long_name, card->name, 0); + soc_setup_card_name(card->snd_card->driver, + card->driver_name, card->name, 1); if (card->late_probe) { ret = card->late_probe(card); -- cgit From 50014499e6a45edd7ba1facf2133c03bbc7d8266 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:22:57 +0900 Subject: ASoC: soc-core: use devm_xxx for component related resource dai / component related resources are created when component is registered, and it will be freed when component was unregistered. These resources are not re-used after that. This means, we can use devm_xxx for dai / component, without thinking about kfree(). This patch uses devm_xxx for these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8736gbbu1a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f79ffc4b5b57..2c2803e6544b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2506,7 +2506,7 @@ static char *fmt_single_name(struct device *dev, int *id) *id = 0; } - return kstrdup(name, GFP_KERNEL); + return devm_kstrdup(dev, name, GFP_KERNEL); } /* @@ -2523,7 +2523,7 @@ static inline char *fmt_multiple_name(struct device *dev, return NULL; } - return kstrdup(dai_drv->name, GFP_KERNEL); + return devm_kstrdup(dev, dai_drv->name, GFP_KERNEL); } /** @@ -2539,8 +2539,6 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", dai->name); list_del(&dai->list); - kfree(dai->name); - kfree(dai); } } @@ -2554,7 +2552,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev)); - dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); + dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL); if (dai == NULL) return NULL; @@ -2576,10 +2574,8 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, else dai->id = component->num_dai; } - if (dai->name == NULL) { - kfree(dai); + if (!dai->name) return NULL; - } dai->component = component; dai->dev = dev; @@ -2765,7 +2761,6 @@ static void snd_soc_component_add(struct snd_soc_component *component) static void snd_soc_component_cleanup(struct snd_soc_component *component) { snd_soc_unregister_dais(component); - kfree(component->name); } static void snd_soc_component_del_unlocked(struct snd_soc_component *component) -- cgit From d8145989ff8c2a938be372b728f90e23de8557a2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:23:07 +0900 Subject: ASoC: soc-core: setup card->rtd_num at snd_soc_instantiate_card() card->rtd_num is used to count rtd. Initialize it at snd_soc_instantiate_card() is very natural and less confusion. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zhijafgk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2c2803e6544b..d39d908f3204 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -462,8 +462,6 @@ static void soc_remove_pcm_runtimes(struct snd_soc_card *card) for_each_card_rtds_safe(card, rtd, _rtd) soc_free_pcm_runtime(rtd); - - card->num_rtd = 0; } struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, @@ -2008,6 +2006,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) goto probe_end; /* add predefined DAI links to the list */ + card->num_rtd = 0; for_each_card_prelinks(card, i, dai_link) { ret = snd_soc_add_dai_link(card, dai_link); if (ret < 0) @@ -2418,7 +2417,6 @@ int snd_soc_register_card(struct snd_soc_card *card) INIT_LIST_HEAD(&card->dapm_dirty); INIT_LIST_HEAD(&card->dobj_list); - card->num_rtd = 0; card->instantiated = 0; mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); -- cgit From 0881ab6e74b0be7df3da3abdf7caeb2552f907d2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:23:14 +0900 Subject: ASoC: soc-ops: use snd_soc_card_get_kcontrol() at snd_soc_limit_volume() snd_soc_limit_volume() is finding snd_kcontrol by using original coding, but we already have snd_soc_card_get_kcontrol(). Let's use existing function. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y2y3afgd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-ops.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index f4dc3d445aae..652657dc6809 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -592,23 +592,16 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); int snd_soc_limit_volume(struct snd_soc_card *card, const char *name, int max) { - struct snd_card *snd_card = card->snd_card; struct snd_kcontrol *kctl; struct soc_mixer_control *mc; - int found = 0; int ret = -EINVAL; /* Sanity check for name and max */ if (unlikely(!name || max <= 0)) return -EINVAL; - list_for_each_entry(kctl, &snd_card->controls, list) { - if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) { - found = 1; - break; - } - } - if (found) { + kctl = snd_soc_card_get_kcontrol(card, name); + if (kctl) { mc = (struct soc_mixer_control *)kctl->private_value; if (max <= mc->max) { mc->platform_max = max; -- cgit From 82e8d723e9e6698572098bf2976223d5069b34b5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 4 Oct 2019 16:49:31 +0200 Subject: sound: Fix Kconfig indentation Adjust indentation from spaces to tab (+optional two spaces) as in coding style with command like: $ sed -e 's/^ /\t/' -i */Kconfig Signed-off-by: Krzysztof Kozlowski Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191004144931.3851-1-krzk@kernel.org Signed-off-by: Takashi Iwai --- sound/core/Kconfig | 28 ++++++++++++------------ sound/drivers/Kconfig | 20 +++++++++--------- sound/firewire/Kconfig | 6 +++--- sound/isa/Kconfig | 18 ++++++++-------- sound/mips/Kconfig | 12 +++++------ sound/pci/Kconfig | 2 +- sound/soc/cirrus/Kconfig | 14 ++++++------ sound/soc/codecs/Kconfig | 32 ++++++++++++++-------------- sound/soc/intel/Kconfig | 2 +- sound/soc/intel/boards/Kconfig | 48 +++++++++++++++++++++--------------------- sound/soc/pxa/Kconfig | 16 +++++++------- sound/soc/qcom/Kconfig | 20 +++++++++--------- sound/soc/samsung/Kconfig | 8 +++---- sound/soc/sof/imx/Kconfig | 12 +++++------ sound/soc/sof/intel/Kconfig | 22 +++++++++---------- sound/soc/xilinx/Kconfig | 20 +++++++++--------- sound/soc/zte/Kconfig | 12 +++++------ sound/usb/Kconfig | 32 ++++++++++++++-------------- 18 files changed, 162 insertions(+), 162 deletions(-) (limited to 'sound') diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 4ee79ad6ae22..4044c42d8595 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -72,11 +72,11 @@ config SND_PCM_OSS config SND_PCM_OSS_PLUGINS bool "OSS PCM (digital audio) API - Include plugin system" depends on SND_PCM_OSS - default y + default y help - If you disable this option, the ALSA's OSS PCM API will not - support conversion of channels, formats and rates. It will - behave like most of new OSS/Free drivers in 2.4/2.6 kernels. + If you disable this option, the ALSA's OSS PCM API will not + support conversion of channels, formats and rates. It will + behave like most of new OSS/Free drivers in 2.4/2.6 kernels. config SND_PCM_TIMER bool "PCM timer interface" if EXPERT @@ -128,13 +128,13 @@ config SND_SUPPORT_OLD_API or older). config SND_PROC_FS - bool "Sound Proc FS Support" if EXPERT - depends on PROC_FS - default y - help - Say 'N' to disable Sound proc FS, which may reduce code size about - 9KB on x86_64 platform. - If unsure say Y. + bool "Sound Proc FS Support" if EXPERT + depends on PROC_FS + default y + help + Say 'N' to disable Sound proc FS, which may reduce code size about + 9KB on x86_64 platform. + If unsure say Y. config SND_VERBOSE_PROCFS bool "Verbose procfs contents" @@ -142,8 +142,8 @@ config SND_VERBOSE_PROCFS default y help Say Y here to include code for verbose procfs contents (provides - useful information to developers when a problem occurs). On the - other side, it makes the ALSA subsystem larger. + useful information to developers when a problem occurs). On the + other side, it makes the ALSA subsystem larger. config SND_VERBOSE_PRINTK bool "Verbose printk" @@ -164,7 +164,7 @@ config SND_DEBUG_VERBOSE depends on SND_DEBUG help Say Y here to enable extra-verbose debugging messages. - + Let me repeat: it enables EXTRA-VERBOSE DEBUGGING messages. So, say Y only if you are ready to be annoyed. diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 09932cc98e9d..15d6d46acf9c 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config SND_MPU401_UART - tristate - select SND_RAWMIDI + tristate + select SND_RAWMIDI config SND_OPL3_LIB tristate @@ -90,16 +90,16 @@ config SND_DUMMY will be called snd-dummy. config SND_ALOOP - tristate "Generic loopback driver (PCM)" - select SND_PCM - help - Say 'Y' or 'M' to include support for the PCM loopback device. + tristate "Generic loopback driver (PCM)" + select SND_PCM + help + Say 'Y' or 'M' to include support for the PCM loopback device. This module returns played samples back to the user space using the standard ALSA PCM device. The devices are routed 0->1 and - 1->0, where first number is the playback PCM device and second + 1->0, where first number is the playback PCM device and second number is the capture device. Module creates two PCM devices and configured number of substreams (see the pcm_substreams module - parameter). + parameter). The loopback device allows time sychronization with an external timing source using the time shift universal control (+-20% @@ -142,12 +142,12 @@ config SND_MTS64 select SND_RAWMIDI help The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with - additional SMPTE Timecode capabilities for the parallel port. + additional SMPTE Timecode capabilities for the parallel port. Say 'Y' to include support for this device. To compile this driver as a module, chose 'M' here: the module - will be called snd-mts64. + will be called snd-mts64. config SND_SERIAL_U16550 tristate "UART16550 serial MIDI driver" diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index b0a904cdb932..995c2cefc222 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -77,7 +77,7 @@ config SND_BEBOB tristate "BridgeCo DM1000/DM1100/DM1500 with BeBoB firmware" select SND_FIREWIRE_LIB select SND_HWDEP - help + help Say Y here to include support for FireWire devices based on BridgeCo DM1000/DM1100/DM1500 with BeBoB firmware: * Edirol FA-66/FA-101 @@ -111,8 +111,8 @@ config SND_BEBOB * M-Audio FireWire 1814/ProjectMix IO * Digidesign Mbox 2 Pro - To compile this driver as a module, choose M here: the module - will be called snd-bebob. + To compile this driver as a module, choose M here: the module + will be called snd-bebob. config SND_FIREWIRE_DIGI00X tristate "Digidesign Digi 002/003 family support" diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index b690ed937cbe..6ffa48dd5983 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -2,22 +2,22 @@ # ALSA ISA drivers config SND_WSS_LIB - tristate - select SND_PCM + tristate + select SND_PCM select SND_TIMER config SND_SB_COMMON - tristate + tristate config SND_SB8_DSP - tristate - select SND_PCM - select SND_SB_COMMON + tristate + select SND_PCM + select SND_SB_COMMON config SND_SB16_DSP - tristate - select SND_PCM - select SND_SB_COMMON + tristate + select SND_PCM + select SND_SB_COMMON menuconfig SND_ISA bool "ISA sound devices" diff --git a/sound/mips/Kconfig b/sound/mips/Kconfig index 8a33402fd415..b497b803c834 100644 --- a/sound/mips/Kconfig +++ b/sound/mips/Kconfig @@ -14,15 +14,15 @@ config SND_SGI_O2 tristate "SGI O2 Audio" depends on SGI_IP32 select SND_PCM - help - Sound support for the SGI O2 Workstation. + help + Sound support for the SGI O2 Workstation. config SND_SGI_HAL2 - tristate "SGI HAL2 Audio" - depends on SGI_HAS_HAL2 + tristate "SGI HAL2 Audio" + depends on SGI_HAS_HAL2 select SND_PCM - help - Sound support for the SGI Indy and Indigo2 Workstation. + help + Sound support for the SGI Indy and Indigo2 Workstation. endif # SND_MIPS diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7630f808d087..93bc9bef7641 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -217,7 +217,7 @@ config SND_CMIPCI will be called snd-cmipci. config SND_OXYGEN_LIB - tristate + tristate config SND_OXYGEN tristate "C-Media 8786, 8787, 8788 (Oxygen)" diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 2333efac758a..8039a8febefa 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig @@ -33,13 +33,13 @@ config SND_EP93XX_SOC_AC97 select SND_SOC_AC97_BUS config SND_EP93XX_SOC_SNAPPERCL15 - tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" - depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C - select SND_EP93XX_SOC_I2S - select SND_SOC_TLV320AIC23_I2C - help - Say Y or M here if you want to add support for I2S audio on the - Bluewater Systems Snapper CL15 module. + tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" + depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C + select SND_EP93XX_SOC_I2S + select SND_SOC_TLV320AIC23_I2C + help + Say Y or M here if you want to add support for I2S audio on the + Bluewater Systems Snapper CL15 module. config SND_EP93XX_SOC_SIMONE tristate "SoC Audio support for Simplemachines Sim.One board" diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 229cc89f8c5a..ef9d73b89623 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -257,16 +257,16 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM9705 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW) select SND_SOC_WM9712 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW) select SND_SOC_WM9713 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW) - help - Normally ASoC codec drivers are only built if a machine driver which - uses them is also built since they are only usable with a machine - driver. Selecting this option will allow these drivers to be built - without an explicit machine driver for test and development purposes. + help + Normally ASoC codec drivers are only built if a machine driver which + uses them is also built since they are only usable with a machine + driver. Selecting this option will allow these drivers to be built + without an explicit machine driver for test and development purposes. Support for the bus types used to access the codecs to be built must be selected separately. - If unsure select "N". + If unsure select "N". config SND_SOC_88PM860X tristate @@ -570,8 +570,8 @@ config SND_SOC_CS42XX8_I2C # Cirrus Logic CS43130 HiFi DAC config SND_SOC_CS43130 - tristate "Cirrus Logic CS43130 CODEC" - depends on I2C + tristate "Cirrus Logic CS43130 CODEC" + depends on I2C config SND_SOC_CS4341 tristate "Cirrus Logic CS4341 CODEC" @@ -643,19 +643,19 @@ config SND_SOC_L3 tristate config SND_SOC_DA7210 - tristate + tristate config SND_SOC_DA7213 - tristate + tristate config SND_SOC_DA7218 tristate config SND_SOC_DA7219 - tristate + tristate config SND_SOC_DA732X - tristate + tristate config SND_SOC_DA9055 tristate @@ -717,7 +717,7 @@ config SND_SOC_INNO_RK3036 select REGMAP_MMIO config SND_SOC_ISABELLE - tristate + tristate config SND_SOC_LM49453 tristate @@ -988,7 +988,7 @@ config SND_SOC_RT5640 tristate config SND_SOC_RT5645 - tristate + tristate config SND_SOC_RT5651 tristate @@ -1220,7 +1220,7 @@ config SND_SOC_UDA134X tristate config SND_SOC_UDA1380 - tristate + tristate depends on I2C config SND_SOC_WCD9335 @@ -1348,7 +1348,7 @@ config SND_SOC_WM8904 depends on I2C config SND_SOC_WM8940 - tristate + tristate config SND_SOC_WM8955 tristate diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 01c99750212a..597516c0c192 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -113,7 +113,7 @@ config SND_SOC_INTEL_SKYLAKE select SND_SOC_INTEL_CNL select SND_SOC_INTEL_CFL help - This is a backwards-compatible option to select all devices + This is a backwards-compatible option to select all devices supported by the Intel SST/Skylake driver. This option is no longer recommended and will be deprecated when the SOF driver is introduced. Distributions should explicitly diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 5c27f7ab4a5f..882ff36a7c9c 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -3,13 +3,13 @@ menuconfig SND_SOC_INTEL_MACH bool "Intel Machine drivers" depends on SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL help - Intel ASoC Machine Drivers. If you have a Intel machine that - has an audio controller with a DSP and I2S or DMIC port, then - enable this option by saying Y + Intel ASoC Machine Drivers. If you have a Intel machine that + has an audio controller with a DSP and I2S or DMIC port, then + enable this option by saying Y - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Intel ASoC machine drivers. + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Intel ASoC machine drivers. if SND_SOC_INTEL_MACH @@ -114,11 +114,11 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH depends on X86_INTEL_LPSS || COMPILE_TEST select SND_SOC_ACPI select SND_SOC_RT5670 - help - This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell - platforms with RT5672 audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". + help + This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell + platforms with RT5672 audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". config SND_SOC_INTEL_CHT_BSW_RT5645_MACH tristate "Cherrytrail & Braswell with RT5645/5650 codec" @@ -311,20 +311,20 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH If unsure select "N". config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH - tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode" + tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SPI - select SND_SOC_RT5663 - select SND_SOC_RT5514 - select SND_SOC_RT5514_SPI - select SND_SOC_MAX98927 - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5663 + RT5514 + MAX98927. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". + depends on SPI + select SND_SOC_RT5663 + select SND_SOC_RT5514 + select SND_SOC_RT5514_SPI + select SND_SOC_MAX98927 + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for RT5663 + RT5514 + MAX98927. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH tristate "KBL with DA7219 and MAX98357A in I2S Mode" @@ -393,7 +393,7 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH help This adds support for ASoC machine driver for Intel platforms SKL/KBL/BXT/APL with iDisp, HDA audio codecs. - Say Y or m if you have such a device. This is a recommended option. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 213d4dab0346..295cfffa4646 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -190,14 +190,14 @@ config SND_PXA2XX_SOC_MAGICIAN HTC Magician. config SND_PXA2XX_SOC_MIOA701 - tristate "SoC Audio support for MIO A701" - depends on SND_PXA2XX_SOC && MACH_MIOA701 + tristate "SoC Audio support for MIO A701" + depends on SND_PXA2XX_SOC && MACH_MIOA701 depends on AC97_BUS=n - select SND_PXA2XX_SOC_AC97 - select SND_SOC_WM9713 - help - Say Y if you want to add support for SoC audio on the - MIO A701. + select SND_PXA2XX_SOC_AC97 + select SND_SOC_WM9713 + help + Say Y if you want to add support for SoC audio on the + MIO A701. config SND_PXA2XX_SOC_IMOTE2 tristate "SoC Audio support for IMote 2" @@ -205,7 +205,7 @@ config SND_PXA2XX_SOC_IMOTE2 select SND_PXA2XX_SOC_I2S select SND_SOC_WM8940 help - Say Y if you want to add support for SoC audio on the + Say Y if you want to add support for SoC audio on the IMote 2. config SND_MMP_SOC_BROWNSTONE diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 60086858e920..6530d2462a9e 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -3,8 +3,8 @@ config SND_SOC_QCOM tristate "ASoC support for QCOM platforms" depends on ARCH_QCOM || COMPILE_TEST help - Say Y or M if you want to add support to use audio devices - in Qualcomm Technologies SOC-based platforms. + Say Y or M if you want to add support to use audio devices + in Qualcomm Technologies SOC-based platforms. config SND_SOC_LPASS_CPU tristate @@ -30,17 +30,17 @@ config SND_SOC_STORM select SND_SOC_LPASS_IPQ806X select SND_SOC_MAX98357A help - Say Y or M if you want add support for SoC audio on the - Qualcomm Technologies IPQ806X-based Storm board. + Say Y or M if you want add support for SoC audio on the + Qualcomm Technologies IPQ806X-based Storm board. config SND_SOC_APQ8016_SBC tristate "SoC Audio support for APQ8016 SBC platforms" depends on SND_SOC_QCOM select SND_SOC_LPASS_APQ8016 help - Support for Qualcomm Technologies LPASS audio block in - APQ8016 SOC-based systems. - Say Y if you want to use audio devices on MI2S. + Support for Qualcomm Technologies LPASS audio block in + APQ8016 SOC-based systems. + Say Y if you want to use audio devices on MI2S. config SND_SOC_QCOM_COMMON tristate @@ -93,9 +93,9 @@ config SND_SOC_MSM8996 select SND_SOC_QDSP6 select SND_SOC_QCOM_COMMON help - Support for Qualcomm Technologies LPASS audio block in - APQ8096 SoC-based systems. - Say Y if you want to use audio device on this SoCs + Support for Qualcomm Technologies LPASS audio block in + APQ8096 SoC-based systems. + Say Y if you want to use audio device on this SoCs config SND_SOC_SDM845 tristate "SoC Machine driver for SDM845 boards" diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 638983123d8f..9304177de78a 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -195,10 +195,10 @@ config SND_SOC_ODROID Say Y here to enable audio support for the Odroid XU3/XU4. config SND_SOC_ARNDALE_RT5631_ALC5631 - tristate "Audio support for RT5631(ALC5631) on Arndale Board" - depends on I2C - select SND_SAMSUNG_I2S - select SND_SOC_RT5631 + tristate "Audio support for RT5631(ALC5631) on Arndale Board" + depends on I2C + select SND_SAMSUNG_I2S + select SND_SOC_RT5631 config SND_SOC_SAMSUNG_TM2_WM5110 tristate "SoC I2S Audio support for WM5110 on TM2 board" diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index 5acae75f5750..6315fba8ce71 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -5,9 +5,9 @@ config SND_SOC_SOF_IMX_TOPLEVEL depends on ARM64|| COMPILE_TEST depends on SND_SOC_SOF_OF help - This adds support for Sound Open Firmware for NXP i.MX platforms. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for NXP i.MX platforms. + Say Y if you have such a device. + If unsure select "N". if SND_SOC_SOF_IMX_TOPLEVEL @@ -16,8 +16,8 @@ config SND_SOC_SOF_IMX8 depends on IMX_SCU depends on IMX_DSP help - This adds support for Sound Open Firmware for NXP i.MX8 platforms - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for NXP i.MX8 platforms + Say Y if you have such a device. + If unsure select "N". endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 479ba249e219..18c41fdc47c8 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -36,7 +36,7 @@ config SND_SOC_SOF_INTEL_PCI config SND_SOC_SOF_INTEL_HIFI_EP_IPC tristate help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_INTEL_ATOM_HIFI_EP @@ -217,31 +217,31 @@ config SND_SOC_SOF_COMETLAKE_H_SUPPORT config SND_SOC_SOF_TIGERLAKE_SUPPORT bool "SOF support for Tigerlake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Tigerlake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Tigerlake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_TIGERLAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_ELKHARTLAKE_SUPPORT bool "SOF support for ElkhartLake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the ElkhartLake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the ElkhartLake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_ELKHARTLAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_HDA_COMMON diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig index 69973179ef15..1d3586b68db7 100644 --- a/sound/soc/xilinx/Kconfig +++ b/sound/soc/xilinx/Kconfig @@ -9,15 +9,15 @@ config SND_SOC_XILINX_I2S encapsulates PCM in AES format and sends AES data. config SND_SOC_XILINX_AUDIO_FORMATTER - tristate "Audio support for the the Xilinx audio formatter" - help - Select this option to enable Xilinx audio formatter - support. This provides DMA platform device support for - audio functionality. + tristate "Audio support for the the Xilinx audio formatter" + help + Select this option to enable Xilinx audio formatter + support. This provides DMA platform device support for + audio functionality. config SND_SOC_XILINX_SPDIF - tristate "Audio support for the the Xilinx SPDIF" - help - Select this option to enable Xilinx SPDIF Audio. - This provides playback and capture of SPDIF audio in - AES format. + tristate "Audio support for the the Xilinx SPDIF" + help + Select this option to enable Xilinx SPDIF Audio. + This provides playback and capture of SPDIF audio in + AES format. diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig index a7842e4b791c..a23d4f13ca19 100644 --- a/sound/soc/zte/Kconfig +++ b/sound/soc/zte/Kconfig @@ -18,9 +18,9 @@ config ZX_I2S ZTE ZX I2S interface config ZX_TDM - tristate "ZTE ZX TDM Driver Support" - depends on COMMON_CLK - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for codecs attached to the - ZTE ZX TDM interface + tristate "ZTE ZX TDM Driver Support" + depends on COMMON_CLK + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for codecs attached to the + ZTE ZX TDM interface diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index e2c53a0841da..059242f15d75 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -107,24 +107,24 @@ config SND_USB_US122L will be called snd-usb-us122l. config SND_USB_6FIRE - tristate "TerraTec DMX 6Fire USB" - select FW_LOADER - select BITREVERSE - select SND_RAWMIDI - select SND_PCM - select SND_VMASTER - help - Say Y here to include support for TerraTec 6fire DMX USB interface. - - You will need firmware files in order to be able to use the device - after it has been coldstarted. An install script for the firmware - and further help can be found at - http://sixfireusb.sourceforge.net + tristate "TerraTec DMX 6Fire USB" + select FW_LOADER + select BITREVERSE + select SND_RAWMIDI + select SND_PCM + select SND_VMASTER + help + Say Y here to include support for TerraTec 6fire DMX USB interface. + + You will need firmware files in order to be able to use the device + after it has been coldstarted. An install script for the firmware + and further help can be found at + http://sixfireusb.sourceforge.net config SND_USB_HIFACE - tristate "M2Tech hiFace USB-SPDIF driver" - select SND_PCM - help + tristate "M2Tech hiFace USB-SPDIF driver" + select SND_PCM + help Select this option to include support for M2Tech hiFace USB-SPDIF interface. -- cgit From 67ad656bdd703157154d0db5bf1b35a5a86073b9 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 4 Oct 2019 14:43:31 -0700 Subject: ASoC: jz4740: Use of_device_get_match_data() This probe function is only called if the device is backed by a DT node, so switch this call to of_device_get_match_data() to reduce code size and simplify a bit. This also avoids needing to reference a potentially undefined variable because of_device_get_match_data() doesn't need to know anything beyond the struct device to find the match table. Cc: Arnd Bergmann Cc: Geert Uytterhoeven Cc: Paul Cercueil Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Rob Herring Cc: Frank Rowand Cc: Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20191004214334.149976-8-swboyd@chromium.org Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 13408de34055..d2dab4d24b87 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -503,9 +503,8 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) if (!i2s) return -ENOMEM; - match = of_match_device(jz4740_of_matches, &pdev->dev); - if (match) - i2s->version = (enum jz47xx_i2s_version)match->data; + i2s->version = + (enum jz47xx_i2s_version)of_device_get_match_data(&pdev->dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2s->base = devm_ioremap_resource(&pdev->dev, mem); -- cgit From 03fe492e8346d3da59b6eb7ea306d46ebf22e9d5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sun, 6 Oct 2019 18:46:31 +0800 Subject: ASoc: tas2770: Fix build error without GPIOLIB If GPIOLIB is not set, building fails: sound/soc/codecs/tas2770.c: In function tas2770_reset: sound/soc/codecs/tas2770.c:38:3: error: implicit declaration of function gpiod_set_value_cansleep; did you mean gpio_set_value_cansleep? [-Werror=implicit-function-declaration] gpiod_set_value_cansleep(tas2770->reset_gpio, 0); ^~~~~~~~~~~~~~~~~~~~~~~~ gpio_set_value_cansleep sound/soc/codecs/tas2770.c: In function tas2770_i2c_probe: sound/soc/codecs/tas2770.c:749:24: error: implicit declaration of function devm_gpiod_get_optional; did you mean devm_regulator_get_optional? [-Werror=implicit-function-declaration] tas2770->reset_gpio = devm_gpiod_get_optional(tas2770->dev, ^~~~~~~~~~~~~~~~~~~~~~~ devm_regulator_get_optional sound/soc/codecs/tas2770.c:751:13: error: GPIOD_OUT_HIGH undeclared (first use in this function); did you mean GPIOF_INIT_HIGH? GPIOD_OUT_HIGH); ^~~~~~~~~~~~~~ GPIOF_INIT_HIGH Reported-by: Hulk Robot Fixes: 1a476abc723e ("tas2770: add tas2770 smart PA kernel driver") Suggested-by: Ladislav Michl Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20191006104631.60608-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2770.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index dbbb21fe0548..15f6fcc6d87e 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include -- cgit From e9e8fc9ed63e7e0fb30f8612f628924fbd868467 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sun, 6 Oct 2019 18:55:22 +0800 Subject: ASoC: fsl_mqs: remove set but not used variable 'bclk' Fixes gcc '-Wunused-but-set-variable' warning: sound/soc/fsl/fsl_mqs.c: In function fsl_mqs_hw_params: sound/soc/fsl/fsl_mqs.c:54:6: warning: variable bclk set but not used [-Wunused-but-set-variable] It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20191006105522.58560-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_mqs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index c1619a553514..7b9cab3a62e7 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -51,10 +51,9 @@ static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); unsigned long mclk_rate; int div, res; - int bclk, lrclk; + int lrclk; mclk_rate = clk_get_rate(mqs_priv->mclk); - bclk = snd_soc_params_to_bclk(params); lrclk = params_rate(params); /* -- cgit From a9d273671440c439c4f236123c59dd839c1a0eb7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Oct 2019 13:22:09 +0300 Subject: ASoC: fsl_mqs: Fix error handling in probe There are several problems in the error handling in fsl_mqs_probe(). 1) "ret" isn't initialized on some paths. GCC has a feature which warns about uninitialized variables but the code initializes "ret" to zero at the start of the function so the checking is turned off. 2) "gpr_np" is a pointer so initializing it to zero is confusing and generates a Sparse warning. 3) of_parse_phandle() doesn't return error pointers on error, it returns NULL. 4) If devm_snd_soc_register_component() fails then the function should free the "gpr_np". Fixes: 9e28f6532c61 ("ASoC: fsl_mqs: Add MQS component driver") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20191004102208.GB823@mwanda Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_mqs.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 7b9cab3a62e7..f7fc44e8fb27 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -178,10 +178,10 @@ static const struct regmap_config fsl_mqs_regmap_config = { static int fsl_mqs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct device_node *gpr_np = 0; + struct device_node *gpr_np = NULL; struct fsl_mqs *mqs_priv; void __iomem *regs; - int ret = 0; + int ret; mqs_priv = devm_kzalloc(&pdev->dev, sizeof(*mqs_priv), GFP_KERNEL); if (!mqs_priv) @@ -198,17 +198,16 @@ static int fsl_mqs_probe(struct platform_device *pdev) if (mqs_priv->use_gpr) { gpr_np = of_parse_phandle(np, "gpr", 0); - if (IS_ERR(gpr_np)) { + if (!gpr_np) { dev_err(&pdev->dev, "failed to get gpr node by phandle\n"); - ret = PTR_ERR(gpr_np); - goto out; + return -EINVAL; } mqs_priv->regmap = syscon_node_to_regmap(gpr_np); if (IS_ERR(mqs_priv->regmap)) { dev_err(&pdev->dev, "failed to get gpr regmap\n"); ret = PTR_ERR(mqs_priv->regmap); - goto out; + goto err_free_gpr_np; } } else { regs = devm_platform_ioremap_resource(pdev, 0); @@ -229,7 +228,7 @@ static int fsl_mqs_probe(struct platform_device *pdev) if (IS_ERR(mqs_priv->ipg)) { dev_err(&pdev->dev, "failed to get the clock: %ld\n", PTR_ERR(mqs_priv->ipg)); - goto out; + return PTR_ERR(mqs_priv->ipg); } } @@ -237,17 +236,21 @@ static int fsl_mqs_probe(struct platform_device *pdev) if (IS_ERR(mqs_priv->mclk)) { dev_err(&pdev->dev, "failed to get the clock: %ld\n", PTR_ERR(mqs_priv->mclk)); - goto out; + ret = PTR_ERR(mqs_priv->mclk); + goto err_free_gpr_np; } dev_set_drvdata(&pdev->dev, mqs_priv); pm_runtime_enable(&pdev->dev); - return devm_snd_soc_register_component(&pdev->dev, &soc_codec_fsl_mqs, + ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_fsl_mqs, &fsl_mqs_dai, 1); -out: - if (!IS_ERR(gpr_np)) - of_node_put(gpr_np); + if (ret) + goto err_free_gpr_np; + return 0; + +err_free_gpr_np: + of_node_put(gpr_np); return ret; } -- cgit From 5911e6729e0886a3fb00b897b73892134d37158a Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 7 Oct 2019 12:11:56 -0500 Subject: ASoC: tas2770: Remove unneeded read of the TDM_CFG3 register Remove the unneeded and incorrect read of the TDM_CFG3 register. The read is done but the value is never used. Signed-off-by: Dan Murphy Link: https://lore.kernel.org/r/20191007171157.17813-2-dmurphy@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2770.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 15f6fcc6d87e..f3a665b64fd6 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -374,7 +374,6 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; int ret; - int value = 0; struct snd_soc_component *component = dai->component; struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component); @@ -430,8 +429,6 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) if (ret) return ret; - value = snd_soc_component_read32(component, TAS2770_TDM_CFG_REG3); - tas2770->asi_format = fmt; return 0; -- cgit From 40f90ef0a77bab65c8f959ba1d264bb674f7234b Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 7 Oct 2019 12:11:57 -0500 Subject: ASoc: tas2770: Remove unused defines and variables Remove unused defines and structure variables that are not referenced by the code. If these are needed for future enhancements then they should be added at that time. Signed-off-by: Dan Murphy Link: https://lore.kernel.org/r/20191007171157.17813-3-dmurphy@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2770.h | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tas2770.h b/sound/soc/codecs/tas2770.h index d597a8280707..cbb858369fe6 100644 --- a/sound/soc/codecs/tas2770.h +++ b/sound/soc/codecs/tas2770.h @@ -125,40 +125,19 @@ #define ERROR_UNDER_VOLTAGE 0x0000008 #define ERROR_BROWNOUT 0x0000010 #define ERROR_CLASSD_PWR 0x0000020 -#define TAS2770_SLOT_16BIT 16 -#define TAS2770_SLOT_32BIT 32 -#define TAS2770_I2C_RETRY_COUNT 3 - -struct tas2770_register { - int book; - int page; - int reg; -}; - -struct tas2770_dai_cfg { - unsigned int dai_fmt; - unsigned int tdm_delay; -}; struct tas2770_priv { struct device *dev; struct regmap *regmap; - struct snd_soc_codec *codec; struct snd_soc_component *component; - struct mutex dev_lock; - struct hrtimer mtimer; int power_state; int asi_format; struct gpio_desc *reset_gpio; int sampling_rate; - int frame_size; int channel_size; int slot_width; int v_sense_slot; int i_sense_slot; - bool runtime_suspend; - unsigned int err_code; - struct mutex codec_lock; }; #endif /* __TAS2770__ */ -- cgit From edd6d5393206ec9bfc74776f6f20a57f11327e1b Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 7 Oct 2019 12:11:55 -0500 Subject: ASoC: tas2770: Fix snd_soc_update_bits error handling According the documentation for snd_soc_update_bits the API will return a 1 if the update was successful with a value change, a 0 if the update was successful with no value change or a negative if the command just failed. So the value of return in the driver needs to be checked for being less then 0 or the caller may indicate failure when the value actually changed. Signed-off-by: Dan Murphy Link: https://lore.kernel.org/r/20191007171157.17813-1-dmurphy@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2770.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index f3a665b64fd6..ad76f22fcfac 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -83,7 +83,8 @@ static int tas2770_codec_suspend(struct snd_soc_component *component) TAS2770_PWR_CTRL, TAS2770_PWR_CTRL_MASK, TAS2770_PWR_CTRL_SHUTDOWN); - if (ret) + + if (ret < 0) return ret; return 0; @@ -97,8 +98,9 @@ static int tas2770_codec_resume(struct snd_soc_component *component) TAS2770_PWR_CTRL, TAS2770_PWR_CTRL_MASK, TAS2770_PWR_CTRL_ACTIVE); - if (ret) - return -EINVAL; + + if (ret < 0) + return ret; return 0; } @@ -150,7 +152,10 @@ static int tas2770_dac_event(struct snd_soc_dapm_widget *w, } end: - return ret; + if (ret < 0) + return ret; + + return 0; } static const struct snd_kcontrol_new isense_switch = @@ -200,7 +205,10 @@ static int tas2770_mute(struct snd_soc_dai *dai, int mute) TAS2770_PWR_CTRL_MASK, TAS2770_PWR_CTRL_ACTIVE); - return ret; + if (ret < 0) + return ret; + + return 0; } static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth) @@ -253,7 +261,10 @@ static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth) tas2770->i_sense_slot); end: - return ret; + if (ret < 0) + return ret; + + return 0; } static int tas2770_set_samplerate(struct tas2770_priv *tas2770, int samplerate) @@ -345,9 +356,11 @@ static int tas2770_set_samplerate(struct tas2770_priv *tas2770, int samplerate) } end: - if (!ret) - tas2770->sampling_rate = samplerate; - return ret; + if (ret < 0) + return ret; + + tas2770->sampling_rate = samplerate; + return 0; } static int tas2770_hw_params(struct snd_pcm_substream *substream, @@ -401,7 +414,7 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1, TAS2770_TDM_CFG_REG1_RX_MASK, asi_cfg_1); - if (ret) + if (ret < 0) return ret; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -426,7 +439,7 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1, TAS2770_TDM_CFG_REG1_MASK, (tdm_rx_start_slot << TAS2770_TDM_CFG_REG1_51_SHIFT)); - if (ret) + if (ret < 0) return ret; tas2770->asi_format = fmt; @@ -470,12 +483,12 @@ static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai, ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3, TAS2770_TDM_CFG_REG3_30_MASK, (left_slot << TAS2770_TDM_CFG_REG3_30_SHIFT)); - if (ret) + if (ret < 0) return ret; ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3, TAS2770_TDM_CFG_REG3_RXS_MASK, (right_slot << TAS2770_TDM_CFG_REG3_RXS_SHIFT)); - if (ret) + if (ret < 0) return ret; switch (slot_width) { @@ -509,10 +522,11 @@ static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai, ret = -EINVAL; } - if (!ret) - tas2770->slot_width = slot_width; + if (ret < 0) + return ret; - return ret; + tas2770->slot_width = slot_width; + return 0; } static struct snd_soc_dai_ops tas2770_dai_ops = { -- cgit From cfc28ac124c456ffbff5b34d4108d8a201cd7fbb Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 8 Oct 2019 14:57:20 +0300 Subject: ASoC: pcm3168a: Use fixup instead of constraint for channels and formats The snd_pcm_hw_constraint_minmax() works fine when a single codec is connected to a single CPU DAI, but in multicodec or DPCM setup the constraints placed by the driver will apply to the whole PCM stream (FE included) and thus prevents more than 8 playback channels for example. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191008115720.7135-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 98 ++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 58 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 88b75695fbf7..708dac27feff 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -62,6 +62,7 @@ struct pcm3168a_priv { unsigned long sysclk; struct pcm3168a_io_params io_params[2]; + struct snd_soc_dai_driver dai_drv[2]; }; static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" }; @@ -314,6 +315,37 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, return 0; } +static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); + u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE; + unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6; + + if (!pcm3168a->io_params[dai->id].fmt) + return; + + if (pcm3168a->io_params[dai->id].fmt == PCM3168A_FMT_RIGHT_J) { + /* S16_LE is only supported in RIGHT_J mode */ + formats |= SNDRV_PCM_FMTBIT_S16_LE; + + /* + * If multi DIN/DOUT is not selected, RIGHT_J can only support + * two channels (no TDM support) + */ + if (pcm3168a->io_params[dai->id].tdm_slots != 2) + channel_max = 2; + } + + if (dai->id == PCM3168A_DAI_DAC) { + dai->driver->playback.channels_max = channel_max; + dai->driver->playback.formats = formats; + } else { + dai->driver->capture.channels_max = channel_max; + dai->driver->capture.formats = formats; + } +} + static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) { struct snd_soc_component *component = dai->component; @@ -376,6 +408,8 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); + pcm3168a_update_fixup_pcm_stream(dai); + return 0; } @@ -409,6 +443,8 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, else io_params->tdm_mask = rx_mask; + pcm3168a_update_fixup_pcm_stream(dai); + return 0; } @@ -530,63 +566,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return 0; } -static int pcm3168a_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); - unsigned int sample_min; - unsigned int channel_max; - unsigned int channel_maxs[] = { - 8, /* DAC */ - 6 /* ADC */ - }; - - /* - * Available Data Bits - * - * RIGHT_J : 24 / 16 - * LEFT_J : 24 - * I2S : 24 - * - * TDM available - * - * I2S - * LEFT_J - */ - switch (pcm3168a->io_params[dai->id].fmt) { - case PCM3168A_FMT_RIGHT_J: - sample_min = 16; - channel_max = 2; - break; - case PCM3168A_FMT_LEFT_J: - case PCM3168A_FMT_I2S: - case PCM3168A_FMT_DSP_A: - case PCM3168A_FMT_DSP_B: - sample_min = 24; - channel_max = channel_maxs[dai->id]; - break; - default: - sample_min = 24; - channel_max = 2; - } - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - sample_min, 32); - - /* Allow all channels in multi DIN/DOUT mode */ - if (pcm3168a->io_params[dai->id].tdm_slots == 2) - channel_max = channel_maxs[dai->id]; - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_CHANNELS, - 2, channel_max); - - return 0; -} static const struct snd_soc_dai_ops pcm3168a_dai_ops = { - .startup = pcm3168a_startup, .set_fmt = pcm3168a_set_dai_fmt, .set_sysclk = pcm3168a_set_dai_sysclk, .hw_params = pcm3168a_hw_params, @@ -776,8 +756,10 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) pm_runtime_enable(dev); pm_runtime_idle(dev); - ret = devm_snd_soc_register_component(dev, &pcm3168a_driver, pcm3168a_dais, - ARRAY_SIZE(pcm3168a_dais)); + memcpy(pcm3168a->dai_drv, pcm3168a_dais, sizeof(pcm3168a->dai_drv)); + ret = devm_snd_soc_register_component(dev, &pcm3168a_driver, + pcm3168a->dai_drv, + ARRAY_SIZE(pcm3168a->dai_drv)); if (ret) { dev_err(dev, "failed to register component: %d\n", ret); goto err_regulator; -- cgit From 9e985503ee4b23d576c303a17dfe52cfc8f32727 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Fri, 27 Sep 2019 18:31:57 +0800 Subject: ASoC: mt8183: fix audio playback slowly after playback during bootup Before regmap_reinit_cache we must reset audio regs as default values. So we use reset controller unit(toprgu) to reset audio hw. Signed-off-by: Jiaxin Yu Reviewed-by: Yingjoe Chen Link: https://lore.kernel.org/r/1569580317-21181-5-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index 4a31106d3471..721632386a50 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "mt8183-afe-common.h" #include "mt8183-afe-clk.h" @@ -1089,6 +1090,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) struct mtk_base_afe *afe; struct mt8183_afe_private *afe_priv; struct device *dev; + struct reset_control *rstc; int i, irq_id, ret; afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); @@ -1126,6 +1128,19 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) return ret; } + rstc = devm_reset_control_get(dev, "audiosys"); + if (IS_ERR(rstc)) { + ret = PTR_ERR(rstc); + dev_err(dev, "could not get audiosys reset:%d\n", ret); + return ret; + } + + ret = reset_control_reset(rstc); + if (ret) { + dev_err(dev, "failed to trigger audio reset:%d\n", ret); + return ret; + } + /* enable clock for regcache get default value from hw */ afe_priv->pm_runtime_bypass_reg_ctl = true; pm_runtime_get_sync(&pdev->dev); -- cgit From e2cb4a14541dba3587bb78e0f62da27a0e1ad399 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:30:48 +0900 Subject: ASoC: soc-core: merge snd_pcm_ops member to component driver Current snd_soc_component_driver has snd_pcm_ops, and each driver can have callback via it (1). But, it is mainly created for ALSA, thus, it doesn't have "component" as parameter for ALSA SoC (1)(2). Thus, each callback can't know it is called for which component. Thus, each callback currently is getting "component" by using snd_soc_rtdcom_lookup() with driver name (3). --- ALSA SoC --- ... if (component->driver->ops && component->driver->ops->open) (1) return component->driver->ops->open(substream); ... --- driver --- (2) static int xxx_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; (3) struct snd_soc_component *component = snd_soc_rtdcom_lookup(..); ... } It works today, but, will not work in the future if we support multi CPU/Codec/Platform, because 1 rtd might have multiple components which have same driver name. To solve this issue, each callback needs to be called with component. We already have many component driver callback. This patch copies each snd_pcm_ops member under component driver, and having "component" as parameter. --- ALSA SoC --- ... if (component->driver->open) => return component->driver->open(component, substream); ... --- driver --- => static int xxx_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { ... } *Note* Only Intel skl-pcm has .get_time_info implementation, but ALSA SoC framework doesn't call it so far. To keep its implementation, this patch keeps .get_time_info, but it is still not called. Intel guy need to support it in the future. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tv8raf3r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-component.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 9 ++++---- 2 files changed, 57 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 79ffc2820ba9..2d9cb763e63a 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -314,6 +314,10 @@ void snd_soc_component_module_put(struct snd_soc_component *component, int snd_soc_component_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + if (component->driver->open) + return component->driver->open(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->open) return component->driver->ops->open(substream); @@ -324,6 +328,10 @@ int snd_soc_component_open(struct snd_soc_component *component, int snd_soc_component_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + if (component->driver->close) + return component->driver->close(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->close) return component->driver->ops->close(substream); @@ -334,6 +342,10 @@ int snd_soc_component_close(struct snd_soc_component *component, int snd_soc_component_prepare(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + if (component->driver->prepare) + return component->driver->prepare(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->prepare) return component->driver->ops->prepare(substream); @@ -345,6 +357,11 @@ int snd_soc_component_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { + if (component->driver->hw_params) + return component->driver->hw_params(component, + substream, params); + + /* remove me */ if (component->driver->ops && component->driver->ops->hw_params) return component->driver->ops->hw_params(substream, params); @@ -355,6 +372,10 @@ int snd_soc_component_hw_params(struct snd_soc_component *component, int snd_soc_component_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + if (component->driver->hw_free) + return component->driver->hw_free(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->hw_free) return component->driver->ops->hw_free(substream); @@ -366,6 +387,10 @@ int snd_soc_component_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) { + if (component->driver->trigger) + return component->driver->trigger(component, substream, cmd); + + /* remove me */ if (component->driver->ops && component->driver->ops->trigger) return component->driver->ops->trigger(substream, cmd); @@ -435,6 +460,10 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) component = rtdcom->component; /* FIXME: use 1st pointer */ + if (component->driver->pointer) + return component->driver->pointer(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->pointer) return component->driver->ops->pointer(substream); @@ -454,6 +483,11 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, component = rtdcom->component; /* FIXME: use 1st ioctl */ + if (component->driver->ioctl) + return component->driver->ioctl(component, substream, + cmd, arg); + + /* remove me */ if (component->driver->ops && component->driver->ops->ioctl) return component->driver->ops->ioctl(substream, @@ -475,6 +509,11 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, component = rtdcom->component; /* FIXME. it returns 1st copy now */ + if (component->driver->copy_user) + return component->driver->copy_user( + component, substream, channel, pos, buf, bytes); + + /* remove me */ if (component->driver->ops && component->driver->ops->copy_user) return component->driver->ops->copy_user( @@ -496,6 +535,14 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, component = rtdcom->component; /* FIXME. it returns 1st page now */ + if (component->driver->page) { + page = component->driver->page(component, + substream, offset); + if (page) + return page; + } + + /* remove me */ if (component->driver->ops && component->driver->ops->page) { page = component->driver->ops->page(substream, offset); @@ -518,6 +565,11 @@ int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, component = rtdcom->component; /* FIXME. it returns 1st mmap now */ + if (component->driver->mmap) + return component->driver->mmap(component, + substream, vma); + + /* remove me */ if (component->driver->ops && component->driver->ops->mmap) return component->driver->ops->mmap(substream, vma); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 66910500e3b6..dbf67d8a5411 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2987,16 +2987,17 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } for_each_rtdcom(rtd, rtdcom) { - const struct snd_pcm_ops *ops = rtdcom->component->driver->ops; + const struct snd_soc_component_driver *drv = rtdcom->component->driver; + const struct snd_pcm_ops *ops = drv->ops; if (!ops) continue; - if (ops->copy_user) + if (ops->copy_user || drv->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; - if (ops->page) + if (ops->page || drv->page) rtd->ops.page = snd_soc_pcm_component_page; - if (ops->mmap) + if (ops->mmap || drv->mmap) rtd->ops.mmap = snd_soc_pcm_component_mmap; } -- cgit From c64bfc9066007962fca1b9b2d426b1efc171cac9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:30:59 +0900 Subject: ASoC: soc-core: add new pcm_construct/pcm_destruct Current snd_soc_component_driver has pcm_new/pcm_free, but, it doesn't have "component" at parameter. Thus, each callback can't know it is called for which component. Each callback currently is getting "component" by using snd_soc_rtdcom_lookup() with driver name. It works today, but, will not work in the future if we support multi CPU/Codec/Platform, because 1 rtd might have multiple same driver name component. To solve this issue, each callback need to be called with component. This patch adds new pcm_construct/pcm_destruct with "component" parameter. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgobaf3g.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-component.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 2d9cb763e63a..d2b052ac88cd 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -588,6 +588,13 @@ int snd_soc_pcm_component_new(struct snd_pcm *pcm) for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; + if (component->driver->pcm_construct) { + ret = component->driver->pcm_construct(component, rtd); + if (ret < 0) + return ret; + } + + /* remove me */ if (component->driver->pcm_new) { ret = component->driver->pcm_new(rtd); if (ret < 0) @@ -607,6 +614,10 @@ void snd_soc_pcm_component_free(struct snd_pcm *pcm) for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; + if (component->driver->pcm_destruct) + component->driver->pcm_destruct(component, pcm); + + /* remove me */ if (component->driver->pcm_free) component->driver->pcm_free(pcm); } -- cgit From 8ec241c495dde3d19a0459304298c2468c60182b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:31:06 +0900 Subject: ASoC: soc-core: add snd_soc_pcm_lib_ioctl() add snd_soc_pcm_lib_ioctl() to bypass to snd_pcm_lib_ioctl() Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r23vaf39.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d39d908f3204..bd2ac1912466 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -277,6 +277,18 @@ static inline void snd_soc_debugfs_exit(void) #endif +/* + * This is glue code between snd_pcm_lib_ioctl() and + * snd_soc_component_driver :: ioctl + */ +int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + return snd_pcm_lib_ioctl(substream, cmd, arg); +} +EXPORT_SYMBOL_GPL(snd_soc_pcm_lib_ioctl); + static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component) { -- cgit From 86c05f3446ec4d8772e9d34b428d2e70c7f68e7a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:31:21 +0900 Subject: ASoC: intel: sst-haswell-pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pnjfaf2u.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-pcm.c | 62 +++++++++++++++++-------------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 7f4f6b755760..6e498a581d20 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -458,12 +458,12 @@ static int create_adsp_page_table(struct snd_pcm_substream *substream, } /* this may get called several times by oss emulation */ -static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int hsw_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; @@ -656,16 +656,17 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int hsw_pcm_hw_free(struct snd_pcm_substream *substream) +static int hsw_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { snd_pcm_lib_free_pages(substream); return 0; } -static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int hsw_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; struct sst_hsw_stream *sst_stream; @@ -770,11 +771,11 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data) return pos; } -static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; @@ -795,10 +796,21 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) return offset; } -static int hsw_pcm_open(struct snd_pcm_substream *substream) +#ifdef CONFIG_SND_DMA_SGBUF +static struct page *hsw_pcm_page(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned long offset) +{ + return snd_pcm_sgbuf_ops_page(substream, offset); +} +#else +#define hsw_pcm_page NULL +#endif /* CONFIG_SND_DMA_SGBUF */ + +static int hsw_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; @@ -828,10 +840,10 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int hsw_pcm_close(struct snd_pcm_substream *substream) +static int hsw_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component); struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; @@ -862,17 +874,6 @@ out: return ret; } -static const struct snd_pcm_ops hsw_pcm_ops = { - .open = hsw_pcm_open, - .close = hsw_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = hsw_pcm_hw_params, - .hw_free = hsw_pcm_hw_free, - .trigger = hsw_pcm_trigger, - .pointer = hsw_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) { struct sst_hsw *hsw = pdata->hsw; @@ -930,10 +931,10 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) } } -static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int hsw_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_pdata *pdata = dev_get_platdata(component->dev); struct hsw_priv_data *priv_data = dev_get_drvdata(component->dev); struct device *dev = pdata->dma_dev; @@ -1121,8 +1122,15 @@ static const struct snd_soc_component_driver hsw_dai_component = { .name = DRV_NAME, .probe = hsw_pcm_probe, .remove = hsw_pcm_remove, - .ops = &hsw_pcm_ops, - .pcm_new = hsw_pcm_new, + .open = hsw_pcm_open, + .close = hsw_pcm_close, + .hw_params = hsw_pcm_hw_params, + .hw_free = hsw_pcm_hw_free, + .trigger = hsw_pcm_trigger, + .pointer = hsw_pcm_pointer, + .page = hsw_pcm_page, + .ioctl = snd_soc_pcm_lib_ioctl, + .pcm_construct = hsw_pcm_new, .controls = hsw_volume_controls, .num_controls = ARRAY_SIZE(hsw_volume_controls), .dapm_widgets = widgets, -- cgit From 3507bb5fe46d12f517b68ea612159376c7ccce09 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:31:36 +0900 Subject: ASoC: intel: skl-pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. *Note* Only Intel skl-pcm has .get_time_info implementation, but ALSA SoC framework doesn't call it so far. To keep its implementation, this patch keeps .get_time_info, but it is still not called. Intel guy need to support it in the future. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o8yzaf2f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 67 +++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 7f287424af9b..0850141c7d47 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1081,7 +1081,8 @@ int skl_dai_load(struct snd_soc_component *cmp, int index, return 0; } -static int skl_platform_open(struct snd_pcm_substream *substream) +static int skl_platform_soc_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *dai_link = rtd->dai_link; @@ -1167,8 +1168,9 @@ static int skl_coupled_trigger(struct snd_pcm_substream *substream, return 0; } -static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) +static int skl_platform_soc_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int cmd) { struct hdac_bus *bus = get_bus_ctx(substream); @@ -1178,8 +1180,9 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, return 0; } -static snd_pcm_uframes_t skl_platform_pcm_pointer - (struct snd_pcm_substream *substream) +static snd_pcm_uframes_t skl_platform_soc_pointer( + struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); struct hdac_bus *bus = get_bus_ctx(substream); @@ -1225,6 +1228,24 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer return bytes_to_frames(substream->runtime, pos); } +static int skl_platform_soc_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *area) +{ + return snd_pcm_lib_default_mmap(substream, area); +} + +#ifdef CONFIG_SND_DMA_SGBUF +static struct page *skl_platform_soc_page(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned long offset) +{ + return snd_pcm_sgbuf_ops_page(substream, offset); +} +#else +#define skl_platform_soc_page NULL +#endif /* CONFIG_SND_DMA_SGBUF */ + static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, u64 nsec) { @@ -1245,7 +1266,9 @@ static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; } -static int skl_get_time_info(struct snd_pcm_substream *substream, +static int skl_platform_soc_get_time_info( + struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct timespec *system_ts, struct timespec *audio_ts, struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_report *audio_tstamp_report) @@ -1277,24 +1300,16 @@ static int skl_get_time_info(struct snd_pcm_substream *substream, return 0; } -static const struct snd_pcm_ops skl_platform_ops = { - .open = skl_platform_open, - .ioctl = snd_pcm_lib_ioctl, - .trigger = skl_platform_pcm_trigger, - .pointer = skl_platform_pcm_pointer, - .get_time_info = skl_get_time_info, - .mmap = snd_pcm_lib_default_mmap, - .page = snd_pcm_sgbuf_ops_page, -}; - -static void skl_pcm_free(struct snd_pcm *pcm) +static void skl_platform_soc_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { snd_pcm_lib_preallocate_free_for_all(pcm); } #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) -static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int skl_platform_soc_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; struct hdac_bus *bus = dev_get_drvdata(dai->dev); @@ -1458,7 +1473,7 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) return 0; } -static void skl_pcm_remove(struct snd_soc_component *component) +static void skl_platform_soc_remove(struct snd_soc_component *component) { struct hdac_bus *bus = dev_get_drvdata(component->dev); struct skl_dev *skl = bus_to_skl(bus); @@ -1471,10 +1486,16 @@ static void skl_pcm_remove(struct snd_soc_component *component) static const struct snd_soc_component_driver skl_component = { .name = "pcm", .probe = skl_platform_soc_probe, - .remove = skl_pcm_remove, - .ops = &skl_platform_ops, - .pcm_new = skl_pcm_new, - .pcm_free = skl_pcm_free, + .remove = skl_platform_soc_remove, + .open = skl_platform_soc_open, + .ioctl = snd_soc_pcm_lib_ioctl, + .trigger = skl_platform_soc_trigger, + .pointer = skl_platform_soc_pointer, + .get_time_info = skl_platform_soc_get_time_info, + .mmap = skl_platform_soc_mmap, + .page = skl_platform_soc_page, + .pcm_construct = skl_platform_soc_new, + .pcm_destruct = skl_platform_soc_free, .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ }; -- cgit From 9b9974d3d5d732a3897c9fa08f43aff65f917738 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:31:41 +0900 Subject: ASoC: intel: sst-mfld-platform-pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87muejaf2a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 30 +++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 8cc3cc363eb0..47e3d1943d7e 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -586,7 +586,8 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { }, }; -static int sst_platform_open(struct snd_pcm_substream *substream) +static int sst_soc_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; @@ -598,15 +599,15 @@ static int sst_platform_open(struct snd_pcm_substream *substream) return 0; } -static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) +static int sst_soc_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { int ret_val = 0, str_id; struct sst_runtime_stream *stream; int status; struct snd_soc_pcm_runtime *rtd = substream->private_data; - dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n"); + dev_dbg(rtd->dev, "%s called\n", __func__); if (substream->pcm->internal) return 0; stream = substream->runtime->private_data; @@ -646,8 +647,8 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, } -static snd_pcm_uframes_t sst_platform_pcm_pointer - (struct snd_pcm_substream *substream) +static snd_pcm_uframes_t sst_soc_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct sst_runtime_stream *stream; int ret_val, status; @@ -668,14 +669,8 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer return str_info->buffer_ptr; } -static const struct snd_pcm_ops sst_platform_ops = { - .open = sst_platform_open, - .ioctl = snd_pcm_lib_ioctl, - .trigger = sst_platform_pcm_trigger, - .pointer = sst_platform_pcm_pointer, -}; - -static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int sst_soc_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_pcm *pcm = rtd->pcm; @@ -709,9 +704,12 @@ static const struct snd_soc_component_driver sst_soc_platform_drv = { .name = DRV_NAME, .probe = sst_soc_probe, .remove = sst_soc_remove, - .ops = &sst_platform_ops, + .open = sst_soc_open, + .ioctl = snd_soc_pcm_lib_ioctl, + .trigger = sst_soc_trigger, + .pointer = sst_soc_pointer, .compr_ops = &sst_platform_compr_ops, - .pcm_new = sst_pcm_new, + .pcm_construct = sst_soc_pcm_new, }; static int sst_platform_probe(struct platform_device *pdev) -- cgit From bb3613515e96d02f665190091e7a0209d7985f8b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:31:47 +0900 Subject: ASoC: intel: sst-baytrail-pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfu3af24.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-pcm.c | 52 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index 54f2ee3010ee..1d780fcc448c 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -58,11 +58,11 @@ struct sst_byt_priv_data { }; /* this may get called several times by oss emulation */ -static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream, +static int sst_byt_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; struct sst_byt *byt = pdata->byt; @@ -121,7 +121,8 @@ static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream) +static int sst_byt_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -164,10 +165,10 @@ static void sst_byt_pcm_work(struct work_struct *work) sst_byt_pcm_restore_stream_context(pcm_data->substream); } -static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int sst_byt_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; struct sst_byt *byt = pdata->byt; @@ -228,11 +229,11 @@ static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data) return pos; } -static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; @@ -241,10 +242,10 @@ static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream return bytes_to_frames(runtime, pcm_data->hw_ptr); } -static int sst_byt_pcm_open(struct snd_pcm_substream *substream) +static int sst_byt_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; struct sst_byt *byt = pdata->byt; @@ -269,10 +270,10 @@ static int sst_byt_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int sst_byt_pcm_close(struct snd_pcm_substream *substream) +static int sst_byt_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component); struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream]; struct sst_byt *byt = pdata->byt; @@ -294,7 +295,8 @@ out: return ret; } -static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream, +static int sst_byt_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct vm_area_struct *vma) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -303,22 +305,11 @@ static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream, return snd_pcm_lib_default_mmap(substream, vma); } -static const struct snd_pcm_ops sst_byt_pcm_ops = { - .open = sst_byt_pcm_open, - .close = sst_byt_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = sst_byt_pcm_hw_params, - .hw_free = sst_byt_pcm_hw_free, - .trigger = sst_byt_pcm_trigger, - .pointer = sst_byt_pcm_pointer, - .mmap = sst_byt_pcm_mmap, -}; - -static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int sst_byt_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; size_t size; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_pdata *pdata = dev_get_platdata(component->dev); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || @@ -380,8 +371,15 @@ static int sst_byt_pcm_probe(struct snd_soc_component *component) static const struct snd_soc_component_driver byt_dai_component = { .name = DRV_NAME, .probe = sst_byt_pcm_probe, - .ops = &sst_byt_pcm_ops, - .pcm_new = sst_byt_pcm_new, + .open = sst_byt_pcm_open, + .close = sst_byt_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = sst_byt_pcm_hw_params, + .hw_free = sst_byt_pcm_hw_free, + .trigger = sst_byt_pcm_trigger, + .pointer = sst_byt_pcm_pointer, + .mmap = sst_byt_pcm_mmap, + .pcm_construct = sst_byt_pcm_new, }; #ifdef CONFIG_PM -- cgit From f52368f36443b4f77758999e34e7a6b54c4b3471 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:31:53 +0900 Subject: ASoC: amd: acp3x-pcm-dma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k19naf1y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/raven/acp3x-pcm-dma.c | 54 ++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index ea57088d50ce..60709e3ba99d 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -275,16 +275,12 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction) rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL); } -static int acp3x_dma_open(struct snd_pcm_substream *substream) +static int acp3x_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { int ret = 0; - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *prtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, - DRV_NAME); struct i2s_dev_data *adata = dev_get_drvdata(component->dev); - struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance), GFP_KERNEL); if (!i2s_data) @@ -334,7 +330,8 @@ static u64 acp_get_byte_count(struct i2s_stream_instance *rtd, int direction) return byte_count; } -static int acp3x_dma_hw_params(struct snd_pcm_substream *substream, +static int acp3x_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { int status; @@ -362,7 +359,8 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream, return status; } -static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { u32 pos = 0; u32 buffersize = 0; @@ -379,33 +377,32 @@ static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(substream->runtime, pos); } -static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd) +static int acp3x_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, - DRV_NAME); struct device *parent = component->dev->parent; snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, parent, MIN_BUFFER, MAX_BUFFER); return 0; } -static int acp3x_dma_hw_free(struct snd_pcm_substream *substream) +static int acp3x_dma_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } -static int acp3x_dma_mmap(struct snd_pcm_substream *substream, +static int acp3x_dma_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct vm_area_struct *vma) { return snd_pcm_lib_default_mmap(substream, vma); } -static int acp3x_dma_close(struct snd_pcm_substream *substream) +static int acp3x_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *prtd = substream->private_data; struct i2s_stream_instance *rtd = substream->runtime->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, - DRV_NAME); struct i2s_dev_data *adata = dev_get_drvdata(component->dev); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -422,17 +419,6 @@ static int acp3x_dma_close(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops acp3x_dma_ops = { - .open = acp3x_dma_open, - .close = acp3x_dma_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = acp3x_dma_hw_params, - .hw_free = acp3x_dma_hw_free, - .pointer = acp3x_dma_pointer, - .mmap = acp3x_dma_mmap, -}; - - static int acp3x_dai_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { @@ -610,9 +596,15 @@ static struct snd_soc_dai_driver acp3x_i2s_dai_driver = { }; static const struct snd_soc_component_driver acp3x_i2s_component = { - .name = DRV_NAME, - .ops = &acp3x_dma_ops, - .pcm_new = acp3x_dma_new, + .name = DRV_NAME, + .open = acp3x_dma_open, + .close = acp3x_dma_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = acp3x_dma_hw_params, + .hw_free = acp3x_dma_hw_free, + .pointer = acp3x_dma_pointer, + .mmap = acp3x_dma_mmap, + .pcm_construct = acp3x_dma_new, }; static int acp3x_audio_probe(struct platform_device *pdev) -- cgit From 8c028a4038ec4d4580971ff0aad86124b684994d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:31:58 +0900 Subject: ASoC: amd: acp-pcm-dma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87imp7af1t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-pcm-dma.c | 63 +++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 52225b4b6382..4b9a27e25206 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -759,14 +759,12 @@ static irqreturn_t dma_irq_handler(int irq, void *arg) return IRQ_NONE; } -static int acp_dma_open(struct snd_pcm_substream *substream) +static int acp_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { u16 bank; int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *prtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, - DRV_NAME); struct audio_drv_data *intr_data = dev_get_drvdata(component->dev); struct audio_substream_data *adata = kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL); @@ -834,7 +832,8 @@ static int acp_dma_open(struct snd_pcm_substream *substream) return 0; } -static int acp_dma_hw_params(struct snd_pcm_substream *substream, +static int acp_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { int status; @@ -843,8 +842,6 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime; struct audio_substream_data *rtd; struct snd_soc_pcm_runtime *prtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, - DRV_NAME); struct audio_drv_data *adata = dev_get_drvdata(component->dev); struct snd_soc_card *card = prtd->card; struct acp_platform_info *pinfo = snd_soc_card_get_drvdata(card); @@ -995,7 +992,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream, return status; } -static int acp_dma_hw_free(struct snd_pcm_substream *substream) +static int acp_dma_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } @@ -1011,7 +1009,8 @@ static u64 acp_get_byte_count(struct audio_substream_data *rtd) return byte_count.bytescount; } -static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { u32 buffersize; u32 pos = 0; @@ -1053,13 +1052,15 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(runtime, pos); } -static int acp_dma_mmap(struct snd_pcm_substream *substream, +static int acp_dma_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct vm_area_struct *vma) { return snd_pcm_lib_default_mmap(substream, vma); } -static int acp_dma_prepare(struct snd_pcm_substream *substream) +static int acp_dma_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct audio_substream_data *rtd = runtime->private_data; @@ -1086,7 +1087,8 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream) return 0; } -static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd) +static int acp_dma_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { int ret; @@ -1132,10 +1134,9 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) +static int acp_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, - DRV_NAME); struct audio_drv_data *adata = dev_get_drvdata(component->dev); struct device *parent = component->dev->parent; @@ -1158,14 +1159,12 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static int acp_dma_close(struct snd_pcm_substream *substream) +static int acp_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { u16 bank; struct snd_pcm_runtime *runtime = substream->runtime; struct audio_substream_data *rtd = runtime->private_data; - struct snd_soc_pcm_runtime *prtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, - DRV_NAME); struct audio_drv_data *adata = dev_get_drvdata(component->dev); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -1216,22 +1215,18 @@ static int acp_dma_close(struct snd_pcm_substream *substream) return 0; } -static const struct snd_pcm_ops acp_dma_ops = { - .open = acp_dma_open, - .close = acp_dma_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = acp_dma_hw_params, - .hw_free = acp_dma_hw_free, - .trigger = acp_dma_trigger, - .pointer = acp_dma_pointer, - .mmap = acp_dma_mmap, - .prepare = acp_dma_prepare, -}; - static const struct snd_soc_component_driver acp_asoc_platform = { - .name = DRV_NAME, - .ops = &acp_dma_ops, - .pcm_new = acp_dma_new, + .name = DRV_NAME, + .open = acp_dma_open, + .close = acp_dma_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = acp_dma_hw_params, + .hw_free = acp_dma_hw_free, + .trigger = acp_dma_trigger, + .pointer = acp_dma_pointer, + .mmap = acp_dma_mmap, + .prepare = acp_dma_prepare, + .pcm_construct = acp_dma_new, }; static int acp_audio_probe(struct platform_device *pdev) -- cgit From a94e3f2dd25c8d5496dbde0e61a73f31adfaddfe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:03 +0900 Subject: ASoC: atmel: atmel-pcm-pdc: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h84raf1o.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm-pdc.c | 48 ++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c index ed095af866db..18a2fd02fffe 100644 --- a/sound/soc/atmel/atmel-pcm-pdc.c +++ b/sound/soc/atmel/atmel-pcm-pdc.c @@ -56,15 +56,17 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, return 0; } -static int atmel_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) +static int atmel_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) { return remap_pfn_range(vma, vma->vm_start, substream->dma_buffer.addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot); } -static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int atmel_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -93,7 +95,8 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) return ret; } -static void atmel_pcm_free(struct snd_pcm *pcm) +static void atmel_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -196,8 +199,9 @@ static void atmel_pcm_dma_irq(u32 ssc_sr, /*--------------------------------------------------------------------------*\ * PCM operations \*--------------------------------------------------------------------------*/ -static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int atmel_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct atmel_runtime_data *prtd = runtime->private_data; @@ -225,7 +229,8 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) +static int atmel_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct atmel_runtime_data *prtd = substream->runtime->private_data; struct atmel_pcm_dma_params *params = prtd->params; @@ -239,7 +244,8 @@ static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int atmel_pcm_prepare(struct snd_pcm_substream *substream) +static int atmel_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct atmel_runtime_data *prtd = substream->runtime->private_data; struct atmel_pcm_dma_params *params = prtd->params; @@ -251,8 +257,8 @@ static int atmel_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static int atmel_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) +static int atmel_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *rtd = substream->runtime; struct atmel_runtime_data *prtd = rtd->private_data; @@ -317,8 +323,8 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream, return ret; } -static snd_pcm_uframes_t atmel_pcm_pointer( - struct snd_pcm_substream *substream) +static snd_pcm_uframes_t atmel_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct atmel_runtime_data *prtd = runtime->private_data; @@ -335,7 +341,8 @@ static snd_pcm_uframes_t atmel_pcm_pointer( return x; } -static int atmel_pcm_open(struct snd_pcm_substream *substream) +static int atmel_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct atmel_runtime_data *prtd; @@ -360,7 +367,8 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream) return ret; } -static int atmel_pcm_close(struct snd_pcm_substream *substream) +static int atmel_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct atmel_runtime_data *prtd = substream->runtime->private_data; @@ -368,22 +376,18 @@ static int atmel_pcm_close(struct snd_pcm_substream *substream) return 0; } -static const struct snd_pcm_ops atmel_pcm_ops = { +static const struct snd_soc_component_driver atmel_soc_platform = { .open = atmel_pcm_open, .close = atmel_pcm_close, - .ioctl = snd_pcm_lib_ioctl, + .ioctl = snd_soc_pcm_lib_ioctl, .hw_params = atmel_pcm_hw_params, .hw_free = atmel_pcm_hw_free, .prepare = atmel_pcm_prepare, .trigger = atmel_pcm_trigger, .pointer = atmel_pcm_pointer, .mmap = atmel_pcm_mmap, -}; - -static struct snd_soc_component_driver atmel_soc_platform = { - .ops = &atmel_pcm_ops, - .pcm_new = atmel_pcm_new, - .pcm_free = atmel_pcm_free, + .pcm_construct = atmel_pcm_new, + .pcm_destruct = atmel_pcm_free, }; int atmel_pcm_pdc_platform_register(struct device *dev) -- cgit From 58c2dbe110df85c8c07a3ce4033bcda265d39f07 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:07 +0900 Subject: ASoC: au1x: dbdma2: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ftkbaf1k.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/au1x/dbdma2.c | 64 ++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index d56092a5ee11..4553108ec92a 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -182,15 +182,15 @@ out: return 0; } -static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss) +static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss, + struct snd_soc_component *component) { - struct snd_soc_pcm_runtime *rtd = ss->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct au1xpsc_audio_dmadata *pcd = snd_soc_component_get_drvdata(component); return &pcd[ss->stream]; } -static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, +static int au1xpsc_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -202,7 +202,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, goto out; stype = substream->stream; - pcd = to_dmadata(substream); + pcd = to_dmadata(substream, component); DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %zu " "runtime->min_align %lu\n", @@ -232,15 +232,17 @@ out: return ret; } -static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream) +static int au1xpsc_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { snd_pcm_lib_free_pages(substream); return 0; } -static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) +static int au1xpsc_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream); + struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream, component); au1xxx_dbdma_reset(pcd->ddma_chan); @@ -255,9 +257,10 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int au1xpsc_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { - u32 c = to_dmadata(substream)->ddma_chan; + u32 c = to_dmadata(substream, component)->ddma_chan; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -275,14 +278,17 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } static snd_pcm_uframes_t -au1xpsc_pcm_pointer(struct snd_pcm_substream *substream) +au1xpsc_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos); + return bytes_to_frames(substream->runtime, + to_dmadata(substream, component)->pos); } -static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) +static int au1xpsc_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream); + struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream, component); struct snd_soc_pcm_runtime *rtd = substream->private_data; int stype = substream->stream, *dmaids; @@ -296,24 +302,15 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int au1xpsc_pcm_close(struct snd_pcm_substream *substream) +static int au1xpsc_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - au1x_pcm_dbdma_free(to_dmadata(substream)); + au1x_pcm_dbdma_free(to_dmadata(substream, component)); return 0; } -static const struct snd_pcm_ops au1xpsc_pcm_ops = { - .open = au1xpsc_pcm_open, - .close = au1xpsc_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = au1xpsc_pcm_hw_params, - .hw_free = au1xpsc_pcm_hw_free, - .prepare = au1xpsc_pcm_prepare, - .trigger = au1xpsc_pcm_trigger, - .pointer = au1xpsc_pcm_pointer, -}; - -static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int au1xpsc_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -327,8 +324,15 @@ static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd) /* au1xpsc audio platform */ static struct snd_soc_component_driver au1xpsc_soc_component = { .name = DRV_NAME, - .ops = &au1xpsc_pcm_ops, - .pcm_new = au1xpsc_pcm_new, + .open = au1xpsc_pcm_open, + .close = au1xpsc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = au1xpsc_pcm_hw_params, + .hw_free = au1xpsc_pcm_hw_free, + .prepare = au1xpsc_pcm_prepare, + .trigger = au1xpsc_pcm_trigger, + .pointer = au1xpsc_pcm_pointer, + .pcm_construct = au1xpsc_pcm_new, }; static int au1xpsc_pcm_drvprobe(struct platform_device *pdev) -- cgit From 297bdfd4f59ce9797d600589760554eb30f6a5f7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:13 +0900 Subject: ASoC: au1x: dma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87eezvaf1f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/au1x/dma.c | 63 +++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c index 1e98cc4f9e27..49556eb409cd 100644 --- a/sound/soc/au1x/dma.c +++ b/sound/soc/au1x/dma.c @@ -174,22 +174,23 @@ static const struct snd_pcm_hardware alchemy_pcm_hardware = { .fifo_size = 16, }; -static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss) +static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss, + struct snd_soc_component *component) { - struct snd_soc_pcm_runtime *rtd = ss->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); return snd_soc_component_get_drvdata(component); } -static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss) +static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss, + struct snd_soc_component *component) { - struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss); + struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss, component); return &(ctx->stream[ss->stream]); } -static int alchemy_pcm_open(struct snd_pcm_substream *substream) +static int alchemy_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream); + struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream, component); struct snd_soc_pcm_runtime *rtd = substream->private_data; int *dmaids, s = substream->stream; char *name; @@ -213,9 +214,10 @@ static int alchemy_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int alchemy_pcm_close(struct snd_pcm_substream *substream) +static int alchemy_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream); + struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream, component); int stype = substream->stream; ctx->stream[stype].substream = NULL; @@ -224,10 +226,11 @@ static int alchemy_pcm_close(struct snd_pcm_substream *substream) return 0; } -static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream, +static int alchemy_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - struct audio_stream *stream = ss_to_as(substream); + struct audio_stream *stream = ss_to_as(substream, component); int err; err = snd_pcm_lib_malloc_pages(substream, @@ -243,16 +246,18 @@ static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream, return err; } -static int alchemy_pcm_hw_free(struct snd_pcm_substream *substream) +static int alchemy_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct audio_stream *stream = ss_to_as(substream); + struct audio_stream *stream = ss_to_as(substream, component); au1000_release_dma_link(stream); return snd_pcm_lib_free_pages(substream); } -static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int alchemy_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { - struct audio_stream *stream = ss_to_as(substream); + struct audio_stream *stream = ss_to_as(substream, component); int err = 0; switch (cmd) { @@ -269,9 +274,10 @@ static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return err; } -static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss) +static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { - struct audio_stream *stream = ss_to_as(ss); + struct audio_stream *stream = ss_to_as(ss, component); long location; location = get_dma_residue(stream->dma); @@ -281,17 +287,8 @@ static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss) return bytes_to_frames(ss->runtime, location); } -static const struct snd_pcm_ops alchemy_pcm_ops = { - .open = alchemy_pcm_open, - .close = alchemy_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = alchemy_pcm_hw_params, - .hw_free = alchemy_pcm_hw_free, - .trigger = alchemy_pcm_trigger, - .pointer = alchemy_pcm_pointer, -}; - -static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int alchemy_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; @@ -303,8 +300,14 @@ static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_component_driver alchemy_pcm_soc_component = { .name = DRV_NAME, - .ops = &alchemy_pcm_ops, - .pcm_new = alchemy_pcm_new, + .open = alchemy_pcm_open, + .close = alchemy_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = alchemy_pcm_hw_params, + .hw_free = alchemy_pcm_hw_free, + .trigger = alchemy_pcm_trigger, + .pointer = alchemy_pcm_pointer, + .pcm_construct = alchemy_pcm_new, }; static int alchemy_pcm_drvprobe(struct platform_device *pdev) -- cgit From 17d48a3186bd7433c3cccabd767c7d7a19b76362 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:23 +0900 Subject: ASoC: xtensa: xtfpga-i2s: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87d0ffaf14.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/xtensa/xtfpga-i2s.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index efd374f114a0..e08f4fee932a 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -365,7 +365,8 @@ static const struct snd_pcm_hardware xtfpga_pcm_hardware = { .fifo_size = 16, }; -static int xtfpga_pcm_open(struct snd_pcm_substream *substream) +static int xtfpga_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -378,13 +379,15 @@ static int xtfpga_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int xtfpga_pcm_close(struct snd_pcm_substream *substream) +static int xtfpga_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { synchronize_rcu(); return 0; } -static int xtfpga_pcm_hw_params(struct snd_pcm_substream *substream, +static int xtfpga_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { int ret; @@ -424,7 +427,8 @@ static int xtfpga_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } -static int xtfpga_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int xtfpga_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; @@ -452,7 +456,8 @@ static int xtfpga_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static snd_pcm_uframes_t xtfpga_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t xtfpga_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct xtfpga_i2s *i2s = runtime->private_data; @@ -461,7 +466,8 @@ static snd_pcm_uframes_t xtfpga_pcm_pointer(struct snd_pcm_substream *substream) return pos < runtime->buffer_size ? pos : 0; } -static int xtfpga_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int xtfpga_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; size_t size = xtfpga_pcm_hardware.buffer_bytes_max; @@ -471,19 +477,15 @@ static int xtfpga_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static const struct snd_pcm_ops xtfpga_pcm_ops = { +static const struct snd_soc_component_driver xtfpga_i2s_component = { + .name = DRV_NAME, .open = xtfpga_pcm_open, .close = xtfpga_pcm_close, - .ioctl = snd_pcm_lib_ioctl, + .ioctl = snd_soc_pcm_lib_ioctl, .hw_params = xtfpga_pcm_hw_params, .trigger = xtfpga_pcm_trigger, .pointer = xtfpga_pcm_pointer, -}; - -static const struct snd_soc_component_driver xtfpga_i2s_component = { - .name = DRV_NAME, - .pcm_new = xtfpga_pcm_new, - .ops = &xtfpga_pcm_ops, + .pcm_construct = xtfpga_pcm_new, }; static const struct snd_soc_dai_ops xtfpga_i2s_dai_ops = { -- cgit From 2bcba42492bf9579c5804692828c56d55b95c1ad Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:29 +0900 Subject: ASoC: xilinx: xlnx_formatter_pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bluzaf0y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_formatter_pcm.c | 54 +++++++++++++++-------------------- 1 file changed, 23 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index fb652e73abeb..296c4caf96a0 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -313,16 +313,14 @@ static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg) return IRQ_NONE; } -static int xlnx_formatter_pcm_open(struct snd_pcm_substream *substream) +static int xlnx_formatter_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { int err; u32 val, data_format_mode; u32 ch_count_mask, ch_count_shift, data_xfer_mode, data_xfer_shift; struct xlnx_pcm_stream_param *stream_data; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *prtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, - DRV_NAME); struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && @@ -387,14 +385,12 @@ static int xlnx_formatter_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int xlnx_formatter_pcm_close(struct snd_pcm_substream *substream) +static int xlnx_formatter_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { int ret; struct xlnx_pcm_stream_param *stream_data = substream->runtime->private_data; - struct snd_soc_pcm_runtime *prtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, - DRV_NAME); ret = xlnx_formatter_pcm_reset(stream_data->mmio); if (ret) { @@ -409,7 +405,8 @@ err_reset: } static snd_pcm_uframes_t -xlnx_formatter_pcm_pointer(struct snd_pcm_substream *substream) +xlnx_formatter_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { u32 pos; struct snd_pcm_runtime *runtime = substream->runtime; @@ -423,16 +420,14 @@ xlnx_formatter_pcm_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(runtime, pos); } -static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream, +static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample; u32 aes_reg1_val, aes_reg2_val; int status; u64 size; - struct snd_soc_pcm_runtime *prtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, - DRV_NAME); struct snd_pcm_runtime *runtime = substream->runtime; struct xlnx_pcm_stream_param *stream_data = runtime->private_data; @@ -500,12 +495,14 @@ static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int xlnx_formatter_pcm_hw_free(struct snd_pcm_substream *substream) +static int xlnx_formatter_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } -static int xlnx_formatter_pcm_trigger(struct snd_pcm_substream *substream, +static int xlnx_formatter_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { u32 val; @@ -532,10 +529,9 @@ static int xlnx_formatter_pcm_trigger(struct snd_pcm_substream *substream, return 0; } -static int xlnx_formatter_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int xlnx_formatter_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, - DRV_NAME); snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, xlnx_pcm_hardware.buffer_bytes_max, @@ -543,20 +539,16 @@ static int xlnx_formatter_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static const struct snd_pcm_ops xlnx_formatter_pcm_ops = { - .open = xlnx_formatter_pcm_open, - .close = xlnx_formatter_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = xlnx_formatter_pcm_hw_params, - .hw_free = xlnx_formatter_pcm_hw_free, - .trigger = xlnx_formatter_pcm_trigger, - .pointer = xlnx_formatter_pcm_pointer, -}; - static const struct snd_soc_component_driver xlnx_asoc_component = { - .name = DRV_NAME, - .ops = &xlnx_formatter_pcm_ops, - .pcm_new = xlnx_formatter_pcm_new, + .name = DRV_NAME, + .open = xlnx_formatter_pcm_open, + .close = xlnx_formatter_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = xlnx_formatter_pcm_hw_params, + .hw_free = xlnx_formatter_pcm_hw_free, + .trigger = xlnx_formatter_pcm_trigger, + .pointer = xlnx_formatter_pcm_pointer, + .pcm_construct = xlnx_formatter_pcm_new, }; static int xlnx_formatter_pcm_probe(struct platform_device *pdev) -- cgit From c645ea1179a4c22ddf58f32be7f69284eae98566 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:36 +0900 Subject: ASoC: uniphier: aio-dma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878sq3af0r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/uniphier/aio-dma.c | 51 ++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c index e8446cc4e8f8..700d936ed94e 100644 --- a/sound/soc/uniphier/aio-dma.c +++ b/sound/soc/uniphier/aio-dma.c @@ -93,7 +93,8 @@ static irqreturn_t aiodma_irq(int irq, void *p) return ret; } -static int uniphier_aiodma_open(struct snd_pcm_substream *substream) +static int uniphier_aiodma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -103,7 +104,8 @@ static int uniphier_aiodma_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256); } -static int uniphier_aiodma_hw_params(struct snd_pcm_substream *substream, +static int uniphier_aiodma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); @@ -112,7 +114,8 @@ static int uniphier_aiodma_hw_params(struct snd_pcm_substream *substream, return 0; } -static int uniphier_aiodma_hw_free(struct snd_pcm_substream *substream) +static int uniphier_aiodma_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { snd_pcm_set_runtime_buffer(substream, NULL); substream->runtime->dma_bytes = 0; @@ -120,7 +123,8 @@ static int uniphier_aiodma_hw_free(struct snd_pcm_substream *substream) return 0; } -static int uniphier_aiodma_prepare(struct snd_pcm_substream *substream) +static int uniphier_aiodma_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); @@ -146,7 +150,8 @@ static int uniphier_aiodma_prepare(struct snd_pcm_substream *substream) return 0; } -static int uniphier_aiodma_trigger(struct snd_pcm_substream *substream, int cmd) +static int uniphier_aiodma_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); @@ -181,6 +186,7 @@ static int uniphier_aiodma_trigger(struct snd_pcm_substream *substream, int cmd) } static snd_pcm_uframes_t uniphier_aiodma_pointer( + struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -204,7 +210,8 @@ static snd_pcm_uframes_t uniphier_aiodma_pointer( return pos; } -static int uniphier_aiodma_mmap(struct snd_pcm_substream *substream, +static int uniphier_aiodma_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct vm_area_struct *vma) { vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); @@ -214,18 +221,8 @@ static int uniphier_aiodma_mmap(struct snd_pcm_substream *substream, vma->vm_end - vma->vm_start, vma->vm_page_prot); } -static const struct snd_pcm_ops uniphier_aiodma_ops = { - .open = uniphier_aiodma_open, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = uniphier_aiodma_hw_params, - .hw_free = uniphier_aiodma_hw_free, - .prepare = uniphier_aiodma_prepare, - .trigger = uniphier_aiodma_trigger, - .pointer = uniphier_aiodma_pointer, - .mmap = uniphier_aiodma_mmap, -}; - -static int uniphier_aiodma_new(struct snd_soc_pcm_runtime *rtd) +static int uniphier_aiodma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct device *dev = rtd->card->snd_card->dev; struct snd_pcm *pcm = rtd->pcm; @@ -242,16 +239,24 @@ static int uniphier_aiodma_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static void uniphier_aiodma_free(struct snd_pcm *pcm) +static void uniphier_aiodma_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { snd_pcm_lib_preallocate_free_for_all(pcm); } static const struct snd_soc_component_driver uniphier_soc_platform = { - .pcm_new = uniphier_aiodma_new, - .pcm_free = uniphier_aiodma_free, - .ops = &uniphier_aiodma_ops, - .compr_ops = &uniphier_aio_compr_ops, + .open = uniphier_aiodma_open, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = uniphier_aiodma_hw_params, + .hw_free = uniphier_aiodma_hw_free, + .prepare = uniphier_aiodma_prepare, + .trigger = uniphier_aiodma_trigger, + .pointer = uniphier_aiodma_pointer, + .mmap = uniphier_aiodma_mmap, + .pcm_construct = uniphier_aiodma_new, + .pcm_destruct = uniphier_aiodma_free, + .compr_ops = &uniphier_aio_compr_ops, }; static const struct regmap_config aiodma_regmap_config = { -- cgit From a857e073ffc67f95ddd6f3f427d0a62edd633d7d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:41 +0900 Subject: ASoC: txx9: txx9aclc: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/877e5naf0m.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/txx9/txx9aclc.c | 48 ++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index 66044559f70f..33c78d33e5a1 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -47,12 +47,12 @@ static const struct snd_pcm_hardware txx9aclc_pcm_hardware = { .buffer_bytes_max = 32 * 1024, }; -static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream, +static int txx9aclc_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct txx9aclc_dmadata *dmadata = runtime->private_data; int ret; @@ -76,12 +76,14 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int txx9aclc_pcm_hw_free(struct snd_pcm_substream *substream) +static int txx9aclc_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } -static int txx9aclc_pcm_prepare(struct snd_pcm_substream *substream) +static int txx9aclc_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct txx9aclc_dmadata *dmadata = runtime->private_data; @@ -203,7 +205,8 @@ static void txx9aclc_dma_tasklet(unsigned long data) spin_unlock_irqrestore(&dmadata->dma_lock, flags); } -static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int txx9aclc_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata; @@ -236,14 +239,16 @@ static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } static snd_pcm_uframes_t -txx9aclc_pcm_pointer(struct snd_pcm_substream *substream) +txx9aclc_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; return bytes_to_frames(substream->runtime, dmadata->pos); } -static int txx9aclc_pcm_open(struct snd_pcm_substream *substream) +static int txx9aclc_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct txx9aclc_soc_device *dev = &txx9aclc_soc_device; struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream]; @@ -261,7 +266,8 @@ static int txx9aclc_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int txx9aclc_pcm_close(struct snd_pcm_substream *substream) +static int txx9aclc_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; struct dma_chan *chan = dmadata->dma_chan; @@ -271,23 +277,12 @@ static int txx9aclc_pcm_close(struct snd_pcm_substream *substream) return 0; } -static const struct snd_pcm_ops txx9aclc_pcm_ops = { - .open = txx9aclc_pcm_open, - .close = txx9aclc_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = txx9aclc_pcm_hw_params, - .hw_free = txx9aclc_pcm_hw_free, - .prepare = txx9aclc_pcm_prepare, - .trigger = txx9aclc_pcm_trigger, - .pointer = txx9aclc_pcm_pointer, -}; - -static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int txx9aclc_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_pcm *pcm = rtd->pcm; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct platform_device *pdev = to_platform_device(component->dev); struct txx9aclc_soc_device *dev; struct resource *r; @@ -409,8 +404,15 @@ static const struct snd_soc_component_driver txx9aclc_soc_component = { .name = DRV_NAME, .probe = txx9aclc_pcm_probe, .remove = txx9aclc_pcm_remove, - .ops = &txx9aclc_pcm_ops, - .pcm_new = txx9aclc_pcm_new, + .open = txx9aclc_pcm_open, + .close = txx9aclc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = txx9aclc_pcm_hw_params, + .hw_free = txx9aclc_pcm_hw_free, + .prepare = txx9aclc_pcm_prepare, + .trigger = txx9aclc_pcm_trigger, + .pointer = txx9aclc_pcm_pointer, + .pcm_construct = txx9aclc_pcm_new, }; static int txx9aclc_soc_platform_probe(struct platform_device *pdev) -- cgit From 21499089765f1e8f69998c0506f69158db821c14 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:46 +0900 Subject: ASoC: stm: stm32_adfsdm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875zl7af0h.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_adfsdm.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 3c9a9deec9af..81c407da15c5 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -210,7 +210,8 @@ static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private) return 0; } -static int stm32_adfsdm_trigger(struct snd_pcm_substream *substream, int cmd) +static int stm32_adfsdm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct stm32_adfsdm_priv *priv = @@ -230,7 +231,8 @@ static int stm32_adfsdm_trigger(struct snd_pcm_substream *substream, int cmd) return -EINVAL; } -static int stm32_adfsdm_pcm_open(struct snd_pcm_substream *substream) +static int stm32_adfsdm_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); @@ -243,7 +245,8 @@ static int stm32_adfsdm_pcm_open(struct snd_pcm_substream *substream) return ret; } -static int stm32_adfsdm_pcm_close(struct snd_pcm_substream *substream) +static int stm32_adfsdm_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct stm32_adfsdm_priv *priv = @@ -256,6 +259,7 @@ static int stm32_adfsdm_pcm_close(struct snd_pcm_substream *substream) } static snd_pcm_uframes_t stm32_adfsdm_pcm_pointer( + struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -265,7 +269,8 @@ static snd_pcm_uframes_t stm32_adfsdm_pcm_pointer( return bytes_to_frames(substream->runtime, priv->pos); } -static int stm32_adfsdm_pcm_hw_params(struct snd_pcm_substream *substream, +static int stm32_adfsdm_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -282,23 +287,16 @@ static int stm32_adfsdm_pcm_hw_params(struct snd_pcm_substream *substream, params_period_size(params)); } -static int stm32_adfsdm_pcm_hw_free(struct snd_pcm_substream *substream) +static int stm32_adfsdm_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { snd_pcm_lib_free_pages(substream); return 0; } -static struct snd_pcm_ops stm32_adfsdm_pcm_ops = { - .open = stm32_adfsdm_pcm_open, - .close = stm32_adfsdm_pcm_close, - .hw_params = stm32_adfsdm_pcm_hw_params, - .hw_free = stm32_adfsdm_pcm_hw_free, - .trigger = stm32_adfsdm_trigger, - .pointer = stm32_adfsdm_pcm_pointer, -}; - -static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int stm32_adfsdm_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; struct stm32_adfsdm_priv *priv = @@ -310,7 +308,8 @@ static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm) +static void stm32_adfsdm_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; @@ -320,9 +319,14 @@ static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm) } static struct snd_soc_component_driver stm32_adfsdm_soc_platform = { - .ops = &stm32_adfsdm_pcm_ops, - .pcm_new = stm32_adfsdm_pcm_new, - .pcm_free = stm32_adfsdm_pcm_free, + .open = stm32_adfsdm_pcm_open, + .close = stm32_adfsdm_pcm_close, + .hw_params = stm32_adfsdm_pcm_hw_params, + .hw_free = stm32_adfsdm_pcm_hw_free, + .trigger = stm32_adfsdm_trigger, + .pointer = stm32_adfsdm_pcm_pointer, + .pcm_construct = stm32_adfsdm_pcm_new, + .pcm_destruct = stm32_adfsdm_pcm_free, }; static const struct of_device_id stm32_adfsdm_of_match[] = { -- cgit From 6702eed85b40a3106aa532880fc8f0bfa8103c52 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:51 +0900 Subject: ASoC: sprd: sprd-pcm-dma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874l0raf0c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sprd/sprd-pcm-dma.c | 74 +++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 42 deletions(-) (limited to 'sound') diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c index d38ebbbbf169..da4b8f5f192b 100644 --- a/sound/soc/sprd/sprd-pcm-dma.c +++ b/sound/soc/sprd/sprd-pcm-dma.c @@ -46,12 +46,10 @@ static const struct snd_pcm_hardware sprd_pcm_hardware = { .buffer_bytes_max = 64 * 1024, }; -static int sprd_pcm_open(struct snd_pcm_substream *substream) +static int sprd_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct device *dev = component->dev; struct sprd_pcm_dma_private *dma_private; int hw_chan = SPRD_PCM_CHANNEL_MAX; @@ -111,13 +109,11 @@ error: return ret; } -static int sprd_pcm_close(struct snd_pcm_substream *substream) +static int sprd_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; struct sprd_pcm_dma_private *dma_private = runtime->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct device *dev = component->dev; int size = runtime->hw.periods_max * SPRD_PCM_DMA_LINKLIST_SIZE; int i; @@ -157,14 +153,12 @@ static void sprd_pcm_release_dma_channel(struct snd_pcm_substream *substream) } } -static int sprd_pcm_request_dma_channel(struct snd_pcm_substream *substream, +static int sprd_pcm_request_dma_channel(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int channels) { struct snd_pcm_runtime *runtime = substream->runtime; struct sprd_pcm_dma_private *dma_private = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct device *dev = component->dev; struct sprd_pcm_dma_params *dma_params = dma_private->params; int i; @@ -190,14 +184,13 @@ static int sprd_pcm_request_dma_channel(struct snd_pcm_substream *substream, return 0; } -static int sprd_pcm_hw_params(struct snd_pcm_substream *substream, +static int sprd_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct sprd_pcm_dma_private *dma_private = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sprd_pcm_dma_params *dma_params; size_t totsize = params_buffer_bytes(params); size_t period = params_period_bytes(params); @@ -218,7 +211,8 @@ static int sprd_pcm_hw_params(struct snd_pcm_substream *substream, if (!dma_private->params) { dma_private->params = dma_params; - ret = sprd_pcm_request_dma_channel(substream, channels); + ret = sprd_pcm_request_dma_channel(component, + substream, channels); if (ret) return ret; } @@ -313,7 +307,8 @@ sg_err: return ret; } -static int sprd_pcm_hw_free(struct snd_pcm_substream *substream) +static int sprd_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { snd_pcm_set_runtime_buffer(substream, NULL); sprd_pcm_release_dma_channel(substream); @@ -321,13 +316,11 @@ static int sprd_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int sprd_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int sprd_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct sprd_pcm_dma_private *dma_private = substream->runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); int ret = 0, i; switch (cmd) { @@ -387,13 +380,11 @@ static int sprd_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static snd_pcm_uframes_t sprd_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t sprd_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; struct sprd_pcm_dma_private *dma_private = runtime->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); int pointer[SPRD_PCM_CHANNEL_MAX]; int bytes_of_pointer = 0, sel_max = 0, i; snd_pcm_uframes_t x; @@ -444,7 +435,8 @@ static snd_pcm_uframes_t sprd_pcm_pointer(struct snd_pcm_substream *substream) return x; } -static int sprd_pcm_mmap(struct snd_pcm_substream *substream, +static int sprd_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -456,18 +448,8 @@ static int sprd_pcm_mmap(struct snd_pcm_substream *substream, vma->vm_page_prot); } -static struct snd_pcm_ops sprd_pcm_ops = { - .open = sprd_pcm_open, - .close = sprd_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = sprd_pcm_hw_params, - .hw_free = sprd_pcm_hw_free, - .trigger = sprd_pcm_trigger, - .pointer = sprd_pcm_pointer, - .mmap = sprd_pcm_mmap, -}; - -static int sprd_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int sprd_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -506,7 +488,8 @@ static int sprd_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static void sprd_pcm_free(struct snd_pcm *pcm) +static void sprd_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; int i; @@ -523,10 +506,17 @@ static void sprd_pcm_free(struct snd_pcm *pcm) static const struct snd_soc_component_driver sprd_soc_component = { .name = DRV_NAME, - .ops = &sprd_pcm_ops, + .open = sprd_pcm_open, + .close = sprd_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = sprd_pcm_hw_params, + .hw_free = sprd_pcm_hw_free, + .trigger = sprd_pcm_trigger, + .pointer = sprd_pcm_pointer, + .mmap = sprd_pcm_mmap, + .pcm_construct = sprd_pcm_new, + .pcm_destruct = sprd_pcm_free, .compr_ops = &sprd_platform_compr_ops, - .pcm_new = sprd_pcm_new, - .pcm_free = sprd_pcm_free, }; static int sprd_soc_platform_probe(struct platform_device *pdev) -- cgit From 1c91d77e1775e0d497382cc3494f42e08582f065 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:32:56 +0900 Subject: ASoC: sof: pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8736gbaf07.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 88 ++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 2b876d497447..6490b1577152 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -19,12 +19,11 @@ #define DRV_NAME "sof-audio-component" /* Create DMA buffer page table for DSP */ -static int create_page_table(struct snd_pcm_substream *substream, +static int create_page_table(struct snd_soc_component *component, + struct snd_pcm_substream *substream, unsigned char *dma_area, size_t size) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); @@ -95,13 +94,12 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) EXPORT_SYMBOL(snd_sof_pcm_period_elapsed); /* this may get called several times by oss emulation */ -static int sof_pcm_hw_params(struct snd_pcm_substream *substream, +static int sof_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct sof_ipc_pcm_params pcm; @@ -135,7 +133,7 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, * ret == 0 means the buffer is not changed * so no need to regenerate the page table */ - ret = create_page_table(substream, runtime->dma_area, + ret = create_page_table(component, substream, runtime->dma_area, runtime->dma_bytes); if (ret < 0) return ret; @@ -237,11 +235,10 @@ static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, return ret; } -static int sof_pcm_hw_free(struct snd_pcm_substream *substream) +static int sof_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; int ret, err = 0; @@ -276,11 +273,10 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) return err; } -static int sof_pcm_prepare(struct snd_pcm_substream *substream) +static int sof_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; int ret; @@ -300,7 +296,8 @@ static int sof_pcm_prepare(struct snd_pcm_substream *substream) substream->stream); /* set hw_params */ - ret = sof_pcm_hw_params(substream, &spcm->params[substream->stream]); + ret = sof_pcm_hw_params(component, + substream, &spcm->params[substream->stream]); if (ret < 0) { dev_err(sdev->dev, "error: set pcm hw_params after resume\n"); return ret; @@ -313,11 +310,10 @@ static int sof_pcm_prepare(struct snd_pcm_substream *substream) * FE dai link trigger actions are always executed in non-atomic context because * they involve IPC's. */ -static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int sof_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; @@ -351,7 +347,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) break; case SNDRV_PCM_TRIGGER_RESUME: /* set up hw_params */ - ret = sof_pcm_prepare(substream); + ret = sof_pcm_prepare(component, substream); if (ret < 0) { dev_err(sdev->dev, "error: failed to set up hw_params upon resume\n"); @@ -395,11 +391,10 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; snd_pcm_uframes_t host, dai; @@ -428,12 +423,22 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) return host; } -static int sof_pcm_open(struct snd_pcm_substream *substream) +#ifdef CONFIG_SND_DMA_SGBUF +static struct page *sof_pcm_page(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned long offset) +{ + return snd_pcm_sgbuf_ops_page(substream, offset); +} +#else +#define sof_pcm_page NULL +#endif /* CONFIG_SND_DMA_SGBUF */ + +static int sof_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct snd_soc_tplg_stream_caps *caps; @@ -505,11 +510,10 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) return ret; } -static int sof_pcm_close(struct snd_pcm_substream *substream) +static int sof_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; int err; @@ -538,27 +542,14 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops sof_pcm_ops = { - .open = sof_pcm_open, - .close = sof_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = sof_pcm_hw_params, - .prepare = sof_pcm_prepare, - .hw_free = sof_pcm_hw_free, - .trigger = sof_pcm_trigger, - .pointer = sof_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - /* * Pre-allocate playback/capture audio buffer pages. * no need to explicitly release memory preallocated by sof_pcm_new in pcm_free * snd_pcm_lib_preallocate_free_for_all() is called by the core. */ -static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int sof_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct snd_pcm *pcm = rtd->pcm; @@ -752,11 +743,20 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->name = "sof-audio-component"; pd->probe = sof_pcm_probe; pd->remove = sof_pcm_remove; - pd->ops = &sof_pcm_ops; + pd->open = sof_pcm_open; + pd->close = sof_pcm_close; + pd->ioctl = snd_soc_pcm_lib_ioctl; + pd->hw_params = sof_pcm_hw_params; + pd->prepare = sof_pcm_prepare; + pd->hw_free = sof_pcm_hw_free; + pd->trigger = sof_pcm_trigger; + pd->pointer = sof_pcm_pointer; + pd->page = sof_pcm_page; + #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) pd->compr_ops = &sof_compressed_ops; #endif - pd->pcm_new = sof_pcm_new; + pd->pcm_construct = sof_pcm_new; pd->ignore_machine = drv_name; pd->be_hw_params_fixup = sof_pcm_dai_link_fixup; pd->be_pcm_base = SOF_BE_PCM_BASE; -- cgit From 9dcefa7232d3fd5a7141454849d46ed24c7af867 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:01 +0900 Subject: ASoC: sh: rsnd: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871rvvaf02.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index bda5b958d0dc..4bed26842095 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1373,8 +1373,9 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) /* * pcm ops */ -static int rsnd_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) +static int rsnd_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); @@ -1421,7 +1422,8 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); } -static int rsnd_hw_free(struct snd_pcm_substream *substream) +static int rsnd_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); @@ -1435,7 +1437,8 @@ static int rsnd_hw_free(struct snd_pcm_substream *substream) return snd_pcm_lib_free_pages(substream); } -static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); @@ -1447,13 +1450,6 @@ static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) return pointer; } -static const struct snd_pcm_ops rsnd_pcm_ops = { - .ioctl = snd_pcm_lib_ioctl, - .hw_params = rsnd_hw_params, - .hw_free = rsnd_hw_free, - .pointer = rsnd_pointer, -}; - /* * snd_kcontrol */ @@ -1647,8 +1643,11 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, * snd_soc_component */ static const struct snd_soc_component_driver rsnd_soc_component = { - .ops = &rsnd_pcm_ops, .name = "rsnd", + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = rsnd_hw_params, + .hw_free = rsnd_hw_free, + .pointer = rsnd_pointer, }; static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, -- cgit From be513045d6fe8284e0e6f9060415d0c5189e179a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:06 +0900 Subject: ASoC: sh: fsi: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zhij90fh.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 3447dbdba1f1..e384fdc8d60e 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1718,7 +1718,8 @@ static const struct snd_pcm_hardware fsi_pcm_hardware = { .fifo_size = 256, }; -static int fsi_pcm_open(struct snd_pcm_substream *substream) +static int fsi_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; int ret = 0; @@ -1731,19 +1732,22 @@ static int fsi_pcm_open(struct snd_pcm_substream *substream) return ret; } -static int fsi_hw_params(struct snd_pcm_substream *substream, +static int fsi_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } -static int fsi_hw_free(struct snd_pcm_substream *substream) +static int fsi_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } -static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t fsi_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct fsi_priv *fsi = fsi_get_priv(substream); struct fsi_stream *io = fsi_stream_get(fsi, substream); @@ -1751,14 +1755,6 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) return fsi_sample2frame(fsi, io->buff_sample_pos); } -static const struct snd_pcm_ops fsi_pcm_ops = { - .open = fsi_pcm_open, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = fsi_hw_params, - .hw_free = fsi_hw_free, - .pointer = fsi_pointer, -}; - /* * snd_soc_component */ @@ -1766,7 +1762,8 @@ static const struct snd_pcm_ops fsi_pcm_ops = { #define PREALLOC_BUFFER (32 * 1024) #define PREALLOC_BUFFER_MAX (32 * 1024) -static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int fsi_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, @@ -1817,8 +1814,12 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { static const struct snd_soc_component_driver fsi_soc_component = { .name = "fsi", - .ops = &fsi_pcm_ops, - .pcm_new = fsi_pcm_new, + .open = fsi_pcm_open, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = fsi_hw_params, + .hw_free = fsi_hw_free, + .pointer = fsi_pointer, + .pcm_construct = fsi_pcm_new, }; /* -- cgit From db5b4ee95238d2c5e9a97f53257f6b7ea7e1caa0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:11 +0900 Subject: ASoC: sh: dma-sh7760: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y2y390fc.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/dma-sh7760.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 5aee11c94f2a..93bb80d089be 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -115,7 +115,8 @@ static void camelot_rxdma(void *data) snd_pcm_period_elapsed(cam->rx_ss); } -static int camelot_pcm_open(struct snd_pcm_substream *substream) +static int camelot_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id]; @@ -148,7 +149,8 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int camelot_pcm_close(struct snd_pcm_substream *substream) +static int camelot_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id]; @@ -168,7 +170,8 @@ static int camelot_pcm_close(struct snd_pcm_substream *substream) return 0; } -static int camelot_hw_params(struct snd_pcm_substream *substream, +static int camelot_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -191,12 +194,14 @@ static int camelot_hw_params(struct snd_pcm_substream *substream, return 0; } -static int camelot_hw_free(struct snd_pcm_substream *substream) +static int camelot_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } -static int camelot_prepare(struct snd_pcm_substream *substream) +static int camelot_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -244,7 +249,8 @@ static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam) BRGREG(BRGACR) = acr | ACR_RDS; } -static int camelot_trigger(struct snd_pcm_substream *substream, int cmd) +static int camelot_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id]; @@ -270,7 +276,8 @@ static int camelot_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t camelot_pos(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -292,18 +299,8 @@ static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream) return bytes_to_frames(runtime, pos); } -static const struct snd_pcm_ops camelot_pcm_ops = { - .open = camelot_pcm_open, - .close = camelot_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = camelot_hw_params, - .hw_free = camelot_hw_free, - .prepare = camelot_prepare, - .trigger = camelot_trigger, - .pointer = camelot_pos, -}; - -static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int camelot_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; @@ -319,8 +316,15 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) } static const struct snd_soc_component_driver sh7760_soc_component = { - .ops = &camelot_pcm_ops, - .pcm_new = camelot_pcm_new, + .open = camelot_pcm_open, + .close = camelot_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = camelot_hw_params, + .hw_free = camelot_hw_free, + .prepare = camelot_prepare, + .trigger = camelot_trigger, + .pointer = camelot_pos, + .pcm_construct = camelot_pcm_new, }; static int sh7760_soc_platform_probe(struct platform_device *pdev) -- cgit From 932eaf7c790458bea89830f6801c10dda569c805 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:16 +0900 Subject: ASoC: sh: siu_pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87wodn90f7.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/siu_pcm.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index 78c3145b4109..a5e21e554da2 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -281,7 +281,8 @@ static int siu_pcm_stmread_stop(struct siu_port *port_info) return 0; } -static int siu_pcm_hw_params(struct snd_pcm_substream *ss, +static int siu_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *ss, struct snd_pcm_hw_params *hw_params) { struct siu_info *info = siu_i2s_data; @@ -297,7 +298,8 @@ static int siu_pcm_hw_params(struct snd_pcm_substream *ss, return ret; } -static int siu_pcm_hw_free(struct snd_pcm_substream *ss) +static int siu_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { struct siu_info *info = siu_i2s_data; struct siu_port *port_info = siu_port_info(ss); @@ -324,11 +326,10 @@ static bool filter(struct dma_chan *chan, void *slave) return true; } -static int siu_pcm_open(struct snd_pcm_substream *ss) +static int siu_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { /* Playback / Capture */ - struct snd_soc_pcm_runtime *rtd = ss->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct siu_platform *pdata = component->dev->platform_data; struct siu_info *info = siu_i2s_data; struct siu_port *port_info = siu_port_info(ss); @@ -367,7 +368,8 @@ static int siu_pcm_open(struct snd_pcm_substream *ss) return 0; } -static int siu_pcm_close(struct snd_pcm_substream *ss) +static int siu_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { struct siu_info *info = siu_i2s_data; struct device *dev = ss->pcm->card->dev; @@ -389,7 +391,8 @@ static int siu_pcm_close(struct snd_pcm_substream *ss) return 0; } -static int siu_pcm_prepare(struct snd_pcm_substream *ss) +static int siu_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { struct siu_info *info = siu_i2s_data; struct siu_port *port_info = siu_port_info(ss); @@ -435,7 +438,8 @@ static int siu_pcm_prepare(struct snd_pcm_substream *ss) return 0; } -static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd) +static int siu_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *ss, int cmd) { struct siu_info *info = siu_i2s_data; struct device *dev = ss->pcm->card->dev; @@ -477,7 +481,9 @@ static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd) * So far only resolution of one period is supported, subject to extending the * dmangine API */ -static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss) +static snd_pcm_uframes_t +siu_pcm_pointer_dma(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { struct device *dev = ss->pcm->card->dev; struct siu_info *info = siu_i2s_data; @@ -512,7 +518,8 @@ static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss) return bytes_to_frames(ss->runtime, ptr); } -static int siu_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int siu_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { /* card->dev == socdev->dev, see snd_soc_new_pcms() */ struct snd_card *card = rtd->card->snd_card; @@ -558,7 +565,8 @@ static int siu_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static void siu_pcm_free(struct snd_pcm *pcm) +static void siu_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct platform_device *pdev = to_platform_device(pcm->card->dev); struct siu_port *port_info = siu_ports[pdev->id]; @@ -571,21 +579,17 @@ static void siu_pcm_free(struct snd_pcm *pcm) dev_dbg(pcm->card->dev, "%s\n", __func__); } -static const struct snd_pcm_ops siu_pcm_ops = { +struct const snd_soc_component_driver siu_component = { + .name = DRV_NAME, .open = siu_pcm_open, .close = siu_pcm_close, - .ioctl = snd_pcm_lib_ioctl, + .ioctl = snd_soc_pcm_lib_ioctl, .hw_params = siu_pcm_hw_params, .hw_free = siu_pcm_hw_free, .prepare = siu_pcm_prepare, .trigger = siu_pcm_trigger, .pointer = siu_pcm_pointer_dma, -}; - -struct snd_soc_component_driver siu_component = { - .name = DRV_NAME, - .ops = &siu_pcm_ops, - .pcm_new = siu_pcm_new, - .pcm_free = siu_pcm_free, + .pcm_construct = siu_pcm_new, + .pcm_destruct = siu_pcm_free, }; EXPORT_SYMBOL_GPL(siu_component); -- cgit From ba40ab6275173ef9b35b466324a25921a3f49b42 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:21 +0900 Subject: ASoC: samsung: idma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v9t790f2.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/idma.c | 58 ++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c index 65497cd477a5..294dce111b05 100644 --- a/sound/soc/samsung/idma.c +++ b/sound/soc/samsung/idma.c @@ -137,8 +137,9 @@ static void idma_done(void *id, int bytes_xfer) snd_pcm_period_elapsed(substream); } -static int idma_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int idma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct idma_ctrl *prtd = substream->runtime->private_data; @@ -163,14 +164,16 @@ static int idma_hw_params(struct snd_pcm_substream *substream, return 0; } -static int idma_hw_free(struct snd_pcm_substream *substream) +static int idma_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { snd_pcm_set_runtime_buffer(substream, NULL); return 0; } -static int idma_prepare(struct snd_pcm_substream *substream) +static int idma_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct idma_ctrl *prtd = substream->runtime->private_data; @@ -183,7 +186,8 @@ static int idma_prepare(struct snd_pcm_substream *substream) return 0; } -static int idma_trigger(struct snd_pcm_substream *substream, int cmd) +static int idma_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct idma_ctrl *prtd = substream->runtime->private_data; int ret = 0; @@ -216,7 +220,8 @@ static int idma_trigger(struct snd_pcm_substream *substream, int cmd) } static snd_pcm_uframes_t - idma_pointer(struct snd_pcm_substream *substream) +idma_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct idma_ctrl *prtd = runtime->private_data; @@ -233,7 +238,8 @@ static snd_pcm_uframes_t return bytes_to_frames(substream->runtime, res); } -static int idma_mmap(struct snd_pcm_substream *substream, +static int idma_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -278,7 +284,8 @@ static irqreturn_t iis_irq(int irqno, void *dev_id) return IRQ_HANDLED; } -static int idma_open(struct snd_pcm_substream *substream) +static int idma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct idma_ctrl *prtd; @@ -304,7 +311,8 @@ static int idma_open(struct snd_pcm_substream *substream) return 0; } -static int idma_close(struct snd_pcm_substream *substream) +static int idma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct idma_ctrl *prtd = runtime->private_data; @@ -319,19 +327,8 @@ static int idma_close(struct snd_pcm_substream *substream) return 0; } -static const struct snd_pcm_ops idma_ops = { - .open = idma_open, - .close = idma_close, - .ioctl = snd_pcm_lib_ioctl, - .trigger = idma_trigger, - .pointer = idma_pointer, - .mmap = idma_mmap, - .hw_params = idma_hw_params, - .hw_free = idma_hw_free, - .prepare = idma_prepare, -}; - -static void idma_free(struct snd_pcm *pcm) +static void idma_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -367,7 +364,8 @@ static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream) return 0; } -static int idma_new(struct snd_soc_pcm_runtime *rtd) +static int idma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -394,9 +392,17 @@ void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr) EXPORT_SYMBOL_GPL(idma_reg_addr_init); static const struct snd_soc_component_driver asoc_idma_platform = { - .ops = &idma_ops, - .pcm_new = idma_new, - .pcm_free = idma_free, + .open = idma_open, + .close = idma_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .trigger = idma_trigger, + .pointer = idma_pointer, + .mmap = idma_mmap, + .hw_params = idma_hw_params, + .hw_free = idma_hw_free, + .prepare = idma_prepare, + .pcm_construct = idma_new, + .pcm_destruct = idma_free, }; static int asoc_idma_platform_probe(struct platform_device *pdev) -- cgit From 8b83c90dbac79ae873d3099d03d9a98c0bf9ed15 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:29 +0900 Subject: ASoC: qcom: lpass-platform: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tv8r90eu.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-platform.c | 70 ++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 36 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 4c745baa39f7..2e8892316423 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -50,12 +50,12 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = { .fifo_size = 0, }; -static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) +static int lpass_platform_pcmops_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME); struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct lpass_variant *v = drvdata->variant; int ret, dma_ch, dir = substream->stream; @@ -105,11 +105,10 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) return 0; } -static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream) +static int lpass_platform_pcmops_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME); struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct lpass_variant *v = drvdata->variant; struct lpass_pcm_data *data; @@ -122,11 +121,11 @@ static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream) return 0; } -static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME); 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; @@ -216,10 +215,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, return 0; } -static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) +static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME); 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; @@ -236,11 +235,11 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) return ret; } -static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) +static int lpass_platform_pcmops_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME); 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; @@ -288,11 +287,11 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) return 0; } -static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, - int cmd) +static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int cmd) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME); 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; @@ -363,10 +362,10 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, } static snd_pcm_uframes_t lpass_platform_pcmops_pointer( + struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME); 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; @@ -395,8 +394,9 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( return bytes_to_frames(substream->runtime, curr_addr - base_addr); } -static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) +static int lpass_platform_pcmops_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -405,18 +405,6 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream, runtime->dma_bytes); } -static const struct snd_pcm_ops lpass_platform_pcm_ops = { - .open = lpass_platform_pcmops_open, - .close = lpass_platform_pcmops_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = lpass_platform_pcmops_hw_params, - .hw_free = lpass_platform_pcmops_hw_free, - .prepare = lpass_platform_pcmops_prepare, - .trigger = lpass_platform_pcmops_trigger, - .pointer = lpass_platform_pcmops_pointer, - .mmap = lpass_platform_pcmops_mmap, -}; - static irqreturn_t lpass_dma_interrupt_handler( struct snd_pcm_substream *substream, struct lpass_data *drvdata, @@ -499,11 +487,11 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) return IRQ_HANDLED; } -static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) +static int lpass_platform_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *soc_runtime) { struct snd_pcm *pcm = soc_runtime->pcm; struct snd_pcm_substream *psubstream, *csubstream; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME); int ret = -EINVAL; size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; @@ -535,7 +523,8 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) return 0; } -static void lpass_platform_pcm_free(struct snd_pcm *pcm) +static void lpass_platform_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; int i; @@ -552,9 +541,18 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm) static const struct snd_soc_component_driver lpass_component_driver = { .name = DRV_NAME, - .pcm_new = lpass_platform_pcm_new, - .pcm_free = lpass_platform_pcm_free, - .ops = &lpass_platform_pcm_ops, + .open = lpass_platform_pcmops_open, + .close = lpass_platform_pcmops_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = lpass_platform_pcmops_hw_params, + .hw_free = lpass_platform_pcmops_hw_free, + .prepare = lpass_platform_pcmops_prepare, + .trigger = lpass_platform_pcmops_trigger, + .pointer = lpass_platform_pcmops_pointer, + .mmap = lpass_platform_pcmops_mmap, + .pcm_construct = lpass_platform_pcm_new, + .pcm_destruct = lpass_platform_pcm_free, + }; int asoc_qcom_lpass_platform_register(struct platform_device *pdev) -- cgit From e198048bdc63b8a5f258c990b4d9ad8a08b7932a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:34 +0900 Subject: ASoC: qcom: q6routing: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgob90ep.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6routing.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index ddcd9978cf57..20724102e85a 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -939,12 +939,12 @@ static const struct snd_soc_dapm_route intercon[] = { }; -static int routing_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int routing_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct msm_routing_data *data = dev_get_drvdata(c->dev); + struct msm_routing_data *data = dev_get_drvdata(component->dev); unsigned int be_id = rtd->cpu_dai->id; struct session_data *session; int path_type; @@ -980,10 +980,6 @@ static int routing_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_pcm_ops q6pcm_routing_ops = { - .hw_params = routing_hw_params, -}; - static int msm_routing_probe(struct snd_soc_component *c) { int i; @@ -997,9 +993,9 @@ static int msm_routing_probe(struct snd_soc_component *c) } static const struct snd_soc_component_driver msm_soc_routing_component = { - .ops = &q6pcm_routing_ops, .probe = msm_routing_probe, .name = DRV_NAME, + .hw_params = routing_hw_params, .dapm_widgets = msm_qdsp6_widgets, .num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets), .dapm_routes = intercon, -- cgit From 2324c8f4cd35280272419df0f45b37429d3256d4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:39 +0900 Subject: ASoC: qcom: q6asm-dai: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r23v90ek.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm-dai.c | 71 ++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 36 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 548eb4fa2da6..f59353f510b8 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -206,16 +206,16 @@ static void event_handler(uint32_t opcode, uint32_t token, } } -static int q6asm_dai_prepare(struct snd_pcm_substream *substream) +static int q6asm_dai_prepare(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 q6asm_dai_rtd *prtd = runtime->private_data; - struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME); struct q6asm_dai_data *pdata; int ret, i; - pdata = snd_soc_component_get_drvdata(c); + pdata = snd_soc_component_get_drvdata(component); if (!pdata) return -EINVAL; @@ -294,7 +294,8 @@ static int q6asm_dai_prepare(struct snd_pcm_substream *substream) return 0; } -static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd) +static int q6asm_dai_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; @@ -322,21 +323,21 @@ static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static int q6asm_dai_open(struct snd_pcm_substream *substream) +static int q6asm_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_dai *cpu_dai = soc_prtd->cpu_dai; - struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME); struct q6asm_dai_rtd *prtd; struct q6asm_dai_data *pdata; - struct device *dev = c->dev; + struct device *dev = component->dev; int ret = 0; int stream_id; stream_id = cpu_dai->driver->id; - pdata = snd_soc_component_get_drvdata(c); + pdata = snd_soc_component_get_drvdata(component); if (!pdata) { pr_err("Drv data not found ..\n"); return -EINVAL; @@ -414,7 +415,8 @@ static int q6asm_dai_open(struct snd_pcm_substream *substream) return 0; } -static int q6asm_dai_close(struct snd_pcm_substream *substream) +static int q6asm_dai_close(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; @@ -435,7 +437,8 @@ static int q6asm_dai_close(struct snd_pcm_substream *substream) return 0; } -static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -447,22 +450,21 @@ static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(runtime, (prtd->pcm_irq_pos)); } -static int q6asm_dai_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) +static int q6asm_dai_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME); - struct device *dev = c->dev; + struct device *dev = component->dev; return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); } -static int q6asm_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int q6asm_dai_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct q6asm_dai_rtd *prtd = runtime->private_data; @@ -482,17 +484,6 @@ static int q6asm_dai_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_pcm_ops q6asm_dai_ops = { - .open = q6asm_dai_open, - .hw_params = q6asm_dai_hw_params, - .close = q6asm_dai_close, - .ioctl = snd_pcm_lib_ioctl, - .prepare = q6asm_dai_prepare, - .trigger = q6asm_dai_trigger, - .pointer = q6asm_dai_pointer, - .mmap = q6asm_dai_mmap, -}; - static void compress_event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) { @@ -800,15 +791,15 @@ static struct snd_compr_ops q6asm_dai_compr_ops = { .ack = q6asm_dai_compr_ack, }; -static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int q6asm_dai_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_pcm_substream *psubstream, *csubstream; - struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_pcm *pcm = rtd->pcm; struct device *dev; int size, ret; - dev = c->dev; + dev = component->dev; size = q6asm_dai_hardware_playback.buffer_bytes_max; psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (psubstream) { @@ -835,7 +826,8 @@ static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static void q6asm_dai_pcm_free(struct snd_pcm *pcm) +static void q6asm_dai_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; int i; @@ -852,9 +844,16 @@ static void q6asm_dai_pcm_free(struct snd_pcm *pcm) static const struct snd_soc_component_driver q6asm_fe_dai_component = { .name = DRV_NAME, - .ops = &q6asm_dai_ops, - .pcm_new = q6asm_dai_pcm_new, - .pcm_free = q6asm_dai_pcm_free, + .open = q6asm_dai_open, + .hw_params = q6asm_dai_hw_params, + .close = q6asm_dai_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .prepare = q6asm_dai_prepare, + .trigger = q6asm_dai_trigger, + .pointer = q6asm_dai_pointer, + .mmap = q6asm_dai_mmap, + .pcm_construct = q6asm_dai_pcm_new, + .pcm_destruct = q6asm_dai_pcm_free, .compr_ops = &q6asm_dai_compr_ops, }; -- cgit From 540e59c68bbcd450d711aaddddc9332507a5a504 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:44 +0900 Subject: ASoC: pxa: mmp-pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pnjf90ef.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-pcm.c | 62 +++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 7096b5263e25..54a4c9213e83 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -55,8 +55,9 @@ static struct snd_pcm_hardware mmp_pcm_hardware[] = { }, }; -static int mmp_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int mmp_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); struct dma_slave_config slave_config; @@ -77,6 +78,18 @@ static int mmp_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } +static int mmp_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + return snd_dmaengine_pcm_trigger(substream, cmd); +} + +static snd_pcm_uframes_t mmp_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return snd_dmaengine_pcm_pointer(substream); +} + static bool filter(struct dma_chan *chan, void *param) { struct mmp_dma_data *dma_data = param; @@ -94,10 +107,10 @@ static bool filter(struct dma_chan *chan, void *param) return found; } -static int mmp_pcm_open(struct snd_pcm_substream *substream) +static int mmp_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct platform_device *pdev = to_platform_device(component->dev); struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct mmp_dma_data dma_data; @@ -117,8 +130,15 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream) &dma_data); } -static int mmp_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) +static int mmp_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return snd_dmaengine_pcm_close_release_chan(substream); +} + +static int mmp_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; unsigned long off = vma->vm_pgoff; @@ -129,17 +149,8 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream, vma->vm_end - vma->vm_start, vma->vm_page_prot); } -static const struct snd_pcm_ops mmp_pcm_ops = { - .open = mmp_pcm_open, - .close = snd_dmaengine_pcm_close_release_chan, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = mmp_pcm_hw_params, - .trigger = snd_dmaengine_pcm_trigger, - .pointer = snd_dmaengine_pcm_pointer, - .mmap = mmp_pcm_mmap, -}; - -static void mmp_pcm_free_dma_buffers(struct snd_pcm *pcm) +static void mmp_pcm_free_dma_buffers(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -188,7 +199,8 @@ static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream, return 0; } -static int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int mmp_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_pcm_substream *substream; struct snd_pcm *pcm = rtd->pcm; @@ -205,15 +217,21 @@ static int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; err: - mmp_pcm_free_dma_buffers(pcm); + mmp_pcm_free_dma_buffers(component, pcm); return ret; } static const struct snd_soc_component_driver mmp_soc_component = { .name = DRV_NAME, - .ops = &mmp_pcm_ops, - .pcm_new = mmp_pcm_new, - .pcm_free = mmp_pcm_free_dma_buffers, + .open = mmp_pcm_open, + .close = mmp_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = mmp_pcm_hw_params, + .trigger = mmp_pcm_trigger, + .pointer = mmp_pcm_pointer, + .mmap = mmp_pcm_mmap, + .pcm_construct = mmp_pcm_new, + .pcm_destruct = mmp_pcm_free_dma_buffers, }; static int mmp_pcm_probe(struct platform_device *pdev) -- cgit From f8772e17def20470f94bd1d6e1cf24badb2611de Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:50 +0900 Subject: ASoC: pxa: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o8yz90e9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/arm/pxa2xx-pcm-lib.c | 80 +++++++++++++++++++++++++++++++++++++-------- sound/soc/pxa/pxa-ssp.c | 14 ++++++-- sound/soc/pxa/pxa2xx-ac97.c | 14 ++++++-- sound/soc/pxa/pxa2xx-i2s.c | 14 ++++++-- sound/soc/pxa/pxa2xx-pcm.c | 14 ++++++-- 5 files changed, 111 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index 54500bd098f9..a86c95d89824 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -175,7 +175,15 @@ void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) } EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers); -int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd) +void pxa2xx_soc_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) +{ + pxa2xx_pcm_free_dma_buffers(pcm); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_free); + +int pxa2xx_soc_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -203,18 +211,64 @@ int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd) } EXPORT_SYMBOL(pxa2xx_soc_pcm_new); -const struct snd_pcm_ops pxa2xx_pcm_ops = { - .open = pxa2xx_pcm_open, - .close = pxa2xx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pxa2xx_pcm_hw_params, - .hw_free = pxa2xx_pcm_hw_free, - .prepare = pxa2xx_pcm_prepare, - .trigger = pxa2xx_pcm_trigger, - .pointer = pxa2xx_pcm_pointer, - .mmap = pxa2xx_pcm_mmap, -}; -EXPORT_SYMBOL(pxa2xx_pcm_ops); +int pxa2xx_soc_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_open(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_open); + +int pxa2xx_soc_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_close(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_close); + +int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return pxa2xx_pcm_hw_params(substream, params); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_params); + +int pxa2xx_soc_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_hw_free(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_free); + +int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_prepare(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_prepare); + +int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + return pxa2xx_pcm_trigger(substream, cmd); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_trigger); + +snd_pcm_uframes_t +pxa2xx_soc_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_pointer(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_pointer); + +int pxa2xx_soc_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return pxa2xx_pcm_mmap(substream, vma); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_mmap); MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("Intel PXA2xx sound library"); diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 5fdd1a24c232..49cb3ba1519f 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -869,9 +869,17 @@ static struct snd_soc_dai_driver pxa_ssp_dai = { static const struct snd_soc_component_driver pxa_ssp_component = { .name = "pxa-ssp", - .ops = &pxa2xx_pcm_ops, - .pcm_new = pxa2xx_soc_pcm_new, - .pcm_free = pxa2xx_pcm_free_dma_buffers, + .pcm_construct = pxa2xx_soc_pcm_new, + .pcm_destruct = pxa2xx_soc_pcm_free, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = pxa2xx_soc_pcm_hw_params, + .hw_free = pxa2xx_soc_pcm_hw_free, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .mmap = pxa2xx_soc_pcm_mmap, }; #ifdef CONFIG_OF diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index bf28187315db..31e81a6f616f 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -204,9 +204,17 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { static const struct snd_soc_component_driver pxa_ac97_component = { .name = "pxa-ac97", - .ops = &pxa2xx_pcm_ops, - .pcm_new = pxa2xx_soc_pcm_new, - .pcm_free = pxa2xx_pcm_free_dma_buffers, + .pcm_construct = pxa2xx_soc_pcm_new, + .pcm_destruct = pxa2xx_soc_pcm_free, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = pxa2xx_soc_pcm_hw_params, + .hw_free = pxa2xx_soc_pcm_hw_free, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .mmap = pxa2xx_soc_pcm_mmap, }; #ifdef CONFIG_OF diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 9f7fb7335ac0..e77d707efde7 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -360,9 +360,17 @@ static struct snd_soc_dai_driver pxa_i2s_dai = { static const struct snd_soc_component_driver pxa_i2s_component = { .name = "pxa-i2s", - .ops = &pxa2xx_pcm_ops, - .pcm_new = pxa2xx_soc_pcm_new, - .pcm_free = pxa2xx_pcm_free_dma_buffers, + .pcm_construct = pxa2xx_soc_pcm_new, + .pcm_destruct = pxa2xx_soc_pcm_free, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = pxa2xx_soc_pcm_hw_params, + .hw_free = pxa2xx_soc_pcm_hw_free, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .mmap = pxa2xx_soc_pcm_mmap, }; static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 74b56fa0870f..07b3455a6f23 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -18,9 +18,17 @@ #include static const struct snd_soc_component_driver pxa2xx_soc_platform = { - .ops = &pxa2xx_pcm_ops, - .pcm_new = pxa2xx_soc_pcm_new, - .pcm_free = pxa2xx_pcm_free_dma_buffers, + .pcm_construct = pxa2xx_soc_pcm_new, + .pcm_destruct = pxa2xx_soc_pcm_free, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = pxa2xx_soc_pcm_hw_params, + .hw_free = pxa2xx_soc_pcm_hw_free, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .mmap = pxa2xx_soc_pcm_mmap, }; static int pxa2xx_soc_platform_probe(struct platform_device *pdev) -- cgit From bb4ba744b1701caf6148ff3b4e8656bf4f6b4758 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:55 +0900 Subject: ASoC: meson: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87muej90e4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-fifo.c | 56 +++++++++++++++++++-------------------------- sound/soc/meson/axg-fifo.h | 20 +++++++++++++--- sound/soc/meson/axg-frddr.c | 24 ++++++++++++++++--- sound/soc/meson/axg-toddr.c | 24 ++++++++++++++++--- 4 files changed, 83 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index 5a3749938900..d6f3eefb8f09 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -70,7 +70,8 @@ static void __dma_enable(struct axg_fifo *fifo, bool enable) enable ? CTRL0_DMA_EN : 0); } -static int axg_fifo_pcm_trigger(struct snd_pcm_substream *ss, int cmd) +int axg_fifo_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *ss, int cmd) { struct axg_fifo *fifo = axg_fifo_data(ss); @@ -91,8 +92,10 @@ static int axg_fifo_pcm_trigger(struct snd_pcm_substream *ss, int cmd) return 0; } +EXPORT_SYMBOL_GPL(axg_fifo_pcm_trigger); -static snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_pcm_substream *ss) +snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { struct axg_fifo *fifo = axg_fifo_data(ss); struct snd_pcm_runtime *runtime = ss->runtime; @@ -102,9 +105,11 @@ static snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_pcm_substream *ss) return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr); } +EXPORT_SYMBOL_GPL(axg_fifo_pcm_pointer); -static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss, - struct snd_pcm_hw_params *params) +int axg_fifo_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *ss, + struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = ss->runtime; struct axg_fifo *fifo = axg_fifo_data(ss); @@ -132,15 +137,17 @@ static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss, return 0; } +EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_params); -static int g12a_fifo_pcm_hw_params(struct snd_pcm_substream *ss, - struct snd_pcm_hw_params *params) +int g12a_fifo_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *ss, + struct snd_pcm_hw_params *params) { struct axg_fifo *fifo = axg_fifo_data(ss); struct snd_pcm_runtime *runtime = ss->runtime; int ret; - ret = axg_fifo_pcm_hw_params(ss, params); + ret = axg_fifo_pcm_hw_params(component, ss, params); if (ret) return ret; @@ -149,8 +156,10 @@ static int g12a_fifo_pcm_hw_params(struct snd_pcm_substream *ss, return 0; } +EXPORT_SYMBOL_GPL(g12a_fifo_pcm_hw_params); -static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss) +int axg_fifo_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { struct axg_fifo *fifo = axg_fifo_data(ss); @@ -160,6 +169,7 @@ static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss) return snd_pcm_lib_free_pages(ss); } +EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free); static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask) { @@ -194,7 +204,8 @@ static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id) return IRQ_RETVAL(status); } -static int axg_fifo_pcm_open(struct snd_pcm_substream *ss) +int axg_fifo_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { struct axg_fifo *fifo = axg_fifo_data(ss); struct device *dev = axg_fifo_dev(ss); @@ -250,8 +261,10 @@ static int axg_fifo_pcm_open(struct snd_pcm_substream *ss) return ret; } +EXPORT_SYMBOL_GPL(axg_fifo_pcm_open); -static int axg_fifo_pcm_close(struct snd_pcm_substream *ss) +int axg_fifo_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *ss) { struct axg_fifo *fifo = axg_fifo_data(ss); int ret; @@ -267,28 +280,7 @@ static int axg_fifo_pcm_close(struct snd_pcm_substream *ss) return ret; } - -const struct snd_pcm_ops axg_fifo_pcm_ops = { - .open = axg_fifo_pcm_open, - .close = axg_fifo_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = axg_fifo_pcm_hw_params, - .hw_free = axg_fifo_pcm_hw_free, - .pointer = axg_fifo_pcm_pointer, - .trigger = axg_fifo_pcm_trigger, -}; -EXPORT_SYMBOL_GPL(axg_fifo_pcm_ops); - -const struct snd_pcm_ops g12a_fifo_pcm_ops = { - .open = axg_fifo_pcm_open, - .close = axg_fifo_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = g12a_fifo_pcm_hw_params, - .hw_free = axg_fifo_pcm_hw_free, - .pointer = axg_fifo_pcm_pointer, - .trigger = axg_fifo_pcm_trigger, -}; -EXPORT_SYMBOL_GPL(g12a_fifo_pcm_ops); +EXPORT_SYMBOL_GPL(axg_fifo_pcm_close); int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type) { diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h index bb1e2ce50256..cf928d43b558 100644 --- a/sound/soc/meson/axg-fifo.h +++ b/sound/soc/meson/axg-fifo.h @@ -15,7 +15,7 @@ struct reset_control; struct snd_soc_component_driver; struct snd_soc_dai; struct snd_soc_dai_driver; -struct snd_pcm_ops; + struct snd_soc_pcm_runtime; #define AXG_FIFO_CH_MAX 128 @@ -75,8 +75,22 @@ struct axg_fifo_match_data { struct snd_soc_dai_driver *dai_drv; }; -extern const struct snd_pcm_ops axg_fifo_pcm_ops; -extern const struct snd_pcm_ops g12a_fifo_pcm_ops; +int axg_fifo_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *ss); +int axg_fifo_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *ss); +int axg_fifo_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *ss, + struct snd_pcm_hw_params *params); +int g12a_fifo_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *ss, + struct snd_pcm_hw_params *params); +int axg_fifo_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *ss); +snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *ss); +int axg_fifo_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *ss, int cmd); int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type); int axg_fifo_probe(struct platform_device *pdev); diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 6ab111c31b28..665d75d49d7b 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -149,7 +149,13 @@ static const struct snd_soc_component_driver axg_frddr_component_drv = { .num_dapm_widgets = ARRAY_SIZE(axg_frddr_dapm_widgets), .dapm_routes = axg_frddr_dapm_routes, .num_dapm_routes = ARRAY_SIZE(axg_frddr_dapm_routes), - .ops = &axg_fifo_pcm_ops + .open = axg_fifo_pcm_open, + .close = axg_fifo_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = axg_fifo_pcm_hw_params, + .hw_free = axg_fifo_pcm_hw_free, + .pointer = axg_fifo_pcm_pointer, + .trigger = axg_fifo_pcm_trigger, }; static const struct axg_fifo_match_data axg_frddr_match_data = { @@ -267,7 +273,13 @@ static const struct snd_soc_component_driver g12a_frddr_component_drv = { .num_dapm_widgets = ARRAY_SIZE(g12a_frddr_dapm_widgets), .dapm_routes = g12a_frddr_dapm_routes, .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes), - .ops = &g12a_fifo_pcm_ops + .open = axg_fifo_pcm_open, + .close = axg_fifo_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = g12a_fifo_pcm_hw_params, + .hw_free = axg_fifo_pcm_hw_free, + .pointer = axg_fifo_pcm_pointer, + .trigger = axg_fifo_pcm_trigger, }; static const struct axg_fifo_match_data g12a_frddr_match_data = { @@ -331,7 +343,13 @@ static const struct snd_soc_component_driver sm1_frddr_component_drv = { .num_dapm_widgets = ARRAY_SIZE(sm1_frddr_dapm_widgets), .dapm_routes = g12a_frddr_dapm_routes, .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes), - .ops = &g12a_fifo_pcm_ops + .open = axg_fifo_pcm_open, + .close = axg_fifo_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = g12a_fifo_pcm_hw_params, + .hw_free = axg_fifo_pcm_hw_free, + .pointer = axg_fifo_pcm_pointer, + .trigger = axg_fifo_pcm_trigger, }; static const struct axg_fifo_match_data sm1_frddr_match_data = { diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index c8ea2145f576..7fef0b961496 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -181,7 +181,13 @@ static const struct snd_soc_component_driver axg_toddr_component_drv = { .num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets), .dapm_routes = axg_toddr_dapm_routes, .num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes), - .ops = &axg_fifo_pcm_ops + .open = axg_fifo_pcm_open, + .close = axg_fifo_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = axg_fifo_pcm_hw_params, + .hw_free = axg_fifo_pcm_hw_free, + .pointer = axg_fifo_pcm_pointer, + .trigger = axg_fifo_pcm_trigger, }; static const struct axg_fifo_match_data axg_toddr_match_data = { @@ -214,7 +220,13 @@ static const struct snd_soc_component_driver g12a_toddr_component_drv = { .num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets), .dapm_routes = axg_toddr_dapm_routes, .num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes), - .ops = &g12a_fifo_pcm_ops + .open = axg_fifo_pcm_open, + .close = axg_fifo_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = g12a_fifo_pcm_hw_params, + .hw_free = axg_fifo_pcm_hw_free, + .pointer = axg_fifo_pcm_pointer, + .trigger = axg_fifo_pcm_trigger, }; static const struct axg_fifo_match_data g12a_toddr_match_data = { @@ -278,7 +290,13 @@ static const struct snd_soc_component_driver sm1_toddr_component_drv = { .num_dapm_widgets = ARRAY_SIZE(sm1_toddr_dapm_widgets), .dapm_routes = sm1_toddr_dapm_routes, .num_dapm_routes = ARRAY_SIZE(sm1_toddr_dapm_routes), - .ops = &g12a_fifo_pcm_ops + .open = axg_fifo_pcm_open, + .close = axg_fifo_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = g12a_fifo_pcm_hw_params, + .hw_free = axg_fifo_pcm_hw_free, + .pointer = axg_fifo_pcm_pointer, + .trigger = axg_fifo_pcm_trigger, }; static const struct axg_fifo_match_data sm1_toddr_match_data = { -- cgit From 9a0b72b71da0d50fe6e4fee2abaced10e61c48cc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:00 +0900 Subject: ASoC: mediatek: mtk-btcvsd: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfu390dz.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-btcvsd.c | 76 +++++++++++++--------------------- 1 file changed, 28 insertions(+), 48 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index d00608c73c6e..2b490ae2e642 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -875,11 +875,9 @@ static const struct snd_pcm_hardware mtk_btcvsd_hardware = { .fifo_size = 0, }; -static int mtk_pcm_btcvsd_open(struct snd_pcm_substream *substream) +static int mtk_pcm_btcvsd_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); int ret; @@ -899,11 +897,9 @@ static int mtk_pcm_btcvsd_open(struct snd_pcm_substream *substream) return ret; } -static int mtk_pcm_btcvsd_close(struct snd_pcm_substream *substream) +static int mtk_pcm_btcvsd_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream); @@ -914,12 +910,10 @@ static int mtk_pcm_btcvsd_close(struct snd_pcm_substream *substream) return 0; } -static int mtk_pcm_btcvsd_hw_params(struct snd_pcm_substream *substream, +static int mtk_pcm_btcvsd_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && @@ -934,11 +928,9 @@ static int mtk_pcm_btcvsd_hw_params(struct snd_pcm_substream *substream, return 0; } -static int mtk_pcm_btcvsd_hw_free(struct snd_pcm_substream *substream) +static int mtk_pcm_btcvsd_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -947,11 +939,9 @@ static int mtk_pcm_btcvsd_hw_free(struct snd_pcm_substream *substream) return 0; } -static int mtk_pcm_btcvsd_prepare(struct snd_pcm_substream *substream) +static int mtk_pcm_btcvsd_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream); @@ -961,11 +951,9 @@ static int mtk_pcm_btcvsd_prepare(struct snd_pcm_substream *substream) return 0; } -static int mtk_pcm_btcvsd_trigger(struct snd_pcm_substream *substream, int cmd) +static int mtk_pcm_btcvsd_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream); int stream = substream->stream; @@ -993,12 +981,10 @@ static int mtk_pcm_btcvsd_trigger(struct snd_pcm_substream *substream, int cmd) } } -static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer - (struct snd_pcm_substream *substream) +static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer( + struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); struct mtk_btcvsd_snd_stream *bt_stream; snd_pcm_uframes_t frame = 0; @@ -1044,13 +1030,11 @@ static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer return frame; } -static int mtk_pcm_btcvsd_copy(struct snd_pcm_substream *substream, +static int mtk_pcm_btcvsd_copy(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int channel, unsigned long pos, void __user *buf, unsigned long count) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -1061,18 +1045,6 @@ static int mtk_pcm_btcvsd_copy(struct snd_pcm_substream *substream, return 0; } -static struct snd_pcm_ops mtk_btcvsd_ops = { - .open = mtk_pcm_btcvsd_open, - .close = mtk_pcm_btcvsd_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = mtk_pcm_btcvsd_hw_params, - .hw_free = mtk_pcm_btcvsd_hw_free, - .prepare = mtk_pcm_btcvsd_prepare, - .trigger = mtk_pcm_btcvsd_trigger, - .pointer = mtk_pcm_btcvsd_pointer, - .copy_user = mtk_pcm_btcvsd_copy, -}; - /* kcontrol */ static const char *const btsco_band_str[] = {"NB", "WB"}; @@ -1295,9 +1267,17 @@ static int mtk_btcvsd_snd_component_probe(struct snd_soc_component *component) } static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = { - .name = BTCVSD_SND_NAME, - .ops = &mtk_btcvsd_ops, - .probe = mtk_btcvsd_snd_component_probe, + .name = BTCVSD_SND_NAME, + .probe = mtk_btcvsd_snd_component_probe, + .open = mtk_pcm_btcvsd_open, + .close = mtk_pcm_btcvsd_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = mtk_pcm_btcvsd_hw_params, + .hw_free = mtk_pcm_btcvsd_hw_free, + .prepare = mtk_pcm_btcvsd_prepare, + .trigger = mtk_pcm_btcvsd_trigger, + .pointer = mtk_pcm_btcvsd_pointer, + .copy_user = mtk_pcm_btcvsd_copy, }; static int mtk_btcvsd_snd_probe(struct platform_device *pdev) -- cgit From 1fddf424b3c49a475ca7c23662f515b53f884172 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:05 +0900 Subject: ASoC: mediatek: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k19n90du.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../soc/mediatek/common/mtk-afe-platform-driver.c | 28 ++++++++++------------ .../soc/mediatek/common/mtk-afe-platform-driver.h | 10 ++++---- sound/soc/mediatek/mt6797/mt6797-afe-pcm.c | 11 +++++---- sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 11 +++++---- 4 files changed, 30 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c index 3ce527ce30ce..b6624d8d084b 100644 --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c @@ -77,11 +77,10 @@ int mtk_afe_add_sub_dai_control(struct snd_soc_component *component) } EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control); -static snd_pcm_uframes_t mtk_afe_pcm_pointer - (struct snd_pcm_substream *substream) +snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; const struct mtk_base_memif_data *memif_data = memif->data; @@ -111,18 +110,13 @@ static snd_pcm_uframes_t mtk_afe_pcm_pointer POINTER_RETURN_FRAMES: return bytes_to_frames(substream->runtime, pcm_ptr_bytes); } +EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer); -const struct snd_pcm_ops mtk_afe_pcm_ops = { - .ioctl = snd_pcm_lib_ioctl, - .pointer = mtk_afe_pcm_pointer, -}; -EXPORT_SYMBOL_GPL(mtk_afe_pcm_ops); - -int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) +int mtk_afe_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { size_t size; struct snd_pcm *pcm = rtd->pcm; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); size = afe->mtk_afe_hardware->buffer_bytes_max; @@ -132,17 +126,19 @@ int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) } EXPORT_SYMBOL_GPL(mtk_afe_pcm_new); -void mtk_afe_pcm_free(struct snd_pcm *pcm) +void mtk_afe_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { snd_pcm_lib_preallocate_free_for_all(pcm); } EXPORT_SYMBOL_GPL(mtk_afe_pcm_free); const struct snd_soc_component_driver mtk_afe_pcm_platform = { - .name = AFE_PCM_NAME, - .ops = &mtk_afe_pcm_ops, - .pcm_new = mtk_afe_pcm_new, - .pcm_free = mtk_afe_pcm_free, + .name = AFE_PCM_NAME, + .ioctl = snd_soc_pcm_lib_ioctl, + .pointer = mtk_afe_pcm_pointer, + .pcm_construct = mtk_afe_pcm_new, + .pcm_destruct = mtk_afe_pcm_free, }; EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform); diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h index 88df6797732f..e550d11568c3 100644 --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.h +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h @@ -10,7 +10,6 @@ #define _MTK_AFE_PLATFORM_DRIVER_H_ #define AFE_PCM_NAME "mtk-afe-pcm" -extern const struct snd_pcm_ops mtk_afe_pcm_ops; extern const struct snd_soc_component_driver mtk_afe_pcm_platform; struct mtk_base_afe; @@ -18,9 +17,12 @@ struct snd_pcm; struct snd_soc_component; struct snd_soc_pcm_runtime; - -int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd); -void mtk_afe_pcm_free(struct snd_pcm *pcm); +snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +int mtk_afe_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd); +void mtk_afe_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm); int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe); int mtk_afe_add_sub_dai_control(struct snd_soc_component *component); diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c index e52c032d53aa..033c07fb599c 100644 --- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c @@ -710,11 +710,12 @@ static int mt6797_afe_component_probe(struct snd_soc_component *component) } static const struct snd_soc_component_driver mt6797_afe_component = { - .name = AFE_PCM_NAME, - .ops = &mtk_afe_pcm_ops, - .pcm_new = mtk_afe_pcm_new, - .pcm_free = mtk_afe_pcm_free, - .probe = mt6797_afe_component_probe, + .name = AFE_PCM_NAME, + .probe = mt6797_afe_component_probe, + .ioctl = snd_soc_pcm_lib_ioctl, + .pointer = mtk_afe_pcm_pointer, + .pcm_construct = mtk_afe_pcm_new, + .pcm_destruct = mtk_afe_pcm_free, }; static int mt6797_dai_memif_register(struct mtk_base_afe *afe) diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index 721632386a50..76af09d8f1af 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -1048,11 +1048,12 @@ static int mt8183_afe_component_probe(struct snd_soc_component *component) } static const struct snd_soc_component_driver mt8183_afe_component = { - .name = AFE_PCM_NAME, - .ops = &mtk_afe_pcm_ops, - .pcm_new = mtk_afe_pcm_new, - .pcm_free = mtk_afe_pcm_free, - .probe = mt8183_afe_component_probe, + .name = AFE_PCM_NAME, + .probe = mt8183_afe_component_probe, + .ioctl = snd_soc_pcm_lib_ioctl, + .pointer = mtk_afe_pcm_pointer, + .pcm_construct = mtk_afe_pcm_new, + .pcm_destruct = mtk_afe_pcm_free, }; static int mt8183_dai_memif_register(struct mtk_base_afe *afe) -- cgit From 851f5abfc83d75b9d021887bd7e89c8dd27a9bd4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:10 +0900 Subject: ASoC: kirkwood: kirkwood-dma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87imp790dp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-dma.c | 50 +++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index 6f69f314f2c2..42bbb7ea20b5 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -98,7 +98,8 @@ kirkwood_dma_conf_mbus_windows(void __iomem *base, int win, } } -static int kirkwood_dma_open(struct snd_pcm_substream *substream) +static int kirkwood_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { int err; struct snd_pcm_runtime *runtime = substream->runtime; @@ -160,7 +161,8 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) return 0; } -static int kirkwood_dma_close(struct snd_pcm_substream *substream) +static int kirkwood_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct kirkwood_dma_data *priv = kirkwood_priv(substream); @@ -180,8 +182,9 @@ static int kirkwood_dma_close(struct snd_pcm_substream *substream) return 0; } -static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int kirkwood_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -191,13 +194,15 @@ static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream, return 0; } -static int kirkwood_dma_hw_free(struct snd_pcm_substream *substream) +static int kirkwood_dma_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { snd_pcm_set_runtime_buffer(substream, NULL); return 0; } -static int kirkwood_dma_prepare(struct snd_pcm_substream *substream) +static int kirkwood_dma_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct kirkwood_dma_data *priv = kirkwood_priv(substream); @@ -222,8 +227,9 @@ static int kirkwood_dma_prepare(struct snd_pcm_substream *substream) return 0; } -static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream - *substream) +static snd_pcm_uframes_t kirkwood_dma_pointer( + struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct kirkwood_dma_data *priv = kirkwood_priv(substream); snd_pcm_uframes_t count; @@ -238,16 +244,6 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream return count; } -static const struct snd_pcm_ops kirkwood_dma_ops = { - .open = kirkwood_dma_open, - .close = kirkwood_dma_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = kirkwood_dma_hw_params, - .hw_free = kirkwood_dma_hw_free, - .prepare = kirkwood_dma_prepare, - .pointer = kirkwood_dma_pointer, -}; - static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { @@ -267,7 +263,8 @@ static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm, return 0; } -static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd) +static int kirkwood_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -294,7 +291,8 @@ static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm) +static void kirkwood_dma_free_dma_buffers(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -316,7 +314,13 @@ static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm) const struct snd_soc_component_driver kirkwood_soc_component = { .name = DRV_NAME, - .ops = &kirkwood_dma_ops, - .pcm_new = kirkwood_dma_new, - .pcm_free = kirkwood_dma_free_dma_buffers, + .open = kirkwood_dma_open, + .close = kirkwood_dma_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = kirkwood_dma_hw_params, + .hw_free = kirkwood_dma_hw_free, + .prepare = kirkwood_dma_prepare, + .pointer = kirkwood_dma_pointer, + .pcm_construct = kirkwood_dma_new, + .pcm_destruct = kirkwood_dma_free_dma_buffers, }; -- cgit From dfd00af5e801d42ee5cdbd0e2f486da0e733b1e3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:15 +0900 Subject: ASoC: dwc: dwc-pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h84r90dk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/dwc/dwc-pcm.c | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c index a9ae91c4597f..de6fcc808832 100644 --- a/sound/soc/dwc/dwc-pcm.c +++ b/sound/soc/dwc/dwc-pcm.c @@ -135,7 +135,8 @@ void dw_pcm_pop_rx(struct dw_i2s_dev *dev) dw_pcm_transfer(dev, false); } -static int dw_pcm_open(struct snd_pcm_substream *substream) +static int dw_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -148,14 +149,16 @@ static int dw_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int dw_pcm_close(struct snd_pcm_substream *substream) +static int dw_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { synchronize_rcu(); return 0; } -static int dw_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) +static int dw_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { struct snd_pcm_runtime *runtime = substream->runtime; struct dw_i2s_dev *dev = runtime->private_data; @@ -192,12 +195,14 @@ static int dw_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int dw_pcm_hw_free(struct snd_pcm_substream *substream) +static int dw_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } -static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int dw_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct dw_i2s_dev *dev = runtime->private_data; @@ -231,7 +236,8 @@ static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t dw_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct dw_i2s_dev *dev = runtime->private_data; @@ -245,7 +251,8 @@ static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream) return pos < runtime->buffer_size ? pos : 0; } -static int dw_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int dw_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { size_t size = dw_pcm_hardware.buffer_bytes_max; @@ -255,25 +262,22 @@ static int dw_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static void dw_pcm_free(struct snd_pcm *pcm) +static void dw_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { snd_pcm_lib_preallocate_free_for_all(pcm); } -static const struct snd_pcm_ops dw_pcm_ops = { - .open = dw_pcm_open, - .close = dw_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = dw_pcm_hw_params, - .hw_free = dw_pcm_hw_free, - .trigger = dw_pcm_trigger, - .pointer = dw_pcm_pointer, -}; - static const struct snd_soc_component_driver dw_pcm_component = { - .pcm_new = dw_pcm_new, - .pcm_free = dw_pcm_free, - .ops = &dw_pcm_ops, + .open = dw_pcm_open, + .close = dw_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = dw_pcm_hw_params, + .hw_free = dw_pcm_hw_free, + .trigger = dw_pcm_trigger, + .pointer = dw_pcm_pointer, + .pcm_construct = dw_pcm_new, + .pcm_destruct = dw_pcm_free, }; int dw_pcm_register(struct platform_device *pdev) -- cgit From 85efbc911ed5ae1d458fe3fc05c4d9cfe13836d6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:20 +0900 Subject: ASoC: rt5514-spi: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ftkb90df.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514-spi.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 892ea406a69b..57ff5aee452d 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -201,18 +201,18 @@ static irqreturn_t rt5514_spi_irq(int irq, void *data) } /* PCM for streaming audio from the DSP buffer */ -static int rt5514_spi_pcm_open(struct snd_pcm_substream *substream) +static int rt5514_spi_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { snd_soc_set_runtime_hwparams(substream, &rt5514_spi_pcm_hardware); return 0; } -static int rt5514_spi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) +static int rt5514_spi_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct rt5514_dsp *rt5514_dsp = snd_soc_component_get_drvdata(component); int ret; @@ -234,10 +234,9 @@ static int rt5514_spi_hw_params(struct snd_pcm_substream *substream, return ret; } -static int rt5514_spi_hw_free(struct snd_pcm_substream *substream) +static int rt5514_spi_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct rt5514_dsp *rt5514_dsp = snd_soc_component_get_drvdata(component); @@ -251,24 +250,22 @@ static int rt5514_spi_hw_free(struct snd_pcm_substream *substream) } static snd_pcm_uframes_t rt5514_spi_pcm_pointer( + struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct rt5514_dsp *rt5514_dsp = snd_soc_component_get_drvdata(component); return bytes_to_frames(runtime, rt5514_dsp->dma_offset); } -static const struct snd_pcm_ops rt5514_spi_pcm_ops = { - .open = rt5514_spi_pcm_open, - .hw_params = rt5514_spi_hw_params, - .hw_free = rt5514_spi_hw_free, - .pointer = rt5514_spi_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, -}; +static struct page *rt5514_spi_pcm_page(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned long offset) +{ + return snd_pcm_lib_get_vmalloc_page(substream, offset); +} static int rt5514_spi_pcm_probe(struct snd_soc_component *component) { @@ -302,9 +299,13 @@ static int rt5514_spi_pcm_probe(struct snd_soc_component *component) } static const struct snd_soc_component_driver rt5514_spi_component = { - .name = DRV_NAME, - .probe = rt5514_spi_pcm_probe, - .ops = &rt5514_spi_pcm_ops, + .name = DRV_NAME, + .probe = rt5514_spi_pcm_probe, + .open = rt5514_spi_pcm_open, + .hw_params = rt5514_spi_hw_params, + .hw_free = rt5514_spi_hw_free, + .pointer = rt5514_spi_pcm_pointer, + .page = rt5514_spi_pcm_page, }; /** -- cgit From dc06bd0fc480417784bae62537f287f2d0d70089 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:24 +0900 Subject: ASoC: bcm: cygnus-pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87eezv90db.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/bcm/cygnus-pcm.c | 56 +++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c index 8966b02844dc..c65408085c1d 100644 --- a/sound/soc/bcm/cygnus-pcm.c +++ b/sound/soc/bcm/cygnus-pcm.c @@ -376,7 +376,8 @@ static void disable_intr(struct snd_pcm_substream *substream) } -static int cygnus_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int cygnus_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { int ret = 0; @@ -577,7 +578,8 @@ static irqreturn_t cygnus_dma_irq(int irq, void *data) return IRQ_HANDLED; } -static int cygnus_pcm_open(struct snd_pcm_substream *substream) +static int cygnus_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; @@ -613,7 +615,8 @@ static int cygnus_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int cygnus_pcm_close(struct snd_pcm_substream *substream) +static int cygnus_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct cygnus_aio_port *aio; @@ -633,8 +636,9 @@ static int cygnus_pcm_close(struct snd_pcm_substream *substream) return 0; } -static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int cygnus_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; @@ -649,7 +653,8 @@ static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int cygnus_pcm_hw_free(struct snd_pcm_substream *substream) +static int cygnus_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct cygnus_aio_port *aio; @@ -661,7 +666,8 @@ static int cygnus_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int cygnus_pcm_prepare(struct snd_pcm_substream *substream) +static int cygnus_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; @@ -694,7 +700,8 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct cygnus_aio_port *aio; unsigned int res = 0, cur = 0, base = 0; @@ -750,19 +757,8 @@ static int cygnus_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) return 0; } - -static const struct snd_pcm_ops cygnus_pcm_ops = { - .open = cygnus_pcm_open, - .close = cygnus_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = cygnus_pcm_hw_params, - .hw_free = cygnus_pcm_hw_free, - .prepare = cygnus_pcm_prepare, - .trigger = cygnus_pcm_trigger, - .pointer = cygnus_pcm_pointer, -}; - -static void cygnus_dma_free_dma_buffers(struct snd_pcm *pcm) +static void cygnus_dma_free_dma_buffers(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -788,7 +784,8 @@ static void cygnus_dma_free_dma_buffers(struct snd_pcm *pcm) } } -static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd) +static int cygnus_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -810,7 +807,7 @@ static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd) ret = cygnus_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); if (ret) { - cygnus_dma_free_dma_buffers(pcm); + cygnus_dma_free_dma_buffers(component, pcm); return ret; } } @@ -819,9 +816,16 @@ static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd) } static struct snd_soc_component_driver cygnus_soc_platform = { - .ops = &cygnus_pcm_ops, - .pcm_new = cygnus_dma_new, - .pcm_free = cygnus_dma_free_dma_buffers, + .open = cygnus_pcm_open, + .close = cygnus_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = cygnus_pcm_hw_params, + .hw_free = cygnus_pcm_hw_free, + .prepare = cygnus_pcm_prepare, + .trigger = cygnus_pcm_trigger, + .pointer = cygnus_pcm_pointer, + .pcm_construct = cygnus_dma_new, + .pcm_destruct = cygnus_dma_free_dma_buffers, }; int cygnus_soc_platform_register(struct device *dev, -- cgit From 2adc3fcc4a1f50e614cff67d8de5dcbb4a3b553d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:29 +0900 Subject: ASoC: fsl: imx-pcm-fiq: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87d0ff90d6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-fiq.c | 56 +++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index c49aea4fba56..08131d147983 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -69,8 +69,9 @@ static struct fiq_handler fh = { .name = DRV_NAME, }; -static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int snd_imx_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; @@ -85,7 +86,8 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) +static int snd_imx_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; @@ -104,7 +106,8 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) static int imx_pcm_fiq; -static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int snd_imx_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; @@ -141,7 +144,9 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t +snd_imx_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; @@ -165,7 +170,8 @@ static const struct snd_pcm_hardware snd_imx_hardware = { .fifo_size = 0, }; -static int snd_imx_open(struct snd_pcm_substream *substream) +static int snd_imx_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd; @@ -194,7 +200,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream) return 0; } -static int snd_imx_close(struct snd_pcm_substream *substream) +static int snd_imx_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; @@ -206,8 +213,9 @@ static int snd_imx_close(struct snd_pcm_substream *substream) return 0; } -static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) +static int snd_imx_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; int ret; @@ -222,17 +230,6 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, return ret; } -static const struct snd_pcm_ops imx_pcm_ops = { - .open = snd_imx_open, - .close = snd_imx_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_imx_pcm_hw_params, - .prepare = snd_imx_pcm_prepare, - .trigger = snd_imx_pcm_trigger, - .pointer = snd_imx_pcm_pointer, - .mmap = snd_imx_pcm_mmap, -}; - static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; @@ -279,7 +276,8 @@ static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) static int ssi_irq; -static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd) +static int snd_imx_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; struct snd_pcm_substream *substream; @@ -329,7 +327,8 @@ static void imx_pcm_free(struct snd_pcm *pcm) } } -static void imx_pcm_fiq_free(struct snd_pcm *pcm) +static void snd_imx_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { mxc_set_irq_fiq(ssi_irq, 0); release_fiq(&fh); @@ -337,9 +336,16 @@ static void imx_pcm_fiq_free(struct snd_pcm *pcm) } static const struct snd_soc_component_driver imx_soc_component_fiq = { - .ops = &imx_pcm_ops, - .pcm_new = imx_pcm_fiq_new, - .pcm_free = imx_pcm_fiq_free, + .open = snd_imx_open, + .close = snd_imx_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = snd_imx_pcm_hw_params, + .prepare = snd_imx_pcm_prepare, + .trigger = snd_imx_pcm_trigger, + .pointer = snd_imx_pcm_pointer, + .mmap = snd_imx_pcm_mmap, + .pcm_construct = snd_imx_pcm_new, + .pcm_destruct = snd_imx_pcm_free, }; int imx_pcm_fiq_init(struct platform_device *pdev, -- cgit From 4ac85de9977e7361ef10be23a33313f3cf56e073 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:34 +0900 Subject: ASoC: fsl: fsl_dma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bluz90d1.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_dma.c | 50 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index e22508301412..bc8691a45131 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -280,7 +280,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) * Regardless of where the memory is actually allocated, since the device can * technically DMA to any 36-bit address, we do need to set the DMA mask to 36. */ -static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd) +static int fsl_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -380,11 +381,10 @@ static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd) * buffer, which is what ALSA expects. We're just dividing it into * contiguous parts, and creating a link descriptor for each one. */ -static int fsl_dma_open(struct snd_pcm_substream *substream) +static int fsl_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct device *dev = component->dev; struct dma_object *dma = container_of(component->driver, struct dma_object, dai); @@ -533,13 +533,12 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) * and 8 bytes at a time). So we do not support packed 24-bit samples. * 24-bit data must be padded to 32 bits. */ -static int fsl_dma_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) +static int fsl_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_dma_private *dma_private = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct device *dev = component->dev; /* Number of bits per sample */ @@ -698,12 +697,11 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, * The base address of the buffer is stored in the source_addr field of the * first link descriptor. */ -static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t fsl_dma_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_dma_private *dma_private = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct device *dev = component->dev; struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; dma_addr_t position; @@ -763,7 +761,8 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream) * * This function can be called multiple times. */ -static int fsl_dma_hw_free(struct snd_pcm_substream *substream) +static int fsl_dma_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_dma_private *dma_private = runtime->private_data; @@ -796,12 +795,11 @@ static int fsl_dma_hw_free(struct snd_pcm_substream *substream) /** * fsl_dma_close: close the stream. */ -static int fsl_dma_close(struct snd_pcm_substream *substream) +static int fsl_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_dma_private *dma_private = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct device *dev = component->dev; struct dma_object *dma = container_of(component->driver, struct dma_object, dai); @@ -824,7 +822,8 @@ static int fsl_dma_close(struct snd_pcm_substream *substream) /* * Remove this PCM driver. */ -static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm) +static void fsl_dma_free_dma_buffers(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; unsigned int i; @@ -872,15 +871,6 @@ static struct device_node *find_ssi_node(struct device_node *dma_channel_np) return NULL; } -static const struct snd_pcm_ops fsl_dma_ops = { - .open = fsl_dma_open, - .close = fsl_dma_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = fsl_dma_hw_params, - .hw_free = fsl_dma_hw_free, - .pointer = fsl_dma_pointer, -}; - static int fsl_soc_dma_probe(struct platform_device *pdev) { struct dma_object *dma; @@ -913,8 +903,14 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) dma->dai.name = DRV_NAME; dma->dai.ops = &fsl_dma_ops; - dma->dai.pcm_new = fsl_dma_new; - dma->dai.pcm_free = fsl_dma_free_dma_buffers; + dma->dai.open = fsl_dma_open; + dma->dai.close = fsl_dma_close; + dma->dai.ioctl = snd_soc_pcm_lib_ioctl; + dma->dai.hw_params = fsl_dma_hw_params; + dma->dai.hw_free = fsl_dma_hw_free; + dma->dai.pointer = fsl_dma_pointer; + dma->dai.pcm_construct = fsl_dma_new; + dma->dai.pcm_destruct = fsl_dma_free_dma_buffers; /* Store the SSI-specific information that we need */ dma->ssi_stx_phys = res.start + REG_SSI_STX0; -- cgit From 6d1048bc115259bb2664b8ef363351428a4aef30 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:38 +0900 Subject: ASoC: fsl: mpc5200_dma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a7aj90cx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 51 +++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index ccf9301889fe..5237ac96b756 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -98,7 +98,8 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream) return IRQ_HANDLED; } -static int psc_dma_hw_free(struct snd_pcm_substream *substream) +static int psc_dma_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { snd_pcm_set_runtime_buffer(substream, NULL); return 0; @@ -110,7 +111,8 @@ static int psc_dma_hw_free(struct snd_pcm_substream *substream) * This function is called by ALSA to start, stop, pause, and resume the DMA * transfer of data. */ -static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) +static int psc_dma_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); @@ -210,7 +212,8 @@ static const struct snd_pcm_hardware psc_dma_hardware = { .fifo_size = 512, }; -static int psc_dma_open(struct snd_pcm_substream *substream) +static int psc_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -238,7 +241,8 @@ static int psc_dma_open(struct snd_pcm_substream *substream) return 0; } -static int psc_dma_close(struct snd_pcm_substream *substream) +static int psc_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); @@ -263,7 +267,8 @@ static int psc_dma_close(struct snd_pcm_substream *substream) } static snd_pcm_uframes_t -psc_dma_pointer(struct snd_pcm_substream *substream) +psc_dma_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); @@ -280,29 +285,19 @@ psc_dma_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(substream->runtime, count); } -static int -psc_dma_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int psc_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); return 0; } -static const struct snd_pcm_ops psc_dma_ops = { - .open = psc_dma_open, - .close = psc_dma_close, - .hw_free = psc_dma_hw_free, - .ioctl = snd_pcm_lib_ioctl, - .pointer = psc_dma_pointer, - .trigger = psc_dma_trigger, - .hw_params = psc_dma_hw_params, -}; - -static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) +static int psc_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_pcm *pcm = rtd->pcm; size_t size = psc_dma_hardware.buffer_bytes_max; @@ -341,10 +336,10 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) return -ENOMEM; } -static void psc_dma_free(struct snd_pcm *pcm) +static void psc_dma_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *rtd = pcm->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_pcm_substream *substream; int stream; @@ -362,9 +357,15 @@ static void psc_dma_free(struct snd_pcm *pcm) static const struct snd_soc_component_driver mpc5200_audio_dma_component = { .name = DRV_NAME, - .ops = &psc_dma_ops, - .pcm_new = &psc_dma_new, - .pcm_free = &psc_dma_free, + .open = psc_dma_open, + .close = psc_dma_close, + .hw_free = psc_dma_hw_free, + .ioctl = snd_soc_pcm_lib_ioctl, + .pointer = psc_dma_pointer, + .trigger = psc_dma_trigger, + .hw_params = psc_dma_hw_params, + .pcm_construct = psc_dma_new, + .pcm_destruct = psc_dma_free, }; int mpc5200_audio_dma_create(struct platform_device *op) -- cgit From 8903ed25e9fdf6cfd02a3a16db69e500803e16b9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:43 +0900 Subject: ASoC: fsl: fsl_asrc_dma: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878sq390cs.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc_dma.c | 56 +++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 2a60fc6142b1..d6146de9acd2 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -52,13 +52,12 @@ static void fsl_asrc_dma_complete(void *arg) snd_pcm_period_elapsed(substream); } -static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream) +static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream, + struct snd_soc_component *component) { u8 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? OUT : IN; - struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct device *dev = component->dev; unsigned long flags = DMA_CTRL_ACK; @@ -95,7 +94,8 @@ static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream) return 0; } -static int fsl_asrc_dma_trigger(struct snd_pcm_substream *substream, int cmd) +static int fsl_asrc_dma_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; @@ -105,7 +105,7 @@ static int fsl_asrc_dma_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = fsl_asrc_dma_prepare_and_submit(substream); + ret = fsl_asrc_dma_prepare_and_submit(substream, component); if (ret) return ret; dma_async_issue_pending(pair->dma_chan[IN]); @@ -124,7 +124,8 @@ static int fsl_asrc_dma_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, +static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; @@ -132,7 +133,6 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL; struct snd_dmaengine_dai_dma_data *dma_params_be = NULL; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; struct fsl_asrc *asrc_priv = pair->asrc_priv; @@ -247,7 +247,8 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, return 0; } -static int fsl_asrc_dma_hw_free(struct snd_pcm_substream *substream) +static int fsl_asrc_dma_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; @@ -266,12 +267,12 @@ static int fsl_asrc_dma_hw_free(struct snd_pcm_substream *substream) return 0; } -static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream) +static int fsl_asrc_dma_startup(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_dmaengine_dai_dma_data *dma_data; struct device *dev = component->dev; struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); @@ -342,7 +343,8 @@ req_pair_err: return ret; } -static int fsl_asrc_dma_shutdown(struct snd_pcm_substream *substream) +static int fsl_asrc_dma_shutdown(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; @@ -361,7 +363,9 @@ static int fsl_asrc_dma_shutdown(struct snd_pcm_substream *substream) return 0; } -static snd_pcm_uframes_t fsl_asrc_dma_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t +fsl_asrc_dma_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; @@ -369,17 +373,8 @@ static snd_pcm_uframes_t fsl_asrc_dma_pcm_pointer(struct snd_pcm_substream *subs return bytes_to_frames(substream->runtime, pair->pos); } -static const struct snd_pcm_ops fsl_asrc_dma_pcm_ops = { - .ioctl = snd_pcm_lib_ioctl, - .hw_params = fsl_asrc_dma_hw_params, - .hw_free = fsl_asrc_dma_hw_free, - .trigger = fsl_asrc_dma_trigger, - .open = fsl_asrc_dma_startup, - .close = fsl_asrc_dma_shutdown, - .pointer = fsl_asrc_dma_pcm_pointer, -}; - -static int fsl_asrc_dma_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int fsl_asrc_dma_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm_substream *substream; @@ -414,7 +409,8 @@ err: return ret; } -static void fsl_asrc_dma_pcm_free(struct snd_pcm *pcm) +static void fsl_asrc_dma_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) { struct snd_pcm_substream *substream; int i; @@ -432,8 +428,14 @@ static void fsl_asrc_dma_pcm_free(struct snd_pcm *pcm) struct snd_soc_component_driver fsl_asrc_component = { .name = DRV_NAME, - .ops = &fsl_asrc_dma_pcm_ops, - .pcm_new = fsl_asrc_dma_pcm_new, - .pcm_free = fsl_asrc_dma_pcm_free, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = fsl_asrc_dma_hw_params, + .hw_free = fsl_asrc_dma_hw_free, + .trigger = fsl_asrc_dma_trigger, + .open = fsl_asrc_dma_startup, + .close = fsl_asrc_dma_shutdown, + .pointer = fsl_asrc_dma_pcm_pointer, + .pcm_construct = fsl_asrc_dma_pcm_new, + .pcm_destruct = fsl_asrc_dma_pcm_free, }; EXPORT_SYMBOL_GPL(fsl_asrc_component); -- cgit From a21192a7daf45f14120d6976b64efc3234499de7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:34:48 +0900 Subject: ASoC: fsl: fsl_dma: don't use snd_soc_rtdcom_lookup() snd_soc_rtdcom_lookup() will be removed. It is used at fsl_dma_isr(), but it is just for dev_err(dev..). rtd->dev is very enough for it. This patch replace component->dev to rtd->dev Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/877e5n90cn.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index bc8691a45131..a092726510d4 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -201,8 +201,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) struct fsl_dma_private *dma_private = dev_id; struct snd_pcm_substream *substream = dma_private->substream; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct device *dev = component->dev; + struct device *dev = rtd->dev; struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; irqreturn_t ret = IRQ_NONE; u32 sr, sr2 = 0; -- cgit From ece23171ea95c4fe9395c1c861af0c1bd50ad9e5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:35:00 +0900 Subject: ASoC: soc-generic-dmaengine-pcm: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875zl790cb.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-generic-dmaengine-pcm.c | 102 +++++++++++++++++----------------- 1 file changed, 51 insertions(+), 51 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index f2c98a9cbf75..f4c755209e03 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -75,12 +75,10 @@ int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_prepare_slave_config); -static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int dmaengine_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME); struct dmaengine_pcm *pcm = soc_component_to_pcm(component); struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); int (*prepare_slave_config)(struct snd_pcm_substream *substream, @@ -109,11 +107,11 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } -static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substream) +static int +dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME); struct dmaengine_pcm *pcm = soc_component_to_pcm(component); struct device *dma_dev = dmaengine_dma_dev(pcm, substream); struct dma_chan *chan = pcm->chan[substream->stream]; @@ -150,28 +148,43 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea return snd_soc_set_runtime_hwparams(substream, &hw); } -static int dmaengine_pcm_open(struct snd_pcm_substream *substream) +static int dmaengine_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME); struct dmaengine_pcm *pcm = soc_component_to_pcm(component); struct dma_chan *chan = pcm->chan[substream->stream]; int ret; - ret = dmaengine_pcm_set_runtime_hwparams(substream); + ret = dmaengine_pcm_set_runtime_hwparams(component, substream); if (ret) return ret; return snd_dmaengine_pcm_open(substream, chan); } +static int dmaengine_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return snd_dmaengine_pcm_close(substream); +} + +static int dmaengine_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int dmaengine_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + return snd_dmaengine_pcm_trigger(substream, cmd); +} + static struct dma_chan *dmaengine_pcm_compat_request_channel( + struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd, struct snd_pcm_substream *substream) { - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME); struct dmaengine_pcm *pcm = soc_component_to_pcm(component); struct snd_dmaengine_dai_dma_data *dma_data; dma_filter_fn fn = NULL; @@ -209,10 +222,9 @@ static bool dmaengine_pcm_can_report_residue(struct device *dev, return true; } -static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int dmaengine_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME); struct dmaengine_pcm *pcm = soc_component_to_pcm(component); const struct snd_dmaengine_pcm_config *config = pcm->config; struct device *dev = component->dev; @@ -239,8 +251,8 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) config->chan_names[i]); if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { - pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, - substream); + pcm->chan[i] = dmaengine_pcm_compat_request_channel( + component, rtd, substream); } if (!pcm->chan[i]) { @@ -269,11 +281,9 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) } static snd_pcm_uframes_t dmaengine_pcm_pointer( + struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME); struct dmaengine_pcm *pcm = soc_component_to_pcm(component); if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) @@ -282,13 +292,11 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer( return snd_dmaengine_pcm_pointer(substream); } -static int dmaengine_copy_user(struct snd_pcm_substream *substream, +static int dmaengine_copy_user(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int channel, unsigned long hwoff, void __user *buf, unsigned long bytes) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME); struct snd_pcm_runtime *runtime = substream->runtime; struct dmaengine_pcm *pcm = soc_component_to_pcm(component); int (*process)(struct snd_pcm_substream *substream, @@ -316,39 +324,31 @@ static int dmaengine_copy_user(struct snd_pcm_substream *substream, return 0; } -static const struct snd_pcm_ops dmaengine_pcm_ops = { +static const struct snd_soc_component_driver dmaengine_pcm_component = { + .name = SND_DMAENGINE_PCM_DRV_NAME, + .probe_order = SND_SOC_COMP_ORDER_LATE, .open = dmaengine_pcm_open, - .close = snd_dmaengine_pcm_close, - .ioctl = snd_pcm_lib_ioctl, + .close = dmaengine_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, .hw_params = dmaengine_pcm_hw_params, - .hw_free = snd_pcm_lib_free_pages, - .trigger = snd_dmaengine_pcm_trigger, + .hw_free = dmaengine_pcm_hw_free, + .trigger = dmaengine_pcm_trigger, .pointer = dmaengine_pcm_pointer, + .pcm_construct = dmaengine_pcm_new, }; -static const struct snd_pcm_ops dmaengine_pcm_process_ops = { +static const struct snd_soc_component_driver dmaengine_pcm_component_process = { + .name = SND_DMAENGINE_PCM_DRV_NAME, + .probe_order = SND_SOC_COMP_ORDER_LATE, .open = dmaengine_pcm_open, - .close = snd_dmaengine_pcm_close, - .ioctl = snd_pcm_lib_ioctl, + .close = dmaengine_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, .hw_params = dmaengine_pcm_hw_params, - .hw_free = snd_pcm_lib_free_pages, - .trigger = snd_dmaengine_pcm_trigger, + .hw_free = dmaengine_pcm_hw_free, + .trigger = dmaengine_pcm_trigger, .pointer = dmaengine_pcm_pointer, .copy_user = dmaengine_copy_user, -}; - -static const struct snd_soc_component_driver dmaengine_pcm_component = { - .name = SND_DMAENGINE_PCM_DRV_NAME, - .probe_order = SND_SOC_COMP_ORDER_LATE, - .ops = &dmaengine_pcm_ops, - .pcm_new = dmaengine_pcm_new, -}; - -static const struct snd_soc_component_driver dmaengine_pcm_component_process = { - .name = SND_DMAENGINE_PCM_DRV_NAME, - .probe_order = SND_SOC_COMP_ORDER_LATE, - .ops = &dmaengine_pcm_process_ops, - .pcm_new = dmaengine_pcm_new, + .pcm_construct = dmaengine_pcm_new, }; static const char * const dmaengine_pcm_dma_channel_names[] = { -- cgit From a49e460f847f54600fb1fdae63765eb54ae659cc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:35:05 +0900 Subject: ASoC: soc-utils: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874l0r90c6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-utils.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 54dcece52b0c..2fd4562f5e63 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -63,7 +63,8 @@ static const struct snd_pcm_hardware dummy_dma_hardware = { .periods_max = 128, }; -static int dummy_dma_open(struct snd_pcm_substream *substream) +static int dummy_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -74,13 +75,9 @@ static int dummy_dma_open(struct snd_pcm_substream *substream) return 0; } -static const struct snd_pcm_ops snd_dummy_dma_ops = { - .open = dummy_dma_open, - .ioctl = snd_pcm_lib_ioctl, -}; - static const struct snd_soc_component_driver dummy_platform = { - .ops = &snd_dummy_dma_ops, + .open = dummy_dma_open, + .ioctl = snd_soc_pcm_lib_ioctl, }; static const struct snd_soc_component_driver dummy_codec = { -- cgit From e9067bb502787869dabe385727baff233024097b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:35:13 +0900 Subject: ASoC: soc-component: remove snd_pcm_ops from component driver No driver is using snd_pcm_ops on component driver. This patch removes it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8736gb90by.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-component.c | 77 ----------------------------------------------- sound/soc/soc-pcm.c | 10 ++---- 2 files changed, 3 insertions(+), 84 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index d2b052ac88cd..debaf1f6f403 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -316,12 +316,6 @@ int snd_soc_component_open(struct snd_soc_component *component, { if (component->driver->open) return component->driver->open(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->open) - return component->driver->ops->open(substream); - return 0; } @@ -330,12 +324,6 @@ int snd_soc_component_close(struct snd_soc_component *component, { if (component->driver->close) return component->driver->close(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->close) - return component->driver->ops->close(substream); - return 0; } @@ -344,12 +332,6 @@ int snd_soc_component_prepare(struct snd_soc_component *component, { if (component->driver->prepare) return component->driver->prepare(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->prepare) - return component->driver->ops->prepare(substream); - return 0; } @@ -360,12 +342,6 @@ int snd_soc_component_hw_params(struct snd_soc_component *component, if (component->driver->hw_params) return component->driver->hw_params(component, substream, params); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->hw_params) - return component->driver->ops->hw_params(substream, params); - return 0; } @@ -374,12 +350,6 @@ int snd_soc_component_hw_free(struct snd_soc_component *component, { if (component->driver->hw_free) return component->driver->hw_free(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->hw_free) - return component->driver->ops->hw_free(substream); - return 0; } @@ -389,12 +359,6 @@ int snd_soc_component_trigger(struct snd_soc_component *component, { if (component->driver->trigger) return component->driver->trigger(component, substream, cmd); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->trigger) - return component->driver->ops->trigger(substream, cmd); - return 0; } @@ -462,11 +426,6 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) /* FIXME: use 1st pointer */ if (component->driver->pointer) return component->driver->pointer(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->pointer) - return component->driver->ops->pointer(substream); } return 0; @@ -486,12 +445,6 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, if (component->driver->ioctl) return component->driver->ioctl(component, substream, cmd, arg); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->ioctl) - return component->driver->ops->ioctl(substream, - cmd, arg); } return snd_pcm_lib_ioctl(substream, cmd, arg); @@ -512,12 +465,6 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, if (component->driver->copy_user) return component->driver->copy_user( component, substream, channel, pos, buf, bytes); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->copy_user) - return component->driver->ops->copy_user( - substream, channel, pos, buf, bytes); } return -EINVAL; @@ -541,14 +488,6 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, if (page) return page; } - - /* remove me */ - if (component->driver->ops && - component->driver->ops->page) { - page = component->driver->ops->page(substream, offset); - if (page) - return page; - } } return NULL; @@ -568,11 +507,6 @@ int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, if (component->driver->mmap) return component->driver->mmap(component, substream, vma); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->mmap) - return component->driver->ops->mmap(substream, vma); } return -EINVAL; @@ -593,13 +527,6 @@ int snd_soc_pcm_component_new(struct snd_pcm *pcm) if (ret < 0) return ret; } - - /* remove me */ - if (component->driver->pcm_new) { - ret = component->driver->pcm_new(rtd); - if (ret < 0) - return ret; - } } return 0; @@ -616,9 +543,5 @@ void snd_soc_pcm_component_free(struct snd_pcm *pcm) if (component->driver->pcm_destruct) component->driver->pcm_destruct(component, pcm); - - /* remove me */ - if (component->driver->pcm_free) - component->driver->pcm_free(pcm); } } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index dbf67d8a5411..f462947a5d27 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2988,16 +2988,12 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) for_each_rtdcom(rtd, rtdcom) { const struct snd_soc_component_driver *drv = rtdcom->component->driver; - const struct snd_pcm_ops *ops = drv->ops; - if (!ops) - continue; - - if (ops->copy_user || drv->copy_user) + if (drv->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; - if (ops->page || drv->page) + if (drv->page) rtd->ops.page = snd_soc_pcm_component_page; - if (ops->mmap || drv->mmap) + if (drv->mmap) rtd->ops.mmap = snd_soc_pcm_component_mmap; } -- cgit From ad4abed36433a4fc18d21c0f0eaede84006f219f Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Oct 2019 16:52:12 -0700 Subject: ASoC: jz4740: Remove unused match variable After commit 67ad656bdd70 ("ASoC: jz4740: Use of_device_get_match_data()"), the match local variable is unused and the compiler rightly warns. sound/soc/jz4740/jz4740-i2s.c: In function 'jz4740_i2s_dev_probe': sound/soc/jz4740/jz4740-i2s.c:500:29: warning: unused variable 'match' [-Wunused-variable] 500 | const struct of_device_id *match; Drop it. Reported-by: Stephen Rothwell Cc: Arnd Bergmann Cc: Geert Uytterhoeven Cc: Paul Cercueil Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Rob Herring Cc: Frank Rowand Cc: Fixes: 67ad656bdd70 ("ASoC: jz4740: Use of_device_get_match_data()") Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20191008235212.228856-1-swboyd@chromium.org Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index d2dab4d24b87..38d48d101783 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -497,7 +497,6 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) struct jz4740_i2s *i2s; struct resource *mem; int ret; - const struct of_device_id *match; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); if (!i2s) -- cgit From ca514c0f12b02a4df32f45ebff056130ee76b202 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Thu, 10 Oct 2019 09:42:33 +0200 Subject: ASOC: Add ADAU7118 8 Channel PDM-to-I2S/TDM Converter driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the 8 channel PDM-to-I2S/TDM converter. The ADAU7118 converts four stereo pulse density modulation (PDM) bitstreams into one pulse code modulation (PCM) output stream. The source for the PDM data can be eight microphones or other PDM sources. The PCM audio data is output on a serial audio interface port in either inter-IC serial (I2S) or time domain multiplexed (TDM) format. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20191010074234.7344-1-nuno.sa@analog.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 28 ++ sound/soc/codecs/Makefile | 6 + sound/soc/codecs/adau7118-hw.c | 43 +++ sound/soc/codecs/adau7118-i2c.c | 82 ++++++ sound/soc/codecs/adau7118.c | 586 ++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/adau7118.h | 24 ++ 6 files changed, 769 insertions(+) create mode 100644 sound/soc/codecs/adau7118-hw.c create mode 100644 sound/soc/codecs/adau7118-i2c.c create mode 100644 sound/soc/codecs/adau7118.c create mode 100644 sound/soc/codecs/adau7118.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bcac95785493..ae213c6392ec 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -34,6 +34,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_ADAU1977_I2C if I2C select SND_SOC_ADAU1701 if I2C select SND_SOC_ADAU7002 + select SND_SOC_ADAU7118_I2C if I2C + select SND_SOC_ADAU7118_HW select SND_SOC_ADS117X select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4118 if I2C @@ -396,6 +398,32 @@ config SND_SOC_ADAU1977_I2C config SND_SOC_ADAU7002 tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter" +config SND_SOC_ADAU7118 + tristate + +config SND_SOC_ADAU7118_HW + tristate "Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM Converter - HW Mode" + select SND_SOC_ADAU7118 + help + Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM + Converter. In this mode, the device works in standalone mode which + means that there is no bus to comunicate with it. Stereo mode is not + supported in this mode. + + To compile this driver as a module, choose M here: the module + will be called snd-soc-adau7118-hw. + +config SND_SOC_ADAU7118_I2C + tristate "Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM Converter - I2C" + select SND_SOC_ADAU7118 + select REGMAP_I2C + help + Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM + Converter over I2C. This gives full support over the device. + + To compile this driver as a module, choose M here: the module + will be called snd-soc-adau7118-i2c. + config SND_SOC_ADAV80X tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 73b2d5982dcb..2118407a1dd5 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -22,6 +22,9 @@ snd-soc-adau1977-objs := adau1977.o snd-soc-adau1977-spi-objs := adau1977-spi.o snd-soc-adau1977-i2c-objs := adau1977-i2c.o snd-soc-adau7002-objs := adau7002.o +snd-soc-adau7118-objs := adau7118.o +snd-soc-adau7118-i2c-objs := adau7118-i2c.o +snd-soc-adau7118-hw-objs := adau7118-hw.o snd-soc-adav80x-objs := adav80x.o snd-soc-adav801-objs := adav801.o snd-soc-adav803-objs := adav803.o @@ -305,6 +308,9 @@ obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o obj-$(CONFIG_SND_SOC_ADAU7002) += snd-soc-adau7002.o +obj-$(CONFIG_SND_SOC_ADAU7118) += snd-soc-adau7118.o +obj-$(CONFIG_SND_SOC_ADAU7118_I2C) += snd-soc-adau7118-i2c.o +obj-$(CONFIG_SND_SOC_ADAU7118_HW) += snd-soc-adau7118-hw.o obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o diff --git a/sound/soc/codecs/adau7118-hw.c b/sound/soc/codecs/adau7118-hw.c new file mode 100644 index 000000000000..45a5d2dcc0f2 --- /dev/null +++ b/sound/soc/codecs/adau7118-hw.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter Standalone Hw +// driver +// +// Copyright 2019 Analog Devices Inc. + +#include +#include +#include + +#include "adau7118.h" + +static int adau7118_probe_hw(struct platform_device *pdev) +{ + return adau7118_probe(&pdev->dev, NULL, true); +} + +static const struct of_device_id adau7118_of_match[] = { + { .compatible = "adi,adau7118" }, + {} +}; +MODULE_DEVICE_TABLE(of, adau7118_of_match); + +static const struct platform_device_id adau7118_id[] = { + { .name = "adau7118" }, + { } +}; +MODULE_DEVICE_TABLE(platform, adau7118_id); + +static struct platform_driver adau7118_driver_hw = { + .driver = { + .name = "adau7118", + .of_match_table = adau7118_of_match, + }, + .probe = adau7118_probe_hw, + .id_table = adau7118_id, +}; +module_platform_driver(adau7118_driver_hw); + +MODULE_AUTHOR("Nuno Sa "); +MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver for standalone hw mode"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c new file mode 100644 index 000000000000..a8211362fe82 --- /dev/null +++ b/sound/soc/codecs/adau7118-i2c.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver over I2C +// +// Copyright 2019 Analog Devices Inc. + +#include +#include +#include + +#include "adau7118.h" + +static const struct reg_default adau7118_reg_defaults[] = { + { ADAU7118_REG_VENDOR_ID, 0x41 }, + { ADAU7118_REG_DEVICE_ID1, 0x71 }, + { ADAU7118_REG_DEVICE_ID2, 0x18 }, + { ADAU7118_REG_REVISION_ID, 0x00 }, + { ADAU7118_REG_ENABLES, 0x3F }, + { ADAU7118_REG_DEC_RATIO_CLK_MAP, 0xC0 }, + { ADAU7118_REG_HPF_CONTROL, 0xD0 }, + { ADAU7118_REG_SPT_CTRL1, 0x41 }, + { ADAU7118_REG_SPT_CTRL2, 0x00 }, + { ADAU7118_REG_SPT_CX(0), 0x01 }, + { ADAU7118_REG_SPT_CX(1), 0x11 }, + { ADAU7118_REG_SPT_CX(2), 0x21 }, + { ADAU7118_REG_SPT_CX(3), 0x31 }, + { ADAU7118_REG_SPT_CX(4), 0x41 }, + { ADAU7118_REG_SPT_CX(5), 0x51 }, + { ADAU7118_REG_SPT_CX(6), 0x61 }, + { ADAU7118_REG_SPT_CX(7), 0x71 }, + { ADAU7118_REG_DRIVE_STRENGTH, 0x2a }, + { ADAU7118_REG_RESET, 0x00 }, +}; + +static const struct regmap_config adau7118_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .reg_defaults = adau7118_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(adau7118_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .max_register = ADAU7118_REG_RESET, +}; + +static int adau7118_probe_i2c(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regmap *map; + + map = devm_regmap_init_i2c(i2c, &adau7118_regmap_config); + if (IS_ERR(map)) { + dev_err(&i2c->dev, "Failed to init regmap %ld\n", PTR_ERR(map)); + return PTR_ERR(map); + } + + return adau7118_probe(&i2c->dev, map, false); +} + +static const struct of_device_id adau7118_of_match[] = { + { .compatible = "adi,adau7118" }, + {} +}; +MODULE_DEVICE_TABLE(of, adau7118_of_match); + +static const struct i2c_device_id adau7118_id[] = { + {"adau7118", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, adau7118_id); + +static struct i2c_driver adau7118_driver = { + .driver = { + .name = "adau7118", + .of_match_table = adau7118_of_match, + }, + .probe = adau7118_probe_i2c, + .id_table = adau7118_id, +}; +module_i2c_driver(adau7118_driver); + +MODULE_AUTHOR("Nuno Sa "); +MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver over I2C"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c new file mode 100644 index 000000000000..bf5a5d75f81a --- /dev/null +++ b/sound/soc/codecs/adau7118.c @@ -0,0 +1,586 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver +// +// Copyright 2019 Analog Devices Inc. + +#include +#include +#include +#include +#include +#include + +#include "adau7118.h" + +#define ADAU7118_DEC_RATIO_MASK GENMASK(1, 0) +#define ADAU7118_DEC_RATIO(x) FIELD_PREP(ADAU7118_DEC_RATIO_MASK, x) +#define ADAU7118_CLK_MAP_MASK GENMASK(7, 4) +#define ADAU7118_SLOT_WIDTH_MASK GENMASK(5, 4) +#define ADAU7118_SLOT_WIDTH(x) FIELD_PREP(ADAU7118_SLOT_WIDTH_MASK, x) +#define ADAU7118_TRISTATE_MASK BIT(6) +#define ADAU7118_TRISTATE(x) FIELD_PREP(ADAU7118_TRISTATE_MASK, x) +#define ADAU7118_DATA_FMT_MASK GENMASK(3, 1) +#define ADAU7118_DATA_FMT(x) FIELD_PREP(ADAU7118_DATA_FMT_MASK, x) +#define ADAU7118_SAI_MODE_MASK BIT(0) +#define ADAU7118_SAI_MODE(x) FIELD_PREP(ADAU7118_SAI_MODE_MASK, x) +#define ADAU7118_LRCLK_BCLK_POL_MASK GENMASK(1, 0) +#define ADAU7118_LRCLK_BCLK_POL(x) \ + FIELD_PREP(ADAU7118_LRCLK_BCLK_POL_MASK, x) +#define ADAU7118_SPT_SLOT_MASK GENMASK(7, 4) +#define ADAU7118_SPT_SLOT(x) FIELD_PREP(ADAU7118_SPT_SLOT_MASK, x) +#define ADAU7118_FULL_SOFT_R_MASK BIT(1) +#define ADAU7118_FULL_SOFT_R(x) FIELD_PREP(ADAU7118_FULL_SOFT_R_MASK, x) + +struct adau7118_data { + struct regmap *map; + struct device *dev; + struct regulator *iovdd; + struct regulator *dvdd; + u32 slot_width; + u32 slots; + bool hw_mode; + bool right_j; +}; + +/* Input Enable */ +static const struct snd_kcontrol_new adau7118_dapm_pdm_control[4] = { + SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 0, 1, 0), + SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 1, 1, 0), + SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 2, 1, 0), + SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 3, 1, 0), +}; + +static const struct snd_soc_dapm_widget adau7118_widgets_sw[] = { + /* Input Enable Switches */ + SND_SOC_DAPM_SWITCH("PDM0", SND_SOC_NOPM, 0, 0, + &adau7118_dapm_pdm_control[0]), + SND_SOC_DAPM_SWITCH("PDM1", SND_SOC_NOPM, 0, 0, + &adau7118_dapm_pdm_control[1]), + SND_SOC_DAPM_SWITCH("PDM2", SND_SOC_NOPM, 0, 0, + &adau7118_dapm_pdm_control[2]), + SND_SOC_DAPM_SWITCH("PDM3", SND_SOC_NOPM, 0, 0, + &adau7118_dapm_pdm_control[3]), + + /* PDM Clocks */ + SND_SOC_DAPM_SUPPLY("PDM_CLK0", ADAU7118_REG_ENABLES, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PDM_CLK1", ADAU7118_REG_ENABLES, 5, 0, NULL, 0), + + /* Output channels */ + SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, ADAU7118_REG_SPT_CX(0), + 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 0, ADAU7118_REG_SPT_CX(1), + 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 0, ADAU7118_REG_SPT_CX(2), + 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 0, ADAU7118_REG_SPT_CX(3), + 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 0, ADAU7118_REG_SPT_CX(4), + 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 0, ADAU7118_REG_SPT_CX(5), + 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX7", "Capture", 0, ADAU7118_REG_SPT_CX(6), + 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX8", "Capture", 0, ADAU7118_REG_SPT_CX(7), + 0, 0), +}; + +static const struct snd_soc_dapm_route adau7118_routes_sw[] = { + { "PDM0", "Capture Switch", "PDM_DAT0" }, + { "PDM1", "Capture Switch", "PDM_DAT1" }, + { "PDM2", "Capture Switch", "PDM_DAT2" }, + { "PDM3", "Capture Switch", "PDM_DAT3" }, + { "AIF1TX1", NULL, "PDM0" }, + { "AIF1TX2", NULL, "PDM0" }, + { "AIF1TX3", NULL, "PDM1" }, + { "AIF1TX4", NULL, "PDM1" }, + { "AIF1TX5", NULL, "PDM2" }, + { "AIF1TX6", NULL, "PDM2" }, + { "AIF1TX7", NULL, "PDM3" }, + { "AIF1TX8", NULL, "PDM3" }, + { "Capture", NULL, "PDM_CLK0" }, + { "Capture", NULL, "PDM_CLK1" }, +}; + +static const struct snd_soc_dapm_widget adau7118_widgets_hw[] = { + SND_SOC_DAPM_AIF_OUT("AIF1TX", "Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route adau7118_routes_hw[] = { + { "AIF1TX", NULL, "PDM_DAT0" }, + { "AIF1TX", NULL, "PDM_DAT1" }, + { "AIF1TX", NULL, "PDM_DAT2" }, + { "AIF1TX", NULL, "PDM_DAT3" }, +}; + +static const struct snd_soc_dapm_widget adau7118_widgets[] = { + SND_SOC_DAPM_INPUT("PDM_DAT0"), + SND_SOC_DAPM_INPUT("PDM_DAT1"), + SND_SOC_DAPM_INPUT("PDM_DAT2"), + SND_SOC_DAPM_INPUT("PDM_DAT3"), +}; + +static int adau7118_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct adau7118_data *st = + snd_soc_component_get_drvdata(dai->component); + int chan, ret; + + dev_dbg(st->dev, "Set channel map, %d", tx_num); + + for (chan = 0; chan < tx_num; chan++) { + ret = snd_soc_component_update_bits(dai->component, + ADAU7118_REG_SPT_CX(chan), + ADAU7118_SPT_SLOT_MASK, + ADAU7118_SPT_SLOT(tx_slot[chan])); + if (ret < 0) + return ret; + } + + return 0; +} + +static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct adau7118_data *st = + snd_soc_component_get_drvdata(dai->component); + int ret = 0; + u32 regval; + + dev_dbg(st->dev, "Set format, fmt:%d\n", fmt); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ret = snd_soc_component_update_bits(dai->component, + ADAU7118_REG_SPT_CTRL1, + ADAU7118_DATA_FMT_MASK, + ADAU7118_DATA_FMT(0)); + break; + case SND_SOC_DAIFMT_LEFT_J: + ret = snd_soc_component_update_bits(dai->component, + ADAU7118_REG_SPT_CTRL1, + ADAU7118_DATA_FMT_MASK, + ADAU7118_DATA_FMT(1)); + break; + case SND_SOC_DAIFMT_RIGHT_J: + st->right_j = true; + break; + default: + dev_err(st->dev, "Invalid format %d", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + if (ret < 0) + return ret; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + regval = ADAU7118_LRCLK_BCLK_POL(0); + break; + case SND_SOC_DAIFMT_NB_IF: + regval = ADAU7118_LRCLK_BCLK_POL(2); + break; + case SND_SOC_DAIFMT_IB_NF: + regval = ADAU7118_LRCLK_BCLK_POL(1); + break; + case SND_SOC_DAIFMT_IB_IF: + regval = ADAU7118_LRCLK_BCLK_POL(3); + break; + default: + dev_err(st->dev, "Invalid Inv mask %d", + fmt & SND_SOC_DAIFMT_INV_MASK); + return -EINVAL; + } + + ret = snd_soc_component_update_bits(dai->component, + ADAU7118_REG_SPT_CTRL2, + ADAU7118_LRCLK_BCLK_POL_MASK, + regval); + if (ret < 0) + return ret; + + return 0; +} + +static int adau7118_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct adau7118_data *st = + snd_soc_component_get_drvdata(dai->component); + int ret; + + dev_dbg(st->dev, "Set tristate, %d\n", tristate); + + ret = snd_soc_component_update_bits(dai->component, + ADAU7118_REG_SPT_CTRL1, + ADAU7118_TRISTATE_MASK, + ADAU7118_TRISTATE(tristate)); + if (ret < 0) + return ret; + + return 0; +} + +static int adau7118_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, + int slot_width) +{ + struct adau7118_data *st = + snd_soc_component_get_drvdata(dai->component); + int ret = 0; + u32 regval; + + dev_dbg(st->dev, "Set tdm, slots:%d width:%d\n", slots, slot_width); + + switch (slot_width) { + case 32: + regval = ADAU7118_SLOT_WIDTH(0); + break; + case 24: + regval = ADAU7118_SLOT_WIDTH(2); + break; + case 16: + regval = ADAU7118_SLOT_WIDTH(1); + break; + default: + dev_err(st->dev, "Invalid slot width:%d\n", slot_width); + return -EINVAL; + } + + ret = snd_soc_component_update_bits(dai->component, + ADAU7118_REG_SPT_CTRL1, + ADAU7118_SLOT_WIDTH_MASK, regval); + if (ret < 0) + return ret; + + st->slot_width = slot_width; + st->slots = slots; + + return 0; +} + +static int adau7118_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct adau7118_data *st = + snd_soc_component_get_drvdata(dai->component); + u32 data_width = params_width(params), slots_width; + int ret; + u32 regval; + + if (!st->slots) { + /* set stereo mode */ + ret = snd_soc_component_update_bits(dai->component, + ADAU7118_REG_SPT_CTRL1, + ADAU7118_SAI_MODE_MASK, + ADAU7118_SAI_MODE(0)); + if (ret < 0) + return ret; + + slots_width = 32; + } else { + slots_width = st->slot_width; + } + + if (data_width > slots_width) { + dev_err(st->dev, "Invalid data_width:%d, slots_width:%d", + data_width, slots_width); + return -EINVAL; + } + + if (st->right_j) { + switch (slots_width - data_width) { + case 8: + /* delay bclck by 8 */ + regval = ADAU7118_DATA_FMT(2); + break; + case 12: + /* delay bclck by 12 */ + regval = ADAU7118_DATA_FMT(3); + break; + case 16: + /* delay bclck by 16 */ + regval = ADAU7118_DATA_FMT(4); + break; + default: + dev_err(st->dev, + "Cannot set right_j setting, slot_w:%d, data_w:%d\n", + slots_width, data_width); + return -EINVAL; + } + + ret = snd_soc_component_update_bits(dai->component, + ADAU7118_REG_SPT_CTRL1, + ADAU7118_DATA_FMT_MASK, + regval); + if (ret < 0) + return ret; + } + + return 0; +} + +static int adau7118_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct adau7118_data *st = snd_soc_component_get_drvdata(component); + int ret = 0; + + dev_dbg(st->dev, "Set bias level %d\n", level); + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + + case SND_SOC_BIAS_STANDBY: + if (snd_soc_component_get_bias_level(component) == + SND_SOC_BIAS_OFF) { + /* power on */ + ret = regulator_enable(st->iovdd); + if (ret) + return ret; + + /* there's no timing constraints before enabling dvdd */ + ret = regulator_enable(st->dvdd); + if (ret) { + regulator_disable(st->iovdd); + return ret; + } + + if (st->hw_mode) + return 0; + + regcache_cache_only(st->map, false); + /* sync cache */ + ret = snd_soc_component_cache_sync(component); + } + break; + case SND_SOC_BIAS_OFF: + /* power off */ + ret = regulator_disable(st->dvdd); + if (ret) + return ret; + + ret = regulator_disable(st->iovdd); + if (ret) + return ret; + + if (st->hw_mode) + return 0; + + /* cache only */ + regcache_mark_dirty(st->map); + regcache_cache_only(st->map, true); + + break; + } + + return ret; +} + +static int adau7118_component_probe(struct snd_soc_component *component) +{ + struct adau7118_data *st = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret = 0; + + if (st->hw_mode) { + ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_hw, + ARRAY_SIZE(adau7118_widgets_hw)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_hw, + ARRAY_SIZE(adau7118_routes_hw)); + } else { + snd_soc_component_init_regmap(component, st->map); + ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_sw, + ARRAY_SIZE(adau7118_widgets_sw)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_sw, + ARRAY_SIZE(adau7118_routes_sw)); + } + + return ret; +} + +static const struct snd_soc_dai_ops adau7118_ops = { + .hw_params = adau7118_hw_params, + .set_channel_map = adau7118_set_channel_map, + .set_fmt = adau7118_set_fmt, + .set_tdm_slot = adau7118_set_tdm_slot, + .set_tristate = adau7118_set_tristate, +}; + +static struct snd_soc_dai_driver adau7118_dai = { + .name = "adau7118-hifi-capture", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 8, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 4000, + .rate_max = 192000, + .sig_bits = 24, + }, +}; + +static const struct snd_soc_component_driver adau7118_component_driver = { + .probe = adau7118_component_probe, + .set_bias_level = adau7118_set_bias_level, + .dapm_widgets = adau7118_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau7118_widgets), + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static void adau7118_regulator_disable(void *data) +{ + struct adau7118_data *st = data; + int ret; + /* + * If we fail to disable DVDD, don't bother in trying IOVDD. We + * actually don't want to be left in the situation where DVDD + * is enabled and IOVDD is disabled. + */ + ret = regulator_disable(st->dvdd); + if (ret) + return; + + regulator_disable(st->iovdd); +} + +static int adau7118_regulator_setup(struct adau7118_data *st) +{ + st->iovdd = devm_regulator_get(st->dev, "IOVDD"); + if (IS_ERR(st->iovdd)) { + dev_err(st->dev, "Could not get iovdd: %ld\n", + PTR_ERR(st->iovdd)); + return PTR_ERR(st->iovdd); + } + + st->dvdd = devm_regulator_get(st->dev, "DVDD"); + if (IS_ERR(st->dvdd)) { + dev_err(st->dev, "Could not get dvdd: %ld\n", + PTR_ERR(st->dvdd)); + return PTR_ERR(st->dvdd); + } + /* just assume the device is in reset */ + if (!st->hw_mode) { + regcache_mark_dirty(st->map); + regcache_cache_only(st->map, true); + } + + return devm_add_action_or_reset(st->dev, adau7118_regulator_disable, + st); +} + +static int adau7118_parset_dt(const struct adau7118_data *st) +{ + int ret; + u32 dec_ratio = 0; + /* 4 inputs */ + u32 clk_map[4], regval; + + if (st->hw_mode) + return 0; + + ret = device_property_read_u32(st->dev, "adi,decimation-ratio", + &dec_ratio); + if (!ret) { + switch (dec_ratio) { + case 64: + regval = ADAU7118_DEC_RATIO(0); + break; + case 32: + regval = ADAU7118_DEC_RATIO(1); + break; + case 16: + regval = ADAU7118_DEC_RATIO(2); + break; + default: + dev_err(st->dev, "Invalid dec ratio: %u", dec_ratio); + return -EINVAL; + } + + ret = regmap_update_bits(st->map, + ADAU7118_REG_DEC_RATIO_CLK_MAP, + ADAU7118_DEC_RATIO_MASK, regval); + if (ret) + return ret; + } + + ret = device_property_read_u32_array(st->dev, "adi,pdm-clk-map", + clk_map, ARRAY_SIZE(clk_map)); + if (!ret) { + int pdm; + u32 _clk_map = 0; + + for (pdm = 0; pdm < ARRAY_SIZE(clk_map); pdm++) + _clk_map |= (clk_map[pdm] << (pdm + 4)); + + ret = regmap_update_bits(st->map, + ADAU7118_REG_DEC_RATIO_CLK_MAP, + ADAU7118_CLK_MAP_MASK, _clk_map); + if (ret) + return ret; + } + + return 0; +} + +int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode) +{ + struct adau7118_data *st; + int ret; + + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + st->dev = dev; + st->hw_mode = hw_mode; + dev_set_drvdata(dev, st); + + if (!hw_mode) { + st->map = map; + adau7118_dai.ops = &adau7118_ops; + /* + * Perform a full soft reset. This will set all register's + * with their reset values. + */ + ret = regmap_update_bits(map, ADAU7118_REG_RESET, + ADAU7118_FULL_SOFT_R_MASK, + ADAU7118_FULL_SOFT_R(1)); + if (ret) + return ret; + } + + ret = adau7118_parset_dt(st); + if (ret) + return ret; + + ret = adau7118_regulator_setup(st); + if (ret) + return ret; + + return devm_snd_soc_register_component(dev, + &adau7118_component_driver, + &adau7118_dai, 1); +} +EXPORT_SYMBOL_GPL(adau7118_probe); + +MODULE_AUTHOR("Nuno Sa "); +MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau7118.h b/sound/soc/codecs/adau7118.h new file mode 100644 index 000000000000..c65679a4dff1 --- /dev/null +++ b/sound/soc/codecs/adau7118.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_ADAU7118_H +#define _LINUX_ADAU7118_H + +struct regmap; +struct device; + +/* register map */ +#define ADAU7118_REG_VENDOR_ID 0x00 +#define ADAU7118_REG_DEVICE_ID1 0x01 +#define ADAU7118_REG_DEVICE_ID2 0x02 +#define ADAU7118_REG_REVISION_ID 0x03 +#define ADAU7118_REG_ENABLES 0x04 +#define ADAU7118_REG_DEC_RATIO_CLK_MAP 0x05 +#define ADAU7118_REG_HPF_CONTROL 0x06 +#define ADAU7118_REG_SPT_CTRL1 0x07 +#define ADAU7118_REG_SPT_CTRL2 0x08 +#define ADAU7118_REG_SPT_CX(num) (0x09 + (num)) +#define ADAU7118_REG_DRIVE_STRENGTH 0x11 +#define ADAU7118_REG_RESET 0x12 + +int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode); + +#endif -- cgit From f3416e7144f5d4ba0fc5dcef6ebfff891266c46a Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 8 Oct 2019 11:44:35 -0500 Subject: ASoC: SOF: enable sync_write in hdac_bus Align SOF HDA implementation with snd-hda-intel driver and enable sync_write flag for all supported Intel platforms in SOF. When set, a sync is issued after each verb write. Sync after write has helped to overcome intermittent delays in system resume flow on Intel Coffee Lake systems, and most recently probe errors related to the HDMI codec on Ice Lake systems. Matches the snd-hda-intel driver change done in commit 2756d9143aa5 ("ALSA: hda - Fix intermittent CORB/RIRB stall on Intel chips"). Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 06e84679087b..5a5163eef2ef 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -268,6 +268,7 @@ static int hda_init(struct snd_sof_dev *sdev) bus->use_posbuf = 1; bus->bdl_pos_adj = 0; + bus->sync_write = 1; mutex_init(&hbus->prepare_mutex); hbus->pci = pci; -- cgit From a68c6b6cc77b841dc37c17a5d9a7074e26801af5 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 8 Oct 2019 11:44:41 -0500 Subject: ASoC: SOF: enable dual control for pga Currently sof pga element supports only 1 kcontrol and you can't create for example a mixer element with combined volume slider and mute switch. So enable sof pga to have more than 1 kcontrol associated with it. Also check for possible NULL tlv pointer as switch element might not have it. Signed-off-by: Jaska Uimonen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 0aabb3190ddc..a0b1c38e666b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1580,7 +1580,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, if (!volume) return -ENOMEM; - if (le32_to_cpu(tw->num_kcontrols) != 1) { + if (!le32_to_cpu(tw->num_kcontrols)) { dev_err(sdev->dev, "error: invalid kcontrol count %d for volume\n", tw->num_kcontrols); ret = -EINVAL; @@ -1617,7 +1617,8 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, swidget->private = volume; list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { - if (scontrol->comp_id == swidget->comp_id) { + if (scontrol->comp_id == swidget->comp_id && + scontrol->volume_table) { min_step = scontrol->min_volume_step; max_step = scontrol->max_volume_step; volume->min_value = scontrol->volume_table[min_step]; -- cgit From acf1b71cb693263c7c9373296e872a8fa61a5cf3 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 8 Oct 2019 11:44:42 -0500 Subject: AsoC: SOF: refactor control load code Move code around to enable token parsing in control load. Signed-off-by: Jaska Uimonen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 314 +++++++++++++++++++++++------------------------ 1 file changed, 157 insertions(+), 157 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a0b1c38e666b..3918301c573b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -432,163 +432,6 @@ static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type) return SOF_COMP_NONE; } -/* - * Standard Kcontrols. - */ - -static int sof_control_load_volume(struct snd_soc_component *scomp, - struct snd_sof_control *scontrol, - struct snd_kcontrol_new *kc, - struct snd_soc_tplg_ctl_hdr *hdr) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_mixer_control *mc = - container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); - struct sof_ipc_ctrl_data *cdata; - int tlv[TLV_ITEMS]; - unsigned int i; - int ret; - - /* validate topology data */ - if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) - return -EINVAL; - - /* init the volume get/put data */ - scontrol->size = struct_size(scontrol->control_data, chanv, - le32_to_cpu(mc->num_channels)); - scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); - if (!scontrol->control_data) - return -ENOMEM; - - scontrol->comp_id = sdev->next_comp_id; - scontrol->min_volume_step = le32_to_cpu(mc->min); - scontrol->max_volume_step = le32_to_cpu(mc->max); - scontrol->num_channels = le32_to_cpu(mc->num_channels); - - /* set cmd for mixer control */ - if (le32_to_cpu(mc->max) == 1) { - scontrol->cmd = SOF_CTRL_CMD_SWITCH; - goto out; - } - - scontrol->cmd = SOF_CTRL_CMD_VOLUME; - - /* extract tlv data */ - if (get_tlv_data(kc->tlv.p, tlv) < 0) { - dev_err(sdev->dev, "error: invalid TLV data\n"); - return -EINVAL; - } - - /* set up volume table */ - ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); - if (ret < 0) { - dev_err(sdev->dev, "error: setting up volume table\n"); - return ret; - } - - /* set default volume values to 0dB in control */ - cdata = scontrol->control_data; - for (i = 0; i < scontrol->num_channels; i++) { - cdata->chanv[i].channel = i; - cdata->chanv[i].value = VOL_ZERO_DB; - } - -out: - dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", - scontrol->comp_id, scontrol->num_channels); - - return 0; -} - -static int sof_control_load_enum(struct snd_soc_component *scomp, - struct snd_sof_control *scontrol, - struct snd_kcontrol_new *kc, - struct snd_soc_tplg_ctl_hdr *hdr) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_enum_control *ec = - container_of(hdr, struct snd_soc_tplg_enum_control, hdr); - - /* validate topology data */ - if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN) - return -EINVAL; - - /* init the enum get/put data */ - scontrol->size = struct_size(scontrol->control_data, chanv, - le32_to_cpu(ec->num_channels)); - scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); - if (!scontrol->control_data) - return -ENOMEM; - - scontrol->comp_id = sdev->next_comp_id; - scontrol->num_channels = le32_to_cpu(ec->num_channels); - - scontrol->cmd = SOF_CTRL_CMD_ENUM; - - dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", - scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); - - return 0; -} - -static int sof_control_load_bytes(struct snd_soc_component *scomp, - struct snd_sof_control *scontrol, - struct snd_kcontrol_new *kc, - struct snd_soc_tplg_ctl_hdr *hdr) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc_ctrl_data *cdata; - struct snd_soc_tplg_bytes_control *control = - container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); - struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; - int max_size = sbe->max; - - if (le32_to_cpu(control->priv.size) > max_size) { - dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", - control->priv.size, max_size); - return -EINVAL; - } - - /* init the get/put bytes data */ - scontrol->size = sizeof(struct sof_ipc_ctrl_data) + - le32_to_cpu(control->priv.size); - scontrol->control_data = kzalloc(max_size, GFP_KERNEL); - cdata = scontrol->control_data; - if (!scontrol->control_data) - return -ENOMEM; - - scontrol->comp_id = sdev->next_comp_id; - scontrol->cmd = SOF_CTRL_CMD_BINARY; - - dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", - scontrol->comp_id, scontrol->num_channels); - - if (le32_to_cpu(control->priv.size) > 0) { - memcpy(cdata->data, control->priv.data, - le32_to_cpu(control->priv.size)); - - if (cdata->data->magic != SOF_ABI_MAGIC) { - dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", - cdata->data->magic); - return -EINVAL; - } - if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, - cdata->data->abi)) { - dev_err(sdev->dev, - "error: Incompatible ABI version 0x%08x.\n", - cdata->data->abi); - return -EINVAL; - } - if (cdata->data->size + sizeof(const struct sof_abi_hdr) != - le32_to_cpu(control->priv.size)) { - dev_err(sdev->dev, - "error: Conflict in bytes vs. priv size.\n"); - return -EINVAL; - } - } - return 0; -} - /* * Topology Token Parsing. * New tokens should be added to headers and parsing tables below. @@ -1039,6 +882,163 @@ static void sof_dbg_comp_config(struct snd_soc_component *scomp, config->frame_fmt); } +/* + * Standard Kcontrols. + */ + +static int sof_control_load_volume(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_mixer_control *mc = + container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); + struct sof_ipc_ctrl_data *cdata; + int tlv[TLV_ITEMS]; + unsigned int i; + int ret; + + /* validate topology data */ + if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + /* init the volume get/put data */ + scontrol->size = struct_size(scontrol->control_data, chanv, + le32_to_cpu(mc->num_channels)); + scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->min_volume_step = le32_to_cpu(mc->min); + scontrol->max_volume_step = le32_to_cpu(mc->max); + scontrol->num_channels = le32_to_cpu(mc->num_channels); + + /* set cmd for mixer control */ + if (le32_to_cpu(mc->max) == 1) { + scontrol->cmd = SOF_CTRL_CMD_SWITCH; + goto out; + } + + scontrol->cmd = SOF_CTRL_CMD_VOLUME; + + /* extract tlv data */ + if (get_tlv_data(kc->tlv.p, tlv) < 0) { + dev_err(sdev->dev, "error: invalid TLV data\n"); + return -EINVAL; + } + + /* set up volume table */ + ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); + if (ret < 0) { + dev_err(sdev->dev, "error: setting up volume table\n"); + return ret; + } + + /* set default volume values to 0dB in control */ + cdata = scontrol->control_data; + for (i = 0; i < scontrol->num_channels; i++) { + cdata->chanv[i].channel = i; + cdata->chanv[i].value = VOL_ZERO_DB; + } + +out: + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + scontrol->comp_id, scontrol->num_channels); + + return 0; +} + +static int sof_control_load_enum(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_enum_control *ec = + container_of(hdr, struct snd_soc_tplg_enum_control, hdr); + + /* validate topology data */ + if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + /* init the enum get/put data */ + scontrol->size = struct_size(scontrol->control_data, chanv, + le32_to_cpu(ec->num_channels)); + scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->num_channels = le32_to_cpu(ec->num_channels); + + scontrol->cmd = SOF_CTRL_CMD_ENUM; + + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", + scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); + + return 0; +} + +static int sof_control_load_bytes(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_ctrl_data *cdata; + struct snd_soc_tplg_bytes_control *control = + container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); + struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; + int max_size = sbe->max; + + if (le32_to_cpu(control->priv.size) > max_size) { + dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", + control->priv.size, max_size); + return -EINVAL; + } + + /* init the get/put bytes data */ + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + le32_to_cpu(control->priv.size); + scontrol->control_data = kzalloc(max_size, GFP_KERNEL); + cdata = scontrol->control_data; + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->cmd = SOF_CTRL_CMD_BINARY; + + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + scontrol->comp_id, scontrol->num_channels); + + if (le32_to_cpu(control->priv.size) > 0) { + memcpy(cdata->data, control->priv.data, + le32_to_cpu(control->priv.size)); + + if (cdata->data->magic != SOF_ABI_MAGIC) { + dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", + cdata->data->magic); + return -EINVAL; + } + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, + cdata->data->abi)) { + dev_err(sdev->dev, + "error: Incompatible ABI version 0x%08x.\n", + cdata->data->abi); + return -EINVAL; + } + if (cdata->data->size + sizeof(const struct sof_abi_hdr) != + le32_to_cpu(control->priv.size)) { + dev_err(sdev->dev, + "error: Conflict in bytes vs. priv size.\n"); + return -EINVAL; + } + } + return 0; +} + /* external kcontrol init - used for any driver specific init */ static int sof_control_load(struct snd_soc_component *scomp, int index, struct snd_kcontrol_new *kc, -- cgit From 902fd492d5ea2c02666ddadc1da977ca94e6b52c Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 8 Oct 2019 11:44:36 -0500 Subject: Revert "ASoC: SOF: Force polling mode on CFL and CNL" This reverts commit 64ca9d9fcb3e3c86b1417e3d17a90b43dd660f81. The workaround is no longer needed after configuring HDAC bus with sync_write=1. Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 5a5163eef2ef..103f4273c4d3 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -32,9 +32,6 @@ /* platform specific devices */ #include "shim.h" -#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) -#define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8) - #define EXCEPT_MAX_HDR_SIZE 0x400 /* @@ -262,10 +259,6 @@ static int hda_init(struct snd_sof_dev *sdev) /* HDA bus init */ sof_hda_bus_init(bus, &pci->dev); - /* Workaround for a communication error on CFL (bko#199007) and CNL */ - if (IS_CFL(pci) || IS_CNL(pci)) - bus->polling_mode = 1; - bus->use_posbuf = 1; bus->bdl_pos_adj = 0; bus->sync_write = 1; -- cgit From 70b0c75ae1e3d35f829b5fe7ae5692efae63ca71 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 8 Oct 2019 11:44:37 -0500 Subject: ASoC: SOF: acpi: add debug module param Add debug parameter for snd-sof-acpi. One of the usages for this debug parameter to disable pm_runtime, which can be useful for platform bringup, or keep the parent device active while enabling pm_runtime for child devices (e.g. with SoundWire or MFD). This can also be useful to measure suspend-resume latencies or child devices. Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-acpi-dev.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index ea7b8b895412..df318f50dd0b 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -29,6 +29,12 @@ static char *tplg_path; module_param(tplg_path, charp, 0444); MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +static int sof_acpi_debug; +module_param_named(sof_acpi_debug, sof_acpi_debug, int, 0444); +MODULE_PARM_DESC(sof_acpi_debug, "SOF ACPI debug options (0x0 all off)"); + +#define SOF_ACPI_DISABLE_PM_RUNTIME BIT(0) + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) static const struct sof_dev_desc sof_acpi_haswell_desc = { .machines = snd_soc_acpi_intel_haswell_machines, @@ -121,6 +127,9 @@ static const struct dev_pm_ops sof_acpi_pm = { static void sof_acpi_probe_complete(struct device *dev) { + if (sof_acpi_debug & SOF_ACPI_DISABLE_PM_RUNTIME) + return; + /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(dev); @@ -221,7 +230,8 @@ static int sof_acpi_probe(struct platform_device *pdev) static int sof_acpi_remove(struct platform_device *pdev) { - pm_runtime_disable(&pdev->dev); + if (!(sof_acpi_debug & SOF_ACPI_DISABLE_PM_RUNTIME)) + pm_runtime_disable(&pdev->dev); /* call sof helper for DSP hardware remove */ snd_sof_device_remove(&pdev->dev); -- cgit From 8b160dc2a92c83a566b0596c79febb5933f9a6b5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 8 Oct 2019 11:44:38 -0500 Subject: ASoC: SOF: pci: add debug module param Add debug parameter for snd-sof-pci. One of the usages for this debug parameter to disable pm_runtime, which can be useful for platform bringup, or keep the parent device active while enabling pm_runtime for child devices (e.g. with SoundWire or MFD). This can also be useful to measure suspend-resume latencies or child devices. Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index d66412a77873..030f2cb06921 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -29,6 +29,12 @@ static char *tplg_path; module_param(tplg_path, charp, 0444); MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +static int sof_pci_debug; +module_param_named(sof_pci_debug, sof_pci_debug, int, 0444); +MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)"); + +#define SOF_PCI_DISABLE_PM_RUNTIME BIT(0) + #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) static const struct sof_dev_desc bxt_desc = { .machines = snd_soc_acpi_intel_bxt_machines, @@ -249,6 +255,9 @@ static void sof_pci_probe_complete(struct device *dev) { dev_dbg(dev, "Completing SOF PCI probe"); + if (sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME) + return; + /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(dev); @@ -370,7 +379,8 @@ static void sof_pci_remove(struct pci_dev *pci) snd_sof_device_remove(&pci->dev); /* follow recommendation in pci-driver.c to increment usage counter */ - pm_runtime_get_noresume(&pci->dev); + if (!(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)) + pm_runtime_get_noresume(&pci->dev); /* release pci regions and disable device */ pci_release_regions(pci); -- cgit From 5d43001ae43606dc525f55c482c545afba01bb55 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 8 Oct 2019 11:44:43 -0500 Subject: ASoC: SOF: acpi led support for switch controls Currently sof doesn't support acpi leds with mute switches. So implement acpi leds following quite shamelessly existing HDA implementation by Takashi Iwai. Mute leds can be enabled in topology by adding led and direction token in switch control private data. Signed-off-by: Jaska Uimonen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 9 +++++++++ sound/soc/sof/topology.c | 13 +++++++++++++ 3 files changed, 54 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index a4983f90ff5b..41551e8f6ac3 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -11,8 +11,37 @@ /* Mixer Controls */ #include +#include #include "sof-priv.h" +static void update_mute_led(struct snd_sof_control *scontrol, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int temp = 0; + unsigned int mask; + int i; + + mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + for (i = 0; i < scontrol->num_channels; i++) { + if (ucontrol->value.integer.value[i]) { + temp |= mask; + break; + } + } + + if (temp == scontrol->led_ctl.led_value) + return; + + scontrol->led_ctl.led_value = temp; + + if (!scontrol->led_ctl.direction) + ledtrig_audio_set(LED_AUDIO_MUTE, temp ? LED_OFF : LED_ON); + else + ledtrig_audio_set(LED_AUDIO_MICMUTE, temp ? LED_OFF : LED_ON); +} + static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) { if (value >= size) @@ -112,6 +141,9 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, cdata->chanv[i].channel = i; } + if (scontrol->led_ctl.use_led) + update_mute_led(scontrol, kcontrol, ucontrol); + /* notify DSP of mixer updates */ if (pm_runtime_active(sdev->dev)) snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 44f789bf7fb0..5a11a8517fa5 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -15,6 +15,7 @@ #include #include +#include #include #include /* needs to be included before control.h */ @@ -310,6 +311,12 @@ struct snd_sof_pcm { bool prepared[2]; /* PCM_PARAMS set successfully */ }; +struct snd_sof_led_control { + unsigned int use_led; + unsigned int direction; + unsigned int led_value; +}; + /* ALSA SOF Kcontrol device */ struct snd_sof_control { struct snd_sof_dev *sdev; @@ -324,6 +331,8 @@ struct snd_sof_control { u32 *volume_table; /* volume table computed from tlv data*/ struct list_head list; /* list in sdev control list */ + + struct snd_sof_led_control led_ctl; }; /* ASoC SOF DAPM widget */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 3918301c573b..2e5fab1cfbb4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -682,6 +682,14 @@ static const struct sof_topology_token dmic_pdm_tokens[] = { static const struct sof_topology_token hda_tokens[] = { }; +/* Leds */ +static const struct sof_topology_token led_tokens[] = { + {SOF_TKN_MUTE_LED_USE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct snd_sof_led_control, use_led), 0}, + {SOF_TKN_MUTE_LED_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, offsetof(struct snd_sof_led_control, direction), 0}, +}; + static void sof_parse_uuid_tokens(struct snd_soc_component *scomp, void *object, const struct sof_topology_token *tokens, @@ -944,6 +952,11 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, } out: + /* set up possible led control from mixer private data */ + ret = sof_parse_tokens(scomp, &scontrol->led_ctl, led_tokens, + ARRAY_SIZE(led_tokens), mc->priv.array, + le32_to_cpu(mc->priv.size)); + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); -- cgit From a4eff5f86c9c5e7d07d880bd86ce8faad19d7063 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 8 Oct 2019 11:44:40 -0500 Subject: ASoC: SOF: imx: Read ESAI parameters and send them to DSP ESAI parameters are read for topology file, packed into sof_ipc_dai_esai_parms struct and then sent to DSP. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 8 ++++++ sound/soc/sof/topology.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 6490b1577152..d72798d2b302 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -682,6 +682,14 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, case SOF_DAI_INTEL_ALH: /* do nothing for ALH dai_link */ break; + case SOF_DAI_IMX_ESAI: + channels->min = dai->dai_config->esai.tdm_slots; + channels->max = dai->dai_config->esai.tdm_slots; + + dev_dbg(sdev->dev, + "channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", dai->dai_config->type); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 2e5fab1cfbb4..a29109ea3c06 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -641,6 +641,13 @@ static const struct sof_topology_token dmic_tokens[] = { }; +/* ESAI */ +static const struct sof_topology_token esai_tokens[] = { + {SOF_TKN_IMX_ESAI_MCLK_ID, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_esai_params, mclk_id), 0}, +}; + /* * DMIC PDM Tokens * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token @@ -2549,8 +2556,66 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_hw_config *hw_config, struct sof_ipc_dai_config *config) { - /*TODO: Add implementation */ - return 0; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->esai, 0, sizeof(struct sof_ipc_dai_esai_params)); + config->hdr.size = size; + + ret = sof_parse_tokens(scomp, &config->esai, esai_tokens, + ARRAY_SIZE(esai_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse esai tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate); + config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate); + config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->esai.mclk_direction = hw_config->mclk_direction; + config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); + config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots); + config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots); + + dev_info(sdev->dev, + "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n", + config->dai_index, config->format, + config->esai.mclk_rate, config->esai.tdm_slot_width, + config->esai.tdm_slots, config->esai.mclk_id); + + if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) { + dev_err(sdev->dev, "error: invalid channel count for ESAI%d\n", + config->dai_index); + return -EINVAL; + } + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for ESAI%d\n", + config->dai_index); + return ret; + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(sdev->dev, "error: failed to save DAI config for ESAI%d\n", + config->dai_index); + + return ret; } static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, -- cgit From c173dba44c2d2ec2adaa4e607e9729b74236bd57 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Tue, 8 Oct 2019 13:15:17 -0500 Subject: ASoC: tas2562: Introduce the TAS2562 amplifier Introduce the Texas Instruments TAS2562 amplifier driver with I/V sense for loud speaker applications. http://www.ti.com/lit/gpn/tas2562 Signed-off-by: Dan Murphy Link: https://lore.kernel.org/r/20191008181517.5332-2-dmurphy@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas2562.c | 590 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas2562.h | 85 +++++++ 4 files changed, 682 insertions(+) create mode 100644 sound/soc/codecs/tas2562.c create mode 100644 sound/soc/codecs/tas2562.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index ae213c6392ec..f4747ebc251e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -181,6 +181,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_STI_SAS select SND_SOC_TAS2552 if I2C + select SND_SOC_TAS2562 if I2C select SND_SOC_TAS2770 if I2C select SND_SOC_TAS5086 if I2C select SND_SOC_TAS571X if I2C @@ -1133,6 +1134,10 @@ config SND_SOC_TAS2552 tristate "Texas Instruments TAS2552 Mono Audio amplifier" depends on I2C +config SND_SOC_TAS2562 + tristate "Texas Instruments TAS2562 Mono Audio amplifier" + depends on I2C + config SND_SOC_TAS2770 tristate "Texas Instruments TAS2770 speaker amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 2118407a1dd5..ddfd07071925 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -284,6 +284,7 @@ snd-soc-max98504-objs := max98504.o snd-soc-simple-amplifier-objs := simple-amplifier.o snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-tas2552-objs := tas2552.o +snd-soc-tas2562-objs := tas2562.o obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o @@ -481,6 +482,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o +obj-$(CONFIG_SND_SOC_TAS2562) += snd-soc-tas2562.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c new file mode 100644 index 000000000000..729acd874c48 --- /dev/null +++ b/sound/soc/codecs/tas2562.c @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Driver for the Texas Instruments TAS2562 CODEC +// Copyright (C) 2019 Texas Instruments Inc. + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "tas2562.h" + +#define TAS2562_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FORMAT_S32_LE) + +struct tas2562_data { + struct snd_soc_component *component; + struct gpio_desc *sdz_gpio; + struct regmap *regmap; + struct device *dev; + struct i2c_client *client; + int v_sense_slot; + int i_sense_slot; +}; + +static int tas2562_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct tas2562_data *tas2562 = + snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_ON: + snd_soc_component_update_bits(component, + TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, TAS2562_ACTIVE); + break; + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_PREPARE: + snd_soc_component_update_bits(component, + TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, TAS2562_MUTE); + break; + case SND_SOC_BIAS_OFF: + snd_soc_component_update_bits(component, + TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, TAS2562_SHUTDOWN); + break; + + default: + dev_err(tas2562->dev, + "wrong power level setting %d\n", level); + return -EINVAL; + } + + return 0; +} + +static int tas2562_set_samplerate(struct tas2562_data *tas2562, int samplerate) +{ + int samp_rate; + int ramp_rate; + + switch (samplerate) { + case 7350: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ; + break; + case 8000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ; + break; + case 14700: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ; + break; + case 16000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ; + break; + case 22050: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ; + break; + case 24000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ; + break; + case 29400: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ; + break; + case 32000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ; + break; + case 44100: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ; + break; + case 48000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ; + break; + case 88200: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ; + break; + case 96000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ; + break; + case 176400: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ; + break; + case 192000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ; + break; + default: + dev_info(tas2562->dev, "%s, unsupported sample rate, %d\n", + __func__, samplerate); + return -EINVAL; + } + + snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0, + TAS2562_TDM_CFG0_RAMPRATE_MASK, ramp_rate); + snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0, + TAS2562_TDM_CFG0_SAMPRATE_MASK, samp_rate); + + return 0; +} + +static int tas2562_set_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + int ret = 0; + + switch (slot_width) { + case 16: + ret = snd_soc_component_update_bits(component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXLEN_MASK, + TAS2562_TDM_CFG2_RXLEN_16B); + break; + case 24: + ret = snd_soc_component_update_bits(component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXLEN_MASK, + TAS2562_TDM_CFG2_RXLEN_24B); + break; + case 32: + ret = snd_soc_component_update_bits(component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXLEN_MASK, + TAS2562_TDM_CFG2_RXLEN_32B); + break; + + case 0: + /* Do not change slot width */ + break; + default: + dev_err(tas2562->dev, "slot width not supported"); + ret = -EINVAL; + } + + if (ret < 0) + return ret; + + return 0; +} + +static int tas2562_set_bitwidth(struct tas2562_data *tas2562, int bitwidth) +{ + int ret; + + switch (bitwidth) { + case SNDRV_PCM_FORMAT_S16_LE: + snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXWLEN_MASK, + TAS2562_TDM_CFG2_RXWLEN_16B); + tas2562->v_sense_slot = tas2562->i_sense_slot + 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXWLEN_MASK, + TAS2562_TDM_CFG2_RXWLEN_24B); + tas2562->v_sense_slot = tas2562->i_sense_slot + 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXWLEN_MASK, + TAS2562_TDM_CFG2_RXWLEN_32B); + tas2562->v_sense_slot = tas2562->i_sense_slot + 4; + break; + + default: + dev_info(tas2562->dev, "Not supported params format\n"); + } + + ret = snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG5, + TAS2562_TDM_CFG5_VSNS_EN | TAS2562_TDM_CFG5_VSNS_SLOT_MASK, + TAS2562_TDM_CFG5_VSNS_EN | tas2562->v_sense_slot); + if (ret < 0) + return ret; + + ret = snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG6, + TAS2562_TDM_CFG6_ISNS_EN | TAS2562_TDM_CFG6_ISNS_SLOT_MASK, + TAS2562_TDM_CFG6_ISNS_EN | tas2562->i_sense_slot); + if (ret < 0) + return ret; + + return 0; +} + +static int tas2562_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + int ret; + + ret = tas2562_set_bitwidth(tas2562, params_format(params)); + if (ret) { + dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret); + return ret; + } + + ret = tas2562_set_samplerate(tas2562, params_rate(params)); + if (ret) + dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret); + + return ret; +} + +static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; + int ret; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + asi_cfg_1 = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + asi_cfg_1 |= TAS2562_TDM_CFG1_RX_FALLING; + break; + default: + dev_err(tas2562->dev, "ASI format Inverse is not found\n"); + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1, + TAS2562_TDM_CFG1_RX_EDGE_MASK, + asi_cfg_1); + if (ret < 0) { + dev_err(tas2562->dev, "Failed to set RX edge\n"); + return ret; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case (SND_SOC_DAIFMT_I2S): + case (SND_SOC_DAIFMT_DSP_A): + case (SND_SOC_DAIFMT_DSP_B): + tdm_rx_start_slot = BIT(1); + break; + case (SND_SOC_DAIFMT_LEFT_J): + tdm_rx_start_slot = 0; + break; + default: + dev_err(tas2562->dev, "DAI Format is not found, fmt=0x%x\n", + fmt); + ret = -EINVAL; + break; + } + + ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1, + TAS2562_TDM_CFG1_RX_OFFSET_MASK, + tdm_rx_start_slot); + + if (ret < 0) + return ret; + + return 0; +} + +static int tas2562_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + + return snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, + mute ? TAS2562_MUTE : 0); +} + +static int tas2562_codec_probe(struct snd_soc_component *component) +{ + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + int ret; + + tas2562->component = component; + + if (tas2562->sdz_gpio) + gpiod_set_value_cansleep(tas2562->sdz_gpio, 1); + + ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, TAS2562_MUTE); + if (ret < 0) + return ret; + + return 0; +} + +#ifdef CONFIG_PM +static int tas2562_suspend(struct snd_soc_component *component) +{ + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(tas2562->regmap, true); + regcache_mark_dirty(tas2562->regmap); + + if (tas2562->sdz_gpio) + gpiod_set_value_cansleep(tas2562->sdz_gpio, 0); + + return 0; +} + +static int tas2562_resume(struct snd_soc_component *component) +{ + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + + if (tas2562->sdz_gpio) + gpiod_set_value_cansleep(tas2562->sdz_gpio, 1); + + regcache_cache_only(tas2562->regmap, false); + + return regcache_sync(tas2562->regmap); +} +#else +#define tas2562_suspend NULL +#define tas2562_resume NULL +#endif + +static const char * const tas2562_ASI1_src[] = { + "I2C offset", "Left", "Right", "LeftRightDiv2", +}; + +static SOC_ENUM_SINGLE_DECL(tas2562_ASI1_src_enum, TAS2562_TDM_CFG2, 4, + tas2562_ASI1_src); + +static const struct snd_kcontrol_new tas2562_asi1_mux = + SOC_DAPM_ENUM("ASI1 Source", tas2562_ASI1_src_enum); + +static int tas2562_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + dev_info(tas2562->dev, "SND_SOC_DAPM_POST_PMU\n"); + break; + case SND_SOC_DAPM_PRE_PMD: + dev_info(tas2562->dev, "SND_SOC_DAPM_PRE_PMD\n"); + break; + default: + break; + } + + return 0; +} + +static DECLARE_TLV_DB_SCALE(tas2562_dac_tlv, 850, 50, 0); + +static const struct snd_kcontrol_new isense_switch = + SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_ISENSE_POWER_EN, + 1, 1); + +static const struct snd_kcontrol_new vsense_switch = + SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_VSENSE_POWER_EN, + 1, 1); + +static const struct snd_kcontrol_new tas2562_snd_controls[] = { + SOC_SINGLE_TLV("Amp Gain Volume", TAS2562_PB_CFG1, 0, 0x1c, 0, + tas2562_dac_tlv), +}; + +static const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2562_asi1_mux), + SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2562_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SWITCH("ISENSE", TAS2562_PWR_CTRL, 3, 1, &isense_switch), + SND_SOC_DAPM_SWITCH("VSENSE", TAS2562_PWR_CTRL, 2, 1, &vsense_switch), + SND_SOC_DAPM_SIGGEN("VMON"), + SND_SOC_DAPM_SIGGEN("IMON"), + SND_SOC_DAPM_OUTPUT("OUT"), +}; + +static const struct snd_soc_dapm_route tas2562_audio_map[] = { + {"ASI1 Sel", "I2C offset", "ASI1"}, + {"ASI1 Sel", "Left", "ASI1"}, + {"ASI1 Sel", "Right", "ASI1"}, + {"ASI1 Sel", "LeftRightDiv2", "ASI1"}, + { "DAC", NULL, "DAC IN" }, + { "OUT", NULL, "DAC" }, + {"ISENSE", "Switch", "IMON"}, + {"VSENSE", "Switch", "VMON"}, +}; + +static const struct snd_soc_component_driver soc_component_dev_tas2562 = { + .probe = tas2562_codec_probe, + .suspend = tas2562_suspend, + .resume = tas2562_resume, + .set_bias_level = tas2562_set_bias_level, + .controls = tas2562_snd_controls, + .num_controls = ARRAY_SIZE(tas2562_snd_controls), + .dapm_widgets = tas2562_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas2562_dapm_widgets), + .dapm_routes = tas2562_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas2562_audio_map), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct snd_soc_dai_ops tas2562_speaker_dai_ops = { + .hw_params = tas2562_hw_params, + .set_fmt = tas2562_set_dai_fmt, + .set_tdm_slot = tas2562_set_dai_tdm_slot, + .digital_mute = tas2562_mute, +}; + +static struct snd_soc_dai_driver tas2562_dai[] = { + { + .name = "tas2562-amplifier", + .id = 0, + .playback = { + .stream_name = "ASI1 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = TAS2562_FORMATS, + }, + .ops = &tas2562_speaker_dai_ops, + }, +}; + +static const struct regmap_range_cfg tas2562_ranges[] = { + { + .range_min = 0, + .range_max = 5 * 128, + .selector_reg = TAS2562_PAGE_CTRL, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 128, + }, +}; + +static const struct reg_default tas2562_reg_defaults[] = { + { TAS2562_PAGE_CTRL, 0x00 }, + { TAS2562_SW_RESET, 0x00 }, + { TAS2562_PWR_CTRL, 0x0e }, + { TAS2562_PB_CFG1, 0x20 }, + { TAS2562_TDM_CFG0, 0x09 }, + { TAS2562_TDM_CFG1, 0x02 }, +}; + +static const struct regmap_config tas2562_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = 5 * 128, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = tas2562_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tas2562_reg_defaults), + .ranges = tas2562_ranges, + .num_ranges = ARRAY_SIZE(tas2562_ranges), +}; + +static int tas2562_parse_dt(struct tas2562_data *tas2562) +{ + struct device *dev = tas2562->dev; + int ret = 0; + + tas2562->sdz_gpio = devm_gpiod_get_optional(dev, "shut-down-gpio", + GPIOD_OUT_HIGH); + if (IS_ERR(tas2562->sdz_gpio)) { + if (PTR_ERR(tas2562->sdz_gpio) == -EPROBE_DEFER) { + tas2562->sdz_gpio = NULL; + return -EPROBE_DEFER; + } + } + + ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no", + &tas2562->i_sense_slot); + if (ret) + dev_err(dev, "Looking up %s property failed %d\n", + "ti,imon-slot-no", ret); + + return ret; +} + +static int tas2562_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct tas2562_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + data->dev = &client->dev; + + tas2562_parse_dt(data); + + data->regmap = devm_regmap_init_i2c(client, &tas2562_regmap_config); + if (IS_ERR(data->regmap)) { + ret = PTR_ERR(data->regmap); + dev_err(dev, "failed to allocate register map: %d\n", ret); + return ret; + } + + dev_set_drvdata(&client->dev, data); + + return devm_snd_soc_register_component(dev, &soc_component_dev_tas2562, + tas2562_dai, + ARRAY_SIZE(tas2562_dai)); + +} + +static const struct i2c_device_id tas2562_id[] = { + { "tas2562", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas2562_id); + +static const struct of_device_id tas2562_of_match[] = { + { .compatible = "ti,tas2562", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tas2562_of_match); + +static struct i2c_driver tas2562_i2c_driver = { + .driver = { + .name = "tas2562", + .of_match_table = of_match_ptr(tas2562_of_match), + }, + .probe = tas2562_probe, + .id_table = tas2562_id, +}; + +module_i2c_driver(tas2562_i2c_driver); + +MODULE_AUTHOR("Dan Murphy "); +MODULE_DESCRIPTION("TAS2562 Audio amplifier driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tas2562.h b/sound/soc/codecs/tas2562.h new file mode 100644 index 000000000000..60f2bb1d198b --- /dev/null +++ b/sound/soc/codecs/tas2562.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tas2562.h - ALSA SoC Texas Instruments TAS2562 Mono Audio Amplifier + * + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Dan Murphy + */ + +#ifndef __TAS2562_H__ +#define __TAS2562_H__ + +#define TAS2562_PAGE_CTRL 0x00 + +#define TAS2562_REG(page, reg) ((page * 128) + reg) + +#define TAS2562_SW_RESET TAS2562_REG(0, 0x01) +#define TAS2562_PWR_CTRL TAS2562_REG(0, 0x02) +#define TAS2562_PB_CFG1 TAS2562_REG(0, 0x03) +#define TAS2562_MISC_CFG1 TAS2562_REG(0, 0x04) +#define TAS2562_MISC_CFG2 TAS2562_REG(0, 0x05) + +#define TAS2562_TDM_CFG0 TAS2562_REG(0, 0x06) +#define TAS2562_TDM_CFG1 TAS2562_REG(0, 0x07) +#define TAS2562_TDM_CFG2 TAS2562_REG(0, 0x08) +#define TAS2562_TDM_CFG3 TAS2562_REG(0, 0x09) +#define TAS2562_TDM_CFG4 TAS2562_REG(0, 0x0a) +#define TAS2562_TDM_CFG5 TAS2562_REG(0, 0x0b) +#define TAS2562_TDM_CFG6 TAS2562_REG(0, 0x0c) +#define TAS2562_TDM_CFG7 TAS2562_REG(0, 0x0d) +#define TAS2562_TDM_CFG8 TAS2562_REG(0, 0x0e) +#define TAS2562_TDM_CFG9 TAS2562_REG(0, 0x0f) +#define TAS2562_TDM_CFG10 TAS2562_REG(0, 0x10) +#define TAS2562_TDM_DET TAS2562_REG(0, 0x11) +#define TAS2562_REV_ID TAS2562_REG(0, 0x7d) + +/* Page 2 */ +#define TAS2562_DVC_CFG1 TAS2562_REG(2, 0x01) +#define TAS2562_DVC_CFG2 TAS2562_REG(2, 0x02) + +#define TAS2562_RESET BIT(0) + +#define TAS2562_MODE_MASK 0x3 +#define TAS2562_ACTIVE 0x0 +#define TAS2562_MUTE 0x1 +#define TAS2562_SHUTDOWN 0x2 + +#define TAS2562_TDM_CFG1_RX_EDGE_MASK BIT(0) +#define TAS2562_TDM_CFG1_RX_FALLING 1 +#define TAS2562_TDM_CFG1_RX_OFFSET_MASK GENMASK(4, 0) + +#define TAS2562_TDM_CFG0_RAMPRATE_MASK BIT(5) +#define TAS2562_TDM_CFG0_RAMPRATE_44_1 BIT(5) +#define TAS2562_TDM_CFG0_SAMPRATE_MASK GENMASK(3, 1) +#define TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ 0x0 +#define TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ 0x1 +#define TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ 0x2 +#define TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ 0x3 +#define TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ 0x4 +#define TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ 0x5 +#define TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ 0x6 + +#define TAS2562_TDM_CFG2_RIGHT_JUSTIFY BIT(6) + +#define TAS2562_TDM_CFG2_RXLEN_MASK GENMASK(0, 1) +#define TAS2562_TDM_CFG2_RXLEN_16B 0x0 +#define TAS2562_TDM_CFG2_RXLEN_24B BIT(0) +#define TAS2562_TDM_CFG2_RXLEN_32B BIT(1) + +#define TAS2562_TDM_CFG2_RXWLEN_MASK GENMASK(3, 2) +#define TAS2562_TDM_CFG2_RXWLEN_16B 0x0 +#define TAS2562_TDM_CFG2_RXWLEN_20B BIT(2) +#define TAS2562_TDM_CFG2_RXWLEN_24B BIT(3) +#define TAS2562_TDM_CFG2_RXWLEN_32B (BIT(2) | BIT(3)) + +#define TAS2562_VSENSE_POWER_EN BIT(2) +#define TAS2562_ISENSE_POWER_EN BIT(3) + +#define TAS2562_TDM_CFG5_VSNS_EN BIT(6) +#define TAS2562_TDM_CFG5_VSNS_SLOT_MASK GENMASK(5, 0) + +#define TAS2562_TDM_CFG6_ISNS_EN BIT(6) +#define TAS2562_TDM_CFG6_ISNS_SLOT_MASK GENMASK(5, 0) + +#endif /* __TAS2562_H__ */ -- cgit From 0c93c291321f2ba8dc4cd3d4df74801caaa297db Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Fri, 11 Oct 2019 10:48:16 +0200 Subject: ASoC: stm32: spdifrx: retry synchronization in sync state When STM32 SPDIFRX is in sync state, allow multiple synchro attempts, instead of exiting on first unsuccessful trial. This is useful when spdif signal is not immediately available on input. This also allows Pulseaudio to check iec capture device availability when no signal is present. Signed-off-by: Olivier Moysan Link: https://lore.kernel.org/r/20191011084816.14279-1-olivier.moysan@st.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_spdifrx.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index cd4b235fce57..3fd28ee01675 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -351,6 +351,8 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO; cr_mask = cr; + cr |= SPDIFRX_CR_NBTRSET(SPDIFRX_NBTR_63); + cr_mask |= SPDIFRX_CR_NBTR_MASK; cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); cr_mask |= SPDIFRX_CR_SPDIFEN_MASK; ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, @@ -666,7 +668,7 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) struct snd_pcm_substream *substream = spdifrx->substream; struct platform_device *pdev = spdifrx->pdev; unsigned int cr, mask, sr, imr; - unsigned int flags; + unsigned int flags, sync_state; int err = 0, err_xrun = 0; regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr); @@ -726,11 +728,23 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) } if (err) { - /* SPDIFRX in STATE_STOP. Disable SPDIFRX to clear errors */ + regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); + sync_state = FIELD_GET(SPDIFRX_CR_SPDIFEN_MASK, cr) && + SPDIFRX_SPDIFEN_SYNC; + + /* SPDIFRX is in STATE_STOP. Disable SPDIFRX to clear errors */ cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, SPDIFRX_CR_SPDIFEN_MASK, cr); + /* If SPDIFRX was in STATE_SYNC, retry synchro */ + if (sync_state) { + cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + SPDIFRX_CR_SPDIFEN_MASK, cr); + return IRQ_HANDLED; + } + if (substream) snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); -- cgit From de729862cc0f0b46dd3a3c11079240ea4e13b97d Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 11 Oct 2019 23:00:42 +0800 Subject: ASoC: adau7118: Fix Kconfig warning without CONFIG_I2C When building a kernel without CONFIG_I2C, Kconfig warns: WARNING: unmet direct dependencies detected for REGMAP_I2C Depends on [n]: I2C [=n] Selected by [y]: - SND_SOC_ADAU7118_I2C [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] Add missing I2C dependency to SND_SOC_ADAU7118_I2C to fix this. Reported-by: Hulk Robot Fixes: ca514c0f12b0 ("ASOC: Add ADAU7118 8 Channel PDM-to-I2S/TDM Converter driver") Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20191011150042.20096-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f4747ebc251e..5a706102db04 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -416,6 +416,7 @@ config SND_SOC_ADAU7118_HW config SND_SOC_ADAU7118_I2C tristate "Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM Converter - I2C" + depends on I2C select SND_SOC_ADAU7118 select REGMAP_I2C help -- cgit From dd79841ca66ff509660880237dc286d7f116a766 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 11 Oct 2019 22:35:38 +0800 Subject: ASoC: fsl_mqs: Move static keyword to the front of declarations gcc warn about this: sound/soc/fsl/fsl_mqs.c:146:1: warning: static is not at beginning of declaration [-Wold-style-declaration] Signed-off-by: YueHaibing Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20191011143538.15300-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_mqs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index f7fc44e8fb27..0c813a45bba7 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -143,7 +143,7 @@ static void fsl_mqs_shutdown(struct snd_pcm_substream *substream, MQS_EN_MASK, 0); } -const static struct snd_soc_component_driver soc_codec_fsl_mqs = { +static const struct snd_soc_component_driver soc_codec_fsl_mqs = { .idle_bias_on = 1, .non_legacy_dai_naming = 1, }; -- cgit From f9f618e7128e834db3f54d290a926c4a71104e02 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Oct 2019 11:43:09 -0500 Subject: ASoC: SOF: Intel: byt: fix operator precedence warnings Address cppcheck warnings sound/soc/sof/intel/byt.c:163:26: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] panic & SHIM_IPCX_BUSY ? "yes" : "no", ^ sound/soc/sof/intel/byt.c:164:26: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] panic & SHIM_IPCX_DONE ? "yes" : "no", panic); ^ sound/soc/sof/intel/byt.c:167:25: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] imrx & SHIM_IMRX_BUSY ? "yes" : "no", ^ sound/soc/sof/intel/byt.c:168:25: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] imrx & SHIM_IMRX_DONE ? "yes" : "no", imrx); ^ sound/soc/sof/intel/byt.c:171:27: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] status & SHIM_IPCD_BUSY ? "yes" : "no", ^ sound/soc/sof/intel/byt.c:172:27: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] status & SHIM_IPCD_DONE ? "yes" : "no", status); ^ sound/soc/sof/intel/byt.c:175:25: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] imrd & SHIM_IMRD_BUSY ? "yes" : "no", ^ sound/soc/sof/intel/byt.c:176:25: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] imrd & SHIM_IMRD_DONE ? "yes" : "no", imrd); ^ Fixes: 3a9e204d4e369 ("ASoC: SOF: Intel: Add context data to any IPC timeout.") Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191011164312.7988-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/byt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index b2597ecfdc1c..07e5efe4945c 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -160,20 +160,20 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags) imrd = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRD); dev_err(sdev->dev, "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n", - panic & SHIM_IPCX_BUSY ? "yes" : "no", - panic & SHIM_IPCX_DONE ? "yes" : "no", panic); + (panic & SHIM_IPCX_BUSY) ? "yes" : "no", + (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic); dev_err(sdev->dev, "error: mask host: pending %s complete %s raw 0x%8.8x\n", - imrx & SHIM_IMRX_BUSY ? "yes" : "no", - imrx & SHIM_IMRX_DONE ? "yes" : "no", imrx); + (imrx & SHIM_IMRX_BUSY) ? "yes" : "no", + (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx); dev_err(sdev->dev, "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n", - status & SHIM_IPCD_BUSY ? "yes" : "no", - status & SHIM_IPCD_DONE ? "yes" : "no", status); + (status & SHIM_IPCD_BUSY) ? "yes" : "no", + (status & SHIM_IPCD_DONE) ? "yes" : "no", status); dev_err(sdev->dev, "error: mask DSP: pending %s complete %s raw 0x%8.8x\n", - imrd & SHIM_IMRD_BUSY ? "yes" : "no", - imrd & SHIM_IMRD_DONE ? "yes" : "no", imrd); + (imrd & SHIM_IMRD_BUSY) ? "yes" : "no", + (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd); } -- cgit From 7ad03a2c848f6fb0a8dea656c9c161929696878e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Oct 2019 11:43:10 -0500 Subject: ASoC: SOF: Intel: bdw: fix operator precedence warnings Address cppcheck warnings sound/soc/sof/intel/bdw.c:265:26: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] panic & SHIM_IPCX_BUSY ? "yes" : "no", ^ sound/soc/sof/intel/bdw.c:266:26: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] panic & SHIM_IPCX_DONE ? "yes" : "no", panic); ^ sound/soc/sof/intel/bdw.c:269:25: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] imrx & SHIM_IMRX_BUSY ? "yes" : "no", ^ sound/soc/sof/intel/bdw.c:270:25: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] imrx & SHIM_IMRX_DONE ? "yes" : "no", imrx); ^ sound/soc/sof/intel/bdw.c:273:27: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] status & SHIM_IPCD_BUSY ? "yes" : "no", ^ sound/soc/sof/intel/bdw.c:274:27: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] status & SHIM_IPCD_DONE ? "yes" : "no", status); ^ sound/soc/sof/intel/bdw.c:277:25: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] imrd & SHIM_IMRD_BUSY ? "yes" : "no", ^ sound/soc/sof/intel/bdw.c:278:25: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] imrd & SHIM_IMRD_DONE ? "yes" : "no", imrd); ^ Fixes: 3a9e204d4e369 ("ASoC: SOF: Intel: Add context data to any IPC timeout.") Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191011164312.7988-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/bdw.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index f395d0638876..bf961a8798a7 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -262,20 +262,20 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) imrd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRD); dev_err(sdev->dev, "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n", - panic & SHIM_IPCX_BUSY ? "yes" : "no", - panic & SHIM_IPCX_DONE ? "yes" : "no", panic); + (panic & SHIM_IPCX_BUSY) ? "yes" : "no", + (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic); dev_err(sdev->dev, "error: mask host: pending %s complete %s raw 0x%8.8x\n", - imrx & SHIM_IMRX_BUSY ? "yes" : "no", - imrx & SHIM_IMRX_DONE ? "yes" : "no", imrx); + (imrx & SHIM_IMRX_BUSY) ? "yes" : "no", + (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx); dev_err(sdev->dev, "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n", - status & SHIM_IPCD_BUSY ? "yes" : "no", - status & SHIM_IPCD_DONE ? "yes" : "no", status); + (status & SHIM_IPCD_BUSY) ? "yes" : "no", + (status & SHIM_IPCD_DONE) ? "yes" : "no", status); dev_err(sdev->dev, "error: mask DSP: pending %s complete %s raw 0x%8.8x\n", - imrd & SHIM_IMRD_BUSY ? "yes" : "no", - imrd & SHIM_IMRD_DONE ? "yes" : "no", imrd); + (imrd & SHIM_IMRD_BUSY) ? "yes" : "no", + (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd); } /* -- cgit From 494e8f65da24d550a5e7c6a85b9433ffb181705c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Oct 2019 11:43:11 -0500 Subject: ASoC: SOF: topology: remove always-true redundant test Address cppcheck warning: sound/soc/sof/topology.c:2322:6: style: Condition 'pcm' is always true [knownConditionTrueFalse] if (pcm) { ^ sound/soc/sof/topology.c:2311:6: note: Assuming that condition '!pcm' is not redundant if (!pcm) ^ sound/soc/sof/topology.c:2322:6: note: Condition 'pcm' is always true if (pcm) { ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191011164312.7988-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a29109ea3c06..3fad1d5cb2ca 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2308,10 +2308,9 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id = COMP_ID_UNASSIGNED; spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id = COMP_ID_UNASSIGNED; - if (pcm) { - spcm->pcm = *pcm; - dev_dbg(sdev->dev, "tplg: load pcm %s\n", pcm->dai_name); - } + spcm->pcm = *pcm; + dev_dbg(sdev->dev, "tplg: load pcm %s\n", pcm->dai_name); + dai_drv->dobj.private = spcm; list_add(&spcm->list, &sdev->pcm_list); -- cgit From 8a3ab38c36926ddbda3d2a3086c0a741fa175cff Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Oct 2019 11:43:12 -0500 Subject: ASoC: SOF: topology: check errors when parsing LED tokens sof_parse_tokens() returns a value that is checked on every call except for LED tokens, fix with explicit test. Detected with cppcheck warning: sound/soc/sof/topology.c:973:6: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] ret = sof_parse_tokens(scomp, &scontrol->led_ctl, led_tokens, ^ Fixes: 5d43001ae4360 ("ASoC: SOF: acpi led support for switch controls") Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191011164312.7988-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 3fad1d5cb2ca..b3ab6f23fc93 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -963,6 +963,11 @@ out: ret = sof_parse_tokens(scomp, &scontrol->led_ctl, led_tokens, ARRAY_SIZE(led_tokens), mc->priv.array, le32_to_cpu(mc->priv.size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse led tokens failed %d\n", + le32_to_cpu(mc->priv.size)); + return ret; + } dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); -- cgit From 9899a7a869935c4c93247b290ac7a70e0deab202 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 14 Oct 2019 17:13:08 +0800 Subject: ASoC: SOF: Fix randbuild error When LEDS_TRIGGER_AUDIO is m and SND_SOC_SOF is y, sound/soc/sof/control.o: In function `snd_sof_switch_put': control.c:(.text+0x587): undefined reference to `ledtrig_audio_set' control.c:(.text+0x593): undefined reference to `ledtrig_audio_set' Reported-by: Hulk Robot Fixes: 5d43001ae436 ("ASoC: SOF: acpi led support for switch controls") Signed-off-by: YueHaibing Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191014091308.23688-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 41551e8f6ac3..2c4abd406c4f 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -36,10 +36,12 @@ static void update_mute_led(struct snd_sof_control *scontrol, scontrol->led_ctl.led_value = temp; +#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO) if (!scontrol->led_ctl.direction) ledtrig_audio_set(LED_AUDIO_MUTE, temp ? LED_OFF : LED_ON); else ledtrig_audio_set(LED_AUDIO_MICMUTE, temp ? LED_OFF : LED_ON); +#endif } static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) -- cgit From 47cbea21628187c32efad562867aa2b6760d83cc Mon Sep 17 00:00:00 2001 From: Naveen M Date: Tue, 15 Oct 2019 00:28:00 +0800 Subject: ASoC: Intel: eve: Enable mclk and ssp sclk early rt5663 and rt5514 needs mclk/sclk early to synchronize its internal clocks. Signed-off-by: Naveen M Signed-off-by: Harsha Priya Signed-off-by: Subhransu S. Prusty Signed-off-by: Brent Lu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/1571070480-25666-1-git-send-email-brent.lu@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + .../soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 94 ++++++++++++++++++++++ 2 files changed, 95 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 5c27f7ab4a5f..5e0e7dbd1300 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -320,6 +320,7 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH select SND_SOC_RT5514_SPI select SND_SOC_MAX98927 select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_SKYLAKE_SSP_CLK help This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for RT5663 + RT5514 + MAX98927. diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index 74dda8784f1a..dc09a85e4c74 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -22,6 +22,9 @@ #include "../../codecs/rt5514.h" #include "../../codecs/rt5663.h" #include "../../codecs/hdac_hdmi.h" +#include +#include +#include #define KBL_REALTEK_CODEC_DAI "rt5663-aif" #define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" @@ -50,6 +53,8 @@ struct kbl_codec_private { struct snd_soc_jack kabylake_headset; struct list_head hdmi_pcm_list; struct snd_soc_jack kabylake_hdmi[2]; + struct clk *mclk; + struct clk *sclk; }; enum { @@ -71,6 +76,61 @@ static const struct snd_kcontrol_new kabylake_controls[] = { SOC_DAPM_PIN_SWITCH("DMIC"), }; +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card); + int ret = 0; + + /* + * MCLK/SCLK need to be ON early for a successful synchronization of + * codec internal clock. And the clocks are turned off during + * POST_PMD after the stream is stopped. + */ + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable MCLK */ + ret = clk_set_rate(priv->mclk, 24000000); + if (ret < 0) { + dev_err(card->dev, "Can't set rate for mclk, err: %d\n", + ret); + return ret; + } + + ret = clk_prepare_enable(priv->mclk); + if (ret < 0) { + dev_err(card->dev, "Can't enable mclk, err: %d\n", ret); + return ret; + } + + /* Enable SCLK */ + ret = clk_set_rate(priv->sclk, 3072000); + if (ret < 0) { + dev_err(card->dev, "Can't set rate for sclk, err: %d\n", + ret); + clk_disable_unprepare(priv->mclk); + return ret; + } + + ret = clk_prepare_enable(priv->sclk); + if (ret < 0) { + dev_err(card->dev, "Can't enable sclk, err: %d\n", ret); + clk_disable_unprepare(priv->mclk); + } + break; + case SND_SOC_DAPM_POST_PMD: + clk_disable_unprepare(priv->mclk); + clk_disable_unprepare(priv->sclk); + break; + default: + return 0; + } + + return 0; +} + static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -79,11 +139,15 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_MIC("DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route kabylake_map[] = { /* Headphones */ + { "Headphone Jack", NULL, "Platform Clock" }, { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -92,6 +156,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = { { "Right Spk", NULL, "Right BE_OUT" }, /* other jacks */ + { "Headset Mic", NULL, "Platform Clock" }, { "IN1P", NULL, "Headset Mic" }, { "IN1N", NULL, "Headset Mic" }, @@ -643,6 +708,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_codec_private *ctx; struct snd_soc_acpi_mach *mach; + int ret = 0; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -658,6 +724,34 @@ static int kabylake_audio_probe(struct platform_device *pdev) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; + ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); + if (IS_ERR(ctx->mclk)) { + ret = PTR_ERR(ctx->mclk); + if (ret == -ENOENT) { + dev_info(&pdev->dev, + "Failed to get ssp1_mclk, defer probe\n"); + return -EPROBE_DEFER; + } + + dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n", + ret); + return ret; + } + + ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk"); + if (IS_ERR(ctx->sclk)) { + ret = PTR_ERR(ctx->sclk); + if (ret == -ENOENT) { + dev_info(&pdev->dev, + "Failed to get ssp1_sclk, defer probe\n"); + return -EPROBE_DEFER; + } + + dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n", + ret); + return ret; + } + return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); } -- cgit From 848704f39ff61f3f618975a76d6379f2848359a8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 15 Oct 2019 11:52:41 +0900 Subject: ASoC: simple-card: fixup simple_dai_link_of_dpcm() comment The comment is wrong. This patch fixup it. Signed-off-by: Kuninori Morimoto Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/87ftju67pi.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index fc9c753db8dd..10b82bf043d1 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -149,7 +149,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (li->cpu) { int is_single_links = 0; - /* BE is dummy */ + /* Codec is dummy */ codecs->of_node = NULL; codecs->dai_name = "snd-soc-dummy-dai"; codecs->name = "snd-soc-dummy"; @@ -179,7 +179,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, } else { struct snd_soc_codec_conf *cconf; - /* FE is dummy */ + /* CPU is dummy */ cpus->of_node = NULL; cpus->dai_name = "snd-soc-dummy-dai"; cpus->name = "snd-soc-dummy"; -- cgit From 9764beeae7cc477c13ffc451a5edd1ab8891e3ea Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 15 Oct 2019 11:52:52 +0900 Subject: ASoC: audio-graph: fixup graph_dai_link_of_dpcm() comment The comment is wrong. This patch fixup it. Signed-off-by: Kuninori Morimoto Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/87eeze67p7.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 6007e6305735..9ad35d9940fe 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -232,7 +232,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (li->cpu) { int is_single_links = 0; - /* BE is dummy */ + /* Codec is dummy */ codecs->of_node = NULL; codecs->dai_name = "snd-soc-dummy-dai"; codecs->name = "snd-soc-dummy"; @@ -263,7 +263,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, } else { struct snd_soc_codec_conf *cconf; - /* FE is dummy */ + /* CPU is dummy */ cpus->of_node = NULL; cpus->dai_name = "snd-soc-dummy-dai"; cpus->name = "snd-soc-dummy"; -- cgit From a35716a95655d8fc15042c9d574374eceb9daf3d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 15 Oct 2019 12:00:37 +0300 Subject: ASoC: pcm3168a: Fix serial mode dependent format support fmt 0 is perfectly valid (PCM3168A_FMT_I2S). Remove the return in case fmt == 0. Fixes: ("ASoC: pcm3168a: Use fixup instead of constraint for channels and formats") Reported-by: Kuninori Morimoto Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191015090037.23271-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 708dac27feff..313500ab36df 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -322,9 +322,6 @@ static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai) u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE; unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6; - if (!pcm3168a->io_params[dai->id].fmt) - return; - if (pcm3168a->io_params[dai->id].fmt == PCM3168A_FMT_RIGHT_J) { /* S16_LE is only supported in RIGHT_J mode */ formats |= SNDRV_PCM_FMTBIT_S16_LE; -- cgit From 81bd644f69858c233245588f18b88bdcd62efd1e Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 16 Oct 2019 16:57:54 +0800 Subject: ASoC: rt1011: set tx/rx slots from tx/rx_mask in TDM case The TX/RX slot configuration use tx/rx_mask which requested by the machine driver. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20191016085754.11614-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 142 ++++++++++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/rt1011.h | 23 ++++++++ 2 files changed, 160 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index be1e276e3631..b927e61b32df 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1805,8 +1805,8 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, struct snd_soc_component *component = dai->component; struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - unsigned int val = 0, tdm_en = 0; - int ret = 0; + unsigned int val = 0, tdm_en = 0, rx_slotnum, tx_slotnum; + int ret = 0, first_bit, last_bit; snd_soc_dapm_mutex_lock(dapm); if (rx_mask || tx_mask) @@ -1829,6 +1829,7 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, break; default: ret = -EINVAL; + goto _set_tdm_err_; } switch (slot_width) { @@ -1848,6 +1849,135 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, break; default: ret = -EINVAL; + goto _set_tdm_err_; + } + + /* Rx slot configuration */ + rx_slotnum = hweight_long(rx_mask); + first_bit = find_next_bit((unsigned long *)&rx_mask, 32, 0); + if (rx_slotnum > 1 || rx_slotnum == 0) { + ret = -EINVAL; + dev_dbg(component->dev, "too many rx slots or zero slot\n"); + goto _set_tdm_err_; + } + + switch (first_bit) { + case 0: + case 2: + case 4: + case 6: + snd_soc_component_update_bits(component, + RT1011_CROSS_BQ_SET_1, RT1011_MONO_LR_SEL_MASK, + RT1011_MONO_L_CHANNEL); + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_4, + RT1011_TDM_I2S_TX_L_DAC1_1_MASK | + RT1011_TDM_I2S_TX_R_DAC1_1_MASK, + (first_bit << RT1011_TDM_I2S_TX_L_DAC1_1_SFT) | + ((first_bit+1) << RT1011_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + case 1: + case 3: + case 5: + case 7: + snd_soc_component_update_bits(component, + RT1011_CROSS_BQ_SET_1, RT1011_MONO_LR_SEL_MASK, + RT1011_MONO_R_CHANNEL); + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_4, + RT1011_TDM_I2S_TX_L_DAC1_1_MASK | + RT1011_TDM_I2S_TX_R_DAC1_1_MASK, + ((first_bit-1) << RT1011_TDM_I2S_TX_L_DAC1_1_SFT) | + (first_bit << RT1011_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + /* Tx slot configuration */ + tx_slotnum = hweight_long(tx_mask); + first_bit = find_next_bit((unsigned long *)&tx_mask, 32, 0); + last_bit = find_last_bit((unsigned long *)&tx_mask, 32); + if (tx_slotnum > 2 || (last_bit-first_bit) > 1) { + ret = -EINVAL; + dev_dbg(component->dev, "too many tx slots or tx slot location error\n"); + goto _set_tdm_err_; + } + + if (tx_slotnum == 1) { + snd_soc_component_update_bits(component, RT1011_TDM1_SET_2, + RT1011_TDM_I2S_DOCK_ADCDAT_LEN_1_MASK | + RT1011_TDM_ADCDAT1_DATA_LOCATION, first_bit); + switch (first_bit) { + case 1: + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_3, + RT1011_TDM_I2S_RX_ADC1_1_MASK, + RT1011_TDM_I2S_RX_ADC1_1_LL); + break; + case 3: + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_3, + RT1011_TDM_I2S_RX_ADC2_1_MASK, + RT1011_TDM_I2S_RX_ADC2_1_LL); + break; + case 5: + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_3, + RT1011_TDM_I2S_RX_ADC3_1_MASK, + RT1011_TDM_I2S_RX_ADC3_1_LL); + break; + case 7: + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_3, + RT1011_TDM_I2S_RX_ADC4_1_MASK, + RT1011_TDM_I2S_RX_ADC4_1_LL); + break; + case 0: + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_3, + RT1011_TDM_I2S_RX_ADC1_1_MASK, 0); + break; + case 2: + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_3, + RT1011_TDM_I2S_RX_ADC2_1_MASK, 0); + break; + case 4: + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_3, + RT1011_TDM_I2S_RX_ADC3_1_MASK, 0); + break; + case 6: + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_3, + RT1011_TDM_I2S_RX_ADC4_1_MASK, 0); + break; + default: + ret = -EINVAL; + dev_dbg(component->dev, + "tx slot location error\n"); + goto _set_tdm_err_; + } + } else if (tx_slotnum == 2) { + switch (first_bit) { + case 0: + case 2: + case 4: + case 6: + snd_soc_component_update_bits(component, + RT1011_TDM1_SET_2, + RT1011_TDM_I2S_DOCK_ADCDAT_LEN_1_MASK | + RT1011_TDM_ADCDAT1_DATA_LOCATION, + RT1011_TDM_I2S_DOCK_ADCDAT_2CH | first_bit); + break; + default: + ret = -EINVAL; + dev_dbg(component->dev, + "tx slot location should be paired and start from slot0/2/4/6\n"); + goto _set_tdm_err_; + } } snd_soc_component_update_bits(component, RT1011_TDM1_SET_1, @@ -1860,10 +1990,12 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, RT1011_TDM_I2S_DOCK_EN_1_MASK, tdm_en); snd_soc_component_update_bits(component, RT1011_TDM2_SET_2, RT1011_TDM_I2S_DOCK_EN_2_MASK, tdm_en); - snd_soc_component_update_bits(component, RT1011_TDM_TOTAL_SET, - RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG, - RT1011_ADCDAT1_OUTPUT | RT1011_ADCDAT2_OUTPUT); + if (tx_slotnum) + snd_soc_component_update_bits(component, RT1011_TDM_TOTAL_SET, + RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG, + RT1011_ADCDAT1_OUTPUT | RT1011_ADCDAT2_OUTPUT); +_set_tdm_err_: snd_soc_dapm_mutex_unlock(dapm); return ret; } diff --git a/sound/soc/codecs/rt1011.h b/sound/soc/codecs/rt1011.h index 2d65983f3d0f..3f7dea1191ad 100644 --- a/sound/soc/codecs/rt1011.h +++ b/sound/soc/codecs/rt1011.h @@ -460,6 +460,23 @@ #define RT1011_TDM_I2S_DOCK_EN_1_MASK (0x1 << 3) #define RT1011_TDM_I2S_DOCK_EN_1_SFT 3 #define RT1011_TDM_I2S_DOCK_EN_1 (0x1 << 3) +#define RT1011_TDM_ADCDAT1_DATA_LOCATION (0x7 << 0) + +/* TDM1 Setting-3 (0x0118) */ +#define RT1011_TDM_I2S_RX_ADC1_1_MASK (0x3 << 6) +#define RT1011_TDM_I2S_RX_ADC2_1_MASK (0x3 << 4) +#define RT1011_TDM_I2S_RX_ADC3_1_MASK (0x3 << 2) +#define RT1011_TDM_I2S_RX_ADC4_1_MASK (0x3 << 0) +#define RT1011_TDM_I2S_RX_ADC1_1_LL (0x2 << 6) +#define RT1011_TDM_I2S_RX_ADC2_1_LL (0x2 << 4) +#define RT1011_TDM_I2S_RX_ADC3_1_LL (0x2 << 2) +#define RT1011_TDM_I2S_RX_ADC4_1_LL (0x2 << 0) + +/* TDM1 Setting-4 (0x011a) */ +#define RT1011_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 12) +#define RT1011_TDM_I2S_TX_R_DAC1_1_MASK (0x7 << 8) +#define RT1011_TDM_I2S_TX_L_DAC1_1_SFT 12 +#define RT1011_TDM_I2S_TX_R_DAC1_1_SFT 8 /* TDM2 Setting-2 (0x0120) */ #define RT1011_TDM_I2S_DOCK_ADCDAT_LEN_2_MASK (0x7 << 13) @@ -585,6 +602,12 @@ #define RT1011_STP_T0_EN_BIT 6 #define RT1011_STP_T0_EN (0x1 << 6) +/* Cross Biquad Setting-1 (0x0702) */ +#define RT1011_MONO_LR_SEL_MASK (0x3 << 5) +#define RT1011_MONO_L_CHANNEL (0x0 << 5) +#define RT1011_MONO_R_CHANNEL (0x1 << 5) +#define RT1011_MONO_LR_MIX_CHANNEL (0x2 << 5) + /* ClassD Internal Setting-1 (0x1300) */ #define RT1011_DRIVER_READY_SPK (0x1 << 12) #define RT1011_DRIVER_READY_SPK_BIT 12 -- cgit From 3ad00f6a5f76d4030a3c712fabe0cf69920925fc Mon Sep 17 00:00:00 2001 From: "Ben Dooks (Codethink)" Date: Wed, 16 Oct 2019 13:01:49 +0100 Subject: ASoC: wm8958: use to simplify code Simplify the memcpy/be32_to_cpu() code by simply using get_unaligned_be32() throughout and makes the code nicer to look at. This fixes the following warnings from sparse: sound/soc/codecs/wm8958-dsp2.c:62:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:62:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:62:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:62:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:62:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:62:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:69:15: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:69:15: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:69:15: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:69:15: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:69:15: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:69:15: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:72:18: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:72:18: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:72:18: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:72:18: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:72:18: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:72:18: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:91:17: warning: cast to restricted __be64 sound/soc/codecs/wm8958-dsp2.c:108:29: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:108:29: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:108:29: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:108:29: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:108:29: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:108:29: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:120:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:120:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:120:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:120:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:120:26: warning: cast to restricted __be32 sound/soc/codecs/wm8958-dsp2.c:120:26: warning: cast to restricted __be32 Signed-off-by: Ben Dooks Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20191016120149.5860-1-ben.dooks@codethink.co.uk Signed-off-by: Mark Brown --- sound/soc/codecs/wm8958-dsp2.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 18535b326680..ca42445b649d 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -25,6 +25,8 @@ #include #include +#include + #include "wm8994.h" #define WM_FW_BLOCK_INFO 0xff @@ -58,18 +60,15 @@ static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name, } if (memcmp(fw->data, "WMFW", 4) != 0) { - memcpy(&data32, fw->data, sizeof(data32)); - data32 = be32_to_cpu(data32); + data32 = get_unaligned_be32(fw->data); dev_err(component->dev, "%s: firmware has bad file magic %08x\n", name, data32); goto err; } - memcpy(&data32, fw->data + 4, sizeof(data32)); - len = be32_to_cpu(data32); + len = get_unaligned_be32(fw->data + 4); + data32 = get_unaligned_be32(fw->data + 8); - memcpy(&data32, fw->data + 8, sizeof(data32)); - data32 = be32_to_cpu(data32); if ((data32 >> 24) & 0xff) { dev_err(component->dev, "%s: unsupported firmware version %d\n", name, (data32 >> 24) & 0xff); @@ -87,9 +86,8 @@ static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name, } if (check) { - memcpy(&data64, fw->data + 24, sizeof(u64)); - dev_info(component->dev, "%s timestamp %llx\n", - name, be64_to_cpu(data64)); + data64 = get_unaligned_be64(fw->data + 24); + dev_info(component->dev, "%s timestamp %llx\n", name, data64); } else { snd_soc_component_write(component, 0x102, 0x2); snd_soc_component_write(component, 0x900, 0x2); @@ -104,8 +102,7 @@ static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name, goto err; } - memcpy(&data32, data + 4, sizeof(data32)); - block_len = be32_to_cpu(data32); + block_len = get_unaligned_be32(data + 4); if (block_len + 8 > len) { dev_err(component->dev, "%zd byte block longer than file\n", block_len); @@ -116,8 +113,7 @@ static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name, goto err; } - memcpy(&data32, data, sizeof(data32)); - data32 = be32_to_cpu(data32); + data32 = get_unaligned_be32(data); switch ((data32 >> 24) & 0xff) { case WM_FW_BLOCK_INFO: -- cgit From 8de6e755069fbfaefae67d3abff2b2e3d83db986 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 16 Oct 2019 16:58:45 +0800 Subject: ASoC: rt1011: Read and apply r0 and temperature device property Typically, the r0 (calibration data) and temperature were measured in the factory. This information is written into the non-volatile area where keeps data whether factory reset or OS update. In Chromium OS case, the coreboot will read the info from VPD and create the device property for each rt1011. Signed-off-by: Shuming Fan Tested-By: Cheng-Yi Chiang Link: https://lore.kernel.org/r/20191016085845.11672-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 41 ++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/rt1011.h | 1 + 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index b927e61b32df..ad049cfddcb0 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2328,8 +2328,12 @@ static void rt1011_calibration_work(struct work_struct *work) struct rt1011_priv *rt1011 = container_of(work, struct rt1011_priv, cali_work); struct snd_soc_component *component = rt1011->component; + unsigned int r0_integer, r0_factor, format; - rt1011_calibrate(rt1011, 1); + if (rt1011->r0_calib) + rt1011_calibrate(rt1011, 0); + else + rt1011_calibrate(rt1011, 1); /* * This flag should reset after booting. @@ -2340,6 +2344,39 @@ static void rt1011_calibration_work(struct work_struct *work) /* initial */ rt1011_reg_init(component); + + /* Apply temperature and calibration data from device property */ + if (rt1011->temperature_calib) { + snd_soc_component_update_bits(component, + RT1011_STP_INITIAL_RESISTANCE_TEMP, 0x3ff, + (rt1011->temperature_calib << 2)); + } + + if (rt1011->r0_calib) { + rt1011->r0_reg = rt1011->r0_calib; + + format = 2147483648U; /* 2^24 * 128 */ + r0_integer = format / rt1011->r0_reg / 128; + r0_factor = ((format / rt1011->r0_reg * 100) / 128) + - (r0_integer * 100); + dev_info(component->dev, "DP r0 resistance about %d.%02d ohm, reg=0x%X\n", + r0_integer, r0_factor, rt1011->r0_reg); + + rt1011_r0_load(rt1011); + } +} + +static int rt1011_parse_dp(struct rt1011_priv *rt1011, struct device *dev) +{ + device_property_read_u32(dev, "realtek,temperature_calib", + &rt1011->temperature_calib); + device_property_read_u32(dev, "realtek,r0_calib", + &rt1011->r0_calib); + + dev_dbg(dev, "%s: r0_calib: 0x%x, temperture_calib: 0x%x", + __func__, rt1011->r0_calib, rt1011->temperature_calib); + + return 0; } static int rt1011_i2c_probe(struct i2c_client *i2c, @@ -2356,6 +2393,8 @@ static int rt1011_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt1011); + rt1011_parse_dp(rt1011, &i2c->dev); + rt1011->regmap = devm_regmap_init_i2c(i2c, &rt1011_regmap); if (IS_ERR(rt1011->regmap)) { ret = PTR_ERR(rt1011->regmap); diff --git a/sound/soc/codecs/rt1011.h b/sound/soc/codecs/rt1011.h index 3f7dea1191ad..68fadc15fa8c 100644 --- a/sound/soc/codecs/rt1011.h +++ b/sound/soc/codecs/rt1011.h @@ -690,6 +690,7 @@ struct rt1011_priv { int bq_drc_set; unsigned int r0_reg, cali_done; + unsigned int r0_calib, temperature_calib; int recv_spk_mode; }; -- cgit From d68c3123ba88dcd6692c90e698473d57856578e1 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:16 +0900 Subject: ALSA: firewire-lib: add a member into AMDTP domain for events per period In IEC 61883-6, it's called as 'event' what has presentation time represented by timestamp in CIP header. Although the ratio of the number of event against the number of data block is different depending on event data type represented by the specific field in CIP header, it's just one in the most cases supported by ALSA IEC 61883-1/6 engine. In 1394 OHCI specification, applications can schedule hardware IRQ by configuring descriptor with IRQ flag for packet against each isochronous cycle. For future commit, I use the hardware IRQ for isoc IT context to acknowledge the elapse of PCM period for both playback/capture directions on AMDTP streams in the same domain. This commit is a preparation for the above idea. This commit adds a member into AMDTP domain structure to record the number of PCM frames. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 4 ++++ sound/firewire/amdtp-stream.h | 10 ++++++++++ 2 files changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index e50e28f77e74..838f695b20de 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1143,6 +1143,8 @@ int amdtp_domain_init(struct amdtp_domain *d) { INIT_LIST_HEAD(&d->streams); + d->events_per_period = 0; + return 0; } EXPORT_SYMBOL_GPL(amdtp_domain_init); @@ -1221,5 +1223,7 @@ void amdtp_domain_stop(struct amdtp_domain *d) amdtp_stream_stop(s); } + + d->events_per_period = 0; } EXPORT_SYMBOL_GPL(amdtp_domain_stop); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index bbbca964b9b4..d95a4ed15f20 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -272,6 +272,8 @@ static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s, struct amdtp_domain { struct list_head streams; + + unsigned int events_per_period; }; int amdtp_domain_init(struct amdtp_domain *d); @@ -283,4 +285,12 @@ int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, int amdtp_domain_start(struct amdtp_domain *d); void amdtp_domain_stop(struct amdtp_domain *d); +static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d, + unsigned int events_per_period) +{ + d->events_per_period = events_per_period; + + return 0; +} + #endif -- cgit From 8737209fe4a251a7d1de8f77c126ce7b69d926e7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:17 +0900 Subject: ALSA: bebob: register the size of PCM period to AMDTP domain This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.h | 3 ++- sound/firewire/bebob/bebob_midi.c | 2 +- sound/firewire/bebob/bebob_pcm.c | 4 +++- sound/firewire/bebob/bebob_stream.c | 11 ++++++++++- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 356d6ba60959..8738c1d8abf7 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -217,7 +217,8 @@ int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob, enum snd_bebob_clock_type *src); int snd_bebob_stream_discover(struct snd_bebob *bebob); int snd_bebob_stream_init_duplex(struct snd_bebob *bebob); -int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate); +int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate, + unsigned int frames_per_period); int snd_bebob_stream_start_duplex(struct snd_bebob *bebob); void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob); void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob); diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c index 4d8805fa8a00..e8f9edf50be5 100644 --- a/sound/firewire/bebob/bebob_midi.c +++ b/sound/firewire/bebob/bebob_midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) return err; mutex_lock(&bebob->mutex); - err = snd_bebob_stream_reserve_duplex(bebob, 0); + err = snd_bebob_stream_reserve_duplex(bebob, 0, 0); if (err >= 0) { ++bebob->substreams_counter; err = snd_bebob_stream_start_duplex(bebob); diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 0fb9eed46837..3b2227abf8a9 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -197,9 +197,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); mutex_lock(&bebob->mutex); - err = snd_bebob_stream_reserve_duplex(bebob, rate); + err = snd_bebob_stream_reserve_duplex(bebob, rate, + frames_per_period); if (err >= 0) ++bebob->substreams_counter; mutex_unlock(&bebob->mutex); diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 73fee991bd75..f1db3ddc3e00 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -554,7 +554,8 @@ static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream, return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream)); } -int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate) +int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -607,6 +608,14 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate) cmp_connection_release(&bebob->out_conn); return err; } + + err = amdtp_domain_set_events_per_period(&bebob->domain, + frames_per_period); + if (err < 0) { + cmp_connection_release(&bebob->out_conn); + cmp_connection_release(&bebob->in_conn); + return err; + } } return 0; -- cgit From dd20e68a305630d7f808268d46709545c358a9b2 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:18 +0900 Subject: ALSA: fireworks: register the size of PCM period to AMDTP domain This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks.h | 3 ++- sound/firewire/fireworks/fireworks_midi.c | 2 +- sound/firewire/fireworks/fireworks_pcm.c | 4 +++- sound/firewire/fireworks/fireworks_stream.c | 11 ++++++++++- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 4cda297f8438..fc5f945a49ff 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -207,7 +207,8 @@ int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate); int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate); int snd_efw_stream_init_duplex(struct snd_efw *efw); -int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate); +int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate, + unsigned int frames_per_period); int snd_efw_stream_start_duplex(struct snd_efw *efw); void snd_efw_stream_stop_duplex(struct snd_efw *efw); void snd_efw_stream_update_duplex(struct snd_efw *efw); diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index a9f4a9630d15..e593f842ee8f 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) goto end; mutex_lock(&efw->mutex); - err = snd_efw_stream_reserve_duplex(efw, 0); + err = snd_efw_stream_reserve_duplex(efw, 0, 0); if (err >= 0) { ++efw->substreams_counter; err = snd_efw_stream_start_duplex(efw); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index a7025dccc754..35fc95283423 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -231,9 +231,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); mutex_lock(&efw->mutex); - err = snd_efw_stream_reserve_duplex(efw, rate); + err = snd_efw_stream_reserve_duplex(efw, rate, + frames_per_period); if (err >= 0) ++efw->substreams_counter; mutex_unlock(&efw->mutex); diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index f2de304d2f26..0787d5c3b01b 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -181,7 +181,8 @@ static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream, return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream)); } -int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) +int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -228,6 +229,14 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) cmp_connection_release(&efw->in_conn); return err; } + + err = amdtp_domain_set_events_per_period(&efw->domain, + frames_per_period); + if (err < 0) { + cmp_connection_release(&efw->in_conn); + cmp_connection_release(&efw->out_conn); + return err; + } } return 0; -- cgit From 1d6a722c4a0146ac20fd0daa541a177279adcbb2 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:19 +0900 Subject: ALSA: oxfw: register the size of PCM period to AMDTP domain This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-midi.c | 4 ++-- sound/firewire/oxfw/oxfw-pcm.c | 6 ++++-- sound/firewire/oxfw/oxfw-stream.c | 12 +++++++++++- sound/firewire/oxfw/oxfw.h | 3 ++- 4 files changed, 19 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index 9bdec08cb8ea..72db7a17d0ad 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -18,7 +18,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0); if (err >= 0) { ++oxfw->substreams_count; err = snd_oxfw_stream_start_duplex(oxfw); @@ -45,7 +45,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0); if (err >= 0) { ++oxfw->substreams_count; err = snd_oxfw_stream_start_duplex(oxfw); diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 7c6d1c277d4d..2d1b5038f7f6 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -221,10 +221,11 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); mutex_lock(&oxfw->mutex); err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, - rate, channels); + rate, channels, frames_per_period); if (err >= 0) ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); @@ -246,10 +247,11 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); mutex_lock(&oxfw->mutex); err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, - rate, channels); + rate, channels, frames_per_period); if (err >= 0) ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 3c9a796b6526..7d2e88c5b73d 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -244,7 +244,8 @@ static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream) int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, - unsigned int rate, unsigned int pcm_channels) + unsigned int rate, unsigned int pcm_channels, + unsigned int frames_per_period) { struct snd_oxfw_stream_formation formation; enum avc_general_plug_dir dir; @@ -305,6 +306,15 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, return err; } } + + err = amdtp_domain_set_events_per_period(&oxfw->domain, + frames_per_period); + if (err < 0) { + cmp_connection_release(&oxfw->in_conn); + if (oxfw->has_output) + cmp_connection_release(&oxfw->out_conn); + return err; + } } return 0; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index c9627b8c5d6e..422746ef2439 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -103,7 +103,8 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate, int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw); int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, - unsigned int rate, unsigned int pcm_channels); + unsigned int rate, unsigned int pcm_channels, + unsigned int frames_per_period); int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw); -- cgit From 94c8101a2717a96457b474580e47142a0ef933c9 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:20 +0900 Subject: ALSA: dice: register the size of PCM period to AMDTP domain This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-midi.c | 2 +- sound/firewire/dice/dice-pcm.c | 7 ++++++- sound/firewire/dice/dice-stream.c | 8 +++++++- sound/firewire/dice/dice.h | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index c9e19bddfc09..69c3c06bd7aa 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) mutex_lock(&dice->mutex); - err = snd_dice_stream_reserve_duplex(dice, 0); + err = snd_dice_stream_reserve_duplex(dice, 0, 0); if (err >= 0) { ++dice->substreams_counter; err = snd_dice_stream_start_duplex(dice); diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 94a4dccfc381..570456a7751d 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -243,9 +243,14 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int events_per_period = params_period_size(hw_params); mutex_lock(&dice->mutex); - err = snd_dice_stream_reserve_duplex(dice, rate); + // For double_pcm_frame quirk. + if (rate > 96000) + events_per_period /= 2; + err = snd_dice_stream_reserve_duplex(dice, rate, + events_per_period); if (err >= 0) ++dice->substreams_counter; mutex_unlock(&dice->mutex); diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index f6a8627ae5a2..ef36bf588d11 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -278,7 +278,8 @@ static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, snd_dice_transaction_clear_enable(dice); } -int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) +int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, + unsigned int events_per_period) { unsigned int curr_rate; int err; @@ -324,6 +325,11 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) &rx_params); if (err < 0) goto error; + + err = amdtp_domain_set_events_per_period(&dice->domain, + events_per_period); + if (err < 0) + goto error; } return 0; diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index fa6d74303f54..1f9e3502974e 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -210,7 +210,8 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice); void snd_dice_stream_stop_duplex(struct snd_dice *dice); int snd_dice_stream_init_duplex(struct snd_dice *dice); void snd_dice_stream_destroy_duplex(struct snd_dice *dice); -int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate); +int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, + unsigned int events_per_period); void snd_dice_stream_update_duplex(struct snd_dice *dice); int snd_dice_stream_detect_current_formats(struct snd_dice *dice); -- cgit From 18b7f18ff694983c69523e8136f9a256596edd59 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:21 +0900 Subject: ALSA: firewire-digi00x: register the size of PCM period to AMDTP domain This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-7-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/digi00x/digi00x-midi.c | 2 +- sound/firewire/digi00x/digi00x-pcm.c | 4 +++- sound/firewire/digi00x/digi00x-stream.c | 11 ++++++++++- sound/firewire/digi00x/digi00x.h | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c index 2b57ece89101..a407e795d8e7 100644 --- a/sound/firewire/digi00x/digi00x-midi.c +++ b/sound/firewire/digi00x/digi00x-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) return err; mutex_lock(&dg00x->mutex); - err = snd_dg00x_stream_reserve_duplex(dg00x, 0); + err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0); if (err >= 0) { ++dg00x->substreams_counter; err = snd_dg00x_stream_start_duplex(dg00x); diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 18e561b26625..9ced309d61fa 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -167,9 +167,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); mutex_lock(&dg00x->mutex); - err = snd_dg00x_stream_reserve_duplex(dg00x, rate); + err = snd_dg00x_stream_reserve_duplex(dg00x, rate, + frames_per_period); if (err >= 0) ++dg00x->substreams_counter; mutex_unlock(&dg00x->mutex); diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index d6a92460060f..96d331e47b07 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -283,7 +283,8 @@ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x) destroy_stream(dg00x, &dg00x->tx_stream); } -int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate) +int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -315,6 +316,14 @@ int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate) fw_iso_resources_free(&dg00x->rx_resources); return err; } + + err = amdtp_domain_set_events_per_period(&dg00x->domain, + frames_per_period); + if (err < 0) { + fw_iso_resources_free(&dg00x->rx_resources); + fw_iso_resources_free(&dg00x->tx_resources); + return err; + } } return 0; diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index 8041c65f2736..d93694282568 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h @@ -141,7 +141,8 @@ int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x, int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect); int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x); -int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate); +int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate, + unsigned int frames_per_period); int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x); void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x); void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x); -- cgit From 262542ed93921c2632abb8a900daecff2b28057c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:22 +0900 Subject: ALSA: firewire-tascam: register the size of PCM period to AMDTP domain This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-8-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/tascam/tascam-pcm.c | 4 +++- sound/firewire/tascam/tascam-stream.c | 11 ++++++++++- sound/firewire/tascam/tascam.h | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 2377732caa52..cea26d5eff1a 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -99,9 +99,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); mutex_lock(&tscm->mutex); - err = snd_tscm_stream_reserve_duplex(tscm, rate); + err = snd_tscm_stream_reserve_duplex(tscm, rate, + frames_per_period); if (err >= 0) ++tscm->substreams_counter; mutex_unlock(&tscm->mutex); diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index adf69a520b80..8c04a0ad17d9 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -383,7 +383,8 @@ void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm) destroy_stream(tscm, &tscm->tx_stream); } -int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate) +int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -413,6 +414,14 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate) fw_iso_resources_free(&tscm->tx_resources); return err; } + + err = amdtp_domain_set_events_per_period(&tscm->domain, + frames_per_period); + if (err < 0) { + fw_iso_resources_free(&tscm->tx_resources); + fw_iso_resources_free(&tscm->rx_resources); + return err; + } } return 0; diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index 15bd335fa07f..32e72a25bf46 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h @@ -168,7 +168,8 @@ int snd_tscm_stream_get_clock(struct snd_tscm *tscm, int snd_tscm_stream_init_duplex(struct snd_tscm *tscm); void snd_tscm_stream_update_duplex(struct snd_tscm *tscm); void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm); -int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate); +int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, + unsigned int frames_per_period); int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate); void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm); -- cgit From 0d39cd0e449925a6221da48835ef962cd72f330f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:23 +0900 Subject: ALSA: firewire-motu: register the size of PCM period to AMDTP domain This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-9-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-midi.c | 2 +- sound/firewire/motu/motu-pcm.c | 4 +++- sound/firewire/motu/motu-stream.c | 11 ++++++++++- sound/firewire/motu/motu.h | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-midi.c b/sound/firewire/motu/motu-midi.c index 46a0035df31e..997dd6c8ec31 100644 --- a/sound/firewire/motu/motu-midi.c +++ b/sound/firewire/motu/motu-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) mutex_lock(&motu->mutex); - err = snd_motu_stream_reserve_duplex(motu, 0); + err = snd_motu_stream_reserve_duplex(motu, 0, 0); if (err >= 0) { ++motu->substreams_counter; err = snd_motu_stream_start_duplex(motu); diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index aa2e584da6fe..9a54c562494b 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -202,9 +202,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); mutex_lock(&motu->mutex); - err = snd_motu_stream_reserve_duplex(motu, rate); + err = snd_motu_stream_reserve_duplex(motu, rate, + frames_per_period); if (err >= 0) ++motu->substreams_counter; mutex_unlock(&motu->mutex); diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 813e38e6a86e..52b7c375bb0b 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -133,7 +133,8 @@ int snd_motu_stream_cache_packet_formats(struct snd_motu *motu) return 0; } -int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate) +int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -171,6 +172,14 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate) fw_iso_resources_free(&motu->tx_resources); return err; } + + err = amdtp_domain_set_events_per_period(&motu->domain, + frames_per_period); + if (err < 0) { + fw_iso_resources_free(&motu->tx_resources); + fw_iso_resources_free(&motu->rx_resources); + return err; + } } return 0; diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index 350ee2c16f4a..a419e6e7daed 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -154,7 +154,8 @@ void snd_motu_transaction_unregister(struct snd_motu *motu); int snd_motu_stream_init_duplex(struct snd_motu *motu); void snd_motu_stream_destroy_duplex(struct snd_motu *motu); int snd_motu_stream_cache_packet_formats(struct snd_motu *motu); -int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate); +int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, + unsigned int frames_per_period); int snd_motu_stream_start_duplex(struct snd_motu *motu); void snd_motu_stream_stop_duplex(struct snd_motu *motu); int snd_motu_stream_lock_try(struct snd_motu *motu); -- cgit From 9d9ff58c2f45f2bf926f7ee7c70bcc01bad4c0e8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:24 +0900 Subject: ALSA: fireface: register the size of PCM period to AMDTP domain This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-10-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-pcm.c | 3 ++- sound/firewire/fireface/ff-stream.c | 11 ++++++++++- sound/firewire/fireface/ff.h | 3 ++- 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index 9eab3ad283ce..4f2208202494 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -211,9 +211,10 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params); mutex_lock(&ff->mutex); - err = snd_ff_stream_reserve_duplex(ff, rate); + err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period); if (err >= 0) ++ff->substreams_counter; mutex_unlock(&ff->mutex); diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index e8e6f9fd6433..d05e7d3055e1 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -106,7 +106,8 @@ void snd_ff_stream_destroy_duplex(struct snd_ff *ff) destroy_stream(ff, &ff->tx_stream); } -int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate) +int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; enum snd_ff_clock_src src; @@ -150,6 +151,14 @@ int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate) err = ff->spec->protocol->allocate_resources(ff, rate); if (err < 0) return err; + + err = amdtp_domain_set_events_per_period(&ff->domain, + frames_per_period); + if (err < 0) { + fw_iso_resources_free(&ff->tx_resources); + fw_iso_resources_free(&ff->rx_resources); + return err; + } } return 0; diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index b4c22ca6079e..970d4ae571ee 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -139,7 +139,8 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc, enum snd_ff_stream_mode *mode); int snd_ff_stream_init_duplex(struct snd_ff *ff); void snd_ff_stream_destroy_duplex(struct snd_ff *ff); -int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate); +int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate, + unsigned int frames_per_period); int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate); void snd_ff_stream_stop_duplex(struct snd_ff *ff); void snd_ff_stream_update_duplex(struct snd_ff *ff); -- cgit From a80b29a41df097fbad6ab7106c0e6c972f1454b9 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:25 +0900 Subject: ALSA: bebob: use the same size of period for PCM substream in AMDTP streams In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream. The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger. This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression. Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue. This commit replaces the check with the substream count and the value for the size of PCM period. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-11-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_pcm.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 3b2227abf8a9..516c9874f4a1 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -129,18 +129,17 @@ end: return err; } -static int -pcm_open(struct snd_pcm_substream *substream) +static int pcm_open(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; const struct snd_bebob_rate_spec *spec = bebob->spec->rate; - unsigned int sampling_rate; + struct amdtp_domain *d = &bebob->domain; enum snd_bebob_clock_type src; int err; err = snd_bebob_stream_lock_try(bebob); if (err < 0) - goto end; + return err; err = pcm_init_hw_params(bebob, substream); if (err < 0) @@ -150,15 +149,19 @@ pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked; - /* - * When source of clock is internal or any PCM stream are running, - * the available sampling rate is limited at current sampling rate. - */ + mutex_lock(&bebob->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL || - amdtp_stream_pcm_running(&bebob->tx_stream) || - amdtp_stream_pcm_running(&bebob->rx_stream)) { + (bebob->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int sampling_rate; + err = spec->get(bebob, &sampling_rate); if (err < 0) { + mutex_unlock(&bebob->mutex); dev_err(&bebob->unit->device, "fail to get sampling rate: %d\n", err); goto err_locked; @@ -166,11 +169,23 @@ pcm_open(struct snd_pcm_substream *substream) substream->runtime->hw.rate_min = sampling_rate; substream->runtime->hw.rate_max = sampling_rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&bebob->mutex); + goto err_locked; + } + } } + mutex_unlock(&bebob->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_bebob_stream_lock_release(bebob); return err; -- cgit From 56faf928db4f68a76274d1675c11279357576226 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:26 +0900 Subject: ALSA: fireworks: use the same size of period for PCM substream in AMDTP streams In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream. The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger. This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression. Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue. This commit replaces the check with the substream count and the value for the size of PCM period. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-12-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks_pcm.c | 39 +++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 35fc95283423..314d1f8b8344 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -173,13 +173,13 @@ end: static int pcm_open(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - unsigned int sampling_rate; + struct amdtp_domain *d = &efw->domain; enum snd_efw_clock_source clock_source; int err; err = snd_efw_stream_lock_try(efw); if (err < 0) - goto end; + return err; err = pcm_init_hw_params(efw, substream); if (err < 0) @@ -189,23 +189,40 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked; - /* - * When source of clock is not internal or any PCM streams are running, - * available sampling rate is limited at current sampling rate. - */ + mutex_lock(&efw->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) || - amdtp_stream_pcm_running(&efw->tx_stream) || - amdtp_stream_pcm_running(&efw->rx_stream)) { + (efw->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int sampling_rate; + err = snd_efw_command_get_sampling_rate(efw, &sampling_rate); - if (err < 0) + if (err < 0) { + mutex_unlock(&efw->mutex); goto err_locked; + } substream->runtime->hw.rate_min = sampling_rate; substream->runtime->hw.rate_max = sampling_rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&efw->mutex); + goto err_locked; + } + } } + mutex_unlock(&efw->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_efw_stream_lock_release(efw); return err; -- cgit From c0ede398b52654edb8b2a90be69dec2fb966f483 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:27 +0900 Subject: ALSA: oxfw: use the same size of period for PCM substream in AMDTP streams In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream. The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger. This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression. Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue. This commit replaces the check with the substream count and the value for the size of PCM period. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-13-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-pcm.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 2d1b5038f7f6..f3e25898d270 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -170,30 +170,47 @@ end: static int pcm_open(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; + struct amdtp_domain *d = &oxfw->domain; int err; err = snd_oxfw_stream_lock_try(oxfw); if (err < 0) - goto end; + return err; err = init_hw_params(oxfw, substream); if (err < 0) goto err_locked; - /* - * When any PCM streams are already running, the available sampling - * rate is limited at current value. - */ - if (amdtp_stream_pcm_running(&oxfw->tx_stream) || - amdtp_stream_pcm_running(&oxfw->rx_stream)) { + mutex_lock(&oxfw->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (oxfw->substreams_count > 0 && d->events_per_period > 0) { + unsigned int frames_per_period = d->events_per_period; + err = limit_to_current_params(substream); - if (err < 0) - goto end; + if (err < 0) { + mutex_unlock(&oxfw->mutex); + goto err_locked; + } + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&oxfw->mutex); + goto err_locked; + } + } } + mutex_unlock(&oxfw->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_oxfw_stream_lock_release(oxfw); return err; -- cgit From a8fb2248028d49b250e8ad686bc7362b1ee4297f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:28 +0900 Subject: ALSA: dice: use the same size of period for PCM substream in AMDTP streams In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream. The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger. This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression. Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue. This commit replaces the check with the substream count and the value for the size of PCM period. Dice hardware has a quirk called as 'Dual Wire'. For a case of higher sampling transmission frequency, this commit performs calculations between the number of PCM frames and the number of events in AMDTP stream. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-14-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-pcm.c | 43 ++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 570456a7751d..813c9ffbeced 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -164,13 +164,14 @@ static int init_hw_info(struct snd_dice *dice, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_dice *dice = substream->private_data; + struct amdtp_domain *d = &dice->domain; unsigned int source; bool internal; int err; err = snd_dice_stream_lock_try(dice); if (err < 0) - goto end; + return err; err = init_hw_info(dice, substream); if (err < 0) @@ -195,27 +196,45 @@ static int pcm_open(struct snd_pcm_substream *substream) break; } - /* - * When source of clock is not internal or any PCM streams are running, - * available sampling rate is limited at current sampling rate. - */ + mutex_lock(&dice->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if (!internal || - amdtp_stream_pcm_running(&dice->tx_stream[0]) || - amdtp_stream_pcm_running(&dice->tx_stream[1]) || - amdtp_stream_pcm_running(&dice->rx_stream[0]) || - amdtp_stream_pcm_running(&dice->rx_stream[1])) { + (dice->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; unsigned int rate; err = snd_dice_transaction_get_rate(dice, &rate); - if (err < 0) + if (err < 0) { + mutex_unlock(&dice->mutex); goto err_locked; + } + substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + // For double_pcm_frame quirk. + if (rate > 96000) + frames_per_period *= 2; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&dice->mutex); + goto err_locked; + } + } } + mutex_unlock(&dice->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_dice_stream_lock_release(dice); return err; -- cgit From c36f8fcc584ce8b54916e4ebdab476288b245e90 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:29 +0900 Subject: ALSA: firewire-digi00x: use the same size of period for PCM substream in AMDTP streams In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream. The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger. This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression. Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue. This commit replaces the check with the substream count and the value for the size of PCM period. I note that DOT AMDTP protocol has a quirk to use different transmission method of IEC 61883-6 for tx/rx streams; non-blocking in tx stream and blocking in rx stream. Although the difference of transmission method between tx/rx streams precisely brings different timing for a certain amount of events due to their different calculation for data blocks per packet, it's possible to approximate enough amount of events mostly has the same timing. Actually current ALSA IEC 61883-1/6 engine uses large amount of data blocks for each hardware IRQ (=16 packets). Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-15-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/digi00x/digi00x-pcm.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 9ced309d61fa..8dbfb3ff17f6 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -100,14 +100,14 @@ static int pcm_init_hw_params(struct snd_dg00x *dg00x, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_dg00x *dg00x = substream->private_data; + struct amdtp_domain *d = &dg00x->domain; enum snd_dg00x_clock clock; bool detect; - unsigned int rate; int err; err = snd_dg00x_stream_lock_try(dg00x); if (err < 0) - goto end; + return err; err = pcm_init_hw_params(dg00x, substream); if (err < 0) @@ -127,19 +127,40 @@ static int pcm_open(struct snd_pcm_substream *substream) } } + mutex_lock(&dg00x->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if ((clock != SND_DG00X_CLOCK_INTERNAL) || - amdtp_stream_pcm_running(&dg00x->rx_stream) || - amdtp_stream_pcm_running(&dg00x->tx_stream)) { + (dg00x->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int rate; + err = snd_dg00x_stream_get_external_rate(dg00x, &rate); - if (err < 0) + if (err < 0) { + mutex_unlock(&dg00x->mutex); goto err_locked; + } substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&dg00x->mutex); + goto err_locked; + } + } } + mutex_unlock(&dg00x->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_dg00x_stream_lock_release(dg00x); return err; -- cgit From 6669a11d35bfa37f319da639594cdcbb164085f4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:30 +0900 Subject: ALSA: firewire-tascam: use the same size of period for PCM substream in AMDTP streams In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream. The number of PCM substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger. This commit replaces the check with the substream count and the value for the size of PCM period. Unlike the other drivers in ALSA firewire stack, no MIDI substream is multiplexed into AMDTP stream. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-16-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/tascam/tascam-pcm.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index cea26d5eff1a..6cd3a420fbdf 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -43,13 +43,13 @@ static int pcm_init_hw_params(struct snd_tscm *tscm, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_tscm *tscm = substream->private_data; + struct amdtp_domain *d = &tscm->domain; enum snd_tscm_clock clock; - unsigned int rate; int err; err = snd_tscm_stream_lock_try(tscm); if (err < 0) - goto end; + return err; err = pcm_init_hw_params(tscm, substream); if (err < 0) @@ -59,19 +59,37 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked; - if (clock != SND_TSCM_CLOCK_INTERNAL || - amdtp_stream_pcm_running(&tscm->rx_stream) || - amdtp_stream_pcm_running(&tscm->tx_stream)) { + mutex_lock(&tscm->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) { + unsigned int frames_per_period = d->events_per_period; + unsigned int rate; + err = snd_tscm_stream_get_rate(tscm, &rate); - if (err < 0) + if (err < 0) { + mutex_unlock(&tscm->mutex); goto err_locked; + } substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&tscm->mutex); + goto err_locked; + } } + mutex_unlock(&tscm->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_tscm_stream_lock_release(tscm); return err; -- cgit From 3fd80b2003882b6a328caff9e6b3a14bed61f27c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:31 +0900 Subject: ALSA: firewire-motu: use the same size of period for PCM substream in AMDTP streams In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream. The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger. This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression. Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue. This commit replaces the check with the substream count and the value for the size of PCM period. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-17-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-pcm.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 9a54c562494b..7bbf8b86a33d 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -134,8 +134,8 @@ static int pcm_open(struct snd_pcm_substream *substream) { struct snd_motu *motu = substream->private_data; const struct snd_motu_protocol *const protocol = motu->spec->protocol; + struct amdtp_domain *d = &motu->domain; enum snd_motu_clock_source src; - unsigned int rate; int err; err = snd_motu_stream_lock_try(motu); @@ -152,28 +152,41 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked; - /* - * When source of clock is not internal or any PCM streams are running, - * available sampling rate is limited at current sampling rate. - */ err = protocol->get_clock_source(motu, &src); if (err < 0) goto err_locked; + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL || - amdtp_stream_pcm_running(&motu->tx_stream) || - amdtp_stream_pcm_running(&motu->rx_stream)) { + (motu->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int rate; + err = protocol->get_clock_rate(motu, &rate); if (err < 0) goto err_locked; + substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&motu->mutex); + goto err_locked; + } + } } snd_pcm_set_sync(substream); mutex_unlock(&motu->mutex); - return err; + return 0; err_locked: mutex_unlock(&motu->mutex); snd_motu_stream_lock_release(motu); -- cgit From 3aac32634172819ede79426c85e0a43ee7fcc3b3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 7 Oct 2019 20:05:32 +0900 Subject: ALSA: fireface: use the same size of period for PCM substreams in AMDTP streams In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream. The number of PCM substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger. This commit replaces the check with the substream count and the value for the size of PCM period. Unlike the other drivers in ALSA firewire stack, no MIDI substream is multiplexed into AMDTP stream. I note that Fireface AMDTP protocol has a quirk that tx stream includes blank isochronous cycle. The packet for blank cycle is equivalent to empty or NODATA packet in IEC 61883-6, thus the protocol is similar to blocking transmission method of IEC 61883-6. On the other hand, rx stream adopts non-blocking transmission method. Although the difference of transmission method between tx/rx streams precisely brings different timing for a certain amount of events due to their different calculation for data blocks per packet, it's possible to approximate enough amount of events mostly has the same timing. Actually current ALSA IEC 61883-1/6 engine uses large amount of data blocks for each hardware IRQ (=16 packets). Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191007110532.30270-18-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-pcm.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index 4f2208202494..415bc9ccd1c7 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -139,6 +139,7 @@ static int pcm_init_hw_params(struct snd_ff *ff, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_ff *ff = substream->private_data; + struct amdtp_domain *d = &ff->domain; unsigned int rate; enum snd_ff_clock_src src; int i, err; @@ -155,16 +156,21 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto release_lock; + mutex_lock(&ff->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if (src != SND_FF_CLOCK_SRC_INTERNAL) { for (i = 0; i < CIP_SFC_COUNT; ++i) { if (amdtp_rate_table[i] == rate) break; } - /* - * The unit is configured at sampling frequency which packet - * streaming engine can't support. - */ + + // The unit is configured at sampling frequency which packet + // streaming engine can't support. if (i >= CIP_SFC_COUNT) { + mutex_unlock(&ff->mutex); err = -EIO; goto release_lock; } @@ -172,14 +178,25 @@ static int pcm_open(struct snd_pcm_substream *substream) substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; } else { - if (amdtp_stream_pcm_running(&ff->rx_stream) || - amdtp_stream_pcm_running(&ff->tx_stream)) { + if (ff->substreams_counter > 0) { + unsigned int frames_per_period = d->events_per_period; + rate = amdtp_rate_table[ff->rx_stream.sfc]; substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&ff->mutex); + goto release_lock; + } } } + mutex_unlock(&ff->mutex); + snd_pcm_set_sync(substream); return 0; -- cgit From a0e023317e2d55c6b2fbf342c12d8a59797e1cff Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:13 +0900 Subject: ALSA: firewire-lib: use variable size of queue for isoc packets instead of fixed size The number of packets in packet buffer has been fixed number (=48) since first commit of ALSA IEC 61883-1/6 packet streaming engine. This commit allows the engine to use variable number of packets in the buffer. The size is calculated by a parameter in AMDTP domain structure surely to store the number of events in the packets of buffer. Although the value of parameter is expected to come from 'period size' parameter of PCM substream, at present 48 is still used. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 45 ++++++++++++++++++----------- sound/firewire/amdtp-stream.h | 6 +++- sound/firewire/bebob/bebob_stream.c | 2 +- sound/firewire/dice/dice-stream.c | 2 +- sound/firewire/digi00x/digi00x-stream.c | 2 +- sound/firewire/fireface/ff-stream.c | 2 +- sound/firewire/fireworks/fireworks_stream.c | 2 +- sound/firewire/motu/motu-stream.c | 2 +- sound/firewire/oxfw/oxfw-stream.c | 2 +- sound/firewire/tascam/tascam-stream.c | 2 +- 10 files changed, 41 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 838f695b20de..1f38729c8e74 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -54,7 +54,6 @@ /* TODO: make these configurable */ #define INTERRUPT_INTERVAL 16 -#define QUEUE_LENGTH 48 // For iso header, tstamp and 2 CIP header. #define IR_CTX_HEADER_SIZE_CIP 16 @@ -451,7 +450,7 @@ static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params) goto end; } - if (++s->packet_index >= QUEUE_LENGTH) + if (++s->packet_index >= s->queue_size) s->packet_index = 0; end: return err; @@ -669,13 +668,14 @@ static inline u32 increment_cycle_count(u32 cycle, unsigned int addend) } // Align to actual cycle count for the packet which is going to be scheduled. -// This module queued the same number of isochronous cycle as QUEUE_LENGTH to -// skip isochronous cycle, therefore it's OK to just increment the cycle by -// QUEUE_LENGTH for scheduled cycle. -static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp) +// This module queued the same number of isochronous cycle as the size of queue +// to kip isochronous cycle, therefore it's OK to just increment the cycle by +// the size of queue for scheduled cycle. +static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp, + unsigned int queue_size) { u32 cycle = compute_cycle_count(ctx_header_tstamp); - return increment_cycle_count(cycle, QUEUE_LENGTH); + return increment_cycle_count(cycle, queue_size); } static int generate_device_pkt_descs(struct amdtp_stream *s, @@ -689,7 +689,7 @@ static int generate_device_pkt_descs(struct amdtp_stream *s, for (i = 0; i < packets; ++i) { struct pkt_desc *desc = descs + i; - unsigned int index = (s->packet_index + i) % QUEUE_LENGTH; + unsigned int index = (s->packet_index + i) % s->queue_size; unsigned int cycle; unsigned int payload_length; unsigned int data_blocks; @@ -730,9 +730,9 @@ static void generate_ideal_pkt_descs(struct amdtp_stream *s, for (i = 0; i < packets; ++i) { struct pkt_desc *desc = descs + i; - unsigned int index = (s->packet_index + i) % QUEUE_LENGTH; + unsigned int index = (s->packet_index + i) % s->queue_size; - desc->cycle = compute_it_cycle(*ctx_header); + desc->cycle = compute_it_cycle(*ctx_header, s->queue_size); desc->syt = calculate_syt(s, desc->cycle); desc->data_blocks = calculate_data_blocks(s, desc->syt); @@ -779,12 +779,15 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, { struct amdtp_stream *s = private_data; const __be32 *ctx_header = header; - unsigned int packets = header_length / sizeof(*ctx_header); + unsigned int packets; int i; if (s->packet_index < 0) return; + // Calculate the number of packets in buffer and check XRUN. + packets = header_length / sizeof(*ctx_header); + generate_ideal_pkt_descs(s, s->pkt_descs, ctx_header, packets); process_ctx_payloads(s, s->pkt_descs, packets); @@ -828,7 +831,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, if (s->packet_index < 0) return; - // The number of packets in buffer. + // Calculate the number of packets in buffer and check XRUN. packets = header_length / s->ctx_data.tx.ctx_header_size; err = generate_device_pkt_descs(s, s->pkt_descs, ctx_header, packets); @@ -874,7 +877,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, context->callback.sc = in_stream_callback; } else { - cycle = compute_it_cycle(*ctx_header); + cycle = compute_it_cycle(*ctx_header, s->queue_size); context->callback.sc = out_stream_callback; } @@ -894,7 +897,8 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI * device can be started. */ -static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) +static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, + struct amdtp_domain *d) { static const struct { unsigned int data_block; @@ -908,6 +912,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) [CIP_SFC_88200] = { 0, 67 }, [CIP_SFC_176400] = { 0, 67 }, }; + unsigned int events_per_buffer = d->events_per_buffer; unsigned int ctx_header_size; unsigned int max_ctx_payload_size; enum dma_data_direction dir; @@ -953,7 +958,13 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP; } - err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH, + if (events_per_buffer == 0) + events_per_buffer = INTERRUPT_INTERVAL * 3; + + s->queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer, + amdtp_rate_table[s->sfc]); + + err = iso_packets_buffer_init(&s->buffer, s->unit, s->queue_size, max_ctx_payload_size, dir); if (err < 0) goto err_unlock; @@ -981,7 +992,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) else s->tag = TAG_CIP; - s->pkt_descs = kcalloc(INTERRUPT_INTERVAL, sizeof(*s->pkt_descs), + s->pkt_descs = kcalloc(s->queue_size, sizeof(*s->pkt_descs), GFP_KERNEL); if (!s->pkt_descs) { err = -ENOMEM; @@ -1196,7 +1207,7 @@ int amdtp_domain_start(struct amdtp_domain *d) int err = 0; list_for_each_entry(s, &d->streams, list) { - err = amdtp_stream_start(s, s->channel, s->speed); + err = amdtp_stream_start(s, s->channel, s->speed, d); if (err < 0) break; } diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index d95a4ed15f20..8d541727e437 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -117,6 +117,7 @@ struct amdtp_stream { /* For packet processing. */ struct fw_iso_context *context; struct iso_packets_buffer buffer; + unsigned int queue_size; int packet_index; struct pkt_desc *pkt_descs; int tag; @@ -274,6 +275,7 @@ struct amdtp_domain { struct list_head streams; unsigned int events_per_period; + unsigned int events_per_buffer; }; int amdtp_domain_init(struct amdtp_domain *d); @@ -286,9 +288,11 @@ int amdtp_domain_start(struct amdtp_domain *d); void amdtp_domain_stop(struct amdtp_domain *d); static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d, - unsigned int events_per_period) + unsigned int events_per_period, + unsigned int events_per_buffer) { d->events_per_period = events_per_period; + d->events_per_buffer = events_per_buffer; return 0; } diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index f1db3ddc3e00..e8e9eca6f116 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -610,7 +610,7 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate, } err = amdtp_domain_set_events_per_period(&bebob->domain, - frames_per_period); + frames_per_period, 0); if (err < 0) { cmp_connection_release(&bebob->out_conn); cmp_connection_release(&bebob->in_conn); diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index ef36bf588d11..b4ef08bd7e8f 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -327,7 +327,7 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, goto error; err = amdtp_domain_set_events_per_period(&dice->domain, - events_per_period); + events_per_period, 0); if (err < 0) goto error; } diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index 96d331e47b07..83659fc0ef25 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -318,7 +318,7 @@ int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate, } err = amdtp_domain_set_events_per_period(&dg00x->domain, - frames_per_period); + frames_per_period, 0); if (err < 0) { fw_iso_resources_free(&dg00x->rx_resources); fw_iso_resources_free(&dg00x->tx_resources); diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index d05e7d3055e1..cbe0e5087b05 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -153,7 +153,7 @@ int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate, return err; err = amdtp_domain_set_events_per_period(&ff->domain, - frames_per_period); + frames_per_period, 0); if (err < 0) { fw_iso_resources_free(&ff->tx_resources); fw_iso_resources_free(&ff->rx_resources); diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 0787d5c3b01b..e4d4dd08c60a 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -231,7 +231,7 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate, } err = amdtp_domain_set_events_per_period(&efw->domain, - frames_per_period); + frames_per_period, 0); if (err < 0) { cmp_connection_release(&efw->in_conn); cmp_connection_release(&efw->out_conn); diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 52b7c375bb0b..97245c670732 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -174,7 +174,7 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, } err = amdtp_domain_set_events_per_period(&motu->domain, - frames_per_period); + frames_per_period, 0); if (err < 0) { fw_iso_resources_free(&motu->tx_resources); fw_iso_resources_free(&motu->rx_resources); diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 7d2e88c5b73d..318de8217b3a 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -308,7 +308,7 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, } err = amdtp_domain_set_events_per_period(&oxfw->domain, - frames_per_period); + frames_per_period, 0); if (err < 0) { cmp_connection_release(&oxfw->in_conn); if (oxfw->has_output) diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index 8c04a0ad17d9..1e4d44ed8bed 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -416,7 +416,7 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, } err = amdtp_domain_set_events_per_period(&tscm->domain, - frames_per_period); + frames_per_period, 0); if (err < 0) { fw_iso_resources_free(&tscm->tx_resources); fw_iso_resources_free(&tscm->rx_resources); -- cgit From 1fde7a447a7f423b893ac3fcac0ba65893924189 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:14 +0900 Subject: ALSA: bebob: share PCM buffer size for both direction This commit allows ALSA bebob driver to share PCM buffer size for both capture and playback PCM substream. When AMDTP domain starts for one of the PCM substream, buffer size of the PCM substream is stores to AMDTP domain structure. Some AMDTP streams have already run with the buffer size when another PCM substream starts, therefore the PCM substream has a constraint to its buffer size. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.h | 3 ++- sound/firewire/bebob/bebob_midi.c | 2 +- sound/firewire/bebob/bebob_pcm.c | 12 +++++++++++- sound/firewire/bebob/bebob_stream.c | 5 +++-- 4 files changed, 17 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 8738c1d8abf7..d1ad9a8451bc 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -218,7 +218,8 @@ int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob, int snd_bebob_stream_discover(struct snd_bebob *bebob); int snd_bebob_stream_init_duplex(struct snd_bebob *bebob); int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate, - unsigned int frames_per_period); + unsigned int frames_per_period, + unsigned int frames_per_buffer); int snd_bebob_stream_start_duplex(struct snd_bebob *bebob); void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob); void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob); diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c index e8f9edf50be5..6f597d03e7c1 100644 --- a/sound/firewire/bebob/bebob_midi.c +++ b/sound/firewire/bebob/bebob_midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) return err; mutex_lock(&bebob->mutex); - err = snd_bebob_stream_reserve_duplex(bebob, 0, 0); + err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0); if (err >= 0) { ++bebob->substreams_counter; err = snd_bebob_stream_start_duplex(bebob); diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 516c9874f4a1..8b2e0ceffe82 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -157,6 +157,7 @@ static int pcm_open(struct snd_pcm_substream *substream) if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL || (bebob->substreams_counter > 0 && d->events_per_period > 0)) { unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; unsigned int sampling_rate; err = spec->get(bebob, &sampling_rate); @@ -178,6 +179,14 @@ static int pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&bebob->mutex); goto err_locked; } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) { + mutex_unlock(&bebob->mutex); + goto err_locked; + } } } @@ -213,10 +222,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); mutex_lock(&bebob->mutex); err = snd_bebob_stream_reserve_duplex(bebob, rate, - frames_per_period); + frames_per_period, frames_per_buffer); if (err >= 0) ++bebob->substreams_counter; mutex_unlock(&bebob->mutex); diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index e8e9eca6f116..5e4a61458be2 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -555,7 +555,8 @@ static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream, } int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate, - unsigned int frames_per_period) + unsigned int frames_per_period, + unsigned int frames_per_buffer) { unsigned int curr_rate; int err; @@ -610,7 +611,7 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate, } err = amdtp_domain_set_events_per_period(&bebob->domain, - frames_per_period, 0); + frames_per_period, frames_per_buffer); if (err < 0) { cmp_connection_release(&bebob->out_conn); cmp_connection_release(&bebob->in_conn); -- cgit From 659c6af569a2bd08b3b3c1f5e445a58510de02c8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:15 +0900 Subject: ALSA: fireworks: share PCM buffer size for both direction This commit allows ALSA fireworks driver to share PCM buffer size for both capture and playback PCM substream. When AMDTP domain starts for one of the PCM substream, buffer size of the PCM substream is stores to AMDTP domain structure. Some AMDTP streams have already run with the buffer size when another PCM substream starts, therefore the PCM substream has a constraint to its buffer size. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks.h | 3 ++- sound/firewire/fireworks/fireworks_midi.c | 2 +- sound/firewire/fireworks/fireworks_pcm.c | 12 +++++++++++- sound/firewire/fireworks/fireworks_stream.c | 5 +++-- 4 files changed, 17 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index fc5f945a49ff..dda797209a27 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -208,7 +208,8 @@ int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate); int snd_efw_stream_init_duplex(struct snd_efw *efw); int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate, - unsigned int frames_per_period); + unsigned int frames_per_period, + unsigned int frames_per_buffer); int snd_efw_stream_start_duplex(struct snd_efw *efw); void snd_efw_stream_stop_duplex(struct snd_efw *efw); void snd_efw_stream_update_duplex(struct snd_efw *efw); diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index e593f842ee8f..84621e356848 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) goto end; mutex_lock(&efw->mutex); - err = snd_efw_stream_reserve_duplex(efw, 0, 0); + err = snd_efw_stream_reserve_duplex(efw, 0, 0, 0); if (err >= 0) { ++efw->substreams_counter; err = snd_efw_stream_start_duplex(efw); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 314d1f8b8344..abcc53dac8a5 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -197,6 +197,7 @@ static int pcm_open(struct snd_pcm_substream *substream) if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) || (efw->substreams_counter > 0 && d->events_per_period > 0)) { unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; unsigned int sampling_rate; err = snd_efw_command_get_sampling_rate(efw, &sampling_rate); @@ -215,6 +216,14 @@ static int pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&efw->mutex); goto err_locked; } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) { + mutex_unlock(&efw->mutex); + goto err_locked; + } } } @@ -249,10 +258,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); mutex_lock(&efw->mutex); err = snd_efw_stream_reserve_duplex(efw, rate, - frames_per_period); + frames_per_period, frames_per_buffer); if (err >= 0) ++efw->substreams_counter; mutex_unlock(&efw->mutex); diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index e4d4dd08c60a..f35a33d4d4e6 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -182,7 +182,8 @@ static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream, } int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate, - unsigned int frames_per_period) + unsigned int frames_per_period, + unsigned int frames_per_buffer) { unsigned int curr_rate; int err; @@ -231,7 +232,7 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate, } err = amdtp_domain_set_events_per_period(&efw->domain, - frames_per_period, 0); + frames_per_period, frames_per_buffer); if (err < 0) { cmp_connection_release(&efw->in_conn); cmp_connection_release(&efw->out_conn); -- cgit From 3299d2a0f74c0774da0672d0bc54741da4bbda6e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:16 +0900 Subject: ALSA: oxfw: share PCM buffer size for both direction This commit allows ALSA oxfw driver to share PCM buffer size for both capture and playback PCM substream. When AMDTP domain starts for one of the PCM substream, buffer size of the PCM substream is stores to AMDTP domain structure. Some AMDTP streams have already run with the buffer size when another PCM substream starts, therefore the PCM substream has a constraint to its buffer size. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-midi.c | 4 ++-- sound/firewire/oxfw/oxfw-pcm.c | 17 +++++++++++++++-- sound/firewire/oxfw/oxfw-stream.c | 5 +++-- sound/firewire/oxfw/oxfw.h | 3 ++- 4 files changed, 22 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index 72db7a17d0ad..775cba3f1f02 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -18,7 +18,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0); if (err >= 0) { ++oxfw->substreams_count; err = snd_oxfw_stream_start_duplex(oxfw); @@ -45,7 +45,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0); if (err >= 0) { ++oxfw->substreams_count; err = snd_oxfw_stream_start_duplex(oxfw); diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index f3e25898d270..ba586d1ac91d 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -188,6 +188,7 @@ static int pcm_open(struct snd_pcm_substream *substream) // at current one. if (oxfw->substreams_count > 0 && d->events_per_period > 0) { unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; err = limit_to_current_params(substream); if (err < 0) { @@ -203,6 +204,14 @@ static int pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&oxfw->mutex); goto err_locked; } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) { + mutex_unlock(&oxfw->mutex); + goto err_locked; + } } } @@ -239,10 +248,12 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); mutex_lock(&oxfw->mutex); err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, - rate, channels, frames_per_period); + rate, channels, frames_per_period, + frames_per_buffer); if (err >= 0) ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); @@ -265,10 +276,12 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); mutex_lock(&oxfw->mutex); err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, - rate, channels, frames_per_period); + rate, channels, frames_per_period, + frames_per_buffer); if (err >= 0) ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 318de8217b3a..995e9c5bd84b 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -245,7 +245,8 @@ static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream) int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, unsigned int rate, unsigned int pcm_channels, - unsigned int frames_per_period) + unsigned int frames_per_period, + unsigned int frames_per_buffer) { struct snd_oxfw_stream_formation formation; enum avc_general_plug_dir dir; @@ -308,7 +309,7 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, } err = amdtp_domain_set_events_per_period(&oxfw->domain, - frames_per_period, 0); + frames_per_period, frames_per_buffer); if (err < 0) { cmp_connection_release(&oxfw->in_conn); if (oxfw->has_output) diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 422746ef2439..c30e537087b0 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -104,7 +104,8 @@ int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw); int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, unsigned int rate, unsigned int pcm_channels, - unsigned int frames_per_period); + unsigned int frames_per_period, + unsigned int frames_per_buffer); int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw); -- cgit From ecb40fd2c8afdb66da7e309b43c6dc90e419c2dc Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:17 +0900 Subject: ALSA: dice: share PCM buffer size for both direction This commit allows ALSA dice driver to share PCM buffer size for both capture and playback PCM substream. When AMDTP domain starts for one of the PCM substream, buffer size of the PCM substream is stores to AMDTP domain structure. Some AMDTP streams have already run with the buffer size when another PCM substream starts, therefore the PCM substream has a constraint to its buffer size. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-midi.c | 2 +- sound/firewire/dice/dice-pcm.c | 20 +++++++++++++++++--- sound/firewire/dice/dice-stream.c | 5 +++-- sound/firewire/dice/dice.h | 3 ++- 4 files changed, 23 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index 69c3c06bd7aa..4c2998034313 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) mutex_lock(&dice->mutex); - err = snd_dice_stream_reserve_duplex(dice, 0, 0); + err = snd_dice_stream_reserve_duplex(dice, 0, 0, 0); if (err >= 0) { ++dice->substreams_counter; err = snd_dice_stream_start_duplex(dice); diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 813c9ffbeced..7c0c34c5bd47 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -204,6 +204,7 @@ static int pcm_open(struct snd_pcm_substream *substream) if (!internal || (dice->substreams_counter > 0 && d->events_per_period > 0)) { unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; unsigned int rate; err = snd_dice_transaction_get_rate(dice, &rate); @@ -217,8 +218,10 @@ static int pcm_open(struct snd_pcm_substream *substream) if (frames_per_period > 0) { // For double_pcm_frame quirk. - if (rate > 96000) + if (rate > 96000) { frames_per_period *= 2; + frames_per_buffer *= 2; + } err = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, @@ -227,6 +230,14 @@ static int pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&dice->mutex); goto err_locked; } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) { + mutex_unlock(&dice->mutex); + goto err_locked; + } } } @@ -263,13 +274,16 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int events_per_period = params_period_size(hw_params); + unsigned int events_per_buffer = params_buffer_size(hw_params); mutex_lock(&dice->mutex); // For double_pcm_frame quirk. - if (rate > 96000) + if (rate > 96000) { events_per_period /= 2; + events_per_buffer /= 2; + } err = snd_dice_stream_reserve_duplex(dice, rate, - events_per_period); + events_per_period, events_per_buffer); if (err >= 0) ++dice->substreams_counter; mutex_unlock(&dice->mutex); diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index b4ef08bd7e8f..0cff346e8052 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -279,7 +279,8 @@ static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, } int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, - unsigned int events_per_period) + unsigned int events_per_period, + unsigned int events_per_buffer) { unsigned int curr_rate; int err; @@ -327,7 +328,7 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, goto error; err = amdtp_domain_set_events_per_period(&dice->domain, - events_per_period, 0); + events_per_period, events_per_buffer); if (err < 0) goto error; } diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index 1f9e3502974e..16366773e22e 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -211,7 +211,8 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice); int snd_dice_stream_init_duplex(struct snd_dice *dice); void snd_dice_stream_destroy_duplex(struct snd_dice *dice); int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, - unsigned int events_per_period); + unsigned int events_per_period, + unsigned int events_per_buffer); void snd_dice_stream_update_duplex(struct snd_dice *dice); int snd_dice_stream_detect_current_formats(struct snd_dice *dice); -- cgit From 76c4ecbe4b07c0d1b1aba31bf2a7f20cccbdbb4e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:18 +0900 Subject: ALSA: firewire-digi00x: share PCM buffer size for both direction This commit allows ALSA firewire-digi00x driver to share PCM buffer size for both capture and playback PCM substream. When AMDTP domain starts for one of the PCM substream, buffer size of the PCM substream is stores to AMDTP domain structure. Some AMDTP streams have already run with the buffer size when another PCM substream starts, therefore the PCM substream has a constraint to its buffer size. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-7-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/digi00x/digi00x-midi.c | 2 +- sound/firewire/digi00x/digi00x-pcm.c | 12 +++++++++++- sound/firewire/digi00x/digi00x-stream.c | 5 +++-- sound/firewire/digi00x/digi00x.h | 3 ++- 4 files changed, 17 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c index a407e795d8e7..68eb8c39afa6 100644 --- a/sound/firewire/digi00x/digi00x-midi.c +++ b/sound/firewire/digi00x/digi00x-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) return err; mutex_lock(&dg00x->mutex); - err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0); + err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0); if (err >= 0) { ++dg00x->substreams_counter; err = snd_dg00x_stream_start_duplex(dg00x); diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 8dbfb3ff17f6..c9a833dff20d 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -135,6 +135,7 @@ static int pcm_open(struct snd_pcm_substream *substream) if ((clock != SND_DG00X_CLOCK_INTERNAL) || (dg00x->substreams_counter > 0 && d->events_per_period > 0)) { unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; unsigned int rate; err = snd_dg00x_stream_get_external_rate(dg00x, &rate); @@ -153,6 +154,14 @@ static int pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&dg00x->mutex); goto err_locked; } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) { + mutex_unlock(&dg00x->mutex); + goto err_locked; + } } } @@ -189,10 +198,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); mutex_lock(&dg00x->mutex); err = snd_dg00x_stream_reserve_duplex(dg00x, rate, - frames_per_period); + frames_per_period, frames_per_buffer); if (err >= 0) ++dg00x->substreams_counter; mutex_unlock(&dg00x->mutex); diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index 83659fc0ef25..0c539188ba18 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -284,7 +284,8 @@ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x) } int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate, - unsigned int frames_per_period) + unsigned int frames_per_period, + unsigned int frames_per_buffer) { unsigned int curr_rate; int err; @@ -318,7 +319,7 @@ int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate, } err = amdtp_domain_set_events_per_period(&dg00x->domain, - frames_per_period, 0); + frames_per_period, frames_per_buffer); if (err < 0) { fw_iso_resources_free(&dg00x->rx_resources); fw_iso_resources_free(&dg00x->tx_resources); diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index d93694282568..129de8edd5ea 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h @@ -142,7 +142,8 @@ int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect); int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x); int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate, - unsigned int frames_per_period); + unsigned int frames_per_period, + unsigned int frames_per_buffer); int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x); void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x); void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x); -- cgit From 128307d5f947d43a89e68dd8357879a0f111821d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:19 +0900 Subject: ALSA: firewire-tascam: share PCM buffer size for both direction This commit allows ALSA firewire-tascam driver to share PCM buffer size for both capture and playback PCM substream. When AMDTP domain starts for one of the PCM substream, buffer size of the PCM substream is stores to AMDTP domain structure. Some AMDTP streams have already run with the buffer size when another PCM substream starts, therefore the PCM substream has a constraint to its buffer size. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-8-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/tascam/tascam-pcm.c | 12 +++++++++++- sound/firewire/tascam/tascam-stream.c | 5 +++-- sound/firewire/tascam/tascam.h | 3 ++- 3 files changed, 16 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 6cd3a420fbdf..b18664fdf955 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -66,6 +66,7 @@ static int pcm_open(struct snd_pcm_substream *substream) // at current one. if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) { unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; unsigned int rate; err = snd_tscm_stream_get_rate(tscm, &rate); @@ -83,6 +84,14 @@ static int pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&tscm->mutex); goto err_locked; } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) { + mutex_unlock(&tscm->mutex); + goto err_locked; + } } mutex_unlock(&tscm->mutex); @@ -118,10 +127,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); mutex_lock(&tscm->mutex); err = snd_tscm_stream_reserve_duplex(tscm, rate, - frames_per_period); + frames_per_period, frames_per_buffer); if (err >= 0) ++tscm->substreams_counter; mutex_unlock(&tscm->mutex); diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index 1e4d44ed8bed..a9b3b7eb6d21 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -384,7 +384,8 @@ void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm) } int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, - unsigned int frames_per_period) + unsigned int frames_per_period, + unsigned int frames_per_buffer) { unsigned int curr_rate; int err; @@ -416,7 +417,7 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, } err = amdtp_domain_set_events_per_period(&tscm->domain, - frames_per_period, 0); + frames_per_period, frames_per_buffer); if (err < 0) { fw_iso_resources_free(&tscm->tx_resources); fw_iso_resources_free(&tscm->rx_resources); diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index 32e72a25bf46..78b7a08986a1 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h @@ -169,7 +169,8 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm); void snd_tscm_stream_update_duplex(struct snd_tscm *tscm); void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm); int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, - unsigned int frames_per_period); + unsigned int frames_per_period, + unsigned int frames_per_buffer); int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate); void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm); -- cgit From 0f5482e7875bc2d507e6d92fcc8de22ff75fbdda Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:20 +0900 Subject: ALSA: firewire-motu: share PCM buffer size for both direction This commit allows ALSA firewire-motu driver to share PCM buffer size for both capture and playback PCM substream. When AMDTP domain starts for one of the PCM substream, buffer size of the PCM substream is stores to AMDTP domain structure. Some AMDTP streams have already run with the buffer size when another PCM substream starts, therefore the PCM substream has a constraint to its buffer size. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-9-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-midi.c | 2 +- sound/firewire/motu/motu-pcm.c | 12 +++++++++++- sound/firewire/motu/motu-stream.c | 5 +++-- sound/firewire/motu/motu.h | 3 ++- 4 files changed, 17 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-midi.c b/sound/firewire/motu/motu-midi.c index 997dd6c8ec31..2365f7dfde26 100644 --- a/sound/firewire/motu/motu-midi.c +++ b/sound/firewire/motu/motu-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) mutex_lock(&motu->mutex); - err = snd_motu_stream_reserve_duplex(motu, 0, 0); + err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0); if (err >= 0) { ++motu->substreams_counter; err = snd_motu_stream_start_duplex(motu); diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 7bbf8b86a33d..00e693da0cad 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -162,6 +162,7 @@ static int pcm_open(struct snd_pcm_substream *substream) if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL || (motu->substreams_counter > 0 && d->events_per_period > 0)) { unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; unsigned int rate; err = protocol->get_clock_rate(motu, &rate); @@ -179,6 +180,14 @@ static int pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&motu->mutex); goto err_locked; } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) { + mutex_unlock(&motu->mutex); + goto err_locked; + } } } @@ -216,10 +225,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); mutex_lock(&motu->mutex); err = snd_motu_stream_reserve_duplex(motu, rate, - frames_per_period); + frames_per_period, frames_per_buffer); if (err >= 0) ++motu->substreams_counter; mutex_unlock(&motu->mutex); diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 97245c670732..9975770c9b1f 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -134,7 +134,8 @@ int snd_motu_stream_cache_packet_formats(struct snd_motu *motu) } int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, - unsigned int frames_per_period) + unsigned int frames_per_period, + unsigned int frames_per_buffer) { unsigned int curr_rate; int err; @@ -174,7 +175,7 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, } err = amdtp_domain_set_events_per_period(&motu->domain, - frames_per_period, 0); + frames_per_period, frames_per_buffer); if (err < 0) { fw_iso_resources_free(&motu->tx_resources); fw_iso_resources_free(&motu->rx_resources); diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index a419e6e7daed..35ed8b6bb8e8 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -155,7 +155,8 @@ int snd_motu_stream_init_duplex(struct snd_motu *motu); void snd_motu_stream_destroy_duplex(struct snd_motu *motu); int snd_motu_stream_cache_packet_formats(struct snd_motu *motu); int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, - unsigned int frames_per_period); + unsigned int frames_per_period, + unsigned int frames_per_buffer); int snd_motu_stream_start_duplex(struct snd_motu *motu); void snd_motu_stream_stop_duplex(struct snd_motu *motu); int snd_motu_stream_lock_try(struct snd_motu *motu); -- cgit From 4de3eb062e2daf04646d23417a39b8843df4508b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:21 +0900 Subject: ALSA: fireface: share PCM buffer size for both direction This commit allows ALSA fireface driver to share PCM buffer size for both capture and playback PCM substream. When AMDTP domain starts for one of the PCM substream, buffer size of the PCM substream is stores to AMDTP domain structure. Some AMDTP streams have already run with the buffer size when another PCM substream starts, therefore the PCM substream has a constraint to its buffer size. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-10-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-pcm.c | 13 ++++++++++++- sound/firewire/fireface/ff-stream.c | 5 +++-- sound/firewire/fireface/ff.h | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index 415bc9ccd1c7..005d959f8651 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -180,6 +180,7 @@ static int pcm_open(struct snd_pcm_substream *substream) } else { if (ff->substreams_counter > 0) { unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; rate = amdtp_rate_table[ff->rx_stream.sfc]; substream->runtime->hw.rate_min = rate; @@ -192,6 +193,14 @@ static int pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&ff->mutex); goto release_lock; } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) { + mutex_unlock(&ff->mutex); + goto release_lock; + } } } @@ -229,9 +238,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); + unsigned int frames_per_buffer = params_buffer_size(hw_params); mutex_lock(&ff->mutex); - err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period); + err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period, + frames_per_buffer); if (err >= 0) ++ff->substreams_counter; mutex_unlock(&ff->mutex); diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index cbe0e5087b05..a13754f914e8 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -107,7 +107,8 @@ void snd_ff_stream_destroy_duplex(struct snd_ff *ff) } int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate, - unsigned int frames_per_period) + unsigned int frames_per_period, + unsigned int frames_per_buffer) { unsigned int curr_rate; enum snd_ff_clock_src src; @@ -153,7 +154,7 @@ int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate, return err; err = amdtp_domain_set_events_per_period(&ff->domain, - frames_per_period, 0); + frames_per_period, frames_per_buffer); if (err < 0) { fw_iso_resources_free(&ff->tx_resources); fw_iso_resources_free(&ff->rx_resources); diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 970d4ae571ee..dc7a20f75983 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -140,7 +140,8 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc, int snd_ff_stream_init_duplex(struct snd_ff *ff); void snd_ff_stream_destroy_duplex(struct snd_ff *ff); int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate, - unsigned int frames_per_period); + unsigned int frames_per_period, + unsigned int frames_per_buffer); int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate); void snd_ff_stream_stop_duplex(struct snd_ff *ff); void snd_ff_stream_update_duplex(struct snd_ff *ff); -- cgit From e229853d505d7ab77e9b68b0ac91d19f48fe6d80 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:22 +0900 Subject: ALSA: firewire-lib: schedule hardware IRQ according to the size of PCM period ALSA IEC 61883-1/6 packet streaming engine controls 1394 OHCI controller to generate hardware IRQ for fixed number of isochronous packets (=16) since its first commit. This commit allow the engine to generate it for variable period according to the number of event to handle. For outgoing stream, internal calculator is used to check the accumulated events. For incoming stream, the number of data block in the packet of stream is used to check the accumulated events. When it's unavailable, fixed number of packet roughly calculated in advance is used instead of event counting. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-11-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 70 +++++++++++++++++++++++++++++++++---------- sound/firewire/amdtp-stream.h | 3 ++ 2 files changed, 58 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 1f38729c8e74..fd7c3e4d5374 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -52,9 +52,6 @@ #define CIP_FMT_AM 0x10 #define AMDTP_FDF_NO_DATA 0xff -/* TODO: make these configurable */ -#define INTERRUPT_INTERVAL 16 - // For iso header, tstamp and 2 CIP header. #define IR_CTX_HEADER_SIZE_CIP 16 // For iso header and tstamp. @@ -435,11 +432,12 @@ static void pcm_period_tasklet(unsigned long data) snd_pcm_period_elapsed(pcm); } -static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params) +static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params, + bool sched_irq) { int err; - params->interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL); + params->interrupt = sched_irq; params->tag = s->tag; params->sy = 0; @@ -457,21 +455,21 @@ end: } static inline int queue_out_packet(struct amdtp_stream *s, - struct fw_iso_packet *params) + struct fw_iso_packet *params, bool sched_irq) { params->skip = !!(params->header_length == 0 && params->payload_length == 0); - return queue_packet(s, params); + return queue_packet(s, params, sched_irq); } static inline int queue_in_packet(struct amdtp_stream *s, - struct fw_iso_packet *params) + struct fw_iso_packet *params, bool sched_irq) { // Queue one packet for IR context. params->header_length = s->ctx_data.tx.ctx_header_size; params->payload_length = s->ctx_data.tx.max_ctx_payload_length; params->skip = false; - return queue_packet(s, params); + return queue_packet(s, params, sched_irq); } static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2], @@ -779,6 +777,8 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, { struct amdtp_stream *s = private_data; const __be32 *ctx_header = header; + unsigned int events_per_period = s->events_per_period; + unsigned int event_count = s->event_count; unsigned int packets; int i; @@ -799,6 +799,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, struct fw_iso_packet params; __be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)]; } template = { {0}, {0} }; + bool sched_irq = false; if (s->ctx_data.rx.syt_override < 0) syt = desc->syt; @@ -809,12 +810,20 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, desc->data_blocks, desc->data_block_counter, syt, i); - if (queue_out_packet(s, &template.params) < 0) { + event_count += desc->data_blocks; + if (event_count >= events_per_period) { + event_count -= events_per_period; + sched_irq = true; + } + + if (queue_out_packet(s, &template.params, sched_irq) < 0) { cancel_stream(s); return; } } + s->event_count = event_count; + fw_iso_context_queue_flush(s->context); } @@ -823,8 +832,10 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, void *private_data) { struct amdtp_stream *s = private_data; - unsigned int packets; __be32 *ctx_header = header; + unsigned int events_per_period = s->events_per_period; + unsigned int event_count = s->event_count; + unsigned int packets; int i; int err; @@ -845,14 +856,29 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, } for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = s->pkt_descs + i; struct fw_iso_packet params = {0}; + bool sched_irq = false; + + if (err >= 0) { + event_count += desc->data_blocks; + if (event_count >= events_per_period) { + event_count -= events_per_period; + sched_irq = true; + } + } else { + sched_irq = + !((s->packet_index + 1) % s->idle_irq_interval); + } - if (queue_in_packet(s, ¶ms) < 0) { + if (queue_in_packet(s, ¶ms, sched_irq) < 0) { cancel_stream(s); return; } } + s->event_count = event_count; + fw_iso_context_queue_flush(s->context); } @@ -913,6 +939,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, [CIP_SFC_176400] = { 0, 67 }, }; unsigned int events_per_buffer = d->events_per_buffer; + unsigned int events_per_period = d->events_per_period; unsigned int ctx_header_size; unsigned int max_ctx_payload_size; enum dma_data_direction dir; @@ -958,11 +985,21 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP; } + // This is a case that AMDTP streams in domain run just for MIDI + // substream. Use the number of events equivalent to 10 msec as + // interval of hardware IRQ. + if (events_per_period == 0) + events_per_period = amdtp_rate_table[s->sfc] / 100; if (events_per_buffer == 0) - events_per_buffer = INTERRUPT_INTERVAL * 3; + events_per_buffer = events_per_period * 3; + s->idle_irq_interval = + DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period, + amdtp_rate_table[s->sfc]); s->queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer, amdtp_rate_table[s->sfc]); + s->events_per_period = events_per_period; + s->event_count = 0; err = iso_packets_buffer_init(&s->buffer, s->unit, s->queue_size, max_ctx_payload_size, dir); @@ -1002,12 +1039,15 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, s->packet_index = 0; do { struct fw_iso_packet params; + bool sched_irq; + + sched_irq = !((s->packet_index + 1) % s->idle_irq_interval); if (s->direction == AMDTP_IN_STREAM) { - err = queue_in_packet(s, ¶ms); + err = queue_in_packet(s, ¶ms, sched_irq); } else { params.header_length = 0; params.payload_length = 0; - err = queue_out_packet(s, ¶ms); + err = queue_out_packet(s, ¶ms, sched_irq); } if (err < 0) goto err_pkt_descs; diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 8d541727e437..344818e936df 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -145,6 +145,9 @@ struct amdtp_stream { int syt_override; } rx; } ctx_data; + unsigned int event_count; + unsigned int events_per_period; + unsigned int idle_irq_interval; /* For CIP headers. */ unsigned int source_node_id_field; -- cgit From 99921ec67dcdaeb5a5cc503f23ea2b5b6ff380ae Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:23 +0900 Subject: ALSA: firewire-lib: tune the maximum available size of PCM period Linux driver for 1394 OHCI controller voluntarily flushes isoc context when total size of accumulated context header reached PAGE_SIZE. This kicks tasklet for the isoc context. This is inconvenient to process runtime of PCM substream. This commit adds a restriction of the maximum size of PCM period to avoid this behaviour. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-12-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index fd7c3e4d5374..8a7818130382 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -176,6 +176,8 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime) { struct snd_pcm_hardware *hw = &runtime->hw; + unsigned int ctx_header_size; + unsigned int maximum_usec_per_period; int err; hw->info = SNDRV_PCM_INFO_BATCH | @@ -196,19 +198,24 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, hw->period_bytes_max = hw->period_bytes_min * 2048; hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; - /* - * Currently firewire-lib processes 16 packets in one software - * interrupt callback. This equals to 2msec but actually the - * interval of the interrupts has a jitter. - * Additionally, even if adding a constraint to fit period size to - * 2msec, actual calculated frames per period doesn't equal to 2msec, - * depending on sampling rate. - * Anyway, the interval to call snd_pcm_period_elapsed() cannot 2msec. - * Here let us use 5msec for safe period interrupt. - */ + // Linux driver for 1394 OHCI controller voluntarily flushes isoc + // context when total size of accumulated context header reaches + // PAGE_SIZE. This kicks tasklet for the isoc context and brings + // callback in the middle of scheduled interrupts. + // Although AMDTP streams in the same domain use the same events per + // IRQ, use the largest size of context header between IT/IR contexts. + // Here, use the value of context header in IR context is for both + // contexts. + if (!(s->flags & CIP_NO_HEADER)) + ctx_header_size = IR_CTX_HEADER_SIZE_CIP; + else + ctx_header_size = IR_CTX_HEADER_SIZE_NO_CIP; + maximum_usec_per_period = USEC_PER_SEC * PAGE_SIZE / + CYCLES_PER_SECOND / ctx_header_size; + err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, - 5000, UINT_MAX); + 5000, maximum_usec_per_period); if (err < 0) goto end; -- cgit From f706df4f42b1b9f5acb6641eb6818d85b6856476 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 00:54:24 +0900 Subject: ALSA: firewire-lib: tune the minimum available size of PCM period In IEC 61883-1/6, one isoc packet can transfer events up to the value of syt interval. This comes from the interval of isoc cycle. As 1394 OHCI controller can generate hardware IRQ per isoc packet, the interval is calculated as 125 usec. In IEC 61883-1/6, two ways of transmission is described; blocking and non-blocking methods. In blocking method, the sequence of packet includes 'empty' or 'NODATA' packets which include no events. In non-blocking method, the number of events per packet is variable up to the syt interval. This commit uses double of the value of syt interval as minimum available size of PCM period due to the above protocol design. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191017155424.885-13-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 8a7818130382..7486eec4d958 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -213,9 +213,21 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, maximum_usec_per_period = USEC_PER_SEC * PAGE_SIZE / CYCLES_PER_SECOND / ctx_header_size; + // In IEC 61883-6, one isoc packet can transfer events up to the value + // of syt interval. This comes from the interval of isoc cycle. As 1394 + // OHCI controller can generate hardware IRQ per isoc packet, the + // interval is 125 usec. + // However, there are two ways of transmission in IEC 61883-6; blocking + // and non-blocking modes. In blocking mode, the sequence of isoc packet + // includes 'empty' or 'NODATA' packets which include no event. In + // non-blocking mode, the number of events per packet is variable up to + // the syt interval. + // Due to the above protocol design, the minimum PCM frames per + // interrupt should be double of the value of syt interval, thus it is + // 250 usec. err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, - 5000, maximum_usec_per_period); + 250, maximum_usec_per_period); if (err < 0) goto end; -- cgit From 0e4b8717578e05ec6aa6d51939e6dc746f3198e9 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Tue, 15 Oct 2019 22:09:00 +0200 Subject: ASoC: tas2562: Fix misuse of GENMASK macro Arguments are supposed to be ordered high then low. Fixes: c173dba44c2d ("ASoC: tas2562: Introduce the TAS2562 amplifier") Signed-off-by: Rikard Falkeborn Link: https://lore.kernel.org/r/20191015200900.25798-1-rikard.falkeborn@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2562.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/tas2562.h b/sound/soc/codecs/tas2562.h index 60f2bb1d198b..62e659ab786d 100644 --- a/sound/soc/codecs/tas2562.h +++ b/sound/soc/codecs/tas2562.h @@ -62,7 +62,7 @@ #define TAS2562_TDM_CFG2_RIGHT_JUSTIFY BIT(6) -#define TAS2562_TDM_CFG2_RXLEN_MASK GENMASK(0, 1) +#define TAS2562_TDM_CFG2_RXLEN_MASK GENMASK(1, 0) #define TAS2562_TDM_CFG2_RXLEN_16B 0x0 #define TAS2562_TDM_CFG2_RXLEN_24B BIT(0) #define TAS2562_TDM_CFG2_RXLEN_32B BIT(1) -- cgit From 727f1c71c780789aeb8f3da2596c65ae008d5d6c Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 14 Oct 2019 18:20:14 +0800 Subject: ASoC: cros_ec_codec: refactor I2S RX Refactor by the following items: - reformat copyright declaration - use more specific name "i2s rx" - use verbose symbol names to separate namespaces - make some short functions inline - remove unused TDM-related code Signed-off-by: Tzung-Bi Shih Acked-By: Benson Leung Link: https://lore.kernel.org/r/20191014180059.02.I43373b9a66dbb70196b3f216b3aa86111c410836@changeid Signed-off-by: Mark Brown --- sound/soc/codecs/cros_ec_codec.c | 502 ++++++++++++++++----------------------- 1 file changed, 199 insertions(+), 303 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 3c1bd24a1057..179fa77291cd 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Driver for ChromeOS Embedded Controller codec. + * Copyright 2019 Google, Inc. + * + * ChromeOS Embedded Controller codec driver. * * This driver uses the cros-ec interface to communicate with the ChromeOS * EC for audio function. @@ -18,403 +20,297 @@ #include #include -#define DRV_NAME "cros-ec-codec" - -/** - * struct cros_ec_codec_data - ChromeOS EC codec driver data. - * @dev: Device structure used in sysfs. - * @ec_device: cros_ec_device structure to talk to the physical device. - * @component: Pointer to the component. - * @max_dmic_gain: Maximum gain in dB supported by EC codec. - */ -struct cros_ec_codec_data { +struct cros_ec_codec_priv { struct device *dev; struct cros_ec_device *ec_device; - struct snd_soc_component *component; - unsigned int max_dmic_gain; }; -static const DECLARE_TLV_DB_SCALE(ec_mic_gain_tlv, 0, 100, 0); - -static int ec_command_get_gain(struct snd_soc_component *component, - struct ec_param_codec_i2s *param, - struct ec_codec_i2s_gain *resp) +static int send_ec_host_command(struct cros_ec_device *ec_dev, uint32_t cmd, + uint8_t *out, size_t outsize, + uint8_t *in, size_t insize) { - struct cros_ec_codec_data *codec_data = - snd_soc_component_get_drvdata(component); - struct cros_ec_device *ec_device = codec_data->ec_device; - u8 buffer[sizeof(struct cros_ec_command) + - max(sizeof(struct ec_param_codec_i2s), - sizeof(struct ec_codec_i2s_gain))]; - struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; int ret; + struct cros_ec_command *msg; + + msg = kmalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); + if (!msg) + return -ENOMEM; msg->version = 0; - msg->command = EC_CMD_CODEC_I2S; - msg->outsize = sizeof(struct ec_param_codec_i2s); - msg->insize = sizeof(struct ec_codec_i2s_gain); + msg->command = cmd; + msg->outsize = outsize; + msg->insize = insize; + + if (outsize) + memcpy(msg->data, out, outsize); - memcpy(msg->data, param, msg->outsize); + ret = cros_ec_cmd_xfer_status(ec_dev, msg); + if (ret < 0) + goto error; - ret = cros_ec_cmd_xfer_status(ec_device, msg); - if (ret > 0) - memcpy(resp, msg->data, msg->insize); + if (insize) + memcpy(in, msg->data, insize); + ret = 0; +error: + kfree(msg); return ret; } -/* - * Wrapper for EC command without response. - */ -static int ec_command_no_resp(struct snd_soc_component *component, - struct ec_param_codec_i2s *param) +static int dmic_get_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct cros_ec_codec_data *codec_data = + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - struct cros_ec_device *ec_device = codec_data->ec_device; - u8 buffer[sizeof(struct cros_ec_command) + - sizeof(struct ec_param_codec_i2s)]; - struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; - - msg->version = 0; - msg->command = EC_CMD_CODEC_I2S; - msg->outsize = sizeof(struct ec_param_codec_i2s); - msg->insize = 0; - - memcpy(msg->data, param, msg->outsize); - - return cros_ec_cmd_xfer_status(ec_device, msg); -} - -static int set_i2s_config(struct snd_soc_component *component, - enum ec_i2s_config i2s_config) -{ - struct ec_param_codec_i2s param; + struct ec_param_ec_codec_i2s_rx p; + struct ec_response_ec_codec_i2s_rx_get_gain r; + int ret; - dev_dbg(component->dev, "%s set I2S format to %u\n", __func__, - i2s_config); + p.cmd = EC_CODEC_I2S_RX_GET_GAIN; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret < 0) + return ret; - param.cmd = EC_CODEC_I2S_SET_CONFIG; - param.i2s_config = i2s_config; + ucontrol->value.integer.value[0] = r.left; + ucontrol->value.integer.value[1] = r.right; - return ec_command_no_resp(component, ¶m); + return 0; } -static int cros_ec_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int dmic_put_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = dai->component; - enum ec_i2s_config i2s_config; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - i2s_config = EC_DAI_FMT_I2S; - break; - - case SND_SOC_DAIFMT_RIGHT_J: - i2s_config = EC_DAI_FMT_RIGHT_J; - break; - - case SND_SOC_DAIFMT_LEFT_J: - i2s_config = EC_DAI_FMT_LEFT_J; - break; - - case SND_SOC_DAIFMT_DSP_A: - i2s_config = EC_DAI_FMT_PCM_A; - break; - - case SND_SOC_DAIFMT_DSP_B: - i2s_config = EC_DAI_FMT_PCM_B; - break; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct soc_mixer_control *control = + (struct soc_mixer_control *)kcontrol->private_value; + int max_dmic_gain = control->max; + int left = ucontrol->value.integer.value[0]; + int right = ucontrol->value.integer.value[1]; + struct ec_param_ec_codec_i2s_rx p; - default: + if (left > max_dmic_gain || right > max_dmic_gain) return -EINVAL; - } - return set_i2s_config(component, i2s_config); -} - -static int set_i2s_sample_depth(struct snd_soc_component *component, - enum ec_sample_depth_value depth) -{ - struct ec_param_codec_i2s param; - - dev_dbg(component->dev, "%s set depth to %u\n", __func__, depth); - - param.cmd = EC_CODEC_SET_SAMPLE_DEPTH; - param.depth = depth; + dev_dbg(component->dev, "set mic gain to %u, %u\n", left, right); - return ec_command_no_resp(component, ¶m); + p.cmd = EC_CODEC_I2S_RX_SET_GAIN; + p.set_gain_param.left = left; + p.set_gain_param.right = right; + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); } -static int set_i2s_bclk(struct snd_soc_component *component, uint32_t bclk) -{ - struct ec_param_codec_i2s param; - - dev_dbg(component->dev, "%s set i2s bclk to %u\n", __func__, bclk); +static const DECLARE_TLV_DB_SCALE(dmic_gain_tlv, 0, 100, 0); - param.cmd = EC_CODEC_I2S_SET_BCLK; - param.bclk = bclk; +enum { + DMIC_CTL_GAIN = 0, +}; - return ec_command_no_resp(component, ¶m); -} +static struct snd_kcontrol_new dmic_controls[] = { + [DMIC_CTL_GAIN] = + SOC_DOUBLE_EXT_TLV("EC Mic Gain", SND_SOC_NOPM, SND_SOC_NOPM, + 0, 0, 0, dmic_get_gain, dmic_put_gain, + dmic_gain_tlv), +}; -static int cros_ec_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int i2s_rx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; - unsigned int rate, bclk; + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct ec_param_ec_codec_i2s_rx p; + enum ec_codec_i2s_rx_sample_depth depth; int ret; - rate = params_rate(params); - if (rate != 48000) + if (params_rate(params) != 48000) return -EINVAL; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: - ret = set_i2s_sample_depth(component, EC_CODEC_SAMPLE_DEPTH_16); + depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_16; break; case SNDRV_PCM_FORMAT_S24_LE: - ret = set_i2s_sample_depth(component, EC_CODEC_SAMPLE_DEPTH_24); + depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_24; break; default: return -EINVAL; } - if (ret < 0) - return ret; - - bclk = snd_soc_params_to_bclk(params); - return set_i2s_bclk(component, bclk); -} -static const struct snd_soc_dai_ops cros_ec_i2s_dai_ops = { - .hw_params = cros_ec_i2s_hw_params, - .set_fmt = cros_ec_i2s_set_dai_fmt, -}; + dev_dbg(component->dev, "set depth to %u\n", depth); -static struct snd_soc_dai_driver cros_ec_dai[] = { - { - .name = "cros_ec_codec I2S", - .id = 0, - .capture = { - .stream_name = "I2S Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, - .ops = &cros_ec_i2s_dai_ops, - } -}; - -static int get_ec_mic_gain(struct snd_soc_component *component, - u8 *left, u8 *right) -{ - struct ec_param_codec_i2s param; - struct ec_codec_i2s_gain resp; - int ret; - - param.cmd = EC_CODEC_GET_GAIN; - - ret = ec_command_get_gain(component, ¶m, &resp); + p.cmd = EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH; + p.set_sample_depth_param.depth = depth; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); if (ret < 0) return ret; - *left = resp.left; - *right = resp.right; - - return 0; -} - -static int mic_gain_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); - u8 left, right; - int ret; - - ret = get_ec_mic_gain(component, &left, &right); - if (ret) - return ret; - - ucontrol->value.integer.value[0] = left; - ucontrol->value.integer.value[1] = right; - - return 0; -} - -static int set_ec_mic_gain(struct snd_soc_component *component, - u8 left, u8 right) -{ - struct ec_param_codec_i2s param; - - dev_dbg(component->dev, "%s set mic gain to %u, %u\n", - __func__, left, right); + dev_dbg(component->dev, "set bclk to %u\n", + snd_soc_params_to_bclk(params)); - param.cmd = EC_CODEC_SET_GAIN; - param.gain.left = left; - param.gain.right = right; - - return ec_command_no_resp(component, ¶m); + p.cmd = EC_CODEC_I2S_RX_SET_BCLK; + p.set_bclk_param.bclk = snd_soc_params_to_bclk(params); + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); } -static int mic_gain_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); - struct cros_ec_codec_data *codec_data = + struct snd_soc_component *component = dai->component; + struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - int left = ucontrol->value.integer.value[0]; - int right = ucontrol->value.integer.value[1]; - unsigned int max_dmic_gain = codec_data->max_dmic_gain; + struct ec_param_ec_codec_i2s_rx p; + enum ec_codec_i2s_rx_daifmt daifmt; - if (left > max_dmic_gain || right > max_dmic_gain) + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: return -EINVAL; + } - return set_ec_mic_gain(component, (u8)left, (u8)right); -} - -static struct snd_kcontrol_new mic_gain_control = - SOC_DOUBLE_EXT_TLV("EC Mic Gain", SND_SOC_NOPM, SND_SOC_NOPM, 0, 0, 0, - mic_gain_get, mic_gain_put, ec_mic_gain_tlv); - -static int enable_i2s(struct snd_soc_component *component, int enable) -{ - struct ec_param_codec_i2s param; + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } - dev_dbg(component->dev, "%s set i2s to %u\n", __func__, enable); + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + daifmt = EC_CODEC_I2S_RX_DAIFMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + daifmt = EC_CODEC_I2S_RX_DAIFMT_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + daifmt = EC_CODEC_I2S_RX_DAIFMT_LEFT_J; + break; + default: + return -EINVAL; + } - param.cmd = EC_CODEC_I2S_ENABLE; - param.i2s_enable = enable; + dev_dbg(component->dev, "set format to %u\n", daifmt); - return ec_command_no_resp(component, ¶m); + p.cmd = EC_CODEC_I2S_RX_SET_DAIFMT; + p.set_daifmt_param.daifmt = daifmt; + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); } -static int cros_ec_i2s_enable_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static const struct snd_soc_dai_ops i2s_rx_dai_ops = { + .hw_params = i2s_rx_hw_params, + .set_fmt = i2s_rx_set_fmt, +}; + +static int i2s_rx_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct ec_param_ec_codec_i2s_rx p; switch (event) { case SND_SOC_DAPM_PRE_PMU: - dev_dbg(component->dev, - "%s got SND_SOC_DAPM_PRE_PMU event\n", __func__); - return enable_i2s(component, 1); - + dev_dbg(component->dev, "enable I2S RX\n"); + p.cmd = EC_CODEC_I2S_RX_ENABLE; + break; case SND_SOC_DAPM_PRE_PMD: - dev_dbg(component->dev, - "%s got SND_SOC_DAPM_PRE_PMD event\n", __func__); - return enable_i2s(component, 0); + dev_dbg(component->dev, "disable I2S RX\n"); + p.cmd = EC_CODEC_I2S_RX_DISABLE; + break; + default: + return 0; } - return 0; + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); } -/* - * The goal of this DAPM route is to turn on/off I2S using EC - * host command when capture stream is started/stopped. - */ -static const struct snd_soc_dapm_widget cros_ec_codec_dapm_widgets[] = { +static struct snd_soc_dapm_widget i2s_rx_dapm_widgets[] = { SND_SOC_DAPM_INPUT("DMIC"), - - /* - * Control EC to enable/disable I2S. - */ - SND_SOC_DAPM_SUPPLY("I2S Enable", SND_SOC_NOPM, - 0, 0, cros_ec_i2s_enable_event, + SND_SOC_DAPM_SUPPLY("I2S RX Enable", SND_SOC_NOPM, 0, 0, i2s_rx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_AIF_OUT("I2S RX", "I2S Capture", 0, SND_SOC_NOPM, 0, 0), +}; - SND_SOC_DAPM_AIF_OUT("I2STX", "I2S Capture", 0, SND_SOC_NOPM, 0, 0), +static struct snd_soc_dapm_route i2s_rx_dapm_routes[] = { + {"I2S RX", NULL, "DMIC"}, + {"I2S RX", NULL, "I2S RX Enable"}, }; -static const struct snd_soc_dapm_route cros_ec_codec_dapm_routes[] = { - { "I2STX", NULL, "DMIC" }, - { "I2STX", NULL, "I2S Enable" }, +static struct snd_soc_dai_driver i2s_rx_dai_driver = { + .name = "EC Codec I2S RX", + .capture = { + .stream_name = "I2S Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &i2s_rx_dai_ops, }; -/* - * Read maximum gain from device property and set it to mixer control. - */ -static int cros_ec_set_gain_range(struct device *dev) +static int i2s_rx_probe(struct snd_soc_component *component) { + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct device *dev = priv->dev; + int ret, val; struct soc_mixer_control *control; - struct cros_ec_codec_data *codec_data = dev_get_drvdata(dev); - int rc; - rc = device_property_read_u32(dev, "max-dmic-gain", - &codec_data->max_dmic_gain); - if (rc) - return rc; + ret = device_property_read_u32(dev, "max-dmic-gain", &val); + if (ret) { + dev_err(dev, "Failed to read 'max-dmic-gain'\n"); + return ret; + } control = (struct soc_mixer_control *) - mic_gain_control.private_value; - control->max = codec_data->max_dmic_gain; - control->platform_max = codec_data->max_dmic_gain; + dmic_controls[DMIC_CTL_GAIN].private_value; + control->max = val; + control->platform_max = val; - return 0; -} - -static int cros_ec_codec_probe(struct snd_soc_component *component) -{ - int rc; - - struct cros_ec_codec_data *codec_data = - snd_soc_component_get_drvdata(component); - - rc = cros_ec_set_gain_range(codec_data->dev); - if (rc) - return rc; - - return snd_soc_add_component_controls(component, &mic_gain_control, 1); + return snd_soc_add_component_controls(component, + &dmic_controls[DMIC_CTL_GAIN], 1); } -static const struct snd_soc_component_driver cros_ec_component_driver = { - .probe = cros_ec_codec_probe, - .dapm_widgets = cros_ec_codec_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cros_ec_codec_dapm_widgets), - .dapm_routes = cros_ec_codec_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(cros_ec_codec_dapm_routes), +static const struct snd_soc_component_driver i2s_rx_component_driver = { + .probe = i2s_rx_probe, + .dapm_widgets = i2s_rx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(i2s_rx_dapm_widgets), + .dapm_routes = i2s_rx_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(i2s_rx_dapm_routes), }; -/* - * Platform device and platform driver fro cros-ec-codec. - */ -static int cros_ec_codec_platform_probe(struct platform_device *pd) +static int cros_ec_codec_platform_probe(struct platform_device *pdev) { - struct device *dev = &pd->dev; - struct cros_ec_device *ec_device = dev_get_drvdata(pd->dev.parent); - struct cros_ec_codec_data *codec_data; + struct device *dev = &pdev->dev; + struct cros_ec_device *ec_device = dev_get_drvdata(pdev->dev.parent); + struct cros_ec_codec_priv *priv; - codec_data = devm_kzalloc(dev, sizeof(struct cros_ec_codec_data), - GFP_KERNEL); - if (!codec_data) + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - codec_data->dev = dev; - codec_data->ec_device = ec_device; + priv->dev = dev; + priv->ec_device = ec_device; - platform_set_drvdata(pd, codec_data); + platform_set_drvdata(pdev, priv); - return devm_snd_soc_register_component(dev, &cros_ec_component_driver, - cros_ec_dai, ARRAY_SIZE(cros_ec_dai)); + return devm_snd_soc_register_component(dev, &i2s_rx_component_driver, + &i2s_rx_dai_driver, 1); } #ifdef CONFIG_OF @@ -427,7 +323,7 @@ MODULE_DEVICE_TABLE(of, cros_ec_codec_of_match); static struct platform_driver cros_ec_codec_platform_driver = { .driver = { - .name = DRV_NAME, + .name = "cros-ec-codec", .of_match_table = of_match_ptr(cros_ec_codec_of_match), }, .probe = cros_ec_codec_platform_probe, @@ -438,4 +334,4 @@ module_platform_driver(cros_ec_codec_platform_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ChromeOS EC codec driver"); MODULE_AUTHOR("Cheng-Yi Chiang "); -MODULE_ALIAS("platform:" DRV_NAME); +MODULE_ALIAS("platform:cros-ec-codec"); -- cgit From 8f731d4c92c2ef9434d4d7f84882c6429754164b Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 14 Oct 2019 18:20:15 +0800 Subject: ASoC: cros_ec_codec: extract DMIC EC command from I2S RX Extract DMIC EC command from I2S RX. Setting and getting microphone gains is common features. Signed-off-by: Tzung-Bi Shih Acked-By: Benson Leung Link: https://lore.kernel.org/r/20191014180059.03.I93d9c65964f3c30f85a36d228e31150ff1917706@changeid Signed-off-by: Mark Brown --- sound/soc/codecs/cros_ec_codec.c | 57 ++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 179fa77291cd..c19c7fe42e2e 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -64,12 +64,12 @@ static int dmic_get_gain(struct snd_kcontrol *kcontrol, snd_soc_kcontrol_component(kcontrol); struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - struct ec_param_ec_codec_i2s_rx p; - struct ec_response_ec_codec_i2s_rx_get_gain r; + struct ec_param_ec_codec_dmic p; + struct ec_response_ec_codec_dmic_get_gain r; int ret; - p.cmd = EC_CODEC_I2S_RX_GET_GAIN; - ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + p.cmd = EC_CODEC_DMIC_GET_GAIN; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, (uint8_t *)&p, sizeof(p), (uint8_t *)&r, sizeof(r)); if (ret < 0) @@ -93,17 +93,17 @@ static int dmic_put_gain(struct snd_kcontrol *kcontrol, int max_dmic_gain = control->max; int left = ucontrol->value.integer.value[0]; int right = ucontrol->value.integer.value[1]; - struct ec_param_ec_codec_i2s_rx p; + struct ec_param_ec_codec_dmic p; if (left > max_dmic_gain || right > max_dmic_gain) return -EINVAL; dev_dbg(component->dev, "set mic gain to %u, %u\n", left, right); - p.cmd = EC_CODEC_I2S_RX_SET_GAIN; + p.cmd = EC_CODEC_DMIC_SET_GAIN; p.set_gain_param.left = left; p.set_gain_param.right = right; - return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, (uint8_t *)&p, sizeof(p), NULL, 0); } @@ -120,6 +120,29 @@ static struct snd_kcontrol_new dmic_controls[] = { dmic_gain_tlv), }; +static int dmic_probe(struct snd_soc_component *component) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct device *dev = priv->dev; + int ret, val; + struct soc_mixer_control *control; + + ret = device_property_read_u32(dev, "max-dmic-gain", &val); + if (ret) { + dev_err(dev, "Failed to read 'max-dmic-gain'\n"); + return ret; + } + + control = (struct soc_mixer_control *) + dmic_controls[DMIC_CTL_GAIN].private_value; + control->max = val; + control->platform_max = val; + + return snd_soc_add_component_controls(component, + &dmic_controls[DMIC_CTL_GAIN], 1); +} + static int i2s_rx_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -265,25 +288,7 @@ static struct snd_soc_dai_driver i2s_rx_dai_driver = { static int i2s_rx_probe(struct snd_soc_component *component) { - struct cros_ec_codec_priv *priv = - snd_soc_component_get_drvdata(component); - struct device *dev = priv->dev; - int ret, val; - struct soc_mixer_control *control; - - ret = device_property_read_u32(dev, "max-dmic-gain", &val); - if (ret) { - dev_err(dev, "Failed to read 'max-dmic-gain'\n"); - return ret; - } - - control = (struct soc_mixer_control *) - dmic_controls[DMIC_CTL_GAIN].private_value; - control->max = val; - control->platform_max = val; - - return snd_soc_add_component_controls(component, - &dmic_controls[DMIC_CTL_GAIN], 1); + return dmic_probe(component); } static const struct snd_soc_component_driver i2s_rx_component_driver = { -- cgit From 349959a9c767cee04b7362fda230cc2433246fd9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 18 Oct 2019 09:23:17 +0100 Subject: ASoC: rt1011: fix spelling mistake "temperture" -> "temperature" There is a spelling mistake in a dev_dbg message. Fix it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20191018082317.11971-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index ad049cfddcb0..dcd397a83cb4 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2373,7 +2373,7 @@ static int rt1011_parse_dp(struct rt1011_priv *rt1011, struct device *dev) device_property_read_u32(dev, "realtek,r0_calib", &rt1011->r0_calib); - dev_dbg(dev, "%s: r0_calib: 0x%x, temperture_calib: 0x%x", + dev_dbg(dev, "%s: r0_calib: 0x%x, temperature_calib: 0x%x", __func__, rt1011->r0_calib, rt1011->temperature_calib); return 0; -- cgit From 1092b09708882e3c216f0b9c02e606b3c0942c5b Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Fri, 18 Oct 2019 16:14:49 +0800 Subject: ASoC: tlv320aic32x4: add a check for devm_clk_get aic32x4_set_dai_sysclk misses a check for devm_clk_get and may miss the failure. Add a check to fix it. Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20191018081448.8486-1-hslester96@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 68165de1c8de..b4e9a6c73f90 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -573,6 +573,9 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct clk *pll; pll = devm_clk_get(component->dev, "pll"); + if (IS_ERR(pll)) + return PTR_ERR(pll); + mclk = clk_get_parent(pll); return clk_set_rate(mclk, freq); -- cgit From f3e82ad43ca538a7e0db0f310e26c5e75db6ba18 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 17 Oct 2019 22:00:10 +0800 Subject: ASoC: cros_ec_codec: read max DMIC gain from EC codec Read max DMIC gain from EC codec instead of DTS. Also removes the dt-binding of max-dmic-gain. Acked-by: Rob Herring Acked-by: Benson Leung Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20191017213539.05.Id4657c864d544634f2b5c1c9b34fa8232ecba44d@changeid Signed-off-by: Mark Brown --- sound/soc/codecs/cros_ec_codec.c | 53 +++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index c19c7fe42e2e..3d4f9e82d6e9 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -65,18 +65,26 @@ static int dmic_get_gain(struct snd_kcontrol *kcontrol, struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); struct ec_param_ec_codec_dmic p; - struct ec_response_ec_codec_dmic_get_gain r; + struct ec_response_ec_codec_dmic_get_gain_idx r; int ret; - p.cmd = EC_CODEC_DMIC_GET_GAIN; + p.cmd = EC_CODEC_DMIC_GET_GAIN_IDX; + p.get_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_0; ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, (uint8_t *)&p, sizeof(p), (uint8_t *)&r, sizeof(r)); if (ret < 0) return ret; + ucontrol->value.integer.value[0] = r.gain; - ucontrol->value.integer.value[0] = r.left; - ucontrol->value.integer.value[1] = r.right; + p.cmd = EC_CODEC_DMIC_GET_GAIN_IDX; + p.get_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_1; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret < 0) + return ret; + ucontrol->value.integer.value[1] = r.gain; return 0; } @@ -94,15 +102,24 @@ static int dmic_put_gain(struct snd_kcontrol *kcontrol, int left = ucontrol->value.integer.value[0]; int right = ucontrol->value.integer.value[1]; struct ec_param_ec_codec_dmic p; + int ret; if (left > max_dmic_gain || right > max_dmic_gain) return -EINVAL; dev_dbg(component->dev, "set mic gain to %u, %u\n", left, right); - p.cmd = EC_CODEC_DMIC_SET_GAIN; - p.set_gain_param.left = left; - p.set_gain_param.right = right; + p.cmd = EC_CODEC_DMIC_SET_GAIN_IDX; + p.set_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_0; + p.set_gain_idx_param.gain = left; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, + (uint8_t *)&p, sizeof(p), NULL, 0); + if (ret < 0) + return ret; + + p.cmd = EC_CODEC_DMIC_SET_GAIN_IDX; + p.set_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_1; + p.set_gain_idx_param.gain = right; return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, (uint8_t *)&p, sizeof(p), NULL, 0); } @@ -125,19 +142,27 @@ static int dmic_probe(struct snd_soc_component *component) struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); struct device *dev = priv->dev; - int ret, val; struct soc_mixer_control *control; + struct ec_param_ec_codec_dmic p; + struct ec_response_ec_codec_dmic_get_max_gain r; + int ret; - ret = device_property_read_u32(dev, "max-dmic-gain", &val); - if (ret) { - dev_err(dev, "Failed to read 'max-dmic-gain'\n"); - return ret; + p.cmd = EC_CODEC_DMIC_GET_MAX_GAIN; + + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret < 0) { + dev_warn(dev, "get_max_gain() unsupported\n"); + return 0; } + dev_dbg(dev, "max gain = %d\n", r.max_gain); + control = (struct soc_mixer_control *) dmic_controls[DMIC_CTL_GAIN].private_value; - control->max = val; - control->platform_max = val; + control->max = r.max_gain; + control->platform_max = r.max_gain; return snd_soc_add_component_controls(component, &dmic_controls[DMIC_CTL_GAIN], 1); -- cgit From 03b4816dcb6ee348edf248f7ba9f04f1e90c2fc7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 15:19:06 +0900 Subject: ALSA: firewire-lib: add irq_target member into amdtp_domain struct This commit is a preparation to handle several IR/IT contexts in the same domain by tasklet context for one of the IT context. Such IT context is stored to AMDTP domain structure as 'irq_target'. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191018061911.24909-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 344818e936df..f92397a2f35f 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -279,6 +279,8 @@ struct amdtp_domain { unsigned int events_per_period; unsigned int events_per_buffer; + + struct amdtp_stream *irq_target; }; int amdtp_domain_init(struct amdtp_domain *d); -- cgit From f890f9a04b361b2209c38e3317e6290a98e6ff6e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 15:19:07 +0900 Subject: ALSA: firewire-lib: replace pointer callback to flush isoc contexts in AMDTP domain An isoc context for AMDTP stream is flushed to queue packet by a call of pcm.pointer. This commit extends this for AMDTP domain. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191018061911.24909-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 51 +++++++++++++++++++------------- sound/firewire/amdtp-stream.h | 3 +- sound/firewire/bebob/bebob_pcm.c | 14 +++++---- sound/firewire/dice/dice-pcm.c | 4 +-- sound/firewire/digi00x/digi00x-pcm.c | 4 +-- sound/firewire/fireface/ff-pcm.c | 4 +-- sound/firewire/fireworks/fireworks_pcm.c | 6 ++-- sound/firewire/motu/motu-pcm.c | 4 +-- sound/firewire/oxfw/oxfw-pcm.c | 4 +-- sound/firewire/tascam/tascam-pcm.c | 4 +-- 10 files changed, 56 insertions(+), 42 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 7486eec4d958..23677b805b05 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1099,35 +1099,44 @@ err_unlock: } /** - * amdtp_stream_pcm_pointer - get the PCM buffer position + * amdtp_domain_stream_pcm_pointer - get the PCM buffer position + * @d: the AMDTP domain. * @s: the AMDTP stream that transports the PCM data * * Returns the current buffer position, in frames. */ -unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s) +unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, + struct amdtp_stream *s) { - /* - * This function is called in software IRQ context of period_tasklet or - * process context. - * - * When the software IRQ context was scheduled by software IRQ context - * of IR/IT contexts, queued packets were already handled. Therefore, - * no need to flush the queue in buffer anymore. - * - * When the process context reach here, some packets will be already - * queued in the buffer. These packets should be handled immediately - * to keep better granularity of PCM pointer. - * - * Later, the process context will sometimes schedules software IRQ - * context of the period_tasklet. Then, no need to flush the queue by - * the same reason as described for IR/IT contexts. - */ - if (!in_interrupt() && amdtp_stream_running(s)) - fw_iso_context_flush_completions(s->context); + struct amdtp_stream *irq_target = d->irq_target; + + if (irq_target && amdtp_stream_running(irq_target)) { + // This function is called in software IRQ context of + // period_tasklet or process context. + // + // When the software IRQ context was scheduled by software IRQ + // context of IT contexts, queued packets were already handled. + // Therefore, no need to flush the queue in buffer furthermore. + // + // When the process context reach here, some packets will be + // already queued in the buffer. These packets should be handled + // immediately to keep better granularity of PCM pointer. + // + // Later, the process context will sometimes schedules software + // IRQ context of the period_tasklet. Then, no need to flush the + // queue by the same reason as described in the above + if (!in_interrupt()) { + // Queued packet should be processed without any kernel + // preemption to keep latency against bus cycle. + preempt_disable(); + fw_iso_context_flush_completions(irq_target->context); + preempt_enable(); + } + } return READ_ONCE(s->pcm_buffer_pointer); } -EXPORT_SYMBOL(amdtp_stream_pcm_pointer); +EXPORT_SYMBOL_GPL(amdtp_domain_stream_pcm_pointer); /** * amdtp_stream_pcm_ack - acknowledge queued PCM frames diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index f92397a2f35f..ba0bbeddfdcb 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -198,7 +198,6 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime); void amdtp_stream_pcm_prepare(struct amdtp_stream *s); -unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s); int amdtp_stream_pcm_ack(struct amdtp_stream *s); void amdtp_stream_pcm_abort(struct amdtp_stream *s); @@ -302,4 +301,6 @@ static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d, return 0; } +unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, + struct amdtp_stream *s); #endif diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 8b2e0ceffe82..dc15ea8d0dc5 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -313,17 +313,19 @@ pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -static snd_pcm_uframes_t -pcm_capture_pointer(struct snd_pcm_substream *sbstrm) +static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) { struct snd_bebob *bebob = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&bebob->tx_stream); + + return amdtp_domain_stream_pcm_pointer(&bebob->domain, + &bebob->tx_stream); } -static snd_pcm_uframes_t -pcm_playback_pointer(struct snd_pcm_substream *sbstrm) +static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) { struct snd_bebob *bebob = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&bebob->rx_stream); + + return amdtp_domain_stream_pcm_pointer(&bebob->domain, + &bebob->rx_stream); } static int pcm_capture_ack(struct snd_pcm_substream *substream) diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 7c0c34c5bd47..81b78e7d181d 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -379,14 +379,14 @@ static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream) struct snd_dice *dice = substream->private_data; struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; - return amdtp_stream_pcm_pointer(stream); + return amdtp_domain_stream_pcm_pointer(&dice->domain, stream); } static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) { struct snd_dice *dice = substream->private_data; struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; - return amdtp_stream_pcm_pointer(stream); + return amdtp_domain_stream_pcm_pointer(&dice->domain, stream); } static int capture_ack(struct snd_pcm_substream *substream) diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index c9a833dff20d..f6a2053d5f10 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -301,14 +301,14 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) { struct snd_dg00x *dg00x = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&dg00x->tx_stream); + return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->tx_stream); } static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) { struct snd_dg00x *dg00x = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&dg00x->rx_stream); + return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->rx_stream); } static int pcm_capture_ack(struct snd_pcm_substream *substream) diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index 005d959f8651..5af1dce90921 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -341,14 +341,14 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) { struct snd_ff *ff = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&ff->tx_stream); + return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->tx_stream); } static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) { struct snd_ff *ff = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&ff->rx_stream); + return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->rx_stream); } static int pcm_capture_ack(struct snd_pcm_substream *substream) diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index abcc53dac8a5..71f5057caa0d 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -348,12 +348,14 @@ static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) { struct snd_efw *efw = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&efw->tx_stream); + + return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->tx_stream); } static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) { struct snd_efw *efw = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&efw->rx_stream); + + return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->rx_stream); } static int pcm_capture_ack(struct snd_pcm_substream *substream) diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 00e693da0cad..13e2577c2a07 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -320,13 +320,13 @@ static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream) { struct snd_motu *motu = substream->private_data; - return amdtp_stream_pcm_pointer(&motu->tx_stream); + return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->tx_stream); } static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) { struct snd_motu *motu = substream->private_data; - return amdtp_stream_pcm_pointer(&motu->rx_stream); + return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->rx_stream); } static int capture_ack(struct snd_pcm_substream *substream) diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index ba586d1ac91d..3be35dfcf270 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -393,13 +393,13 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm) { struct snd_oxfw *oxfw = sbstm->private_data; - return amdtp_stream_pcm_pointer(&oxfw->tx_stream); + return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->tx_stream); } static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm) { struct snd_oxfw *oxfw = sbstm->private_data; - return amdtp_stream_pcm_pointer(&oxfw->rx_stream); + return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->rx_stream); } static int pcm_capture_ack(struct snd_pcm_substream *substream) diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index b18664fdf955..1f66c8be7528 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -230,14 +230,14 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) { struct snd_tscm *tscm = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&tscm->tx_stream); + return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->tx_stream); } static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) { struct snd_tscm *tscm = sbstrm->private_data; - return amdtp_stream_pcm_pointer(&tscm->rx_stream); + return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->rx_stream); } static int pcm_capture_ack(struct snd_pcm_substream *substream) -- cgit From e6dcc92fcea07f23c13996b7bb6a2a32ed4c6ed5 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 15:19:08 +0900 Subject: ALSA: firewire-lib: replace ack callback to flush isoc contexts in AMDTP domain An isoc context for AMDTP stream is flushed to queue packet by a call of pcm.ack. This commit extends this for AMDTP domain. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191018061911.24909-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 24 +++++++++++++++--------- sound/firewire/amdtp-stream.h | 3 ++- sound/firewire/bebob/bebob_pcm.c | 4 ++-- sound/firewire/dice/dice-pcm.c | 4 ++-- sound/firewire/digi00x/digi00x-pcm.c | 4 ++-- sound/firewire/fireface/ff-pcm.c | 4 ++-- sound/firewire/fireworks/fireworks_pcm.c | 4 ++-- sound/firewire/motu/motu-pcm.c | 4 ++-- sound/firewire/oxfw/oxfw-pcm.c | 4 ++-- sound/firewire/tascam/tascam-pcm.c | 4 ++-- 10 files changed, 33 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 23677b805b05..3d27d4ce2b45 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1139,23 +1139,29 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, EXPORT_SYMBOL_GPL(amdtp_domain_stream_pcm_pointer); /** - * amdtp_stream_pcm_ack - acknowledge queued PCM frames + * amdtp_domain_stream_pcm_ack - acknowledge queued PCM frames + * @d: the AMDTP domain. * @s: the AMDTP stream that transfers the PCM frames * * Returns zero always. */ -int amdtp_stream_pcm_ack(struct amdtp_stream *s) +int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s) { - /* - * Process isochronous packets for recent isochronous cycle to handle - * queued PCM frames. - */ - if (amdtp_stream_running(s)) - fw_iso_context_flush_completions(s->context); + struct amdtp_stream *irq_target = d->irq_target; + + // Process isochronous packets for recent isochronous cycle to handle + // queued PCM frames. + if (irq_target && amdtp_stream_running(irq_target)) { + // Queued packet should be processed without any kernel + // preemption to keep latency against bus cycle. + preempt_disable(); + fw_iso_context_flush_completions(irq_target->context); + preempt_enable(); + } return 0; } -EXPORT_SYMBOL(amdtp_stream_pcm_ack); +EXPORT_SYMBOL_GPL(amdtp_domain_stream_pcm_ack); /** * amdtp_stream_update - update the stream after a bus reset diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index ba0bbeddfdcb..470e77ca0061 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -198,7 +198,6 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime); void amdtp_stream_pcm_prepare(struct amdtp_stream *s); -int amdtp_stream_pcm_ack(struct amdtp_stream *s); void amdtp_stream_pcm_abort(struct amdtp_stream *s); extern const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT]; @@ -303,4 +302,6 @@ static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d, unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, struct amdtp_stream *s); +int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s); + #endif diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index dc15ea8d0dc5..1b100159f4c5 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -332,14 +332,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; - return amdtp_stream_pcm_ack(&bebob->tx_stream); + return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->tx_stream); } static int pcm_playback_ack(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; - return amdtp_stream_pcm_ack(&bebob->rx_stream); + return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->rx_stream); } int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 81b78e7d181d..f1848fb39bd0 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -394,7 +394,7 @@ static int capture_ack(struct snd_pcm_substream *substream) struct snd_dice *dice = substream->private_data; struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; - return amdtp_stream_pcm_ack(stream); + return amdtp_domain_stream_pcm_ack(&dice->domain, stream); } static int playback_ack(struct snd_pcm_substream *substream) @@ -402,7 +402,7 @@ static int playback_ack(struct snd_pcm_substream *substream) struct snd_dice *dice = substream->private_data; struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; - return amdtp_stream_pcm_ack(stream); + return amdtp_domain_stream_pcm_ack(&dice->domain, stream); } int snd_dice_create_pcm(struct snd_dice *dice) diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index f6a2053d5f10..8befc5d2ef22 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -315,14 +315,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream) { struct snd_dg00x *dg00x = substream->private_data; - return amdtp_stream_pcm_ack(&dg00x->tx_stream); + return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->tx_stream); } static int pcm_playback_ack(struct snd_pcm_substream *substream) { struct snd_dg00x *dg00x = substream->private_data; - return amdtp_stream_pcm_ack(&dg00x->rx_stream); + return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->rx_stream); } int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index 5af1dce90921..c29f87a65c0f 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -355,14 +355,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream) { struct snd_ff *ff = substream->private_data; - return amdtp_stream_pcm_ack(&ff->tx_stream); + return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->tx_stream); } static int pcm_playback_ack(struct snd_pcm_substream *substream) { struct snd_ff *ff = substream->private_data; - return amdtp_stream_pcm_ack(&ff->rx_stream); + return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->rx_stream); } int snd_ff_create_pcm_devices(struct snd_ff *ff) diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 71f5057caa0d..64c1bcf28dfa 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -362,14 +362,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - return amdtp_stream_pcm_ack(&efw->tx_stream); + return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->tx_stream); } static int pcm_playback_ack(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - return amdtp_stream_pcm_ack(&efw->rx_stream); + return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->rx_stream); } int snd_efw_create_pcm_devices(struct snd_efw *efw) diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 13e2577c2a07..55d3d6661731 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -333,14 +333,14 @@ static int capture_ack(struct snd_pcm_substream *substream) { struct snd_motu *motu = substream->private_data; - return amdtp_stream_pcm_ack(&motu->tx_stream); + return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->tx_stream); } static int playback_ack(struct snd_pcm_substream *substream) { struct snd_motu *motu = substream->private_data; - return amdtp_stream_pcm_ack(&motu->rx_stream); + return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->rx_stream); } int snd_motu_create_pcm_devices(struct snd_motu *motu) diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 3be35dfcf270..74bd1811cec2 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -406,14 +406,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - return amdtp_stream_pcm_ack(&oxfw->tx_stream); + return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->tx_stream); } static int pcm_playback_ack(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - return amdtp_stream_pcm_ack(&oxfw->rx_stream); + return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->rx_stream); } int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 1f66c8be7528..cd45f20ba515 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -244,14 +244,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream) { struct snd_tscm *tscm = substream->private_data; - return amdtp_stream_pcm_ack(&tscm->tx_stream); + return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->tx_stream); } static int pcm_playback_ack(struct snd_pcm_substream *substream) { struct snd_tscm *tscm = substream->private_data; - return amdtp_stream_pcm_ack(&tscm->rx_stream); + return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->rx_stream); } int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) -- cgit From 813dfbd6845e5366f2dbef190a695f8b06c1d83d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 15:19:09 +0900 Subject: ALSA: firewire-lib: cancel flushing isoc context in the laste step to process context callback The aim of AMDTP domain is to process several isoc context in the same time. However, current implementation is against this idea because it flushes each isoc context in the end of processing context callback. This commit cancels it. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191018061911.24909-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 3d27d4ce2b45..36c3f1f9dbff 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -842,8 +842,6 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, } s->event_count = event_count; - - fw_iso_context_queue_flush(s->context); } static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, @@ -897,8 +895,6 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, } s->event_count = event_count; - - fw_iso_context_queue_flush(s->context); } /* this is executed one time */ -- cgit From 60dd49298ec5803ca423836d5a724c3fe402cc3f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 15:19:10 +0900 Subject: ALSA: firewire-lib: handle several AMDTP streams in callback handler of IRQ target This commit changes AMDTP domain to run on an IT context of 1394 OHCI as IRQ target. No hardware interrupt is scheduled for the other isoc contexts. All of the isoc context are processed in a callback for an isoc context of IRQ target. The IRQ target is automatically selected from a list of AMDTP streams, thus users of AMDTP domain should add an AMDTP stream for IT context at least. The reason to select IT context as IRQ target is that the IT context runs on local 1394 OHCI controller and it can be used as reliable, constant IRQ generator. On the other hand, IR context can include skip cycle according to isoc packet transferred by device. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191018061911.24909-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 179 ++++++++++++++++++++++++++++++++---------- sound/firewire/amdtp-stream.h | 7 +- 2 files changed, 140 insertions(+), 46 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 36c3f1f9dbff..48be31eae9a5 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -482,13 +482,13 @@ static inline int queue_out_packet(struct amdtp_stream *s, } static inline int queue_in_packet(struct amdtp_stream *s, - struct fw_iso_packet *params, bool sched_irq) + struct fw_iso_packet *params) { // Queue one packet for IR context. params->header_length = s->ctx_data.tx.ctx_header_size; params->payload_length = s->ctx_data.tx.max_ctx_payload_length; params->skip = false; - return queue_packet(s, params, sched_irq); + return queue_packet(s, params, false); } static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2], @@ -790,15 +790,24 @@ static void process_ctx_payloads(struct amdtp_stream *s, update_pcm_pointers(s, pcm, pcm_frames); } +static void amdtp_stream_master_callback(struct fw_iso_context *context, + u32 tstamp, size_t header_length, + void *header, void *private_data); + +static void amdtp_stream_master_first_callback(struct fw_iso_context *context, + u32 tstamp, size_t header_length, + void *header, void *private_data); + static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, size_t header_length, void *header, void *private_data) { struct amdtp_stream *s = private_data; const __be32 *ctx_header = header; - unsigned int events_per_period = s->events_per_period; - unsigned int event_count = s->event_count; + unsigned int events_per_period = s->ctx_data.rx.events_per_period; + unsigned int event_count = s->ctx_data.rx.event_count; unsigned int packets; + bool is_irq_target; int i; if (s->packet_index < 0) @@ -811,6 +820,10 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, process_ctx_payloads(s, s->pkt_descs, packets); + is_irq_target = + !!(context->callback.sc == amdtp_stream_master_callback || + context->callback.sc == amdtp_stream_master_first_callback); + for (i = 0; i < packets; ++i) { const struct pkt_desc *desc = s->pkt_descs + i; unsigned int syt; @@ -829,10 +842,12 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, desc->data_blocks, desc->data_block_counter, syt, i); - event_count += desc->data_blocks; - if (event_count >= events_per_period) { - event_count -= events_per_period; - sched_irq = true; + if (is_irq_target) { + event_count += desc->data_blocks; + if (event_count >= events_per_period) { + event_count -= events_per_period; + sched_irq = true; + } } if (queue_out_packet(s, &template.params, sched_irq) < 0) { @@ -841,7 +856,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, } } - s->event_count = event_count; + s->ctx_data.rx.event_count = event_count; } static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, @@ -850,8 +865,6 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, { struct amdtp_stream *s = private_data; __be32 *ctx_header = header; - unsigned int events_per_period = s->events_per_period; - unsigned int event_count = s->event_count; unsigned int packets; int i; int err; @@ -873,31 +886,47 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, } for (i = 0; i < packets; ++i) { - const struct pkt_desc *desc = s->pkt_descs + i; struct fw_iso_packet params = {0}; - bool sched_irq = false; - - if (err >= 0) { - event_count += desc->data_blocks; - if (event_count >= events_per_period) { - event_count -= events_per_period; - sched_irq = true; - } - } else { - sched_irq = - !((s->packet_index + 1) % s->idle_irq_interval); - } - if (queue_in_packet(s, ¶ms, sched_irq) < 0) { + if (queue_in_packet(s, ¶ms) < 0) { cancel_stream(s); return; } } +} + +static void amdtp_stream_master_callback(struct fw_iso_context *context, + u32 tstamp, size_t header_length, + void *header, void *private_data) +{ + struct amdtp_domain *d = private_data; + struct amdtp_stream *irq_target = d->irq_target; + struct amdtp_stream *s; + + out_stream_callback(context, tstamp, header_length, header, irq_target); + if (amdtp_streaming_error(irq_target)) + goto error; - s->event_count = event_count; + list_for_each_entry(s, &d->streams, list) { + if (s != irq_target && amdtp_stream_running(s)) { + fw_iso_context_flush_completions(s->context); + if (amdtp_streaming_error(s)) + goto error; + } + } + + return; +error: + if (amdtp_stream_running(irq_target)) + cancel_stream(irq_target); + + list_for_each_entry(s, &d->streams, list) { + if (amdtp_stream_running(s)) + cancel_stream(s); + } } -/* this is executed one time */ +// this is executed one time. static void amdtp_stream_first_callback(struct fw_iso_context *context, u32 tstamp, size_t header_length, void *header, void *private_data) @@ -928,18 +957,39 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, context->callback.sc(context, tstamp, header_length, header, s); } +static void amdtp_stream_master_first_callback(struct fw_iso_context *context, + u32 tstamp, size_t header_length, + void *header, void *private_data) +{ + struct amdtp_domain *d = private_data; + struct amdtp_stream *s = d->irq_target; + const __be32 *ctx_header = header; + + s->callbacked = true; + wake_up(&s->callback_wait); + + s->start_cycle = compute_it_cycle(*ctx_header, s->queue_size); + + context->callback.sc = amdtp_stream_master_callback; + + context->callback.sc(context, tstamp, header_length, header, d); +} + /** * amdtp_stream_start - start transferring packets * @s: the AMDTP stream to start * @channel: the isochronous channel on the bus * @speed: firewire speed code + * @d: the AMDTP domain to which the AMDTP stream belongs + * @is_irq_target: whether isoc context for the AMDTP stream is used to generate + * hardware IRQ. * * The stream cannot be started until it has been configured with * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI * device can be started. */ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, - struct amdtp_domain *d) + struct amdtp_domain *d, bool is_irq_target) { static const struct { unsigned int data_block; @@ -955,10 +1005,13 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, }; unsigned int events_per_buffer = d->events_per_buffer; unsigned int events_per_period = d->events_per_period; + unsigned int idle_irq_interval; unsigned int ctx_header_size; unsigned int max_ctx_payload_size; enum dma_data_direction dir; int type, tag, err; + fw_iso_callback_t ctx_cb; + void *ctx_data; mutex_lock(&s->mutex); @@ -969,6 +1022,12 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, } if (s->direction == AMDTP_IN_STREAM) { + // NOTE: IT context should be used for constant IRQ. + if (is_irq_target) { + err = -EINVAL; + goto err_unlock; + } + s->data_block_counter = UINT_MAX; } else { entry = &initial_state[s->sfc]; @@ -1008,22 +1067,29 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, if (events_per_buffer == 0) events_per_buffer = events_per_period * 3; - s->idle_irq_interval = - DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period, - amdtp_rate_table[s->sfc]); + idle_irq_interval = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period, + amdtp_rate_table[s->sfc]); s->queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer, amdtp_rate_table[s->sfc]); - s->events_per_period = events_per_period; - s->event_count = 0; err = iso_packets_buffer_init(&s->buffer, s->unit, s->queue_size, max_ctx_payload_size, dir); if (err < 0) goto err_unlock; + if (is_irq_target) { + s->ctx_data.rx.events_per_period = events_per_period; + s->ctx_data.rx.event_count = 0; + ctx_cb = amdtp_stream_master_first_callback; + ctx_data = d; + } else { + ctx_cb = amdtp_stream_first_callback; + ctx_data = s; + } + s->context = fw_iso_context_create(fw_parent_device(s->unit)->card, type, channel, speed, ctx_header_size, - amdtp_stream_first_callback, s); + ctx_cb, ctx_data); if (IS_ERR(s->context)) { err = PTR_ERR(s->context); if (err == -EBUSY) @@ -1054,14 +1120,20 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, s->packet_index = 0; do { struct fw_iso_packet params; - bool sched_irq; - sched_irq = !((s->packet_index + 1) % s->idle_irq_interval); if (s->direction == AMDTP_IN_STREAM) { - err = queue_in_packet(s, ¶ms, sched_irq); + err = queue_in_packet(s, ¶ms); } else { + bool sched_irq = false; + params.header_length = 0; params.payload_length = 0; + + if (is_irq_target) { + sched_irq = !((s->packet_index + 1) % + idle_irq_interval); + } + err = queue_out_packet(s, ¶ms, sched_irq); } if (err < 0) @@ -1276,17 +1348,33 @@ int amdtp_domain_start(struct amdtp_domain *d) struct amdtp_stream *s; int err = 0; + // Select an IT context as IRQ target. list_for_each_entry(s, &d->streams, list) { - err = amdtp_stream_start(s, s->channel, s->speed, d); - if (err < 0) + if (s->direction == AMDTP_OUT_STREAM) break; } + if (!s) + return -ENXIO; + d->irq_target = s; - if (err < 0) { - list_for_each_entry(s, &d->streams, list) - amdtp_stream_stop(s); + list_for_each_entry(s, &d->streams, list) { + if (s != d->irq_target) { + err = amdtp_stream_start(s, s->channel, s->speed, d, + false); + if (err < 0) + goto error; + } } + s = d->irq_target; + err = amdtp_stream_start(s, s->channel, s->speed, d, true); + if (err < 0) + goto error; + + return 0; +error: + list_for_each_entry(s, &d->streams, list) + amdtp_stream_stop(s); return err; } EXPORT_SYMBOL_GPL(amdtp_domain_start); @@ -1299,12 +1387,17 @@ void amdtp_domain_stop(struct amdtp_domain *d) { struct amdtp_stream *s, *next; + if (d->irq_target) + amdtp_stream_stop(d->irq_target); + list_for_each_entry_safe(s, next, &d->streams, list) { list_del(&s->list); - amdtp_stream_stop(s); + if (s != d->irq_target) + amdtp_stream_stop(s); } d->events_per_period = 0; + d->irq_target = NULL; } EXPORT_SYMBOL_GPL(amdtp_domain_stop); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 470e77ca0061..c4bde69c2d4f 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -143,11 +143,12 @@ struct amdtp_stream { // To generate CIP header. unsigned int fdf; int syt_override; + + // To generate constant hardware IRQ. + unsigned int event_count; + unsigned int events_per_period; } rx; } ctx_data; - unsigned int event_count; - unsigned int events_per_period; - unsigned int idle_irq_interval; /* For CIP headers. */ unsigned int source_node_id_field; -- cgit From acfedcbe1ce4c69e1da914f39c02d945c80198d4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Oct 2019 15:19:11 +0900 Subject: ALSA: firewire-lib: postpone to start IR context Some devices have a quirk to postpone transmission of isoc packet for several dozen or hundred isoc cycles since configured to transmit. Furthermore, some devices have a quirk to transmit isoc packet with discontinued data of its header. In 1394 OHCI specification, software allows to start isoc context with certain isoc cycle. Linux firewire subsystem has kernel API to use it as well. This commit uses the functionality of 1394 OHCI controller to handle the quirks. At present, this feature is convenient to ALSA bebob and fireface driver. As a result, some devices can be safely handled, as long as I know: - MAudio FireWire solo - MAudio ProFire Lightbridge - MAudio FireWire 410 - Roland FA-66 Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191018061911.24909-7-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 79 ++++++++++++++++++++++++++--- sound/firewire/amdtp-stream.h | 2 +- sound/firewire/bebob/bebob_stream.c | 10 +++- sound/firewire/dice/dice-stream.c | 2 +- sound/firewire/digi00x/digi00x-stream.c | 2 +- sound/firewire/fireface/ff-stream.c | 10 +++- sound/firewire/fireworks/fireworks_stream.c | 2 +- sound/firewire/motu/motu-stream.c | 2 +- sound/firewire/oxfw/oxfw-stream.c | 2 +- sound/firewire/tascam/tascam-stream.c | 2 +- 10 files changed, 98 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 48be31eae9a5..37d38efb4c87 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -983,13 +984,16 @@ static void amdtp_stream_master_first_callback(struct fw_iso_context *context, * @d: the AMDTP domain to which the AMDTP stream belongs * @is_irq_target: whether isoc context for the AMDTP stream is used to generate * hardware IRQ. + * @start_cycle: the isochronous cycle to start the context. Start immediately + * if negative value is given. * * The stream cannot be started until it has been configured with * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI * device can be started. */ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, - struct amdtp_domain *d, bool is_irq_target) + struct amdtp_domain *d, bool is_irq_target, + int start_cycle) { static const struct { unsigned int data_block; @@ -1146,7 +1150,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, tag |= FW_ISO_CONTEXT_MATCH_TAG0; s->callbacked = false; - err = fw_iso_context_start(s->context, -1, 0, tag); + err = fw_iso_context_start(s->context, start_cycle, 0, tag); if (err < 0) goto err_pkt_descs; @@ -1339,14 +1343,40 @@ int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, } EXPORT_SYMBOL_GPL(amdtp_domain_add_stream); +static int get_current_cycle_time(struct fw_card *fw_card, int *cur_cycle) +{ + int generation; + int rcode; + __be32 reg; + u32 data; + + // This is a request to local 1394 OHCI controller and expected to + // complete without any event waiting. + generation = fw_card->generation; + smp_rmb(); // node_id vs. generation. + rcode = fw_run_transaction(fw_card, TCODE_READ_QUADLET_REQUEST, + fw_card->node_id, generation, SCODE_100, + CSR_REGISTER_BASE + CSR_CYCLE_TIME, + ®, sizeof(reg)); + if (rcode != RCODE_COMPLETE) + return -EIO; + + data = be32_to_cpu(reg); + *cur_cycle = data >> 12; + + return 0; +} + /** * amdtp_domain_start - start sending packets for isoc context in the domain. * @d: the AMDTP domain. + * @ir_delay_cycle: the cycle delay to start all IR contexts. */ -int amdtp_domain_start(struct amdtp_domain *d) +int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle) { struct amdtp_stream *s; - int err = 0; + int cycle; + int err; // Select an IT context as IRQ target. list_for_each_entry(s, &d->streams, list) { @@ -1357,17 +1387,54 @@ int amdtp_domain_start(struct amdtp_domain *d) return -ENXIO; d->irq_target = s; + if (ir_delay_cycle > 0) { + struct fw_card *fw_card = fw_parent_device(s->unit)->card; + + err = get_current_cycle_time(fw_card, &cycle); + if (err < 0) + return err; + + // No need to care overflow in cycle field because of enough + // width. + cycle += ir_delay_cycle; + + // Round up to sec field. + if ((cycle & 0x00001fff) >= CYCLES_PER_SECOND) { + unsigned int sec; + + // The sec field can overflow. + sec = (cycle & 0xffffe000) >> 13; + cycle = (++sec << 13) | + ((cycle & 0x00001fff) / CYCLES_PER_SECOND); + } + + // In OHCI 1394 specification, lower 2 bits are available for + // sec field. + cycle &= 0x00007fff; + } else { + cycle = -1; + } + list_for_each_entry(s, &d->streams, list) { + int cycle_match; + + if (s->direction == AMDTP_IN_STREAM) { + cycle_match = cycle; + } else { + // IT context starts immediately. + cycle_match = -1; + } + if (s != d->irq_target) { err = amdtp_stream_start(s, s->channel, s->speed, d, - false); + false, cycle_match); if (err < 0) goto error; } } s = d->irq_target; - err = amdtp_stream_start(s, s->channel, s->speed, d, true); + err = amdtp_stream_start(s, s->channel, s->speed, d, true, -1); if (err < 0) goto error; diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index c4bde69c2d4f..f2d44e2dc3c8 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -288,7 +288,7 @@ void amdtp_domain_destroy(struct amdtp_domain *d); int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, int channel, int speed); -int amdtp_domain_start(struct amdtp_domain *d); +int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle); void amdtp_domain_stop(struct amdtp_domain *d); static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d, diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 5e4a61458be2..7ac0d9f495c4 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -658,7 +658,15 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) if (err < 0) goto error; - err = amdtp_domain_start(&bebob->domain); + // The device postpones start of transmission mostly for 1 sec + // after receives packets firstly. For safe, IR context starts + // 1.5 sec (=12000 cycles) later. This is within 2.0 sec + // (=CALLBACK_TIMEOUT). + // Furthermore, some devices transfer isoc packets with + // discontinuous counter in the beginning of packet streaming. + // The delay has an effect to avoid detection of this + // discontinuity. + err = amdtp_domain_start(&bebob->domain, 12000); if (err < 0) goto error; diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 0cff346e8052..6a3d60913e10 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -462,7 +462,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) goto error; } - err = amdtp_domain_start(&dice->domain); + err = amdtp_domain_start(&dice->domain, 0); if (err < 0) goto error; diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index 0c539188ba18..405d6903bfbc 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -375,7 +375,7 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) if (err < 0) goto error; - err = amdtp_domain_start(&dg00x->domain); + err = amdtp_domain_start(&dg00x->domain, 0); if (err < 0) goto error; diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index a13754f914e8..63b79c4a5405 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -184,6 +184,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) */ if (!amdtp_stream_running(&ff->rx_stream)) { int spd = fw_parent_device(ff->unit)->max_speed; + unsigned int ir_delay_cycle; err = ff->spec->protocol->begin_session(ff, rate); if (err < 0) @@ -199,7 +200,14 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) if (err < 0) goto error; - err = amdtp_domain_start(&ff->domain); + // The device postpones start of transmission mostly for several + // cycles after receiving packets firstly. + if (ff->spec->protocol == &snd_ff_protocol_ff800) + ir_delay_cycle = 800; // = 100 msec + else + ir_delay_cycle = 16; // = 2 msec + + err = amdtp_domain_start(&ff->domain, ir_delay_cycle); if (err < 0) goto error; diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index f35a33d4d4e6..2206af0fef42 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -272,7 +272,7 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw) if (err < 0) goto error; - err = amdtp_domain_start(&efw->domain); + err = amdtp_domain_start(&efw->domain, 0); if (err < 0) goto error; diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 9975770c9b1f..a17ddceb1bec 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -260,7 +260,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) if (err < 0) goto stop_streams; - err = amdtp_domain_start(&motu->domain); + err = amdtp_domain_start(&motu->domain, 0); if (err < 0) goto stop_streams; diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 995e9c5bd84b..501a80094bf7 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -355,7 +355,7 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) } } - err = amdtp_domain_start(&oxfw->domain); + err = amdtp_domain_start(&oxfw->domain, 0); if (err < 0) goto error; diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index a9b3b7eb6d21..eb07e1decf9b 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -473,7 +473,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) if (err < 0) goto error; - err = amdtp_domain_start(&tscm->domain); + err = amdtp_domain_start(&tscm->domain, 0); if (err < 0) return err; -- cgit From 7d2f70f248ab0e4251591cf7b36cc43281941f56 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Sun, 20 Oct 2019 17:30:07 +0200 Subject: ASoC: msm8916-wcd-analog: Add earpiece PM8916 supports an earpiece as another (small) speaker. The earpiece is routed through RX MIX1 similarly to the headphones, except that RDAC2 MUX is set to RX1. Signed-off-by: Stephan Gerhold Acked-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20191020153007.206070-2-stephan@gerhold.net Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 54 +++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 667e9f73aba3..4168b0a0aafb 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -228,6 +228,10 @@ #define CDC_A_RX_EAR_CTL (0xf19E) #define RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK BIT(0) #define RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE BIT(0) +#define RX_EAR_CTL_PA_EAR_PA_EN_MASK BIT(6) +#define RX_EAR_CTL_PA_EAR_PA_EN_ENABLE BIT(6) +#define RX_EAR_CTL_PA_SEL_MASK BIT(7) +#define RX_EAR_CTL_PA_SEL BIT(7) #define CDC_A_SPKR_DAC_CTL (0xf1B0) #define SPKR_DAC_CTL_DAC_RESET_MASK BIT(4) @@ -312,6 +316,7 @@ static const char *const hph_text[] = { "ZERO", "Switch", }; static const struct soc_enum hph_enum = SOC_ENUM_SINGLE_VIRT( ARRAY_SIZE(hph_text), hph_text); +static const struct snd_kcontrol_new ear_mux = SOC_DAPM_ENUM("EAR_S", hph_enum); static const struct snd_kcontrol_new hphl_mux = SOC_DAPM_ENUM("HPHL", hph_enum); static const struct snd_kcontrol_new hphr_mux = SOC_DAPM_ENUM("HPHR", hph_enum); @@ -685,6 +690,34 @@ static int pm8916_wcd_analog_enable_spk_pa(struct snd_soc_dapm_widget *w, return 0; } +static int pm8916_wcd_analog_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL, + RX_EAR_CTL_PA_SEL_MASK, RX_EAR_CTL_PA_SEL); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL, + RX_EAR_CTL_PA_EAR_PA_EN_MASK, + RX_EAR_CTL_PA_EAR_PA_EN_ENABLE); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL, + RX_EAR_CTL_PA_EAR_PA_EN_MASK, 0); + /* Delay to reduce ear turn off pop */ + usleep_range(7000, 7100); + snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL, + RX_EAR_CTL_PA_SEL_MASK, 0); + break; + } + return 0; +} + static const struct reg_default wcd_reg_defaults_2_0[] = { {CDC_A_RX_COM_OCP_CTL, 0xD1}, {CDC_A_RX_COM_OCP_COUNT, 0xFF}, @@ -801,12 +834,20 @@ static const struct snd_soc_dapm_route pm8916_wcd_analog_audio_map[] = { {"PDM_TX", NULL, "A_MCLK2"}, {"A_MCLK2", NULL, "A_MCLK"}, + /* Earpiece (RX MIX1) */ + {"EAR", NULL, "EAR_S"}, + {"EAR_S", "Switch", "EAR PA"}, + {"EAR PA", NULL, "RX_BIAS"}, + {"EAR PA", NULL, "HPHL DAC"}, + {"EAR PA", NULL, "HPHR DAC"}, + {"EAR PA", NULL, "EAR CP"}, + /* Headset (RX MIX1 and RX MIX2) */ {"HEADPHONE", NULL, "HPHL PA"}, {"HEADPHONE", NULL, "HPHR PA"}, - {"HPHL PA", NULL, "EAR_HPHL_CLK"}, - {"HPHR PA", NULL, "EAR_HPHR_CLK"}, + {"HPHL DAC", NULL, "EAR_HPHL_CLK"}, + {"HPHR DAC", NULL, "EAR_HPHR_CLK"}, {"CP", NULL, "NCP_CLK"}, @@ -847,11 +888,20 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { SND_SOC_DAPM_INPUT("AMIC1"), SND_SOC_DAPM_INPUT("AMIC3"), SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_OUTPUT("EAR"), SND_SOC_DAPM_OUTPUT("HEADPHONE"), /* RX stuff */ SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM, + 0, 0, NULL, 0, + pm8916_wcd_analog_enable_ear_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, &ear_mux), + SND_SOC_DAPM_SUPPLY("EAR CP", CDC_A_NCP_EN, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0), SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux), SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL, -- cgit From b6bc07d4360dbf766e551f18e43c67fff6784955 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Sat, 19 Oct 2019 15:02:51 +0800 Subject: ASoC: cros_ec_codec: support WoV 1. Get EC codec's capabilities. 2. Get and set SHM address if any. 3. Transmit language model to EC codec if needed. 4. Start to read audio data from EC codec if receives host event. Signed-off-by: Tzung-Bi Shih Acked-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20191019143504.1.I5388b69a7a9c551078fed216a77440cee6dedf49@changeid Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 + sound/soc/codecs/cros_ec_codec.c | 700 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 700 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5a706102db04..1a4b084cc90d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -509,6 +509,8 @@ config SND_SOC_CQ0093VC config SND_SOC_CROS_EC_CODEC tristate "codec driver for ChromeOS EC" depends on CROS_EC + select CRYPTO + select CRYPTO_SHA256 help If you say yes here you will get support for the ChromeOS Embedded Controller's Audio Codec. diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 3d4f9e82d6e9..dd14caf9091a 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -8,10 +8,16 @@ * EC for audio function. */ +#include +#include #include #include +#include +#include #include #include +#include +#include #include #include #include @@ -23,8 +29,45 @@ struct cros_ec_codec_priv { struct device *dev; struct cros_ec_device *ec_device; + + /* common */ + uint32_t ec_capabilities; + + uint64_t ec_shm_addr; + uint32_t ec_shm_len; + + uint64_t ap_shm_phys_addr; + uint32_t ap_shm_len; + uint64_t ap_shm_addr; + uint64_t ap_shm_last_alloc; + + /* DMIC */ + atomic_t dmic_probed; + + /* WoV */ + bool wov_enabled; + uint8_t *wov_audio_shm_p; + uint32_t wov_audio_shm_len; + uint8_t wov_audio_shm_type; + uint8_t *wov_lang_shm_p; + uint32_t wov_lang_shm_len; + uint8_t wov_lang_shm_type; + + struct mutex wov_dma_lock; + uint8_t wov_buf[64000]; + uint32_t wov_rp, wov_wp; + size_t wov_dma_offset; + bool wov_burst_read; + struct snd_pcm_substream *wov_substream; + struct delayed_work wov_copy_work; + struct notifier_block wov_notifier; }; +static int ec_codec_capable(struct cros_ec_codec_priv *priv, uint8_t cap) +{ + return priv->ec_capabilities & BIT(cap); +} + static int send_ec_host_command(struct cros_ec_device *ec_dev, uint32_t cmd, uint8_t *out, size_t outsize, uint8_t *in, size_t insize) @@ -57,6 +100,41 @@ error: return ret; } +static int calculate_sha256(struct cros_ec_codec_priv *priv, + uint8_t *buf, uint32_t size, uint8_t *digest) +{ + struct crypto_shash *tfm; + + tfm = crypto_alloc_shash("sha256", CRYPTO_ALG_TYPE_SHASH, 0); + if (IS_ERR(tfm)) { + dev_err(priv->dev, "can't alloc shash\n"); + return PTR_ERR(tfm); + } + + { + SHASH_DESC_ON_STACK(desc, tfm); + + desc->tfm = tfm; + + crypto_shash_digest(desc, buf, size, digest); + shash_desc_zero(desc); + } + + crypto_free_shash(tfm); + +#ifdef DEBUG + { + char digest_str[65]; + + bin2hex(digest_str, digest, 32); + digest_str[64] = 0; + dev_dbg(priv->dev, "hash=%s\n", digest_str); + } +#endif + + return 0; +} + static int dmic_get_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -147,6 +225,9 @@ static int dmic_probe(struct snd_soc_component *component) struct ec_response_ec_codec_dmic_get_max_gain r; int ret; + if (!atomic_add_unless(&priv->dmic_probed, 1, 1)) + return 0; + p.cmd = EC_CODEC_DMIC_GET_MAX_GAIN; ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, @@ -324,23 +405,638 @@ static const struct snd_soc_component_driver i2s_rx_component_driver = { .num_dapm_routes = ARRAY_SIZE(i2s_rx_dapm_routes), }; +static void *wov_map_shm(struct cros_ec_codec_priv *priv, + uint8_t shm_id, uint32_t *len, uint8_t *type) +{ + struct ec_param_ec_codec p; + struct ec_response_ec_codec_get_shm_addr r; + uint32_t req, offset; + + p.cmd = EC_CODEC_GET_SHM_ADDR; + p.get_shm_addr_param.shm_id = shm_id; + if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)) < 0) { + dev_err(priv->dev, "failed to EC_CODEC_GET_SHM_ADDR\n"); + return NULL; + } + + dev_dbg(priv->dev, "phys_addr=%#llx, len=%#x\n", r.phys_addr, r.len); + + *len = r.len; + *type = r.type; + + switch (r.type) { + case EC_CODEC_SHM_TYPE_EC_RAM: + return (void __force *)devm_ioremap_wc(priv->dev, + r.phys_addr + priv->ec_shm_addr, r.len); + case EC_CODEC_SHM_TYPE_SYSTEM_RAM: + if (r.phys_addr) { + dev_err(priv->dev, "unknown status\n"); + return NULL; + } + + req = round_up(r.len, PAGE_SIZE); + dev_dbg(priv->dev, "round up from %u to %u\n", r.len, req); + + if (priv->ap_shm_last_alloc + req > + priv->ap_shm_phys_addr + priv->ap_shm_len) { + dev_err(priv->dev, "insufficient space for AP SHM\n"); + return NULL; + } + + dev_dbg(priv->dev, "alloc AP SHM addr=%#llx, len=%#x\n", + priv->ap_shm_last_alloc, req); + + p.cmd = EC_CODEC_SET_SHM_ADDR; + p.set_shm_addr_param.phys_addr = priv->ap_shm_last_alloc; + p.set_shm_addr_param.len = req; + p.set_shm_addr_param.shm_id = shm_id; + if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, + (uint8_t *)&p, sizeof(p), + NULL, 0) < 0) { + dev_err(priv->dev, "failed to EC_CODEC_SET_SHM_ADDR\n"); + return NULL; + } + + /* + * Note: EC codec only requests for `r.len' but we allocate + * round up PAGE_SIZE `req'. + */ + offset = priv->ap_shm_last_alloc - priv->ap_shm_phys_addr; + priv->ap_shm_last_alloc += req; + + return (void *)(uintptr_t)(priv->ap_shm_addr + offset); + default: + return NULL; + } +} + +static bool wov_queue_full(struct cros_ec_codec_priv *priv) +{ + return ((priv->wov_wp + 1) % sizeof(priv->wov_buf)) == priv->wov_rp; +} + +static size_t wov_queue_size(struct cros_ec_codec_priv *priv) +{ + if (priv->wov_wp >= priv->wov_rp) + return priv->wov_wp - priv->wov_rp; + else + return sizeof(priv->wov_buf) - priv->wov_rp + priv->wov_wp; +} + +static void wov_queue_dequeue(struct cros_ec_codec_priv *priv, size_t len) +{ + struct snd_pcm_runtime *runtime = priv->wov_substream->runtime; + size_t req; + + while (len) { + req = min(len, runtime->dma_bytes - priv->wov_dma_offset); + if (priv->wov_wp >= priv->wov_rp) + req = min(req, (size_t)priv->wov_wp - priv->wov_rp); + else + req = min(req, sizeof(priv->wov_buf) - priv->wov_rp); + + memcpy(runtime->dma_area + priv->wov_dma_offset, + priv->wov_buf + priv->wov_rp, req); + + priv->wov_dma_offset += req; + if (priv->wov_dma_offset == runtime->dma_bytes) + priv->wov_dma_offset = 0; + + priv->wov_rp += req; + if (priv->wov_rp == sizeof(priv->wov_buf)) + priv->wov_rp = 0; + + len -= req; + } + + snd_pcm_period_elapsed(priv->wov_substream); +} + +static void wov_queue_try_dequeue(struct cros_ec_codec_priv *priv) +{ + size_t period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); + + while (period_bytes && wov_queue_size(priv) >= period_bytes) { + wov_queue_dequeue(priv, period_bytes); + period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); + } +} + +static void wov_queue_enqueue(struct cros_ec_codec_priv *priv, + uint8_t *addr, size_t len, bool iomem) +{ + size_t req; + + while (len) { + if (wov_queue_full(priv)) { + wov_queue_try_dequeue(priv); + + if (wov_queue_full(priv)) { + dev_err(priv->dev, "overrun detected\n"); + return; + } + } + + if (priv->wov_wp >= priv->wov_rp) + req = sizeof(priv->wov_buf) - priv->wov_wp; + else + /* Note: waste 1-byte to differentiate full and empty */ + req = priv->wov_rp - priv->wov_wp - 1; + req = min(req, len); + + if (iomem) + memcpy_fromio(priv->wov_buf + priv->wov_wp, + (void __force __iomem *)addr, req); + else + memcpy(priv->wov_buf + priv->wov_wp, addr, req); + + priv->wov_wp += req; + if (priv->wov_wp == sizeof(priv->wov_buf)) + priv->wov_wp = 0; + + addr += req; + len -= req; + } + + wov_queue_try_dequeue(priv); +} + +static int wov_read_audio_shm(struct cros_ec_codec_priv *priv) +{ + struct ec_param_ec_codec_wov p; + struct ec_response_ec_codec_wov_read_audio_shm r; + int ret; + + p.cmd = EC_CODEC_WOV_READ_AUDIO_SHM; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret) { + dev_err(priv->dev, "failed to EC_CODEC_WOV_READ_AUDIO_SHM\n"); + return ret; + } + + if (!r.len) + dev_dbg(priv->dev, "no data, sleep\n"); + else + wov_queue_enqueue(priv, priv->wov_audio_shm_p + r.offset, r.len, + priv->wov_audio_shm_type == EC_CODEC_SHM_TYPE_EC_RAM); + return -EAGAIN; +} + +static int wov_read_audio(struct cros_ec_codec_priv *priv) +{ + struct ec_param_ec_codec_wov p; + struct ec_response_ec_codec_wov_read_audio r; + int remain = priv->wov_burst_read ? 16000 : 320; + int ret; + + while (remain >= 0) { + p.cmd = EC_CODEC_WOV_READ_AUDIO; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret) { + dev_err(priv->dev, + "failed to EC_CODEC_WOV_READ_AUDIO\n"); + return ret; + } + + if (!r.len) { + dev_dbg(priv->dev, "no data, sleep\n"); + priv->wov_burst_read = false; + break; + } + + wov_queue_enqueue(priv, r.buf, r.len, false); + remain -= r.len; + } + + return -EAGAIN; +} + +static void wov_copy_work(struct work_struct *w) +{ + struct cros_ec_codec_priv *priv = + container_of(w, struct cros_ec_codec_priv, wov_copy_work.work); + int ret; + + mutex_lock(&priv->wov_dma_lock); + if (!priv->wov_substream) { + dev_warn(priv->dev, "no pcm substream\n"); + goto leave; + } + + if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM)) + ret = wov_read_audio_shm(priv); + else + ret = wov_read_audio(priv); + + if (ret == -EAGAIN) + schedule_delayed_work(&priv->wov_copy_work, + msecs_to_jiffies(10)); + else if (ret) + dev_err(priv->dev, "failed to read audio data\n"); +leave: + mutex_unlock(&priv->wov_dma_lock); +} + +static int wov_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(c); + + ucontrol->value.integer.value[0] = priv->wov_enabled; + return 0; +} + +static int wov_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(c); + int enabled = ucontrol->value.integer.value[0]; + struct ec_param_ec_codec_wov p; + int ret; + + if (priv->wov_enabled != enabled) { + if (enabled) + p.cmd = EC_CODEC_WOV_ENABLE; + else + p.cmd = EC_CODEC_WOV_DISABLE; + + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), NULL, 0); + if (ret) { + dev_err(priv->dev, "failed to %s wov\n", + enabled ? "enable" : "disable"); + return ret; + } + + priv->wov_enabled = enabled; + } + + return 0; +} + +static int wov_set_lang_shm(struct cros_ec_codec_priv *priv, + uint8_t *buf, size_t size, uint8_t *digest) +{ + struct ec_param_ec_codec_wov p; + struct ec_param_ec_codec_wov_set_lang_shm *pp = &p.set_lang_shm_param; + int ret; + + if (size > priv->wov_lang_shm_len) { + dev_err(priv->dev, "no enough SHM size: %d\n", + priv->wov_lang_shm_len); + return -EIO; + } + + switch (priv->wov_lang_shm_type) { + case EC_CODEC_SHM_TYPE_EC_RAM: + memcpy_toio((void __force __iomem *)priv->wov_lang_shm_p, + buf, size); + memset_io((void __force __iomem *)priv->wov_lang_shm_p + size, + 0, priv->wov_lang_shm_len - size); + break; + case EC_CODEC_SHM_TYPE_SYSTEM_RAM: + memcpy(priv->wov_lang_shm_p, buf, size); + memset(priv->wov_lang_shm_p + size, 0, + priv->wov_lang_shm_len - size); + + /* make sure write to memory before calling host command */ + wmb(); + break; + } + + p.cmd = EC_CODEC_WOV_SET_LANG_SHM; + memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); + pp->total_len = size; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), NULL, 0); + if (ret) { + dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG_SHM\n"); + return ret; + } + + return 0; +} + +static int wov_set_lang(struct cros_ec_codec_priv *priv, + uint8_t *buf, size_t size, uint8_t *digest) +{ + struct ec_param_ec_codec_wov p; + struct ec_param_ec_codec_wov_set_lang *pp = &p.set_lang_param; + size_t i, req; + int ret; + + for (i = 0; i < size; i += req) { + req = min(size - i, ARRAY_SIZE(pp->buf)); + + p.cmd = EC_CODEC_WOV_SET_LANG; + memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); + pp->total_len = size; + pp->offset = i; + memcpy(pp->buf, buf + i, req); + pp->len = req; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), NULL, 0); + if (ret) { + dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG\n"); + return ret; + } + } + + return 0; +} + +static int wov_hotword_model_put(struct snd_kcontrol *kcontrol, + const unsigned int __user *bytes, + unsigned int size) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct ec_param_ec_codec_wov p; + struct ec_response_ec_codec_wov_get_lang r; + uint8_t digest[SHA256_DIGEST_SIZE]; + uint8_t *buf; + int ret; + + /* Skips the TLV header. */ + bytes += 2; + size -= 8; + + dev_dbg(priv->dev, "%s: size=%d\n", __func__, size); + + buf = memdup_user(bytes, size); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + ret = calculate_sha256(priv, buf, size, digest); + if (ret) + goto leave; + + p.cmd = EC_CODEC_WOV_GET_LANG; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret) + goto leave; + + if (memcmp(digest, r.hash, SHA256_DIGEST_SIZE) == 0) { + dev_dbg(priv->dev, "not updated"); + goto leave; + } + + if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_LANG_SHM)) + ret = wov_set_lang_shm(priv, buf, size, digest); + else + ret = wov_set_lang(priv, buf, size, digest); + +leave: + kfree(buf); + return ret; +} + +static struct snd_kcontrol_new wov_controls[] = { + SOC_SINGLE_BOOL_EXT("Wake-on-Voice Switch", 0, + wov_enable_get, wov_enable_put), + SND_SOC_BYTES_TLV("Hotword Model", 0x11000, NULL, + wov_hotword_model_put), +}; + +static struct snd_soc_dai_driver wov_dai_driver = { + .name = "Wake on Voice", + .capture = { + .stream_name = "WoV Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; + +static int wov_host_event(struct notifier_block *nb, + unsigned long queued_during_suspend, void *notify) +{ + struct cros_ec_codec_priv *priv = + container_of(nb, struct cros_ec_codec_priv, wov_notifier); + u32 host_event; + + dev_dbg(priv->dev, "%s\n", __func__); + + host_event = cros_ec_get_host_event(priv->ec_device); + if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_WOV)) { + schedule_delayed_work(&priv->wov_copy_work, 0); + return NOTIFY_OK; + } else { + return NOTIFY_DONE; + } +} + +static int wov_probe(struct snd_soc_component *component) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + int ret; + + mutex_init(&priv->wov_dma_lock); + INIT_DELAYED_WORK(&priv->wov_copy_work, wov_copy_work); + + priv->wov_notifier.notifier_call = wov_host_event; + ret = blocking_notifier_chain_register( + &priv->ec_device->event_notifier, &priv->wov_notifier); + if (ret) + return ret; + + if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_LANG_SHM)) { + priv->wov_lang_shm_p = wov_map_shm(priv, + EC_CODEC_SHM_ID_WOV_LANG, + &priv->wov_lang_shm_len, + &priv->wov_lang_shm_type); + if (!priv->wov_lang_shm_p) + return -EFAULT; + } + + if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM)) { + priv->wov_audio_shm_p = wov_map_shm(priv, + EC_CODEC_SHM_ID_WOV_AUDIO, + &priv->wov_audio_shm_len, + &priv->wov_audio_shm_type); + if (!priv->wov_audio_shm_p) + return -EFAULT; + } + + return dmic_probe(component); +} + +static void wov_remove(struct snd_soc_component *component) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + + blocking_notifier_chain_unregister( + &priv->ec_device->event_notifier, &priv->wov_notifier); +} + +static int wov_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + static const struct snd_pcm_hardware hw_param = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_16000, + .channels_min = 1, + .channels_max = 1, + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = 0x20000 / 8, + .periods_min = 8, + .periods_max = 8, + .buffer_bytes_max = 0x20000, + }; + + return snd_soc_set_runtime_hwparams(substream, &hw_param); +} + +static int wov_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + + mutex_lock(&priv->wov_dma_lock); + priv->wov_substream = substream; + priv->wov_rp = priv->wov_wp = 0; + priv->wov_dma_offset = 0; + priv->wov_burst_read = true; + mutex_unlock(&priv->wov_dma_lock); + + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); +} + +static int wov_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + + mutex_lock(&priv->wov_dma_lock); + wov_queue_dequeue(priv, wov_queue_size(priv)); + priv->wov_substream = NULL; + mutex_unlock(&priv->wov_dma_lock); + + cancel_delayed_work_sync(&priv->wov_copy_work); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static snd_pcm_uframes_t wov_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + + return bytes_to_frames(runtime, priv->wov_dma_offset); +} + +static struct page *wov_pcm_page(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned long offset) +{ + return snd_pcm_lib_get_vmalloc_page(substream, offset); +} + +static const struct snd_soc_component_driver wov_component_driver = { + .probe = wov_probe, + .remove = wov_remove, + .controls = wov_controls, + .num_controls = ARRAY_SIZE(wov_controls), + .open = wov_pcm_open, + .hw_params = wov_pcm_hw_params, + .hw_free = wov_pcm_hw_free, + .pointer = wov_pcm_pointer, + .page = wov_pcm_page, +}; + static int cros_ec_codec_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct cros_ec_device *ec_device = dev_get_drvdata(pdev->dev.parent); struct cros_ec_codec_priv *priv; + struct ec_param_ec_codec p; + struct ec_response_ec_codec_get_capabilities r; + int ret; +#ifdef CONFIG_OF + struct device_node *node; + struct resource res; + u64 ec_shm_size; + const __be32 *regaddr_p; +#endif priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; +#ifdef CONFIG_OF + regaddr_p = of_get_address(dev->of_node, 0, &ec_shm_size, NULL); + if (regaddr_p) { + priv->ec_shm_addr = of_read_number(regaddr_p, 2); + priv->ec_shm_len = ec_shm_size; + + dev_dbg(dev, "ec_shm_addr=%#llx len=%#x\n", + priv->ec_shm_addr, priv->ec_shm_len); + } + + node = of_parse_phandle(dev->of_node, "memory-region", 0); + if (node) { + ret = of_address_to_resource(node, 0, &res); + if (!ret) { + priv->ap_shm_phys_addr = res.start; + priv->ap_shm_len = resource_size(&res); + priv->ap_shm_addr = + (uint64_t)(uintptr_t)devm_ioremap_wc( + dev, priv->ap_shm_phys_addr, + priv->ap_shm_len); + priv->ap_shm_last_alloc = priv->ap_shm_phys_addr; + + dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n", + priv->ap_shm_phys_addr, priv->ap_shm_len); + } + } +#endif + priv->dev = dev; priv->ec_device = ec_device; + atomic_set(&priv->dmic_probed, 0); + + p.cmd = EC_CODEC_GET_CAPABILITIES; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret) { + dev_err(dev, "failed to EC_CODEC_GET_CAPABILITIES\n"); + return ret; + } + priv->ec_capabilities = r.capabilities; platform_set_drvdata(pdev, priv); - return devm_snd_soc_register_component(dev, &i2s_rx_component_driver, - &i2s_rx_dai_driver, 1); + ret = devm_snd_soc_register_component(dev, &i2s_rx_component_driver, + &i2s_rx_dai_driver, 1); + if (ret) + return ret; + + return devm_snd_soc_register_component(dev, &wov_component_driver, + &wov_dai_driver, 1); } #ifdef CONFIG_OF -- cgit From 8e8c533b132ad0ce9c99a50ff4c910a8dd7efb8e Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Sat, 19 Oct 2019 15:02:52 +0800 Subject: ASoC: mediatek: mt6358: support WoV Switch mono DMIC on to support wake-on-voice. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20191019143504.2.I57266d36564f393e9d701c9db648cc2efb0346fc@changeid Signed-off-by: Mark Brown --- sound/soc/codecs/mt6358.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index bb737fd678cc..1b830ea4f6ed 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -93,6 +93,8 @@ struct mt6358_priv { int mtkaif_protocol; struct regulator *avdd_reg; + + int wov_enabled; }; int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, @@ -464,6 +466,106 @@ static int mt6358_put_volsw(struct snd_kcontrol *kcontrol, return ret; } +static void mt6358_restore_pga(struct mt6358_priv *priv); + +static int mt6358_enable_wov_phase2(struct mt6358_priv *priv) +{ + /* analog */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0xffff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_DCXO_CW14, 0xffff, 0xa2b5); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0xffff, 0x0800); + mt6358_restore_pga(priv); + + regmap_update_bits(priv->regmap, MT6358_DCXO_CW13, 0xffff, 0x9929); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xffff, 0x0025); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON8, + 0xffff, 0x0005); + + /* digital */ + regmap_update_bits(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0, + 0xffff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3, 0xffff, 0x0120); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG0, 0xffff, 0xffff); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG1, 0xffff, 0x0200); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG2, 0xffff, 0x2424); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG3, 0xffff, 0xdbac); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG4, 0xffff, 0x029e); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG5, 0xffff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_POSDIV_CFG0, + 0xffff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_HPF_CFG0, + 0xffff, 0x0451); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_TOP, 0xffff, 0x68d1); + + return 0; +} + +static int mt6358_disable_wov_phase2(struct mt6358_priv *priv) +{ + /* digital */ + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_TOP, 0xffff, 0xc000); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_HPF_CFG0, + 0xffff, 0x0450); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_POSDIV_CFG0, + 0xffff, 0x0c00); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG5, 0xffff, 0x0100); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG4, 0xffff, 0x006c); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG3, 0xffff, 0xa879); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG2, 0xffff, 0x2323); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG1, 0xffff, 0x0400); + regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG0, 0xffff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3, 0xffff, 0x02d8); + regmap_update_bits(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0, + 0xffff, 0x0000); + + /* analog */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON8, + 0xffff, 0x0004); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xffff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_DCXO_CW13, 0xffff, 0x9829); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0xffff, 0x0000); + mt6358_restore_pga(priv); + regmap_update_bits(priv->regmap, MT6358_DCXO_CW14, 0xffff, 0xa2b5); + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0xffff, 0x0010); + + return 0; +} + +static int mt6358_get_wov(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(c); + + ucontrol->value.integer.value[0] = priv->wov_enabled; + return 0; +} + +static int mt6358_put_wov(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(c); + int enabled = ucontrol->value.integer.value[0]; + + if (priv->wov_enabled != enabled) { + if (enabled) + mt6358_enable_wov_phase2(priv); + else + mt6358_disable_wov_phase2(priv); + + priv->wov_enabled = enabled; + } + + return 0; +} + static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0); static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0); @@ -483,6 +585,9 @@ static const struct snd_kcontrol_new mt6358_snd_controls[] = { MT6358_AUDENC_ANA_CON0, MT6358_AUDENC_ANA_CON1, 8, 4, 0, snd_soc_get_volsw, mt6358_put_volsw, pga_tlv), + + SOC_SINGLE_BOOL_EXT("Wake-on-Voice Phase2 Switch", 0, + mt6358_get_wov, mt6358_put_wov), }; /* MUX */ -- cgit From 2cc3cd5fdc8ba07ba590204a3a6f6d16289d25e5 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Sat, 19 Oct 2019 15:02:54 +0800 Subject: ASoC: mediatek: mt8183: support WoV Add DAI link and pin muxing for wake on voice. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20191019143504.4.Ibf012d0cd8679d846213606dc5f426aea1ff590a@changeid Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 1 + .../mt8183/mt8183-mt6358-ts3a227-max98357.c | 70 +++++++++++++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 111e44b64b38..8b29f3979899 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -125,6 +125,7 @@ config SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A select SND_SOC_MAX98357A select SND_SOC_BT_SCO select SND_SOC_TS3A227E + select SND_SOC_CROS_EC_CODEC help This adds ASoC driver for Mediatek MT8183 boards with the MT6358 TS3A227E MAX98357A audio codec. diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index bb9cdc0d6552..0555f7d73d05 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -19,11 +19,12 @@ enum PINCTRL_PIN_STATE { PIN_STATE_DEFAULT = 0, PIN_TDM_OUT_ON, PIN_TDM_OUT_OFF, + PIN_WOV, PIN_STATE_MAX }; static const char * const mt8183_pin_str[PIN_STATE_MAX] = { - "default", "aud_tdm_out_on", "aud_tdm_out_off", + "default", "aud_tdm_out_on", "aud_tdm_out_off", "wov", }; struct mt8183_mt6358_ts3a227_max98357_priv { @@ -142,6 +143,11 @@ SND_SOC_DAILINK_DEFS(playback_hdmi, DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(wake_on_voice, + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + /* BE */ SND_SOC_DAILINK_DEFS(primary_codec, DAILINK_COMP_ARRAY(COMP_CPU("ADDA")), @@ -229,6 +235,41 @@ static struct snd_soc_ops mt8183_mt6358_tdm_ops = { .shutdown = mt8183_mt6358_tdm_shutdown, }; +static int +mt8183_mt6358_ts3a227_max98357_wov_startup( + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct mt8183_mt6358_ts3a227_max98357_priv *priv = + snd_soc_card_get_drvdata(card); + + return pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_WOV]); +} + +static void +mt8183_mt6358_ts3a227_max98357_wov_shutdown( + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct mt8183_mt6358_ts3a227_max98357_priv *priv = + snd_soc_card_get_drvdata(card); + int ret; + + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_STATE_DEFAULT]); + if (ret) + dev_err(card->dev, "%s failed to select state %d\n", + __func__, ret); +} + +static const struct snd_soc_ops mt8183_mt6358_ts3a227_max98357_wov_ops = { + .startup = mt8183_mt6358_ts3a227_max98357_wov_startup, + .shutdown = mt8183_mt6358_ts3a227_max98357_wov_shutdown, +}; + static struct snd_soc_dai_link mt8183_mt6358_ts3a227_max98357_dai_links[] = { /* FE */ @@ -306,6 +347,15 @@ mt8183_mt6358_ts3a227_max98357_dai_links[] = { .dpcm_playback = 1, SND_SOC_DAILINK_REG(playback_hdmi), }, + { + .name = "Wake on Voice", + .stream_name = "Wake on Voice", + .ignore_suspend = 1, + .ignore = 1, + SND_SOC_DAILINK_REG(wake_on_voice), + .ops = &mt8183_mt6358_ts3a227_max98357_wov_ops, + }, + /* BE */ { .name = "Primary Codec", @@ -429,7 +479,7 @@ static int mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8183_mt6358_ts3a227_max98357_card; - struct device_node *platform_node; + struct device_node *platform_node, *ec_codec; struct snd_soc_dai_link *dai_link; struct mt8183_mt6358_ts3a227_max98357_priv *priv; int ret; @@ -444,10 +494,24 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) return -EINVAL; } + ec_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,ec-codec", 0); + for_each_card_prelinks(card, i, dai_link) { if (dai_link->platforms->name) continue; - dai_link->platforms->of_node = platform_node; + + if (ec_codec && strcmp(dai_link->name, "Wake on Voice") == 0) { + dai_link->cpus[0].name = NULL; + dai_link->cpus[0].of_node = ec_codec; + dai_link->cpus[0].dai_name = NULL; + dai_link->codecs[0].name = NULL; + dai_link->codecs[0].of_node = ec_codec; + dai_link->codecs[0].dai_name = "Wake on Voice"; + dai_link->platforms[0].of_node = ec_codec; + dai_link->ignore = 0; + } else { + dai_link->platforms->of_node = platform_node; + } } mt8183_mt6358_ts3a227_max98357_headset_dev.dlc.of_node = -- cgit From bacd861452d2be86a4df341b12e32db7dac8021e Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 18 Oct 2019 15:38:48 +0800 Subject: ALSA: hda: Allow HDA to be runtime suspended when dGPU is not bound to a driver Nvidia proprietary driver doesn't support runtime power management, so when a user only wants to use the integrated GPU, it's a common practice to let dGPU not to bind any driver, and let its upstream port to be runtime suspended. At the end of runtime suspension the port uses platform power management to disable power through _OFF method of power resource, which is listed by _PR3. After commit b516ea586d71 ("PCI: Enable NVIDIA HDA controllers"), when the dGPU comes with an HDA function, the HDA won't be suspended if the dGPU is unbound, so the power resource can't be turned off by its upstream port driver. Commit 37a3a98ef601 ("ALSA: hda - Enable runtime PM only for discrete GPU") only allows HDA to be runtime suspended once GPU is bound, to keep APU's HDA working. However, HDA on dGPU isn't that useful if dGPU is not bound to any driver. So let's relax the runtime suspend requirement for dGPU's HDA function, to disable the power source to save lots of power. BugLink: https://bugs.launchpad.net/bugs/1840835 Fixes: b516ea586d71 ("PCI: Enable NVIDIA HDA controllers") Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20191018073848.14590-2-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 240f4ca76391..e63b871343e5 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1280,11 +1280,17 @@ static void init_vga_switcheroo(struct azx *chip) { struct hda_intel *hda = container_of(chip, struct hda_intel, chip); struct pci_dev *p = get_bound_vga(chip->pci); + struct pci_dev *parent; if (p) { dev_info(chip->card->dev, "Handle vga_switcheroo audio client\n"); hda->use_vga_switcheroo = 1; - chip->bus.keep_power = 1; /* cleared in either gpu_bound op or codec probe */ + + /* cleared in either gpu_bound op or codec probe, or when its + * upstream port has _PR3 (i.e. dGPU). + */ + parent = pci_upstream_bridge(p); + chip->bus.keep_power = parent ? !pci_pr3_present(parent) : 1; chip->driver_caps |= AZX_DCAPS_PM_RUNTIME; pci_dev_put(p); } -- cgit From b2d6ee75312649d55b41386d1d80cdbca48e3cf0 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Mon, 21 Oct 2019 16:08:16 +0200 Subject: ASOC: adau7118: Change regulators id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the regulators id in accordance with b670e44fc3bd. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20191021140816.262401-3-nuno.sa@analog.com Signed-off-by: Mark Brown --- sound/soc/codecs/adau7118.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c index bf5a5d75f81a..841229dcbca1 100644 --- a/sound/soc/codecs/adau7118.c +++ b/sound/soc/codecs/adau7118.c @@ -463,14 +463,14 @@ static void adau7118_regulator_disable(void *data) static int adau7118_regulator_setup(struct adau7118_data *st) { - st->iovdd = devm_regulator_get(st->dev, "IOVDD"); + st->iovdd = devm_regulator_get(st->dev, "iovdd"); if (IS_ERR(st->iovdd)) { dev_err(st->dev, "Could not get iovdd: %ld\n", PTR_ERR(st->iovdd)); return PTR_ERR(st->iovdd); } - st->dvdd = devm_regulator_get(st->dev, "DVDD"); + st->dvdd = devm_regulator_get(st->dev, "dvdd"); if (IS_ERR(st->dvdd)) { dev_err(st->dev, "Could not get dvdd: %ld\n", PTR_ERR(st->dvdd)); -- cgit From a0e0d135427cf699fe2dee77da0924e0b47f3170 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Fri, 18 Oct 2019 13:04:38 -0700 Subject: ASoC: rt5677: Add a PCM device for streaming hotword via SPI This patch implements a PCM interface for streaming hotword phrases over SPI. Userspace can open the PCM device at anytime. The stream is blocked when no hotword is detected. The mic audio buffer on the DSP is a ~128KByte ring buffer that holds ~4sec of audio samples recorded from the DMIC (S16_LE, mono, 16KHz). After a hotword is detected, previous 2 seconds of audio (containing the detected hotword) is streamed first, then live capture continues until userspace closes the PCM stream. When transferring, copy one period at a time then call snd_pcm_period_elapsed(). This reduces the latency of transferring the initial ~2sec of audio after hotword detect since audio samples are available for userspace earlier. Signed-off-by: Ben Zhang Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191018200449.141123-2-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 385 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5677-spi.h | 1 + 2 files changed, 386 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index d681488f5312..36c02d200cfc 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -24,6 +24,8 @@ #include #include +#include + #include "rt5677-spi.h" #define DRV_NAME "rt5677spi" @@ -45,9 +47,355 @@ #define RT5677_SPI_WRITE_16 0x1 #define RT5677_SPI_READ_16 0x0 +#define RT5677_BUF_BYTES_TOTAL 0x20000 +#define RT5677_MIC_BUF_ADDR 0x60030000 +#define RT5677_MODEL_ADDR 0x5FFC9800 +#define RT5677_MIC_BUF_BYTES ((u32)(RT5677_BUF_BYTES_TOTAL - \ + sizeof(u32))) +#define RT5677_MIC_BUF_FIRST_READ_SIZE 0x10000 + static struct spi_device *g_spi; static DEFINE_MUTEX(spi_mutex); +struct rt5677_dsp { + struct device *dev; + struct delayed_work copy_work; + struct mutex dma_lock; + struct snd_pcm_substream *substream; + size_t dma_offset; /* zero-based offset into runtime->dma_area */ + size_t avail_bytes; /* number of new bytes since last period */ + u32 mic_read_offset; /* zero-based offset into DSP's mic buffer */ + bool new_hotword; /* a new hotword is fired */ +}; + +static const struct snd_pcm_hardware rt5677_spi_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = RT5677_BUF_BYTES_TOTAL / 8, + .periods_min = 8, + .periods_max = 8, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = RT5677_BUF_BYTES_TOTAL, +}; + +static struct snd_soc_dai_driver rt5677_spi_dai = { + /* The DAI name "rt5677-dsp-cpu-dai" is not used. The actual DAI name + * registered with ASoC is the name of the device "spi-RT5677AA:00", + * because we only have one DAI. See snd_soc_register_dais(). + */ + .name = "rt5677-dsp-cpu-dai", + .id = 0, + .capture = { + .stream_name = "DSP Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; + +/* PCM for streaming audio from the DSP buffer */ +static int rt5677_spi_pcm_open( + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + snd_soc_set_runtime_hwparams(substream, &rt5677_spi_pcm_hardware); + return 0; +} + +static int rt5677_spi_pcm_close( + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct rt5677_dsp *rt5677_dsp = + snd_soc_component_get_drvdata(component); + + cancel_delayed_work_sync(&rt5677_dsp->copy_work); + return 0; +} + +static int rt5677_spi_hw_params( + struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct rt5677_dsp *rt5677_dsp = + snd_soc_component_get_drvdata(component); + int ret; + + mutex_lock(&rt5677_dsp->dma_lock); + ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + rt5677_dsp->substream = substream; + mutex_unlock(&rt5677_dsp->dma_lock); + + return ret; +} + +static int rt5677_spi_hw_free( + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct rt5677_dsp *rt5677_dsp = + snd_soc_component_get_drvdata(component); + + mutex_lock(&rt5677_dsp->dma_lock); + rt5677_dsp->substream = 0; + mutex_unlock(&rt5677_dsp->dma_lock); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int rt5677_spi_prepare( + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct rt5677_dsp *rt5677_dsp = + snd_soc_component_get_drvdata(component); + + rt5677_dsp->dma_offset = 0; + rt5677_dsp->avail_bytes = 0; + return 0; +} + +static snd_pcm_uframes_t rt5677_spi_pcm_pointer( + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct rt5677_dsp *rt5677_dsp = + snd_soc_component_get_drvdata(component); + + return bytes_to_frames(runtime, rt5677_dsp->dma_offset); +} + +static int rt5677_spi_mic_write_offset(u32 *mic_write_offset) +{ + int ret; + /* Grab the first 4 bytes that hold the write pointer on the + * dsp, and check to make sure that it points somewhere inside the + * buffer. + */ + ret = rt5677_spi_read(RT5677_MIC_BUF_ADDR, mic_write_offset, + sizeof(u32)); + if (ret) + return ret; + /* Adjust the offset so that it's zero-based */ + *mic_write_offset = *mic_write_offset - sizeof(u32); + return *mic_write_offset < RT5677_MIC_BUF_BYTES ? 0 : -EFAULT; +} + +/* + * Copy one contiguous block of audio samples from the DSP mic buffer to the + * dma_area of the pcm runtime. The receiving buffer may wrap around. + * @begin: start offset of the block to copy, in bytes. + * @end: offset of the first byte after the block to copy, must be greater + * than or equal to begin. + * + * Return: Zero if successful, or a negative error code on failure. + */ +static int rt5677_spi_copy_block(struct rt5677_dsp *rt5677_dsp, + u32 begin, u32 end) +{ + struct snd_pcm_runtime *runtime = rt5677_dsp->substream->runtime; + size_t bytes_per_frame = frames_to_bytes(runtime, 1); + size_t first_chunk_len, second_chunk_len; + int ret; + + if (begin > end || runtime->dma_bytes < 2 * bytes_per_frame) { + dev_err(rt5677_dsp->dev, + "Invalid copy from (%u, %u), dma_area size %zu\n", + begin, end, runtime->dma_bytes); + return -EINVAL; + } + + /* The block to copy is empty */ + if (begin == end) + return 0; + + /* If the incoming chunk is too big for the receiving buffer, only the + * last "receiving buffer size - one frame" bytes are copied. + */ + if (end - begin > runtime->dma_bytes - bytes_per_frame) + begin = end - (runtime->dma_bytes - bytes_per_frame); + + /* May need to split to two chunks, calculate the size of each */ + first_chunk_len = end - begin; + second_chunk_len = 0; + if (rt5677_dsp->dma_offset + first_chunk_len > runtime->dma_bytes) { + /* Receiving buffer wrapped around */ + second_chunk_len = first_chunk_len; + first_chunk_len = runtime->dma_bytes - rt5677_dsp->dma_offset; + second_chunk_len -= first_chunk_len; + } + + /* Copy first chunk */ + ret = rt5677_spi_read(RT5677_MIC_BUF_ADDR + sizeof(u32) + begin, + runtime->dma_area + rt5677_dsp->dma_offset, + first_chunk_len); + if (ret) + return ret; + rt5677_dsp->dma_offset += first_chunk_len; + if (rt5677_dsp->dma_offset == runtime->dma_bytes) + rt5677_dsp->dma_offset = 0; + + /* Copy second chunk */ + if (second_chunk_len) { + ret = rt5677_spi_read(RT5677_MIC_BUF_ADDR + sizeof(u32) + + begin + first_chunk_len, runtime->dma_area, + second_chunk_len); + if (!ret) + rt5677_dsp->dma_offset = second_chunk_len; + } + return ret; +} + +/* + * Copy a given amount of audio samples from the DSP mic buffer starting at + * mic_read_offset, to the dma_area of the pcm runtime. The source buffer may + * wrap around. mic_read_offset is updated after successful copy. + * @amount: amount of samples to copy, in bytes. + * + * Return: Zero if successful, or a negative error code on failure. + */ +static int rt5677_spi_copy(struct rt5677_dsp *rt5677_dsp, u32 amount) +{ + int ret = 0; + u32 target; + + if (amount == 0) + return ret; + + target = rt5677_dsp->mic_read_offset + amount; + /* Copy the first chunk in DSP's mic buffer */ + ret |= rt5677_spi_copy_block(rt5677_dsp, rt5677_dsp->mic_read_offset, + min(target, RT5677_MIC_BUF_BYTES)); + + if (target >= RT5677_MIC_BUF_BYTES) { + /* Wrap around, copy the second chunk */ + target -= RT5677_MIC_BUF_BYTES; + ret |= rt5677_spi_copy_block(rt5677_dsp, 0, target); + } + + if (!ret) + rt5677_dsp->mic_read_offset = target; + return ret; +} + +/* + * A delayed work that streams audio samples from the DSP mic buffer to the + * dma_area of the pcm runtime via SPI. + */ +static void rt5677_spi_copy_work(struct work_struct *work) +{ + struct rt5677_dsp *rt5677_dsp = + container_of(work, struct rt5677_dsp, copy_work.work); + struct snd_pcm_runtime *runtime; + u32 mic_write_offset; + size_t new_bytes, copy_bytes, period_bytes; + unsigned int delay; + int ret = 0; + + /* Ensure runtime->dma_area buffer does not go away while copying. */ + mutex_lock(&rt5677_dsp->dma_lock); + if (!rt5677_dsp->substream) { + dev_err(rt5677_dsp->dev, "No pcm substream\n"); + goto done; + } + + runtime = rt5677_dsp->substream->runtime; + + if (rt5677_spi_mic_write_offset(&mic_write_offset)) { + dev_err(rt5677_dsp->dev, "No mic_write_offset\n"); + goto done; + } + + /* If this is the first time that we've asked for streaming data after + * a hotword is fired, we should start reading from the previous 2 + * seconds of audio from wherever the mic_write_offset is currently. + */ + if (rt5677_dsp->new_hotword) { + rt5677_dsp->new_hotword = false; + /* See if buffer wraparound happens */ + if (mic_write_offset < RT5677_MIC_BUF_FIRST_READ_SIZE) + rt5677_dsp->mic_read_offset = RT5677_MIC_BUF_BYTES - + (RT5677_MIC_BUF_FIRST_READ_SIZE - + mic_write_offset); + else + rt5677_dsp->mic_read_offset = mic_write_offset - + RT5677_MIC_BUF_FIRST_READ_SIZE; + } + + /* Calculate the amount of new samples in bytes */ + if (rt5677_dsp->mic_read_offset <= mic_write_offset) + new_bytes = mic_write_offset - rt5677_dsp->mic_read_offset; + else + new_bytes = RT5677_MIC_BUF_BYTES + mic_write_offset + - rt5677_dsp->mic_read_offset; + + /* Copy all new samples from DSP mic buffer, one period at a time */ + period_bytes = snd_pcm_lib_period_bytes(rt5677_dsp->substream); + while (new_bytes) { + copy_bytes = min(new_bytes, period_bytes + - rt5677_dsp->avail_bytes); + ret = rt5677_spi_copy(rt5677_dsp, copy_bytes); + if (ret) { + dev_err(rt5677_dsp->dev, "Copy failed %d\n", ret); + goto done; + } + rt5677_dsp->avail_bytes += copy_bytes; + if (rt5677_dsp->avail_bytes >= period_bytes) { + snd_pcm_period_elapsed(rt5677_dsp->substream); + rt5677_dsp->avail_bytes = 0; + } + new_bytes -= copy_bytes; + } + + delay = bytes_to_frames(runtime, period_bytes) / (runtime->rate / 1000); + schedule_delayed_work(&rt5677_dsp->copy_work, msecs_to_jiffies(delay)); +done: + mutex_unlock(&rt5677_dsp->dma_lock); +} + +struct page *rt5677_spi_pcm_page( + struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned long offset) +{ + return snd_pcm_lib_get_vmalloc_page(substream, offset); +} + +static int rt5677_spi_pcm_probe(struct snd_soc_component *component) +{ + struct rt5677_dsp *rt5677_dsp; + + rt5677_dsp = devm_kzalloc(component->dev, sizeof(*rt5677_dsp), + GFP_KERNEL); + rt5677_dsp->dev = &g_spi->dev; + mutex_init(&rt5677_dsp->dma_lock); + INIT_DELAYED_WORK(&rt5677_dsp->copy_work, rt5677_spi_copy_work); + + snd_soc_component_set_drvdata(component, rt5677_dsp); + return 0; +} + +static const struct snd_soc_component_driver rt5677_spi_dai_component = { + .name = DRV_NAME, + .probe = rt5677_spi_pcm_probe, + .open = rt5677_spi_pcm_open, + .close = rt5677_spi_pcm_close, + .hw_params = rt5677_spi_hw_params, + .hw_free = rt5677_spi_hw_free, + .prepare = rt5677_spi_prepare, + .pointer = rt5677_spi_pcm_pointer, + .page = rt5677_spi_pcm_page, +}; + /* Select a suitable transfer command for the next transfer to ensure * the transfer address is always naturally aligned while minimizing * the total number of transfers required. @@ -218,9 +566,45 @@ int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw) } EXPORT_SYMBOL_GPL(rt5677_spi_write_firmware); +void rt5677_spi_hotword_detected(void) +{ + struct rt5677_dsp *rt5677_dsp; + + if (!g_spi) + return; + + rt5677_dsp = dev_get_drvdata(&g_spi->dev); + if (!rt5677_dsp) { + dev_err(&g_spi->dev, "Can't get rt5677_dsp\n"); + return; + } + + mutex_lock(&rt5677_dsp->dma_lock); + dev_info(rt5677_dsp->dev, "Hotword detected\n"); + rt5677_dsp->new_hotword = true; + mutex_unlock(&rt5677_dsp->dma_lock); + + schedule_delayed_work(&rt5677_dsp->copy_work, 0); +} +EXPORT_SYMBOL_GPL(rt5677_spi_hotword_detected); + static int rt5677_spi_probe(struct spi_device *spi) { + int ret; + g_spi = spi; + + ret = snd_soc_register_component(&spi->dev, &rt5677_spi_dai_component, + &rt5677_spi_dai, 1); + if (ret < 0) + dev_err(&spi->dev, "Failed to register component.\n"); + + return ret; +} + +static int rt5677_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_component(&spi->dev); return 0; } @@ -236,6 +620,7 @@ static struct spi_driver rt5677_spi_driver = { .acpi_match_table = ACPI_PTR(rt5677_spi_acpi_id), }, .probe = rt5677_spi_probe, + .remove = rt5677_spi_remove, }; module_spi_driver(rt5677_spi_driver); diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h index 6ba3369dc235..3af36ec928e9 100644 --- a/sound/soc/codecs/rt5677-spi.h +++ b/sound/soc/codecs/rt5677-spi.h @@ -12,5 +12,6 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len); int rt5677_spi_write(u32 addr, const void *txbuf, size_t len); int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw); +void rt5677_spi_hotword_detected(void); #endif /* __RT5677_SPI_H__ */ -- cgit From bed646dc3f7bcec91178c278deaf969cce0700a8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 15 Oct 2019 12:59:38 +0900 Subject: ASoC: soc-pcm: fixup dpcm_prune_paths() loop continue dpcm_prune_paths() is checking widget at 2 parts. (A) is for CPU, (B) is for Codec. If we focus to (A) part, continue at (a) is for (1) loop. But, if we focus to (B) part, continue at (b) is for (2) loop, not for (1). This is bug. This patch fixup this issue. static int dpcm_prune_paths(...) { ... (1) for_each_dpcm_be(fe, stream, dpcm) { ... ^ widget = dai_get_widget(...); | (A) if (widget && widget_in_list(...)) | (a) continue; v ^ (2) for_each_rtd_codec_dai(...) { | widget = dai_get_widget(...); (B) | if (widget && widget_in_list(...)) v (b) continue; } ... Fixes: 2e5894d73789 ("ASoC: pcm: Add support for DAI multicodec") Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87blui64mf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index f462947a5d27..600d9bf3b076 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1436,6 +1436,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dapm_widget *widget; struct snd_soc_dai *dai; int prune = 0; + int do_prune; /* Destroy any old FE <--> BE connections */ for_each_dpcm_be(fe, stream, dpcm) { @@ -1449,13 +1450,16 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, continue; /* is there a valid CODEC DAI widget for this BE */ + do_prune = 1; for_each_rtd_codec_dai(dpcm->be, i, dai) { widget = dai_get_widget(dai, stream); /* prune the BE if it's no longer in our active list */ if (widget && widget_in_list(list, widget)) - continue; + do_prune = 0; } + if (!do_prune) + continue; dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", stream ? "capture" : "playback", -- cgit From 5a4c9f054ceeaa90caef033f5a52eca2d7975364 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 15 Oct 2019 12:59:51 +0900 Subject: ASoC: soc-core: snd_soc_unbind_card() cleanup soc_remove_link_components() will be called from soc_cleanup_card_resources(). This patch removes duplicate call. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/877e5664lz.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bd2ac1912466..f028a6938ee8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2446,9 +2446,6 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) snd_soc_dapm_shutdown(card); snd_soc_flush_all_delayed_work(card); - /* remove all components used by DAI links on this card */ - soc_remove_link_components(card); - soc_cleanup_card_resources(card); if (!unregister) list_add(&card->list, &unbind_card_list); -- cgit From 82d9d54a6c0ee8b12211fa4e59fd940a2da4e063 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 22 Oct 2019 19:43:12 +0200 Subject: ALSA: hda: add Intel DSP configuration / probe code For distributions, we need one place where we can decide which driver will be activated for the auto-configation of the Intel's HDA hardware with DSP. Actually, we cover three drivers: * Legacy HDA * Intel SST * Intel Sound Open Firmware (SOF) All those drivers registers similar PCI IDs, so the first driver probed from the PCI stack can win. But... it is not guaranteed that the correct driver wins. This commit changes Intel's NHLT ACPI module to a common DSP probe module for the Intel's hardware. All above sound drivers calls this code. The user can force another behaviour using the module parameter 'dsp_driver' located in the 'snd-intel-dspcfg' module. This change allows to add specific dmi checks for the specific systems. The examples are taken from the pull request: https://github.com/thesofproject/linux/pull/927 Tested on Lenovo Carbon X1 7th gen. Signed-off-by: Jaroslav Kysela Tested-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191022174313.29087-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/hda/Kconfig | 10 +- sound/hda/Makefile | 5 +- sound/hda/intel-dsp-config.c | 249 ++++++++++++++++++++++++++++++++++++++++++ sound/hda/intel-nhlt.c | 3 - sound/pci/hda/Kconfig | 11 +- sound/pci/hda/hda_intel.c | 49 +++------ sound/soc/intel/Kconfig | 2 +- sound/soc/intel/skylake/skl.c | 19 +--- sound/soc/sof/intel/Kconfig | 2 +- sound/soc/sof/sof-pci-dev.c | 6 + 10 files changed, 288 insertions(+), 68 deletions(-) create mode 100644 sound/hda/intel-dsp-config.c (limited to 'sound') diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 3d33fc1757ba..b0c88fe040ee 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -34,6 +34,12 @@ config SND_HDA_PREALLOC_SIZE via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. config SND_INTEL_NHLT - tristate + bool # this config should be selected only for Intel ACPI platforms. - # A fallback is provided so that the code compiles in all cases. \ No newline at end of file + # A fallback is provided so that the code compiles in all cases. + +config SND_INTEL_DSP_CONFIG + tristate + select SND_INTEL_NHLT if ACPI + # this config should be selected only for Intel DSP platforms. + # A fallback is provided so that the code compiles in all cases. diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 8560f6ef1b19..601e617918b8 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -14,5 +14,6 @@ obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o #extended hda obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/ -snd-intel-nhlt-objs := intel-nhlt.o -obj-$(CONFIG_SND_INTEL_NHLT) += snd-intel-nhlt.o +snd-intel-dspcfg-objs := intel-dsp-config.o +snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o +obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c new file mode 100644 index 000000000000..d9f6d9e872b4 --- /dev/null +++ b/sound/hda/intel-dsp-config.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Jaroslav Kysela + +#include +#include +#include +#include +#include +#include +#include + +static int dsp_driver; + +module_param(dsp_driver, int, 0444); +MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)"); + +#define FLAG_SST BIT(0) +#define FLAG_SOF BIT(1) +#define FLAG_SOF_ONLY_IF_DMIC BIT(16) + +struct config_entry { + u32 flags; + u16 device; + const struct dmi_system_id *dmi_table; +}; + +/* + * configuration table + * - the order of similar PCI ID entries is important! + * - the first successful match will win + */ +static const struct config_entry config_table[] = { +/* Cometlake-LP */ +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP) + { + /* prefer SST */ + .flags = FLAG_SST, + .device = 0x02c8, + }, +#elif IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) + { + .flags = FLAG_SOF, + .device = 0x02c8, + }, +#endif +/* Cometlake-H */ +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H) + { + .flags = FLAG_SST, + .device = 0x06c8, + }, +#elif IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) + { + .flags = FLAG_SOF, + .device = 0x06c8, + }, +#endif +/* Merrifield */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) + { + .flags = FLAG_SOF, + .device = 0x119a, + }, +#endif +/* Broxton-T */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x1a98, + }, +#endif +/* Geminilake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) + { + .flags = FLAG_SOF, + .device = 0x3198, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) + { + .flags = FLAG_SST, + .device = 0x3198, + }, +#endif +/* Icelake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x34c8, + }, +#endif +/* Elkhart Lake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x4b55, + }, +#endif +/* Appololake (Broxton-P) */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) + { + .flags = FLAG_SOF, + .device = 0x5a98, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Up Squared", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), + } + }, + {} + } + }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) + { + .flags = FLAG_SST, + .device = 0x5a98, + }, +#endif +/* Cannonlake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x9dc8, + }, +#endif +/* Sunrise Point-LP */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x9d70, + }, +#endif +/* Kabylake-LP */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x9d71, + }, +#endif +/* Tigerlake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0xa0c8, + }, +#endif +/* Coffelake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0xa348, + }, +#endif +}; + +static const struct config_entry *snd_intel_dsp_find_config + (struct pci_dev *pci, const struct config_entry *table, u32 len) +{ + u16 device; + + device = pci->device; + for (; len > 0; len--, table++) { + if (table->device != device) + continue; + if (table->dmi_table && !dmi_check_system(table->dmi_table)) + continue; + return table; + } + return NULL; +} + +static int snd_intel_dsp_check_dmic(struct pci_dev *pci) +{ + struct nhlt_acpi_table *nhlt; + int ret = 0; + + nhlt = intel_nhlt_init(&pci->dev); + if (nhlt) { + if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) + ret = 1; + intel_nhlt_free(nhlt); + } + return ret; +} + +int snd_intel_dsp_driver_probe(struct pci_dev *pci) +{ + const struct config_entry *cfg; + + if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) + return dsp_driver; + + /* Intel vendor only */ + if (snd_BUG_ON(pci->vendor != 0x8086)) + return SND_INTEL_DSP_DRIVER_ANY; + + /* + * detect DSP by checking class/subclass/prog-id information + * class=04 subclass 03 prog-if 00: no DSP, use legacy driver + * class=04 subclass 01 prog-if 00: DSP is present + * (and may be required e.g. for DMIC or SSP support) + * class=04 subclass 03 prog-if 80: use DSP or legacy mode + */ + if (pci->class == 0x040300) + return SND_INTEL_DSP_DRIVER_LEGACY; + if (pci->class != 0x040100 && pci->class != 0x040380) { + dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDA legacy driver\n", pci->class); + return SND_INTEL_DSP_DRIVER_LEGACY; + } + + dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); + + /* find the configuration for the specific device */ + cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); + if (!cfg) + return SND_INTEL_DSP_DRIVER_ANY; + + if (cfg->flags & FLAG_SOF) { + if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC) { + if (snd_intel_dsp_check_dmic(pci)) { + dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); + return SND_INTEL_DSP_DRIVER_SOF; + } + } else { + return SND_INTEL_DSP_DRIVER_SOF; + } + } + + if (cfg->flags & FLAG_SST) + return SND_INTEL_DSP_DRIVER_SST; + + return SND_INTEL_DSP_DRIVER_LEGACY; +} +EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel DSP config driver"); diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index daede96f28ee..097ff6c10099 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -102,6 +102,3 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) return dmic_geo; } EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel NHLT driver"); diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index dae47a45b2b8..bd48335d09d7 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -12,7 +12,7 @@ config SND_HDA_INTEL tristate "HD Audio PCI" depends on SND_PCI select SND_HDA - select SND_INTEL_NHLT if ACPI + select SND_INTEL_DSP_CONFIG help Say Y here to include support for Intel "High Definition Audio" (Azalia) and its compatible devices. @@ -23,15 +23,6 @@ config SND_HDA_INTEL To compile this driver as a module, choose M here: the module will be called snd-hda-intel. -config SND_HDA_INTEL_DETECT_DMIC - bool "DMIC detection and probe abort" - depends on SND_HDA_INTEL - help - Say Y to detect digital microphones on SKL+ devices. DMICs - cannot be handled by the HDaudio legacy driver and are - currently only supported by the SOF driver. - If unsure say N. - config SND_HDA_TEGRA tristate "NVIDIA Tegra HD Audio" depends on ARCH_TEGRA diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e63b871343e5..ca462dd39a48 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include @@ -124,7 +124,7 @@ static char *patch[SNDRV_CARDS]; static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = CONFIG_SND_HDA_INPUT_BEEP_MODE}; #endif -static bool dmic_detect = IS_ENABLED(CONFIG_SND_HDA_INTEL_DETECT_DMIC); +static bool dsp_driver = 1; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); @@ -159,8 +159,9 @@ module_param_array(beep_mode, bool, NULL, 0444); MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " "(0=off, 1=on) (default=1)."); #endif -module_param(dmic_detect, bool, 0444); -MODULE_PARM_DESC(dmic_detect, "DMIC detect on SKL+ platforms"); +module_param(dsp_driver, bool, 0444); +MODULE_PARM_DESC(dsp_driver, "Allow DSP driver selection (bypass this driver) " + "(0=off, 1=on) (default=1)"); #ifdef CONFIG_PM static int param_set_xint(const char *val, const struct kernel_param *kp); @@ -2026,25 +2027,6 @@ static const struct hda_controller_ops pci_hda_ops = { .position_check = azx_position_check, }; -static int azx_check_dmic(struct pci_dev *pci, struct azx *chip) -{ - struct nhlt_acpi_table *nhlt; - int ret = 0; - - if (chip->driver_type == AZX_DRIVER_SKL && - pci->class != 0x040300) { - nhlt = intel_nhlt_init(&pci->dev); - if (nhlt) { - if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) { - ret = -ENODEV; - dev_info(&pci->dev, "Digital mics found on Skylake+ platform, aborting probe\n"); - } - intel_nhlt_free(nhlt); - } - } - return ret; -} - static int azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -2062,6 +2044,16 @@ static int azx_probe(struct pci_dev *pci, return -ENOENT; } + /* + * stop probe if another Intel's DSP driver should be activated + */ + if (dsp_driver) { + err = snd_intel_dsp_driver_probe(pci); + if (err != SND_INTEL_DSP_DRIVER_ANY && + err != SND_INTEL_DSP_DRIVER_LEGACY) + return -ENODEV; + } + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 0, &card); if (err < 0) { @@ -2075,17 +2067,6 @@ static int azx_probe(struct pci_dev *pci, card->private_data = chip; hda = container_of(chip, struct hda_intel, chip); - /* - * stop probe if digital microphones detected on Skylake+ platform - * with the DSP enabled. This is an opt-in behavior defined at build - * time or at run-time with a module parameter - */ - if (dmic_detect) { - err = azx_check_dmic(pci, chip); - if (err < 0) - goto out_free; - } - pci_set_drvdata(pci, card); err = register_vga_switcheroo(chip); diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 597516c0c192..3f9e65c10d5b 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -215,7 +215,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON select SND_SOC_INTEL_SST select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC select SND_SOC_ACPI_INTEL_MATCH - select SND_INTEL_NHLT if ACPI + select SND_INTEL_DSP_CONFIG help If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ GeminiLake or CannonLake platform with the DSP enabled in the BIOS diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 141dbbf975ac..58ba3e9469ba 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" @@ -987,22 +988,10 @@ static int skl_probe(struct pci_dev *pci, switch (skl_pci_binding) { case SND_SKL_PCI_BIND_AUTO: - /* - * detect DSP by checking class/subclass/prog-id information - * class=04 subclass 03 prog-if 00: no DSP, use legacy driver - * class=04 subclass 01 prog-if 00: DSP is present - * (and may be required e.g. for DMIC or SSP support) - * class=04 subclass 03 prog-if 80: use DSP or legacy mode - */ - if (pci->class == 0x040300) { - dev_info(&pci->dev, "The DSP is not enabled on this platform, aborting probe\n"); + err = snd_intel_dsp_driver_probe(pci); + if (err != SND_INTEL_DSP_DRIVER_ANY && + err != SND_INTEL_DSP_DRIVER_SST) return -ENODEV; - } - if (pci->class != 0x040100 && pci->class != 0x040380) { - dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class); - return -ENODEV; - } - dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); break; case SND_SKL_PCI_BIND_LEGACY: dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, aborting probe\n"); diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 18c41fdc47c8..806dfa0e5eae 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -286,7 +286,7 @@ config SND_SOC_SOF_HDA tristate select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_INTEL_NHLT if ACPI + select SND_INTEL_DSP_CONFIG help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index d66412a77873..3a9e0e2a150d 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -277,6 +278,11 @@ static int sof_pci_probe(struct pci_dev *pci, const struct snd_sof_dsp_ops *ops; int ret; + ret = snd_intel_dsp_driver_probe(pci); + if (ret != SND_INTEL_DSP_DRIVER_ANY && + ret != SND_INTEL_DSP_DRIVER_SOF) + return -ENODEV; + dev_dbg(&pci->dev, "PCI DSP detected"); /* get ops for platform */ -- cgit From cc8f81c7e625168a60843b2b39e3a327cf5170fe Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Oct 2019 19:43:13 +0200 Subject: ALSA: hda: fix intel DSP config Reshuffle list of devices by historical order and add correct information as needed. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20191022174313.29087-2-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/hda/intel-dsp-config.c | 220 ++++++++++++++++++++++++++++++++----------- 1 file changed, 164 insertions(+), 56 deletions(-) (limited to 'sound') diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index d9f6d9e872b4..0b2a7201a46a 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -30,45 +30,98 @@ struct config_entry { * - the first successful match will win */ static const struct config_entry config_table[] = { -/* Cometlake-LP */ -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP) +/* Merrifield */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) { - /* prefer SST */ - .flags = FLAG_SST, - .device = 0x02c8, + .flags = FLAG_SOF, + .device = 0x119a, }, -#elif IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) +#endif +/* Broxton-T */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) { .flags = FLAG_SOF, - .device = 0x02c8, + .device = 0x1a98, }, #endif -/* Cometlake-H */ -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H) +/* + * Apollolake (Broxton-P) + * the legacy HDaudio driver is used except on Up Squared (SOF) and + * Chromebooks (SST) + */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) { - .flags = FLAG_SST, - .device = 0x06c8, + .flags = FLAG_SOF, + .device = 0x5a98, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Up Squared", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), + } + }, + {} + } }, -#elif IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) { - .flags = FLAG_SOF, - .device = 0x06c8, + .flags = FLAG_SST, + .device = 0x5a98, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } }, #endif -/* Merrifield */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) +/* + * Skylake and Kabylake use legacy HDaudio driver except for Google + * Chromebooks (SST) + */ + +/* Sunrise Point-LP */ +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) { - .flags = FLAG_SOF, - .device = 0x119a, + .flags = FLAG_SST, + .device = 0x9d70, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } }, #endif -/* Broxton-T */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) +/* Kabylake-LP */ +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x1a98, + .flags = FLAG_SST, + .device = 0x9d71, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } }, #endif + +/* + * Geminilake uses legacy HDaudio driver except for Google + * Chromebooks + */ /* Geminilake */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) { @@ -85,84 +138,139 @@ static const struct config_entry config_table[] = { } }, #endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) + +/* + * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy + * HDaudio driver except for Google Chromebooks and when DMICs are + * present. Two cases are required since Coreboot does not expose NHLT + * tables. + * + * When the Chromebook quirk is not present, it's based on information + * that no such device exists. When the quirk is present, it could be + * either based on product information or a placeholder. + */ + +/* Cannonlake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) { - .flags = FLAG_SST, - .device = 0x3198, + .flags = FLAG_SOF, + .device = 0x9dc8, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } }, -#endif -/* Icelake */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x34c8, + .device = 0x9dc8, }, #endif -/* Elkhart Lake */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) + +/* Coffelake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) + { + .flags = FLAG_SOF, + .device = 0xa348, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x4b55, + .device = 0xa348, }, #endif -/* Appololake (Broxton-P) */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) + +/* Cometlake-LP */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) { .flags = FLAG_SOF, - .device = 0x5a98, + .device = 0x02c8, .dmi_table = (const struct dmi_system_id []) { { - .ident = "Up Squared", + .ident = "Google Chromebooks", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), - DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), + DMI_MATCH(DMI_SYS_VENDOR, "Google"), } }, {} } }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) { - .flags = FLAG_SST, - .device = 0x5a98, + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x02c8, }, #endif -/* Cannonlake */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) +/* Cometlake-H */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x9dc8, + .device = 0x06c8, }, #endif -/* Sunrise Point-LP */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) + +/* Icelake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x9d70, + .flags = FLAG_SOF, + .device = 0x34c8, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } }, -#endif -/* Kabylake-LP */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x9d71, + .device = 0x34c8, }, #endif + /* Tigerlake */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) + { + .flags = FLAG_SOF, + .device = 0xa0c8, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, + { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, .device = 0xa0c8, }, #endif -/* Coffelake */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) + +/* Elkhart Lake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0xa348, + .device = 0x4b55, }, #endif + }; static const struct config_entry *snd_intel_dsp_find_config -- cgit From 2b544dd7b43b19fb55ea4fbb3e30b60eb20b7828 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 15 Oct 2019 12:59:31 +0900 Subject: ASoC: soc-core: add for_each_rtd_components() and replace ALSA SoC has for_each_rtdcom() which is link list for rtd-component which is called as rtdcom. The relationship image is like below rtdcom rtdcom rtdcom component component component rtd->component_list -> list -> list -> list ... Here, the pointer get via normal link list is rtdcom, Thus, current for_each loop is like below, and need to get component via rtdcom->component for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; ... } but usually, user want to get pointer from for_each_xxx is component directly, like below. for_each_rtd_component(rtd, rtdcom, component) { ... } This patch expands list_for_each_entry manually, and enable to get component directly from for_each macro. Because of it, the macro becoming difficult to read, but macro itself becoming useful. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878spm64m4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-component.c | 43 +++++++++++---------------------------- sound/soc/soc-compress.c | 52 ++++++++++++----------------------------------- sound/soc/soc-core.c | 22 ++++++++------------ sound/soc/soc-pcm.c | 49 +++++++++++++------------------------------- 4 files changed, 48 insertions(+), 118 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index debaf1f6f403..98ef0666add2 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -420,13 +420,10 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME: use 1st pointer */ + /* FIXME: use 1st pointer */ + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->pointer) return component->driver->pointer(component, substream); - } return 0; } @@ -438,14 +435,11 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME: use 1st ioctl */ + /* FIXME: use 1st ioctl */ + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->ioctl) return component->driver->ioctl(component, substream, cmd, arg); - } return snd_pcm_lib_ioctl(substream, cmd, arg); } @@ -458,14 +452,11 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME. it returns 1st copy now */ + /* FIXME. it returns 1st copy now */ + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->copy_user) return component->driver->copy_user( component, substream, channel, pos, buf, bytes); - } return -EINVAL; } @@ -478,10 +469,8 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, struct snd_soc_component *component; struct page *page; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME. it returns 1st page now */ + /* FIXME. it returns 1st page now */ + for_each_rtd_components(rtd, rtdcom, component) { if (component->driver->page) { page = component->driver->page(component, substream, offset); @@ -500,14 +489,11 @@ int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME. it returns 1st mmap now */ + /* FIXME. it returns 1st mmap now */ + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->mmap) return component->driver->mmap(component, substream, vma); - } return -EINVAL; } @@ -519,9 +505,7 @@ int snd_soc_pcm_component_new(struct snd_pcm *pcm) struct snd_soc_component *component; int ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component->driver->pcm_construct) { ret = component->driver->pcm_construct(component, rtd); if (ret < 0) @@ -538,10 +522,7 @@ void snd_soc_pcm_component_free(struct snd_pcm *pcm) struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->pcm_destruct) component->driver->pcm_destruct(component, pcm); - } } diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 9e54d8ae6d2c..61f230324164 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -28,9 +28,7 @@ static int soc_compr_components_open(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->open) continue; @@ -57,9 +55,7 @@ static int soc_compr_components_free(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component == last) break; @@ -353,9 +349,7 @@ static int soc_compr_components_trigger(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->trigger) continue; @@ -458,9 +452,7 @@ static int soc_compr_components_set_params(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->set_params) continue; @@ -601,9 +593,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, goto err; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->get_params) continue; @@ -627,9 +617,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->get_caps) continue; @@ -652,9 +640,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->get_codec_caps) continue; @@ -684,9 +670,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) goto err; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->ack) continue; @@ -715,9 +699,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer) cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->pointer) continue; @@ -740,9 +722,7 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->copy) continue; @@ -770,9 +750,7 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, return ret; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->set_metadata) continue; @@ -801,9 +779,7 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, return ret; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->get_metadata) continue; @@ -932,9 +908,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->copy) continue; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f028a6938ee8..f1b41b0391ed 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -293,10 +293,11 @@ static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component) { struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *comp; - for_each_rtdcom(rtd, rtdcom) { + for_each_rtd_components(rtd, rtdcom, comp) { /* already connected */ - if (rtdcom->component == component) + if (comp == component) return 0; } @@ -327,6 +328,7 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, const char *driver_name) { struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; if (!driver_name) return NULL; @@ -339,8 +341,8 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, * But, if many components which have same driver name are connected * to 1 rtd, this function will return 1st found component. */ - for_each_rtdcom(rtd, rtdcom) { - const char *component_name = rtdcom->component->driver->name; + for_each_rtd_components(rtd, rtdcom, component) { + const char *component_name = component->driver->name; if (!component_name) continue; @@ -1248,9 +1250,7 @@ static void soc_remove_link_components(struct snd_soc_card *card) for_each_comp_order(order) { for_each_card_rtds(card, rtd) { - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component->driver->remove_order != order) continue; @@ -1269,9 +1269,7 @@ static int soc_probe_link_components(struct snd_soc_card *card) for_each_comp_order(order) { for_each_card_rtds(card, rtd) { - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component->driver->probe_order != order) continue; @@ -1520,9 +1518,7 @@ static int soc_link_init(struct snd_soc_card *card, * topology based drivers can use the DAI link id field to set PCM * device number and then use rtd + a base offset of the BEs. */ - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->use_dai_pcm_id) continue; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 600d9bf3b076..8655df6a6089 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -118,11 +118,8 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) return true; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) ignore &= !component->driver->use_pmdown_time; - } return ignore; } @@ -435,8 +432,7 @@ static int soc_pcm_components_open(struct snd_pcm_substream *substream, struct snd_soc_component *component; int ret = 0; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; + for_each_rtd_components(rtd, rtdcom, component) { *last = component; ret = snd_soc_component_module_get_when_open(component); @@ -467,9 +463,7 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, struct snd_soc_component *component; int ret = 0; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component == last) break; @@ -500,9 +494,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) for_each_rtd_codec_dai(rtd, i, codec_dai) pinctrl_pm_select_default_state(codec_dai->dev); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { pm_runtime_get_sync(component->dev); } @@ -625,9 +617,7 @@ component_err: out: mutex_unlock(&rtd->card->pcm_mutex); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); } @@ -740,9 +730,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) mutex_unlock(&rtd->card->pcm_mutex); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); } @@ -782,9 +770,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { ret = snd_soc_component_prepare(component, substream); if (ret < 0) { dev_err(component->dev, @@ -849,9 +835,7 @@ static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream, struct snd_soc_component *component; int ret = 0; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component == last) break; @@ -945,9 +929,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, snd_soc_dapm_update_dai(substream, params, cpu_dai); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { ret = snd_soc_component_hw_params(component, substream, params); if (ret < 0) { dev_err(component->dev, @@ -1062,9 +1044,7 @@ static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd) return ret; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { ret = snd_soc_component_trigger(component, substream, cmd); if (ret < 0) return ret; @@ -1102,9 +1082,7 @@ static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd) if (ret < 0) return ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { ret = snd_soc_component_trigger(component, substream, cmd); if (ret < 0) return ret; @@ -2879,6 +2857,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; struct snd_pcm *pcm; char new_name[64]; int ret = 0, playback = 0, capture = 0; @@ -2990,8 +2969,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.ioctl = snd_soc_pcm_component_ioctl; } - for_each_rtdcom(rtd, rtdcom) { - const struct snd_soc_component_driver *drv = rtdcom->component->driver; + for_each_rtd_components(rtd, rtdcom, component) { + const struct snd_soc_component_driver *drv = component->driver; if (drv->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; -- cgit From d4d9360bf702890b5d3b1b62d8619a2690dd3278 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Tue, 22 Oct 2019 20:55:18 +0200 Subject: ASoC: rsnd: dma: set bus width to data width for monaural data According to R-Car3 HW manual 40.3.3 (Data Format on Audio Local Bus), in case of monaural data writing or reading through Audio-DMAC, it's always in Left Justified format, so both src and dst DMA Bus width should be equal to physical data width. Therefore set src and dst's DMA bus width to: - [monaural case] data width - [non-monaural case] 32bits (as prior applying the patch) Cc: Andrew Gabbasov Cc: Timo Wischer Signed-off-by: Jiada Wang Signed-off-by: Eugeniu Rosca Link: https://lore.kernel.org/r/20191022185518.12838-1-erosca@de.adit-jv.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 0324a5c39619..bcb6d5960661 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -165,14 +165,40 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; struct dma_slave_config cfg = {}; + enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; int is_play = rsnd_io_is_play(io); int ret; + /* + * in case of monaural data writing or reading through Audio-DMAC + * data is always in Left Justified format, so both src and dst + * DMA Bus width need to be set equal to physical data width. + */ + if (rsnd_runtime_channel_original(io) == 1) { + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int bits = snd_pcm_format_physical_width(runtime->format); + + switch (bits) { + case 8: + buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; + break; + case 16: + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case 32: + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + default: + dev_err(dev, "invalid format width %d\n", bits); + return -EINVAL; + } + } + cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; cfg.src_addr = dma->src_addr; cfg.dst_addr = dma->dst_addr; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.src_addr_width = buswidth; + cfg.dst_addr_width = buswidth; dev_dbg(dev, "%s %pad -> %pad\n", rsnd_mod_name(mod), -- cgit From ef2c695151df54817f92128f96a920ff888c6920 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 23 Oct 2019 11:10:43 +0900 Subject: ASoC: rsnd: add missing of_node_put() This patch adds missing of_node_put() for rsnd_parse_tdm_split_mode() rsnd_parse_connect_graph() Reported-by: Pavel Machek Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8736fkyzx8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 4bed26842095..72924c8b0696 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1075,7 +1075,10 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, j++; } + of_node_put(node); } + + of_node_put(ssiu_np); } static void rsnd_parse_connect_simple(struct rsnd_priv *priv, @@ -1093,11 +1096,13 @@ static void rsnd_parse_connect_graph(struct rsnd_priv *priv, struct device_node *endpoint) { struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint); + struct device_node *remote_node; if (!rsnd_io_to_mod_ssi(io)) return; + remote_node = of_graph_get_remote_port_parent(endpoint); + /* HDMI0 */ if (strstr(remote_node->full_name, "hdmi@fead0000")) { rsnd_flags_set(io, RSND_STREAM_HDMI0); @@ -1111,6 +1116,8 @@ static void rsnd_parse_connect_graph(struct rsnd_priv *priv, } rsnd_parse_tdm_split_mode(priv, io, endpoint); + + of_node_put(remote_node); } void rsnd_parse_connect_common(struct rsnd_dai *rdai, -- cgit From ef5dee551e3e6568fb203ea57fa24f55cb64d451 Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Wed, 23 Oct 2019 14:31:03 +0800 Subject: ASoC: mediatek: Check SND_SOC_CROS_EC_CODEC dependency If SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A=y, below errors can be seen: sound/soc/codecs/cros_ec_codec.o: In function `send_ec_host_command': cros_ec_codec.c:(.text+0x534): undefined reference to `cros_ec_cmd_xfer_status' cros_ec_codec.c:(.text+0x101c): undefined reference to `cros_ec_get_host_event' This is because it will select SND_SOC_CROS_EC_CODEC after commit 2cc3cd5fdc8b ("ASoC: mediatek: mt8183: support WoV"), but SND_SOC_CROS_EC_CODEC depends on CROS_EC. Fixes: 2cc3cd5fdc8b ("ASoC: mediatek: mt8183: support WoV") Signed-off-by: Mao Wenan Link: https://lore.kernel.org/r/20191023063103.44941-1-maowenan@huawei.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 8b29f3979899..a656d2014127 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -125,7 +125,7 @@ config SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A select SND_SOC_MAX98357A select SND_SOC_BT_SCO select SND_SOC_TS3A227E - select SND_SOC_CROS_EC_CODEC + select SND_SOC_CROS_EC_CODEC if CROS_EC help This adds ASoC driver for Mediatek MT8183 boards with the MT6358 TS3A227E MAX98357A audio codec. -- cgit From 76dc6a2b312d15c91ff4b4d171e98cdc73ba3745 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Oct 2019 14:28:43 -0500 Subject: ASoC: SOF: Intel: hda-loader: improve error handling If a ROM timeout is detected, we still stop the DMA but will return the initial error should the DMA stop also fail. Likewise the cleanup is handled regardless of the status, but we return the initial error. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191022192844.21022-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 65c2af3fcaab..7956dbf5be88 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -253,10 +253,16 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_BASEFW_TIMEOUT_US); + /* + * even in case of errors we still need to stop the DMAs, + * but we return the initial error should the DMA stop also fail + */ + ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) { dev_err(sdev->dev, "error: DMA trigger stop failed\n"); - return ret; + if (!status) + status = ret; } return status; @@ -341,13 +347,15 @@ cleanup: /* * Perform codeloader stream cleanup. * This should be done even if firmware loading fails. + * If the cleanup also fails, we return the initial error */ ret1 = cl_cleanup(sdev, &sdev->dmab, stream); if (ret1 < 0) { dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); /* set return value to indicate cleanup failure */ - ret = ret1; + if (!ret) + ret = ret1; } /* -- cgit From 6a414489e0f3309a221f26b3d11c19d1a96a3635 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Oct 2019 14:28:44 -0500 Subject: ASoC: SOF: Intel: hda: add dev_err() traces for snd_sof_dsp_read_poll_timeout() Such traces should be extremely rare but extremely useful for debug. Report errors for all calls to sdn_sof_dsp_read_poll_timeout(), but only on negative values for consistency. Add traces that enable each timeout to be uniquely identified. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191022192844.21022-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 30 +++++++++++++++++++++++++++--- sound/soc/sof/intel/hda-loader.c | 13 ++++++++++++- sound/soc/sof/intel/hda-stream.c | 24 ++++++++++++++++++++---- 3 files changed, 59 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index fb55a3c5afd0..3ea401646e0c 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -42,6 +42,12 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) ((adspcs & reset) == reset), HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + return ret; + } /* has core entered reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -77,6 +83,13 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + return ret; + } + /* has core left reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS); @@ -151,8 +164,12 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) (adspcs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); - if (ret < 0) - dev_err(sdev->dev, "error: timeout on core powerup\n"); + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + return ret; + } /* did core power up ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -171,17 +188,24 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) { u32 adspcs; + int ret; /* update bits */ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0); - return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, adspcs, !(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)), HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); + if (ret < 0) + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + + return ret; } bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 7956dbf5be88..b1783360fe10 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -126,7 +126,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) { - dev_err(sdev->dev, "error: waiting for HIPCIE done\n"); + dev_err(sdev->dev, "error: %s: timeout for HIPCIE done\n", + __func__); goto err; } @@ -152,6 +153,10 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, if (!ret) return 0; + dev_err(sdev->dev, + "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", + __func__); + err: hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); hda_dsp_core_reset_power_down(sdev, chip->cores_mask); @@ -258,6 +263,12 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) * but we return the initial error should the DMA stop also fail */ + if (status < 0) { + dev_err(sdev->dev, + "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", + __func__); + } + ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) { dev_err(sdev->dev, "error: DMA trigger stop failed\n"); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 2c7447188402..450f9c55785f 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -275,8 +275,12 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n", + __func__, cmd); return ret; + } hstream->running = true; break; @@ -294,8 +298,12 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n", + __func__, cmd); return ret; + } snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, @@ -356,8 +364,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on STREAM_SD_OFFSET read1\n", + __func__); return ret; + } snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, @@ -418,8 +430,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on STREAM_SD_OFFSET read2\n", + __func__); return ret; + } snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, -- cgit From 4f0637eae56f02ef648de5ed839d572259d396e9 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 22 Oct 2019 14:47:04 -0500 Subject: ASoC: Intel: common: add ACPI matching tables for JSL There are no upstream machine drivers just yet so just add dummy table for compilation in nocodec-mode. Signed-off-by: Pan Xiuli Link: https://lore.kernel.org/r/20191022194705.23347-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/Makefile | 1 + sound/soc/intel/common/soc-acpi-intel-jsl-match.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 sound/soc/intel/common/soc-acpi-intel-jsl-match.c (limited to 'sound') diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 18d9630ae9a2..eafe95ead49b 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -9,6 +9,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ + soc-acpi-intel-jsl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c new file mode 100644 index 000000000000..1c68a04f0c6e --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-jsl-match.c - tables and support for JSL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); -- cgit From 6fd9903527bf103167004022a0199b8fac1b8b29 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 22 Oct 2019 14:47:05 -0500 Subject: ASoC: SOF: Intel: initial support to JasperLake. Add Kconfig, PCI ID and chip info for JSL platform. The DSP only has 2 cores for this platform. Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191022194705.23347-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 16 ++++++++++++++++ sound/soc/sof/intel/cnl.c | 17 +++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/sof-pci-dev.c | 22 ++++++++++++++++++++++ 4 files changed, 56 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index d62f51d33be1..342f22a7c64f 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -29,6 +29,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT + select SND_SOC_SOF_JASPERLAKE if SND_SOC_SOF_JASPERLAKE_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -244,6 +245,21 @@ config SND_SOC_SOF_ELKHARTLAKE This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_JASPERLAKE_SUPPORT + bool "SOF support for JasperLake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the JasperLake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_JASPERLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 4ddd73762d81..5b97bdfba823 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -327,3 +327,20 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(ehl_chip_info); + +const struct sof_intel_dsp_desc jsl_chip_info = { + /* Jasperlake */ + .cores_num = 2, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(jsl_chip_info); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 23e430d3e056..ea02bf40cb25 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -604,5 +604,6 @@ extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc icl_chip_info; extern const struct sof_intel_dsp_desc tgl_chip_info; extern const struct sof_intel_dsp_desc ehl_chip_info; +extern const struct sof_intel_dsp_desc jsl_chip_info; #endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 030f2cb06921..4adbb27c76c5 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -245,6 +245,24 @@ static const struct sof_dev_desc ehl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) +static const struct sof_dev_desc jsl_desc = { + .machines = snd_soc_acpi_intel_jsl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &jsl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-jsl.ri", + .nocodec_tplg_filename = "sof-jsl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -423,6 +441,10 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x34C8), .driver_data = (unsigned long)&icl_desc}, #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) + { PCI_DEVICE(0x8086, 0x38c8), + .driver_data = (unsigned long)&jsl_desc}, +#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) { PCI_DEVICE(0x8086, 0x02c8), .driver_data = (unsigned long)&cml_desc}, -- cgit From 175fc928198236037174e5c5c066fe3c4691903e Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 23 Oct 2019 16:46:59 +0100 Subject: ASoC: kirkwood: fix IRQ error handling Propagate the error code from request_irq(), rather than returning -EBUSY. Signed-off-by: Russell King Link: https://lore.kernel.org/r/E1iNIqh-0000tW-EZ@rmk-PC.armlinux.org.uk Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index 42bbb7ea20b5..e28fb3449f1d 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -133,7 +133,7 @@ static int kirkwood_dma_open(struct snd_soc_component *component, err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED, "kirkwood-i2s", priv); if (err) - return -EBUSY; + return err; /* * Enable Error interrupts. We're only ack'ing them but -- cgit From e42599d6bbf5aa48ae8a2942946b0f6194017fdf Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Wed, 23 Oct 2019 14:29:47 -0700 Subject: ASoC: rt5650: Add Kahlee platform specfic changes Add platform specific data for Kahlee project. Signed-off-by: Akshu Agrawal Signed-off-by: Shirish S Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191023212948.92246-1-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 1c06b3b9218c..a15e4ecd2a24 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3636,6 +3636,12 @@ static const struct rt5645_platform_data lattepanda_board_platform_data = { .inv_jd1_1 = true }; +static const struct rt5645_platform_data kahlee_platform_data = { + .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5, + .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, + .jd_mode = 3, +}; + static const struct dmi_system_id dmi_platform_data[] = { { .ident = "Chrome Buddy", @@ -3742,6 +3748,13 @@ static const struct dmi_system_id dmi_platform_data[] = { }, .driver_data = (void *)&lattepanda_board_platform_data, }, + { + .ident = "Chrome Kahlee", + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Kahlee"), + }, + .driver_data = (void *)&kahlee_platform_data, + }, { } }; -- cgit From f8a60435703bdde8f8a0ceb1aa8dad59df821583 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Oct 2019 13:46:10 +0100 Subject: ASoC: rt5677: Add missing null check for failed allocation of rt5677_dsp The allocation of rt5677_dsp can potentially fail and return null, so add a null check and return -ENOMEM on a memory allocation failure. Addresses-Coverity: ("Dereference null return") Fixes: a0e0d135427c ("ASoC: rt5677: Add a PCM device for streaming hotword via SPI") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20191024124610.18182-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 36c02d200cfc..3a17643fcd9f 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -376,6 +376,8 @@ static int rt5677_spi_pcm_probe(struct snd_soc_component *component) rt5677_dsp = devm_kzalloc(component->dev, sizeof(*rt5677_dsp), GFP_KERNEL); + if (!rt5677_dsp) + return -ENOMEM; rt5677_dsp->dev = &g_spi->dev; mutex_init(&rt5677_dsp->dma_lock); INIT_DELAYED_WORK(&rt5677_dsp->copy_work, rt5677_spi_copy_work); -- cgit From 6442793abf75a8081aa1f5da439529c08af2a5be Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Thu, 24 Oct 2019 11:40:26 -0700 Subject: ASoC: rt5677-spi: fix sparse warnings Fix bugs reported by kbuild test robot Fixes: a0e0d135427c ("ASoC: rt5677: Add a PCM device for streaming hotword via SPI") Reported-by: kbuild test robot Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191024184026.183913-1-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 3a17643fcd9f..dac1097bc740 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -145,7 +145,7 @@ static int rt5677_spi_hw_free( snd_soc_component_get_drvdata(component); mutex_lock(&rt5677_dsp->dma_lock); - rt5677_dsp->substream = 0; + rt5677_dsp->substream = NULL; mutex_unlock(&rt5677_dsp->dma_lock); return snd_pcm_lib_free_vmalloc_buffer(substream); @@ -362,7 +362,7 @@ done: mutex_unlock(&rt5677_dsp->dma_lock); } -struct page *rt5677_spi_pcm_page( +static struct page *rt5677_spi_pcm_page( struct snd_soc_component *component, struct snd_pcm_substream *substream, unsigned long offset) -- cgit From f3ee99087c8ca0ecfdd549ef5a94f557c42d5428 Mon Sep 17 00:00:00 2001 From: Edward Cragg Date: Fri, 18 Oct 2019 16:48:28 +0100 Subject: ASoC: tegra: Allow 24bit and 32bit samples The tegra3 audio can support 24 and 32 bit sample sizes so add the option to the tegra30_i2s_hw_params to configure the S24_LE or S32_LE formats when requested. Signed-off-by: Edward Cragg [ben.dooks@codethink.co.uk: fixup merge of 24 and 32bit] [ben.dooks@codethink.co.uk: add pm calls around ytdm config] [ben.dooks@codethink.co.uk: drop debug printing to dev_dbg] Signed-off-by: Ben Dooks Reviewed-by: Jon Hunter Link: https://lore.kernel.org/r/20191018154833.7560-3-ben.dooks@codethink.co.uk Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_i2s.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index e6d548fa980b..48a09c9d60be 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -127,7 +127,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, struct device *dev = dai->dev; struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int mask, val, reg; - int ret, sample_size, srate, i2sclock, bitcnt; + int ret, sample_size, srate, i2sclock, bitcnt, audio_bits; struct tegra30_ahub_cif_conf cif_conf; if (params_channels(params) != 2) @@ -137,8 +137,19 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: val = TEGRA30_I2S_CTRL_BIT_SIZE_16; + audio_bits = TEGRA30_AUDIOCIF_BITS_16; sample_size = 16; break; + case SNDRV_PCM_FORMAT_S24_LE: + val = TEGRA30_I2S_CTRL_BIT_SIZE_24; + audio_bits = TEGRA30_AUDIOCIF_BITS_24; + sample_size = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + val = TEGRA30_I2S_CTRL_BIT_SIZE_32; + audio_bits = TEGRA30_AUDIOCIF_BITS_32; + sample_size = 32; + break; default: return -EINVAL; } @@ -170,8 +181,8 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, cif_conf.threshold = 0; cif_conf.audio_channels = 2; cif_conf.client_channels = 2; - cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; - cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; + cif_conf.audio_bits = audio_bits; + cif_conf.client_bits = audio_bits; cif_conf.expand = 0; cif_conf.stereo_conv = 0; cif_conf.replicate = 0; @@ -277,14 +288,18 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S16_LE, }, .ops = &tegra30_i2s_dai_ops, .symmetric_rates = 1, -- cgit From c19255659b6ed952948ce54a260efb2ad950cc54 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Oct 2019 17:16:03 +0200 Subject: ASoC: Spelling s/configr/configur/ Fix misspellings of "configuration" and "configure". Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20191024151603.29043-1-geert+renesas@glider.be Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 1c1ba7bea4d8..2ad00ed21bec 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1507,7 +1507,7 @@ static int cx2072x_probe(struct snd_soc_component *codec) regmap_multi_reg_write(cx2072x->regmap, cx2072x_reg_init, ARRAY_SIZE(cx2072x_reg_init)); - /* configre PortC as input device */ + /* configure PortC as input device */ regmap_update_bits(cx2072x->regmap, CX2072X_PORTC_PIN_CTRL, 0x20, 0x20); -- cgit From 16c33235321d5ce3463ebefc205d7cf11929d59f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Oct 2019 17:31:30 +0200 Subject: ASoC: pxa: poodle: Spelling s/enpoints/endpoints/, s/connetion/connection/ Fix misspelling of "endpoints" and "connection". Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20191024153130.31082-1-geert+renesas@glider.be Signed-off-by: Mark Brown --- sound/soc/pxa/poodle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 48d5c2252b10..59ef04d0467a 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -56,7 +56,7 @@ static void poodle_ext_control(struct snd_soc_dapm_context *dapm) snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); } - /* set the enpoints to their new connetion states */ + /* set the endpoints to their new connection states */ if (poodle_spk_func == POODLE_SPK_ON) snd_soc_dapm_enable_pin(dapm, "Ext Spk"); else -- cgit From 07932563686a6c51b26266c8572901c46fd1cd55 Mon Sep 17 00:00:00 2001 From: Edward Cragg Date: Fri, 18 Oct 2019 16:48:27 +0100 Subject: ASoC: tegra: add a TDM configuration callback Add a callback to configure TDM settings for the Tegra30 I2S ASoC 'platform' driver. Signed-off-by: Edward Cragg [ben.dooks@codethink.co.uk: merge fix for power management] [ben.dooks@codethink.co.uk: add review change for fsync of 1 clock] Signed-off-by: Ben Dooks Reviewed-by: Jon Hunter Link: https://lore.kernel.org/r/20191018154833.7560-2-ben.dooks@codethink.co.uk Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_i2s.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'sound') diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 48a09c9d60be..8f8924060d9d 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -265,6 +265,34 @@ static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } +static int tegra30_i2s_set_tdm(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int mask, val; + + dev_dbg(dai->dev, "%s: txmask=0x%08x rxmask=0x%08x slots=%d width=%d\n", + __func__, tx_mask, rx_mask, slots, slot_width); + + mask = TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK | + TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK | + TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK; + + val = (tx_mask << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT) | + (rx_mask << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT) | + ((slots - 1) << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT); + + pm_runtime_get_sync(dai->dev); + regmap_update_bits(i2s->regmap, TEGRA30_I2S_SLOT_CTRL, mask, val); + /* set the fsync width to minimum of 1 clock width */ + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CH_CTRL, + TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK, 0x0); + pm_runtime_put(dai->dev); + + return 0; +} + static int tegra30_i2s_probe(struct snd_soc_dai *dai) { struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -279,6 +307,7 @@ static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = { .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, + .set_tdm_slot = tegra30_i2s_set_tdm, }; static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { -- cgit From 8c05f6af7b7d713e327cd6df5a8889c32fc1c10f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 18 Oct 2019 16:48:30 +0100 Subject: ASoC: tegra: disable rx_fifo after disable stream We see odd FIFO overruns with this, we assume the best thing to do is to disable the RX I2S frontend first, and then disable the FIFO that is using it. This also fixes an issue where using multi-word frames (TDM) have partial samples stuck in the FIFO which then get read out when the next capture is started. Signed-off-by: Ben Dooks Acked-by: Jon Hunter Link: https://lore.kernel.org/r/20191018154833.7560-5-ben.dooks@codethink.co.uk Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 8f8924060d9d..dbed3c5408e7 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -231,9 +231,9 @@ static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) { - tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif); regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, TEGRA30_I2S_CTRL_XFER_EN_RX, 0); + tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif); } static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, -- cgit From 27e322fabd508ba73ced625fc41f0b7ceee26416 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Oct 2019 16:03:17 -0500 Subject: ASoC: SOF: define INFO_ flags in dsp_ops Currently the INFO_ flags such as PAUSE/NO_PERIOD_WAKEUP are defined in the SOF PCM core, which doesn't scale. To account for platform variations, these flags need to be set in DSP ops. This patch only moves the definitions and does not change any functionality. Reviewed-by: Jaska Uimonen Reviewed-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191024210318.30068-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8.c | 7 +++++++ sound/soc/sof/intel/apl.c | 7 +++++++ sound/soc/sof/intel/bdw.c | 9 ++++++++- sound/soc/sof/intel/byt.c | 21 +++++++++++++++++++++ sound/soc/sof/intel/cnl.c | 7 +++++++ sound/soc/sof/pcm.c | 8 +++----- sound/soc/sof/sof-priv.h | 3 +++ 7 files changed, 56 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 2a22b18e5ec0..cfefcfd92798 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -388,6 +388,13 @@ struct snd_sof_dsp_ops sof_imx8_ops = { /* DAI drivers */ .drv = imx8_dai, .num_drv = 1, /* we have only 1 ESAI interface on i.MX8 */ + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP }; EXPORT_SYMBOL(sof_imx8_ops); diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 8dc7a5558da4..15d26e8d90a9 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -97,6 +97,13 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .runtime_resume = hda_dsp_runtime_resume, .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_apl_ops); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index bf961a8798a7..7b4cd1f456bf 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -591,7 +591,14 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { /* DAI drivers */ .drv = bdw_dai, - .num_drv = ARRAY_SIZE(bdw_dai) + .num_drv = ARRAY_SIZE(bdw_dai), + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_bdw_ops); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 07e5efe4945c..62edb959f1fc 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -532,6 +532,13 @@ const struct snd_sof_dsp_ops sof_tng_ops = { /* DAI drivers */ .drv = byt_dai, .num_drv = 3, /* we have only 3 SSPs on byt*/ + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_tng_ops); @@ -693,6 +700,13 @@ const struct snd_sof_dsp_ops sof_byt_ops = { /* DAI drivers */ .drv = byt_dai, .num_drv = 3, /* we have only 3 SSPs on byt*/ + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_byt_ops); @@ -753,6 +767,13 @@ const struct snd_sof_dsp_ops sof_cht_ops = { .drv = byt_dai, /* all 6 SSPs may be available for cherrytrail */ .num_drv = ARRAY_SIZE(byt_dai), + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_cht_ops); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 5b97bdfba823..e9cdcc040fb5 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -255,6 +255,13 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .runtime_resume = hda_dsp_runtime_resume, .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_cnl_ops); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index d72798d2b302..9ba505cf5966 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -440,6 +440,7 @@ static int sof_pcm_open(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + const struct snd_sof_dsp_ops *ops = sof_ops(sdev); struct snd_sof_pcm *spcm; struct snd_soc_tplg_stream_caps *caps; int ret; @@ -469,11 +470,8 @@ static int sof_pcm_open(struct snd_soc_component *component, le32_to_cpu(caps->period_size_min)); /* set runtime config */ - runtime->hw.info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; + runtime->hw.info = ops->hw_info; /* platform-specific */ + runtime->hw.formats = le64_to_cpu(caps->formats); runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min); runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 5a11a8517fa5..2d40de5ee285 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -211,6 +211,9 @@ struct snd_sof_dsp_ops { /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; + + /* ALSA HW info flags, will be stored in snd_pcm_runtime.hw.info */ + u32 hw_info; }; /* DSP architecture specific callbacks for oops and stack dumps */ -- cgit From 4c02a7bd43e22f4de53ad55b94d24e4388f712f0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Oct 2019 16:03:18 -0500 Subject: ASoC: SOF: Intel: only support INFO_BATCH for legacy platforms The current position update is not precise enough for PulseAudio to work reliably with the timer-based scheduling on Baytrail, Cherrytrail, Broadwell. Disable the NO_PERIOD_WAKEUP capability and use BATCH to signal that the position is only reliable and updated during period_elapsed events. This will be reverted when the firmware provides a more accurate position for those platforms. Reviewed-by: Jaska Uimonen Reviewed-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191024210318.30068-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/byt.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 7b4cd1f456bf..141dad554764 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -598,7 +598,7 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_bdw_ops); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 62edb959f1fc..2abf80b3eb52 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -538,7 +538,7 @@ const struct snd_sof_dsp_ops sof_tng_ops = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_tng_ops); @@ -706,7 +706,7 @@ const struct snd_sof_dsp_ops sof_byt_ops = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_byt_ops); @@ -773,7 +773,7 @@ const struct snd_sof_dsp_ops sof_cht_ops = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_cht_ops); -- cgit From 0a671dc500553cf6f4cc3efbcb0923b5e9adccb5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 25 Oct 2019 17:39:05 +0800 Subject: ALSA: intel_hdmi: Remove dev_err() on platform_get_irq() failure platform_get_irq() will call dev_err() itself on failure, so there is no need for the driver to also do this. This is detected by coccinelle. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20191025093905.14888-1-yuehaibing@huawei.com Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 5fd4e32247a6..cd389d21219a 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1708,10 +1708,8 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) /* get resources */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Could not get irq resource: %d\n", irq); + if (irq < 0) return irq; - } res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_mmio) { -- cgit From ca58f55108fee41d87c9123f85ad4863e5de7f45 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Oct 2019 11:58:03 +0100 Subject: ALSA: hda - Fix pending unsol events at shutdown This is an alternative fix attemp for the issue reported in the commit caa8422d01e9 ("ALSA: hda: Flush interrupts on disabling") that was reverted later due to regressions. Instead of tweaking the hardware disablement order and the enforced irq flushing, do calling cancel_work_sync() of the unsol work early enough, and explicitly ignore the unsol events during the shutdown by checking the bus->shutdown flag. Fixes: caa8422d01e9 ("ALSA: hda: Flush interrupts on disabling") Cc: Chris Wilson Link: https://lore.kernel.org/r/s5h1ruxt9cz.wl-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_bind.c | 4 ++++ sound/pci/hda/hda_intel.c | 3 +++ 2 files changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index 8272b50b8349..6a8564566375 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -43,6 +43,10 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) { struct hda_codec *codec = container_of(dev, struct hda_codec, core); + /* ignore unsol events during shutdown */ + if (codec->bus->shutdown) + return; + if (codec->patch_ops.unsol_event) codec->patch_ops.unsol_event(codec, ev); } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 2a9d87ff2e1c..121b20121dae 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1389,8 +1389,11 @@ static int azx_free(struct azx *chip) static int azx_dev_disconnect(struct snd_device *device) { struct azx *chip = device->device_data; + struct hdac_bus *bus = azx_bus(chip); chip->bus.shutdown = 1; + cancel_work_sync(&bus->unsol_work); + return 0; } -- cgit From d3de1eb461e5bac0b07f5c785e6e0d959915df96 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 25 Oct 2019 16:13:53 +1100 Subject: ASoC: fsl: fsl_dma: fix build failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 4ac85de9977e ("ASoC: fsl: fsl_dma: remove snd_pcm_ops") removed fsl_dma_ops but left a usage, leading to a build error for some configs, eg. mpc85xx_defconfig: sound/soc/fsl/fsl_dma.c: In function ‘fsl_soc_dma_probe’: sound/soc/fsl/fsl_dma.c:905:18: error: ‘fsl_dma_ops’ undeclared (first use in this function) dma->dai.ops = &fsl_dma_ops; ^~~~~~~~~~~ Remove the usage to fix the build. Fixes: 4ac85de9977e ("ASoC: fsl: fsl_dma: remove snd_pcm_ops") Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191025051353.2878-1-mpe@ellerman.id.au Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_dma.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index a092726510d4..2868c4f97cb2 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -901,7 +901,6 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) } dma->dai.name = DRV_NAME; - dma->dai.ops = &fsl_dma_ops; dma->dai.open = fsl_dma_open; dma->dai.close = fsl_dma_close; dma->dai.ioctl = snd_soc_pcm_lib_ioctl; -- cgit From 24d05966b560b88d37d90e64f018af2fed888104 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 25 Oct 2019 20:08:01 +0800 Subject: ASoC: sunxi: sun4i-codec: remove unneeded semicolon remove unneeded semicolon. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20191025120801.16236-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index ee448d5e07a6..34f3e0be3058 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1442,7 +1442,7 @@ static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) if (!aux_dev.dlc.of_node) { dev_err(dev, "Can't find analog controls for codec.\n"); return ERR_PTR(-EINVAL); - }; + } card->dai_link = sun4i_codec_create_link(dev, &card->num_links); if (!card->dai_link) @@ -1480,7 +1480,7 @@ static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) if (!aux_dev.dlc.of_node) { dev_err(dev, "Can't find analog controls for codec.\n"); return ERR_PTR(-EINVAL); - }; + } card->dai_link = sun4i_codec_create_link(dev, &card->num_links); if (!card->dai_link) @@ -1518,7 +1518,7 @@ static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev) if (!aux_dev.dlc.of_node) { dev_err(dev, "Can't find analog controls for codec.\n"); return ERR_PTR(-EINVAL); - }; + } card->dai_link = sun4i_codec_create_link(dev, &card->num_links); if (!card->dai_link) -- cgit From 15747a80207585fe942416025540c0ff34e2aef8 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Fri, 25 Oct 2019 17:11:31 +0800 Subject: ASoC: eve: implement set_bias_level function for rt5514 The first DMIC capture always fail (zero sequence data from PCM port) after using DSP hotwording function (i.e. Google assistant). This rt5514 codec requires to control mclk directly in the set_bias_level function. Implement this function in machine driver to control the ssp1_mclk clock explicitly could fix this issue. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/1571994691-20199-1-git-send-email-brent.lu@intel.com Signed-off-by: Mark Brown --- .../soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index dc09a85e4c74..b546de8ba1e3 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -653,6 +653,55 @@ static struct snd_soc_dai_link kabylake_dais[] = { }, }; +static int kabylake_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) +{ + struct snd_soc_component *component = dapm->component; + struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card); + int ret = 0; + + if (!component || strcmp(component->name, RT5514_DEV_NAME)) + return 0; + + if (IS_ERR(priv->mclk)) + return 0; + + /* + * It's required to control mclk directly in the set_bias_level + * function for rt5514 codec or the recording function could + * break. + */ + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level == SND_SOC_BIAS_ON) { + dev_dbg(card->dev, "Disable mclk"); + clk_disable_unprepare(priv->mclk); + } else { + dev_dbg(card->dev, "Enable mclk"); + ret = clk_set_rate(priv->mclk, 24000000); + if (ret) { + dev_err(card->dev, "Can't set rate for mclk, err: %d\n", + ret); + return ret; + } + + ret = clk_prepare_enable(priv->mclk); + if (ret) { + dev_err(card->dev, "Can't enable mclk, err: %d\n", + ret); + + /* mclk is already enabled in FW */ + ret = 0; + } + } + break; + default: + break; + } + + return ret; +} + static int kabylake_card_late_probe(struct snd_soc_card *card) { struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); @@ -692,6 +741,7 @@ static struct snd_soc_card kabylake_audio_card = { .owner = THIS_MODULE, .dai_link = kabylake_dais, .num_links = ARRAY_SIZE(kabylake_dais), + .set_bias_level = kabylake_set_bias_level, .controls = kabylake_controls, .num_controls = ARRAY_SIZE(kabylake_controls), .dapm_widgets = kabylake_widgets, -- cgit From b39eb1e250c32c695a780f1814086f2bfa0fb593 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 28 Oct 2019 17:10:29 +0800 Subject: ASoC: fsl_asrc: refine the setting of internal clock divider The output divider should align with the output sample rate, if use ideal sample rate, there will be a lot of overload, which would cause underrun. The maximum divider of asrc clock is 1024, but there is no judgement for this limitation in driver, which may cause the divider setting not correct. For non-ideal ratio mode, the clock rate should divide the sample rate with no remainder, and the quotient should be less than 1024. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/23c634e4bf58afce5b3ae67f5f42e8d1cae2639a.1572252307.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 0bf91a6f54b9..a3cfceea7d2f 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -259,8 +259,15 @@ static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, * It configures those ASRC registers according to a configuration instance * of struct asrc_config which includes in/output sample rate, width, channel * and clock settings. + * + * Note: + * The ideal ratio configuration can work with a flexible clock rate setting. + * Using IDEAL_RATIO_RATE gives a faster converting speed but overloads ASRC. + * For a regular audio playback, the clock rate should not be slower than an + * clock rate aligning with the output sample rate; For a use case requiring + * faster conversion, set use_ideal_rate to have the faster speed. */ -static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) +static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) { struct asrc_config *config = pair->config; struct fsl_asrc *asrc_priv = pair->asrc_priv; @@ -268,7 +275,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) enum asrc_word_width input_word_width; enum asrc_word_width output_word_width; u32 inrate, outrate, indiv, outdiv; - u32 clk_index[2], div[2]; + u32 clk_index[2], div[2], rem[2]; + u64 clk_rate; int in, out, channels; int pre_proc, post_proc; struct clk *clk; @@ -351,27 +359,42 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) /* We only have output clock for ideal ratio mode */ clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; - div[IN] = clk_get_rate(clk) / inrate; - if (div[IN] == 0) { + clk_rate = clk_get_rate(clk); + rem[IN] = do_div(clk_rate, inrate); + div[IN] = (u32)clk_rate; + + /* + * The divider range is [1, 1024], defined by the hardware. For non- + * ideal ratio configuration, clock rate has to be strictly aligned + * with the sample rate. For ideal ratio configuration, clock rates + * only result in different converting speeds. So remainder does not + * matter, as long as we keep the divider within its valid range. + */ + if (div[IN] == 0 || (!ideal && (div[IN] > 1024 || rem[IN] != 0))) { pair_err("failed to support input sample rate %dHz by asrck_%x\n", inrate, clk_index[ideal ? OUT : IN]); return -EINVAL; } - clk = asrc_priv->asrck_clk[clk_index[OUT]]; + div[IN] = min_t(u32, 1024, div[IN]); - /* Use fixed output rate for Ideal Ratio mode (INCLK_NONE) */ - if (ideal) - div[OUT] = clk_get_rate(clk) / IDEAL_RATIO_RATE; + clk = asrc_priv->asrck_clk[clk_index[OUT]]; + clk_rate = clk_get_rate(clk); + if (ideal && use_ideal_rate) + rem[OUT] = do_div(clk_rate, IDEAL_RATIO_RATE); else - div[OUT] = clk_get_rate(clk) / outrate; + rem[OUT] = do_div(clk_rate, outrate); + div[OUT] = clk_rate; - if (div[OUT] == 0) { + /* Output divider has the same limitation as the input one */ + if (div[OUT] == 0 || (!ideal && (div[OUT] > 1024 || rem[OUT] != 0))) { pair_err("failed to support output sample rate %dHz by asrck_%x\n", outrate, clk_index[OUT]); return -EINVAL; } + div[OUT] = min_t(u32, 1024, div[OUT]); + /* Set the channel number */ channels = config->channel_num; @@ -560,7 +583,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, config.output_sample_rate = rate; } - ret = fsl_asrc_config_pair(pair); + ret = fsl_asrc_config_pair(pair, false); if (ret) { dev_err(dai->dev, "fail to config asrc pair\n"); return ret; -- cgit From 35dac627471938eda89fa39ee4ead1f7667e0f57 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 28 Oct 2019 17:11:05 +0800 Subject: ASoC: fsl_esai: Add spin lock to protect reset, stop and start xrun may happen at the end of stream, the trigger->fsl_esai_trigger_stop maybe called in the middle of fsl_esai_hw_reset, this may cause esai in wrong state after stop, and there may be endless xrun interrupt. This issue may also happen with trigger->fsl_esai_trigger_start. So Add spin lock to lock those functions. Fixes: 7ccafa2b3879 ("ASoC: fsl_esai: recover the channel swap after xrun") Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/52e92c4221a83e39a84a6cd92fc3d5479b44894c.1572252321.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index a78e4ab478df..c7a49d03463a 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -33,6 +33,7 @@ * @fsysclk: system clock source to derive HCK, SCK and FS * @spbaclk: SPBA clock (optional, depending on SoC design) * @task: tasklet to handle the reset operation + * @lock: spin lock between hw_reset() and trigger() * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot * @slots: number of slots @@ -56,6 +57,7 @@ struct fsl_esai { struct clk *fsysclk; struct clk *spbaclk; struct tasklet_struct task; + spinlock_t lock; /* Protect hw_reset and trigger */ u32 fifo_depth; u32 slot_width; u32 slots; @@ -676,8 +678,10 @@ static void fsl_esai_hw_reset(unsigned long arg) { struct fsl_esai *esai_priv = (struct fsl_esai *)arg; bool tx = true, rx = false, enabled[2]; + unsigned long lock_flags; u32 tfcr, rfcr; + spin_lock_irqsave(&esai_priv->lock, lock_flags); /* Save the registers */ regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr); regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr); @@ -715,6 +719,8 @@ static void fsl_esai_hw_reset(unsigned long arg) fsl_esai_trigger_start(esai_priv, tx); if (enabled[rx]) fsl_esai_trigger_start(esai_priv, rx); + + spin_unlock_irqrestore(&esai_priv->lock, lock_flags); } static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, @@ -722,6 +728,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + unsigned long lock_flags; esai_priv->channels[tx] = substream->runtime->channels; @@ -729,12 +736,16 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + spin_lock_irqsave(&esai_priv->lock, lock_flags); fsl_esai_trigger_start(esai_priv, tx); + spin_unlock_irqrestore(&esai_priv->lock, lock_flags); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock_irqsave(&esai_priv->lock, lock_flags); fsl_esai_trigger_stop(esai_priv, tx); + spin_unlock_irqrestore(&esai_priv->lock, lock_flags); break; default: return -EINVAL; @@ -1002,6 +1013,7 @@ static int fsl_esai_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, esai_priv); + spin_lock_init(&esai_priv->lock); ret = fsl_esai_hw_init(esai_priv); if (ret) return ret; -- cgit From 5db8617ba7e8fcda1c5dd310c62ac8d31eaf9eae Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Oct 2019 14:29:55 +0900 Subject: ASoC: rsnd: core.c: add WARN_ON() on rsnd_channel_normalization() chan > 8 or chan < 0 shouldn't happen. This patch uses WARN_ON() for such case. Reported-by: Pavel Machek Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y2x530a4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 72924c8b0696..871afe75ca42 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -302,7 +302,7 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, int rsnd_channel_normalization(int chan) { - if ((chan > 8) || (chan < 0)) + if (WARN_ON((chan > 8) || (chan < 0))) return 0; /* TDM Extend Mode needs 8ch */ -- cgit From 4c19030c511fd6eab029bae838f736256d2f43cd Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:40:57 -0500 Subject: ASoC: SOF: add a field to store the current D0 substate of DSP Add field d0_substate to struct snd_sof_dev to store the current DSP D0 sub-state(only meaningful when DSP in D0), which could be D0I0 or D0I3. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-priv.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 2d40de5ee285..481dfe4ee2d0 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -68,6 +68,12 @@ extern int sof_core_debug; #define DMA_CHAN_INVALID 0xFFFFFFFF +/* DSP D0ix sub-state */ +enum sof_d0_substate { + SOF_DSP_D0I0 = 0, /* DSP default D0 substate */ + SOF_DSP_D0I3, /* DSP D0i3(low power) substate*/ +}; + struct snd_sof_dev; struct snd_sof_ipc_msg; struct snd_sof_ipc; @@ -387,6 +393,9 @@ struct snd_sof_dev { */ struct snd_soc_component_driver plat_drv; + /* power states related */ + enum sof_d0_substate d0_substate; + /* DSP firmware boot */ wait_queue_head_t boot_wait; u32 boot_complete; -- cgit From 09fe6b528886c0d07ce539b837749edcc46618d0 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:40:58 -0500 Subject: ASoC: SOF: reset default d0_substate at probe() and resume() We initialize/reset d0_substate to default d0i0 value when doing transition D3-->D0, e.g. at success of probing and resuming. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 3 +++ sound/soc/sof/pm.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 5998861a9002..8661c2cca76b 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -458,6 +458,9 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) /* initialize sof device */ sdev->dev = dev; + /* initialize default D0 sub-state */ + sdev->d0_substate = SOF_DSP_D0I0; + sdev->pdata = plat_data; sdev->first_boot = true; dev_set_drvdata(dev, sdev); diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index e23beaeefe00..81e623dfc7e5 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -326,6 +326,9 @@ static int sof_resume(struct device *dev, bool runtime_resume) "error: ctx_restore ipc error during resume %d\n", ret); + /* initialize default D0 sub-state */ + sdev->d0_substate = SOF_DSP_D0I0; + return ret; } -- cgit From e8f112d8c29f44ded83f97828c104bf0904871ec Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:40:59 -0500 Subject: ASoC: SOF: add set_power_state() to dsp_ops for power state update D0i3 is a platform-defined substate of D0, so we need a platform-specific callback in dsp_ops to handle the relevant configurations. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.h | 9 +++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 824d36fe59fd..d7c8fc06f961 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -193,6 +193,15 @@ static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) return 0; } +static inline int snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate substate) +{ + if (sof_ops(sdev)->set_power_state) + return sof_ops(sdev)->set_power_state(sdev, substate); + + return 0; +} + /* debug */ static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 481dfe4ee2d0..e9902e4e8e55 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -189,6 +189,8 @@ struct snd_sof_dsp_ops { int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ int (*runtime_idle)(struct snd_sof_dev *sof_dev); /* optional */ int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */ + int (*set_power_state)(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate); /* optional */ /* DSP clocking */ int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */ -- cgit From 62f8f76604623980d41cf73691ca45288871efd9 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:00 -0500 Subject: ASoC: SOF: Intel: hda-dsp: Add helper for setting DSP D0ix substate Adding helper to implement setting dsp to d0i3 or d0i0 status, this will be needed for driver D0ix support. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 46 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 10 ++++++++++ 2 files changed, 56 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 3ea401646e0c..fa2f1f66c72c 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -306,6 +306,52 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } +static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev, int retry) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) { + if (!retry--) + return -ETIMEDOUT; + usleep_range(10, 15); + } + + return 0; +} + +int hda_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int retry = 50; + int ret; + u8 value; + + /* Write to D0I3C after Command-In-Progress bit is cleared */ + ret = hda_dsp_wait_d0i3c_done(sdev, retry); + if (ret < 0) { + dev_err(bus->dev, "CIP timeout before update D0I3C!\n"); + return ret; + } + + /* Update D0I3C register */ + value = d0_substate == SOF_DSP_D0I3 ? SOF_HDA_VS_D0I3C_I3 : 0; + snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); + + /* Wait for cmd in progress to be cleared before exiting the function */ + retry = 50; + ret = hda_dsp_wait_d0i3c_done(sdev, retry); + if (ret < 0) { + dev_err(bus->dev, "CIP timeout after D0I3C updated!\n"); + return ret; + } + + dev_vdbg(bus->dev, "D0I3C updated, register = 0x%x\n", + snd_hdac_chip_readb(bus, VS_D0I3C)); + + return 0; +} + static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ea02bf40cb25..0e7c366b8f71 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -64,6 +64,13 @@ #define SOF_HDA_PPCTL_PIE BIT(31) #define SOF_HDA_PPCTL_GPROCEN BIT(30) +/*Vendor Specific Registers*/ +#define SOF_HDA_VS_D0I3C 0x104A + +/* D0I3C Register fields */ +#define SOF_HDA_VS_D0I3C_CIP BIT(0) /* Command-In-Progress */ +#define SOF_HDA_VS_D0I3C_I3 BIT(2) /* D0i3 enable bit */ + /* DPIB entry size: 8 Bytes = 2 DWords */ #define SOF_HDA_DPIB_ENTRY_SIZE 0x8 @@ -455,6 +462,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); +int hda_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate); + int hda_dsp_suspend(struct snd_sof_dev *sdev); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev); -- cgit From 73b51957122dc47a40325a5359b44ef337cbf217 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:01 -0500 Subject: ASoC: SOF: Intel: CNL: add set_power_state() ops Using hda_dsp_set_power_state() as set_power_state() ops for cnl to do d0ix platform configuration updates. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/cnl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index e9cdcc040fb5..982b81a0b13a 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -255,6 +255,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .runtime_resume = hda_dsp_runtime_resume, .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + .set_power_state = hda_dsp_set_power_state, /* ALSA HW info flags */ .hw_info = SNDRV_PCM_INFO_MMAP | -- cgit From 35c930ba6025964ac71f041065ae212a0fcc7cca Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:02 -0500 Subject: ASoC: SOF: Intel: APL: add set_power_state() ops Using hda_dsp_set_power_state() as set_power_state() ops for apl to do d0ix platform configuration updates. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 15d26e8d90a9..7daa8eb456c8 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -97,6 +97,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .runtime_resume = hda_dsp_runtime_resume, .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + .set_power_state = hda_dsp_set_power_state, /* ALSA HW info flags */ .hw_info = SNDRV_PCM_INFO_MMAP | -- cgit From e5c97e88084b8dca6850eba5d2937716b88306c1 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:03 -0500 Subject: ASoC: SOF: add flag to snd_sof_pcm_stream for D0i3 compatible stream Add flag d0i3_compatible to struct snd_sof_pcm_stream to denote if the stream can tolerate a transition to the D0i3 substate while opened (thus seen as 'active' by pm_runtime). Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-priv.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index e9902e4e8e55..7a21a45d3635 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -310,6 +310,7 @@ struct snd_sof_pcm_stream { struct sof_ipc_stream_posn posn; struct snd_pcm_substream *substream; struct work_struct period_elapsed_work; + bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */ }; /* ALSA SOF PCM device */ -- cgit From 4a94940988cc44adeb383401dea0beeac4abbe63 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:04 -0500 Subject: ASoC: SOF: token: add tokens for PCM compatible with D0i3 substate Add stream token SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3 and SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3 to denote if the stream can be opened at low power d0i3 status or not. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b3ab6f23fc93..121e5d6f8477 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -567,6 +567,16 @@ static const struct sof_topology_token pcm_tokens[] = { offsetof(struct sof_ipc_comp_host, dmac_config), 0}, }; +/* PCM */ +static const struct sof_topology_token stream_tokens[] = { + {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3, + SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct snd_sof_pcm, stream[0].d0i3_compatible), 0}, + {SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3, + SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct snd_sof_pcm, stream[1].d0i3_compatible), 0}, +}; + /* Generic components */ static const struct sof_topology_token comp_tokens[] = { {SOF_TKN_COMP_PERIOD_SINK_COUNT, -- cgit From c5232c0171428f005a3204e1c264231fb5999b28 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:05 -0500 Subject: ASoC: SOF: topology: parse and store d0i3_compatible flag Parses the token from tplg file and store it to snd_sof_pcm_stream d0i3_compatible flag, which can be used later for d0ix transition management. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 121e5d6f8477..cc138ac6a8eb 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2307,6 +2307,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_stream_caps *caps; + struct snd_soc_tplg_private *private = &pcm->priv; struct snd_sof_pcm *spcm; int stream = SNDRV_PCM_STREAM_PLAYBACK; int ret = 0; @@ -2329,10 +2330,22 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, dai_drv->dobj.private = spcm; list_add(&spcm->list, &sdev->pcm_list); + ret = sof_parse_tokens(scomp, spcm, stream_tokens, + ARRAY_SIZE(stream_tokens), private->array, + le32_to_cpu(private->size)); + if (ret) { + dev_err(sdev->dev, "error: parse stream tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + /* do we need to allocate playback PCM DMA pages */ if (!spcm->pcm.playback) goto capture; + dev_vdbg(sdev->dev, "tplg: pcm %s stream tokens: playback d0i3:%d\n", + spcm->pcm.pcm_name, spcm->stream[0].d0i3_compatible); + caps = &spcm->pcm.caps[stream]; /* allocate playback page table buffer */ @@ -2360,6 +2373,9 @@ capture: if (!spcm->pcm.capture) return ret; + dev_vdbg(sdev->dev, "tplg: pcm %s stream tokens: capture d0i3:%d\n", + spcm->pcm.pcm_name, spcm->stream[1].d0i3_compatible); + caps = &spcm->pcm.caps[stream]; /* allocate capture page table buffer */ -- cgit From aae7c82d01219bf568a7b12f5839d7ca52b17d59 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:06 -0500 Subject: ASoC: SOF: Intel: hda-dsp: align the comments for D0I3C update Align the logs for CIP timeout at D0I3C.I3 updating. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index fa2f1f66c72c..74805a066183 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -330,7 +330,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, /* Write to D0I3C after Command-In-Progress bit is cleared */ ret = hda_dsp_wait_d0i3c_done(sdev, retry); if (ret < 0) { - dev_err(bus->dev, "CIP timeout before update D0I3C!\n"); + dev_err(bus->dev, "CIP timeout before D0I3C update!\n"); return ret; } @@ -342,7 +342,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, retry = 50; ret = hda_dsp_wait_d0i3c_done(sdev, retry); if (ret < 0) { - dev_err(bus->dev, "CIP timeout after D0I3C updated!\n"); + dev_err(bus->dev, "CIP timeout after D0I3C update!\n"); return ret; } -- cgit From 92f4beb718d76e93b76343a3ba872df6cb210672 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:07 -0500 Subject: ASoC: SOF: Intel: HDA: use macro for register polling retry count Define macro and use it for the register polling retry count. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 6 ++---- sound/soc/sof/intel/hda.h | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 74805a066183..936361bd25e9 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -323,12 +323,11 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, enum sof_d0_substate d0_substate) { struct hdac_bus *bus = sof_to_bus(sdev); - int retry = 50; int ret; u8 value; /* Write to D0I3C after Command-In-Progress bit is cleared */ - ret = hda_dsp_wait_d0i3c_done(sdev, retry); + ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); if (ret < 0) { dev_err(bus->dev, "CIP timeout before D0I3C update!\n"); return ret; @@ -339,8 +338,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); /* Wait for cmd in progress to be cleared before exiting the function */ - retry = 50; - ret = hda_dsp_wait_d0i3c_done(sdev, retry); + ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); if (ret < 0) { dev_err(bus->dev, "CIP timeout after D0I3C update!\n"); return ret; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 0e7c366b8f71..99ec60218c16 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -214,6 +214,7 @@ #define HDA_DSP_CTRL_RESET_TIMEOUT 100 #define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ #define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */ +#define HDA_DSP_REG_POLL_RETRY_COUNT 50 #define HDA_DSP_ADSPIC_IPC 1 #define HDA_DSP_ADSPIS_IPC 1 -- cgit From 7c7eba2402c11137d1fa1d3fb964a2c6fc1ded3e Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:08 -0500 Subject: ASoC: SOF: PM: rename sof_send_pm_ipc to sof_send_pm_ctx_ipc The helper sof_send_pm_ipc() is only suitable for context save/restore IPCs' sending, so rename it to sof_send_pm_ctx_ipc here. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 81e623dfc7e5..ac900fb3379e 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -197,7 +197,7 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) return ret; } -static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) +static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd) { struct sof_ipc_pm_ctx pm_ctx; struct sof_ipc_reply reply; @@ -320,7 +320,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) } /* notify DSP of system resume */ - ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_RESTORE); + ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE); if (ret < 0) dev_err(sdev->dev, "error: ctx_restore ipc error during resume %d\n", @@ -361,7 +361,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) sof_cache_debugfs(sdev); #endif /* notify DSP of upcoming power down */ - ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE); + ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE); if (ret == -EBUSY || ret == -EAGAIN) { /* * runtime PM has logic to handle -EBUSY/-EAGAIN so -- cgit From 463fbf6dc03aff41e973602bbad6cb135fa6d48a Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:10 -0500 Subject: ASoC: SOF: Intel: hda-ipc: Don't read mailbox for PM_GATE reply Memory windows could be powered off before receiving PM_GATE IPC reply from FW, we can't read the mailbox to get reply. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ipc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 6aae6f18b3dc..0fd2153c1769 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -83,10 +83,12 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) } hdr = msg->msg_data; - if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { + if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE) || + hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { /* * memory windows are powered off before sending IPC reply, - * so we can't read the mailbox for CTX_SAVE reply. + * so we can't read the mailbox for CTX_SAVE and PM_GATE + * replies. */ reply.error = 0; reply.hdr.cmd = SOF_IPC_GLB_REPLY; -- cgit From 5056193d4d1a8b73087145add21141c46027d6a2 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:11 -0500 Subject: ASoC: SOF: Intel: HDA: add cAVS specific compact IPC header file On cAVS platforms, some IPCs are required to be sent via IPC registers only(e.g. when in D0i3, mailbox is unaccessible), add hda-ipc.h to hold definition of those compact IPCs. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ipc.h | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 sound/soc/sof/intel/hda-ipc.h (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-ipc.h b/sound/soc/sof/intel/hda-ipc.h new file mode 100644 index 000000000000..aef0ceac9803 --- /dev/null +++ b/sound/soc/sof/intel/hda-ipc.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Keyon Jie + */ + +#ifndef __SOF_INTEL_HDA_IPC_H +#define __SOF_INTEL_HDA_IPC_H + +/* + * Primary register, mapped to + * - DIPCTDR (HIPCIDR) in sideband IPC (cAVS 1.8+) + * - DIPCT in cAVS 1.5 IPC + * + * Secondary register, mapped to: + * - DIPCTDD (HIPCIDD) in sideband IPC (cAVS 1.8+) + * - DIPCTE in cAVS 1.5 IPC + */ + +/* Common bits in primary register */ + +/* Reserved for doorbell */ +#define HDA_IPC_RSVD_31 BIT(31) +/* Target, 0 - normal message, 1 - compact message(cAVS compatible) */ +#define HDA_IPC_MSG_COMPACT BIT(30) +/* Direction, 0 - request, 1 - response */ +#define HDA_IPC_RSP BIT(29) + +#define HDA_IPC_TYPE_SHIFT 24 +#define HDA_IPC_TYPE_MASK GENMASK(28, 24) +#define HDA_IPC_TYPE(x) ((x) << HDA_IPC_TYPE_SHIFT) + +#define HDA_IPC_PM_GATE HDA_IPC_TYPE(0x8U) + +/* Command specific payload bits in secondary register */ + +/* Disable DMA tracing (0 - keep tracing, 1 - to disable DMA trace) */ +#define HDA_PM_NO_DMA_TRACE BIT(4) +/* Prevent clock gating (0 - cg allowed, 1 - DSP clock always on) */ +#define HDA_PM_PCG BIT(3) +/* Prevent power gating (0 - deep power state transitions allowed) */ +#define HDA_PM_PPG BIT(2) +/* Indicates whether streaming is active */ +#define HDA_PM_PG_STREAMING BIT(1) +#define HDA_PM_PG_RSVD BIT(0) + +#endif -- cgit From 534037fddd34b58be86a826d449a5a6635ecdbf5 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:12 -0500 Subject: ASoC: SOF: configure D0ix IPC flags in set_power_state The configuration for D0ix in FW is platform specific, let's do this and send IPC in the platform set_power_state() ops. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 936361bd25e9..b5070409a5e3 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -19,6 +19,7 @@ #include #include "../ops.h" #include "hda.h" +#include "hda-ipc.h" /* * DSP Core control. @@ -319,10 +320,28 @@ static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev, int retry) return 0; } +static int hda_dsp_send_pm_gate_ipc(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_pm_gate pm_gate; + struct sof_ipc_reply reply; + + memset(&pm_gate, 0, sizeof(pm_gate)); + + /* configure pm_gate ipc message */ + pm_gate.hdr.size = sizeof(pm_gate); + pm_gate.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE; + pm_gate.flags = flags; + + /* send pm_gate ipc to dsp */ + return sof_ipc_tx_message(sdev->ipc, pm_gate.hdr.cmd, &pm_gate, + sizeof(pm_gate), &reply, sizeof(reply)); +} + int hda_dsp_set_power_state(struct snd_sof_dev *sdev, enum sof_d0_substate d0_substate) { struct hdac_bus *bus = sof_to_bus(sdev); + u32 flags; int ret; u8 value; @@ -347,7 +366,18 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, dev_vdbg(bus->dev, "D0I3C updated, register = 0x%x\n", snd_hdac_chip_readb(bus, VS_D0I3C)); - return 0; + if (d0_substate == SOF_DSP_D0I0) + flags = HDA_PM_PPG;/* prevent power gating in D0 */ + else + flags = HDA_PM_NO_DMA_TRACE;/* disable DMA trace in D0I3*/ + + /* sending pm_gate IPC */ + ret = hda_dsp_send_pm_gate_ipc(sdev, flags); + if (ret < 0) + dev_err(sdev->dev, + "error: PM_GATE ipc error %d\n", ret); + + return ret; } static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) -- cgit From 601252869f50af6f5ab377e7f4846d7b09cc66c0 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:13 -0500 Subject: ASoC: SOF: PM: add helpers for setting D0 substate for ADSP Add snd_sof_set_d0_substate() helper for setting ADSP to a specific D0 substate, it will call into the platform specific implementation, and update the d0_substate at success. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pm.c | 17 +++++++++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 19 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index ac900fb3379e..584241e9734a 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -411,6 +411,23 @@ int snd_sof_runtime_resume(struct device *dev) } EXPORT_SYMBOL(snd_sof_runtime_resume); +int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate) +{ + int ret; + + /* do platform specific set_state */ + ret = snd_sof_dsp_set_power_state(sdev, d0_substate); + if (ret < 0) + return ret; + + /* update dsp D0 sub-state */ + sdev->d0_substate = d0_substate; + + return 0; +} +EXPORT_SYMBOL(snd_sof_set_d0_substate); + int snd_sof_resume(struct device *dev) { return sof_resume(dev, false); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 7a21a45d3635..2231c673c678 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -485,6 +485,8 @@ int snd_sof_runtime_resume(struct device *dev); int snd_sof_runtime_idle(struct device *dev); int snd_sof_resume(struct device *dev); int snd_sof_suspend(struct device *dev); +int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate); void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); -- cgit From 0267de58acfe5059ace739741f1533dd605ed22f Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:14 -0500 Subject: ASoC: SOF: Intel: CNL: add support for sending compact IPC For compact IPCs, we will send the IPC header/command via the HIPCIDR register and the first 32bit payload via the HIPCIDD register, no mailbox will be used. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-19-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/cnl.c | 42 +++++++++++++++++++++++++++++++++++++----- sound/soc/sof/intel/hda.h | 1 + 2 files changed, 38 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 982b81a0b13a..0e1e265f3f3b 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -17,6 +17,7 @@ #include "../ops.h" #include "hda.h" +#include "hda-ipc.h" static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, @@ -150,14 +151,45 @@ static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev) CNL_DSP_REG_HIPCCTL_DONE); } +static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg, + u32 *dr, u32 *dd) +{ + struct sof_ipc_pm_gate *pm_gate; + + if (msg->header == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { + pm_gate = msg->msg_data; + + /* send the compact message via the primary register */ + *dr = HDA_IPC_MSG_COMPACT | HDA_IPC_PM_GATE; + + /* send payload via the extended data register */ + *dd = pm_gate->flags; + + return true; + } + + return false; +} + static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - /* send the message */ - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, - CNL_DSP_REG_HIPCIDR_BUSY); + u32 dr = 0; + u32 dd = 0; + + if (cnl_compact_ipc_compress(msg, &dr, &dd)) { + /* send the message via IPC registers */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDD, + dd); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, + CNL_DSP_REG_HIPCIDR_BUSY | dr); + } else { + /* send the message via mailbox */ + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, + CNL_DSP_REG_HIPCIDR_BUSY); + } return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 99ec60218c16..52a87a47029d 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -312,6 +312,7 @@ #define CNL_DSP_REG_HIPCTDD (CNL_DSP_IPC_BASE + 0x08) #define CNL_DSP_REG_HIPCIDR (CNL_DSP_IPC_BASE + 0x10) #define CNL_DSP_REG_HIPCIDA (CNL_DSP_IPC_BASE + 0x14) +#define CNL_DSP_REG_HIPCIDD (CNL_DSP_IPC_BASE + 0x18) #define CNL_DSP_REG_HIPCCTL (CNL_DSP_IPC_BASE + 0x28) /* HIPCI */ -- cgit From 7367d3096b1443e55a2c730d1966f423b15d5cad Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:15 -0500 Subject: ASoC: SOF: add a flag to indicate the system suspend target Add flag 's0_suspend' to indicate if the system is entering S0ix or not. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-20-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-priv.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 2231c673c678..e715673f20e5 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -398,6 +398,8 @@ struct snd_sof_dev { /* power states related */ enum sof_d0_substate d0_substate; + /* flag to track if the intended power target of suspend is S0ix */ + bool s0_suspend; /* DSP firmware boot */ wait_queue_head_t boot_wait; -- cgit From 4cd933abd4820da7eefe672ff439b32d199a07be Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:16 -0500 Subject: ASoC: SOF: add a flag suspend_ignored for sof stream Add a suspend_ignored flag to snd_sof_pcm_stream that will be used to decide if the corresponding FW pipeline should be kept active to perform always on tasks when the system is entering the S0ix state. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-21-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-priv.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index e715673f20e5..c2541d020bde 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -311,6 +311,11 @@ struct snd_sof_pcm_stream { struct snd_pcm_substream *substream; struct work_struct period_elapsed_work; bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */ + /* + * flag to indicate that the DSP pipelines should be kept + * active or not while suspending the stream + */ + bool suspend_ignored; }; /* ALSA SOF PCM device */ -- cgit From 0b50b3b1c3bc2a2c9eeab418b3de3e60e0530cf4 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:17 -0500 Subject: ASoC: SOF: PM: implement prepare/complete callbacks Implement the prepare() and complete() callbacks for power management, initialize s0_suspend flag at prepare(), and reset it at complete(). Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-22-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pm.c | 23 +++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 25 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 584241e9734a..99e4e6ffff74 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -439,3 +439,26 @@ int snd_sof_suspend(struct device *dev) return sof_suspend(dev, false); } EXPORT_SYMBOL(snd_sof_suspend); + +int snd_sof_prepare(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + +#if defined(CONFIG_ACPI) + sdev->s0_suspend = acpi_target_system_state() == ACPI_STATE_S0; +#else + /* will suspend to S3 by default */ + sdev->s0_suspend = false; +#endif + + return 0; +} +EXPORT_SYMBOL(snd_sof_prepare); + +void snd_sof_complete(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + + sdev->s0_suspend = false; +} +EXPORT_SYMBOL(snd_sof_complete); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index c2541d020bde..6408ac88a3e5 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -492,6 +492,8 @@ int snd_sof_runtime_resume(struct device *dev); int snd_sof_runtime_idle(struct device *dev); int snd_sof_resume(struct device *dev); int snd_sof_suspend(struct device *dev); +int snd_sof_prepare(struct device *dev); +void snd_sof_complete(struct device *dev); int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, enum sof_d0_substate d0_substate); -- cgit From ac8c046f19f94ec419c60d7a073af75a71386e97 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:18 -0500 Subject: ASoC: SOF: ignore suspend/resume for D0ix compatible streams During system suspend, the PM framework will freeze all applications and the ALSA/ASoC core will suspend all RUNNING PCM streams. However, D0ix-compatible PCM streams should keep the related pipelines active in the DSP when the system is entering S0ix. The TRIGGER_SUSPEND event is trapped in such cases to prevent the pipelines from being stopped. Likewise, the TRIGGER_RESUME/START events should not affect the pipeline state. The SOF driver also triggers some DSP Firmware pipelines based on the DAPM widgets power events. In such cases, we also ignore PRE_PMU and POST_PMD events to keep the pipelines active. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-23-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 31 +++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 17 ++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 9ba505cf5966..3d5cd1b445ba 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -346,6 +346,16 @@ static int sof_pcm_trigger(struct snd_soc_component *component, stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; break; case SNDRV_PCM_TRIGGER_RESUME: + if (spcm->stream[substream->stream].suspend_ignored) { + /* + * this case will be triggered when INFO_RESUME is + * supported, no need to resume streams that remained + * enabled in D0ix. + */ + spcm->stream[substream->stream].suspend_ignored = false; + return 0; + } + /* set up hw_params */ ret = sof_pcm_prepare(component, substream); if (ret < 0) { @@ -356,9 +366,30 @@ static int sof_pcm_trigger(struct snd_soc_component *component, /* fallthrough */ case SNDRV_PCM_TRIGGER_START: + if (spcm->stream[substream->stream].suspend_ignored) { + /* + * This case will be triggered when INFO_RESUME is + * not supported, no need to re-start streams that + * remained enabled in D0ix. + */ + spcm->stream[substream->stream].suspend_ignored = false; + return 0; + } stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; break; case SNDRV_PCM_TRIGGER_SUSPEND: + if (sdev->s0_suspend && + spcm->stream[substream->stream].d0i3_compatible) { + /* + * trap the event, not sending trigger stop to + * prevent the FW pipelines from being stopped, + * and mark the flag to ignore the upcoming DAPM + * PM events. + */ + spcm->stream[substream->stream].suspend_ignored = true; + return 0; + } + /* fallthrough */ case SNDRV_PCM_TRIGGER_STOP: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; ipc_first = true; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index cc138ac6a8eb..e0e2ae734632 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -135,7 +135,9 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_sof_widget *swidget = w->dobj.private; + int stream = SNDRV_PCM_STREAM_CAPTURE; struct snd_sof_dev *sdev; + struct snd_sof_pcm *spcm; int ret = 0; if (!swidget) @@ -146,11 +148,19 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, dev_dbg(sdev->dev, "received event %d for widget %s\n", event, w->name); + /* get runtime PCM params using widget's stream name */ + spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname); + /* process events */ switch (event) { case SND_SOC_DAPM_PRE_PMU: + if (spcm->stream[stream].suspend_ignored) { + dev_dbg(sdev->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n"); + return 0; + } + /* set pcm params */ - ret = ipc_pcm_params(swidget, SOF_IPC_STREAM_CAPTURE); + ret = ipc_pcm_params(swidget, stream); if (ret < 0) { dev_err(sdev->dev, "error: failed to set pcm params for widget %s\n", @@ -166,6 +176,11 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, swidget->widget->name); break; case SND_SOC_DAPM_POST_PMD: + if (spcm->stream[stream].suspend_ignored) { + dev_dbg(sdev->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n"); + return 0; + } + /* stop trigger */ ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP); if (ret < 0) -- cgit From 66e40876ddc325d892c493a6d83574bbba5770ce Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:19 -0500 Subject: ASoC: SOF: Intel: hda-dsp: implement suspend/resume for S0ix<->S0 transition Enable system wake up via IPC interrupt from DSP when the system is suspending to the S0ix state, and disable it in the corresponding resuming. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-24-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index b5070409a5e3..d23573d9e9c4 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -477,6 +477,15 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) int hda_dsp_resume(struct snd_sof_dev *sdev) { + struct pci_dev *pci = to_pci_dev(sdev->dev); + + if (sdev->s0_suspend) { + /* restore and disable the system wakeup */ + pci_restore_state(pci); + disable_irq_wake(pci->irq); + return 0; + } + /* init hda controller. DSP cores will be powered up during fw boot */ return hda_resume(sdev, false); } @@ -509,8 +518,16 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) int hda_dsp_suspend(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); + struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; + if (sdev->s0_suspend) { + /* enable the system waking up via IPC IRQ */ + enable_irq_wake(pci->irq); + pci_save_state(pci); + return 0; + } + /* stop hda controller and power dsp off */ ret = hda_suspend(sdev, false); if (ret < 0) { -- cgit From 5655ce660a6d3eec4a3ad37feb99fb228540d1a9 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:20 -0500 Subject: ASoC: SOF: return -ENOTSUPP if D0I3 is not supported No set_power_state ops means that the platform doesn't support D0i3, return -ENOTSUPP for the case. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-25-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index d7c8fc06f961..93512dcbaacd 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -199,7 +199,8 @@ static inline int snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev, if (sof_ops(sdev)->set_power_state) return sof_ops(sdev)->set_power_state(sdev, substate); - return 0; + /* D0 substate is not supported */ + return -ENOTSUPP; } /* debug */ -- cgit From c470fc3f61b25e955f8ba90fc9dc554881e4e72c Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:21 -0500 Subject: ASoC: SOF: PM: Add support for DSP D0i3 state when entering S0ix When system is entering into S0ix, the PCI device may transition to the D0i3 substate instead of D3. In D0i3, some always-on functionality can be enabled, such as acoustic event detection, voice activity detection or hotwording. When an event is detected, the DSP firmware can wake-up the device for a transition to D0 with an interrupt. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-26-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pm.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 99e4e6ffff74..560a937e0484 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -430,12 +430,58 @@ EXPORT_SYMBOL(snd_sof_set_d0_substate); int snd_sof_resume(struct device *dev) { + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + int ret; + + if (sdev->s0_suspend) { + /* resume from D0I3 */ + dev_dbg(sdev->dev, "DSP will exit from D0i3...\n"); + ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I0); + if (ret == -ENOTSUPP) { + /* fallback to resume from D3 */ + dev_dbg(sdev->dev, "D0i3 not supported, fall back to resume from D3...\n"); + goto d3_resume; + } else if (ret < 0) { + dev_err(sdev->dev, "error: failed to exit from D0I3 %d\n", + ret); + return ret; + } + + /* platform-specific resume from D0i3 */ + return snd_sof_dsp_resume(sdev); + } + +d3_resume: + /* resume from D3 */ return sof_resume(dev, false); } EXPORT_SYMBOL(snd_sof_resume); int snd_sof_suspend(struct device *dev) { + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + int ret; + + if (sdev->s0_suspend) { + /* suspend to D0i3 */ + dev_dbg(sdev->dev, "DSP is trying to enter D0i3...\n"); + ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I3); + if (ret == -ENOTSUPP) { + /* fallback to D3 suspend */ + dev_dbg(sdev->dev, "D0i3 not supported, fall back to D3...\n"); + goto d3_suspend; + } else if (ret < 0) { + dev_err(sdev->dev, "error: failed to enter D0I3, %d\n", + ret); + return ret; + } + + /* platform-specific suspend to D0i3 */ + return snd_sof_dsp_suspend(sdev); + } + +d3_suspend: + /* suspend to D3 */ return sof_suspend(dev, false); } EXPORT_SYMBOL(snd_sof_suspend); -- cgit From 6d407a39cc9619d0088b44333c6526924be00f8d Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:22 -0500 Subject: ASoC: SOF: pci: Add prepare/complete PM callbacks Use the new implemented snd_sof_prepare() and snd_sof_complete() as the power management callbacks for pci probing platforms. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-27-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 4adbb27c76c5..487b1f29f84d 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -264,6 +264,8 @@ static const struct sof_dev_desc jsl_desc = { #endif static const struct dev_pm_ops sof_pci_pm = { + .prepare = snd_sof_prepare, + .complete = snd_sof_complete, SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, snd_sof_runtime_idle) -- cgit From 91636a82044a2821201b54faac4d1d2425260842 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Oct 2019 14:06:34 +0100 Subject: ALSA: hda: Allow non-Intel device probe gracefully The recent addition of snd_intel_dsp_driver_probe() check caused a spurious kernel warning when the driver is loaded for a non-Intel hardware due to snd_BUG_ON(). Moreover, for such a hardware, we should always return SND_INTEL_DSP_DRIVER_ANY, not check the dsp_driver option at all. This patch fixes these issues for non-Intel devices. Fixes: 82d9d54a6c0e ("ALSA: hda: add Intel DSP configuration / probe code") Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20191028130634.3501-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/intel-dsp-config.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 0b2a7201a46a..be1df80ed013 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -307,13 +307,13 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) { const struct config_entry *cfg; - if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) - return dsp_driver; - /* Intel vendor only */ - if (snd_BUG_ON(pci->vendor != 0x8086)) + if (pci->vendor != 0x8086) return SND_INTEL_DSP_DRIVER_ANY; + if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) + return dsp_driver; + /* * detect DSP by checking class/subclass/prog-id information * class=04 subclass 03 prog-if 00: no DSP, use legacy driver -- cgit From d745cc1ab65945b2d17ec9c5652f38299c054649 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 28 Oct 2019 17:46:24 +0100 Subject: ASoC: intel - fix the card names Those strings are exposed to the user space as the card name thus used in the GUIs. The common standard is to avoid '_' here. The worst case is 'sof-skl_hda_card' string. Signed-off-by: Jaroslav Kysela Cc: Pierre-Louis Bossart Cc: Mark Brown Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191028164624.14334-1-perex@perex.cz Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 2 +- sound/soc/intel/boards/sof_rt5682.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index b546de8ba1e3..a1056cda3dd7 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -737,7 +737,7 @@ static int kabylake_card_late_probe(struct snd_soc_card *card) * kabylake audio machine driver for MAX98927 + RT5514 + RT5663 */ static struct snd_soc_card kabylake_audio_card = { - .name = "kbl_r5514_5663_max", + .name = "kbl-r5514-5663-max", .owner = THIS_MODULE, .dai_link = kabylake_dais, .num_links = ARRAY_SIZE(kabylake_dais), diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 1778acdc367c..e8d676c192f6 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -90,7 +90,7 @@ skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) } static struct snd_soc_card hda_soc_card = { - .name = "skl_hda_card", + .name = "hda-dsp", .owner = THIS_MODULE, .dai_link = skl_hda_be_dai_links, .dapm_widgets = skl_hda_widgets, diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 5ce643d62faf..2caebc77fdb5 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -370,7 +370,7 @@ static int dmic_init(struct snd_soc_pcm_runtime *rtd) /* sof audio machine driver for rt5682 codec */ static struct snd_soc_card sof_audio_card_rt5682 = { - .name = "sof_rt5682", + .name = "rt5682", /* the sof- prefix is added by the core */ .owner = THIS_MODULE, .controls = sof_controls, .num_controls = ARRAY_SIZE(sof_controls), -- cgit From c3ad1092e1069f27d0ca110dcaada8a5435ea3e0 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 28 Oct 2019 18:33:29 +0100 Subject: ASoC: SOF - remove the dead code (skylake/kabylake) Appearently the CONFIG_SND_SOC_SOF_KABYLAKE and CONFIG_SND_SOC_SOF_SKYLAKE options are not present in Kconfig and 'struct snd_sof_dsp_ops sof_skl_ops' is not declared in the code, too. Signed-off-by: Jaroslav Kysela Cc: Pierre-Louis Bossart Cc: Mark Brown Link: https://lore.kernel.org/r/20191028173329.29538-1-perex@perex.cz Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.h | 1 - sound/soc/sof/sof-pci-dev.c | 44 -------------------------------------------- 2 files changed, 45 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 52a87a47029d..16376f55e420 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -608,7 +608,6 @@ extern struct snd_soc_dai_driver skl_dai[]; */ extern const struct snd_sof_dsp_ops sof_apl_ops; extern const struct snd_sof_dsp_ops sof_cnl_ops; -extern const struct snd_sof_dsp_ops sof_skl_ops; extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 487b1f29f84d..4de90d04a91b 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -173,42 +173,6 @@ static const struct sof_dev_desc icl_desc = { }; #endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) -static const struct sof_dev_desc skl_desc = { - .machines = snd_soc_acpi_intel_skl_machines, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &skl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-skl.ri", - .nocodec_tplg_filename = "sof-skl-nocodec.tplg", - .ops = &sof_skl_ops, - .arch_ops = &sof_xtensa_arch_ops -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) -static const struct sof_dev_desc kbl_desc = { - .machines = snd_soc_acpi_intel_kbl_machines, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &skl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-kbl.ri", - .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", - .ops = &sof_skl_ops, - .arch_ops = &sof_xtensa_arch_ops -}; -#endif - #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) static const struct sof_dev_desc tgl_desc = { .machines = snd_soc_acpi_intel_tgl_machines, @@ -431,14 +395,6 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0xa348), .driver_data = (unsigned long)&cfl_desc}, #endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) - { PCI_DEVICE(0x8086, 0x9d71), - .driver_data = (unsigned long)&kbl_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) - { PCI_DEVICE(0x8086, 0x9d70), - .driver_data = (unsigned long)&skl_desc}, -#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) { PCI_DEVICE(0x8086, 0x34C8), .driver_data = (unsigned long)&icl_desc}, -- cgit From 05b754f5f41c1ea5366c37c8f0ee04c4b4899ff9 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Mon, 28 Oct 2019 15:19:27 +0800 Subject: ASoC: rockchip_max98090: Optionally support HDMI use case Support three different use cases with rockchip_max98090 driver. The three use cases: - max98090 only: Current usage, where HDMI link is missing. - HDMI only: Needed use case for veyron_mickey board. - max98090 + HDMI: Ideal use case for veyron_jerry, veyron_minnie..etc. The presence of max98090 is determined by the presence of rockchip,audio-codec device property. The presence of HDMI is determined by the presence of rockchip,hdmi-codec device property. Create different sound card based on the configuration. Note that we keep max98090 only usage for backward compatibility. Signed-off-by: Cheng-Yi Chiang Link: https://lore.kernel.org/r/20191028071930.145899-4-cychiang@chromium.org Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_max98090.c | 291 +++++++++++++++++++++++++-------- 1 file changed, 226 insertions(+), 65 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index 0097df1fae66..50ef9b8e7ce4 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -36,28 +37,73 @@ static struct snd_soc_jack_pin headset_jack_pins[] = { }; -static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), +#define RK_MAX98090_WIDGETS \ + SND_SOC_DAPM_HP("Headphone", NULL), \ + SND_SOC_DAPM_MIC("Headset Mic", NULL), \ + SND_SOC_DAPM_MIC("Int Mic", NULL), \ + SND_SOC_DAPM_SPK("Speaker", NULL) + +#define RK_HDMI_WIDGETS \ + SND_SOC_DAPM_LINE("HDMI", NULL) + +static const struct snd_soc_dapm_widget rk_max98090_dapm_widgets[] = { + RK_MAX98090_WIDGETS, +}; + +static const struct snd_soc_dapm_widget rk_hdmi_dapm_widgets[] = { + RK_HDMI_WIDGETS, +}; + +static const struct snd_soc_dapm_widget rk_max98090_hdmi_dapm_widgets[] = { + RK_MAX98090_WIDGETS, + RK_HDMI_WIDGETS, +}; + +#define RK_MAX98090_AUDIO_MAP \ + {"IN34", NULL, "Headset Mic"}, \ + {"Headset Mic", NULL, "MICBIAS"}, \ + {"DMICL", NULL, "Int Mic"}, \ + {"Headphone", NULL, "HPL"}, \ + {"Headphone", NULL, "HPR"}, \ + {"Speaker", NULL, "SPKL"}, \ + {"Speaker", NULL, "SPKR"} + +#define RK_HDMI_AUDIO_MAP \ + {"HDMI", NULL, "TX"} + +static const struct snd_soc_dapm_route rk_max98090_audio_map[] = { + RK_MAX98090_AUDIO_MAP, +}; + +static const struct snd_soc_dapm_route rk_hdmi_audio_map[] = { + RK_HDMI_AUDIO_MAP, }; -static const struct snd_soc_dapm_route rk_audio_map[] = { - {"IN34", NULL, "Headset Mic"}, - {"Headset Mic", NULL, "MICBIAS"}, - {"DMICL", NULL, "Int Mic"}, - {"Headphone", NULL, "HPL"}, - {"Headphone", NULL, "HPR"}, - {"Speaker", NULL, "SPKL"}, - {"Speaker", NULL, "SPKR"}, +static const struct snd_soc_dapm_route rk_max98090_hdmi_audio_map[] = { + RK_MAX98090_AUDIO_MAP, + RK_HDMI_AUDIO_MAP, +}; + +#define RK_MAX98090_CONTROLS \ + SOC_DAPM_PIN_SWITCH("Headphone"), \ + SOC_DAPM_PIN_SWITCH("Headset Mic"), \ + SOC_DAPM_PIN_SWITCH("Int Mic"), \ + SOC_DAPM_PIN_SWITCH("Speaker") + +#define RK_HDMI_CONTROLS \ + SOC_DAPM_PIN_SWITCH("HDMI") + +static const struct snd_kcontrol_new rk_max98090_controls[] = { + RK_MAX98090_CONTROLS, }; -static const struct snd_kcontrol_new rk_mc_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Int Mic"), - SOC_DAPM_PIN_SWITCH("Speaker"), +static const struct snd_kcontrol_new rk_hdmi_controls[] = { + RK_HDMI_CONTROLS, +}; + +static const struct snd_kcontrol_new rk_max98090_hdmi_controls[] = { + RK_MAX98090_CONTROLS, + RK_HDMI_CONTROLS, }; static int rk_jack_event(struct notifier_block *nb, unsigned long event, @@ -122,15 +168,20 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, SND_SOC_CLOCK_OUT); - if (ret < 0) { - dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + if (ret) { + dev_err(cpu_dai->dev, "Can't set cpu dai clock %d\n", ret); return ret; } ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + + /* HDMI codec dai does not need to set sysclk. */ + if (!strcmp(rtd->dai_link->name, "HDMI")) + return 0; + + if (ret) { + dev_err(codec_dai->dev, "Can't set codec dai clock %d\n", ret); return ret; } @@ -152,20 +203,67 @@ static const struct snd_soc_ops rk_aif1_ops = { .startup = rk_aif1_startup, }; -SND_SOC_DAILINK_DEFS(hifi, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link rk_dailink = { - .name = "max98090", - .stream_name = "Audio", - .init = rk_init, - .ops = &rk_aif1_ops, - /* set max98090 as slave */ - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - SND_SOC_DAILINK_REG(hifi), +SND_SOC_DAILINK_DEFS(analog, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(hdmi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +enum { + DAILINK_MAX98090, + DAILINK_HDMI, +}; + +/* max98090 dai_link */ +static struct snd_soc_dai_link rk_max98090_dailinks[] = { + { + .name = "max98090", + .stream_name = "Analog", + .init = rk_init, + .ops = &rk_aif1_ops, + /* set max98090 as slave */ + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(analog), + }, +}; + +/* HDMI codec dai_link */ +static struct snd_soc_dai_link rk_hdmi_dailinks[] = { + { + .name = "HDMI", + .stream_name = "HDMI", + .ops = &rk_aif1_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(hdmi), + } +}; + +/* max98090 and HDMI codec dai_link */ +static struct snd_soc_dai_link rk_max98090_hdmi_dailinks[] = { + [DAILINK_MAX98090] = { + .name = "max98090", + .stream_name = "Analog", + .init = rk_init, + .ops = &rk_aif1_ops, + /* set max98090 as slave */ + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(analog), + }, + [DAILINK_HDMI] = { + .name = "HDMI", + .stream_name = "HDMI", + .ops = &rk_aif1_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(hdmi), + } }; static int rk_98090_headset_init(struct snd_soc_component *component); @@ -175,19 +273,47 @@ static struct snd_soc_aux_dev rk_98090_headset_dev = { .init = rk_98090_headset_init, }; -static struct snd_soc_card snd_soc_card_rk = { +static struct snd_soc_card rockchip_max98090_card = { .name = "ROCKCHIP-I2S", .owner = THIS_MODULE, - .dai_link = &rk_dailink, - .num_links = 1, + .dai_link = rk_max98090_dailinks, + .num_links = ARRAY_SIZE(rk_max98090_dailinks), .aux_dev = &rk_98090_headset_dev, .num_aux_devs = 1, - .dapm_widgets = rk_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets), - .dapm_routes = rk_audio_map, - .num_dapm_routes = ARRAY_SIZE(rk_audio_map), - .controls = rk_mc_controls, - .num_controls = ARRAY_SIZE(rk_mc_controls), + .dapm_widgets = rk_max98090_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk_max98090_dapm_widgets), + .dapm_routes = rk_max98090_audio_map, + .num_dapm_routes = ARRAY_SIZE(rk_max98090_audio_map), + .controls = rk_max98090_controls, + .num_controls = ARRAY_SIZE(rk_max98090_controls), +}; + +static struct snd_soc_card rockchip_hdmi_card = { + .name = "ROCKCHIP-HDMI", + .owner = THIS_MODULE, + .dai_link = rk_hdmi_dailinks, + .num_links = ARRAY_SIZE(rk_hdmi_dailinks), + .dapm_widgets = rk_hdmi_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk_hdmi_dapm_widgets), + .dapm_routes = rk_hdmi_audio_map, + .num_dapm_routes = ARRAY_SIZE(rk_hdmi_audio_map), + .controls = rk_hdmi_controls, + .num_controls = ARRAY_SIZE(rk_hdmi_controls), +}; + +static struct snd_soc_card rockchip_max98090_hdmi_card = { + .name = "ROCKCHIP-MAX98090-HDMI", + .owner = THIS_MODULE, + .dai_link = rk_max98090_hdmi_dailinks, + .num_links = ARRAY_SIZE(rk_max98090_hdmi_dailinks), + .aux_dev = &rk_98090_headset_dev, + .num_aux_devs = 1, + .dapm_widgets = rk_max98090_hdmi_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk_max98090_hdmi_dapm_widgets), + .dapm_routes = rk_max98090_hdmi_audio_map, + .num_dapm_routes = ARRAY_SIZE(rk_max98090_hdmi_audio_map), + .controls = rk_max98090_hdmi_controls, + .num_controls = ARRAY_SIZE(rk_max98090_hdmi_controls), }; static int rk_98090_headset_init(struct snd_soc_component *component) @@ -195,7 +321,7 @@ static int rk_98090_headset_init(struct snd_soc_component *component) int ret; /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(&snd_soc_card_rk, "Headset Jack", + ret = snd_soc_card_jack_new(component->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, @@ -210,41 +336,75 @@ static int rk_98090_headset_init(struct snd_soc_component *component) return ret; } +static int rk_parse_headset_from_of(struct device *dev, struct device_node *np) +{ + rk_98090_headset_dev.dlc.of_node = of_parse_phandle( + np, "rockchip,headset-codec", 0); + if (!rk_98090_headset_dev.dlc.of_node) { + dev_err(dev, + "Property 'rockchip,headset-codec' missing/invalid\n"); + return -EINVAL; + } + return 0; +} + static int snd_rk_mc_probe(struct platform_device *pdev) { int ret = 0; - struct snd_soc_card *card = &snd_soc_card_rk; + struct snd_soc_card *card; + struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; + struct device_node *np_cpu; + struct device_node *np_audio, *np_hdmi; - /* register the soc card */ - card->dev = &pdev->dev; + /* Parse DTS for I2S controller. */ + np_cpu = of_parse_phandle(np, "rockchip,i2s-controller", 0); - rk_dailink.codecs->of_node = of_parse_phandle(np, - "rockchip,audio-codec", 0); - if (!rk_dailink.codecs->of_node) { + if (!np_cpu) { dev_err(&pdev->dev, - "Property 'rockchip,audio-codec' missing or invalid\n"); + "Property 'rockchip,i2s-controller missing or invalid\n"); return -EINVAL; } - rk_dailink.cpus->of_node = of_parse_phandle(np, - "rockchip,i2s-controller", 0); - if (!rk_dailink.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'rockchip,i2s-controller' missing or invalid\n"); + /* + * Find the card to use based on the presences of audio codec + * and hdmi codec in device property. Set their of_node accordingly. + */ + np_audio = of_parse_phandle(np, "rockchip,audio-codec", 0); + np_hdmi = of_parse_phandle(np, "rockchip,hdmi-codec", 0); + if (np_audio && np_hdmi) { + card = &rockchip_max98090_hdmi_card; + card->dai_link[DAILINK_MAX98090].codecs->of_node = np_audio; + card->dai_link[DAILINK_HDMI].codecs->of_node = np_hdmi; + card->dai_link[DAILINK_MAX98090].cpus->of_node = np_cpu; + card->dai_link[DAILINK_MAX98090].platforms->of_node = np_cpu; + card->dai_link[DAILINK_HDMI].cpus->of_node = np_cpu; + card->dai_link[DAILINK_HDMI].platforms->of_node = np_cpu; + } else if (np_audio) { + card = &rockchip_max98090_card; + card->dai_link[0].codecs->of_node = np_audio; + card->dai_link[0].cpus->of_node = np_cpu; + card->dai_link[0].platforms->of_node = np_cpu; + } else if (np_hdmi) { + card = &rockchip_hdmi_card; + card->dai_link[0].codecs->of_node = np_hdmi; + card->dai_link[0].cpus->of_node = np_cpu; + card->dai_link[0].platforms->of_node = np_cpu; + } else { + dev_err(dev, "At least one of codecs should be specified\n"); return -EINVAL; } - rk_dailink.platforms->of_node = rk_dailink.cpus->of_node; + card->dev = dev; - rk_98090_headset_dev.dlc.of_node = of_parse_phandle(np, - "rockchip,headset-codec", 0); - if (!rk_98090_headset_dev.dlc.of_node) { - dev_err(&pdev->dev, - "Property 'rockchip,headset-codec' missing/invalid\n"); - return -EINVAL; + /* Parse headset detection codec. */ + if (np_audio) { + ret = rk_parse_headset_from_of(dev, np); + if (ret) + return ret; } + /* Parse card name. */ ret = snd_soc_of_parse_card_name(card, "rockchip,model"); if (ret) { dev_err(&pdev->dev, @@ -252,6 +412,7 @@ static int snd_rk_mc_probe(struct platform_device *pdev) return ret; } + /* register the soc card */ ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { dev_err(&pdev->dev, -- cgit From bf2f64ea6594066081b0d30b128fa4947e83e737 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Mon, 28 Oct 2019 15:19:28 +0800 Subject: ASoC: rockchip_max98090: Add HDMI jack support In machine driver, create a jack and let hdmi-codec report jack status. Signed-off-by: Cheng-Yi Chiang Link: https://lore.kernel.org/r/20191028071930.145899-5-cychiang@chromium.org Signed-off-by: Mark Brown --- sound/soc/rockchip/Kconfig | 3 ++- sound/soc/rockchip/rockchip_max98090.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index b43657e6e655..d610b553ea3b 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -40,9 +40,10 @@ config SND_SOC_ROCKCHIP_MAX98090 select SND_SOC_ROCKCHIP_I2S select SND_SOC_MAX98090 select SND_SOC_TS3A227E + select SND_SOC_HDMI_CODEC help Say Y or M here if you want to add support for SoC audio on Rockchip - boards using the MAX98090 codec, such as Veyron. + boards using the MAX98090 codec and HDMI codec, such as Veyron. config SND_SOC_ROCKCHIP_RT5645 tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec" diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index 50ef9b8e7ce4..5c2504a465f4 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -218,6 +219,25 @@ enum { DAILINK_HDMI, }; +static struct snd_soc_jack rk_hdmi_jack; + +static int rk_hdmi_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct snd_soc_component *component = runtime->codec_dai->component; + int ret; + + /* enable jack detection */ + ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT, + &rk_hdmi_jack, NULL, 0); + if (ret) { + dev_err(card->dev, "Can't new HDMI Jack %d\n", ret); + return ret; + } + + return hdmi_codec_set_jack_detect(component, &rk_hdmi_jack); +} + /* max98090 dai_link */ static struct snd_soc_dai_link rk_max98090_dailinks[] = { { @@ -237,6 +257,7 @@ static struct snd_soc_dai_link rk_hdmi_dailinks[] = { { .name = "HDMI", .stream_name = "HDMI", + .init = rk_hdmi_init, .ops = &rk_aif1_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -259,6 +280,7 @@ static struct snd_soc_dai_link rk_max98090_hdmi_dailinks[] = { [DAILINK_HDMI] = { .name = "HDMI", .stream_name = "HDMI", + .init = rk_hdmi_init, .ops = &rk_aif1_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, -- cgit From 2a2edfbbfee47947dd05f5860c66c0e80ee5e09d Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:09 +0200 Subject: ALSA: hda/hdmi - implement mst_no_extra_pcms flag To support the DP-MST multiple streams via single connector feature, the HDMI driver was extended with the concept of backup PCMs. See commit 9152085defb6 ("ALSA: hda - add DP MST audio support"). This implementation works fine with snd_hda_intel.c as PCM topology is fully managed within the single driver. When the HDA codec driver is used from ASoC components, the concept of backup PCMs no longer fits. For ASoC topologies, the physical HDMI converters are presented as backend DAIs and these should match with hardware capabilities. The ASoC topology may define arbitrary PCMs (i.e. frontend DAIs) and have processing elements before eventual routing to the HDMI BE DAIs. With backup PCMs, the link between FE and BE DAIs would become dynamic and change when monitors are (un)plugged. This would lead to modifying the topology every time hotplug events happen, which is not currently possible in ASoC and there does not seem to be any obvious benefits from this design. To overcome above problems and enable the HDMI driver to be used from ASoC, this patch adds a new mode (mst_no_extra_pcms flags) to patch_hdmi.c. In this mode, the codec driver does not assume the backup PCMs to be created. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/pci/hda/patch_hdmi.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index bca5de78e9ad..59aaee4a40fd 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2072,15 +2072,24 @@ static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) static int generic_hdmi_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int idx; + int idx, pcm_num; /* * for non-mst mode, pcm number is the same as before - * for DP MST mode, pcm number is (nid number + dev_num - 1) - * dev_num is the device entry number in a pin - * + * for DP MST mode without extra PCM, pcm number is same + * for DP MST mode with extra PCMs, pcm number is + * (nid number + dev_num - 1) + * dev_num is the device entry number in a pin */ - for (idx = 0; idx < spec->num_nids + spec->dev_num - 1; idx++) { + + if (codec->mst_no_extra_pcms) + pcm_num = spec->num_nids; + else + pcm_num = spec->num_nids + spec->dev_num - 1; + + codec_dbg(codec, "hdmi: pcm_num set to %d\n", pcm_num); + + for (idx = 0; idx < pcm_num; idx++) { struct hda_pcm *info; struct hda_pcm_stream *pstr; -- cgit From 608b8c36c37114289e3ea328783161f542fdf71d Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:10 +0200 Subject: ASoC: hdac_hda: add support for HDMI/DP as a HDA codec Handle all HDA codecs using same logic, including HDMI/DP. Call to snd_hda_codec_build_controls() is delayed for HDMI/DP HDA devices. This is needed to discover the PCM device numbers as defined in topology. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hda.c | 114 +++++++++++++++++++++++++++++++++++++++----- sound/soc/codecs/hdac_hda.h | 13 ++++- 2 files changed, 114 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 91242b6f8ea7..298761a26180 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -14,13 +14,11 @@ #include #include #include +#include #include #include -#include "hdac_hda.h" -#define HDAC_ANALOG_DAI_ID 0 -#define HDAC_DIGITAL_DAI_ID 1 -#define HDAC_ALT_ANALOG_DAI_ID 2 +#include "hdac_hda.h" #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_U8 | \ @@ -32,6 +30,11 @@ SNDRV_PCM_FMTBIT_U32_LE | \ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) +#define STUB_HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + static int hdac_hda_dai_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static void hdac_hda_dai_close(struct snd_pcm_substream *substream, @@ -121,7 +124,46 @@ static struct snd_soc_dai_driver hdac_hda_dais[] = { .formats = STUB_FORMATS, .sig_bits = 24, }, -} +}, +{ + .id = HDAC_HDMI_0_DAI_ID, + .name = "intel-hdmi-hifi1", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "hifi1", + .channels_min = 1, + .channels_max = 32, + .rates = STUB_HDMI_RATES, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, +{ + .id = HDAC_HDMI_1_DAI_ID, + .name = "intel-hdmi-hifi2", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "hifi2", + .channels_min = 1, + .channels_max = 32, + .rates = STUB_HDMI_RATES, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, +{ + .id = HDAC_HDMI_2_DAI_ID, + .name = "intel-hdmi-hifi3", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "hifi3", + .channels_min = 1, + .channels_max = 32, + .rates = STUB_HDMI_RATES, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, }; @@ -135,10 +177,11 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, hda_pvt = snd_soc_component_get_drvdata(component); pcm = &hda_pvt->pcm[dai->id]; + if (tx_mask) - pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; + pcm->stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; else - pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; + pcm->stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; return 0; } @@ -278,6 +321,12 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, struct hda_pcm *cpcm; const char *pcm_name; + /* + * map DAI ID to the closest matching PCM name, using the naming + * scheme used by hda-codec snd_hda_gen_build_pcms() and for + * HDMI in hda_codec patch_hdmi.c) + */ + switch (dai->id) { case HDAC_ANALOG_DAI_ID: pcm_name = "Analog"; @@ -288,13 +337,22 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, case HDAC_ALT_ANALOG_DAI_ID: pcm_name = "Alt Analog"; break; + case HDAC_HDMI_0_DAI_ID: + pcm_name = "HDMI 0"; + break; + case HDAC_HDMI_1_DAI_ID: + pcm_name = "HDMI 1"; + break; + case HDAC_HDMI_2_DAI_ID: + pcm_name = "HDMI 2"; + break; default: dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id); return NULL; } list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) { - if (strpbrk(cpcm->name, pcm_name)) + if (strstr(cpcm->name, pcm_name)) return cpcm; } @@ -302,6 +360,18 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, return NULL; } +static bool is_hdmi_codec(struct hda_codec *hcodec) +{ + struct hda_pcm *cpcm; + + list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) { + if (cpcm->pcm_type == HDA_PCM_TYPE_HDMI) + return true; + } + + return false; +} + static int hdac_hda_codec_probe(struct snd_soc_component *component) { struct hdac_hda_priv *hda_pvt = @@ -322,6 +392,15 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) snd_hdac_ext_bus_link_get(hdev->bus, hlink); + /* + * Ensure any HDA display is powered at codec probe. + * After snd_hda_codec_device_new(), display power is + * managed by runtime PM. + */ + if (hda_pvt->need_display_power) + snd_hdac_display_power(hdev->bus, + HDA_CODEC_IDX_CONTROLLER, true); + ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card, hdev->addr, hcodec); if (ret < 0) { @@ -366,20 +445,31 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) dev_dbg(&hdev->dev, "no patch file found\n"); } + /* configure codec for 1:1 PCM:DAI mapping */ + hcodec->mst_no_extra_pcms = 1; + ret = snd_hda_codec_parse_pcms(hcodec); if (ret < 0) { dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); goto error; } - ret = snd_hda_codec_build_controls(hcodec); - if (ret < 0) { - dev_err(&hdev->dev, "unable to create controls %d\n", ret); - goto error; + /* HDMI controls need to be created in machine drivers */ + if (!is_hdmi_codec(hcodec)) { + ret = snd_hda_codec_build_controls(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to create controls %d\n", + ret); + goto error; + } } hcodec->core.lazy_cache = true; + if (hda_pvt->need_display_power) + snd_hdac_display_power(hdev->bus, + HDA_CODEC_IDX_CONTROLLER, false); + /* * hdac_device core already sets the state to active and calls * get_noresume. So enable runtime and set the device to suspend. diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h index 6b1bd4f428e7..e145cec085b8 100644 --- a/sound/soc/codecs/hdac_hda.h +++ b/sound/soc/codecs/hdac_hda.h @@ -6,6 +6,16 @@ #ifndef __HDAC_HDA_H__ #define __HDAC_HDA_H__ +enum { + HDAC_ANALOG_DAI_ID = 0, + HDAC_DIGITAL_DAI_ID, + HDAC_ALT_ANALOG_DAI_ID, + HDAC_HDMI_0_DAI_ID, + HDAC_HDMI_1_DAI_ID, + HDAC_HDMI_2_DAI_ID, + HDAC_LAST_DAI_ID = HDAC_HDMI_2_DAI_ID, +}; + struct hdac_hda_pcm { int stream_tag[2]; unsigned int format_val[2]; @@ -13,7 +23,8 @@ struct hdac_hda_pcm { struct hdac_hda_priv { struct hda_codec codec; - struct hdac_hda_pcm pcm[2]; + struct hdac_hda_pcm pcm[HDAC_LAST_DAI_ID]; + bool need_display_power; }; #define hdac_to_hda_priv(_hdac) \ -- cgit From 7de9a47c8971bdec07cc9a62e948382003c5908f Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:11 +0200 Subject: ASoC: Intel: skl-hda-dsp-generic: use snd-hda-codec-hdmi Add support for using snd-hda-codec-hdmi driver for HDMI/DP instead of ASoC hdac-hdmi. This is aligned with how other HDA codecs are already handled. When snd-hda-codec-hdmi is used, the PCM device numbers are parsed from card topology and passed to the codec driver. This needs to be done at runtime as topology changes may affect PCM device allocation. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/hda_dsp_common.c | 85 ++++++++++++++++++++++++++++ sound/soc/intel/boards/hda_dsp_common.h | 32 +++++++++++ sound/soc/intel/boards/skl_hda_dsp_common.c | 6 ++ sound/soc/intel/boards/skl_hda_dsp_common.h | 23 ++++++++ sound/soc/intel/boards/skl_hda_dsp_generic.c | 1 + 6 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/boards/hda_dsp_common.c create mode 100644 sound/soc/intel/boards/hda_dsp_common.h (limited to 'sound') diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 6445f90ea542..52e990b16b0d 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -24,7 +24,7 @@ snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-kbl_rt5660-objs := kbl_rt5660.o snd-soc-skl_rt286-objs := skl_rt286.o -snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o +snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c new file mode 100644 index 000000000000..ed36b68d6705 --- /dev/null +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include "../../codecs/hdac_hda.h" + +#include "hda_dsp_common.h" + +/* + * Search card topology and return PCM device number + * matching Nth HDMI device (zero-based index). + */ +struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, + int hdmi_idx) +{ + struct snd_soc_pcm_runtime *rtd; + struct snd_pcm *spcm; + int i = 0; + + for_each_card_rtds(card, rtd) { + spcm = rtd->pcm ? + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].pcm : NULL; + if (spcm && strstr(spcm->id, "HDMI")) { + if (i == hdmi_idx) + return rtd->pcm; + ++i; + } + } + + return NULL; +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +/* + * Search card topology and register HDMI PCM related controls + * to codec driver. + */ +int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, + struct snd_soc_component *comp) +{ + struct hdac_hda_priv *hda_pvt; + struct hda_codec *hcodec; + struct snd_pcm *spcm; + struct hda_pcm *hpcm; + int err = 0, i = 0; + + if (!comp) + return -EINVAL; + + hda_pvt = snd_soc_component_get_drvdata(comp); + hcodec = &hda_pvt->codec; + + list_for_each_entry(hpcm, &hcodec->pcm_list_head, list) { + spcm = hda_dsp_hdmi_pcm_handle(card, i); + if (spcm) { + hpcm->pcm = spcm; + hpcm->device = spcm->device; + dev_dbg(card->dev, + "%s: mapping HDMI converter %d to PCM %d (%p)\n", + __func__, i, hpcm->device, spcm); + } else { + hpcm->pcm = 0; + hpcm->device = SNDRV_PCM_INVALID_DEVICE; + dev_warn(card->dev, + "%s: no PCM in topology for HDMI converter %d\n\n", + __func__, i); + } + i++; + } + snd_hdac_display_power(hcodec->core.bus, + HDA_CODEC_IDX_CONTROLLER, true); + err = snd_hda_codec_build_controls(hcodec); + if (err < 0) + dev_err(card->dev, "unable to create controls %d\n", err); + snd_hdac_display_power(hcodec->core.bus, + HDA_CODEC_IDX_CONTROLLER, false); + + return err; +} + +#endif diff --git a/sound/soc/intel/boards/hda_dsp_common.h b/sound/soc/intel/boards/hda_dsp_common.h new file mode 100644 index 000000000000..431f7f09dccb --- /dev/null +++ b/sound/soc/intel/boards/hda_dsp_common.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2019 Intel Corporation. + */ + +/* + * This file defines helper functions used by multiple + * Intel HDA based machine drivers. + */ + +#ifndef __HDA_DSP_COMMON_H +#define __HDA_DSP_COMMON_H + +#include +#include +#include "../../codecs/hdac_hda.h" + +struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, + int hdmi_idx); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, + struct snd_soc_component *comp); +#else +static inline int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, + struct snd_soc_component *comp) +{ + return -EINVAL; +} +#endif + +#endif /* __HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index 58409b6e476e..eb419e1ec42b 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -14,6 +14,9 @@ #include "../../codecs/hdac_hdmi.h" #include "skl_hda_dsp_common.h" +#include +#include "../../codecs/hdac_hda.h" + #define NAME_SIZE 32 int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device) @@ -136,6 +139,9 @@ int skl_hda_hdmi_jack_init(struct snd_soc_card *card) char jack_name[NAME_SIZE]; int err; + if (ctx->common_hdmi_codec_drv) + return skl_hda_hdmi_build_controls(card); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h index daa582e513b2..bbe6e2acfda3 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -14,6 +14,9 @@ #include #include #include +#include +#include "../../codecs/hdac_hda.h" +#include "hda_dsp_common.h" #define HDA_DSP_MAX_BE_DAI_LINKS 7 @@ -29,10 +32,30 @@ struct skl_hda_private { int pcm_count; int dai_index; const char *platform_name; + bool common_hdmi_codec_drv; }; extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS]; int skl_hda_hdmi_jack_init(struct snd_soc_card *card); int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device); +/* + * Search card topology and register HDMI PCM related controls + * to codec driver. + */ +static inline int skl_hda_hdmi_build_controls(struct snd_soc_card *card) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + struct skl_hda_hdmi_pcm *pcm; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct skl_hda_hdmi_pcm, + head); + component = pcm->codec_dai->component; + if (!component) + return -EINVAL; + + return hda_dsp_hdmi_build_controls(card, component); +} + #endif /* __SOUND_SOC_HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index e8d676c192f6..4e45901e3a2f 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -178,6 +178,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) ctx->pcm_count = hda_soc_card.num_links; ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ ctx->platform_name = mach->mach_params.platform; + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; hda_soc_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&hda_soc_card, ctx); -- cgit From 0f163110256ac91aee562da149838fcb8a39d518 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:12 +0200 Subject: ASoC: Intel: skl-hda-dsp-generic: fix include guard name Match the include guard define to actual filename. The source directory now has an actual hda_dsp_common.h header, so the old include guard may cause confusion. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-5-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_hda_dsp_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h index bbe6e2acfda3..d6150670ca05 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -8,8 +8,8 @@ * platforms with HDA Codecs. */ -#ifndef __SOUND_SOC_HDA_DSP_COMMON_H -#define __SOUND_SOC_HDA_DSP_COMMON_H +#ifndef __SKL_HDA_DSP_COMMON_H +#define __SKL_HDA_DSP_COMMON_H #include #include #include -- cgit From 139c7febad1afa221c687f3314560284e482a1f4 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:13 +0200 Subject: ASoC: SOF: Intel: add support for snd-hda-codec-hdmi Add support to implement HDMI/DP audio by using the common snd-hda-codec-hdmi driver. Change of codec driver affects user-space as the two drivers expose different mixer controls. A new kernel module option "use_common_hdmi" is added to user-space to indicate which interface should be used. The default driver can be selected via a Kconfig option. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-6-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 10 ++++++++++ sound/soc/sof/intel/hda-codec.c | 22 ++++++++++++++++++---- sound/soc/sof/intel/hda.c | 6 ++++++ sound/soc/sof/intel/hda.h | 6 ++++-- 4 files changed, 38 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 342f22a7c64f..d52298946c00 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -299,6 +299,16 @@ config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1 Say Y if you want to enable DMI Link L1 If unsure, select "N". +config SND_SOC_SOF_HDA_COMMON_HDMI_CODEC + bool "SOF common HDA HDMI codec driver" + depends on SND_SOC_SOF_HDA_LINK + depends on SND_HDA_CODEC_HDMI + help + This adds support for HDMI audio by using the common HDA + HDMI/DisplayPort codec driver. + Say Y if you want to use the common codec driver with SOF. + If unsure select "Y". + endif ## SND_SOC_SOF_HDA_COMMON config SND_SOC_SOF_HDA_LINK_BASELINE diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 3ca6795a89ba..827f84a0722e 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -84,6 +84,8 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hdac_hda_priv *hda_priv; + struct snd_soc_acpi_mach_params *mach_params = NULL; + struct snd_sof_pdata *pdata = sdev->pdata; #endif struct hda_bus *hbus = sof_to_hbus(sdev); struct hdac_device *hdev; @@ -113,8 +115,19 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) if (ret < 0) return ret; - /* use legacy bus only for HDA codecs, idisp uses ext bus */ - if ((resp & 0xFFFF0000) != IDISP_VID_INTEL) { + if (pdata->machine) + mach_params = (struct snd_soc_acpi_mach_params *) + &pdata->machine->mach_params; + + if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) + hda_priv->need_display_power = true; + + /* + * if common HDMI codec driver is not used, codec load + * is skipped here and hdac_hdmi is used instead + */ + if ((mach_params && mach_params->common_hdmi_codec_drv) || + (resp & 0xFFFF0000) != IDISP_VID_INTEL) { hdev->type = HDA_DEV_LEGACY; hda_codec_load_module(&hda_priv->codec); } @@ -155,7 +168,8 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev) } EXPORT_SYMBOL(hda_codec_probe_bus); -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \ + IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) void hda_codec_i915_get(struct snd_sof_dev *sdev) { @@ -204,6 +218,6 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev) } EXPORT_SYMBOL(hda_codec_i915_exit); -#endif /* CONFIG_SND_SOC_HDAC_HDMI */ +#endif MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 103f4273c4d3..7dc0018dc4c3 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -53,6 +53,11 @@ MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode"); static int hda_dmic_num = -1; module_param_named(dmic_num, hda_dmic_num, int, 0444); MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number"); + +static bool hda_codec_use_common_hdmi = + IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_COMMON_HDMI_CODEC); +module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444); +MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver"); #endif static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { @@ -459,6 +464,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) &pdata->machine->mach_params; mach_params->codec_mask = bus->codec_mask; mach_params->platform = dev_name(sdev->dev); + mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi; } /* create codec instances */ diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 16376f55e420..5ad73a34b09c 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -577,7 +577,9 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev); #endif /* CONFIG_SND_SOC_SOF_HDA */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && \ + (IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \ + IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) void hda_codec_i915_get(struct snd_sof_dev *sdev); void hda_codec_i915_put(struct snd_sof_dev *sdev); @@ -591,7 +593,7 @@ static inline void hda_codec_i915_put(struct snd_sof_dev *sdev) { } static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; } static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; } -#endif /* CONFIG_SND_SOC_SOF_HDA && CONFIG_SND_SOC_HDAC_HDMI */ +#endif /* * Trace Control. -- cgit From 57ad18906f24278893b128967551fe7fa0996129 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:14 +0200 Subject: ASoC: Intel: bxt-da7219-max98357a: common hdmi codec support Add support for using snd-hda-codec-hdmi driver for HDMI/DP instead of ASoC hdac-hdmi. This is aligned with how other HDA codecs are already handled. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-7-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/bxt_da7219_max98357a.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 52e990b16b0d..0cf4a984f083 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -4,7 +4,7 @@ snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o snd-soc-sst-broadwell-objs := broadwell.o -snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o +snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o hda_dsp_common.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index ac1dea5f9d11..5873abb46441 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -21,6 +21,7 @@ #include "../../codecs/da7219.h" #include "../../codecs/da7219-aad.h" #include "../common/soc-intel-quirks.h" +#include "hda_dsp_common.h" #define BXT_DIALOG_CODEC_DAI "da7219-hifi" #define BXT_MAXIM_CODEC_DAI "HiFi" @@ -38,6 +39,7 @@ struct bxt_hdmi_pcm { struct bxt_card_private { struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; }; enum { @@ -615,6 +617,13 @@ static int bxt_card_late_probe(struct snd_soc_card *card) snd_soc_dapm_add_routes(&card->dapm, broxton_map, ARRAY_SIZE(broxton_map)); + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -720,6 +729,8 @@ static int broxton_audio_probe(struct platform_device *pdev) if (ret) return ret; + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } -- cgit From dfe87aa86cd92d21603d64f4035fecae19c92e7a Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:15 +0200 Subject: ASoC: Intel: glk_rt5682_max98357a: common hdmi codec support Add support for using snd-hda-codec-hdmi driver for HDMI/DP instead of ASoC hdac-hdmi. This is aligned with how other HDA codecs are already handled. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-8-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/glk_rt5682_max98357a.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 0cf4a984f083..b36f44906c91 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -6,7 +6,7 @@ snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o hda_dsp_common.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o -snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o +snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o hda_dsp_common.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index bd2d371f2acd..b36264d1d1cd 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -19,6 +19,7 @@ #include #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" +#include "hda_dsp_common.h" /* The platform clock outputs 19.2Mhz clock to codec as I2S MCLK */ #define GLK_PLAT_CLK_FREQ 19200000 @@ -41,6 +42,7 @@ struct glk_hdmi_pcm { struct glk_card_private { struct snd_soc_jack geminilake_headset; struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; }; enum { @@ -545,6 +547,13 @@ static int glk_card_late_probe(struct snd_soc_card *card) int err = 0; int i = 0; + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct glk_hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -612,6 +621,8 @@ static int geminilake_audio_probe(struct platform_device *pdev) if (ret) return ret; + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + return devm_snd_soc_register_card(&pdev->dev, card); } -- cgit From 59bbd703ea2eae7c2766713135e4742c07fbbad7 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:16 +0200 Subject: ASoC: intel: sof_rt5682: common hdmi codec support Add support for using snd-hda-codec-hdmi driver for HDMI/DP instead of ASoC hdac-hdmi. This is aligned with how other HDA codecs are already handled. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-9-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/sof_rt5682.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index b36f44906c91..255cee8c7906 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -17,7 +17,7 @@ snd-soc-sst-byt-cht-cx2072x-objs := bytcht_cx2072x.o snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o -snd-soc-sof_rt5682-objs := sof_rt5682.o +snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 2caebc77fdb5..6164d54fc992 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -21,6 +21,7 @@ #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" #include "../common/soc-intel-quirks.h" +#include "hda_dsp_common.h" #define NAME_SIZE 32 @@ -53,6 +54,7 @@ struct sof_card_private { struct clk *mclk; struct snd_soc_jack sof_headset; struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; }; static int sof_rt5682_quirk_cb(const struct dmi_system_id *id) @@ -274,6 +276,13 @@ static int sof_card_late_probe(struct snd_soc_card *card) if (is_legacy_cpu) return 0; + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -642,6 +651,8 @@ static int sof_audio_probe(struct platform_device *pdev) if (ret) return ret; + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx); return devm_snd_soc_register_card(&pdev->dev, -- cgit From 7d2ae58376658a3ca0d8f9a53f6f065df126c432 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:17 +0200 Subject: ASoC: Intel: bxt_rt298: common hdmi codec support Add support for using snd-hda-codec-hdmi driver for HDMI/DP instead of ASoC hdac-hdmi. This is aligned with how other HDA codecs are already handled. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-10-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/bxt_rt298.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 255cee8c7906..8bddf379cef1 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -5,7 +5,7 @@ snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o hda_dsp_common.o -snd-soc-sst-bxt-rt298-objs := bxt_rt298.o +snd-soc-sst-bxt-rt298-objs := bxt_rt298.o hda_dsp_common.o snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o hda_dsp_common.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index adf416a49b48..eabf9d8468ae 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -18,6 +18,7 @@ #include #include "../../codecs/hdac_hdmi.h" #include "../../codecs/rt298.h" +#include "hda_dsp_common.h" /* Headset jack detection DAPM pins */ static struct snd_soc_jack broxton_headset; @@ -31,6 +32,7 @@ struct bxt_hdmi_pcm { struct bxt_rt286_private { struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; }; enum { @@ -527,6 +529,13 @@ static int bxt_card_late_probe(struct snd_soc_card *card) int err, i = 0; char jack_name[NAME_SIZE]; + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -626,6 +635,8 @@ static int broxton_audio_probe(struct platform_device *pdev) if (ret) return ret; + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + return devm_snd_soc_register_card(&pdev->dev, card); } -- cgit From 1d4961d9eb1aaa498dfb44779b7e4b95d79112d0 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Tue, 29 Oct 2019 23:22:00 +0530 Subject: ALSA: usb-audio: sound: usb: usb true/false for bool return type Use true/false for bool type return in uac_clock_source_is_valid(). Signed-off-by: Saurav Girepunje Link: https://lore.kernel.org/r/20191029175200.GA7320@saurav Signed-off-by: Takashi Iwai --- sound/usb/clock.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 6b8c14f9b5d4..018b1ecb5404 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -165,21 +165,21 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id); if (!cs_desc) - return 0; + return false; bmControls = le32_to_cpu(cs_desc->bmControls); } else { /* UAC_VERSION_1/2 */ struct uac_clock_source_descriptor *cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, source_id); if (!cs_desc) - return 0; + return false; bmControls = cs_desc->bmControls; } /* If a clock source can't tell us whether it's valid, we assume it is */ if (!uac_v2v3_control_is_readable(bmControls, UAC2_CS_CONTROL_CLOCK_VALID)) - return 1; + return true; err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, @@ -191,10 +191,10 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, dev_warn(&dev->dev, "%s(): cannot get clock validity for id %d\n", __func__, source_id); - return 0; + return false; } - return !!data; + return data ? true : false; } static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, -- cgit From 2644df63c709e107c1882be95d802adea284dbf5 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 30 Oct 2019 17:06:39 +0900 Subject: ALSA: firewire-motu: fix wrong spelling for macro Just replace 'SEPARETED' with 'SEPARATED' for macro. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191030080644.1704-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-protocol-v2.c | 2 +- sound/firewire/motu/motu-protocol-v3.c | 2 +- sound/firewire/motu/motu.c | 8 ++++---- sound/firewire/motu/motu.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c index 9e2f16eebe0a..a42f77fc3858 100644 --- a/sound/firewire/motu/motu-protocol-v2.c +++ b/sound/firewire/motu/motu-protocol-v2.c @@ -191,7 +191,7 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats, pcm_chunks[1] += 2; } } else { - if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) { + if (flags & SND_MOTU_SPEC_RX_SEPARATED_MAIN) { pcm_chunks[0] += 2; pcm_chunks[1] += 2; } diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c index 5eafa506e8a9..ba5794c724be 100644 --- a/sound/firewire/motu/motu-protocol-v3.c +++ b/sound/firewire/motu/motu-protocol-v3.c @@ -187,7 +187,7 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats, pcm_chunks[1] += 2; } } else { - if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) { + if (flags & SND_MOTU_SPEC_RX_SEPARATED_MAIN) { pcm_chunks[0] += 2; pcm_chunks[1] += 2; } diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 72908b4de77c..680e363d0a4b 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -178,7 +178,7 @@ static const struct snd_motu_spec motu_828mk2 = { .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | SND_MOTU_SPEC_TX_MICINST_CHUNK | SND_MOTU_SPEC_TX_RETURN_CHUNK | - SND_MOTU_SPEC_RX_SEPARETED_MAIN | + SND_MOTU_SPEC_RX_SEPARATED_MAIN | SND_MOTU_SPEC_HAS_OPT_IFACE_A | SND_MOTU_SPEC_RX_MIDI_2ND_Q | SND_MOTU_SPEC_TX_MIDI_2ND_Q, @@ -224,7 +224,7 @@ static const struct snd_motu_spec motu_828mk3 = { SND_MOTU_SPEC_TX_MICINST_CHUNK | SND_MOTU_SPEC_TX_RETURN_CHUNK | SND_MOTU_SPEC_TX_REVERB_CHUNK | - SND_MOTU_SPEC_RX_SEPARETED_MAIN | + SND_MOTU_SPEC_RX_SEPARATED_MAIN | SND_MOTU_SPEC_HAS_OPT_IFACE_A | SND_MOTU_SPEC_HAS_OPT_IFACE_B | SND_MOTU_SPEC_RX_MIDI_3RD_Q | @@ -240,7 +240,7 @@ static const struct snd_motu_spec motu_audio_express = { .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | SND_MOTU_SPEC_TX_MICINST_CHUNK | SND_MOTU_SPEC_TX_RETURN_CHUNK | - SND_MOTU_SPEC_RX_SEPARETED_MAIN | + SND_MOTU_SPEC_RX_SEPARATED_MAIN | SND_MOTU_SPEC_RX_MIDI_2ND_Q | SND_MOTU_SPEC_TX_MIDI_3RD_Q, .analog_in_ports = 2, @@ -253,7 +253,7 @@ static const struct snd_motu_spec motu_4pre = { .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | SND_MOTU_SPEC_TX_MICINST_CHUNK | SND_MOTU_SPEC_TX_RETURN_CHUNK | - SND_MOTU_SPEC_RX_SEPARETED_MAIN, + SND_MOTU_SPEC_RX_SEPARATED_MAIN, .analog_in_ports = 2, .analog_out_ports = 2, }; diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index 35ed8b6bb8e8..08e3d568221d 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -86,7 +86,7 @@ enum snd_motu_spec_flags { SND_MOTU_SPEC_RX_MIDI_3RD_Q = 0x0200, SND_MOTU_SPEC_TX_MIDI_2ND_Q = 0x0400, SND_MOTU_SPEC_TX_MIDI_3RD_Q = 0x0800, - SND_MOTU_SPEC_RX_SEPARETED_MAIN = 0x1000, + SND_MOTU_SPEC_RX_SEPARATED_MAIN = 0x1000, }; #define SND_MOTU_CLOCK_RATE_COUNT 6 -- cgit From 1ef2ff941424bde4fd1d8dc97e0e600c5dc5472e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 30 Oct 2019 17:06:40 +0900 Subject: ALSA: firewire-motu: print for unknown source of sampling clock When unknown source is detected for sampling clock, corresponding label was not added for node on procfs. This commit adds it. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191030080644.1704-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-proc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/firewire/motu/motu-proc.c b/sound/firewire/motu/motu-proc.c index ea46fb4c1b5a..4e5767c0c8d7 100644 --- a/sound/firewire/motu/motu-proc.c +++ b/sound/firewire/motu/motu-proc.c @@ -19,6 +19,7 @@ static const char *const clock_names[] = { [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PCIF on coaxial interface", [SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR] = "AESEBU on XLR interface", [SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC] = "Word clock on BNC interface", + [SND_MOTU_CLOCK_SOURCE_UNKNOWN] = "Unknown", }; static void proc_read_clock(struct snd_info_entry *entry, -- cgit From 3f58f004bff3273d102583e0b2f478526cf9d3c8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 30 Oct 2019 17:06:41 +0900 Subject: ALSA: firewire-motu: detect SPH source of sampling clock In MOTU FireWire series, devices have a mode to generate sampling clock from a sequence of source packet header (SPH) included in each data block of received packet. This mode is used for several purposes such as mode for SMPTE time code, sync to the other sound cards and so on. This commit adds support for the SPH mode. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191030080644.1704-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-pcm.c | 3 ++- sound/firewire/motu/motu-proc.c | 1 + sound/firewire/motu/motu-protocol-v2.c | 3 +++ sound/firewire/motu/motu-protocol-v3.c | 2 ++ sound/firewire/motu/motu.h | 1 + 5 files changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 55d3d6661731..490408b49157 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -159,7 +159,8 @@ static int pcm_open(struct snd_pcm_substream *substream) // When source of clock is not internal or any stream is reserved for // transmission of PCM frames, the available sampling rate is limited // at current one. - if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL || + if ((src != SND_MOTU_CLOCK_SOURCE_INTERNAL && + src != SND_MOTU_CLOCK_SOURCE_SPH) || (motu->substreams_counter > 0 && d->events_per_period > 0)) { unsigned int frames_per_period = d->events_per_period; unsigned int frames_per_buffer = d->events_per_buffer; diff --git a/sound/firewire/motu/motu-proc.c b/sound/firewire/motu/motu-proc.c index 4e5767c0c8d7..b47ba818343f 100644 --- a/sound/firewire/motu/motu-proc.c +++ b/sound/firewire/motu/motu-proc.c @@ -19,6 +19,7 @@ static const char *const clock_names[] = { [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PCIF on coaxial interface", [SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR] = "AESEBU on XLR interface", [SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC] = "Word clock on BNC interface", + [SND_MOTU_CLOCK_SOURCE_SPH] = "Source packet header", [SND_MOTU_CLOCK_SOURCE_UNKNOWN] = "Unknown", }; diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c index a42f77fc3858..2757e5b42b9b 100644 --- a/sound/firewire/motu/motu-protocol-v2.c +++ b/sound/firewire/motu/motu-protocol-v2.c @@ -114,6 +114,9 @@ static int v2_get_clock_source(struct snd_motu *motu, case 2: *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; break; + case 3: + *src = SND_MOTU_CLOCK_SOURCE_SPH; + break; case 4: *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; break; diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c index ba5794c724be..d1545e2b5caa 100644 --- a/sound/firewire/motu/motu-protocol-v3.c +++ b/sound/firewire/motu/motu-protocol-v3.c @@ -104,6 +104,8 @@ static int v3_get_clock_source(struct snd_motu *motu, *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; } else if (val == 0x01) { *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; + } else if (val == 0x02) { + *src = SND_MOTU_CLOCK_SOURCE_SPH; } else if (val == 0x10) { *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; } else if (val == 0x18 || val == 0x19) { diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index 08e3d568221d..bd782ee4e763 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -104,6 +104,7 @@ enum snd_motu_clock_source { SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX, SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR, SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC, + SND_MOTU_CLOCK_SOURCE_SPH, SND_MOTU_CLOCK_SOURCE_UNKNOWN, }; -- cgit From 4b2079f80aa065b237955e75d0b627943656b0ab Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 30 Oct 2019 17:06:42 +0900 Subject: ALSA: firewire-motu: minor code refactoring for protocol version 2 This commit adds some helper functions to parse register value for source of sampling clock and nominal sampling transmission frequency. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191030080644.1704-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-protocol-v2.c | 65 ++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c index 2757e5b42b9b..cb0e58a9f33d 100644 --- a/sound/firewire/motu/motu-protocol-v2.c +++ b/sound/firewire/motu/motu-protocol-v2.c @@ -26,10 +26,20 @@ #define V2_OPT_IFACE_MODE_ADAT 1 #define V2_OPT_IFACE_MODE_SPDIF 2 +static int get_clock_rate(u32 data, unsigned int *rate) +{ + unsigned int index = (data & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT; + if (index >= ARRAY_SIZE(snd_motu_clock_rates)) + return -EIO; + + *rate = snd_motu_clock_rates[index]; + + return 0; +} + static int v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate) { __be32 reg; - unsigned int index; int err; err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, @@ -37,13 +47,7 @@ static int v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate) if (err < 0) return err; - index = (be32_to_cpu(reg) & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT; - if (index >= ARRAY_SIZE(snd_motu_clock_rates)) - return -EIO; - - *rate = snd_motu_clock_rates[index]; - - return 0; + return get_clock_rate(be32_to_cpu(reg), rate); } static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate) @@ -79,38 +83,33 @@ static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate) sizeof(reg)); } -static int v2_get_clock_source(struct snd_motu *motu, - enum snd_motu_clock_source *src) +static int get_clock_source(struct snd_motu *motu, u32 data, + enum snd_motu_clock_source *src) { - __be32 reg; - unsigned int index; - int err; - - err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, - sizeof(reg)); - if (err < 0) - return err; - - index = be32_to_cpu(reg) & V2_CLOCK_SRC_MASK; + unsigned int index = data & V2_CLOCK_SRC_MASK; if (index > 5) return -EIO; - /* To check the configuration of optical interface. */ - err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, ®, - sizeof(reg)); - if (err < 0) - return err; - switch (index) { case 0: *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; break; case 1: + { + __be32 reg; + + // To check the configuration of optical interface. + int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, + ®, sizeof(reg)); + if (err < 0) + return err; + if (be32_to_cpu(reg) & 0x00000200) *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT; else *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT; break; + } case 2: *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; break; @@ -130,6 +129,20 @@ static int v2_get_clock_source(struct snd_motu *motu, return 0; } +static int v2_get_clock_source(struct snd_motu *motu, + enum snd_motu_clock_source *src) +{ + __be32 reg; + int err; + + err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, + sizeof(reg)); + if (err < 0) + return err; + + return get_clock_source(motu, be32_to_cpu(reg), src); +} + static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable) { __be32 reg; -- cgit From bd1073728260e1d2f9589c928b6d8ddb14f5646f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 30 Oct 2019 17:06:43 +0900 Subject: ALSA: firewire-motu: code refactoring to handle model specific switch for protocol v2 In MOTU FireWire series, devices which support protocol version 2 have several types of hardware design to process audio data frames for isoc packet. Roughly devices are categorized into three groups: - 828mkII - Traveler/896HD - UltraLite/8pre FireWire Some bit flags in register addressed by 0x'ffff'f000'0b14 includes device-specific effects. This commit cleanups implementation of protocol v2 in this point. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191030080644.1704-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-protocol-v2.c | 72 +++++++++++++++++----------------- sound/firewire/motu/motu.c | 12 +++--- sound/firewire/motu/motu.h | 3 +- 3 files changed, 43 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c index cb0e58a9f33d..619b6ae73f62 100644 --- a/sound/firewire/motu/motu-protocol-v2.c +++ b/sound/firewire/motu/motu-protocol-v2.c @@ -12,10 +12,8 @@ #define V2_CLOCK_RATE_SHIFT 3 #define V2_CLOCK_SRC_MASK 0x00000007 #define V2_CLOCK_SRC_SHIFT 0 -#define V2_CLOCK_TRAVELER_FETCH_DISABLE 0x04000000 -#define V2_CLOCK_TRAVELER_FETCH_ENABLE 0x03000000 -#define V2_CLOCK_8PRE_FETCH_DISABLE 0x02000000 -#define V2_CLOCK_8PRE_FETCH_ENABLE 0x00000000 +#define V2_CLOCK_FETCH_ENABLE 0x02000000 +#define V2_CLOCK_MODEL_SPECIFIC 0x04000000 #define V2_IN_OUT_CONF_OFFSET 0x0c04 #define V2_OPT_OUT_IFACE_MASK 0x00000c00 @@ -73,11 +71,6 @@ static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate) data &= ~V2_CLOCK_RATE_MASK; data |= i << V2_CLOCK_RATE_SHIFT; - if (motu->spec == &snd_motu_spec_traveler) { - data &= ~V2_CLOCK_TRAVELER_FETCH_ENABLE; - data |= V2_CLOCK_TRAVELER_FETCH_DISABLE; - } - reg = cpu_to_be32(data); return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, ®, sizeof(reg)); @@ -145,42 +138,49 @@ static int v2_get_clock_source(struct snd_motu *motu, static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable) { + enum snd_motu_clock_source src; __be32 reg; u32 data; int err = 0; - if (motu->spec == &snd_motu_spec_traveler || - motu->spec == &snd_motu_spec_8pre) { - err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, - ®, sizeof(reg)); + // 828mkII implements Altera ACEX 1K EP1K30. Nothing to do. + if (motu->spec == &snd_motu_spec_828mk2) + return 0; + + err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, + sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg); + + err = get_clock_source(motu, data, &src); + if (err < 0) + return err; + + data &= ~(V2_CLOCK_FETCH_ENABLE | V2_CLOCK_MODEL_SPECIFIC); + if (enable) + data |= V2_CLOCK_FETCH_ENABLE; + + if (motu->spec->flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) { + // Expected for Traveler and 896HD, which implements Altera + // Cyclone EP1C3. + data |= V2_CLOCK_MODEL_SPECIFIC; + } else { + // For UltraLite and 8pre, which implements Xilinx Spartan + // XC3S200. + unsigned int rate; + + err = get_clock_rate(data, &rate); if (err < 0) return err; - data = be32_to_cpu(reg); - - if (motu->spec == &snd_motu_spec_traveler) { - data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE | - V2_CLOCK_TRAVELER_FETCH_ENABLE); - - if (enable) - data |= V2_CLOCK_TRAVELER_FETCH_ENABLE; - else - data |= V2_CLOCK_TRAVELER_FETCH_DISABLE; - } else if (motu->spec == &snd_motu_spec_8pre) { - data &= ~(V2_CLOCK_8PRE_FETCH_DISABLE | - V2_CLOCK_8PRE_FETCH_ENABLE); - - if (enable) - data |= V2_CLOCK_8PRE_FETCH_DISABLE; - else - data |= V2_CLOCK_8PRE_FETCH_ENABLE; - } - reg = cpu_to_be32(data); - err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, - ®, sizeof(reg)); + if (src == SND_MOTU_CLOCK_SOURCE_SPH && rate > 48000) + data |= V2_CLOCK_MODEL_SPECIFIC; } - return err; + reg = cpu_to_be32(data); + return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, ®, + sizeof(reg)); } static void calculate_fixed_part(struct snd_motu_packet_format *formats, diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 680e363d0a4b..f249ad39d8a8 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -172,7 +172,7 @@ static void motu_bus_update(struct fw_unit *unit) snd_motu_transaction_reregister(motu); } -static const struct snd_motu_spec motu_828mk2 = { +const struct snd_motu_spec snd_motu_spec_828mk2 = { .name = "828mk2", .protocol = &snd_motu_protocol_v2, .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | @@ -187,7 +187,7 @@ static const struct snd_motu_spec motu_828mk2 = { .analog_out_ports = 8, }; -const struct snd_motu_spec snd_motu_spec_traveler = { +static const struct snd_motu_spec motu_traveler = { .name = "Traveler", .protocol = &snd_motu_protocol_v2, .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | @@ -202,7 +202,7 @@ const struct snd_motu_spec snd_motu_spec_traveler = { .analog_out_ports = 8, }; -const struct snd_motu_spec snd_motu_spec_8pre = { +static const struct snd_motu_spec motu_8pre = { .name = "8pre", .protocol = &snd_motu_protocol_v2, // In tx, use coax chunks for mix-return 1/2. In rx, use coax chunks for @@ -270,9 +270,9 @@ static const struct snd_motu_spec motu_4pre = { } static const struct ieee1394_device_id motu_id_table[] = { - SND_MOTU_DEV_ENTRY(0x000003, &motu_828mk2), - SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler), - SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre), + SND_MOTU_DEV_ENTRY(0x000003, &snd_motu_spec_828mk2), + SND_MOTU_DEV_ENTRY(0x000009, &motu_traveler), + SND_MOTU_DEV_ENTRY(0x00000f, &motu_8pre), SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3), /* FireWire only. */ SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3), /* Hybrid. */ SND_MOTU_DEV_ENTRY(0x000033, &motu_audio_express), diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index bd782ee4e763..6efbde405a0d 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -130,8 +130,7 @@ struct snd_motu_spec { extern const struct snd_motu_protocol snd_motu_protocol_v2; extern const struct snd_motu_protocol snd_motu_protocol_v3; -extern const struct snd_motu_spec snd_motu_spec_traveler; -extern const struct snd_motu_spec snd_motu_spec_8pre; +extern const struct snd_motu_spec snd_motu_spec_828mk2; int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, -- cgit From 271e657f92ed94ced8a9fccf265b993650272a6b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 30 Oct 2019 17:06:44 +0900 Subject: ALSA: firewire-motu: add support for MOTU UltraLite UltraLite was shipped in 2005 by MOTU, and already discontinued. This model consists of below ICs: - Texus Instruments TSB41AB2 for physical layer of IEEE 1394 bus - Xilinx Spartan XC35S200 for link layer of IEEE 1394 bus, protocol layer and signal processing This commit adds support for this model. Like the other MOTU models, ALSA firewire MOTU driver fails to drive the device for stable sampling clock and generate noisy sound. $ python2 crpp < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 400 04107574 bus_info_length 4, crc_length 16, crc 30068 404 31333934 bus_name "1394" 408 20001000 irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 0, max_rec 1 (4) 40c 0001f200 company_id 0001f2 | 410 0007b82d device_id 000007b82d | EUI-64 0001f2000007b82d root directory ----------------------------------------------------------------- 414 0004c65c directory_length 4, crc 50780 418 030001f2 vendor 41c 0c0083c0 node capabilities per IEEE 1394 420 8d000006 --> eui-64 leaf at 438 424 d1000001 --> unit directory at 428 unit directory at 428 ----------------------------------------------------------------- 428 0003d80a directory_length 3, crc 55306 42c 120001f2 specifier id 430 1300000d version 434 17100800 model eui-64 leaf at 438 ----------------------------------------------------------------- 438 00024566 leaf_length 2, crc 17766 43c 0001f200 company_id 0001f2 | 440 0007b82d device_id 000007b82d | EUI-64 0001f2000007b82d Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191030080644.1704-7-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index f249ad39d8a8..f2080d720aa9 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -202,6 +202,19 @@ static const struct snd_motu_spec motu_traveler = { .analog_out_ports = 8, }; +static const struct snd_motu_spec motu_ultralite = { + .name = "UltraLite", + .protocol = &snd_motu_protocol_v2, + .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | + SND_MOTU_SPEC_TX_MICINST_CHUNK | // padding. + SND_MOTU_SPEC_TX_RETURN_CHUNK | + SND_MOTU_SPEC_RX_MIDI_2ND_Q | + SND_MOTU_SPEC_TX_MIDI_2ND_Q | + SND_MOTU_SPEC_RX_SEPARATED_MAIN, + .analog_in_ports = 8, + .analog_out_ports = 8, +}; + static const struct snd_motu_spec motu_8pre = { .name = "8pre", .protocol = &snd_motu_protocol_v2, @@ -272,6 +285,7 @@ static const struct snd_motu_spec motu_4pre = { static const struct ieee1394_device_id motu_id_table[] = { SND_MOTU_DEV_ENTRY(0x000003, &snd_motu_spec_828mk2), SND_MOTU_DEV_ENTRY(0x000009, &motu_traveler), + SND_MOTU_DEV_ENTRY(0x00000d, &motu_ultralite), SND_MOTU_DEV_ENTRY(0x00000f, &motu_8pre), SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3), /* FireWire only. */ SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3), /* Hybrid. */ -- cgit From 0929249e3be3bb82ee6cfec0025f4dde952210b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Oct 2019 11:09:21 +0100 Subject: ALSA: firewire-motu: Correct a typo in the clock proc string Just fix a typo of "S/PDIF" in the clock name string. Fixes: 4638ec6ede08 ("ALSA: firewire-motu: add proc node to show current statuc of clock and packet formats") Acked-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191030100921.3826-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-proc.c b/sound/firewire/motu/motu-proc.c index b47ba818343f..187f6abd878c 100644 --- a/sound/firewire/motu/motu-proc.c +++ b/sound/firewire/motu/motu-proc.c @@ -16,7 +16,7 @@ static const char *const clock_names[] = { [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT] = "S/PDIF on optical interface", [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A] = "S/PDIF on optical interface A", [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B] = "S/PDIF on optical interface B", - [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PCIF on coaxial interface", + [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PDIF on coaxial interface", [SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR] = "AESEBU on XLR interface", [SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC] = "Word clock on BNC interface", [SND_MOTU_CLOCK_SOURCE_SPH] = "Source packet header", -- cgit From d247568bb21b6665cc32dee8b0a9716d44bd11a7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 30 Oct 2019 15:14:58 +0900 Subject: ASoC: rt5677-spi: fixup compile warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixup this warning LINUX/sound/soc/codecs/rt5677-spi.c: In function ‘rt5677_spi_pcm_close’: LINUX/sound/soc/codecs/rt5677-spi.c:114:30: warning: unused variable ‘rtd’ [-Wunused-variable] struct snd_soc_pcm_runtime *rtd = substream->private_data; ^~~ Fixes: a0e0d135427c ("ASoC: rt5677: Add a PCM device for streaming hotword via SPI") Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a79idajh.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index dac1097bc740..3aa3ea7c2768 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -111,7 +111,6 @@ static int rt5677_spi_pcm_close( struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; struct rt5677_dsp *rt5677_dsp = snd_soc_component_get_drvdata(component); -- cgit From e9904ed5e73af4fd00cf4fcf705420a385af45da Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 30 Oct 2019 10:26:10 +0900 Subject: ASoC: soc-core: remove unneeded snd_soc_tplg_component_remove() snd_soc_tplg_component_remove() is pair of snd_soc_tplg_component_load(), and it is topology related cleanup function. The driver which called _load() needs to call _remove() by its responsibility. Today, skl-pcm and topology are the user, and these are calling both _load() and _remove(). soc-core doesn't need to call it. This patch remove it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8736fbdnwt.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f1b41b0391ed..b07ecfac39d7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2890,8 +2890,6 @@ static int __snd_soc_unregister_component(struct device *dev) if (dev != component->dev) continue; - snd_soc_tplg_component_remove(component, - SND_SOC_TPLG_INDEX_ALL); snd_soc_component_del_unlocked(component); found = 1; break; -- cgit From e226445802cb2a51c3cb127fac31fba0a4330e87 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 30 Oct 2019 16:55:33 +0800 Subject: ASoC: rt5682: improve the sensitivity of push button The sensitivity could improve by decreasing the HW debounce time and reduce the delay time of workequeue. This patch added a device property for HW debounce time control. We could change this value to tune the sensitivity of push button. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20191030085533.14299-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index c50b75ce82e0..35dcec135c8a 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -44,6 +44,7 @@ static const struct rt5682_platform_data i2s_default_platform_data = { .dmic1_data_pin = RT5682_DMIC1_DATA_GPIO2, .dmic1_clk_pin = RT5682_DMIC1_CLK_GPIO3, .jd_src = RT5682_JD1, + .btndet_delay = 16, }; struct rt5682_priv { @@ -1026,6 +1027,18 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, RT5682_JD1_EN_MASK | RT5682_JD1_POL_MASK, RT5682_JD1_EN | RT5682_JD1_POL_NOR); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_4, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_5, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_6, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_7, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); mod_delayed_work(system_power_efficient_wq, &rt5682->jack_detect_work, msecs_to_jiffies(250)); break; @@ -2467,6 +2480,8 @@ static int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev) &rt5682->pdata.dmic1_clk_pin); device_property_read_u32(dev, "realtek,jd-src", &rt5682->pdata.jd_src); + device_property_read_u32(dev, "realtek,btndet-delay", + &rt5682->pdata.btndet_delay); rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node, "realtek,ldo1-en-gpios", 0); -- cgit From b9a3eea38b1eb8dd96fce64a8480e8ee38ee1451 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 31 Oct 2019 19:54:01 +0800 Subject: ASoC: rt1011: remove redundant code in kcontrol The !component->card->instantiated statement should remove in kcontrol. It is no need to check the card->instantiated in kcontrol. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20191031115401.20898-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index dcd397a83cb4..8a74f374d779 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1163,9 +1163,6 @@ static int rt1011_bq_drc_coeff_put(struct snd_kcontrol *kcontrol, (struct rt1011_bq_drc_params *)ucontrol->value.integer.value; unsigned int i, mode_idx = 0; - if (!component->card->instantiated) - return 0; - if (strstr(ucontrol->id.name, "AdvanceMode Initial Set")) mode_idx = RT1011_ADVMODE_INITIAL_SET; else if (strstr(ucontrol->id.name, "AdvanceMode SEP BQ Coeff")) @@ -1236,9 +1233,6 @@ static int rt1011_r0_cali_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt1011_priv *rt1011 = snd_soc_component_get_drvdata(component); - if (!component->card->instantiated) - return 0; - rt1011->cali_done = 0; if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF && ucontrol->value.integer.value[0]) @@ -1284,9 +1278,6 @@ static int rt1011_r0_load_mode_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.integer.value[0] == rt1011->r0_reg) return 0; - if (!component->card->instantiated) - return 0; - if (ucontrol->value.integer.value[0] == 0) return -EINVAL; -- cgit From 5cf93491ff98cff0d2f9725e7c44e0bd38325697 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 31 Oct 2019 19:54:14 +0800 Subject: ASoC: rt1011: improve the rt1011_set_dai_fmt() function If there is a wrong format setting, the driver will goto the end of the function directly. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20191031115414.20951-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 8a74f374d779..57a3a34b5f18 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1631,6 +1631,7 @@ static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) break; default: ret = -EINVAL; + goto _set_fmt_err_; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -1641,6 +1642,7 @@ static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) break; default: ret = -EINVAL; + goto _set_fmt_err_; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -1657,6 +1659,7 @@ static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) break; default: ret = -EINVAL; + goto _set_fmt_err_; } switch (dai->id) { @@ -1674,6 +1677,7 @@ static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ret = -EINVAL; } +_set_fmt_err_: snd_soc_dapm_mutex_unlock(dapm); return ret; } -- cgit From 270d1b39b006a408e35278d4b64b2c4e1945adf0 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 31 Oct 2019 19:54:25 +0800 Subject: ASoC: rt1011: remove unnecessary tabs using spaces instead There are unnecessary tabs inside some statements. It uses sapces instead. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20191031115425.21003-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 57a3a34b5f18..2f1de933f3ac 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -989,7 +989,7 @@ static SOC_ENUM_SINGLE_DECL(rt1011_din_source_enum, RT1011_CROSS_BQ_SET_1, 5, static const char * const rt1011_tdm_data_out_select[] = { "TDM_O_LR", "BQ1", "DVOL", "BQ10", "ALC", "DMIX", "ADC_SRC_LR", - "ADC_O_LR", "ADC_MONO", "RSPK_BPF_LR", "DMIX_ADD", "ENVELOPE_FS", + "ADC_O_LR", "ADC_MONO", "RSPK_BPF_LR", "DMIX_ADD", "ENVELOPE_FS", "SEP_O_GAIN", "ALC_BK_GAIN", "STP_V_C", "DMIX_ABST" }; @@ -1002,7 +1002,7 @@ static SOC_ENUM_SINGLE_DECL(rt1011_tdm2_l_dac1_enum, RT1011_TDM2_SET_4, 12, rt1011_tdm_l_ch_data_select); static SOC_ENUM_SINGLE_DECL(rt1011_tdm1_adc1_dat_enum, - RT1011_ADCDAT_OUT_SOURCE, 0, rt1011_tdm_data_out_select); + RT1011_ADCDAT_OUT_SOURCE, 0, rt1011_tdm_data_out_select); static SOC_ENUM_SINGLE_DECL(rt1011_tdm1_adc1_loc_enum, RT1011_TDM1_SET_2, 0, rt1011_tdm_l_ch_data_select); @@ -1024,9 +1024,9 @@ static const char * const rt1011_tdm_adc_swap_select[] = { "L/R", "R/L", "L/L", "R/R" }; -static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc1_1_enum, RT1011_TDM1_SET_3, 6, +static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc1_1_enum, RT1011_TDM1_SET_3, 6, rt1011_tdm_adc_swap_select); -static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc2_1_enum, RT1011_TDM1_SET_3, 4, +static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc2_1_enum, RT1011_TDM1_SET_3, 4, rt1011_tdm_adc_swap_select); static void rt1011_reset(struct regmap *regmap) @@ -1092,9 +1092,9 @@ static bool rt1011_validate_bq_drc_coeff(unsigned short reg) { if ((reg == RT1011_DAC_SET_1) | (reg >= RT1011_ADC_SET && reg <= RT1011_ADC_SET_1) | - (reg == RT1011_ADC_SET_4) | (reg == RT1011_ADC_SET_5) | + (reg == RT1011_ADC_SET_4) | (reg == RT1011_ADC_SET_5) | (reg == RT1011_MIXER_1) | - (reg == RT1011_A_TIMING_1) | (reg >= RT1011_POWER_7 && + (reg == RT1011_A_TIMING_1) | (reg >= RT1011_POWER_7 && reg <= RT1011_POWER_8) | (reg == RT1011_CLASS_D_POS) | (reg == RT1011_ANALOG_CTRL) | (reg >= RT1011_SPK_TEMP_PROTECT_0 && @@ -1289,7 +1289,7 @@ static int rt1011_r0_load_mode_put(struct snd_kcontrol *kcontrol, r0_integer = format / rt1011->r0_reg / 128; r0_factor = ((format / rt1011->r0_reg * 100) / 128) - (r0_integer * 100); - dev_info(dev, "New r0 resistance about %d.%02d ohm, reg=0x%X\n", + dev_info(dev, "New r0 resistance about %d.%02d ohm, reg=0x%X\n", r0_integer, r0_factor, rt1011->r0_reg); if (rt1011->r0_reg) @@ -1977,14 +1977,14 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, snd_soc_component_update_bits(component, RT1011_TDM1_SET_1, RT1011_I2S_CH_TX_MASK | RT1011_I2S_CH_RX_MASK | - RT1011_I2S_CH_TX_LEN_MASK | RT1011_I2S_CH_RX_LEN_MASK, val); + RT1011_I2S_CH_TX_LEN_MASK | RT1011_I2S_CH_RX_LEN_MASK, val); snd_soc_component_update_bits(component, RT1011_TDM2_SET_1, RT1011_I2S_CH_TX_MASK | RT1011_I2S_CH_RX_MASK | - RT1011_I2S_CH_TX_LEN_MASK | RT1011_I2S_CH_RX_LEN_MASK, val); + RT1011_I2S_CH_TX_LEN_MASK | RT1011_I2S_CH_RX_LEN_MASK, val); snd_soc_component_update_bits(component, RT1011_TDM1_SET_2, - RT1011_TDM_I2S_DOCK_EN_1_MASK, tdm_en); + RT1011_TDM_I2S_DOCK_EN_1_MASK, tdm_en); snd_soc_component_update_bits(component, RT1011_TDM2_SET_2, - RT1011_TDM_I2S_DOCK_EN_2_MASK, tdm_en); + RT1011_TDM_I2S_DOCK_EN_2_MASK, tdm_en); if (tx_slotnum) snd_soc_component_update_bits(component, RT1011_TDM_TOTAL_SET, RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG, @@ -2109,7 +2109,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt1011 = { .remove = rt1011_remove, .suspend = rt1011_suspend, .resume = rt1011_resume, - .set_bias_level = rt1011_set_bias_level, + .set_bias_level = rt1011_set_bias_level, .controls = rt1011_snd_controls, .num_controls = ARRAY_SIZE(rt1011_snd_controls), .dapm_widgets = rt1011_dapm_widgets, @@ -2118,9 +2118,9 @@ static const struct snd_soc_component_driver soc_component_dev_rt1011 = { .num_dapm_routes = ARRAY_SIZE(rt1011_dapm_routes), .set_sysclk = rt1011_set_component_sysclk, .set_pll = rt1011_set_component_pll, - .use_pmdown_time = 1, - .endianness = 1, - .non_legacy_dai_naming = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1011_regmap = { @@ -2222,17 +2222,17 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag) dc_offset = value << 16; regmap_read(rt1011->regmap, RT1011_EFUSE_ADC_OFFSET_15_0, &value); dc_offset |= (value & 0xffff); - dev_info(dev, "ADC offset=0x%x\n", dc_offset); + dev_info(dev, "ADC offset=0x%x\n", dc_offset); regmap_read(rt1011->regmap, RT1011_EFUSE_DAC_OFFSET_G0_20_16, &value); dc_offset = value << 16; regmap_read(rt1011->regmap, RT1011_EFUSE_DAC_OFFSET_G0_15_0, &value); dc_offset |= (value & 0xffff); - dev_info(dev, "Gain0 offset=0x%x\n", dc_offset); + dev_info(dev, "Gain0 offset=0x%x\n", dc_offset); regmap_read(rt1011->regmap, RT1011_EFUSE_DAC_OFFSET_G1_20_16, &value); dc_offset = value << 16; regmap_read(rt1011->regmap, RT1011_EFUSE_DAC_OFFSET_G1_15_0, &value); dc_offset |= (value & 0xffff); - dev_info(dev, "Gain1 offset=0x%x\n", dc_offset); + dev_info(dev, "Gain1 offset=0x%x\n", dc_offset); if (cali_flag) { @@ -2252,7 +2252,7 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag) while (count < chk_cnt) { msleep(100); regmap_read(rt1011->regmap, - RT1011_INIT_RECIPROCAL_SYN_24_16, &value); + RT1011_INIT_RECIPROCAL_SYN_24_16, &value); r0[count%3] = value << 16; regmap_read(rt1011->regmap, RT1011_INIT_RECIPROCAL_SYN_15_0, &value); @@ -2267,7 +2267,7 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag) break; } if (count > chk_cnt) { - dev_err(dev, "Calibrate R0 Failure\n"); + dev_err(dev, "Calibrate R0 Failure\n"); ret = -EAGAIN; } else { format = 2147483648U; /* 2^24 * 128 */ @@ -2276,7 +2276,7 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag) - (r0_integer * 100); rt1011->r0_reg = r0[0]; rt1011->cali_done = 1; - dev_info(dev, "r0 resistance about %d.%02d ohm, reg=0x%X\n", + dev_info(dev, "r0 resistance about %d.%02d ohm, reg=0x%X\n", r0_integer, r0_factor, r0[0]); } } @@ -2354,7 +2354,7 @@ static void rt1011_calibration_work(struct work_struct *work) r0_integer = format / rt1011->r0_reg / 128; r0_factor = ((format / rt1011->r0_reg * 100) / 128) - (r0_integer * 100); - dev_info(component->dev, "DP r0 resistance about %d.%02d ohm, reg=0x%X\n", + dev_info(component->dev, "DP r0 resistance about %d.%02d ohm, reg=0x%X\n", r0_integer, r0_factor, rt1011->r0_reg); rt1011_r0_load(rt1011); @@ -2420,7 +2420,6 @@ static void rt1011_i2c_shutdown(struct i2c_client *client) rt1011_reset(rt1011->regmap); } - static struct i2c_driver rt1011_i2c_driver = { .driver = { .name = "rt1011", -- cgit From 98b6b8df06c7929de65ca3bf28a13b11170943e3 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 31 Oct 2019 19:54:36 +0800 Subject: ASoC: rt1011: add the range check for temperature_calib from device property The driver will check the range for temperature_calib. It should be from 1 to 255. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20191031115436.21055-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 2f1de933f3ac..f2c581b66d32 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2341,7 +2341,8 @@ static void rt1011_calibration_work(struct work_struct *work) rt1011_reg_init(component); /* Apply temperature and calibration data from device property */ - if (rt1011->temperature_calib) { + if (rt1011->temperature_calib <= 0xff && + rt1011->temperature_calib > 0) { snd_soc_component_update_bits(component, RT1011_STP_INITIAL_RESISTANCE_TEMP, 0x3ff, (rt1011->temperature_calib << 2)); -- cgit From 683b85152e3606f4d3145b99e2df4d6eaeb758d0 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 31 Oct 2019 19:54:46 +0800 Subject: ASoC: rt1011: some minor changes to improve readability There is no other code use the RT1011_INIT_REG_LEN definition, except rt1011_reg_init(). Hence, we remove it and fix the typo. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20191031115446.21108-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index f2c581b66d32..2552073e54ce 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -61,7 +61,6 @@ static const struct reg_sequence init_list[] = { { RT1011_DAC_SET_1, 0xe702 }, { RT1011_DAC_SET_3, 0x2004 }, }; -#define RT1011_INIT_REG_LEN ARRAY_SIZE(init_list) static const struct reg_default rt1011_reg[] = { {0x0000, 0x0000}, @@ -684,7 +683,8 @@ static int rt1011_reg_init(struct snd_soc_component *component) { struct rt1011_priv *rt1011 = snd_soc_component_get_drvdata(component); - regmap_multi_reg_write(rt1011->regmap, init_list, RT1011_INIT_REG_LEN); + regmap_multi_reg_write(rt1011->regmap, + init_list, ARRAY_SIZE(init_list)); return 0; } @@ -1773,7 +1773,8 @@ static int rt1011_set_component_pll(struct snd_soc_component *component, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", + freq_in); return ret; } @@ -2384,7 +2385,7 @@ static int rt1011_i2c_probe(struct i2c_client *i2c, rt1011 = devm_kzalloc(&i2c->dev, sizeof(struct rt1011_priv), GFP_KERNEL); - if (rt1011 == NULL) + if (!rt1011) return -ENOMEM; i2c_set_clientdata(i2c, rt1011); -- cgit From d3eabe939aee3ffd5b133766a932629a9746298c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 1 Nov 2019 22:13:21 +0900 Subject: ALSA: bebob: expand sleep just after breaking connections for protocol version 1 As long as I investigated, some devices with BeBoB protocol version 1 can be freezed during several hundreds milliseconds after breaking connections. When accessing during the freezed time, any transaction is corrupted. In the worst case, the device is going to reboot. I can see this issue in: * Roland FA-66 * M-Audio FireWire Solo This commit expands sleep just after breaking connections to avoid the freezed time as much as possible. I note that the freeze/reboot behaviour is similar to below models: * Focusrite Saffire Pro 10 I/O * Focusrite Saffire Pro 26 I/O The above models certainly reboot after breaking connections. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191101131323.17300-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_stream.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index f7f0db5aa811..1b264d0d63eb 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -415,15 +415,16 @@ static int make_both_connections(struct snd_bebob *bebob) return 0; } -static void -break_both_connections(struct snd_bebob *bebob) +static void break_both_connections(struct snd_bebob *bebob) { cmp_connection_break(&bebob->in_conn); cmp_connection_break(&bebob->out_conn); - /* These models seems to be in transition state for a longer time. */ - if (bebob->maudio_special_quirk != NULL) - msleep(200); + // These models seem to be in transition state for a longer time. When + // accessing in the state, any transactions is corrupted. In the worst + // case, the device is going to reboot. + if (bebob->version < 2) + msleep(600); } static int -- cgit From da5e83374f463a4dd91321428d5ea5230b6d87b4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 1 Nov 2019 22:13:22 +0900 Subject: ALSA: bebob: expand delay of start for IR context just for version 3 firmware As long as I investigated, there's some cases about the delay for device between establishing OUTPUT_PLUG and transmitting first isoc packet. For devices which support BeBoB protocol version 1 can transmit the packet within several hundred milliseconds, while for devices which support BeBoB protocol version 3 can transmit the packet within 2 seconds. Devices with protocol version 1: * Edirol FA-66 * Yamaha GO46 * Terratec Phase x24 FW * M-Audio FireWire AudioPhile * M-Audio FireWire Solo * M-Audio FireWire 1814 * M-Audio FireWire 410 * Focusrite Saffire Pro 26 I/O Devices with protocol version 3: * M-Audio Profire Lightbridge * Behringer FCA610 * Phonic Firefly 202 At present ALSA bebob driver postpones starting IR context during 1.5 sec for all of supported devices. The delay is too long for devices with protocol version 1, while it's not enough for devices with protocol version 3. This commit improves the delay for these protocols. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191101131323.17300-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_stream.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 1b264d0d63eb..895a113635af 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -7,7 +7,7 @@ #include "./bebob.h" -#define CALLBACK_TIMEOUT 2000 +#define CALLBACK_TIMEOUT 2500 #define FW_ISO_RESOURCE_DELAY 1000 /* @@ -639,6 +639,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) if (!amdtp_stream_running(&bebob->rx_stream)) { unsigned int curr_rate; + unsigned int ir_delay_cycle; if (bebob->maudio_special_quirk) { err = bebob->spec->rate->get(bebob, &curr_rate); @@ -660,13 +661,18 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) // The device postpones start of transmission mostly for 1 sec // after receives packets firstly. For safe, IR context starts - // 1.5 sec (=12000 cycles) later. This is within 2.0 sec - // (=CALLBACK_TIMEOUT). + // 0.4 sec (=3200 cycles) later to version 1 or 2 firmware, + // 2.0 sec (=16000 cycles) for version 3 firmware. This is + // within 2.5 sec (=CALLBACK_TIMEOUT). // Furthermore, some devices transfer isoc packets with // discontinuous counter in the beginning of packet streaming. // The delay has an effect to avoid detection of this // discontinuity. - err = amdtp_domain_start(&bebob->domain, 12000); + if (bebob->version < 2) + ir_delay_cycle = 3200; + else + ir_delay_cycle = 16000; + err = amdtp_domain_start(&bebob->domain, ir_delay_cycle); if (err < 0) goto error; -- cgit From 6c94f380c6c1d0206da55b0342557926052f2b3e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 1 Nov 2019 22:13:23 +0900 Subject: ALSA: bebob: link the order of establishing connections and Syt-match clock mode Originally BeBeB ASICs and firmware supports clock mode to synchronizing to syt field of received isoc packet. This mode is known as 'SYT Match' slightly described in IEC 61883-6 (but no detail mechanisms). In this mode, drivers can control sampling clock in device. Driver for Windows and macOS uses this feature to perform synchronization for devices on the same bus. In this mode, a plug of Music subunit for synchronization is connected to a plug of isoc unit for incoming packet streaming, then the order to establish connections is INPUT_PLUG first, OUTPUT_PLUG second. This commit implements the above. Actually each device works with its own clock for sampling, therefore the original design is hardly implemented to vendor's products. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20191101131323.17300-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_stream.c | 51 ++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 895a113635af..bbae04793c50 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -398,23 +398,6 @@ check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s) return err; } -static int make_both_connections(struct snd_bebob *bebob) -{ - int err = 0; - - err = cmp_connection_establish(&bebob->out_conn); - if (err < 0) - return err; - - err = cmp_connection_establish(&bebob->in_conn); - if (err < 0) { - cmp_connection_break(&bebob->out_conn); - return err; - } - - return 0; -} - static void break_both_connections(struct snd_bebob *bebob) { cmp_connection_break(&bebob->in_conn); @@ -427,8 +410,7 @@ static void break_both_connections(struct snd_bebob *bebob) msleep(600); } -static int -start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) +static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) { struct cmp_connection *conn; int err = 0; @@ -438,18 +420,19 @@ start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) else conn = &bebob->out_conn; - /* channel mapping */ + // channel mapping. if (bebob->maudio_special_quirk == NULL) { err = map_data_channels(bebob, stream); if (err < 0) - goto end; + return err; } - // start amdtp stream. - err = amdtp_domain_add_stream(&bebob->domain, stream, - conn->resources.channel, conn->speed); -end: - return err; + err = cmp_connection_establish(conn); + if (err < 0) + return err; + + return amdtp_domain_add_stream(&bebob->domain, stream, + conn->resources.channel, conn->speed); } static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) @@ -638,6 +621,8 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) } if (!amdtp_stream_running(&bebob->rx_stream)) { + enum snd_bebob_clock_type src; + struct amdtp_stream *master, *slave; unsigned int curr_rate; unsigned int ir_delay_cycle; @@ -647,15 +632,23 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) return err; } - err = make_both_connections(bebob); + err = snd_bebob_stream_get_clock_src(bebob, &src); if (err < 0) return err; - err = start_stream(bebob, &bebob->rx_stream); + if (src != SND_BEBOB_CLOCK_TYPE_SYT) { + master = &bebob->tx_stream; + slave = &bebob->rx_stream; + } else { + master = &bebob->rx_stream; + slave = &bebob->tx_stream; + } + + err = start_stream(bebob, master); if (err < 0) goto error; - err = start_stream(bebob, &bebob->tx_stream); + err = start_stream(bebob, slave); if (err < 0) goto error; -- cgit From 6111fd2370eecae9f11bfdc08ba097e0b51fcfd3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Nov 2019 11:11:15 +0100 Subject: ALSA: pcm: Fix missing check of the new non-cached buffer type The check for the mmap support via hw_support_mmap() function misses the case where the device is with SNDRV_DMA_TYPE_DEV_UC, which should have been treated equally as SNDRV_DMA_TYPE_DEV. Let's fix it. Note that this bug doesn't hit any practical problem, because SNDRV_DMA_TYPE_DEV_UC is used only for x86-specific drivers (snd-hda-intel and snd-intel8x0) for the specific platforms that need the non-cached buffers. And, on such platforms, hw_support_mmap() already returns true in anyway. That's the reason I didn't put Cc-to-stable mark here. This is only for any theoretical future extension. Fixes: 425da159707b ("ALSA: pcm: use dma_can_mmap() to check if a device supports dma_mmap_*") Fixes: 42e748a0b325 ("ALSA: memalloc: Add non-cached buffer type") Link: https://lore.kernel.org/r/20191104101115.27311-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 91c6ad58729f..c3a139436ac2 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -222,7 +222,8 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream) return false; if (substream->ops->mmap || - substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_DEV) + (substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_DEV && + substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_DEV_UC)) return true; return dma_can_mmap(substream->dma_buffer.dev.dev); -- cgit From e0859710516c98b189879966b48ea1c77e0cd979 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 31 Oct 2019 21:34:15 +0800 Subject: ASoC: ux500: Remove redundant variable "status" local variable "status" is not used. hence it is safe to remove and just return 0. Signed-off-by: zhong jiang Link: https://lore.kernel.org/r/1572528855-25990-1-git-send-email-zhongjiang@huawei.com Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_i2s.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index a90e0d7f0b73..394d8b2a4a16 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -533,7 +533,6 @@ static void disable_msp_tx(struct ux500_msp *msp) static int disable_msp(struct ux500_msp *msp, unsigned int dir) { u32 reg_val_GCR; - int status = 0; unsigned int disable_tx, disable_rx; reg_val_GCR = readl(msp->registers + MSP_GCR); @@ -566,7 +565,7 @@ static int disable_msp(struct ux500_msp *msp, unsigned int dir) else if (disable_rx) disable_msp_rx(msp); - return status; + return 0; } int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction) -- cgit From f95ce1355944189c26e4182c813d7f018b434dbd Mon Sep 17 00:00:00 2001 From: Naveen Manohar Date: Fri, 1 Nov 2019 12:18:46 -0500 Subject: ASoC: Intel: Add acpi match for rt1011 based m/c driver Add match for CML m/c with RT1011 and RT5682 Signed-off-by: Naveen Manohar Signed-off-by: Sathya Prakash M R Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101171847.26767-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 985aa366c9e8..16d0bae8b316 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -47,6 +47,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", }, + { + .id = "10EC1011", + .drv_name = "cml_rt1011_rt5682", + .quirk_data = &cml_codecs, + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", + }, { .id = "10EC5682", .drv_name = "sof_rt5682", -- cgit From 17fe95d6df9320409015e5114309a3c05e31b736 Mon Sep 17 00:00:00 2001 From: Naveen Manohar Date: Fri, 1 Nov 2019 12:18:47 -0500 Subject: ASoC: Intel: boards: Add CML m/c using RT1011 and RT5682 Machine driver to enable RT5682 on SSP0, DMIC, HDMI and RT1011 AMP on SSP1 with 2 CH / 24 bit TDM Playback over 4 individual codecs and 4 CH / 24 bit Capture to provide feedback. Signed-off-by: Naveen Manohar Signed-off-by: Sathya Prakash M R Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101171847.26767-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 14 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/cml_rt1011_rt5682.c | 487 +++++++++++++++++++++++++++++ 3 files changed, 503 insertions(+) create mode 100644 sound/soc/intel/boards/cml_rt1011_rt5682.c (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 5e0e7dbd1300..e591b058f46e 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -423,6 +423,20 @@ config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC +config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH + tristate "CML with RT1011 and RT5682 in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT1011 + select SND_SOC_RT5682 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC machine driver for SOF platform with + RT1011 + RT5682 I2S codec. + Say Y if you have such a device. + If unsure select "N". + endif ## SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 8bddf379cef1..9ae6544c6f3b 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -18,6 +18,7 @@ snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o +snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o hda_dsp_common.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o @@ -47,6 +48,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH) += snd-soc-sst-byt-cht-cx2072x. obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH) += snd-soc-cml_rt1011_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c new file mode 100644 index 000000000000..a22f97234201 --- /dev/null +++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c @@ -0,0 +1,487 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2019 Intel Corporation. + +/* + * Intel Cometlake I2S Machine driver for RT1011 + RT5682 codec + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/rt1011.h" +#include "../../codecs/rt5682.h" +#include "../../codecs/hdac_hdmi.h" +#include "hda_dsp_common.h" + +/* The platform clock outputs 24Mhz clock to codec as I2S MCLK */ +#define CML_PLAT_CLK 24000000 +#define CML_RT1011_CODEC_DAI "rt1011-aif" +#define CML_RT5682_CODEC_DAI "rt5682-aif1" +#define NAME_SIZE 32 + +static struct snd_soc_jack hdmi_jack[3]; + +struct hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct card_private { + char codec_name[SND_ACPI_I2C_ID_LEN]; + struct snd_soc_jack headset; + struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; +}; + +static const struct snd_kcontrol_new cml_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("TL Ext Spk"), + SOC_DAPM_PIN_SWITCH("TR Ext Spk"), + SOC_DAPM_PIN_SWITCH("WL Ext Spk"), + SOC_DAPM_PIN_SWITCH("WR Ext Spk"), +}; + +static const struct snd_soc_dapm_widget cml_rt1011_rt5682_widgets[] = { + SND_SOC_DAPM_SPK("TL Ext Spk", NULL), + SND_SOC_DAPM_SPK("TR Ext Spk", NULL), + SND_SOC_DAPM_SPK("WL Ext Spk", NULL), + SND_SOC_DAPM_SPK("WR Ext Spk", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static const struct snd_soc_dapm_route cml_rt1011_rt5682_map[] = { + /*speaker*/ + {"TL Ext Spk", NULL, "TL SPO"}, + {"TR Ext Spk", NULL, "TR SPO"}, + {"WL Ext Spk", NULL, "WL SPO"}, + {"WR Ext Spk", NULL, "WR SPO"}, + + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* other jacks */ + { "IN1P", NULL, "Headset Mic" }, + + /* DMIC */ + {"DMic", NULL, "SoC DMIC"}, +}; + +static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + int ret; + + /* need to enable ASRC function for 24MHz mclk rate */ + rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | + RT5682_AD_STEREO1_FILTER, + RT5682_CLK_SEL_I2S1_ASRC); + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->headset, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + jack = &ctx->headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + + return ret; +}; + +static int cml_rt5682_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_dai *codec_dai = rtd->codec_dai; + int clk_id, clk_freq, pll_out, ret; + + clk_id = RT5682_PLL1_S_MCLK; + clk_freq = CML_PLAT_CLK; + + pll_out = params_rate(params) * 512; + + ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + if (ret < 0) + dev_warn(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, + pll_out, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_warn(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + /* + * slot_width should be equal or large than data length, set them + * be the same + */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, + params_width(params)); + if (ret < 0) + dev_warn(rtd->dev, "set TDM slot err:%d\n", ret); + return ret; +} + +static int cml_rt1011_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_dai *codec_dai; + struct snd_soc_card *card = rtd->card; + int srate, i, ret = 0; + + srate = params_rate(params); + + for (i = 0; i < rtd->num_codecs; i++) { + codec_dai = rtd->codec_dais[i]; + + /* 100 Fs to drive 24 bit data */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK, + 100 * srate, 256 * srate); + if (ret < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT1011_FS_SYS_PRE_S_PLL1, + 256 * srate, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return ret; + } + + /* + * Codec TDM is configured as 24 bit capture/ playback. + * 2 CH PB is done over 4 codecs - 2 Woofers and 2 Tweeters. + * The Left woofer and tweeter plays the Left playback data + * and similar by the Right. + * Hence 2 codecs (1 T and 1 W pair) share same Rx slot. + * The feedback is captured for each codec individually. + * Hence all 4 codecs use 1 Tx slot each for feedback. + */ + if (!strcmp(codec_dai->component->name, "i2c-10EC1011:00")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x4, 0x1, 4, 24); + if (ret < 0) + break; + } + if (!strcmp(codec_dai->component->name, "i2c-10EC1011:02")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x1, 0x1, 4, 24); + if (ret < 0) + break; + } + /* TDM Rx slot 2 is used for Right Woofer & Tweeters pair */ + if (!strcmp(codec_dai->component->name, "i2c-10EC1011:01")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x8, 0x2, 4, 24); + if (ret < 0) + break; + } + if (!strcmp(codec_dai->component->name, "i2c-10EC1011:03")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x2, 0x2, 4, 24); + if (ret < 0) + break; + } + } + if (ret < 0) + dev_err(rtd->dev, + "set codec TDM slot for %s failed with error %d\n", + codec_dai->component->name, ret); + return ret; +} + +static struct snd_soc_ops cml_rt5682_ops = { + .hw_params = cml_rt5682_hw_params, +}; + +static const struct snd_soc_ops cml_rt1011_ops = { + .hw_params = cml_rt1011_hw_params, +}; + +static int sof_card_late_probe(struct snd_soc_card *card) +{ + struct card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = NULL; + char jack_name[NAME_SIZE]; + struct hdmi_pcm *pcm; + int ret, i = 0; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + ret = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &hdmi_jack[i], + NULL, 0); + if (ret) + return ret; + + ret = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &hdmi_jack[i]); + if (ret < 0) + return ret; + + i++; + } + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} + +static int hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +/* Cometlake digital audio interface glue - connects codec <--> CPU */ + +SND_SOC_DAILINK_DEF(ssp0_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); +SND_SOC_DAILINK_DEF(ssp0_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", + CML_RT5682_CODEC_DAI))); + +SND_SOC_DAILINK_DEF(ssp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); +SND_SOC_DAILINK_DEF(ssp1_codec, + DAILINK_COMP_ARRAY( + /* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI), + /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI), + /* TL */ COMP_CODEC("i2c-10EC1011:02", CML_RT1011_CODEC_DAI), + /* TR */ COMP_CODEC("i2c-10EC1011:03", CML_RT1011_CODEC_DAI))); + +SND_SOC_DAILINK_DEF(dmic_pin, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); + +SND_SOC_DAILINK_DEF(dmic16k_pin, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); + +SND_SOC_DAILINK_DEF(dmic_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); + +SND_SOC_DAILINK_DEF(idisp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); +SND_SOC_DAILINK_DEF(idisp1_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); + +SND_SOC_DAILINK_DEF(idisp2_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); +SND_SOC_DAILINK_DEF(idisp2_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); + +SND_SOC_DAILINK_DEF(idisp3_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); +SND_SOC_DAILINK_DEF(idisp3_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); + +static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = { + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .init = cml_rt5682_codec_init, + .ignore_pmdown_time = 1, + .ops = &cml_rt5682_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), + }, + { + .name = "dmic01", + .id = 1, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), + }, + { + .name = "dmic16k", + .id = 2, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), + }, + { + .name = "iDisp1", + .id = 3, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), + }, + { + .name = "iDisp2", + .id = 4, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), + }, + { + .name = "iDisp3", + .id = 5, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), + }, + { + /* + * SSP1 - Codec : added to end of list ensuring + * reuse of common topologies for other end points + * and changing only SSP1's codec + */ + .name = "SSP1-Codec", + .id = 6, + .dpcm_playback = 1, + .dpcm_capture = 1, /* Capture stream provides Feedback */ + .no_pcm = 1, + .ops = &cml_rt1011_ops, + SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), + }, +}; + +static struct snd_soc_codec_conf rt1011_conf[] = { + { + .dev_name = "i2c-10EC1011:00", + .name_prefix = "WL", + }, + { + .dev_name = "i2c-10EC1011:01", + .name_prefix = "WR", + }, + { + .dev_name = "i2c-10EC1011:02", + .name_prefix = "TL", + }, + { + .dev_name = "i2c-10EC1011:03", + .name_prefix = "TR", + }, +}; + +/* Cometlake audio machine driver for RT1011 and RT5682 */ +static struct snd_soc_card snd_soc_card_cml = { + .name = "cml_rt1011_rt5682", + .dai_link = cml_rt1011_rt5682_dailink, + .num_links = ARRAY_SIZE(cml_rt1011_rt5682_dailink), + .codec_conf = rt1011_conf, + .num_configs = ARRAY_SIZE(rt1011_conf), + .dapm_widgets = cml_rt1011_rt5682_widgets, + .num_dapm_widgets = ARRAY_SIZE(cml_rt1011_rt5682_widgets), + .dapm_routes = cml_rt1011_rt5682_map, + .num_dapm_routes = ARRAY_SIZE(cml_rt1011_rt5682_map), + .controls = cml_controls, + .num_controls = ARRAY_SIZE(cml_controls), + .fully_routed = true, + .late_probe = sof_card_late_probe, +}; + +static int snd_cml_rt1011_probe(struct platform_device *pdev) +{ + struct card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + mach = (&pdev->dev)->platform_data; + snd_soc_card_cml.dev = &pdev->dev; + platform_name = mach->mach_params.platform; + + /* set platform name for each dailink */ + ret = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cml, + platform_name); + if (ret) + return ret; + + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + + snd_soc_card_set_drvdata(&snd_soc_card_cml, ctx); + + return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cml); +} + +static struct platform_driver snd_cml_rt1011_rt5682_driver = { + .probe = snd_cml_rt1011_probe, + .driver = { + .name = "cml_rt1011_rt5682", + .pm = &snd_soc_pm_ops, + }, +}; +module_platform_driver(snd_cml_rt1011_rt5682_driver); + +/* Module information */ +MODULE_DESCRIPTION("Cometlake Audio Machine driver - RT1011 and RT5682 in I2S mode"); +MODULE_AUTHOR("Naveen Manohar "); +MODULE_AUTHOR("Sathya Prakash M R "); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cml_rt1011_rt5682"); -- cgit From 65c56f5dccc87ca2993a50672e144c7378189f2c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 1 Nov 2019 12:09:16 -0500 Subject: ASoC: SOF: Intel: hda: Simplify the hda_dsp_wait_d0i3c_done() function Remove the retry argument for the hda_dsp_wait_d0i3c_done() function and use the HDA_DSP_REG_POLL_RETRY_COUNT macro directly. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101170916.26517-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index d23573d9e9c4..8cd5ecc01b62 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -307,9 +307,10 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } -static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev, int retry) +static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); + int retry = HDA_DSP_REG_POLL_RETRY_COUNT; while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) { if (!retry--) @@ -346,7 +347,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, u8 value; /* Write to D0I3C after Command-In-Progress bit is cleared */ - ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); + ret = hda_dsp_wait_d0i3c_done(sdev); if (ret < 0) { dev_err(bus->dev, "CIP timeout before D0I3C update!\n"); return ret; @@ -357,7 +358,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); /* Wait for cmd in progress to be cleared before exiting the function */ - ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); + ret = hda_dsp_wait_d0i3c_done(sdev); if (ret < 0) { dev_err(bus->dev, "CIP timeout after D0I3C update!\n"); return ret; -- cgit From df7257e544faf838c3e7ad6b4e89ffe59e87f5e1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:35 -0500 Subject: ASoC: SOF: Intel: Baytrail: clarify mutual exclusion with Atom/SST driver Some distros select all options blindly, which leads to confusion and bug reports. Since SOF does not support Baytrail-CR for now, and UCM/topology files are still being propagated to downstream distros, make SOF on Baytrail an opt-in option that first require distros to opt-out of existing defaults. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 3 +++ sound/soc/sof/intel/Kconfig | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 01c99750212a..ba5b90e66e2f 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -101,6 +101,9 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI If you have a Intel Baytrail or Cherrytrail platform with an I2S codec, then enable this option by saying Y or m. This is a recommended option + This option is mutually exclusive with the SOF support on + Baytrail/Cherrytrail. If you want to enable SOF on + Baytrail/Cherrytrail, you need to deselect this option first. config SND_SOC_INTEL_SKYLAKE tristate "All Skylake/SST Platforms" diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index d52298946c00..973c137a6c5a 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -62,10 +62,18 @@ if SND_SOC_SOF_INTEL_ACPI config SND_SOC_SOF_BAYTRAIL_SUPPORT bool "SOF support for Baytrail, Braswell and Cherrytrail" + depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI=n help This adds support for Sound Open Firmware for Intel(R) platforms using the Baytrail, Braswell or Cherrytrail processors. - Say Y if you have such a device. + This option is mutually exclusive with the Atom/SST and Baytrail + legacy drivers. If you want to enable SOF on Baytrail/Cherrytrail, + you need to deselect those options first. + SOF does not support Baytrail-CR for now, so this option is not + recommended for distros. At some point all legacy drivers will be + deprecated but not before all userspace firmware/topology/UCM files + are made available to downstream distros. + Say Y if you want to enable SOF on Baytrail/Cherrytrail If unsure select "N". config SND_SOC_SOF_BAYTRAIL -- cgit From a6955fe0e2309feeab5ec71e4b0dcbe498f4f497 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:36 -0500 Subject: ASoC: SOF: Intel: Broadwell: clarify mutual exclusion with legacy driver Some distros select all options blindly, which leads to confusion and bug reports. SOF does not fully support Broadwell due to firmware dependencies, the machine drivers can only support one option, and UCM/topology files are still being propagated to downstream distros, so make SOF on Broadwell an opt-in option that first require distros to opt-out of existing defaults. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=204237 Fixes: f35bf70f61d3 ('ASoC: Intel: Make sure BDW based machine drivers build for SOF') Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 3 +++ sound/soc/sof/intel/Kconfig | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index ba5b90e66e2f..93ebe1297e41 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -59,6 +59,9 @@ config SND_SOC_INTEL_HASWELL If you have a Intel Haswell or Broadwell platform connected to an I2S codec, then enable this option by saying Y or m. This is typically used for Chromebooks. This is a recommended option. + This option is mutually exclusive with the SOF support on + Broadwell. If you want to enable SOF on Broadwell, you need to + deselect this option first. config SND_SOC_INTEL_BAYTRAIL tristate "Baytrail (legacy) Platforms" diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 973c137a6c5a..cd9954bfec0b 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -85,10 +85,18 @@ config SND_SOC_SOF_BAYTRAIL config SND_SOC_SOF_BROADWELL_SUPPORT bool "SOF support for Broadwell" + depends on SND_SOC_INTEL_HASWELL=n help This adds support for Sound Open Firmware for Intel(R) platforms using the Broadwell processors. - Say Y if you have such a device. + This option is mutually exclusive with the Haswell/Broadwell legacy + driver. If you want to enable SOF on Broadwell you need to deselect + the legacy driver first. + SOF does fully support Broadwell yet, so this option is not + recommended for distros. At some point all legacy drivers will be + deprecated but not before all userspace firmware/topology/UCM files + are made available to downstream distros. + Say Y if you want to enable SOF on Broadwell If unsure select "N". config SND_SOC_SOF_BROADWELL -- cgit From 280393b712b7e338addc2f7f60b4e4da787ba19b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:37 -0500 Subject: ASoC: Intel: add mutual exclusion between SOF and legacy Baytrail driver This legacy driver is already deprecated, let's make sure there is no conflict with SOF. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 93ebe1297e41..086fc60b2a14 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -65,7 +65,7 @@ config SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_BAYTRAIL tristate "Baytrail (legacy) Platforms" - depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n + depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n && SND_SOC_SOF_BAYTRAIL=n select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_ACPI select SND_SOC_INTEL_SST_FIRMWARE -- cgit From 70ae4eb540af32ee6a6260143ccae6054ebd433f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:38 -0500 Subject: ASoC: SOF: Kconfig: add EXPERT dependency for developer options, clarify help Some distros select all possible options, despite existing warnings to be careful. This leads to e.g. user reports that the HDaudio codec and DMIC are not handled by SOF. Add an explicit menu item to unlock developer options, and make them dependent on CONFIG_EXPERT. Hopefully with this double-lock these options will only be selected by developers. GitHub issue: https://github.com/thesofproject/sof/issues/1885 Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 56a3ab66b46b..6435eb531668 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -14,7 +14,6 @@ config SND_SOC_SOF_PCI depends on PCI select SND_SOC_SOF select SND_SOC_ACPI if ACPI - select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL help This adds support for PCI enumeration. This option is @@ -27,7 +26,6 @@ config SND_SOC_SOF_ACPI depends on ACPI || COMPILE_TEST select SND_SOC_SOF select SND_SOC_ACPI if ACPI - select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL select IOSF_MBI if X86 && PCI help @@ -40,19 +38,23 @@ config SND_SOC_SOF_OF tristate "SOF OF enumeration support" depends on OF || COMPILE_TEST select SND_SOC_SOF - select SND_SOC_SOF_OPTIONS help This adds support for Device Tree enumeration. This option is required to enable i.MX8 devices. Say Y if you need this option. If unsure select "N". -config SND_SOC_SOF_OPTIONS - tristate +config SND_SOC_SOF_DEVELOPER_SUPPORT + bool "SOF developer options support" + depends on EXPERT help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level + This option unlock SOF developer options for debug/performance/ + code hardening. + Distributions should not select this option, only SOF development + teams should select it. + Say Y if you are involved in SOF development and need this option + If not, select N -if SND_SOC_SOF_OPTIONS +if SND_SOC_SOF_DEVELOPER_SUPPORT config SND_SOC_SOF_NOCODEC tristate @@ -64,6 +66,11 @@ config SND_SOC_SOF_NOCODEC_SUPPORT option if no known codec is detected. This is typically only enabled for developers or devices where the sound card is controlled externally + This option is mutually exclusive with the Intel HDaudio support, + selecting it may have negative impacts and prevent e.g. microphone + functionality from being enabled on Intel CoffeeLake and later + platforms. + Distributions should not select this option! Say Y if you need this nocodec fallback option If unsure select "N". @@ -168,7 +175,7 @@ config SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT endif ## SND_SOC_SOF_DEBUG -endif ## SND_SOC_SOF_OPTIONS +endif ## SND_SOC_SOF_DEVELOPER_SUPPORT config SND_SOC_SOF tristate -- cgit From f9ad75468453b019b92c5296e6a04bf7c37f49e4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:39 -0500 Subject: ASoC: SOF: imx: fix reverse CONFIG_SND_SOC_SOF_OF dependency updated solution to the problem reported with randconfig: CONFIG_SND_SOC_SOF_IMX depends on CONFIG_SND_SOC_SOF, but is in turn referenced by the sof-of-dev driver. This creates a reverse dependency that manifests in a link error when CONFIG_SND_SOC_SOF_OF is built-in but CONFIG_SND_SOC_SOF_IMX=m: sound/soc/sof/sof-of-dev.o:(.data+0x118): undefined reference to `sof_imx8_ops' use def_trisate to propagate the right settings without select. Fixes: f4df4e4042b0 ("ASoC: SOF: imx8: Fix COMPILE_TEST error") Fixes: 202acc565a1f ("ASoC: SOF: imx: Add i.MX8 HW support") Suggested-by: Arnd Bergmann Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/Kconfig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index 5acae75f5750..71f318bc2c74 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -11,8 +11,8 @@ config SND_SOC_SOF_IMX_TOPLEVEL if SND_SOC_SOF_IMX_TOPLEVEL -config SND_SOC_SOF_IMX8 - tristate "SOF support for i.MX8" +config SND_SOC_SOF_IMX8_SUPPORT + bool "SOF support for i.MX8" depends on IMX_SCU depends on IMX_DSP help @@ -20,4 +20,8 @@ config SND_SOC_SOF_IMX8 Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_IMX8 + def_tristate SND_SOC_SOF_OF + depends on SND_SOC_SOF_IMX8_SUPPORT + endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL -- cgit From b000135e5f272118e576e9720590e5979f0abe49 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:40 -0500 Subject: ASoC: SOF: Intel: use def_tristate, avoid using select So far we used select to use the relevant built-in/module options, but this led to blurring layers between core and Intel Kconfigs. Use def_tristate works just as well and removes Intel stuff from the code. Suggested-by: Arnd Bergmann Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 2 -- sound/soc/sof/intel/Kconfig | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 6435eb531668..71a0fc075a63 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -14,7 +14,6 @@ config SND_SOC_SOF_PCI depends on PCI select SND_SOC_SOF select SND_SOC_ACPI if ACPI - select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL help This adds support for PCI enumeration. This option is required to enable Intel Skylake+ devices @@ -26,7 +25,6 @@ config SND_SOC_SOF_ACPI depends on ACPI || COMPILE_TEST select SND_SOC_SOF select SND_SOC_ACPI if ACPI - select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL select IOSF_MBI if X86 && PCI help This adds support for ACPI enumeration. This option is required diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index cd9954bfec0b..04d4929cf91f 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -10,7 +10,7 @@ config SND_SOC_SOF_INTEL_TOPLEVEL if SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_SOF_INTEL_ACPI - tristate + def_tristate SND_SOC_SOF_ACPI select SND_SOC_SOF_BAYTRAIL if SND_SOC_SOF_BAYTRAIL_SUPPORT select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT help @@ -18,7 +18,7 @@ config SND_SOC_SOF_INTEL_ACPI 'select' statements at a higher level config SND_SOC_SOF_INTEL_PCI - tristate + def_tristate SND_SOC_SOF_PCI select SND_SOC_SOF_MERRIFIELD if SND_SOC_SOF_MERRIFIELD_SUPPORT select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT -- cgit From 02701b909c2fab4b49f9c9545ab921c9b2c7a768 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:41 -0500 Subject: ASoC: Intel: Skylake: mark HDAudio codec support as deprecated. This option famously broke audio on Linus' laptop and the problem have not been fixed. Mark as DEPRECATED to avoid any ambiguity with distros. Use SOF if you need HDaudio support w/ the DSP enabled, e.g. for DMIC capture. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 086fc60b2a14..79b227613108 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -209,9 +209,12 @@ config SND_SOC_INTEL_SKYLAKE_SSP_CLK config SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC bool "HDAudio codec support" help - If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ - GeminiLake or CannonLake platform with an HDaudio codec - then enable this option by saying Y + This option broke audio on Linus' Skylake laptop in December 2018 + and the race conditions during the probe were not fixed since. + This option is DEPRECATED, all HDaudio codec support needs + to be handled by the SOF driver. + Distributions should not enable this option and there are no known + users of this capability. config SND_SOC_INTEL_SKYLAKE_COMMON tristate -- cgit From 9e7301762f6df44bb4a452b6aecbe0f322b370ee Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:42 -0500 Subject: ASoC: Intel: boards: remove select SND_HDA_DSP_LOADER This option is only required with the Skylake platform driver, there is no reason to have this option in machine drivers. This is e.g. useless for SOF-based solutions. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index e591b058f46e..c63070c3a250 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -270,7 +270,6 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - select SND_HDA_DSP_LOADER help This adds support for ASoC machine driver for Broxton-P platforms with DA7219 + MAX98357A I2S audio codec. @@ -284,7 +283,6 @@ config SND_SOC_INTEL_BXT_RT298_MACH select SND_SOC_RT298 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI - select SND_HDA_DSP_LOADER help This adds support for ASoC machine driver for Broxton platforms with RT286 I2S audio codec. @@ -375,7 +373,6 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH select SND_SOC_MAX98357A select SND_SOC_DMIC select SND_SOC_HDAC_HDMI - select SND_HDA_DSP_LOADER help This adds support for ASoC machine driver for Geminilake platforms with RT5682 + MAX98357A I2S audio codec. -- cgit From c4a09f9a523e674ef9a046e05d99c90f2c9513b1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:43 -0500 Subject: ASoC: Intel: boards: fix configs for bxt-da7219-max98057a The same driver is reused for 3 different configurations, but the driver will only be build if ApolloLake is selected. Fix and make sure each device can work without dependencies on others (useful for minimal configurations). Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 24 ++++++++++++++++++++++-- sound/soc/intel/boards/Makefile | 2 +- 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index c63070c3a250..0b3101dc8286 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -263,13 +263,17 @@ config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC select SND_SOC_DMIC select SND_SOC_HDAC_HDMI +config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + tristate + select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + if SND_SOC_INTEL_APL config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "Broxton with DA7219 and MAX98357A in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON help This adds support for ASoC machine driver for Broxton-P platforms with DA7219 + MAX98357A I2S audio codec. @@ -365,6 +369,17 @@ endif ## SND_SOC_INTEL_KBL if SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK) +config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH + tristate "GLK with DA7219 and MAX98357A in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + help + This adds support for ASoC machine driver for Geminilake platforms + with DA7219 + MAX98357A I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" depends on I2C && ACPI @@ -418,7 +433,12 @@ config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH tristate "CML_LP with DA7219 and MAX98357A in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + help + This adds support for ASoC machine driver for Cometlake platforms + with DA7219 + MAX98357A I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH tristate "CML with RT1011 and RT5682 in I2S Mode" diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 9ae6544c6f3b..ba1aa89db09d 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o -obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o +obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON) += snd-soc-sst-bxt-da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o -- cgit From 3315e5b40f59d1aab6543773d99b1f19c3ea1848 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:44 -0500 Subject: ASoC: Intel: boards: Geminilake is only supported by SOF Geminilake machine drivers are only tested and recommended with SOF. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 0b3101dc8286..746e087ff6d7 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -367,7 +367,7 @@ config SND_SOC_INTEL_KBL_RT5660_MACH endif ## SND_SOC_INTEL_KBL -if SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK) +if SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH tristate "GLK with DA7219 and MAX98357A in I2S Mode" @@ -394,7 +394,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK) +endif ## SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC -- cgit From 8039105987fcd8dda39074df013cfdf0025dd297 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 12:30:45 -0500 Subject: ASoC: Intel: boards: sof_rt5682: use dependency on SOF_HDA_LINK The wrong dependency is used and the build can be broken Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101173045.27099-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 746e087ff6d7..dfa2c365379f 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -411,11 +411,11 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC -if SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL +if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_SOF_RT5682_MACH tristate "SOF with rt5682 codec in I2S Mode" depends on I2C && ACPI - depends on (SND_SOC_SOF_HDA_COMMON && (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ + depends on (SND_SOC_SOF_HDA_LINK && (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) select SND_SOC_RT5682 select SND_SOC_DMIC @@ -425,7 +425,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH with rt5682 codec. Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL +endif ## SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL if (SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK) -- cgit From 42ec336f1f9d54049811b749f729e9e01c152ade Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 09:18:06 +0100 Subject: ALSA: hda: Disable regmap internal locking Since we apply the own mutex (bus->cmd_mutex) in HDA core side, the internal locking in regmap is superfluous. This patch adds the flag to indicate that. Also, an infamous side-effect by this change is that it disables the regmap debugfs, too, and this is seen rather good; the regmap debugfs isn't quite useful for HD-audio as it provides the very sparse registers and its debugfs access tends to lead to the way too high resource usages or sometimes hang up. So it'd be rather safe to disable it altogether. Link: https://lore.kernel.org/r/2029139028.10333037.1572874551626.JavaMail.zimbra@redhat.com Link: https://lore.kernel.org/r/20191105081806.4896-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/hdac_regmap.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index 286361ecd640..906b1e20bae0 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c @@ -363,6 +363,7 @@ static const struct regmap_config hda_regmap_cfg = { .reg_write = hda_reg_write, .use_single_read = true, .use_single_write = true, + .disable_locking = true, }; /** -- cgit From acbf27746ecfa96b290b54cc7f05273482ea128a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 4 Nov 2019 14:48:11 -0800 Subject: ASoC: pcm: update FE/BE trigger order based on the command Currently, the trigger orders SND_SOC_DPCM_TRIGGER_PRE/POST determine the order in which FE DAI and BE DAI are triggered. In the case of SND_SOC_DPCM_TRIGGER_PRE, the FE DAI is triggered before the BE DAI and in the case of SND_SOC_DPCM_TRIGGER_POST, the BE DAI is triggered before the FE DAI. And this order remains the same irrespective of the trigger command. In the case of the SOF driver, during playback, the FW expects the BE DAI to be triggered before the FE DAI during the START trigger. The BE DAI trigger handles the starting of Link DMA and so it must be started before the FE DAI is started to prevent xruns during pause/release. This can be addressed by setting the trigger order for the FE dai link to SND_SOC_DPCM_TRIGGER_POST. But during the STOP trigger, the FW expects the FE DAI to be triggered before the BE DAI. Retaining the same order during the START and STOP commands, results in FW error as the DAI component in the FW is still active. The issue can be fixed by mirroring the trigger order of FE and BE DAI's during the START and STOP trigger. So, with the trigger order set to SND_SOC_DPCM_TRIGGER_PRE, the FE DAI will be trigger first during SNDRV_PCM_TRIGGER_START/STOP/RESUME and the BE DAI will be triggered first during the STOP/SUSPEND/PAUSE commands. Conversely, with the trigger order set to SND_SOC_DPCM_TRIGGER_POST, the BE DAI will be triggered first during the SNDRV_PCM_TRIGGER_START/STOP/RESUME commands and the FE DAI will be triggered first during the SNDRV_PCM_TRIGGER_STOP/SUSPEND/PAUSE commands. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191104224812.3393-2-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 95 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8655df6a6089..1c00119b72e3 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2322,42 +2322,81 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, } EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); +static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream, + int cmd, bool fe_first) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + int ret; + + /* call trigger on the frontend before the backend. */ + if (fe_first) { + dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_trigger(substream, cmd); + if (ret < 0) + return ret; + + ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); + return ret; + } + + /* call trigger on the frontend after the backend. */ + ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); + if (ret < 0) + return ret; + + dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_trigger(substream, cmd); + + return ret; +} + static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *fe = substream->private_data; - int stream = substream->stream, ret; + int stream = substream->stream; + int ret = 0; enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; switch (trigger) { case SND_SOC_DPCM_TRIGGER_PRE: - /* call trigger on the frontend before the backend. */ - - dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", - fe->dai_link->name, cmd); - - ret = soc_pcm_trigger(substream, cmd); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); - goto out; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = dpcm_dai_trigger_fe_be(substream, cmd, true); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = dpcm_dai_trigger_fe_be(substream, cmd, false); + break; + default: + ret = -EINVAL; + break; } - - ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); break; case SND_SOC_DPCM_TRIGGER_POST: - /* call trigger on the frontend after the backend. */ - - ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); - goto out; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = dpcm_dai_trigger_fe_be(substream, cmd, false); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = dpcm_dai_trigger_fe_be(substream, cmd, true); + break; + default: + ret = -EINVAL; + break; } - - dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", - fe->dai_link->name, cmd); - - ret = soc_pcm_trigger(substream, cmd); break; case SND_SOC_DPCM_TRIGGER_BESPOKE: /* bespoke trigger() - handles both FE and BEs */ @@ -2366,10 +2405,6 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) fe->dai_link->name, cmd); ret = soc_pcm_bespoke_trigger(substream, cmd); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); - goto out; - } break; default: dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, @@ -2378,6 +2413,12 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) goto out; } + if (ret < 0) { + dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n", + cmd, ret); + goto out; + } + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: -- cgit From 5eee2b3f60065a2530d13f28e771be48b989eb4c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 4 Nov 2019 14:48:12 -0800 Subject: ASoC: SOF: topology: set trigger order for FE DAI link Set trigger order for FE DAI links to SND_SOC_DPCM_TRIGGER_POST to trigger the BE DAI's before the FE DAI's. This prevents the xruns seen on playback pipelines using the link DMA. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191104224812.3393-3-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e0e2ae734632..e7076692119b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2951,6 +2951,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, if (!link->no_pcm) { link->nonatomic = true; + /* set trigger order */ + link->trigger[0] = SND_SOC_DPCM_TRIGGER_POST; + link->trigger[1] = SND_SOC_DPCM_TRIGGER_POST; + /* nothing more to do for FE dai links */ return 0; } -- cgit From 36794902de1fe6f46f8aa5e0d6a8d9884eecae1d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:45:41 +0900 Subject: ASoC: soc-core: move soc_init_dai_link() This patch moves soc_init_dai_link() next to soc_bind_dai_link(). This is prepare for soc_bind_dai_link() cleanup. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87eeym3joq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 192 +++++++++++++++++++++++++-------------------------- 1 file changed, 96 insertions(+), 96 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b07ecfac39d7..a141828f8638 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -941,6 +941,102 @@ static bool soc_is_dai_link_bound(struct snd_soc_card *card, return false; } +static int soc_init_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link) +{ + int i; + struct snd_soc_dai_link_component *codec, *platform; + + for_each_link_codecs(link, i, codec) { + /* + * Codec must be specified by 1 of name or OF node, + * not both or neither. + */ + if (!!codec->name == !!codec->of_node) { + dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + + /* Codec DAI name must be specified */ + if (!codec->dai_name) { + dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", + link->name); + return -EINVAL; + } + + /* + * Defer card registration if codec component is not added to + * component list. + */ + if (!soc_find_component(codec)) + return -EPROBE_DEFER; + } + + for_each_link_platforms(link, i, platform) { + /* + * Platform may be specified by either name or OF node, but it + * can be left unspecified, then no components will be inserted + * in the rtdcom list + */ + if (!!platform->name == !!platform->of_node) { + dev_err(card->dev, + "ASoC: Neither/both platform name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + + /* + * Defer card registration if platform component is not added to + * component list. + */ + if (!soc_find_component(platform)) + return -EPROBE_DEFER; + } + + /* FIXME */ + if (link->num_cpus > 1) { + dev_err(card->dev, + "ASoC: multi cpu is not yet supported %s\n", + link->name); + return -EINVAL; + } + + /* + * CPU device may be specified by either name or OF node, but + * can be left unspecified, and will be matched based on DAI + * name alone.. + */ + if (link->cpus->name && link->cpus->of_node) { + dev_err(card->dev, + "ASoC: Neither/both cpu name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + + /* + * Defer card registartion if cpu dai component is not added to + * component list. + */ + if ((link->cpus->of_node || link->cpus->name) && + !soc_find_component(link->cpus)) + return -EPROBE_DEFER; + + /* + * At least one of CPU DAI name or CPU device name/node must be + * specified + */ + if (!link->cpus->dai_name && + !(link->cpus->name || link->cpus->of_node)) { + dev_err(card->dev, + "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + + return 0; +} + static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -1283,102 +1379,6 @@ static int soc_probe_link_components(struct snd_soc_card *card) return 0; } -static int soc_init_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *link) -{ - int i; - struct snd_soc_dai_link_component *codec, *platform; - - for_each_link_codecs(link, i, codec) { - /* - * Codec must be specified by 1 of name or OF node, - * not both or neither. - */ - if (!!codec->name == !!codec->of_node) { - dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - - /* Codec DAI name must be specified */ - if (!codec->dai_name) { - dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", - link->name); - return -EINVAL; - } - - /* - * Defer card registration if codec component is not added to - * component list. - */ - if (!soc_find_component(codec)) - return -EPROBE_DEFER; - } - - for_each_link_platforms(link, i, platform) { - /* - * Platform may be specified by either name or OF node, but it - * can be left unspecified, then no components will be inserted - * in the rtdcom list - */ - if (!!platform->name == !!platform->of_node) { - dev_err(card->dev, - "ASoC: Neither/both platform name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - - /* - * Defer card registration if platform component is not added to - * component list. - */ - if (!soc_find_component(platform)) - return -EPROBE_DEFER; - } - - /* FIXME */ - if (link->num_cpus > 1) { - dev_err(card->dev, - "ASoC: multi cpu is not yet supported %s\n", - link->name); - return -EINVAL; - } - - /* - * CPU device may be specified by either name or OF node, but - * can be left unspecified, and will be matched based on DAI - * name alone.. - */ - if (link->cpus->name && link->cpus->of_node) { - dev_err(card->dev, - "ASoC: Neither/both cpu name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - - /* - * Defer card registartion if cpu dai component is not added to - * component list. - */ - if ((link->cpus->of_node || link->cpus->name) && - !soc_find_component(link->cpus)) - return -EPROBE_DEFER; - - /* - * At least one of CPU DAI name or CPU device name/node must be - * specified - */ - if (!link->cpus->dai_name && - !(link->cpus->name || link->cpus->of_node)) { - dev_err(card->dev, - "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - - return 0; -} - void snd_soc_disconnect_sync(struct device *dev) { struct snd_soc_component *component = -- cgit From bfce78a559655c5c4512a898a7e5d3a796fbb473 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:45:50 +0900 Subject: ASoC: soc-core: tidyup soc_init_dai_link() soc_init_dai_link() is needed to be called before soc_bind_dai_link(). int snd_soc_instantiate_card() { for_each_card_prelinks(...) { (1) ret = soc_init_dai_link(...); ... } ... for_each_card_prelinks(...) { (2) ret = soc_bind_dai_link(...); ... } ... for_each_card_links(...) { ... (A) ret = soc_init_dai_link(...); ... (B) ret = soc_bind_dai_link(...); } ... (1) is for (2), and (A) is for (B) (1) and (2) are for card prelink dai_link. (A) and (B) are for topology added dai_link. soc_init_dai_link() is sanity check for dai_link, not initializing today. Therefore, it is confusable naming. We can rename it as sanity_check. And this check is for soc_bind_dai_link(). It can be more simple code if we can call it from soc_bind_dai_link(). This patch renames it to soc_dai_link_sanity_check(), and call it from soc_bind_dai_link(). Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87d0e63joh.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a141828f8638..827625bd35cd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -941,8 +941,8 @@ static bool soc_is_dai_link_bound(struct snd_soc_card *card, return false; } -static int soc_init_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *link) +static int soc_dai_link_sanity_check(struct snd_soc_card *card, + struct snd_soc_dai_link *link) { int i; struct snd_soc_dai_link_component *codec, *platform; @@ -1043,7 +1043,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codec, *platform; struct snd_soc_component *component; - int i; + int i, ret; if (dai_link->ignore) return 0; @@ -1056,6 +1056,10 @@ static int soc_bind_dai_link(struct snd_soc_card *card, return 0; } + ret = soc_dai_link_sanity_check(card, dai_link); + if (ret < 0) + return ret; + rtd = soc_new_pcm_runtime(card, dai_link); if (!rtd) return -ENOMEM; @@ -1985,15 +1989,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) int ret, i; mutex_lock(&client_mutex); - for_each_card_prelinks(card, i, dai_link) { - ret = soc_init_dai_link(card, dai_link); - if (ret) { - dev_err(card->dev, "ASoC: failed to init link %s: %d\n", - dai_link->name, ret); - mutex_unlock(&client_mutex); - return ret; - } - } mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); snd_soc_dapm_init(&card->dapm, card, NULL); @@ -2073,9 +2068,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (soc_is_dai_link_bound(card, dai_link)) continue; - ret = soc_init_dai_link(card, dai_link); - if (ret) - goto probe_end; ret = soc_bind_dai_link(card, dai_link); if (ret) goto probe_end; -- cgit From cd3c5ad7b2503f4fb4dfcc095b3fccc2b3603c36 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:00 +0900 Subject: ASoC: soc-core: typo fix at soc_dai_link_sanity_check() Reported-by: Pierre-Louis Bossart Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87bltq3jo7.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 827625bd35cd..e1b0d861807c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1015,7 +1015,7 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card, } /* - * Defer card registartion if cpu dai component is not added to + * Defer card registration if cpu dai component is not added to * component list. */ if ((link->cpus->of_node || link->cpus->name) && -- cgit From 95b562e57f0b3a21a3945297862cb51bc2072c7b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:15 +0900 Subject: ASoC: soc-core: remove duplicated soc_is_dai_link_bound() soc_is_dai_link_bound() check will be called both *before* soc_bind_dai_link() (A), and *under* soc_bind_dai_link() (B). These are very verbose code. Let's remove one of them. * static int soc_bind_dai_link(...) { ... (B) if (soc_is_dai_link_bound(...)) { ... return 0; } ... } static int snd_soc_instantiate_card(...) { ... for_each_card_links(...) { (A) if (soc_is_dai_link_bound(...)) continue; * ret = soc_bind_dai_link(...); if (ret) goto probe_end; } ... } Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87a79a3jns.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e1b0d861807c..3cc36c2d99da 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2065,9 +2065,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) * Components with topology may bring new DAIs and DAI links. */ for_each_card_links(card, dai_link) { - if (soc_is_dai_link_bound(card, dai_link)) - continue; - ret = soc_bind_dai_link(card, dai_link); if (ret) goto probe_end; -- cgit From 6b1dff0266a30df16846a20d1109ab25b985f0d7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:20 +0900 Subject: ASoC: soc-core: call soc_bind_dai_link() under snd_soc_add_dai_link() If we focus to soc_bind_dai_link() at snd_soc_instantiate_card(), we will notice very complex operation. static int snd_soc_instantiate_card(...) { ... /* * (1) Bind dai_link via card pre-linked dai_link * * Bind dai_link via card pre-linked. * 1 dai_link will be 1 rtd, and connected to card. * for_each_card_prelinks() is for card pre-linked dai_link. * * Image * * card * - rtd(A) * - rtd(A) */ for_each_card_prelinks(card, i, dai_link) { ret = soc_bind_dai_link(card, dai_link); ... } ... /* * (2) Connect card pre-linked dai_link to card list * * Connect all card pre-linked dai_link to *card list*. * Here, (A) means from card pre-linked. * * Image * * card card list * - rtd(A) - dai_link(A) * - rtd(A) - dai_link(A) * - ... - ... */ for_each_card_prelinks(card, i, dai_link) { ret = snd_soc_add_dai_link(card, dai_link); ... } ... /* * (3) Probe binded component * * Each rtd has many components. * Here probes each rtd connected components. * rtd(A) in Image is the probe target. * * During this component probe, topology may add new dai_link to * *card list* by using snd_soc_add_dai_link() which is * used at (2). * Here, (B) means from topology * * Image * * card card list * - rtd(A) - dai_link(A) * - rtd(A) - dai_link(A) * - ... - ... * - dai_link(B) * - dai_link(B) */ ret = soc_probe_link_components(card); ... /* * (4) Bind dai_link again * * Bind dai_link again for topology. * Note, (1) used for_each_card_prelinks(), * here is using for_each_card_links() * * This means from card list. * As Image indicating, it has dai_link(A) (from card pre-link) * and dai_link(B) (from topology). * main target here is dai_link(B). * soc_bind_dai_link() ignores already used * dai_link (= dai_link(A)) * * Image * * card card list * - rtd(A) - dai_link(A) * - rtd(A) - dai_link(A) * - ... - ... * - rtd(B) - dai_link(B) * - rtd(B) - dai_link(B) */ for_each_card_links(card, dai_link) { ret = soc_bind_dai_link(card, dai_link); ... } ... } As you see above, it is doing very complex method. The problem is binding dai_link via "card pre-linked" (= (1)) and "topology added dai_link" (= (3)) are separated. The code can be simple if we can bind dai_link when dai_link is connected to *card list*. This patch do it. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/878sou3jnn.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3cc36c2d99da..e8ff6f2f58ba 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1409,6 +1409,8 @@ EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync); int snd_soc_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { + int ret; + if (dai_link->dobj.type && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { dev_err(card->dev, "Invalid dai link type %d\n", @@ -1424,6 +1426,10 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, if (dai_link->dobj.type && card->add_dai_link) card->add_dai_link(card, dai_link); + ret = soc_bind_dai_link(card, dai_link); + if (ret < 0) + return ret; + /* see for_each_card_links */ list_add_tail(&dai_link->list, &card->dai_link_list); @@ -1996,13 +2002,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* check whether any platform is ignore machine FE and using topology */ soc_check_tplg_fes(card); - /* bind DAIs */ - for_each_card_prelinks(card, i, dai_link) { - ret = soc_bind_dai_link(card, dai_link); - if (ret != 0) - goto probe_end; - } - /* bind aux_devs too */ ret = soc_bind_aux_dev(card); if (ret < 0) @@ -2060,16 +2059,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) goto probe_end; - /* - * Find new DAI links added during probing components and bind them. - * Components with topology may bring new DAIs and DAI links. - */ - for_each_card_links(card, dai_link) { - ret = soc_bind_dai_link(card, dai_link); - if (ret) - goto probe_end; - } - /* probe all DAI links on this card */ ret = soc_probe_link_dais(card); if (ret < 0) { -- cgit From bc7a9091e5b927ecc20dbb3bc07a5a09783fc27b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:25 +0900 Subject: ASoC: soc-core: add soc_unbind_dai_link() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. ALSA SoC has soc_bind_dai_link(), but its paired soc_unbind_dai_link() is not implemented. More confusable is that soc_remove_pcm_runtimes() which should be soc_unbind_dai_link() is implemented without synchronised to soc_bind_dai_link(). This patch cleanup this unbalance. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/877e4e3jni.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e8ff6f2f58ba..1e8dd19cba24 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -470,14 +470,6 @@ free_rtd: return NULL; } -static void soc_remove_pcm_runtimes(struct snd_soc_card *card) -{ - struct snd_soc_pcm_runtime *rtd, *_rtd; - - for_each_card_rtds_safe(card, rtd, _rtd) - soc_free_pcm_runtime(rtd); -} - struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, const char *dai_link) { @@ -1037,6 +1029,16 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card, return 0; } +static void soc_unbind_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_pcm_runtime *rtd; + + rtd = snd_soc_get_pcm_runtime(card, dai_link->name); + if (rtd) + soc_free_pcm_runtime(rtd); +} + static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -1466,6 +1468,8 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, card->remove_dai_link(card, dai_link); list_del(&dai_link->list); + + soc_unbind_dai_link(card, dai_link); } EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); @@ -1974,8 +1978,6 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) for_each_card_links_safe(card, link, _link) snd_soc_remove_dai_link(card, link); - soc_remove_pcm_runtimes(card); - /* remove auxiliary devices */ soc_remove_aux_devices(card); soc_unbind_aux_dev(card); -- cgit From b8132657990b5a09ad8e1c9e2c8efc20b5f9372a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:30 +0900 Subject: ASoC: soc-core: move snd_soc_lookup_component() This patch moves snd_soc_lookup_component() to upper side. This is prepare for snd_soc_unregister_component() Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/875zjy3jnd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1e8dd19cba24..b71bddb30db1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -356,6 +356,32 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup); +struct snd_soc_component *snd_soc_lookup_component(struct device *dev, + const char *driver_name) +{ + struct snd_soc_component *component; + struct snd_soc_component *ret; + + ret = NULL; + mutex_lock(&client_mutex); + for_each_component(component) { + if (dev != component->dev) + continue; + + if (driver_name && + (driver_name != component->driver->name) && + (strcmp(component->driver->name, driver_name) != 0)) + continue; + + ret = component; + break; + } + mutex_unlock(&client_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_lookup_component); + struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, const char *dai_link, int stream) { @@ -2889,32 +2915,6 @@ void snd_soc_unregister_component(struct device *dev) } EXPORT_SYMBOL_GPL(snd_soc_unregister_component); -struct snd_soc_component *snd_soc_lookup_component(struct device *dev, - const char *driver_name) -{ - struct snd_soc_component *component; - struct snd_soc_component *ret; - - ret = NULL; - mutex_lock(&client_mutex); - for_each_component(component) { - if (dev != component->dev) - continue; - - if (driver_name && - (driver_name != component->driver->name) && - (strcmp(component->driver->name, driver_name) != 0)) - continue; - - ret = component; - break; - } - mutex_unlock(&client_mutex); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_lookup_component); - /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname) -- cgit From 5bd7e08b3c5f3924259643e1f413e10ca6c97634 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:35 +0900 Subject: ASoC: soc-core: tidyup snd_soc_lookup_component() snd_soc_lookup_component() is using mix of continue and break in the same loop. It is odd. This patch cleanup it. Reported-by: Pierre-Louis Bossart Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/874kzi3jn8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b71bddb30db1..acbaed4e4e9d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -360,25 +360,22 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev, const char *driver_name) { struct snd_soc_component *component; - struct snd_soc_component *ret; + struct snd_soc_component *found_component; - ret = NULL; + found_component = NULL; mutex_lock(&client_mutex); for_each_component(component) { - if (dev != component->dev) - continue; - - if (driver_name && - (driver_name != component->driver->name) && - (strcmp(component->driver->name, driver_name) != 0)) - continue; - - ret = component; - break; + if ((dev == component->dev) && + (!driver_name || + (driver_name == component->driver->name) || + (strcmp(component->driver->name, driver_name) == 0))) { + found_component = component; + break; + } } mutex_unlock(&client_mutex); - return ret; + return found_component; } EXPORT_SYMBOL_GPL(snd_soc_lookup_component); -- cgit From 486c7978ff665eb763f70cc9477e0de6326e1c41 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:39 +0900 Subject: ASoC: soc-core: add snd_soc_del_component_unlocked() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and is difficult to debug. Now ALSA SoC has snd_soc_add_component(), but there is no paired snd_soc_del_component(). Thus, snd_soc_unregister_component() is calling cleanup function randomly. it is difficult to read. This patch adds missing snd_soc_del_component_unlocked() and balance up code. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/8736f23jn4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index acbaed4e4e9d..e91325b688f2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2764,12 +2764,7 @@ static void snd_soc_component_add(struct snd_soc_component *component) mutex_unlock(&client_mutex); } -static void snd_soc_component_cleanup(struct snd_soc_component *component) -{ - snd_soc_unregister_dais(component); -} - -static void snd_soc_component_del_unlocked(struct snd_soc_component *component) +static void snd_soc_component_del(struct snd_soc_component *component) { struct snd_soc_card *card = component->card; @@ -2823,6 +2818,12 @@ static void snd_soc_try_rebind_card(void) list_del(&card->list); } +static void snd_soc_del_component_unlocked(struct snd_soc_component *component) +{ + snd_soc_unregister_dais(component); + snd_soc_component_del(component); +} + int snd_soc_add_component(struct device *dev, struct snd_soc_component *component, const struct snd_soc_component_driver *component_driver, @@ -2855,7 +2856,7 @@ int snd_soc_add_component(struct device *dev, return 0; err_cleanup: - snd_soc_component_cleanup(component); + snd_soc_del_component_unlocked(component); err_free: return ret; } @@ -2893,15 +2894,12 @@ static int __snd_soc_unregister_component(struct device *dev) if (dev != component->dev) continue; - snd_soc_component_del_unlocked(component); + snd_soc_del_component_unlocked(component); found = 1; break; } mutex_unlock(&client_mutex); - if (found) - snd_soc_component_cleanup(component); - return found; } -- cgit From b18768f56162964f70bbb9119dba59a947d7d577 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:45 +0900 Subject: ASoC: soc-core: remove snd_soc_component_add/del() soc-core has snd_soc_add_component(), snd_soc_component_add(), snd_soc_del_component(), snd_soc_component_del(). These are very confusing naming. snd_soc_component_xxx() are called from snd_soc_xxx_component(), and these are very small. Let's merge these into snd_soc_xxx_component(), and remove snd_soc_component_xxx(). Reported-by: Pierre-Louis Bossart Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/871rum3jmy.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 58 ++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e91325b688f2..bb0592159414 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2746,34 +2746,6 @@ EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); #endif -static void snd_soc_component_add(struct snd_soc_component *component) -{ - mutex_lock(&client_mutex); - - if (!component->driver->write && !component->driver->read) { - if (!component->regmap) - component->regmap = dev_get_regmap(component->dev, - NULL); - if (component->regmap) - snd_soc_component_setup_regmap(component); - } - - /* see for_each_component */ - list_add(&component->list, &component_list); - - mutex_unlock(&client_mutex); -} - -static void snd_soc_component_del(struct snd_soc_component *component) -{ - struct snd_soc_card *card = component->card; - - if (card) - snd_soc_unbind_card(card, false); - - list_del(&component->list); -} - #define ENDIANNESS_MAP(name) \ (SNDRV_PCM_FMTBIT_##name##LE | SNDRV_PCM_FMTBIT_##name##BE) static u64 endianness_format_map[] = { @@ -2820,8 +2792,14 @@ static void snd_soc_try_rebind_card(void) static void snd_soc_del_component_unlocked(struct snd_soc_component *component) { + struct snd_soc_card *card = component->card; + snd_soc_unregister_dais(component); - snd_soc_component_del(component); + + if (card) + snd_soc_unbind_card(card, false); + + list_del(&component->list); } int snd_soc_add_component(struct device *dev, @@ -2833,6 +2811,8 @@ int snd_soc_add_component(struct device *dev, int ret; int i; + mutex_lock(&client_mutex); + ret = snd_soc_component_initialize(component, component_driver, dev); if (ret) goto err_free; @@ -2850,14 +2830,26 @@ int snd_soc_add_component(struct device *dev, goto err_cleanup; } - snd_soc_component_add(component); - snd_soc_try_rebind_card(); + if (!component->driver->write && !component->driver->read) { + if (!component->regmap) + component->regmap = dev_get_regmap(component->dev, + NULL); + if (component->regmap) + snd_soc_component_setup_regmap(component); + } - return 0; + /* see for_each_component */ + list_add(&component->list, &component_list); err_cleanup: - snd_soc_del_component_unlocked(component); + if (ret < 0) + snd_soc_del_component_unlocked(component); err_free: + mutex_unlock(&client_mutex); + + if (ret == 0) + snd_soc_try_rebind_card(); + return ret; } EXPORT_SYMBOL_GPL(snd_soc_add_component); -- cgit From ac6a4dd3e9f09697ab6a1774d7ab6a34e7ab36fa Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:51 +0900 Subject: ASoC: soc-core: use snd_soc_lookup_component() at snd_soc_unregister_component() snd_soc_unregister_component() is now finding component manually, but we already have snd_soc_lookup_component() to find component; Let's use existing function. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87zhha252c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bb0592159414..0ce333669138 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2876,29 +2876,19 @@ EXPORT_SYMBOL_GPL(snd_soc_register_component); * * @dev: The device to unregister */ -static int __snd_soc_unregister_component(struct device *dev) +void snd_soc_unregister_component(struct device *dev) { struct snd_soc_component *component; - int found = 0; mutex_lock(&client_mutex); - for_each_component(component) { - if (dev != component->dev) - continue; + while (1) { + component = snd_soc_lookup_component(dev, NULL); + if (!component) + break; snd_soc_del_component_unlocked(component); - found = 1; - break; } mutex_unlock(&client_mutex); - - return found; -} - -void snd_soc_unregister_component(struct device *dev) -{ - while (__snd_soc_unregister_component(dev)) - ; } EXPORT_SYMBOL_GPL(snd_soc_unregister_component); -- cgit From daf7737335bf555abf14031530fe8e47b46b373a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:46:55 +0900 Subject: ASoC: soc-core: move snd_soc_register_dai() This patch moves snd_soc_register_dai() next to snd_soc_register_dais(). This is prepare for snd_soc_register_dais() cleanup. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87y2wu2528.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 72 ++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0ce333669138..fb5f01497498 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2597,42 +2597,6 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, return dai; } -/** - * snd_soc_register_dais - Register a DAI with the ASoC core - * - * @component: The component the DAIs are registered for - * @dai_drv: DAI driver to use for the DAIs - * @count: Number of DAIs - */ -static int snd_soc_register_dais(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, - size_t count) -{ - struct device *dev = component->dev; - struct snd_soc_dai *dai; - unsigned int i; - int ret; - - dev_dbg(dev, "ASoC: dai register %s #%zu\n", dev_name(dev), count); - - for (i = 0; i < count; i++) { - - dai = soc_add_dai(component, dai_drv + i, count == 1 && - !component->driver->non_legacy_dai_naming); - if (dai == NULL) { - ret = -ENOMEM; - goto err; - } - } - - return 0; - -err: - snd_soc_unregister_dais(component); - - return ret; -} - /** * snd_soc_register_dai - Register a DAI dynamically & create its widgets * @@ -2676,6 +2640,42 @@ int snd_soc_register_dai(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(snd_soc_register_dai); +/** + * snd_soc_register_dais - Register a DAI with the ASoC core + * + * @component: The component the DAIs are registered for + * @dai_drv: DAI driver to use for the DAIs + * @count: Number of DAIs + */ +static int snd_soc_register_dais(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv, + size_t count) +{ + struct device *dev = component->dev; + struct snd_soc_dai *dai; + unsigned int i; + int ret; + + dev_dbg(dev, "ASoC: dai register %s #%zu\n", dev_name(dev), count); + + for (i = 0; i < count; i++) { + + dai = soc_add_dai(component, dai_drv + i, count == 1 && + !component->driver->non_legacy_dai_naming); + if (dai == NULL) { + ret = -ENOMEM; + goto err; + } + } + + return 0; + +err: + snd_soc_unregister_dais(component); + + return ret; +} + static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev) { -- cgit From 3f6674ae13a1e498f249b0255659bfc4f692a7e0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:00 +0900 Subject: ASoC: soc-core: move snd_soc_unregister_dais() This patch moves snd_soc_unregister_dais() next to snd_soc_register_dais(). This is prepare for snd_soc_register_dais() cleanup Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87woce2524.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fb5f01497498..c803447fe639 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2532,22 +2532,6 @@ static inline char *fmt_multiple_name(struct device *dev, return devm_kstrdup(dev, dai_drv->name, GFP_KERNEL); } -/** - * snd_soc_unregister_dai - Unregister DAIs from the ASoC core - * - * @component: The component for which the DAIs should be unregistered - */ -static void snd_soc_unregister_dais(struct snd_soc_component *component) -{ - struct snd_soc_dai *dai, *_dai; - - for_each_component_dais_safe(component, dai, _dai) { - dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", - dai->name); - list_del(&dai->list); - } -} - /* Create a DAI and add it to the component's DAI list */ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, @@ -2640,6 +2624,22 @@ int snd_soc_register_dai(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(snd_soc_register_dai); +/** + * snd_soc_unregister_dai - Unregister DAIs from the ASoC core + * + * @component: The component for which the DAIs should be unregistered + */ +static void snd_soc_unregister_dais(struct snd_soc_component *component) +{ + struct snd_soc_dai *dai, *_dai; + + for_each_component_dais_safe(component, dai, _dai) { + dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", + dai->name); + list_del(&dai->list); + } +} + /** * snd_soc_register_dais - Register a DAI with the ASoC core * -- cgit From e11381f38f34789b374880c4a149e25e8d7f0cfd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:04 +0900 Subject: ASoC: soc-core: add snd_soc_unregister_dai() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and is difficult to debug. This patch adds missing soc_del_dai() and snd_soc_unregister_dai(). Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87v9ry251z.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c803447fe639..38199cd7ce97 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2532,6 +2532,12 @@ static inline char *fmt_multiple_name(struct device *dev, return devm_kstrdup(dev, dai_drv->name, GFP_KERNEL); } +static void soc_del_dai(struct snd_soc_dai *dai) +{ + dev_dbg(dai->dev, "ASoC: Unregistered DAI '%s'\n", dai->name); + list_del(&dai->list); +} + /* Create a DAI and add it to the component's DAI list */ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, @@ -2581,6 +2587,12 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, return dai; } +void snd_soc_unregister_dai(struct snd_soc_dai *dai) +{ + soc_del_dai(dai); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); + /** * snd_soc_register_dai - Register a DAI dynamically & create its widgets * @@ -2633,11 +2645,8 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) { struct snd_soc_dai *dai, *_dai; - for_each_component_dais_safe(component, dai, _dai) { - dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", - dai->name); - list_del(&dai->list); - } + for_each_component_dais_safe(component, dai, _dai) + snd_soc_unregister_dai(dai); } /** -- cgit From 5d07519703bc2f0bf19d33652401552a480d68b8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:09 +0900 Subject: ASoC: soc-core: have legacy_dai_naming at snd_soc_register_dai() ALSA SoC has 2 functions. snd_soc_register_dai() is used from topology snd_soc_register_dais() is used from snd_soc_add_component() In general, people think like _dai() is called from _dais() with for loop. But in reality, these are very similar but different implementation. We shouldn't have duplicated and confusing implementation. snd_soc_register_dai() is now used from topology. But to reduce duplicated code, it should be used from _dais(), too. To prepare it, this patch adds missing parameter legacy_dai_naming to snd_soc_register_dai(). Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87tv7i251u.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 +++-- sound/soc/soc-topology.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 38199cd7ce97..6f4933f13b08 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2604,7 +2604,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); * will be freed in the component cleanup. */ int snd_soc_register_dai(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv) + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); @@ -2618,7 +2619,7 @@ int snd_soc_register_dai(struct snd_soc_component *component, } lockdep_assert_held(&client_mutex); - dai = soc_add_dai(component, dai_drv, false); + dai = soc_add_dai(component, dai_drv, legacy_dai_naming); if (!dai) return -ENOMEM; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 0fd032914a31..b6e145627ab4 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1842,7 +1842,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list); /* register the DAI to the component */ - return snd_soc_register_dai(tplg->comp, dai_drv); + return snd_soc_register_dai(tplg->comp, dai_drv, false); } static void set_link_flags(struct snd_soc_dai_link *link, -- cgit From e443c20593de9f8efd9b2935ed40eb0bbacce30b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:14 +0900 Subject: ASoC: soc-core: don't call snd_soc_dapm_new_dai_widgets() at snd_soc_register_dai() ALSA SoC has 2 functions. snd_soc_register_dai() is used from topology snd_soc_register_dais() is used from snd_soc_add_component() In general, people think like _dai() is called from _dais() with for loop. But in reality, these are very similar but different implementation. We shouldn't have duplicated and confusing implementation. snd_soc_register_dai() is now used from topology. But to reduce duplicated code, it should be used from _dais(), too. Because of topology side specific reason, it is calling snd_soc_dapm_new_dai_widgets(), but it is not needed _dais() side. This patch factorizes snd_soc_register_dai() to topology / _dais() common part, and topology specific part. And do topology specific part at soc-topology. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87sgn2251p.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 29 +++++------------------------ sound/soc/soc-topology.c | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6f4933f13b08..55b13c0037d2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2603,37 +2603,18 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); * These DAIs's widgets will be freed in the card cleanup and the DAIs * will be freed in the component cleanup. */ -int snd_soc_register_dai(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, - bool legacy_dai_naming) +struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming) { - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - struct snd_soc_dai *dai; - int ret; - if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { dev_err(component->dev, "Invalid dai type %d\n", dai_drv->dobj.type); - return -EINVAL; + return NULL; } lockdep_assert_held(&client_mutex); - dai = soc_add_dai(component, dai_drv, legacy_dai_naming); - if (!dai) - return -ENOMEM; - - /* - * Create the DAI widgets here. After adding DAIs, topology may - * also add routes that need these widgets as source or sink. - */ - ret = snd_soc_dapm_new_dai_widgets(dapm, dai); - if (ret != 0) { - dev_err(component->dev, - "Failed to create DAI widgets %d\n", ret); - } - - return ret; + return soc_add_dai(component, dai_drv, legacy_dai_naming); } EXPORT_SYMBOL_GPL(snd_soc_register_dai); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b6e145627ab4..81d2af000a5c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1800,6 +1800,9 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, struct snd_soc_dai_driver *dai_drv; struct snd_soc_pcm_stream *stream; struct snd_soc_tplg_stream_caps *caps; + struct snd_soc_dai *dai; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(tplg->comp); int ret; dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL); @@ -1842,7 +1845,19 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list); /* register the DAI to the component */ - return snd_soc_register_dai(tplg->comp, dai_drv, false); + dai = snd_soc_register_dai(tplg->comp, dai_drv, false); + if (!dai) + return -ENOMEM; + + /* Create the DAI widgets here */ + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(dai->dev, "Failed to create DAI widgets %d\n", ret); + snd_soc_unregister_dai(dai); + return ret; + } + + return ret; } static void set_link_flags(struct snd_soc_dai_link *link, -- cgit From 71cb85f5e9da4aa3ab62020389b513275121083d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:18 +0900 Subject: ASoC: soc-core: call snd_soc_register_dai() from snd_soc_register_dais() ALSA SoC has 2 functions. snd_soc_register_dai() is used from topology snd_soc_register_dais() is used from snd_soc_add_component() In general, people think like _dai() is called from _dais() with for loop. But in reality, these are very similar but different implementation. We shouldn't have duplicated and confusing implementation. This patch calls snd_soc_register_dai() from snd_soc_register_dais() Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87r22m251l.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 55b13c0037d2..86c45f751598 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2607,12 +2607,16 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, bool legacy_dai_naming) { - if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { - dev_err(component->dev, "Invalid dai type %d\n", - dai_drv->dobj.type); + struct device *dev = component->dev; + + if (dai_drv->dobj.type && + dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { + dev_err(dev, "Invalid dai type %d\n", dai_drv->dobj.type); return NULL; } + dev_dbg(dev, "ASoC: dai register %s\n", dai_drv->name); + lockdep_assert_held(&client_mutex); return soc_add_dai(component, dai_drv, legacy_dai_naming); } @@ -2642,16 +2646,12 @@ static int snd_soc_register_dais(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, size_t count) { - struct device *dev = component->dev; struct snd_soc_dai *dai; unsigned int i; int ret; - dev_dbg(dev, "ASoC: dai register %s #%zu\n", dev_name(dev), count); - for (i = 0; i < count; i++) { - - dai = soc_add_dai(component, dai_drv + i, count == 1 && + dai = snd_soc_register_dai(component, dai_drv + i, count == 1 && !component->driver->non_legacy_dai_naming); if (dai == NULL) { ret = -ENOMEM; -- cgit From 237d19080cd37e1ccf5462e63d8577d713f6da46 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:22 +0900 Subject: ASoC: soc-core: remove topology specific operation soc-core has some API which is used from topology, but it is doing topology specific operation at soc-core. soc-core should care about core things, and topology should care about topology things, otherwise, it is very confusable. For example topology type is not related to soc-core, it is topology side issue. This patch removes meaningless check from soc-core. This patch keeps extra initialization/destruction at snd_soc_add_dai_link() / snd_soc_remove_dai_link() which were for topology. From this patch, non-topology card can use it. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87pni6251h.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 86c45f751598..cc596871ba7f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1436,19 +1436,12 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, { int ret; - if (dai_link->dobj.type - && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { - dev_err(card->dev, "Invalid dai link type %d\n", - dai_link->dobj.type); - return -EINVAL; - } - lockdep_assert_held(&client_mutex); + /* * Notify the machine driver for extra initialization - * on the link created by topology. */ - if (dai_link->dobj.type && card->add_dai_link) + if (card->add_dai_link) card->add_dai_link(card, dai_link); ret = soc_bind_dai_link(card, dai_link); @@ -1475,19 +1468,12 @@ EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); void snd_soc_remove_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - if (dai_link->dobj.type - && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { - dev_err(card->dev, "Invalid dai link type %d\n", - dai_link->dobj.type); - return; - } - lockdep_assert_held(&client_mutex); + /* * Notify the machine driver for extra destruction - * on the link created by topology. */ - if (dai_link->dobj.type && card->remove_dai_link) + if (card->remove_dai_link) card->remove_dai_link(card, dai_link); list_del(&dai_link->list); @@ -2609,12 +2595,6 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, { struct device *dev = component->dev; - if (dai_drv->dobj.type && - dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { - dev_err(dev, "Invalid dai type %d\n", dai_drv->dobj.type); - return NULL; - } - dev_dbg(dev, "ASoC: dai register %s\n", dai_drv->name); lockdep_assert_held(&client_mutex); -- cgit From 08422d2c559d1119b17c14e79b2d8ff89f46a356 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 09:01:35 +0100 Subject: ALSA: memalloc: Allow NULL device for SNDRV_DMA_TYPE_CONTINUOUS type Currently we pass the artificial device pointer to the allocation helper in the case of SNDRV_DMA_TYPE_CONTINUOUS for passing the GFP flags. But all common cases are the allocations with GFP_KERNEL, and it's messy to put this in each place. In this patch, the memalloc core helper is changed to accept the NULL device pointer and it treats as the default mode, GFP_KERNEL, so that all callers can omit the complex argument but just leave NULL. Link: https://lore.kernel.org/r/20191105080138.1260-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 6850d13aa98c..1b1c7620cbda 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -99,6 +99,13 @@ static void snd_free_dev_iram(struct snd_dma_buffer *dmab) * */ +static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev) +{ + if (!dev) + return GFP_KERNEL; + else + return (__force gfp_t)(unsigned long)dev; +} /** * snd_dma_alloc_pages - allocate the buffer area according to the given type @@ -120,8 +127,6 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, return -ENXIO; if (WARN_ON(!dmab)) return -ENXIO; - if (WARN_ON(!device)) - return -EINVAL; dmab->dev.type = type; dmab->dev.dev = device; @@ -129,7 +134,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, switch (type) { case SNDRV_DMA_TYPE_CONTINUOUS: dmab->area = alloc_pages_exact(size, - (__force gfp_t)(unsigned long)device); + snd_mem_get_gfp_flags(device)); dmab->addr = 0; break; #ifdef CONFIG_HAS_DMA -- cgit From 1fe7f397cfe229494a88c6496b53ba532d4d4a42 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 09:01:36 +0100 Subject: ALSA: memalloc: Add vmalloc buffer allocation support This patch adds the vmalloc buffer support to ALSA memalloc core. A new type, SNDRV_DMA_TYPE_VMALLOC was added. The vmalloc buffer has been already supported in the PCM via a few own helper functions, but the user sometimes get confused and misuse them. With this patch, the whole buffer management is integrated into the memalloc core, so they can be used in a sole common way. Link: https://lore.kernel.org/r/20191105080138.1260-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 1b1c7620cbda..a83553fbedf0 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -10,6 +10,7 @@ #include #include #include +#include #ifdef CONFIG_X86 #include #endif @@ -99,10 +100,11 @@ static void snd_free_dev_iram(struct snd_dma_buffer *dmab) * */ -static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev) +static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev, + gfp_t default_gfp) { if (!dev) - return GFP_KERNEL; + return default_gfp; else return (__force gfp_t)(unsigned long)dev; } @@ -123,6 +125,8 @@ static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev) int snd_dma_alloc_pages(int type, struct device *device, size_t size, struct snd_dma_buffer *dmab) { + gfp_t gfp; + if (WARN_ON(!size)) return -ENXIO; if (WARN_ON(!dmab)) @@ -133,8 +137,13 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->bytes = 0; switch (type) { case SNDRV_DMA_TYPE_CONTINUOUS: - dmab->area = alloc_pages_exact(size, - snd_mem_get_gfp_flags(device)); + gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL); + dmab->area = alloc_pages_exact(size, gfp); + dmab->addr = 0; + break; + case SNDRV_DMA_TYPE_VMALLOC: + gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM); + dmab->area = __vmalloc(size, gfp, PAGE_KERNEL); dmab->addr = 0; break; #ifdef CONFIG_HAS_DMA @@ -220,6 +229,9 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) case SNDRV_DMA_TYPE_CONTINUOUS: free_pages_exact(dmab->area, dmab->bytes); break; + case SNDRV_DMA_TYPE_VMALLOC: + vfree(dmab->area); + break; #ifdef CONFIG_HAS_DMA #ifdef CONFIG_GENERIC_ALLOCATOR case SNDRV_DMA_TYPE_DEV_IRAM: -- cgit From 7e8edae39fd1f880f098612c991cf6d0f646c20d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 09:01:37 +0100 Subject: ALSA: pcm: Handle special page mapping in the default mmap handler When a driver needs to deal with a special buffer like a SG or a vmalloc buffer, it has to set up the PCM page ops explicitly for the corresponding helper function. This is rather error-prone and many people forgot or incorrectly used it. For simplifying the call patterns and avoiding such a potential bug, this patch enhances the PCM default mmap handler to check the (pre-)allocated buffer type and handles the page gracefully depending on the buffer type. If the PCM page ops is given, the ops is still used in a higher priority. The new code path is only for the default (NULL page ops) case. Link: https://lore.kernel.org/r/20191105080138.1260-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index c3a139436ac2..998c63192ae4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -3335,7 +3336,18 @@ static inline struct page * snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) { void *vaddr = substream->runtime->dma_area + ofs; - return virt_to_page(vaddr); + + switch (substream->dma_buffer.dev.type) { +#ifdef CONFIG_SND_DMA_SGBUF + case SNDRV_DMA_TYPE_DEV_SG: + case SNDRV_DMA_TYPE_DEV_UC_SG: + return snd_pcm_sgbuf_ops_page(substream, ofs); +#endif /* CONFIG_SND_DMA_SGBUF */ + case SNDRV_DMA_TYPE_VMALLOC: + return vmalloc_to_page(vaddr); + default: + return virt_to_page(vaddr); + } } /* -- cgit From a55eaf177a36f7789eec0985a7edd00fe7353d90 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 20:10:06 +0100 Subject: ALSA: pcm: Warn if doubly preallocated Warn if snd_pcm_lib_preallocate_pages*() is applied to the stream that has already the preallocated buffers and skip the allocation. It's a clearly a driver bug. Link: https://lore.kernel.org/r/20191105191007.18150-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_memory.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 7600dcdf5fd4..19407f79b638 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -221,6 +221,8 @@ void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, int type, struct device *data, size_t size, size_t max) { + if (snd_BUG_ON(substream->dma_buffer.dev.type)) + return; substream->dma_buffer.dev.type = type; substream->dma_buffer.dev.dev = data; snd_pcm_lib_preallocate_pages1(substream, size, max); -- cgit From d39789912f150b66515ccda7ed00bba828a334d4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 20:10:07 +0100 Subject: ALSA: pcm: Create proc files only for non-empty preallocations It makes little sense to create prealloc proc files for streams that have the zero max size, which is a typical case for vmalloc buffers. Skip the proc file creations to save resources in such a case. Link: https://lore.kernel.org/r/20191105191007.18150-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 19407f79b638..17ee361ce791 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -203,7 +203,8 @@ static void snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, if (substream->dma_buffer.bytes > 0) substream->buffer_bytes_max = substream->dma_buffer.bytes; substream->dma_max = max; - preallocate_info_init(substream); + if (max > 0) + preallocate_info_init(substream); } -- cgit From 8fd9da750e76c321cd0a781c89a0d70cc399b22d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:33 +0100 Subject: ALSA: drivers: Remove superfluous snd_dma_continuous_data() The recent change (commit 08422d2c559d: "ALSA: memalloc: Allow NULL device for SNDRV_DMA_TYPE_CONTINUOUS type") made the PCM preallocation helper accepting NULL as the device pointer for the default usage. Drop the snd_dma_continuous_data() usage that became superfluous from the callers. Link: https://lore.kernel.org/r/20191105151856.10785-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 2 +- sound/drivers/ml403-ac97cr.c | 2 +- sound/drivers/pcsp/pcsp_lib.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index aee7c04d49e5..022a0db692e0 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -702,7 +702,7 @@ static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device, if (!fake_buffer) { snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 0, 64*1024); } return 0; diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c index a3c1c064d1b5..70a6d1832698 100644 --- a/sound/drivers/ml403-ac97cr.c +++ b/sound/drivers/ml403-ac97cr.c @@ -1242,7 +1242,7 @@ snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device) ml403_ac97cr->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 64 * 1024, 128 * 1024); return 0; diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index 8f0f05bbc081..f91316bf01cb 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -352,8 +352,8 @@ int snd_pcsp_new_pcm(struct snd_pcsp *chip) snd_pcm_lib_preallocate_pages_for_all(chip->pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data - (GFP_KERNEL), PCSP_BUFFER_SIZE, + NULL, + PCSP_BUFFER_SIZE, PCSP_BUFFER_SIZE); return 0; -- cgit From 987334266d087a4974c73f4a071bc24596f545aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:34 +0100 Subject: ALSA: mips: Remove superfluous snd_dma_continuous_data() The recent change (commit 08422d2c559d: "ALSA: memalloc: Allow NULL device for SNDRV_DMA_TYPE_CONTINUOUS type") made the PCM preallocation helper accepting NULL as the device pointer for the default usage. Drop the snd_dma_continuous_data() usage that became superfluous from the callers. Link: https://lore.kernel.org/r/20191105151856.10785-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 6676bcbd769f..c9e060939708 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -741,8 +741,7 @@ static int hal2_pcm_create(struct snd_hal2 *hal2) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &hal2_capture_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - 0, 1024 * 1024); + NULL, 0, 1024 * 1024); return 0; } -- cgit From 1422bc5001a98f5be618a4abc62325f8a9310941 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:35 +0100 Subject: ALSA: rme32: Remove superfluous snd_dma_continuous_data() The recent change (commit 08422d2c559d: "ALSA: memalloc: Allow NULL device for SNDRV_DMA_TYPE_CONTINUOUS type") made the PCM preallocation helper accepting NULL as the device pointer for the default usage. Drop the snd_dma_continuous_data() usage that became superfluous from the callers. Link: https://lore.kernel.org/r/20191105151856.10785-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 40cc6ca88f7b..58a4b8df25d4 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1375,7 +1375,7 @@ static int snd_rme32_create(struct rme32 *rme32) snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme32_capture_spdif_fd_ops); snd_pcm_lib_preallocate_pages_for_all(rme32->spdif_pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 0, RME32_MID_BUFFER_SIZE); rme32->spdif_pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; } else { @@ -1407,7 +1407,7 @@ static int snd_rme32_create(struct rme32 *rme32) snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme32_capture_adat_fd_ops); snd_pcm_lib_preallocate_pages_for_all(rme32->adat_pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 0, RME32_MID_BUFFER_SIZE); rme32->adat_pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; } else { -- cgit From a1aef4881cf1781e3d5c5c07df1b8774d3fe2def Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:36 +0100 Subject: ALSA: sh: Remove superfluous snd_dma_continuous_data() The recent change (commit 08422d2c559d: "ALSA: memalloc: Allow NULL device for SNDRV_DMA_TYPE_CONTINUOUS type") made the PCM preallocation helper accepting NULL as the device pointer for the default usage. Drop the snd_dma_continuous_data() usage that became superfluous from the callers. Link: https://lore.kernel.org/r/20191105151856.10785-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/sh/aica.c | 2 +- sound/sh/sh_dac_audio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 52e9cfb4f819..bf1fb0d8a930 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -443,7 +443,7 @@ static int __init snd_aicapcmchip(struct snd_card_aica /* Allocate the DMA buffers */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, AICA_BUFFER_SIZE, AICA_BUFFER_SIZE); return 0; diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c index ed877a138965..f9e36abc98ac 100644 --- a/sound/sh/sh_dac_audio.c +++ b/sound/sh/sh_dac_audio.c @@ -268,7 +268,7 @@ static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device) /* buffer size=48K */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 48 * 1024, 48 * 1024); -- cgit From 0382e4e18fafcaea75ffab85838ef2110fac1668 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:37 +0100 Subject: ALSA: sparc: Remove superfluous snd_dma_continuous_data() The recent change (commit 08422d2c559d: "ALSA: memalloc: Allow NULL device for SNDRV_DMA_TYPE_CONTINUOUS type") made the PCM preallocation helper accepting NULL as the device pointer for the default usage. Drop the snd_dma_continuous_data() usage that became superfluous from the callers. Link: https://lore.kernel.org/r/20191105151856.10785-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/sparc/amd7930.c | 2 +- sound/sparc/dbri.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 441222c8e223..d4b8ccc61dc2 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -777,7 +777,7 @@ static int snd_amd7930_pcm(struct snd_amd7930 *amd) amd->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 64*1024, 64*1024); return 0; diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 6e065d44060e..4911103421ff 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2249,7 +2249,7 @@ static int snd_dbri_pcm(struct snd_card *card) strcpy(pcm->name, card->shortname); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 64 * 1024, 64 * 1024); return 0; } -- cgit From 0af0a4fec0c48d591a3788cb6c08b21a17201dd3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:38 +0100 Subject: ALSA: usb: Remove superfluous snd_dma_continuous_data() The recent change (commit 08422d2c559d: "ALSA: memalloc: Allow NULL device for SNDRV_DMA_TYPE_CONTINUOUS type") made the PCM preallocation helper accepting NULL as the device pointer for the default usage. Drop the snd_dma_continuous_data() usage that became superfluous from the callers. Link: https://lore.kernel.org/r/20191105151856.10785-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/line6/pcm.c | 4 +--- sound/usb/usx2y/usbusx2yaudio.c | 4 ++-- sound/usb/usx2y/usx2yhwdeppcm.c | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index f70211e6b174..9c437c716cfd 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -502,9 +502,7 @@ static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret) /* pre-allocation of buffers */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data - (GFP_KERNEL), 64 * 1024, - 128 * 1024); + NULL, 64 * 1024, 128 * 1024); return 0; } diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 89fa287678fc..25a0939f410a 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -970,13 +970,13 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, if (playback_endpoint) { snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 64*1024, 128*1024); } snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 64*1024, 128*1024); usX2Y(card)->pcm_devs++; diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index ac8960b6b299..997493e839ee 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -728,11 +728,11 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card) sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio"); snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 64*1024, 128*1024); snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, 64*1024, 128*1024); return 0; -- cgit From 1158e89c9d8f5e676870ab0a729de16ac39e59af Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:39 +0100 Subject: ALSA: 6fire: Drop the dead code A few error handling code was forgotten where it never reaches. Drop it. Link: https://lore.kernel.org/r/20191105151856.10785-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/6fire/pcm.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'sound') diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index 88ac1c4ee163..4ded944e5d5d 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -660,13 +660,6 @@ int usb6fire_pcm_init(struct sfire_chip *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops); - if (ret) { - usb6fire_pcm_buffers_destroy(rt); - kfree(rt); - dev_err(&chip->dev->dev, - "error preallocating pcm buffers.\n"); - return ret; - } rt->instance = pcm; chip->pcm = rt; -- cgit From b315997d7c2295b2b32cb661a584208ab05ffaea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:40 +0100 Subject: ALSA: usb-audio: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Also, since the SG-buffer-specific PCM ops becomes identical with the normal PCM ops, unify them again to the single ops, too. Link: https://lore.kernel.org/r/20191105151856.10785-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 50 ++++++++------------------------------------------ 1 file changed, 8 insertions(+), 42 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index ff5ab24f3bd1..9c8930bb00c8 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -785,12 +785,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; - if (snd_usb_use_vmalloc) - ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - else - ret = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); if (ret < 0) goto stop_pipeline; @@ -857,10 +853,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) snd_usb_unlock_shutdown(subs->stream->chip); } - if (snd_usb_use_vmalloc) - return snd_pcm_lib_free_vmalloc_buffer(substream); - else - return snd_pcm_lib_free_pages(substream); + return snd_pcm_lib_free_pages(substream); } /* @@ -1781,7 +1774,6 @@ static const struct snd_pcm_ops snd_usb_playback_ops = { .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_substream_playback_trigger, .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops snd_usb_capture_ops = { @@ -1793,43 +1785,14 @@ static const struct snd_pcm_ops snd_usb_capture_ops = { .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_substream_capture_trigger, .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, -}; - -static const struct snd_pcm_ops snd_usb_playback_dev_ops = { - .open = snd_usb_pcm_open, - .close = snd_usb_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_usb_hw_params, - .hw_free = snd_usb_hw_free, - .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_substream_playback_trigger, - .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - -static const struct snd_pcm_ops snd_usb_capture_dev_ops = { - .open = snd_usb_pcm_open, - .close = snd_usb_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_usb_hw_params, - .hw_free = snd_usb_hw_free, - .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_substream_capture_trigger, - .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream) { const struct snd_pcm_ops *ops; - if (snd_usb_use_vmalloc) - ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? + ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? &snd_usb_playback_ops : &snd_usb_capture_ops; - else - ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? - &snd_usb_playback_dev_ops : &snd_usb_capture_dev_ops; snd_pcm_set_ops(pcm, stream, ops); } @@ -1839,7 +1802,10 @@ void snd_usb_preallocate_buffer(struct snd_usb_substream *subs) struct snd_pcm_substream *s = pcm->streams[subs->direction].substream; struct device *dev = subs->dev->bus->controller; - if (!snd_usb_use_vmalloc) + if (snd_usb_use_vmalloc) + snd_pcm_lib_preallocate_pages(s, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); + else snd_pcm_lib_preallocate_pages(s, SNDRV_DMA_TYPE_DEV_SG, dev, 64*1024, 512*1024); } -- cgit From b29e5ef15115cd77cdd250b7ec4fdb4cb8d40ddd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:41 +0100 Subject: ALSA: aloop: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Link: https://lore.kernel.org/r/20191105151856.10785-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 9ccdad89c288..54f8b17476a1 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -576,8 +576,7 @@ static void loopback_runtime_free(struct snd_pcm_runtime *runtime) static int loopback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(params)); + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } static int loopback_hw_free(struct snd_pcm_substream *substream) @@ -589,7 +588,7 @@ static int loopback_hw_free(struct snd_pcm_substream *substream) mutex_lock(&dpcm->loopback->cable_lock); cable->valid &= ~(1 << substream->stream); mutex_unlock(&dpcm->loopback->cable_lock); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static unsigned int get_cable_index(struct snd_pcm_substream *substream) @@ -765,7 +764,6 @@ static const struct snd_pcm_ops loopback_pcm_ops = { .prepare = loopback_prepare, .trigger = loopback_trigger, .pointer = loopback_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static int loopback_pcm_new(struct loopback *loopback, @@ -780,6 +778,8 @@ static int loopback_pcm_new(struct loopback *loopback, return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_pcm_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); pcm->private_data = loopback; pcm->info_flags = 0; -- cgit From a3f4f2d5d02095d098ff03c4d0bdbae2e53a5bba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:42 +0100 Subject: ALSA: firewire: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Link: https://lore.kernel.org/r/20191105151856.10785-11-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_pcm.c | 9 ++++----- sound/firewire/dice/dice-pcm.c | 11 ++++++----- sound/firewire/digi00x/digi00x-pcm.c | 9 ++++----- sound/firewire/fireface/ff-pcm.c | 9 ++++----- sound/firewire/fireworks/fireworks_pcm.c | 9 ++++----- sound/firewire/isight.c | 8 ++++---- sound/firewire/motu/motu-pcm.c | 9 ++++----- sound/firewire/oxfw/oxfw-pcm.c | 14 ++++++-------- sound/firewire/tascam/tascam-pcm.c | 9 ++++----- 9 files changed, 40 insertions(+), 47 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 1b100159f4c5..d4edd06d32cf 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -214,8 +214,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_bebob *bebob = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -248,7 +247,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&bebob->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int @@ -354,7 +353,6 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, .ack = pcm_capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -366,7 +364,6 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; int err; @@ -380,6 +377,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) "%s PCM", bebob->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); end: return err; } diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index f1848fb39bd0..be79d659eedf 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -266,8 +266,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_dice *dice = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -305,7 +304,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&dice->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int capture_prepare(struct snd_pcm_substream *substream) @@ -417,7 +416,6 @@ int snd_dice_create_pcm(struct snd_dice *dice) .trigger = capture_trigger, .pointer = capture_pointer, .ack = capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -429,7 +427,6 @@ int snd_dice_create_pcm(struct snd_dice *dice) .trigger = playback_trigger, .pointer = playback_pointer, .ack = playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; unsigned int capture, playback; @@ -459,6 +456,10 @@ int snd_dice_create_pcm(struct snd_dice *dice) if (playback > 0) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); + + snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); } return 0; diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 8befc5d2ef22..57cbce4fd836 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -190,8 +190,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_dg00x *dg00x = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -224,7 +223,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&dg00x->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int pcm_capture_prepare(struct snd_pcm_substream *substream) @@ -337,7 +336,6 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, .ack = pcm_capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -349,7 +347,6 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; int err; @@ -363,6 +360,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) "%s PCM", dg00x->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); return 0; } diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index c29f87a65c0f..4e3bd9a2bec0 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -230,8 +230,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_ff *ff = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -264,7 +263,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&ff->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int pcm_capture_prepare(struct snd_pcm_substream *substream) @@ -377,7 +376,6 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff) .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, .ack = pcm_capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops pcm_playback_ops = { .open = pcm_open, @@ -389,7 +387,6 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff) .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; int err; @@ -403,6 +400,8 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff) "%s PCM", ff->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); return 0; } diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 64c1bcf28dfa..e69896d748df 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -250,8 +250,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_efw *efw = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -284,7 +283,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&efw->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int pcm_capture_prepare(struct snd_pcm_substream *substream) @@ -384,7 +383,6 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, .ack = pcm_capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -396,7 +394,6 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; int err; @@ -409,6 +406,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); end: return err; } diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index a16beda7c530..d9f1b962bfef 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -288,8 +288,7 @@ static int isight_hw_params(struct snd_pcm_substream *substream, struct isight *isight = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -337,7 +336,7 @@ static int isight_hw_free(struct snd_pcm_substream *substream) isight_stop_streaming(isight); mutex_unlock(&isight->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int isight_start_streaming(struct isight *isight) @@ -453,7 +452,6 @@ static int isight_create_pcm(struct isight *isight) .prepare = isight_prepare, .trigger = isight_trigger, .pointer = isight_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; int err; @@ -465,6 +463,8 @@ static int isight_create_pcm(struct isight *isight) strcpy(pcm->name, "iSight"); isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; isight->pcm->ops = &ops; + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); return 0; } diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 490408b49157..349b4d09e84f 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -218,8 +218,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_motu *motu = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -252,7 +251,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&motu->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int capture_prepare(struct snd_pcm_substream *substream) @@ -356,7 +355,6 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) .trigger = capture_trigger, .pointer = capture_pointer, .ack = capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -368,7 +366,6 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) .trigger = playback_trigger, .pointer = playback_pointer, .ack = playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; int err; @@ -381,6 +378,8 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); return 0; } diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 74bd1811cec2..9124603edabe 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -239,8 +239,7 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, struct snd_oxfw *oxfw = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -267,8 +266,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, struct snd_oxfw *oxfw = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -303,7 +301,7 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&oxfw->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int pcm_playback_hw_free(struct snd_pcm_substream *substream) { @@ -318,7 +316,7 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&oxfw->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int pcm_capture_prepare(struct snd_pcm_substream *substream) @@ -428,7 +426,6 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, .ack = pcm_capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -440,7 +437,6 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; unsigned int cap = 0; @@ -458,6 +454,8 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); if (cap > 0) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); return 0; } diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index cd45f20ba515..8e9b444c8bff 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -119,8 +119,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_tscm *tscm = substream->private_data; int err; - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; @@ -153,7 +152,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_unlock(&tscm->mutex); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int pcm_capture_prepare(struct snd_pcm_substream *substream) @@ -266,7 +265,6 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, .ack = pcm_capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { .open = pcm_open, @@ -278,7 +276,6 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, .ack = pcm_playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, }; struct snd_pcm *pcm; int err; @@ -292,6 +289,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) "%s PCM", tscm->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); return 0; } -- cgit From 94ce90c562efd4222c1d58c52bb7dc8e2ba5827d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:43 +0100 Subject: ALSA: 6fire: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Link: https://lore.kernel.org/r/20191105151856.10785-12-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/6fire/pcm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index 4ded944e5d5d..cdc5dd7fbe16 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -449,13 +449,13 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) static int usb6fire_pcm_hw_params(struct snd_pcm_substream *alsa_sub, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(alsa_sub, + params_buffer_bytes(hw_params)); } static int usb6fire_pcm_hw_free(struct snd_pcm_substream *alsa_sub) { - return snd_pcm_lib_free_vmalloc_buffer(alsa_sub); + return snd_pcm_lib_free_pages(alsa_sub); } static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) @@ -560,7 +560,6 @@ static const struct snd_pcm_ops pcm_ops = { .prepare = usb6fire_pcm_prepare, .trigger = usb6fire_pcm_trigger, .pointer = usb6fire_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static void usb6fire_pcm_init_urb(struct pcm_urb *urb, @@ -659,6 +658,8 @@ int usb6fire_pcm_init(struct sfire_chip *chip) strcpy(pcm->name, "DMX 6Fire USB"); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); rt->instance = pcm; -- cgit From c7b03852e74dc294d0f09c2c6f3d5e28615ce689 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:44 +0100 Subject: ALSA: caiaq: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Link: https://lore.kernel.org/r/20191105151856.10785-13-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/caiaq/audio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 444bb637ce13..970eb0865ba3 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -170,15 +170,14 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_alloc_vmalloc_buffer(sub, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); } static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) { struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub); deactivate_substream(cdev, sub); - return snd_pcm_lib_free_vmalloc_buffer(sub); + return snd_pcm_lib_free_pages(sub); } /* this should probably go upstream */ @@ -334,7 +333,6 @@ static const struct snd_pcm_ops snd_usb_caiaq_ops = { .prepare = snd_usb_caiaq_pcm_prepare, .trigger = snd_usb_caiaq_pcm_trigger, .pointer = snd_usb_caiaq_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev, @@ -843,6 +841,8 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev) &snd_usb_caiaq_ops); snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_caiaq_ops); + snd_pcm_lib_preallocate_pages_for_all(cdev->pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); cdev->data_cb_info = kmalloc_array(N_URBS, sizeof(struct snd_usb_caiaq_cb_info), -- cgit From d7867ee7d264d4760214de2a1cb10c694d935dab Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:45 +0100 Subject: ALSA: hiface: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Link: https://lore.kernel.org/r/20191105151856.10785-14-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/hiface/pcm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index c406497c5919..e0de71917274 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -418,13 +418,13 @@ static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub) static int hiface_pcm_hw_params(struct snd_pcm_substream *alsa_sub, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(alsa_sub, + params_buffer_bytes(hw_params)); } static int hiface_pcm_hw_free(struct snd_pcm_substream *alsa_sub) { - return snd_pcm_lib_free_vmalloc_buffer(alsa_sub); + return snd_pcm_lib_free_pages(alsa_sub); } static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub) @@ -518,7 +518,6 @@ static const struct snd_pcm_ops pcm_ops = { .prepare = hiface_pcm_prepare, .trigger = hiface_pcm_trigger, .pointer = hiface_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static int hiface_pcm_init_urb(struct pcm_urb *urb, @@ -614,6 +613,8 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) strlcpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name)); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); rt->instance = pcm; -- cgit From 95ef15c65ae0d36569ac374e83498b6bf08d861f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:46 +0100 Subject: ALSA: ua101: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Link: https://lore.kernel.org/r/20191105151856.10785-15-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/misc/ua101.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 307b72d5fffa..566a4a31528a 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -733,8 +733,8 @@ static int capture_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); } static int playback_pcm_hw_params(struct snd_pcm_substream *substream, @@ -751,13 +751,13 @@ static int playback_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); } static int ua101_pcm_hw_free(struct snd_pcm_substream *substream) { - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int capture_pcm_prepare(struct snd_pcm_substream *substream) @@ -889,7 +889,6 @@ static const struct snd_pcm_ops capture_pcm_ops = { .prepare = capture_pcm_prepare, .trigger = capture_pcm_trigger, .pointer = capture_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_pcm_ops = { @@ -901,7 +900,6 @@ static const struct snd_pcm_ops playback_pcm_ops = { .prepare = playback_pcm_prepare, .trigger = playback_pcm_trigger, .pointer = playback_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct uac_format_type_i_discrete_descriptor * @@ -1296,6 +1294,8 @@ static int ua101_probe(struct usb_interface *interface, strcpy(ua->pcm->name, name); snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_pcm_ops); snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_pcm_ops); + snd_pcm_lib_preallocate_pages_for_all(ua->pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); err = snd_usbmidi_create(card, ua->intf[INTF_MIDI], &ua->midi_list, &midi_quirk); -- cgit From 748a76b215a36e9bb88a5bd8b56c5088371b2f19 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:47 +0100 Subject: ALSA: vx: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Since the driver requires the DMA32 allocation, it passes the specially encoded device to snd_pcm_lib_preallocate_pages(). Link: https://lore.kernel.org/r/20191105151856.10785-16-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_pcm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 4705c50fbf4f..f17e0a76c73c 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -778,8 +778,7 @@ static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs) static int vx_pcm_hw_params(struct snd_pcm_substream *subs, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_alloc_vmalloc_32_buffer - (subs, params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw_params)); } /* @@ -787,7 +786,7 @@ static int vx_pcm_hw_params(struct snd_pcm_substream *subs, */ static int vx_pcm_hw_free(struct snd_pcm_substream *subs) { - return snd_pcm_lib_free_vmalloc_buffer(subs); + return snd_pcm_lib_free_pages(subs); } /* @@ -867,7 +866,6 @@ static const struct snd_pcm_ops vx_pcm_playback_ops = { .prepare = vx_pcm_prepare, .trigger = vx_pcm_trigger, .pointer = vx_pcm_playback_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; @@ -1088,7 +1086,6 @@ static const struct snd_pcm_ops vx_pcm_capture_ops = { .prepare = vx_pcm_prepare, .trigger = vx_pcm_trigger, .pointer = vx_pcm_capture_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; @@ -1233,6 +1230,9 @@ int snd_vx_pcm_new(struct vx_core *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &vx_pcm_playback_ops); if (ins) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vx_pcm_capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + snd_dma_continuous_data(GFP_KERNEL | GFP_DMA32), + 0, 0); pcm->private_data = chip; pcm->private_free = snd_vx_pcm_free; -- cgit From d5dec270c00c155db64c3d2151b94002dfb2c6c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:48 +0100 Subject: ALSA: pdaudiocf: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Since the driver requires the DMA32 allocation, it passes the specially encoded device to snd_pcm_lib_preallocate_pages(). Link: https://lore.kernel.org/r/20191105151856.10785-17-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index c21fec60cd98..067b1c3a3e02 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -89,8 +89,7 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_alloc_vmalloc_32_buffer - (subs, params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw_params)); } /* @@ -98,7 +97,7 @@ static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, */ static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs) { - return snd_pcm_lib_free_vmalloc_buffer(subs); + return snd_pcm_lib_free_pages(subs); } /* @@ -262,7 +261,6 @@ static const struct snd_pcm_ops pdacf_pcm_capture_ops = { .prepare = pdacf_pcm_prepare, .trigger = pdacf_pcm_trigger, .pointer = pdacf_pcm_capture_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; @@ -279,6 +277,9 @@ int snd_pdacf_pcm_new(struct snd_pdacf *chip) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + snd_dma_continuous_data(GFP_KERNEL | GFP_DMA32), + 0, 0); pcm->private_data = chip; pcm->info_flags = 0; -- cgit From 30f2ce712d29325b0150243a9a2dd215c2ff60c8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:49 +0100 Subject: ALSA: mips: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Link: https://lore.kernel.org/r/20191105151856.10785-18-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/mips/sgio2audio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index fadc1194b136..9d20ce6118a0 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -582,14 +582,13 @@ static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream) static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } /* hw_free callback */ static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) { - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } /* prepare callback */ @@ -670,7 +669,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback1_ops = { .prepare = snd_sgio2audio_pcm_prepare, .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = { @@ -682,7 +680,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = { .prepare = snd_sgio2audio_pcm_prepare, .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops snd_sgio2audio_capture_ops = { @@ -694,7 +691,6 @@ static const struct snd_pcm_ops snd_sgio2audio_capture_ops = { .prepare = snd_sgio2audio_pcm_prepare, .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; /* @@ -720,6 +716,8 @@ static int snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip) &snd_sgio2audio_playback1_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sgio2audio_capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); /* create second pcm device with one outputs and no input */ err = snd_pcm_new(chip->card, "SGI O2 Audio", 1, 1, 0, &pcm); @@ -732,6 +730,8 @@ static int snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip) /* set operators */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sgio2audio_playback2_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); return 0; } -- cgit From 16ccca11088c1bdd9311a2c630b453541305c48a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:50 +0100 Subject: ALSA: pci: Drop superfluous snd_pcm_sgbuf_ops_page snd_pcm_sgbuf_ops_page is no longer needed to be set explicitly to PCM page ops since the recent change in the PCM core (*). Leaving it NULL should work as long as the preallocation has been done properly. This patch drops the redundant lines. (*) 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Link: https://lore.kernel.org/r/20191105151856.10785-19-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0_pcm.c | 1 - sound/pci/bt87x.c | 1 - sound/pci/ctxfi/ctpcm.c | 2 -- sound/pci/echoaudio/echoaudio.c | 4 ---- sound/pci/emu10k1/emupcm.c | 2 -- sound/pci/hda/hda_controller.c | 1 - sound/pci/lola/lola_pcm.c | 1 - sound/pci/riptide/riptide.c | 2 -- sound/pci/rme9652/hdspm.c | 1 - sound/pci/trident/trident_main.c | 2 -- sound/pci/via82xx.c | 5 ----- sound/pci/via82xx_modem.c | 2 -- 12 files changed, 24 deletions(-) (limited to 'sound') diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 39ea9ef00f47..b835042893d9 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -436,7 +436,6 @@ static const struct snd_pcm_ops snd_vortex_playback_ops = { .prepare = snd_vortex_pcm_prepare, .trigger = snd_vortex_pcm_trigger, .pointer = snd_vortex_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; /* diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 66a5a24e7558..d4b6da79ef49 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -545,7 +545,6 @@ static const struct snd_pcm_ops snd_bt87x_pcm_ops = { .prepare = snd_bt87x_prepare, .trigger = snd_bt87x_trigger, .pointer = snd_bt87x_pointer, - .page = snd_pcm_sgbuf_ops_page, }; static int snd_bt87x_capture_volume_info(struct snd_kcontrol *kcontrol, diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index 89923399e646..c341f509e4fc 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -379,7 +379,6 @@ static const struct snd_pcm_ops ct_pcm_playback_ops = { .prepare = ct_pcm_playback_prepare, .trigger = ct_pcm_playback_trigger, .pointer = ct_pcm_playback_pointer, - .page = snd_pcm_sgbuf_ops_page, }; /* PCM operators for capture */ @@ -392,7 +391,6 @@ static const struct snd_pcm_ops ct_pcm_capture_ops = { .prepare = ct_pcm_capture_prepare, .trigger = ct_pcm_capture_trigger, .pointer = ct_pcm_capture_pointer, - .page = snd_pcm_sgbuf_ops_page, }; static const struct snd_pcm_chmap_elem surround_map[] = { diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index ca9125726be2..40877e478bb6 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -824,7 +824,6 @@ static const struct snd_pcm_ops analog_playback_ops = { .prepare = pcm_prepare, .trigger = pcm_trigger, .pointer = pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; static const struct snd_pcm_ops analog_capture_ops = { .open = pcm_analog_in_open, @@ -835,7 +834,6 @@ static const struct snd_pcm_ops analog_capture_ops = { .prepare = pcm_prepare, .trigger = pcm_trigger, .pointer = pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; #ifdef ECHOCARD_HAS_DIGITAL_IO #ifndef ECHOCARD_HAS_VMIXER @@ -848,7 +846,6 @@ static const struct snd_pcm_ops digital_playback_ops = { .prepare = pcm_prepare, .trigger = pcm_trigger, .pointer = pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; #endif /* !ECHOCARD_HAS_VMIXER */ static const struct snd_pcm_ops digital_capture_ops = { @@ -860,7 +857,6 @@ static const struct snd_pcm_ops digital_capture_ops = { .prepare = pcm_prepare, .trigger = pcm_trigger, .pointer = pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; #endif /* ECHOCARD_HAS_DIGITAL_IO */ diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 6530a55fb878..46d8768adc01 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1366,7 +1366,6 @@ static const struct snd_pcm_ops snd_emu10k1_playback_ops = { .prepare = snd_emu10k1_playback_prepare, .trigger = snd_emu10k1_playback_trigger, .pointer = snd_emu10k1_playback_pointer, - .page = snd_pcm_sgbuf_ops_page, }; static const struct snd_pcm_ops snd_emu10k1_capture_ops = { @@ -1390,7 +1389,6 @@ static const struct snd_pcm_ops snd_emu10k1_efx_playback_ops = { .prepare = snd_emu10k1_efx_playback_prepare, .trigger = snd_emu10k1_efx_playback_trigger, .pointer = snd_emu10k1_efx_playback_pointer, - .page = snd_pcm_sgbuf_ops_page, }; int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 6387c7e90918..2f3b7a35f2d9 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -701,7 +701,6 @@ static const struct snd_pcm_ops azx_pcm_ops = { .pointer = azx_pcm_pointer, .get_time_info = azx_get_time_info, .mmap = azx_pcm_mmap, - .page = snd_pcm_sgbuf_ops_page, }; static void azx_pcm_free(struct snd_pcm *pcm) diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c index 151f7cf5ce0e..f032d7ceb6e5 100644 --- a/sound/pci/lola/lola_pcm.c +++ b/sound/pci/lola/lola_pcm.c @@ -582,7 +582,6 @@ static const struct snd_pcm_ops lola_pcm_ops = { .prepare = lola_pcm_prepare, .trigger = lola_pcm_trigger, .pointer = lola_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; int lola_create_pcm(struct lola *chip) diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 58771ae0ed63..ac10d6f229d8 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1661,7 +1661,6 @@ static const struct snd_pcm_ops snd_riptide_playback_ops = { .hw_params = snd_riptide_hw_params, .hw_free = snd_riptide_hw_free, .prepare = snd_riptide_prepare, - .page = snd_pcm_sgbuf_ops_page, .trigger = snd_riptide_trigger, .pointer = snd_riptide_pointer, }; @@ -1672,7 +1671,6 @@ static const struct snd_pcm_ops snd_riptide_capture_ops = { .hw_params = snd_riptide_hw_params, .hw_free = snd_riptide_hw_free, .prepare = snd_riptide_prepare, - .page = snd_pcm_sgbuf_ops_page, .trigger = snd_riptide_trigger, .pointer = snd_riptide_pointer, }; diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 81a6f4b2bd3c..b571d9d017bb 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6368,7 +6368,6 @@ static const struct snd_pcm_ops snd_hdspm_ops = { .prepare = snd_hdspm_prepare, .trigger = snd_hdspm_trigger, .pointer = snd_hdspm_hw_pointer, - .page = snd_pcm_sgbuf_ops_page, }; static int snd_hdspm_create_hwdep(struct snd_card *card, diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 1a6f6202fd16..8ac6f541b008 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -2076,7 +2076,6 @@ static const struct snd_pcm_ops snd_trident_nx_playback_ops = { .prepare = snd_trident_playback_prepare, .trigger = snd_trident_trigger, .pointer = snd_trident_playback_pointer, - .page = snd_pcm_sgbuf_ops_page, }; static const struct snd_pcm_ops snd_trident_capture_ops = { @@ -2121,7 +2120,6 @@ static const struct snd_pcm_ops snd_trident_nx_foldback_ops = { .prepare = snd_trident_foldback_prepare, .trigger = snd_trident_trigger, .pointer = snd_trident_playback_pointer, - .page = snd_pcm_sgbuf_ops_page, }; static const struct snd_pcm_ops snd_trident_spdif_ops = { diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 38601d0dfb73..902409dbc4c8 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1363,7 +1363,6 @@ static const struct snd_pcm_ops snd_via686_playback_ops = { .prepare = snd_via686_playback_prepare, .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via686_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; /* via686 capture callbacks */ @@ -1376,7 +1375,6 @@ static const struct snd_pcm_ops snd_via686_capture_ops = { .prepare = snd_via686_capture_prepare, .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via686_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; /* via823x DSX playback callbacks */ @@ -1389,7 +1387,6 @@ static const struct snd_pcm_ops snd_via8233_playback_ops = { .prepare = snd_via8233_playback_prepare, .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via8233_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; /* via823x multi-channel playback callbacks */ @@ -1402,7 +1399,6 @@ static const struct snd_pcm_ops snd_via8233_multi_ops = { .prepare = snd_via8233_multi_prepare, .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via8233_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; /* via823x capture callbacks */ @@ -1415,7 +1411,6 @@ static const struct snd_pcm_ops snd_via8233_capture_ops = { .prepare = snd_via8233_capture_prepare, .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via8233_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index bfb5e1b89d5f..2c8370cf03b3 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -801,7 +801,6 @@ static const struct snd_pcm_ops snd_via686_playback_ops = { .prepare = snd_via82xx_pcm_prepare, .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via686_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; /* via686 capture callbacks */ @@ -814,7 +813,6 @@ static const struct snd_pcm_ops snd_via686_capture_ops = { .prepare = snd_via82xx_pcm_prepare, .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via686_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; -- cgit From 3ca5fc0664ec47fae86bc07749ceb185f7b175f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:51 +0100 Subject: ALSA: aoa: Avoid non-standard macro usage Pass the device pointer from the PCI pointer directly, instead of a non-standard macro. The macro didn't give any better readability. Link: https://lore.kernel.org/r/20191105151856.10785-20-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/aoa/soundbus/i2sbus/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index 7f0754dd3d7d..a94e4023fadf 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -1028,7 +1028,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, /* well, we really should support scatter/gather DMA */ snd_pcm_lib_preallocate_pages_for_all( dev->pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)), + &macio_get_pci_dev(i2sdev->macio)->dev, 64 * 1024, 64 * 1024); return 0; -- cgit From 7564d3b6334c5dd619827a85dd32bf7c21df6667 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:52 +0100 Subject: ALSA: echoaudio: Avoid non-standard macro usage Pass the device pointer from the PCI pointer directly, instead of a non-standard macro. The macro didn't give any better readability. Also slightly refactor the code (drop the return value check from the preallocation) as it never returns an error. Link: https://lore.kernel.org/r/20191105151856.10785-21-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 40877e478bb6..1465813bf7c6 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -324,7 +324,7 @@ static int pcm_open(struct snd_pcm_substream *substream, /* Finally allocate a page for the scatter-gather list */ if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, PAGE_SIZE, &pipe->sgpage)) < 0) { dev_err(chip->card->dev, "s-g list allocation failed\n"); return err; @@ -865,7 +865,7 @@ static const struct snd_pcm_ops digital_capture_ops = { /* Preallocate memory only for the first substream because it's the most * used one */ -static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev) +static void snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev) { struct snd_pcm_substream *ss; int stream; @@ -876,8 +876,6 @@ static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev) dev, ss->number ? 0 : 128<<10, 256<<10); - - return 0; } @@ -904,8 +902,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) strcpy(pcm->name, chip->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); - if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) - return err; + snd_echo_preallocate_pages(pcm, &chip->pci->dev); #ifdef ECHOCARD_HAS_DIGITAL_IO /* PCM#1 Digital inputs, no outputs */ @@ -916,8 +913,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) chip->digital_pcm = pcm; strcpy(pcm->name, chip->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); - if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) - return err; + snd_echo_preallocate_pages(pcm, &chip->pci->dev); #endif /* ECHOCARD_HAS_DIGITAL_IO */ #else /* ECHOCARD_HAS_VMIXER */ @@ -937,8 +933,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) strcpy(pcm->name, chip->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); - if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) - return err; + snd_echo_preallocate_pages(pcm, &chip->pci->dev); #ifdef ECHOCARD_HAS_DIGITAL_IO /* PCM#1 Digital i/o */ @@ -951,8 +946,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) strcpy(pcm->name, chip->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); - if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) - return err; + snd_echo_preallocate_pages(pcm, &chip->pci->dev); #endif /* ECHOCARD_HAS_DIGITAL_IO */ #endif /* ECHOCARD_HAS_VMIXER */ @@ -1954,7 +1948,7 @@ static int snd_echo_create(struct snd_card *card, /* Create the DSP comm page - this is the area of memory used for most of the communication with the DSP, which accesses it via bus mastering */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, sizeof(struct comm_page), &chip->commpage_dma_buf) < 0) { dev_err(chip->card->dev, "cannot allocate the comm page\n"); -- cgit From af7153a29d5f0bed1f62b5347dc6cce291d40d69 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:53 +0100 Subject: ALSA: es1968: Avoid non-standard macro usage Pass the device pointer from the PCI pointer directly, instead of a non-standard macro. The macro didn't give any better readability. Along with it, the unneeded assignment before snd_dma_alloc_pages*() call is dropped. Link: https://lore.kernel.org/r/20191105151856.10785-22-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/es1968.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 974142535a25..7017ca9dea4a 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1422,10 +1422,8 @@ snd_es1968_init_dmabuf(struct es1968 *chip) int err; struct esm_memory *chunk; - chip->dma.dev.type = SNDRV_DMA_TYPE_DEV; - chip->dma.dev.dev = snd_dma_pci_data(chip->pci); err = snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, chip->total_bufsize, &chip->dma); if (err < 0 || ! chip->dma.area) { dev_err(chip->card->dev, -- cgit From 1a810436a2eff372aa1a934fe4d1bef50bd9dac8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:54 +0100 Subject: ALSA: rme: Avoid non-standard macro usage Pass the device pointer from the PCI pointer directly, instead of a non-standard macro. The macro didn't give any better readability. Along with it, drop the unnecessary assignment before the snd_dma_alloc_pages() call and simplify by returning the error code directly. Link: https://lore.kernel.org/r/20191105151856.10785-23-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 7 +------ sound/pci/rme9652/hdspm.c | 2 +- sound/pci/rme9652/rme9652.c | 7 +------ 3 files changed, 3 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 5cbdc9be9c7e..cd20af465d8e 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -569,12 +569,7 @@ static char channel_map_H9632_qs[HDSP_MAX_CHANNELS] = { static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer *dmab, size_t size) { - dmab->dev.type = SNDRV_DMA_TYPE_DEV; - dmab->dev.dev = snd_dma_pci_data(pci); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - size, dmab) < 0) - return -ENOMEM; - return 0; + return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, size, dmab); } static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index b571d9d017bb..75c06a7cc779 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6406,7 +6406,7 @@ static int snd_hdspm_preallocate_memory(struct hdspm *hdspm) wanted = HDSPM_DMA_AREA_BYTES; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(hdspm->pci), + &hdspm->pci->dev, wanted, wanted); dev_dbg(hdspm->card->dev, " Preallocated %zd Bytes\n", wanted); return 0; diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 4c851f8dcaf8..ef5c2f8e17c7 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -279,12 +279,7 @@ static char channel_map_9636_ds[26] = { static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer *dmab, size_t size) { - dmab->dev.type = SNDRV_DMA_TYPE_DEV; - dmab->dev.dev = snd_dma_pci_data(pci); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - size, dmab) < 0) - return -ENOMEM; - return 0; + return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, size, dmab); } static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) -- cgit From 6974f8ad44946701779209cb03cd8c6b598c3342 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Nov 2019 16:18:55 +0100 Subject: ALSA: pci: Avoid non-standard macro usage Pass the device pointer from the PCI pointer directly, instead of a non-standard macro. The macro didn't give any better readability. Link: https://lore.kernel.org/r/20191105151856.10785-24-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ad1889.c | 6 +++--- sound/pci/ali5451/ali5451.c | 2 +- sound/pci/als300.c | 3 ++- sound/pci/als4000.c | 3 ++- sound/pci/asihpi/asihpi.c | 4 ++-- sound/pci/atiixp.c | 6 +++--- sound/pci/atiixp_modem.c | 4 ++-- sound/pci/au88x0/au88x0_pcm.c | 2 +- sound/pci/aw2/aw2-alsa.c | 6 +++--- sound/pci/azt3328.c | 8 ++++---- sound/pci/bt87x.c | 4 ++-- sound/pci/ca0106/ca0106_main.c | 6 +++--- sound/pci/cmipci.c | 6 +++--- sound/pci/cs4281.c | 3 ++- sound/pci/cs46xx/cs46xx_lib.c | 16 ++++++++++------ sound/pci/cs5535audio/cs5535audio_pcm.c | 6 +++--- sound/pci/ctxfi/ctpcm.c | 3 ++- sound/pci/ctxfi/ctvmem.c | 2 +- sound/pci/emu10k1/emu10k1.c | 5 +++-- sound/pci/emu10k1/emu10k1x.c | 6 +++--- sound/pci/emu10k1/emufx.c | 2 +- sound/pci/emu10k1/emupcm.c | 10 +++++----- sound/pci/emu10k1/memory.c | 4 ++-- sound/pci/emu10k1/p16v.c | 4 ++-- sound/pci/ens1370.c | 8 +++++--- sound/pci/es1938.c | 3 ++- sound/pci/fm801.c | 2 +- sound/pci/ice1712/ice1712.c | 9 ++++++--- sound/pci/ice1712/ice1724.c | 6 +++--- sound/pci/intel8x0.c | 4 ++-- sound/pci/intel8x0m.c | 4 ++-- sound/pci/korg1212/korg1212.c | 8 ++++---- sound/pci/lola/lola.c | 2 +- sound/pci/lola/lola_pcm.c | 4 ++-- sound/pci/lx6464es/lx6464es.c | 2 +- sound/pci/maestro3.c | 3 ++- sound/pci/mixart/mixart.c | 7 ++++--- sound/pci/oxygen/oxygen_pcm.c | 10 +++++----- sound/pci/pcxhr/pcxhr.c | 4 ++-- sound/pci/riptide/riptide.c | 4 ++-- sound/pci/sis7019.c | 3 ++- sound/pci/sonicvibes.c | 3 ++- sound/pci/trident/trident_main.c | 22 ++++++++++++++-------- sound/pci/via82xx.c | 12 ++++++------ sound/pci/via82xx_modem.c | 4 ++-- sound/pci/ymfpci/ymfpci_main.c | 16 ++++++++++------ 46 files changed, 145 insertions(+), 116 deletions(-) (limited to 'sound') diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 4b2451287e2c..5b6452df8bbd 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -633,9 +633,9 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device) chip->csubs = NULL; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - BUFFER_BYTES_MAX / 2, - BUFFER_BYTES_MAX); + &chip->pci->dev, + BUFFER_BYTES_MAX / 2, + BUFFER_BYTES_MAX); return 0; } diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 6e28e381c21a..ae29df085ae1 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1672,7 +1672,7 @@ static int snd_ali_pcm(struct snd_ali *codec, int device, desc->capture_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(codec->pci), + &codec->pci->dev, 64*1024, 128*1024); pcm->info_flags = 0; diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 530799c8d3ce..cfbb8cacaaac 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -592,7 +592,8 @@ static int snd_als300_new_pcm(struct snd_als300 *chip) /* pre-allocation of buffers */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 64*1024); + &chip->pci->dev, + 64*1024, 64*1024); return 0; } diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index b06c3dbb525d..d6f5487afe52 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -693,7 +693,8 @@ static int snd_als4000_pcm(struct snd_sb *chip, int device) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_als4000_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_als4000_capture_ops); - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + &chip->pci->dev, 64*1024, 64*1024); chip->pcm = pcm; diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 2a21a3d99719..147005fdd3ea 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -1325,8 +1325,8 @@ static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device) /*? do we want to emulate MMAP for non-BBM cards? Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(asihpi->pci), - 64*1024, BUFFER_BYTES_MAX); + &asihpi->pci->dev, + 64*1024, BUFFER_BYTES_MAX); return 0; } diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index c953bd73a48c..1e1ededf8eb2 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -353,7 +353,7 @@ static int atiixp_build_dma_packets(struct atiixp *chip, struct atiixp_dma *dma, if (dma->desc_buf.area == NULL) { if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, ATI_DESC_LIST_SIZE, &dma->desc_buf) < 0) return -ENOMEM; @@ -1284,7 +1284,7 @@ static int snd_atiixp_pcm_new(struct atiixp *chip) chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64*1024, 128*1024); err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -1317,7 +1317,7 @@ static int snd_atiixp_pcm_new(struct atiixp *chip) chip->pcmdevs[ATI_PCMDEV_DIGITAL] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64*1024, 128*1024); /* pre-select AC97 SPDIF slots 10/11 */ diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 95d209f96581..6f088c1949f3 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -321,7 +321,7 @@ static int atiixp_build_dma_packets(struct atiixp_modem *chip, return -ENOMEM; if (dma->desc_buf.area == NULL) { - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, ATI_DESC_LIST_SIZE, &dma->desc_buf) < 0) return -ENOMEM; dma->period_bytes = dma->periods = 0; /* clear */ @@ -995,7 +995,7 @@ static int snd_atiixp_pcm_new(struct atiixp_modem *chip) chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64*1024, 128*1024); return 0; diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index b835042893d9..1012e8da29e7 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -637,7 +637,7 @@ static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) /* pre-allocation of Scatter-Gather buffers */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci_dev), + &chip->pci_dev, 0x10000, 0x10000); switch (VORTEX_PCM_TYPE(pcm)) { diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index e413414181df..1cbfae856a2a 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -613,7 +613,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip) /* Preallocate continuous pages. */ snd_pcm_lib_preallocate_pages_for_all(pcm_playback_ana, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64 * 1024, 64 * 1024); err = snd_pcm_new(chip->card, "Audiowerk2 digital playback", 1, 1, 0, @@ -645,7 +645,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip) /* Preallocate continuous pages. */ snd_pcm_lib_preallocate_pages_for_all(pcm_playback_num, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64 * 1024, 64 * 1024); err = snd_pcm_new(chip->card, "Audiowerk2 capture", 2, 0, 1, @@ -678,7 +678,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip) /* Preallocate continuous pages. */ snd_pcm_lib_preallocate_pages_for_all(pcm_capture, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64 * 1024, 64 * 1024); /* Create control */ diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index f92c9cbb955a..f475370faaaa 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -2135,8 +2135,8 @@ snd_azf3328_pcm(struct snd_azf3328 *chip) chip->pcm[AZF_CODEC_CAPTURE] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - 64*1024, 64*1024); + &chip->pci->dev, + 64*1024, 64*1024); err = snd_pcm_new(chip->card, "AZF3328 I2S OUT", AZF_PCMDEV_I2S_OUT, 1, 0, &pcm); @@ -2151,8 +2151,8 @@ snd_azf3328_pcm(struct snd_azf3328 *chip) chip->pcm[AZF_CODEC_I2S_OUT] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - 64*1024, 64*1024); + &chip->pci->dev, + 64*1024, 64*1024); return 0; } diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index d4b6da79ef49..6bf5ac3600c5 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -217,7 +217,7 @@ static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substrea __le32 *risc; if (chip->dma_risc.area == NULL) { - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, PAGE_ALIGN(MAX_RISC_SIZE), &chip->dma_risc) < 0) return -ENOMEM; } @@ -700,7 +700,7 @@ static int snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name) strcpy(pcm->name, name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_bt87x_pcm_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 128 * 1024, ALIGN(255 * 4092, 1024)); return 0; diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 478412e0aa3c..abc2440dc2d9 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1389,7 +1389,7 @@ static int snd_ca0106_pcm(struct snd_ca0106 *emu, int device) substream; substream = substream->next) { snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, 64*1024, 64*1024); } @@ -1397,7 +1397,7 @@ static int snd_ca0106_pcm(struct snd_ca0106 *emu, int device) substream; substream = substream->next) { snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, 64*1024, 64*1024); } @@ -1692,7 +1692,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card, chip->irq = pci->irq; /* This stores the periods table. */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, 1024, &chip->buffer) < 0) { snd_ca0106_free(chip); return -ENOMEM; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index df720881eb99..dd9d62e2b633 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -1902,7 +1902,7 @@ static int snd_cmipci_pcm_new(struct cmipci *cm, int device) cm->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(cm->pci), 64*1024, 128*1024); + &cm->pci->dev, 64*1024, 128*1024); return 0; } @@ -1924,7 +1924,7 @@ static int snd_cmipci_pcm2_new(struct cmipci *cm, int device) cm->pcm2 = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(cm->pci), 64*1024, 128*1024); + &cm->pci->dev, 64*1024, 128*1024); return 0; } @@ -1947,7 +1947,7 @@ static int snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device) cm->pcm_spdif = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(cm->pci), 64*1024, 128*1024); + &cm->pci->dev, 64*1024, 128*1024); err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_alt_chmaps, cm->max_channels, 0, diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 04c712647853..058c1414b777 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -975,7 +975,8 @@ static int snd_cs4281_pcm(struct cs4281 *chip, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 512*1024); + &chip->pci->dev, + 64*1024, 512*1024); return 0; } diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 5b888b795f7e..102a62965ac1 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1494,7 +1494,7 @@ static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,in cpcm = kzalloc(sizeof(*cpcm), GFP_KERNEL); if (cpcm == NULL) return -ENOMEM; - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, PAGE_SIZE, &cpcm->hw_buf) < 0) { kfree(cpcm); return -ENOMEM; @@ -1582,7 +1582,7 @@ static int snd_cs46xx_capture_open(struct snd_pcm_substream *substream) { struct snd_cs46xx *chip = snd_pcm_substream_chip(substream); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, PAGE_SIZE, &chip->capt.hw_buf) < 0) return -ENOMEM; chip->capt.substream = substream; @@ -1784,7 +1784,8 @@ int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 256*1024); + &chip->pci->dev, + 64*1024, 256*1024); return 0; } @@ -1809,7 +1810,8 @@ int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device) chip->pcm_rear = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 256*1024); + &chip->pci->dev, + 64*1024, 256*1024); return 0; } @@ -1832,7 +1834,8 @@ int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device) chip->pcm_center_lfe = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 256*1024); + &chip->pci->dev, + 64*1024, 256*1024); return 0; } @@ -1855,7 +1858,8 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device) chip->pcm_iec958 = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 256*1024); + &chip->pci->dev, + 64*1024, 256*1024); return 0; } diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 04822bf2f987..4642e5384e83 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -117,7 +117,7 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, if (dma->desc_buf.area == NULL) { if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(cs5535au->pci), + &cs5535au->pci->dev, CS5535AUDIO_DESC_LIST_SIZE+1, &dma->desc_buf) < 0) return -ENOMEM; @@ -432,8 +432,8 @@ int snd_cs5535audio_pcm(struct cs5535audio *cs5535au) strcpy(pcm->name, "CS5535 Audio"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(cs5535au->pci), - 64*1024, 128*1024); + &cs5535au->pci->dev, + 64*1024, 128*1024); cs5535au->pcm = pcm; return 0; diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index c341f509e4fc..7ae5b238703c 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -450,7 +450,8 @@ int ct_alsa_pcm_create(struct ct_atc *atc, SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(atc->pci), 128*1024, 128*1024); + &atc->pci->dev, + 128*1024, 128*1024); chs = 2; switch (device) { diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 2e80b17a7104..bde28aa9e139 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -183,7 +183,7 @@ int ct_vm_create(struct ct_vm **rvm, struct pci_dev *pci) /* Allocate page table pages */ for (i = 0; i < CT_PTP_NUM; i++) { err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(pci), + &pci->dev, PAGE_SIZE, &vm->ptp[i]); if (err < 0) break; diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index f208b6e217fd..29b7720d7961 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -124,8 +124,9 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, goto error; /* This stores the periods table. */ if (emu->card_capabilities->ca0151_chip) { /* P16V */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - 1024, &emu->p16v_buffer)) < 0) + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + 1024, &emu->p16v_buffer); + if (err < 0) goto error; } diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 9cf81832259c..241b4a0631ab 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -877,7 +877,7 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device) emu->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, 32*1024, 32*1024); return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2, @@ -936,8 +936,8 @@ static int snd_emu10k1x_create(struct snd_card *card, } chip->irq = pci->irq; - if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - 4 * 1024, &chip->dma_buffer) < 0) { + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + 4 * 1024, &chip->dma_buffer) < 0) { snd_emu10k1x_free(chip); return -ENOMEM; } diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index e053f0d58bdd..a31adecfe608 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -2464,7 +2464,7 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size) } if (size > 0) { - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &emu->pci->dev, size * 2, &emu->fx8010.etram_pages) < 0) return -ENOMEM; memset(emu->fx8010.etram_pages.area, 0, size * 2); diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 46d8768adc01..9a8cf3c7dd67 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1412,12 +1412,12 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device) for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, 64*1024, 64*1024); for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, 64*1024, 64*1024); return 0; @@ -1443,7 +1443,7 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device) for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, 64*1024, 64*1024); return 0; @@ -1478,7 +1478,7 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device) emu->pcm_mic = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, 64*1024, 64*1024); return 0; @@ -1853,7 +1853,7 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) return err; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, 64*1024, 64*1024); return 0; diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 135e26544275..94b8d5b08225 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -387,7 +387,7 @@ int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size, } return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), size, dmab); + &emu->pci->dev, size, dmab); } /* @@ -477,7 +477,7 @@ static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page, int page; dmab.dev.type = SNDRV_DMA_TYPE_DEV; - dmab.dev.dev = snd_dma_pci_data(emu->pci); + dmab.dev.dev = &emu->pci->dev; for (page = first_page; page <= last_page; page++) { if (emu->page_ptr_table[page] == NULL) diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index eeaed555185c..ab8876855989 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -643,7 +643,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) substream; substream = substream->next) { snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, (65536 - 64) * 8, (65536 - 64) * 8); /* @@ -656,7 +656,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) substream; substream = substream->next) { snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), + &emu->pci->dev, 65536 - 64, 65536 - 64); /* dev_dbg(emu->card->dev, diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index b767df8181b5..0499dc863202 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1275,7 +1275,8 @@ static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device) ensoniq->pcm1 = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024); + &ensoniq->pci->dev, + 64*1024, 128*1024); #ifdef CHIP1370 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -1307,7 +1308,8 @@ static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device) ensoniq->pcm2 = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024); + &ensoniq->pci->dev, + 64*1024, 128*1024); #ifdef CHIP1370 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -2095,7 +2097,7 @@ static int snd_ensoniq_create(struct snd_card *card, } ensoniq->irq = pci->irq; #ifdef CHIP1370 - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, 16, &ensoniq->dma_bug) < 0) { dev_err(card->dev, "unable to allocate space for phantom area - dma_bug\n"); snd_ensoniq_free(ensoniq); diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index ecf77c8c9e59..c571c5d380ca 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1032,7 +1032,8 @@ static int snd_es1938_new_pcm(struct es1938 *chip, int device) strcpy(pcm->name, "ESS Solo-1"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 64*1024); + &chip->pci->dev, + 64*1024, 64*1024); chip->pcm = pcm; return 0; diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 3ef7d507eb9b..a7f8109acced 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -721,7 +721,7 @@ static int snd_fm801_pcm(struct fm801 *chip, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(pdev), + &pdev->dev, chip->multichannel ? 128*1024 : 64*1024, 128*1024); return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 4b0dea7f7669..deadba40131c 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -884,7 +884,8 @@ static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device) ice->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(ice->pci), 64*1024, 64*1024); + &ice->pci->dev, + 64*1024, 64*1024); dev_warn(ice->card->dev, "Consumer PCM code does not work well at the moment --jk\n"); @@ -909,7 +910,8 @@ static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device) ice->pcm_ds = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(ice->pci), 64*1024, 128*1024); + &ice->pci->dev, + 64*1024, 128*1024); return 0; } @@ -1253,7 +1255,8 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device) strcpy(pcm->name, "ICE1712 multi"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(ice->pci), 256*1024, 256*1024); + &ice->pci->dev, + 256*1024, 256*1024); ice->pcm_pro = pcm; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index e62c11816683..c80a16ee6e76 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -1143,7 +1143,7 @@ static int snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) strcpy(pcm->name, "ICE1724"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(ice->pci), + &ice->pci->dev, 256*1024, 256*1024); ice->pcm_pro = pcm; @@ -1341,7 +1341,7 @@ static int snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device) strcpy(pcm->name, name); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(ice->pci), + &ice->pci->dev, 256*1024, 256*1024); ice->pcm = pcm; @@ -1455,7 +1455,7 @@ static int snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device) strcpy(pcm->name, "ICE1724 Surround PCM"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(ice->pci), + &ice->pci->dev, 256*1024, 256*1024); ice->pcm_ds = pcm; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6ff94d8ad86e..12374ba08ca2 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1488,7 +1488,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, chip->pcm[device] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, intel8x0_dma_type(chip), - snd_dma_pci_data(chip->pci), + &chip->pci->dev, rec->prealloc_size, rec->prealloc_max_size); if (rec->playback_ops && @@ -3047,7 +3047,7 @@ static int snd_intel8x0_create(struct snd_card *card, /* allocate buffer descriptor lists */ /* the start of each lists must be aligned to 8 bytes */ - if (snd_dma_alloc_pages(intel8x0_dma_type(chip), snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(intel8x0_dma_type(chip), &pci->dev, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars) < 0) { snd_intel8x0_free(chip); diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 2f960fb092df..a9add5fedfcb 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -734,7 +734,7 @@ static int snd_intel8x0m_pcm1(struct intel8x0m *chip, int device, chip->pcm[device] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, rec->prealloc_size, rec->prealloc_max_size); @@ -1176,7 +1176,7 @@ static int snd_intel8x0m_create(struct snd_card *card, /* allocate buffer descriptor lists */ /* the start of each lists must be aligned to 8 bytes */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars) < 0) { snd_intel8x0m_free(chip); diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 0d81eac0a478..2b8204a13c69 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2275,7 +2275,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, korg1212->idRegPtr, stateName[korg1212->cardState]); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, sizeof(struct KorgSharedBuffer), &korg1212->dma_shared) < 0) { snd_printk(KERN_ERR "korg1212: can not allocate shared buffer memory (%zd bytes)\n", sizeof(struct KorgSharedBuffer)); snd_korg1212_free(korg1212); @@ -2290,7 +2290,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, korg1212->DataBufsSize = sizeof(struct KorgAudioBuffer) * kNumBuffers; - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, korg1212->DataBufsSize, &korg1212->dma_play) < 0) { snd_printk(KERN_ERR "korg1212: can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize); snd_korg1212_free(korg1212); @@ -2302,7 +2302,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, K1212_DEBUG_PRINTK("K1212_DEBUG: Play Data Area = 0x%p (0x%08x), %d bytes\n", korg1212->playDataBufsPtr, korg1212->PlayDataPhy, korg1212->DataBufsSize); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, korg1212->DataBufsSize, &korg1212->dma_rec) < 0) { snd_printk(KERN_ERR "korg1212: can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize); snd_korg1212_free(korg1212); @@ -2337,7 +2337,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, return err; } - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, dsp_code->size, &korg1212->dma_dsp) < 0) { snd_printk(KERN_ERR "korg1212: cannot allocate dsp code memory (%zd bytes)\n", dsp_code->size); snd_korg1212_free(korg1212); diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index 5cda3488ceab..21ac9d003e8e 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -350,7 +350,7 @@ static int setup_corb_rirb(struct lola *chip) unsigned long end_time; err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, PAGE_SIZE, &chip->rb); if (err < 0) return err; diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c index f032d7ceb6e5..856bcca60128 100644 --- a/sound/pci/lola/lola_pcm.c +++ b/sound/pci/lola/lola_pcm.c @@ -591,7 +591,7 @@ int lola_create_pcm(struct lola *chip) for (i = 0; i < 2; i++) { err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, PAGE_SIZE, &chip->pcm[i].bdl); if (err < 0) return err; @@ -611,7 +611,7 @@ int lola_create_pcm(struct lola *chip) } /* buffer pre-allocation */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 1024 * 64, 32 * 1024 * 1024); return 0; } diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index fe10714380f2..d0f63fa54121 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -846,7 +846,7 @@ static int lx_pcm_create(struct lx6464es *chip) strcpy(pcm->name, card_name); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, size, size); chip->pcm = pcm; diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 19fa73df0846..cc8594d76c70 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1861,7 +1861,8 @@ snd_m3_pcm(struct snd_m3 * chip, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 64*1024); + &chip->pci->dev, + 64*1024, 64*1024); return 0; } diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index e5279ce54ee1..674d37ec96b3 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -948,7 +948,8 @@ static void preallocate_buffers(struct snd_mixart *chip, struct snd_pcm *pcm) } #endif snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->mgr->pci), 32*1024, 32*1024); + &chip->mgr->pci->dev, + 32*1024, 32*1024); } /* @@ -1360,7 +1361,7 @@ static int snd_mixart_probe(struct pci_dev *pci, /* create array of streaminfo */ size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(struct mixart_flowinfo)) ); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, size, &mgr->flowinfo) < 0) { snd_mixart_free(mgr); return -ENOMEM; @@ -1371,7 +1372,7 @@ static int snd_mixart_probe(struct pci_dev *pci, /* create array of bufferinfo */ size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(struct mixart_bufferinfo)) ); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, size, &mgr->bufferinfo) < 0) { snd_mixart_free(mgr); return -ENOMEM; diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index e6aa16646fd4..203c8fe48a01 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -713,13 +713,13 @@ int oxygen_pcm_init(struct oxygen *chip) if (outs) snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, DEFAULT_BUFFER_BYTES_MULTICH, BUFFER_BYTES_MAX_MULTICH); if (ins) snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, DEFAULT_BUFFER_BYTES, BUFFER_BYTES_MAX); } @@ -739,7 +739,7 @@ int oxygen_pcm_init(struct oxygen *chip) pcm->private_data = chip; strcpy(pcm->name, "Digital"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, DEFAULT_BUFFER_BYTES, BUFFER_BYTES_MAX); } @@ -769,7 +769,7 @@ int oxygen_pcm_init(struct oxygen *chip) pcm->private_data = chip; strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, DEFAULT_BUFFER_BYTES, BUFFER_BYTES_MAX); } @@ -787,7 +787,7 @@ int oxygen_pcm_init(struct oxygen *chip) pcm->private_data = chip; strcpy(pcm->name, "Analog 3"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, DEFAULT_BUFFER_BYTES, BUFFER_BYTES_MAX); } diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index e493962d8455..4af34d6d92df 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -1171,7 +1171,7 @@ int pcxhr_create_pcm(struct snd_pcxhr *chip) strcpy(pcm->name, name); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->mgr->pci), + &chip->mgr->pci->dev, 32*1024, 32*1024); chip->pcm = pcm; return 0; @@ -1644,7 +1644,7 @@ static int pcxhr_probe(struct pci_dev *pci, /* create hostport purgebuffer */ size = PAGE_ALIGN(sizeof(struct pcxhr_hostport)); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, size, &mgr->hostport) < 0) { pcxhr_free(mgr); return -ENOMEM; diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index ac10d6f229d8..abcea86045ec 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1550,7 +1550,7 @@ snd_riptide_hw_params(struct snd_pcm_substream *substream, if (sgdlist->area) snd_dma_free_pages(sgdlist); if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, sizeof(struct sgd) * (DESC_MAX_MASK + 1), sgdlist)) < 0) { snd_printk(KERN_ERR "Riptide: failed to alloc %d dma bytes\n", @@ -1693,7 +1693,7 @@ static int snd_riptide_pcm(struct snd_riptide *chip, int device) strcpy(pcm->name, "RIPTIDE"); chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64 * 1024, 128 * 1024); return 0; } diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index b0b5e74e776c..ef7dd290ae05 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -905,7 +905,8 @@ static int sis_pcm_create(struct sis7019 *sis) * world if this fails. */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(sis->pci), 64*1024, 128*1024); + &sis->pci->dev, + 64*1024, 128*1024); return 0; } diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 13103f5c309b..31cbc811ad37 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -884,7 +884,8 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device) sonic->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(sonic->pci), 64*1024, 128*1024); + &sonic->pci->dev, + 64*1024, 128*1024); return 0; } diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 8ac6f541b008..07022c0dad40 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -2184,14 +2184,16 @@ int snd_trident_pcm(struct snd_trident *trident, int device) struct snd_pcm_substream *substream; for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(trident->pci), + &trident->pci->dev, 64*1024, 128*1024); snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, - SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), + SNDRV_DMA_TYPE_DEV, + &trident->pci->dev, 64*1024, 128*1024); } else { snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(trident->pci), 64*1024, 128*1024); + &trident->pci->dev, + 64*1024, 128*1024); } return 0; @@ -2241,10 +2243,12 @@ int snd_trident_foldback_pcm(struct snd_trident *trident, int device) if (trident->tlb.entries) snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(trident->pci), 0, 128*1024); + &trident->pci->dev, + 0, 128*1024); else snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(trident->pci), 64*1024, 128*1024); + &trident->pci->dev, + 64*1024, 128*1024); return 0; } @@ -2278,7 +2282,9 @@ int snd_trident_spdif_pcm(struct snd_trident *trident, int device) strcpy(spdif->name, "Trident 4DWave IEC958"); trident->spdif = spdif; - snd_pcm_lib_preallocate_pages_for_all(spdif, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(spdif, SNDRV_DMA_TYPE_DEV, + &trident->pci->dev, + 64*1024, 128*1024); return 0; } @@ -3336,7 +3342,7 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident) /* TLB array must be aligned to 16kB !!! so we allocate 32kB region and correct offset when necessary */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &trident->pci->dev, 2 * SNDRV_TRIDENT_MAX_PAGES * 4, &trident->tlb.buffer) < 0) { dev_err(trident->card->dev, "unable to allocate TLB buffer\n"); return -ENOMEM; @@ -3351,7 +3357,7 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident) return -ENOMEM; /* allocate and setup silent page and initialise TLB entries */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &trident->pci->dev, SNDRV_TRIDENT_PAGE_SIZE, &trident->tlb.silent_page) < 0) { dev_err(trident->card->dev, "unable to allocate silent page\n"); return -ENOMEM; diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 902409dbc4c8..30c817b6b635 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -419,7 +419,7 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre /* the start of each lists must be aligned to 8 bytes, * but the kernel pages are much bigger, so we don't care */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), &dev->table) < 0) return -ENOMEM; @@ -1454,7 +1454,7 @@ static int snd_via8233_pcm_new(struct via82xx *chip) init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 6, 1); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64*1024, VIA_MAX_BUFSIZE); err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -1478,7 +1478,7 @@ static int snd_via8233_pcm_new(struct via82xx *chip) init_viadev(chip, chip->capture_devno + 1, VIA_REG_CAPTURE_8233_STATUS + 0x10, 7, 1); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64*1024, VIA_MAX_BUFSIZE); err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -1521,7 +1521,7 @@ static int snd_via8233a_pcm_new(struct via82xx *chip) init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 6, 1); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64*1024, VIA_MAX_BUFSIZE); err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -1547,7 +1547,7 @@ static int snd_via8233a_pcm_new(struct via82xx *chip) init_viadev(chip, chip->playback_devno, 0x30, 3, 0); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64*1024, VIA_MAX_BUFSIZE); return 0; } @@ -1577,7 +1577,7 @@ static int snd_via686_pcm_new(struct via82xx *chip) init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 0, 1); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64*1024, VIA_MAX_BUFSIZE); return 0; } diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 2c8370cf03b3..0edb9ea6e8a6 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -272,7 +272,7 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre /* the start of each lists must be aligned to 8 bytes, * but the kernel pages are much bigger, so we don't care */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), &dev->table) < 0) return -ENOMEM; @@ -850,7 +850,7 @@ static int snd_via686_pcm_new(struct via82xx_modem *chip) init_viadev(chip, 1, VIA_REG_MI_STATUS, 1); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), + &chip->pci->dev, 64*1024, 128*1024); return 0; } diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 90400ebb64af..125c11ed5064 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -587,7 +587,7 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int static int snd_ymfpci_ac3_init(struct snd_ymfpci *chip) { - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, 4096, &chip->ac3_tmp_base) < 0) return -ENOMEM; @@ -1149,7 +1149,8 @@ int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 256*1024); + &chip->pci->dev, + 64*1024, 256*1024); return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_std_chmaps, 2, 0, NULL); @@ -1184,7 +1185,8 @@ int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device) chip->pcm2 = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 256*1024); + &chip->pci->dev, + 64*1024, 256*1024); return 0; } @@ -1217,7 +1219,8 @@ int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device) chip->pcm_spdif = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 256*1024); + &chip->pci->dev, + 64*1024, 256*1024); return 0; } @@ -1258,7 +1261,8 @@ int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device) chip->pcm_4ch = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 256*1024); + &chip->pci->dev, + 64*1024, 256*1024); return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, surround_map, 2, 0, NULL); @@ -2108,7 +2112,7 @@ static int snd_ymfpci_memalloc(struct snd_ymfpci *chip) chip->work_size; /* work_ptr must be aligned to 256 bytes, but it's already covered with the kernel page allocation mechanism */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, size, &chip->work_ptr) < 0) return -ENOMEM; ptr = chip->work_ptr.area; -- cgit From df95a16d2a9626dcfc3f2b3671c9b91fa076c997 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 6 Nov 2019 08:58:01 -0600 Subject: ASoC: soc-core: fix RIP warning on card removal SOF module load/unload tests show nasty recurring warnings: WARNING: CPU: 5 PID: 1339 at sound/core/control.c:466 snd_ctl_remove+0xf0/0x100 [snd] RIP: 0010:snd_ctl_remove+0xf0/0x100 [snd] This regression was introduced by the removal of the call to soc_remove_link_components() before soc_card_free() is invoked. Go back to the initial order but only call soc_remove_link_components() once. Reviewed-by: Ranjani Sridharan Acked-by: Kuninori Morimoto Fixes: 5a4c9f054ceea ("ASoC: soc-core: snd_soc_unbind_card() cleanup") GitHub issue: https://github.com/thesofproject/linux/issues/1424 Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191106145801.9316-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cc596871ba7f..a7ad81ec59db 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1974,6 +1974,9 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) { struct snd_soc_dai_link *link, *_link; + /* This should be called before snd_card_free() */ + soc_remove_link_components(card); + /* free the ALSA card at first; this syncs with pending operations */ if (card->snd_card) { snd_card_free(card->snd_card); @@ -1982,7 +1985,6 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) /* remove and free each DAI */ soc_remove_link_dais(card); - soc_remove_link_components(card); for_each_card_links_safe(card, link, _link) snd_soc_remove_dai_link(card, link); -- cgit From 18dd66ea84464a4bc86089276d5f75cadeb94a09 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Nov 2019 16:05:05 +0900 Subject: ASoC: soc-core: fixup dead-lock at snd_soc_unregister_component() snd_soc_unregister_component() is calling snd_soc_lookup_component() under mutex_lock(). But, snd_soc_lookup_component() itself is using mutex_lock(), thus it will be dead-lock. This patch adds _nolocked version of it, and avoid dead-lock issue. Fixes: ac6a4dd3e9f0("ASoC: soc-core: use snd_soc_lookup_component() at snd_soc_unregister_component()") Reported-by: "kernelci.org bot" " Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bltph4da.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a7ad81ec59db..55014e7ae0d8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -356,14 +356,13 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup); -struct snd_soc_component *snd_soc_lookup_component(struct device *dev, - const char *driver_name) +static struct snd_soc_component +*snd_soc_lookup_component_nolocked(struct device *dev, const char *driver_name) { struct snd_soc_component *component; struct snd_soc_component *found_component; found_component = NULL; - mutex_lock(&client_mutex); for_each_component(component) { if ((dev == component->dev) && (!driver_name || @@ -373,10 +372,21 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev, break; } } - mutex_unlock(&client_mutex); return found_component; } + +struct snd_soc_component *snd_soc_lookup_component(struct device *dev, + const char *driver_name) +{ + struct snd_soc_component *component; + + mutex_lock(&client_mutex); + component = snd_soc_lookup_component_nolocked(dev, driver_name); + mutex_unlock(&client_mutex); + + return component; +} EXPORT_SYMBOL_GPL(snd_soc_lookup_component); struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, @@ -2855,7 +2865,7 @@ void snd_soc_unregister_component(struct device *dev) mutex_lock(&client_mutex); while (1) { - component = snd_soc_lookup_component(dev, NULL); + component = snd_soc_lookup_component_nolocked(dev, NULL); if (!component) break; -- cgit From fdea53fe5de532969a332d6e5e727f2ad8bf084d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 6 Nov 2019 16:42:57 +0100 Subject: ALSA: timer: Limit max amount of slave instances The fuzzer tries to open the timer instances as much as possible, and this may cause a system hiccup easily. We've already introduced the cap for the max number of available instances for the h/w timers, and we should put such a limit also to the slave timers, too. This patch introduces the limit to the multiple opened slave timers. The upper limit is hard-coded to 1000 for now, which should suffice for any practical usages up to now. Link: https://lore.kernel.org/r/20191106154257.5853-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/timer.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 5c9fbf3f4340..219249627cc3 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -74,6 +74,9 @@ static LIST_HEAD(snd_timer_slave_list); /* lock for slave active lists */ static DEFINE_SPINLOCK(slave_active_lock); +#define MAX_SLAVE_INSTANCES 1000 +static int num_slaves; + static DEFINE_MUTEX(register_mutex); static int snd_timer_free(struct snd_timer *timer); @@ -250,6 +253,10 @@ int snd_timer_open(struct snd_timer_instance **ti, err = -EINVAL; goto unlock; } + if (num_slaves >= MAX_SLAVE_INSTANCES) { + err = -EBUSY; + goto unlock; + } timeri = snd_timer_instance_new(owner, NULL); if (!timeri) { err = -ENOMEM; @@ -259,6 +266,7 @@ int snd_timer_open(struct snd_timer_instance **ti, timeri->slave_id = tid->device; timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; list_add_tail(&timeri->open_list, &snd_timer_slave_list); + num_slaves++; err = snd_timer_check_slave(timeri); if (err < 0) { snd_timer_close_locked(timeri); @@ -350,6 +358,8 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri) } list_del(&timeri->open_list); + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) + num_slaves--; /* force to stop the timer */ snd_timer_stop(timeri); -- cgit From 2acdcabb8a4089476208a822050dd47a6557290d Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Wed, 6 Nov 2019 08:58:16 -0600 Subject: ASoC: SOF: topology: Fix bytes control size checks When using the example SOF amp widget topology, KASAN dumps this when the AMP bytes kcontrol gets loaded: [ 9.579548] BUG: KASAN: slab-out-of-bounds in sof_control_load+0x8cc/0xac0 [snd_sof] [ 9.588194] Write of size 40 at addr ffff8882314559dc by task systemd-udevd/2411 Fix that by rejecting the topology if the bytes data size > max_size Fixes: 311ce4fe7637d ("ASoC: SOF: Add support for loading topologies") Reviewed-by: Jaska Uimonen Reviewed-by: Ranjani Sridharan Signed-off-by: Dragos Tarcatu Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191106145816.9367-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e7076692119b..143b8259a70a 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1043,15 +1043,16 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; int max_size = sbe->max; - if (le32_to_cpu(control->priv.size) > max_size) { + /* init the get/put bytes data */ + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + le32_to_cpu(control->priv.size); + + if (scontrol->size > max_size) { dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", - control->priv.size, max_size); + scontrol->size, max_size); return -EINVAL; } - /* init the get/put bytes data */ - scontrol->size = sizeof(struct sof_ipc_ctrl_data) + - le32_to_cpu(control->priv.size); scontrol->control_data = kzalloc(max_size, GFP_KERNEL); cdata = scontrol->control_data; if (!scontrol->control_data) -- cgit From bd0b609e0c3362cb167c51d4bd4330d79fc00987 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Nov 2019 14:48:33 +0100 Subject: ASoC: core: Fix compile warning with CONFIG_DEBUG_FS=n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Paper over a compile warning: sound/soc/soc-pcm.c:1185:8: warning: unused variable ‘name’ Fixes: 0632fa042541 ("ASoC: core: Fix pcm code debugfs error") Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20191107134833.1502-1-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 493a2e80e893..4bf71e3211d8 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1182,7 +1182,9 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, { struct snd_soc_dpcm *dpcm; unsigned long flags; +#ifdef CONFIG_DEBUG_FS char *name; +#endif /* only add new dpcms */ for_each_dpcm_be(fe, stream, dpcm) { -- cgit From 8cd73ce7ba6381feb9df763240dee3a6d4aff1ca Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 1 Nov 2019 12:09:14 -0500 Subject: ASoC: SOF: topology: fix missing NULL pointer check Add check to avoid possible NULL pointer dereference issue. This issue was reported by static analysis tools, we didn't face this issue but we can't rule it out either as a false positive. Reported-by: Keqiao Zhang Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101170916.26517-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 143b8259a70a..6096731e89ce 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -150,6 +150,11 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, /* get runtime PCM params using widget's stream name */ spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname); + if (!spcm) { + dev_err(sdev->dev, "error: cannot find PCM for %s\n", + swidget->widget->name); + return -EINVAL; + } /* process events */ switch (event) { -- cgit From 16299326a0cbbc88d4d6491a8ceebbfca81064c5 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 1 Nov 2019 12:09:15 -0500 Subject: ASoC: SOF: Intel: hda: set L1SEN on S0ix suspend Set L1SEN to make sure the system can enter S0ix, and restore it on resume. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191101170916.26517-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 15 +++++++++++++++ sound/soc/sof/intel/hda.h | 3 +++ 2 files changed, 18 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 8cd5ecc01b62..4a4d318f97ff 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -478,9 +478,16 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) int hda_dsp_resume(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct pci_dev *pci = to_pci_dev(sdev->dev); if (sdev->s0_suspend) { + /* restore L1SEN bit */ + if (hda->l1_support_changed) + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, 0); + /* restore and disable the system wakeup */ pci_restore_state(pci); disable_irq_wake(pci->irq); @@ -518,11 +525,19 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) int hda_dsp_suspend(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; if (sdev->s0_suspend) { + /* enable L1SEN to make sure the system can enter S0Ix */ + hda->l1_support_changed = + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, + HDA_VS_INTEL_EM2_L1SEN); + /* enable the system waking up via IPC IRQ */ enable_irq_wake(pci->irq); pci_save_state(pci); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 5ad73a34b09c..18d7e72bf9b7 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -408,6 +408,9 @@ struct sof_intel_hda_dev { int irq; + /* PM related */ + bool l1_support_changed;/* during suspend, is L1SEN changed or not */ + /* DMIC device */ struct platform_device *dmic_dev; }; -- cgit From ebfc6de29ae8e48f91e280fd37539188b5252b38 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Nov 2019 20:20:06 +0100 Subject: ALSA: timer: Unify master/slave linking code The code in both snd_timer_check_master() and snd_timer_check_slave() are almost identical, both check whether the master/slave link and does linkage. Factor out the common code and call it from both functions for readability. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20191107192008.32331-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/timer.c | 66 +++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 013f0e69ff0f..21c2d25e4074 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -163,6 +163,28 @@ static void snd_timer_request(struct snd_timer_id *tid) #endif +/* move the slave if it belongs to the master; return 1 if match */ +static int check_matching_master_slave(struct snd_timer_instance *master, + struct snd_timer_instance *slave) +{ + if (slave->slave_class != master->slave_class || + slave->slave_id != master->slave_id) + return 0; + if (master->timer->num_instances >= master->timer->max_instances) + return -EBUSY; + list_move_tail(&slave->open_list, &master->slave_list_head); + master->timer->num_instances++; + spin_lock_irq(&slave_active_lock); + spin_lock(&master->timer->lock); + slave->master = master; + slave->timer = master->timer; + if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) + list_add_tail(&slave->active_list, &master->slave_active_head); + spin_unlock(&master->timer->lock); + spin_unlock_irq(&slave_active_lock); + return 1; +} + /* * look for a master instance matching with the slave id of the given slave. * when found, relink the open_link of the slave. @@ -173,27 +195,18 @@ static int snd_timer_check_slave(struct snd_timer_instance *slave) { struct snd_timer *timer; struct snd_timer_instance *master; + int err = 0; /* FIXME: it's really dumb to look up all entries.. */ list_for_each_entry(timer, &snd_timer_list, device_list) { list_for_each_entry(master, &timer->open_list_head, open_list) { - if (slave->slave_class == master->slave_class && - slave->slave_id == master->slave_id) { - if (master->timer->num_instances >= - master->timer->max_instances) - return -EBUSY; - list_move_tail(&slave->open_list, - &master->slave_list_head); - master->timer->num_instances++; - spin_lock_irq(&slave_active_lock); - slave->master = master; - slave->timer = master->timer; - spin_unlock_irq(&slave_active_lock); - return 0; - } + err = check_matching_master_slave(master, slave); + if (err != 0) /* match found or error */ + goto out; } } - return 0; + out: + return err < 0 ? err : 0; } /* @@ -205,28 +218,15 @@ static int snd_timer_check_slave(struct snd_timer_instance *slave) static int snd_timer_check_master(struct snd_timer_instance *master) { struct snd_timer_instance *slave, *tmp; + int err = 0; /* check all pending slaves */ list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { - if (slave->slave_class == master->slave_class && - slave->slave_id == master->slave_id) { - if (master->timer->num_instances >= - master->timer->max_instances) - return -EBUSY; - list_move_tail(&slave->open_list, &master->slave_list_head); - master->timer->num_instances++; - spin_lock_irq(&slave_active_lock); - spin_lock(&master->timer->lock); - slave->master = master; - slave->timer = master->timer; - if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) - list_add_tail(&slave->active_list, - &master->slave_active_head); - spin_unlock(&master->timer->lock); - spin_unlock_irq(&slave_active_lock); - } + err = check_matching_master_slave(master, slave); + if (err < 0) + break; } - return 0; + return err < 0 ? err : 0; } static int snd_timer_close_locked(struct snd_timer_instance *timeri, -- cgit From 33bbb8a0ecd142fb5e78f26f3a0b927ae77c30e7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Nov 2019 20:20:07 +0100 Subject: ALSA: timer: Make snd_timer_close() returning void The function doesn't return any useful value, so let's make it void to be clearer. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20191107192008.32331-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/timer.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 21c2d25e4074..c0a73913ec62 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -229,8 +229,8 @@ static int snd_timer_check_master(struct snd_timer_instance *master) return err < 0 ? err : 0; } -static int snd_timer_close_locked(struct snd_timer_instance *timeri, - struct device **card_devp_to_put); +static void snd_timer_close_locked(struct snd_timer_instance *timeri, + struct device **card_devp_to_put); /* * open a timer instance @@ -351,8 +351,8 @@ EXPORT_SYMBOL(snd_timer_open); * close a timer instance * call this with register_mutex down. */ -static int snd_timer_close_locked(struct snd_timer_instance *timeri, - struct device **card_devp_to_put) +static void snd_timer_close_locked(struct snd_timer_instance *timeri, + struct device **card_devp_to_put) { struct snd_timer *timer = timeri->timer; struct snd_timer_instance *slave, *tmp; @@ -414,28 +414,24 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri, *card_devp_to_put = &timer->card->card_dev; module_put(timer->module); } - - return 0; } /* * close a timer instance */ -int snd_timer_close(struct snd_timer_instance *timeri) +void snd_timer_close(struct snd_timer_instance *timeri) { struct device *card_dev_to_put = NULL; - int err; if (snd_BUG_ON(!timeri)) - return -ENXIO; + return; mutex_lock(®ister_mutex); - err = snd_timer_close_locked(timeri, &card_dev_to_put); + snd_timer_close_locked(timeri, &card_dev_to_put); mutex_unlock(®ister_mutex); /* put_device() is called after unlock for avoiding deadlock */ if (card_dev_to_put) put_device(card_dev_to_put); - return err; } EXPORT_SYMBOL(snd_timer_close); -- cgit From 6a34367e52caea1413eb0a0dcbb524f0c9b67e82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Nov 2019 20:20:08 +0100 Subject: ALSA: timer: Fix possible race at assigning a timer instance When a new timer instance is created and assigned to the active link in snd_timer_open(), the caller still doesn't (can't) set its callback and callback data. In both the user-timer and the sequencer-timer code, they do manually set up the callbacks after calling snd_timer_open(). This has a potential risk of race when the timer instance is added to the already running timer target, as the callback might get triggered during setting up the callback itself. This patch tries to address it by changing the API usage slightly: - An empty timer instance is created at first via the new function snd_timer_instance_new(). This object isn't linked to the timer list yet. - The caller sets up the callbacks and others stuff for the new timer instance. - The caller invokes snd_timer_open() with this instance, so that it's linked to the target timer. For closing, do similarly: - Call snd_timer_close(). This unlinks the timer instance from the timer list. - Free the timer instance via snd_timer_instance_free() after that. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20191107192008.32331-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/seq/seq_timer.c | 18 ++++++--- sound/core/timer.c | 97 +++++++++++++++++++++++----------------------- 2 files changed, 60 insertions(+), 55 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 161f3170bd7e..63dc7bdb622d 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -272,7 +272,13 @@ int snd_seq_timer_open(struct snd_seq_queue *q) return -EINVAL; if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) tmr->alsa_id.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER; - err = snd_timer_open(&t, str, &tmr->alsa_id, q->queue); + t = snd_timer_instance_new(str); + if (!t) + return -ENOMEM; + t->callback = snd_seq_timer_interrupt; + t->callback_data = q; + t->flags |= SNDRV_TIMER_IFLG_AUTO; + err = snd_timer_open(t, &tmr->alsa_id, q->queue); if (err < 0 && tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) { if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_GLOBAL || tmr->alsa_id.device != SNDRV_TIMER_GLOBAL_SYSTEM) { @@ -282,16 +288,14 @@ int snd_seq_timer_open(struct snd_seq_queue *q) tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER; tid.card = -1; tid.device = SNDRV_TIMER_GLOBAL_SYSTEM; - err = snd_timer_open(&t, str, &tid, q->queue); + err = snd_timer_open(t, &tid, q->queue); } } if (err < 0) { pr_err("ALSA: seq fatal error: cannot create timer (%i)\n", err); + snd_timer_instance_free(t); return err; } - t->callback = snd_seq_timer_interrupt; - t->callback_data = q; - t->flags |= SNDRV_TIMER_IFLG_AUTO; spin_lock_irq(&tmr->lock); tmr->timeri = t; spin_unlock_irq(&tmr->lock); @@ -310,8 +314,10 @@ int snd_seq_timer_close(struct snd_seq_queue *q) t = tmr->timeri; tmr->timeri = NULL; spin_unlock_irq(&tmr->lock); - if (t) + if (t) { snd_timer_close(t); + snd_timer_instance_free(t); + } return 0; } diff --git a/sound/core/timer.c b/sound/core/timer.c index c0a73913ec62..9091030f4a89 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -88,12 +88,11 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l /* * create a timer instance with the given owner string. - * when timer is not NULL, increments the module counter */ -static struct snd_timer_instance *snd_timer_instance_new(char *owner, - struct snd_timer *timer) +struct snd_timer_instance *snd_timer_instance_new(const char *owner) { struct snd_timer_instance *timeri; + timeri = kzalloc(sizeof(*timeri), GFP_KERNEL); if (timeri == NULL) return NULL; @@ -108,15 +107,20 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner, INIT_LIST_HEAD(&timeri->slave_list_head); INIT_LIST_HEAD(&timeri->slave_active_head); - timeri->timer = timer; - if (timer && !try_module_get(timer->module)) { + return timeri; +} +EXPORT_SYMBOL(snd_timer_instance_new); + +void snd_timer_instance_free(struct snd_timer_instance *timeri) +{ + if (timeri) { + if (timeri->private_free) + timeri->private_free(timeri); kfree(timeri->owner); kfree(timeri); - return NULL; } - - return timeri; } +EXPORT_SYMBOL(snd_timer_instance_free); /* * find a timer instance from the given timer id @@ -236,12 +240,11 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri, * open a timer instance * when opening a master, the slave id must be here given. */ -int snd_timer_open(struct snd_timer_instance **ti, - char *owner, struct snd_timer_id *tid, +int snd_timer_open(struct snd_timer_instance *timeri, + struct snd_timer_id *tid, unsigned int slave_id) { struct snd_timer *timer; - struct snd_timer_instance *timeri = NULL; struct device *card_dev_to_put = NULL; int err; @@ -259,22 +262,14 @@ int snd_timer_open(struct snd_timer_instance **ti, err = -EBUSY; goto unlock; } - timeri = snd_timer_instance_new(owner, NULL); - if (!timeri) { - err = -ENOMEM; - goto unlock; - } timeri->slave_class = tid->dev_sclass; timeri->slave_id = tid->device; timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; list_add_tail(&timeri->open_list, &snd_timer_slave_list); num_slaves++; err = snd_timer_check_slave(timeri); - if (err < 0) { - snd_timer_close_locked(timeri, &card_dev_to_put); - timeri = NULL; - } - goto unlock; + if (err < 0) + goto close; } /* open a master instance */ @@ -304,45 +299,40 @@ int snd_timer_open(struct snd_timer_instance **ti, err = -EBUSY; goto unlock; } - timeri = snd_timer_instance_new(owner, timer); - if (!timeri) { - err = -ENOMEM; + if (!try_module_get(timer->module)) { + err = -EBUSY; goto unlock; } /* take a card refcount for safe disconnection */ - if (timer->card) + if (timer->card) { get_device(&timer->card->card_dev); - timeri->slave_class = tid->dev_sclass; - timeri->slave_id = slave_id; + card_dev_to_put = &timer->card->card_dev; + } if (list_empty(&timer->open_list_head) && timer->hw.open) { err = timer->hw.open(timer); if (err) { - kfree(timeri->owner); - kfree(timeri); - timeri = NULL; - - if (timer->card) - card_dev_to_put = &timer->card->card_dev; module_put(timer->module); goto unlock; } } + timeri->timer = timer; + timeri->slave_class = tid->dev_sclass; + timeri->slave_id = slave_id; + list_add_tail(&timeri->open_list, &timer->open_list_head); timer->num_instances++; err = snd_timer_check_master(timeri); - if (err < 0) { + close: + if (err < 0) snd_timer_close_locked(timeri, &card_dev_to_put); - timeri = NULL; - } unlock: mutex_unlock(®ister_mutex); /* put_device() is called after unlock for avoiding deadlock */ - if (card_dev_to_put) + if (err < 0 && card_dev_to_put) put_device(card_dev_to_put); - *ti = timeri; return err; } EXPORT_SYMBOL(snd_timer_open); @@ -363,9 +353,11 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri, spin_unlock_irq(&timer->lock); } - list_del(&timeri->open_list); - if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) - num_slaves--; + if (!list_empty(&timeri->open_list)) { + list_del_init(&timeri->open_list); + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) + num_slaves--; + } /* force to stop the timer */ snd_timer_stop(timeri); @@ -384,6 +376,7 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri, /* remove slave links */ spin_lock_irq(&slave_active_lock); spin_lock(&timer->lock); + timeri->timer = NULL; list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) { list_move_tail(&slave->open_list, &snd_timer_slave_list); @@ -401,11 +394,6 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri, timer = NULL; } - if (timeri->private_free) - timeri->private_free(timeri); - kfree(timeri->owner); - kfree(timeri); - if (timer) { if (list_empty(&timer->open_list_head) && timer->hw.close) timer->hw.close(timer); @@ -1480,8 +1468,10 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) tu = file->private_data; file->private_data = NULL; mutex_lock(&tu->ioctl_lock); - if (tu->timeri) + if (tu->timeri) { snd_timer_close(tu->timeri); + snd_timer_instance_free(tu->timeri); + } mutex_unlock(&tu->ioctl_lock); kfree(tu->queue); kfree(tu->tqueue); @@ -1722,6 +1712,7 @@ static int snd_timer_user_tselect(struct file *file, tu = file->private_data; if (tu->timeri) { snd_timer_close(tu->timeri); + snd_timer_instance_free(tu->timeri); tu->timeri = NULL; } if (copy_from_user(&tselect, _tselect, sizeof(tselect))) { @@ -1731,9 +1722,11 @@ static int snd_timer_user_tselect(struct file *file, sprintf(str, "application %i", current->pid); if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; - err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid); - if (err < 0) + tu->timeri = snd_timer_instance_new(str); + if (!tu->timeri) { + err = -ENOMEM; goto __err; + } tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; tu->timeri->callback = tu->tread @@ -1742,6 +1735,12 @@ static int snd_timer_user_tselect(struct file *file, tu->timeri->callback_data = (void *)tu; tu->timeri->disconnect = snd_timer_user_disconnect; + err = snd_timer_open(tu->timeri, &tselect.id, current->pid); + if (err < 0) { + snd_timer_instance_free(tu->timeri); + tu->timeri = NULL; + } + __err: return err; } -- cgit From 2406ff9b86aa1b77fe1a6d15f37195ac1fdb2a14 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Nov 2019 17:56:26 +0100 Subject: ALSA: pcm: Yet another missing check of non-cached buffer type For non-x86 architectures, SNDRV_DMA_TYPE_DEV_UC should be treated equivalent with SNDRV_DMA_TYPE_DEV, where the default mmap handler still checks only about SNDRV_DMA_TYPE_DEV. Make the check more proper. Note that all existing users of *_UC buffer types are x86-only, so this doesn't fix any bug, but just for consistency. Fixes: 42e748a0b325 ("ALSA: memalloc: Add non-cached buffer type") Link: https://lore.kernel.org/r/20191108165626.5947-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 998c63192ae4..0c27009dc3df 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3416,7 +3416,8 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, #endif /* CONFIG_GENERIC_ALLOCATOR */ #ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */ if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page && - substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) + (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV || + substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_UC)) return dma_mmap_coherent(substream->dma_buffer.dev.dev, area, substream->runtime->dma_area, -- cgit From 1a4860325cc740b4ec4b849f31fa694cf8870569 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Nov 2019 10:46:34 +0100 Subject: ASoC: Remove superfluous snd_dma_continuous_data() The recent change (commit 08422d2c559d: "ALSA: memalloc: Allow NULL device for SNDRV_DMA_TYPE_CONTINOUS type") made the PCM preallocation helper accepting NULL as the device pointer for the default usage. Drop the snd_dma_continuous_data() usage that became superfluous from the callers. Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191108094641.20086-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/au1x/dma.c | 2 +- sound/soc/dwc/dwc-pcm.c | 2 +- sound/soc/sh/dma-sh7760.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c index 49556eb409cd..054dfda89d3e 100644 --- a/sound/soc/au1x/dma.c +++ b/sound/soc/au1x/dma.c @@ -293,7 +293,7 @@ static int alchemy_pcm_new(struct snd_soc_component *component, struct snd_pcm *pcm = rtd->pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), 65536, (4096 * 1024) - 1); + NULL, 65536, (4096 * 1024) - 1); return 0; } diff --git a/sound/soc/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c index de6fcc808832..4771eb5fbe2a 100644 --- a/sound/soc/dwc/dwc-pcm.c +++ b/sound/soc/dwc/dwc-pcm.c @@ -258,7 +258,7 @@ static int dw_pcm_new(struct snd_soc_component *component, snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), size, size); + NULL, size, size); return 0; } diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 93bb80d089be..2b0eca02a8b9 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -309,7 +309,7 @@ static int camelot_pcm_new(struct snd_soc_component *component, */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + NULL, DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX); return 0; -- cgit From 26105a6f05709ad7059c91e28005a5c75be24819 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Nov 2019 10:46:35 +0100 Subject: ASoC: rt5514-spi: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Since it requires the specific buffer type (SNDRV_DMA_TYPE_VMALLOC), it's set in the pcm_new ops now. Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191108094641.20086-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/codecs/rt5514-spi.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 57ff5aee452d..f1b7b947ecbd 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -219,8 +219,7 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component, u8 buf[8]; mutex_lock(&rt5514_dsp->dma_lock); - ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); rt5514_dsp->substream = substream; rt5514_dsp->dma_offset = 0; @@ -246,7 +245,7 @@ static int rt5514_spi_hw_free(struct snd_soc_component *component, cancel_delayed_work_sync(&rt5514_dsp->copy_work); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static snd_pcm_uframes_t rt5514_spi_pcm_pointer( @@ -260,12 +259,6 @@ static snd_pcm_uframes_t rt5514_spi_pcm_pointer( return bytes_to_frames(runtime, rt5514_dsp->dma_offset); } -static struct page *rt5514_spi_pcm_page(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - unsigned long offset) -{ - return snd_pcm_lib_get_vmalloc_page(substream, offset); -} static int rt5514_spi_pcm_probe(struct snd_soc_component *component) { @@ -298,6 +291,14 @@ static int rt5514_spi_pcm_probe(struct snd_soc_component *component) return 0; } +static int rt5514_spi_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); + return 0; +} + static const struct snd_soc_component_driver rt5514_spi_component = { .name = DRV_NAME, .probe = rt5514_spi_pcm_probe, @@ -305,7 +306,7 @@ static const struct snd_soc_component_driver rt5514_spi_component = { .hw_params = rt5514_spi_hw_params, .hw_free = rt5514_spi_hw_free, .pointer = rt5514_spi_pcm_pointer, - .page = rt5514_spi_pcm_page, + .pcm_construct = rt5514_spi_pcm_new, }; /** -- cgit From 1508f32f1adb220e61d1b7839e35d93ebee89f58 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Nov 2019 10:46:36 +0100 Subject: ASoC: intel: Drop superfluous snd_pcm_sgbuf_ops_page snd_pcm_sgbuf_ops_page is no longer needed to be set explicitly to PCM page ops since the recent change in the PCM core (*). Leaving it NULL should work as long as the preallocation has been done properly. This patch drops the redundant lines. (*) 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191108094641.20086-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/intel/haswell/sst-haswell-pcm.c | 12 ------------ sound/soc/intel/skylake/skl-pcm.c | 12 ------------ 2 files changed, 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 6e498a581d20..a3a5bba2fbd9 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -796,17 +796,6 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_soc_component *component, return offset; } -#ifdef CONFIG_SND_DMA_SGBUF -static struct page *hsw_pcm_page(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - unsigned long offset) -{ - return snd_pcm_sgbuf_ops_page(substream, offset); -} -#else -#define hsw_pcm_page NULL -#endif /* CONFIG_SND_DMA_SGBUF */ - static int hsw_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -1128,7 +1117,6 @@ static const struct snd_soc_component_driver hsw_dai_component = { .hw_free = hsw_pcm_hw_free, .trigger = hsw_pcm_trigger, .pointer = hsw_pcm_pointer, - .page = hsw_pcm_page, .ioctl = snd_soc_pcm_lib_ioctl, .pcm_construct = hsw_pcm_new, .controls = hsw_volume_controls, diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 0850141c7d47..6bd14f65fe71 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1235,17 +1235,6 @@ static int skl_platform_soc_mmap(struct snd_soc_component *component, return snd_pcm_lib_default_mmap(substream, area); } -#ifdef CONFIG_SND_DMA_SGBUF -static struct page *skl_platform_soc_page(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - unsigned long offset) -{ - return snd_pcm_sgbuf_ops_page(substream, offset); -} -#else -#define skl_platform_soc_page NULL -#endif /* CONFIG_SND_DMA_SGBUF */ - static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, u64 nsec) { @@ -1493,7 +1482,6 @@ static const struct snd_soc_component_driver skl_component = { .pointer = skl_platform_soc_pointer, .get_time_info = skl_platform_soc_get_time_info, .mmap = skl_platform_soc_mmap, - .page = skl_platform_soc_page, .pcm_construct = skl_platform_soc_new, .pcm_destruct = skl_platform_soc_free, .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ -- cgit From 6420c24a30006e2fdbc292f88d37db56ca28f6e8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Nov 2019 10:46:37 +0100 Subject: ASoC: intel: Avoid non-standard macro usage Pass the device pointer from the PCI pointer directly, instead of a non-standard macro. The macro didn't give any better readability. Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191108094641.20086-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/intel/skylake/skl-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 6bd14f65fe71..8b9abb79a69e 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1314,7 +1314,7 @@ static int skl_platform_soc_new(struct snd_soc_component *component, size = MAX_PREALLOC_SIZE; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(skl->pci), + &skl->pci->dev, size, MAX_PREALLOC_SIZE); } -- cgit From b01aa131fae9da3c1898baff17176307c0e23e12 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Nov 2019 10:46:38 +0100 Subject: ASoC: SOF: Drop superfluous snd_pcm_sgbuf_ops_page snd_pcm_sgbuf_ops_page is no longer needed to be set explicitly to PCM page ops since the recent change in the PCM core (*). Leaving it NULL should work as long as the preallocation has been done properly. This patch drops the redundant lines. (*) 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191108094641.20086-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/sof/pcm.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 3d5cd1b445ba..549238a98b2a 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -454,17 +454,6 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component, return host; } -#ifdef CONFIG_SND_DMA_SGBUF -static struct page *sof_pcm_page(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - unsigned long offset) -{ - return snd_pcm_sgbuf_ops_page(substream, offset); -} -#else -#define sof_pcm_page NULL -#endif /* CONFIG_SND_DMA_SGBUF */ - static int sof_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -788,7 +777,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->hw_free = sof_pcm_hw_free; pd->trigger = sof_pcm_trigger; pd->pointer = sof_pcm_pointer; - pd->page = sof_pcm_page; #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) pd->compr_ops = &sof_compressed_ops; -- cgit From f541220cd590e4a7436913d6f7d41ff4aba67982 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Nov 2019 10:46:39 +0100 Subject: ASoC: rt5677-spi: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Acked-by: Mark Brown Acked-by: Curtis Malainey Link: https://lore.kernel.org/r/20191108094641.20086-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/codecs/rt5677-spi.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 3aa3ea7c2768..0c90f99b693f 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -128,8 +128,7 @@ static int rt5677_spi_hw_params( int ret; mutex_lock(&rt5677_dsp->dma_lock); - ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); rt5677_dsp->substream = substream; mutex_unlock(&rt5677_dsp->dma_lock); @@ -147,7 +146,7 @@ static int rt5677_spi_hw_free( rt5677_dsp->substream = NULL; mutex_unlock(&rt5677_dsp->dma_lock); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static int rt5677_spi_prepare( @@ -361,12 +360,12 @@ done: mutex_unlock(&rt5677_dsp->dma_lock); } -static struct page *rt5677_spi_pcm_page( - struct snd_soc_component *component, - struct snd_pcm_substream *substream, - unsigned long offset) +static int rt5677_spi_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { - return snd_pcm_lib_get_vmalloc_page(substream, offset); + snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); + return 0; } static int rt5677_spi_pcm_probe(struct snd_soc_component *component) @@ -394,7 +393,7 @@ static const struct snd_soc_component_driver rt5677_spi_dai_component = { .hw_free = rt5677_spi_hw_free, .prepare = rt5677_spi_prepare, .pointer = rt5677_spi_pcm_pointer, - .page = rt5677_spi_pcm_page, + .pcm_construct = rt5677_spi_pcm_new, }; /* Select a suitable transfer command for the next transfer to ensure -- cgit From e610748ad4388f02a2cd8b3ad051a662c03dbfbc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Nov 2019 10:46:40 +0100 Subject: ASoC: cros_ec_codec: Convert to the common vmalloc memalloc The recent change (*) in the ALSA memalloc core allows us to drop the special vmalloc-specific allocation and page handling. This patch coverts to the common code. (*) 1fe7f397cfe2: ALSA: memalloc: Add vmalloc buffer allocation support 7e8edae39fd1: ALSA: pcm: Handle special page mapping in the default mmap handler Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191108094641.20086-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/codecs/cros_ec_codec.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index dd14caf9091a..7b17f39a6a10 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -918,8 +918,7 @@ static int wov_pcm_hw_params(struct snd_soc_component *component, priv->wov_burst_read = true; mutex_unlock(&priv->wov_dma_lock); - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } static int wov_pcm_hw_free(struct snd_soc_component *component, @@ -935,7 +934,7 @@ static int wov_pcm_hw_free(struct snd_soc_component *component, cancel_delayed_work_sync(&priv->wov_copy_work); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static snd_pcm_uframes_t wov_pcm_pointer(struct snd_soc_component *component, @@ -948,11 +947,12 @@ static snd_pcm_uframes_t wov_pcm_pointer(struct snd_soc_component *component, return bytes_to_frames(runtime, priv->wov_dma_offset); } -static struct page *wov_pcm_page(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - unsigned long offset) +static int wov_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { - return snd_pcm_lib_get_vmalloc_page(substream, offset); + snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); + return 0; } static const struct snd_soc_component_driver wov_component_driver = { @@ -964,7 +964,7 @@ static const struct snd_soc_component_driver wov_component_driver = { .hw_params = wov_pcm_hw_params, .hw_free = wov_pcm_hw_free, .pointer = wov_pcm_pointer, - .page = wov_pcm_page, + .pcm_construct = wov_pcm_new, }; static int cros_ec_codec_platform_probe(struct platform_device *pdev) -- cgit From fc7af6bc2707e32d73c639d63f1543d890a00db4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Nov 2019 10:46:41 +0100 Subject: ALSA: pcm: Unexport snd_pcm_sgbuf_ops_page The helper is no longer referred after the recent code refactoring. Drop the export for saving some bits and future misuse. Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191108094641.20086-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_local.h | 5 +++++ sound/core/pcm_memory.c | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index 1161ab2d6a5b..5565e1c4196a 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h @@ -67,4 +67,9 @@ static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} void __snd_pcm_xrun(struct snd_pcm_substream *substream); void snd_pcm_group_init(struct snd_pcm_group *group); +#ifdef CONFIG_SND_DMA_SGBUF +struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, + unsigned long offset); +#endif + #endif /* __SOUND_CORE_PCM_LOCAL_H */ diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 17ee361ce791..286f333f8e4c 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -255,7 +255,7 @@ void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); #ifdef CONFIG_SND_DMA_SGBUF -/** +/* * snd_pcm_sgbuf_ops_page - get the page struct at the given offset * @substream: the pcm substream instance * @offset: the buffer offset @@ -273,7 +273,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne return NULL; return sgbuf->page_table[idx]; } -EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); #endif /* CONFIG_SND_DMA_SGBUF */ /** -- cgit From fe965096c9495ddcf78ec163348105e2baf8d185 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 11 Nov 2019 15:50:48 +0800 Subject: ASoC: fsl_audmix: Add spin lock to protect tdms Audmix support two substream, When two substream start to run, the trigger function may be called by two substream in same time, that the priv->tdms may be updated wrongly. The expected priv->tdms is 0x3, but sometimes the result is 0x2, or 0x1. Fixes: be1df61cf06e ("ASoC: fsl: Add Audio Mixer CPU DAI driver") Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/1e706afe53fdd1fbbbc79277c48a98f8416ba873.1573458378.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown Cc: --- sound/soc/fsl/fsl_audmix.c | 6 ++++++ sound/soc/fsl/fsl_audmix.h | 1 + 2 files changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index c7e4e9757dce..a1db1bce330f 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -286,6 +286,7 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct fsl_audmix *priv = snd_soc_dai_get_drvdata(dai); + unsigned long lock_flags; /* Capture stream shall not be handled */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) @@ -295,12 +296,16 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + spin_lock_irqsave(&priv->lock, lock_flags); priv->tdms |= BIT(dai->driver->id); + spin_unlock_irqrestore(&priv->lock, lock_flags); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock_irqsave(&priv->lock, lock_flags); priv->tdms &= ~BIT(dai->driver->id); + spin_unlock_irqrestore(&priv->lock, lock_flags); break; default: return -EINVAL; @@ -491,6 +496,7 @@ static int fsl_audmix_probe(struct platform_device *pdev) return PTR_ERR(priv->ipg_clk); } + spin_lock_init(&priv->lock); platform_set_drvdata(pdev, priv); pm_runtime_enable(dev); diff --git a/sound/soc/fsl/fsl_audmix.h b/sound/soc/fsl/fsl_audmix.h index 7812ffec45c5..479f05695d53 100644 --- a/sound/soc/fsl/fsl_audmix.h +++ b/sound/soc/fsl/fsl_audmix.h @@ -96,6 +96,7 @@ struct fsl_audmix { struct platform_device *pdev; struct regmap *regmap; struct clk *ipg_clk; + spinlock_t lock; /* Protect tdms */ u8 tdms; }; -- cgit From 461c623270e4fa9cbab44e3ac2f0ddab2842c034 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Tue, 5 Nov 2019 17:13:26 -0800 Subject: ASoC: rt5677: Load firmware via SPI using delayed work The firmware rt5677_elf_vad is an ELF binary obtained from request_firmware(). Sections of the ELF are loaded to the DSP via SPI. A model (e.g. en_us.mmap) can optionally be loaded to the DSP at RT5677_MODEL_ADDR to overwrite the baked-in model in rt5677_elf_vad. Then we switch to DSP mode, load firmware, and let DSP run. When a hotword is detected, an interrupt is fired and rt5677_irq() is called. When 'DSP VAD Switch' is turned off, the codec is set back to normal mode. The kcontrol 'DSP VAD Switch' is automatically enabled/disabled when the hotwording PCM stream is opened/closed. Signed-off-by: Ben Zhang Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-2-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 13 ++ sound/soc/codecs/rt5677.c | 301 +++++++++++++++++++++++++++++++++--------- sound/soc/codecs/rt5677.h | 6 +- 3 files changed, 253 insertions(+), 67 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 3aa3ea7c2768..25e28be3722e 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -26,6 +26,7 @@ #include +#include "rt5677.h" #include "rt5677-spi.h" #define DRV_NAME "rt5677spi" @@ -111,10 +112,16 @@ static int rt5677_spi_pcm_close( struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *codec_component = + snd_soc_rtdcom_lookup(rtd, "rt5677"); + struct rt5677_priv *rt5677 = + snd_soc_component_get_drvdata(codec_component); struct rt5677_dsp *rt5677_dsp = snd_soc_component_get_drvdata(component); cancel_delayed_work_sync(&rt5677_dsp->copy_work); + rt5677->set_dsp_vad(codec_component, false); return 0; } @@ -154,9 +161,15 @@ static int rt5677_spi_prepare( struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *rt5677_component = + snd_soc_rtdcom_lookup(rtd, "rt5677"); + struct rt5677_priv *rt5677 = + snd_soc_component_get_drvdata(rt5677_component); struct rt5677_dsp *rt5677_dsp = snd_soc_component_get_drvdata(component); + rt5677->set_dsp_vad(rt5677_component, true); rt5677_dsp->dma_offset = 0; rt5677_dsp->avail_bytes = 0; return 0; diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 315a3d39bc09..13f21bf4e04e 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -38,6 +38,10 @@ #define RT5677_DEVICE_ID 0x6327 +/* Register controlling boot vector */ +#define RT5677_DSP_BOOT_VECTOR 0x1801f090 +#define RT5677_MODEL_ADDR 0x5FFC9800 + #define RT5677_PR_RANGE_BASE (0xff + 1) #define RT5677_PR_SPACING 0x100 @@ -686,10 +690,8 @@ static int rt5677_dsp_mode_i2c_read( return ret; } -static void rt5677_set_dsp_mode(struct snd_soc_component *component, bool on) +static void rt5677_set_dsp_mode(struct rt5677_priv *rt5677, bool on) { - struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); - if (on) { regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, RT5677_PWR_DSP, RT5677_PWR_DSP); @@ -701,86 +703,234 @@ static void rt5677_set_dsp_mode(struct snd_soc_component *component, bool on) } } +static unsigned int rt5677_set_vad_source(struct rt5677_priv *rt5677) +{ + /* DMIC1 power = enabled + * DMIC CLK = 256 * fs / 12 + */ + regmap_update_bits(rt5677->regmap, RT5677_DMIC_CTRL1, + RT5677_DMIC_CLK_MASK, 5 << RT5677_DMIC_CLK_SFT); + + /* I2S pre divide 2 = /6 (clk_sys2) */ + regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1, + RT5677_I2S_PD2_MASK, RT5677_I2S_PD2_6); + + /* DSP Clock = MCLK1 (bypassed PLL2) */ + regmap_write(rt5677->regmap, RT5677_GLB_CLK2, + RT5677_DSP_CLK_SRC_BYPASS); + + /* SAD Threshold1 */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL2, 0x013f); + /* SAD Threshold2 */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL3, 0x0ae5); + /* SAD Sample Rate Converter = Up 6 (8K to 48K) + * SAD Output Sample Rate = Same as I2S + * SAD Threshold3 + */ + regmap_update_bits(rt5677->regmap, RT5677_VAD_CTRL4, + RT5677_VAD_OUT_SRC_RATE_MASK | RT5677_VAD_OUT_SRC_MASK | + RT5677_VAD_LV_DIFF_MASK, 0x7f << RT5677_VAD_LV_DIFF_SFT); + /* Minimum frame level within a pre-determined duration = 32 frames + * Bypass ADPCM Encoder/Decoder = Bypass ADPCM + * Automatic Push Data to SAD Buffer Once SAD Flag is triggered = enable + * SAD Buffer Over-Writing = enable + * SAD Buffer Pop Mode Control = disable + * SAD Buffer Push Mode Control = enable + * SAD Detector Control = enable + * SAD Function Control = enable + * SAD Function Reset = normal + */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, + RT5677_VAD_FUNC_RESET | RT5677_VAD_FUNC_ENABLE | + RT5677_VAD_DET_ENABLE | RT5677_VAD_BUF_PUSH | + RT5677_VAD_BUF_OW | RT5677_VAD_FG2ENC | + RT5677_VAD_ADPCM_BYPASS | 1 << RT5677_VAD_MIN_DUR_SFT); + + /* IRQ Source of VAD Jack Detection = enable */ + regmap_write(rt5677->regmap, RT5677_IRQ_CTRL2, 0x4000); + + /* Private register, no doc */ + regmap_update_bits(rt5677->regmap, RT5677_PR_BASE + RT5677_BIAS_CUR4, + 0x0f00, 0x0100); + + /* LDO2 output = 1.2V + * LDO1 output = 1.2V (LDO_IN = 1.8V) + */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, + RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, + 5 << RT5677_LDO1_SEL_SFT | 5 << RT5677_LDO2_SEL_SFT); + + /* Codec core power = power on + * LDO1 power = power on + */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, + RT5677_PWR_CORE | RT5677_PWR_LDO1, + RT5677_PWR_CORE | RT5677_PWR_LDO1); + + /* Isolation for DCVDD4 = normal (set during probe) + * Isolation for DCVDD2 = normal (set during probe) + * Isolation for DSP = normal + * Isolation for Band 0~7 = disable + * Isolation for InBound 4~10 and OutBound 4~10 = disable + */ + regmap_write(rt5677->regmap, RT5677_PWR_DSP2, + RT5677_PWR_CORE_ISO | RT5677_PWR_DSP_ISO | + RT5677_PWR_SR7_ISO | RT5677_PWR_SR6_ISO | + RT5677_PWR_SR5_ISO | RT5677_PWR_SR4_ISO | + RT5677_PWR_SR3_ISO | RT5677_PWR_SR2_ISO | + RT5677_PWR_SR1_ISO | RT5677_PWR_SR0_ISO | + RT5677_PWR_MLT_ISO); + + /* System Band 0~7 = power on + * InBound 4~10 and OutBound 4~10 = power on + * DSP = power on + * DSP CPU = stop (will be set to "run" after firmware loaded) + */ + regmap_write(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_SR7 | RT5677_PWR_SR6 | + RT5677_PWR_SR5 | RT5677_PWR_SR4 | + RT5677_PWR_SR3 | RT5677_PWR_SR2 | + RT5677_PWR_SR1 | RT5677_PWR_SR0 | + RT5677_PWR_MLT | RT5677_PWR_DSP | + RT5677_PWR_DSP_CPU); + + return 0; +} + +static int rt5677_parse_and_load_dsp(struct rt5677_priv *rt5677, const u8 *buf, + unsigned int len) +{ + struct snd_soc_component *component = rt5677->component; + Elf32_Ehdr *elf_hdr; + Elf32_Phdr *pr_hdr; + Elf32_Half i; + int ret = 0; + + if (!buf || (len < sizeof(Elf32_Ehdr))) + return -ENOMEM; + + elf_hdr = (Elf32_Ehdr *)buf; +#ifndef EM_XTENSA +#define EM_XTENSA 94 +#endif + if (strncmp(elf_hdr->e_ident, ELFMAG, sizeof(ELFMAG) - 1)) + dev_err(component->dev, "Wrong ELF header prefix\n"); + if (elf_hdr->e_ehsize != sizeof(Elf32_Ehdr)) + dev_err(component->dev, "Wrong Elf header size\n"); + if (elf_hdr->e_machine != EM_XTENSA) + dev_err(component->dev, "Wrong DSP code file\n"); + + if (len < elf_hdr->e_phoff) + return -ENOMEM; + pr_hdr = (Elf32_Phdr *)(buf + elf_hdr->e_phoff); + for (i = 0; i < elf_hdr->e_phnum; i++) { + /* TODO: handle p_memsz != p_filesz */ + if (pr_hdr->p_paddr && pr_hdr->p_filesz) { + dev_info(component->dev, "Load 0x%x bytes to 0x%x\n", + pr_hdr->p_filesz, pr_hdr->p_paddr); + + ret = rt5677_spi_write(pr_hdr->p_paddr, + buf + pr_hdr->p_offset, + pr_hdr->p_filesz); + if (ret) + dev_err(component->dev, "Load firmware failed %d\n", + ret); + } + pr_hdr++; + } + return ret; +} + +static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677) +{ + const struct firmware *fwp; + struct device *dev = rt5677->component->dev; + int ret = 0; + + /* Load dsp firmware from rt5677_elf_vad file */ + ret = request_firmware(&fwp, "rt5677_elf_vad", dev); + if (ret) { + dev_err(dev, "Request rt5677_elf_vad failed %d\n", ret); + return ret; + } + dev_info(dev, "Requested rt5677_elf_vad (%zu)\n", fwp->size); + + ret = rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size); + release_firmware(fwp); + return ret; +} + static int rt5677_set_dsp_vad(struct snd_soc_component *component, bool on) { struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); - static bool activity; - int ret; + rt5677->dsp_vad_en = on; if (!IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI)) return -ENXIO; - if (on && !activity) { - activity = true; + schedule_delayed_work(&rt5677->dsp_work, 0); + return 0; +} - regcache_cache_only(rt5677->regmap, false); - regcache_cache_bypass(rt5677->regmap, true); +static void rt5677_dsp_work(struct work_struct *work) +{ + struct rt5677_priv *rt5677 = + container_of(work, struct rt5677_priv, dsp_work.work); + static bool activity; + bool enable = rt5677->dsp_vad_en; - regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1); - regmap_update_bits(rt5677->regmap, - RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00); - regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, - RT5677_LDO1_SEL_MASK, 0x0); - regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, - RT5677_PWR_LDO1, RT5677_PWR_LDO1); - switch (rt5677->type) { - case RT5677: - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, - RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC); - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, - RT5677_PLL2_PR_SRC_MASK | - RT5677_DSP_CLK_SRC_MASK, - RT5677_PLL2_PR_SRC_MCLK2 | - RT5677_DSP_CLK_SRC_BYPASS); - break; - case RT5676: - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, - RT5677_DSP_CLK_SRC_MASK, - RT5677_DSP_CLK_SRC_BYPASS); - break; - default: - break; - } - regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff); - regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd); - rt5677_set_dsp_mode(component, true); - - ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, - component->dev); - if (ret == 0) { - rt5677_spi_write_firmware(0x50000000, rt5677->fw1); - release_firmware(rt5677->fw1); - } - ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, - component->dev); - if (ret == 0) { - rt5677_spi_write_firmware(0x60000000, rt5677->fw2); - release_firmware(rt5677->fw2); - } + dev_info(rt5677->component->dev, "DSP VAD: enable=%d, activity=%d\n", + enable, activity); - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x0); + if (enable && !activity) { + activity = true; - regcache_cache_bypass(rt5677->regmap, false); - regcache_cache_only(rt5677->regmap, true); - } else if (!on && activity) { + /* Set GPIO1 as an output pin driving a 0. Firmware will + * raise GPIO1 upon hotword detect. + */ + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + RT5677_GPIO1_DIR_MASK | RT5677_GPIO1_OUT_MASK | + RT5677_GPIO1_P_MASK, RT5677_GPIO1_DIR_OUT | + RT5677_GPIO1_OUT_LO | RT5677_GPIO1_P_NOR); + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, + RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_GPIO1); + + rt5677_set_vad_source(rt5677); + rt5677_set_dsp_mode(rt5677, true); + + /* Boot the firmware from IRAM instead of SRAM0. */ + rt5677_dsp_mode_i2c_write_addr(rt5677, RT5677_DSP_BOOT_VECTOR, + 0x0009, 0x0003); + rt5677_dsp_mode_i2c_write_addr(rt5677, RT5677_DSP_BOOT_VECTOR, + 0x0019, 0x0003); + rt5677_dsp_mode_i2c_write_addr(rt5677, RT5677_DSP_BOOT_VECTOR, + 0x0009, 0x0003); + + rt5677_load_dsp_from_file(rt5677); + + /* Set DSP CPU to Run */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP_CPU, 0x0); + } else if (!enable && activity) { activity = false; - regcache_cache_only(rt5677->regmap, false); - regcache_cache_bypass(rt5677->regmap, true); + /* Set DSP CPU to Stop */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU); - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1); - rt5677_set_dsp_mode(component, false); - regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001); + rt5677_set_dsp_mode(rt5677, false); - regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); + /* Disable and clear VAD interrupt */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184); + regmap_update_bits(rt5677->regmap, RT5677_IRQ_CTRL2, + 0xF000, 0x0000); - regcache_cache_bypass(rt5677->regmap, false); - regcache_mark_dirty(rt5677->regmap); - regcache_sync(rt5677->regmap); - } + /* Set GPIO1 pin back to be IRQ output for jack detect */ + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, + RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); - return 0; + } } static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); @@ -819,7 +969,8 @@ static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol, rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0]; if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) - rt5677_set_dsp_vad(component, rt5677->dsp_vad_en); + rt5677_set_dsp_vad(component, + !!ucontrol->value.integer.value[0]); return 0; } @@ -4740,6 +4891,8 @@ static void rt5677_remove(struct snd_soc_component *component) { struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); + cancel_delayed_work_sync(&rt5677->dsp_work); + regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); gpiod_set_value_cansleep(rt5677->reset_pin, 1); @@ -4938,6 +5091,17 @@ static struct snd_soc_dai_driver rt5677_dai[] = { }, .ops = &rt5677_aif_dai_ops, }, + { + .name = "rt5677-dspbuffer", + .id = RT5677_DSPBUFF, + .capture = { + .stream_name = "DSP Buffer", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, }; static const struct snd_soc_component_driver soc_component_dev_rt5677 = { @@ -5081,6 +5245,9 @@ static irqreturn_t rt5677_irq(int unused, void *data) mutex_lock(&rt5677->irq_lock); + if (rt5677->dsp_vad_en) + rt5677_spi_hotword_detected(); + /* * Loop to handle interrupts until the last i2c read shows no pending * irqs. The interrupt line is shared by multiple interrupt sources. @@ -5271,6 +5438,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) return -ENOMEM; rt5677->dev = &i2c->dev; + rt5677->set_dsp_vad = rt5677_set_dsp_vad; + INIT_DELAYED_WORK(&rt5677->dsp_work, rt5677_dsp_work); i2c_set_clientdata(i2c, rt5677); if (i2c->dev.of_node) { diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 213f4b8ca269..d18b41da1176 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1730,6 +1730,7 @@ enum { RT5677_AIF4, RT5677_AIF5, RT5677_AIFS, + RT5677_DSPBUFF, }; enum { @@ -1845,14 +1846,17 @@ struct rt5677_priv { #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; #endif - bool dsp_vad_en; + bool dsp_vad_en; /* DSP VAD enable/disable request */ bool is_dsp_mode; bool is_vref_slow; + struct delayed_work dsp_work; /* Interrupt handling */ struct irq_domain *domain; struct mutex irq_lock; unsigned int irq_en; + + int (*set_dsp_vad)(struct snd_soc_component *component, bool on); }; int rt5677_sel_asrc_clk_src(struct snd_soc_component *component, -- cgit From 157b006f6be46be833b2941856b86e0a9d8bfb0e Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Tue, 5 Nov 2019 17:13:27 -0800 Subject: ASoC: bdw-rt5677: Add a DAI link for rt5677 SPI PCM device This link is needed for the RT5677 DSP to do hotwording Signed-off-by: Ben Zhang Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-3-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5677.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 4a4d3353e26d..eeb9a11e4e14 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -74,6 +74,7 @@ static const struct snd_soc_dapm_route bdw_rt5677_map[] = { /* CODEC BE connections */ {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, + {"DSP Capture", NULL, "DSP Buffer"}, }; static const struct snd_kcontrol_new bdw_rt5677_controls[] = { @@ -258,6 +259,12 @@ SND_SOC_DAILINK_DEF(platform, SND_SOC_DAILINK_DEF(be, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RT5677CE:00", "rt5677-aif1"))); +/* Wake on voice interface */ +SND_SOC_DAILINK_DEFS(dsp, + DAILINK_COMP_ARRAY(COMP_CPU("spi-RT5677AA:00")), + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RT5677CE:00", "rt5677-dspbuffer")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("spi-RT5677AA:00"))); + static struct snd_soc_dai_link bdw_rt5677_dais[] = { /* Front End DAI links */ { @@ -276,6 +283,13 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { SND_SOC_DAILINK_REG(fe, dummy, platform), }, + /* Non-DPCM links */ + { + .name = "Codec DSP", + .stream_name = "Wake on Voice", + SND_SOC_DAILINK_REG(dsp), + }, + /* Back End DAI links */ { /* SSP0 - Codec */ -- cgit From 21c00e5df4397870ee835c974bf50570f9d24253 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Tue, 5 Nov 2019 17:13:28 -0800 Subject: ASoC: rt5677: Enable jack detect while DSP is running Before a hotword is detected, GPIO1 pin is configured as IRQ output so that jack detect works. When a hotword is detected, the DSP firmware configures the GPIO1 pin as GPIO1 and drives a 1. rt5677_irq() is called after a rising edge on the GPIO1 pin, due to either jack detect event or hotword event, or both. All possible events are checked and handled in rt5677_irq() where GPIO1 pin is configured back to IRQ output if a hotword is detected. Signed-off-by: Ben Zhang Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-4-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 64 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 13f21bf4e04e..48955b22262f 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -312,6 +312,8 @@ static bool rt5677_volatile_register(struct device *dev, unsigned int reg) case RT5677_IRQ_CTRL1: case RT5677_IRQ_CTRL2: case RT5677_GPIO_ST: + case RT5677_GPIO_CTRL1: /* Modified by DSP firmware */ + case RT5677_GPIO_CTRL2: /* Modified by DSP firmware */ case RT5677_DSP_INB1_SRC_CTRL4: case RT5677_DSP_INB2_SRC_CTRL4: case RT5677_DSP_INB3_SRC_CTRL4: @@ -746,8 +748,11 @@ static unsigned int rt5677_set_vad_source(struct rt5677_priv *rt5677) RT5677_VAD_BUF_OW | RT5677_VAD_FG2ENC | RT5677_VAD_ADPCM_BYPASS | 1 << RT5677_VAD_MIN_DUR_SFT); - /* IRQ Source of VAD Jack Detection = enable */ - regmap_write(rt5677->regmap, RT5677_IRQ_CTRL2, 0x4000); + /* VAD/SAD is not routed to the IRQ output (i.e. MX-BE[14] = 0), but it + * is routed to DSP_IRQ_0, so DSP firmware may use it to sleep and save + * power. See ALC5677 datasheet section 9.17 "GPIO, Interrupt and Jack + * Detection" for more info. + */ /* Private register, no doc */ regmap_update_bits(rt5677->regmap, RT5677_PR_BASE + RT5677_BIAS_CUR4, @@ -886,15 +891,15 @@ static void rt5677_dsp_work(struct work_struct *work) if (enable && !activity) { activity = true; - /* Set GPIO1 as an output pin driving a 0. Firmware will - * raise GPIO1 upon hotword detect. + /* Before a hotword is detected, GPIO1 pin is configured as IRQ + * output so that jack detect works. When a hotword is detected, + * the DSP firmware configures the GPIO1 pin as GPIO1 and + * drives a 1. rt5677_irq() is called after a rising edge on + * the GPIO1 pin, due to either jack detect event or hotword + * event, or both. All possible events are checked and handled + * in rt5677_irq() where GPIO1 pin is configured back to IRQ + * output if a hotword is detected. */ - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, - RT5677_GPIO1_DIR_MASK | RT5677_GPIO1_OUT_MASK | - RT5677_GPIO1_P_MASK, RT5677_GPIO1_DIR_OUT | - RT5677_GPIO1_OUT_LO | RT5677_GPIO1_P_NOR); - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, - RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_GPIO1); rt5677_set_vad_source(rt5677); rt5677_set_dsp_mode(rt5677, true); @@ -915,6 +920,8 @@ static void rt5677_dsp_work(struct work_struct *work) } else if (!enable && activity) { activity = false; + /* Don't turn off the DSP while handling irqs */ + mutex_lock(&rt5677->irq_lock); /* Set DSP CPU to Stop */ regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU); @@ -923,13 +930,12 @@ static void rt5677_dsp_work(struct work_struct *work) /* Disable and clear VAD interrupt */ regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184); - regmap_update_bits(rt5677->regmap, RT5677_IRQ_CTRL2, - 0xF000, 0x0000); /* Set GPIO1 pin back to be IRQ output for jack detect */ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); + mutex_unlock(&rt5677->irq_lock); } } @@ -5237,6 +5243,28 @@ static const struct rt5677_irq_desc rt5677_irq_descs[] = { }, }; +bool rt5677_check_hotword(struct rt5677_priv *rt5677) +{ + int reg_gpio; + + if (!rt5677->is_dsp_mode) + return false; + + if (regmap_read(rt5677->regmap, RT5677_GPIO_CTRL1, ®_gpio)) + return false; + + /* Firmware sets GPIO1 pin to be GPIO1 after hotword is detected */ + if ((reg_gpio & RT5677_GPIO1_PIN_MASK) == RT5677_GPIO1_PIN_IRQ) + return false; + + /* Set GPIO1 pin back to be IRQ output for jack detect */ + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, + RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); + + rt5677_spi_hotword_detected(); + return true; +} + static irqreturn_t rt5677_irq(int unused, void *data) { struct rt5677_priv *rt5677 = data; @@ -5245,9 +5273,6 @@ static irqreturn_t rt5677_irq(int unused, void *data) mutex_lock(&rt5677->irq_lock); - if (rt5677->dsp_vad_en) - rt5677_spi_hotword_detected(); - /* * Loop to handle interrupts until the last i2c read shows no pending * irqs. The interrupt line is shared by multiple interrupt sources. @@ -5285,7 +5310,13 @@ static irqreturn_t rt5677_irq(int unused, void *data) reg_irq ^= rt5677_irq_descs[i].polarity_mask; } } - if (!irq_fired) + + /* Exit the loop only when we know for sure that GPIO1 pin + * was low at some point since irq_lock was acquired. Any event + * after that point creates a rising edge that triggers another + * call to rt5677_irq(). + */ + if (!irq_fired && !rt5677_check_hotword(rt5677)) goto exit; ret = regmap_write(rt5677->regmap, RT5677_IRQ_CTRL1, reg_irq); @@ -5296,6 +5327,7 @@ static irqreturn_t rt5677_irq(int unused, void *data) } } exit: + WARN_ON_ONCE(loop == 20); mutex_unlock(&rt5677->irq_lock); if (irq_fired) return IRQ_HANDLED; -- cgit From 29073ae40c472f17d42aa38850da861b5e3f912e Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Tue, 5 Nov 2019 17:13:29 -0800 Subject: ASoC: rt5677: Add DAPM audio path for hotword stream Add a DAPM audio path from "DMIC L1" to "DSP Buffer" so that when hotwording is enabled, DAPM does not power off the codec with SND_SOC_BIAS_OFF. Signed-off-by: Ben Zhang Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-5-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 48955b22262f..ea235f3874ca 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -707,6 +707,13 @@ static void rt5677_set_dsp_mode(struct rt5677_priv *rt5677, bool on) static unsigned int rt5677_set_vad_source(struct rt5677_priv *rt5677) { + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(rt5677->component); + /* Force dapm to sync before we enable the + * DSP to prevent write corruption + */ + snd_soc_dapm_sync(dapm); + /* DMIC1 power = enabled * DMIC CLK = 256 * fs / 12 */ @@ -3167,6 +3174,7 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("AIF4TX", "AIF4 Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("SLBRX", "SLIMBus Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("SLBTX", "SLIMBus Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DSPTX", "DSP Buffer", 0, SND_SOC_NOPM, 0, 0), /* Sidetone Mux */ SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0, @@ -3701,11 +3709,24 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "SLBTX", NULL, "SLB ADC3 Mux" }, { "SLBTX", NULL, "SLB ADC4 Mux" }, + { "DSPTX", NULL, "IB01 Bypass Mux" }, + { "IB01 Mux", "IF1 DAC 01", "IF1 DAC01" }, { "IB01 Mux", "IF2 DAC 01", "IF2 DAC01" }, { "IB01 Mux", "SLB DAC 01", "SLB DAC01" }, { "IB01 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, - { "IB01 Mux", "VAD ADC/DAC1 FS", "DAC1 FS" }, + /* The IB01 Mux controls the source for InBound0 and InBound1. + * When the mux option "VAD ADC/DAC1 FS" is selected, "VAD ADC" goes to + * InBound0 and "DAC1 FS" goes to InBound1. "VAD ADC" is used for + * hotwording. "DAC1 FS" is not used currently. + * + * Creating a common widget node for "VAD ADC" + "DAC1 FS" and + * connecting the common widget to IB01 Mux causes the issue where + * there is an active path going from system playback -> "DAC1 FS" -> + * IB01 Mux -> DSP Buffer -> hotword stream. This wrong path confuses + * DAPM. Therefore "DAC1 FS" is ignored for now. + */ + { "IB01 Mux", "VAD ADC/DAC1 FS", "VAD ADC Mux" }, { "IB01 Bypass Mux", "Bypass", "IB01 Mux" }, { "IB01 Bypass Mux", "Pass SRC", "IB01 Mux" }, -- cgit From eabf424f7b60246c76dcb0ea6f1e83ef9abbeaa6 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Tue, 5 Nov 2019 17:13:30 -0800 Subject: ASoC: rt5677: Mark reg RT5677_PWR_ANLG2 as volatile The codec dies when RT5677_PWR_ANLG2(MX-64h) is set to 0xACE1 while it's streaming audio over SPI. The DSP firmware turns on PLL2 (MX-64 bit 8) when SPI streaming starts. However regmap does not believe that register can change by itself. When BST1 (bit 15) is turned on with regmap_update_bits(), it doesn't read the register first before write, so PLL2 power bit is cleared by accident. Marking MX-64h as volatile in regmap solved the issue. Signed-off-by: Ben Zhang Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-6-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index ea235f3874ca..e5db9dc60378 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -302,6 +302,7 @@ static bool rt5677_volatile_register(struct device *dev, unsigned int reg) case RT5677_I2C_MASTER_CTRL7: case RT5677_I2C_MASTER_CTRL8: case RT5677_HAP_GENE_CTRL2: + case RT5677_PWR_ANLG2: /* Modified by DSP firmware */ case RT5677_PWR_DSP_ST: case RT5677_PRIV_DATA: case RT5677_ASRC_22: -- cgit From 3f81068dc8e5fc0d3b0d67a5ae99c5140a4e96cb Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Tue, 5 Nov 2019 17:13:31 -0800 Subject: ASoC: rt5677: Stop and restart DSP over suspend/resume MCLK1 gets disabled at suspend and re-enabled at resume. Before MCLK1 is re-enabled, if the DSP is already on (either the DSP was left on during suspend, or the DSP is turned on early at resume), i2c register read returns garbage and corrupts the regmap cache. This patch stops the DSP before suspend and restarts it after resume with a dalay to ensure MCLK is on while loading firmware. Signed-off-by: Ben Zhang Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-7-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 24 +++++++++++++++++++++--- sound/soc/codecs/rt5677.h | 3 ++- 2 files changed, 23 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index e5db9dc60378..eb55d6b9d0c1 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -876,6 +876,7 @@ static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677) static int rt5677_set_dsp_vad(struct snd_soc_component *component, bool on) { struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); + rt5677->dsp_vad_en_request = on; rt5677->dsp_vad_en = on; if (!IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI)) @@ -969,7 +970,7 @@ static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); - ucontrol->value.integer.value[0] = rt5677->dsp_vad_en; + ucontrol->value.integer.value[0] = rt5677->dsp_vad_en_request; return 0; } @@ -4636,14 +4637,15 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); + enum snd_soc_bias_level prev_bias = + snd_soc_component_get_bias_level(component); switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: - if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) { - rt5677_set_dsp_vad(component, false); + if (prev_bias == SND_SOC_BIAS_STANDBY) { regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, @@ -4667,9 +4669,25 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_STANDBY: + if (prev_bias == SND_SOC_BIAS_OFF && + rt5677->dsp_vad_en_request) { + /* Re-enable the DSP if it was turned off at suspend */ + rt5677->dsp_vad_en = true; + /* The delay is to wait for MCLK */ + schedule_delayed_work(&rt5677->dsp_work, + msecs_to_jiffies(1000)); + } break; case SND_SOC_BIAS_OFF: + flush_delayed_work(&rt5677->dsp_work); + if (rt5677->is_dsp_mode) { + /* Turn off the DSP before suspend */ + rt5677->dsp_vad_en = false; + schedule_delayed_work(&rt5677->dsp_work, 0); + flush_delayed_work(&rt5677->dsp_work); + } + regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x0); regmap_write(rt5677->regmap, RT5677_PWR_DIG1, 0x0000); regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index d18b41da1176..046ed2ee8e31 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1846,7 +1846,8 @@ struct rt5677_priv { #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; #endif - bool dsp_vad_en; /* DSP VAD enable/disable request */ + bool dsp_vad_en_request; /* DSP VAD enable/disable request */ + bool dsp_vad_en; /* dsp_work parameter */ bool is_dsp_mode; bool is_vref_slow; struct delayed_work dsp_work; -- cgit From ee0be4a99d4923a9b9c681b008df561648731793 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Tue, 5 Nov 2019 17:13:32 -0800 Subject: ASoC: rt5677: Disable irq at suspend The irq is disabled at suspend to avoid running the threaded irq handler after the codec has been powered off. At resume, codec irq is re-enabled and the interrupt status register is checked to see if headphone has been pluggnd/unplugged while the device is suspended. There is still a chance that the headphone gets enabled or disabled after the codec is suspended. disable_irq syncs the threaded irq handler, but soc-jack's threaded irq handler schedules a delayed work to poll gpios (for debounce). This is still OK. The codec won't be powered back on again because all audio paths have been suspended, and there are no force enabled supply widgets (MICBIAS1 is disabled). The gpio status read after codec power off could be wrong, so the gpio values are checked again after resume. Signed-off-by: Ben Zhang Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-8-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5677.h | 2 ++ 2 files changed, 48 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index eb55d6b9d0c1..14f04db8e5e7 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4949,6 +4949,11 @@ static int rt5677_suspend(struct snd_soc_component *component) { struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); + if (rt5677->irq) { + cancel_delayed_work_sync(&rt5677->resume_irq_check); + disable_irq(rt5677->irq); + } + if (!rt5677->dsp_vad_en) { regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); @@ -4977,6 +4982,11 @@ static int rt5677_resume(struct snd_soc_component *component) regcache_sync(rt5677->regmap); } + if (rt5677->irq) { + enable_irq(rt5677->irq); + schedule_delayed_work(&rt5677->resume_irq_check, 0); + } + return 0; } #else @@ -5375,6 +5385,39 @@ exit: return IRQ_NONE; } +static void rt5677_resume_irq_check(struct work_struct *work) +{ + int i, virq; + struct rt5677_priv *rt5677 = + container_of(work, struct rt5677_priv, resume_irq_check.work); + + /* This is needed to check and clear the interrupt status register + * at resume. If the headset is plugged/unplugged when the device is + * fully suspended, there won't be a rising edge at resume to trigger + * the interrupt. Without this, we miss the next unplug/plug event. + */ + rt5677_irq(0, rt5677); + + /* Call all enabled jack detect irq handlers again. This is needed in + * addition to the above check for a corner case caused by jack gpio + * debounce. After codec irq is disabled at suspend, the delayed work + * scheduled by soc-jack may run and read wrong jack gpio values, since + * the regmap is in cache only mode. At resume, there is no irq because + * rt5677_irq has already ran and cleared the irq status at suspend. + * Without this explicit check, unplug the headset right after suspend + * starts, then after resume the headset is still shown as plugged in. + */ + mutex_lock(&rt5677->irq_lock); + for (i = 0; i < RT5677_IRQ_NUM; i++) { + if (rt5677->irq_en & rt5677_irq_descs[i].enable_mask) { + virq = irq_find_mapping(rt5677->domain, i); + if (virq) + handle_nested_irq(virq); + } + } + mutex_unlock(&rt5677->irq_lock); +} + static void rt5677_irq_bus_lock(struct irq_data *data) { struct rt5677_priv *rt5677 = irq_data_get_irq_chip_data(data); @@ -5450,6 +5493,7 @@ static int rt5677_init_irq(struct i2c_client *i2c) } mutex_init(&rt5677->irq_lock); + INIT_DELAYED_WORK(&rt5677->resume_irq_check, rt5677_resume_irq_check); /* * Select RC as the debounce clock so that GPIO works even when @@ -5495,6 +5539,8 @@ static int rt5677_init_irq(struct i2c_client *i2c) if (ret) dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret); + rt5677->irq = i2c->irq; + return ret; } diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 046ed2ee8e31..f8ada967fdbc 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1856,6 +1856,8 @@ struct rt5677_priv { struct irq_domain *domain; struct mutex irq_lock; unsigned int irq_en; + struct delayed_work resume_irq_check; + int irq; int (*set_dsp_vad)(struct snd_soc_component *component, bool on); }; -- cgit From 395f02ef210e6f7dad2ca0efc16ffaea4a9ed030 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Tue, 5 Nov 2019 17:13:33 -0800 Subject: ASoC: rt5677: Allow VAD to be shut on/off at all times Due to limitations of the clocking configuration, we have no way of scheduling our hibernation before the bdw dsp hibernates. This causes issues when the system suspends with an open stream. We need userspace to toggle the kcontrol before we are suspended so that any writes on suspend are not lost and we don't corrupt the regmap. Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-9-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 14f04db8e5e7..a65d1554366d 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -979,13 +979,8 @@ static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); - - rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0]; - if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) - rt5677_set_dsp_vad(component, - !!ucontrol->value.integer.value[0]); + rt5677_set_dsp_vad(component, !!ucontrol->value.integer.value[0]); return 0; } -- cgit From 55229597a94531726878229ccfcd3fe4ec572dc3 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Tue, 5 Nov 2019 17:13:34 -0800 Subject: ASoC: bdw-rt5677: Turn on MCLK1 for DSP via DAPM The RT5677 DSP needs the I2S MCLK1 to run its DSP. Add a dapm route to SSP0 CODEC IN so the clock is turned on automatically when the DSP is turned on. Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-10-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5677.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index eeb9a11e4e14..b2475e3eff7b 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -75,6 +75,10 @@ static const struct snd_soc_dapm_route bdw_rt5677_map[] = { {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, {"DSP Capture", NULL, "DSP Buffer"}, + + /* DSP Clock Connections */ + { "DSP Buffer", NULL, "SSP0 CODEC IN" }, + { "SSP0 CODEC IN", NULL, "DSPTX" }, }; static const struct snd_kcontrol_new bdw_rt5677_controls[] = { -- cgit From ba0b3a977ecf525231d36f2d9f3a6ea05c35090a Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Tue, 5 Nov 2019 17:13:35 -0800 Subject: ASoC: rt5677: Set ADC clock to use PLL and enable ASRC Use the PLL to kept the correct 24M clock rate so frequency shift does not occur when using the DSP VAD. Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-11-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 6 ++++++ sound/soc/codecs/rt5677.h | 2 ++ sound/soc/intel/boards/bdw-rt5677.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index a65d1554366d..0e7773584145 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5046,6 +5046,11 @@ static const struct snd_soc_dai_ops rt5677_aif_dai_ops = { .set_tdm_slot = rt5677_set_tdm_slot, }; +static const struct snd_soc_dai_ops rt5677_dsp_dai_ops = { + .set_sysclk = rt5677_set_dai_sysclk, + .set_pll = rt5677_set_dai_pll, +}; + static struct snd_soc_dai_driver rt5677_dai[] = { { .name = "rt5677-aif1", @@ -5152,6 +5157,7 @@ static struct snd_soc_dai_driver rt5677_dai[] = { .rates = SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, + .ops = &rt5677_dsp_dai_ops, }, }; diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index f8ada967fdbc..944ae02aafc2 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1336,6 +1336,8 @@ #define RT5677_PLL_M_SFT 12 #define RT5677_PLL_M_BP (0x1 << 11) #define RT5677_PLL_M_BP_SFT 11 +#define RT5677_PLL_UPDATE_PLL1 (0x1 << 1) +#define RT5677_PLL_UPDATE_PLL1_SFT 1 /* Global Clock Control 1 (0x80) */ #define RT5677_SCLK_SRC_MASK (0x3 << 14) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index b2475e3eff7b..2af8e5a62da8 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -170,10 +170,37 @@ static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream, return ret; } +static int bdw_rt5677_dsp_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_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_PLL1, 24576000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec sysclk configuration\n"); + return ret; + } + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5677_PLL1_S_MCLK, + 24000000, 24576000); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec pll configuration\n"); + return ret; + } + + return 0; +} + static const struct snd_soc_ops bdw_rt5677_ops = { .hw_params = bdw_rt5677_hw_params, }; +static const struct snd_soc_ops bdw_rt5677_dsp_ops = { + .hw_params = bdw_rt5677_dsp_hw_params, +}; + #if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) { @@ -213,6 +240,11 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) rt5677_sel_asrc_clk_src(component, RT5677_DA_STEREO_FILTER | RT5677_AD_STEREO1_FILTER | RT5677_I2S1_SOURCE, RT5677_CLK_SEL_I2S1_ASRC); + /* Enable codec ASRC function for Mono ADC L. + * The ASRC clock source is clk_sys2_asrc. + */ + rt5677_sel_asrc_clk_src(component, RT5677_AD_MONO_L_FILTER, + RT5677_CLK_SEL_SYS2); /* Request rt5677 GPIO for headphone amp control */ bdw_rt5677->gpio_hp_en = devm_gpiod_get(component->dev, "headphone-enable", @@ -291,6 +323,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { { .name = "Codec DSP", .stream_name = "Wake on Voice", + .ops = &bdw_rt5677_dsp_ops, SND_SOC_DAILINK_REG(dsp), }, -- cgit From 9da776ba7852f9b5cbfdfaa80a1dc07cda592b55 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Tue, 5 Nov 2019 17:13:36 -0800 Subject: ASoC: rt5677: Wait for DSP to boot before loading firmware Wait for hardware to startup. If we load before hardware is ready we could end up corrupting the firmware. Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20191106011335.223061-12-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 0e7773584145..f2f763b4c399 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -892,6 +892,7 @@ static void rt5677_dsp_work(struct work_struct *work) container_of(work, struct rt5677_priv, dsp_work.work); static bool activity; bool enable = rt5677->dsp_vad_en; + int i, val; dev_info(rt5677->component->dev, "DSP VAD: enable=%d, activity=%d\n", @@ -913,6 +914,18 @@ static void rt5677_dsp_work(struct work_struct *work) rt5677_set_vad_source(rt5677); rt5677_set_dsp_mode(rt5677, true); +#define RT5677_BOOT_RETRY 20 + for (i = 0; i < RT5677_BOOT_RETRY; i++) { + regmap_read(rt5677->regmap, RT5677_PWR_DSP_ST, &val); + if (val == 0x3ff) + break; + udelay(500); + } + if (i == RT5677_BOOT_RETRY && val != 0x3ff) { + dev_err(rt5677->component->dev, "DSP Boot Timed Out!"); + return; + } + /* Boot the firmware from IRAM instead of SRAM0. */ rt5677_dsp_mode_i2c_write_addr(rt5677, RT5677_DSP_BOOT_VECTOR, 0x0009, 0x0003); -- cgit From 0c4f09ceec3d7afbef6ad4077d96e36e0fad4028 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Nov 2019 18:36:42 +0100 Subject: ALSA: timer: Fix the breakage of slave link open A silly mistake was made while applying the fix for potential races in commit 6a34367e52ca ("ALSA: timer: Fix possible race at assigning a timer instance"): when a slave PCM is opened and succeeds, it doesn't return but proceeds to the master timer open code instead. Plug the hole and beautify a bit. Fixes: 6a34367e52ca ("ALSA: timer: Fix possible race at assigning a timer instance") Reported-by: syzbot+4476917c053f60112c99@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20191111173642.6093-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/timer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 9091030f4a89..24fed5c78273 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -268,8 +268,7 @@ int snd_timer_open(struct snd_timer_instance *timeri, list_add_tail(&timeri->open_list, &snd_timer_slave_list); num_slaves++; err = snd_timer_check_slave(timeri); - if (err < 0) - goto close; + goto list_added; } /* open a master instance */ @@ -324,7 +323,7 @@ int snd_timer_open(struct snd_timer_instance *timeri, list_add_tail(&timeri->open_list, &timer->open_list_head); timer->num_instances++; err = snd_timer_check_master(timeri); - close: +list_added: if (err < 0) snd_timer_close_locked(timeri, &card_dev_to_put); -- cgit From 36da67630d3159e48e37a9f9b2d26ceece426482 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 8 Nov 2019 18:48:40 +0100 Subject: ASoC: Add DA7213 audio codec as selectable option This commit adds the Dialog DA7213 audio codec as a selectable option in the kernel config. Currently the driver can only be selected for Intel Baytrail/Cherrytrail devices or if SND_SOC_ALL_CODECS is enabled. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20191108174843.11227-3-sebastian.reichel@collabora.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1a4b084cc90d..ec01e4f12a78 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -679,7 +679,8 @@ config SND_SOC_DA7210 tristate config SND_SOC_DA7213 - tristate + tristate "Dialog DA7213 CODEC" + depends on I2C config SND_SOC_DA7218 tristate -- cgit From e2db787bdcb4f2722ecf410168f0583764634e45 Mon Sep 17 00:00:00 2001 From: Yu-Hsuan Hsu Date: Tue, 24 Sep 2019 00:29:40 +0800 Subject: ASoC: Intel: kbl_rt5663_rt5514_max98927: Add dmic format constraint On KBL platform, the microphone is attached to external codec(rt5514) instead of PCH. However, TDM slot between PCH and codec is 16 bits only. In order to avoid setting wrong format, we should add a constraint to force to use 16 bits format forever. Signed-off-by: Yu-Hsuan Hsu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190923162940.199580-1-yuhsuan@chromium.org Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index a1056cda3dd7..3e5f6bead229 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -465,6 +465,9 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, dmic_constraints); + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -- cgit From 13409d27cb39fb1dfcb28418a9bc3d26907e1dbc Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 8 Nov 2019 21:31:52 +0100 Subject: ASoC: wm8904: configure sysclk/FLL automatically This adds a new mode WM8904_CLK_AUTO which automatically enables the FLL if a frequency different than the MCLK is set. These additions make the codec work with the simple-card driver in general and especially in systems where the MCLK doesn't match the required clock. Signed-off-by: Michael Walle Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20191108203152.19098-1-michael@walle.cc Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 72 +++++++++++++++++++++++++++++------------------ sound/soc/codecs/wm8904.h | 1 + 2 files changed, 45 insertions(+), 28 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index bcb3c9d5abf0..2a7d23a5daa8 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1410,34 +1410,6 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream, return 0; } - -static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) -{ - struct snd_soc_component *component = dai->component; - struct wm8904_priv *priv = snd_soc_component_get_drvdata(component); - - switch (clk_id) { - case WM8904_CLK_MCLK: - priv->sysclk_src = clk_id; - priv->mclk_rate = freq; - break; - - case WM8904_CLK_FLL: - priv->sysclk_src = clk_id; - break; - - default: - return -EINVAL; - } - - dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq); - - wm8904_configure_clocking(component); - - return 0; -} - static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; @@ -1824,6 +1796,50 @@ out: return 0; } +static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct wm8904_priv *priv = snd_soc_component_get_drvdata(component); + unsigned long mclk_freq; + int ret; + + switch (clk_id) { + case WM8904_CLK_AUTO: + mclk_freq = clk_get_rate(priv->mclk); + /* enable FLL if a different sysclk is desired */ + if (mclk_freq != freq) { + priv->sysclk_src = WM8904_CLK_FLL; + ret = wm8904_set_fll(dai, WM8904_FLL_MCLK, + WM8904_FLL_MCLK, + mclk_freq, freq); + if (ret) + return ret; + break; + } + clk_id = WM8904_CLK_MCLK; + /* fallthrough */ + + case WM8904_CLK_MCLK: + priv->sysclk_src = clk_id; + priv->mclk_rate = freq; + break; + + case WM8904_CLK_FLL: + priv->sysclk_src = clk_id; + break; + + default: + return -EINVAL; + } + + dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq); + + wm8904_configure_clocking(component); + + return 0; +} + static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute) { struct snd_soc_component *component = codec_dai->component; diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h index c1bca52f9927..de6340446b1f 100644 --- a/sound/soc/codecs/wm8904.h +++ b/sound/soc/codecs/wm8904.h @@ -10,6 +10,7 @@ #ifndef _WM8904_H #define _WM8904_H +#define WM8904_CLK_AUTO 0 #define WM8904_CLK_MCLK 1 #define WM8904_CLK_FLL 2 -- cgit From e7cfd867fd9842f346688f28412eb83dec342900 Mon Sep 17 00:00:00 2001 From: Jacob Rasmussen Date: Mon, 11 Nov 2019 11:59:57 -0700 Subject: ASoC: rt5645: Fixed buddy jack support. The headphone jack on buddy was broken with the following commit: commit 6b5da66322c5 ("ASoC: rt5645: read jd1_1 status for jd detection"). This changes the jd_mode for buddy to 4 so buddy can read from the same register that was used in the working version of this driver without affecting any other devices that might use this, since no other device uses jd_mode = 4. To test this I plugged and uplugged the headphone jack, verifying audio works. Signed-off-by: Jacob Rasmussen Reviewed-by: Ross Zwisler Link: https://lore.kernel.org/r/20191111185957.217244-1-jacobraz@google.com Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/rt5645.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 1c06b3b9218c..902ac98a3fbe 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3270,6 +3270,9 @@ static void rt5645_jack_detect_work(struct work_struct *work) snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); return; + case 4: + val = snd_soc_component_read32(rt5645->component, RT5645_A_JD_CTRL1) & 0x002; + break; default: /* read rt5645 jd1_1 status */ val = snd_soc_component_read32(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000; break; @@ -3603,7 +3606,7 @@ static const struct rt5645_platform_data intel_braswell_platform_data = { static const struct rt5645_platform_data buddy_platform_data = { .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5, .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, - .jd_mode = 3, + .jd_mode = 4, .level_trigger_irq = true, }; @@ -3999,6 +4002,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, RT5645_JD1_MODE_1); break; case 3: + case 4: regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, RT5645_JD1_MODE_MASK, RT5645_JD1_MODE_2); -- cgit From 24de63562b9da9fb3145329abb226ab623e6af19 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 11 Nov 2019 16:21:52 -0600 Subject: ASoC: rt5682: cancel jack_detect_work if hs_jack is set to null jack_detect_work will be triggered by rt5682_irq. We should cancel it if hs_jack is set to null. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111222152.19723-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index c50b75ce82e0..62b8ed412bd1 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1002,6 +1002,7 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, RT5682_JD1_EN_MASK, RT5682_JD1_DIS); regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, RT5682_POW_JDH | RT5682_POW_JDL, 0); + cancel_delayed_work_sync(&rt5682->jack_detect_work); return 0; } -- cgit From 130d3e90777fe974e4b8fa100cec8faf19cac998 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 11 Nov 2019 16:29:00 -0600 Subject: ASoC: SOF: Intel: Fix CFL and CML FW nocodec binary names. The manifest information is different between CNL, CML and CFL platforms hence we need to load different files. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111222901.19892-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index d66412a77873..2ef927371b23 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -113,7 +113,7 @@ static const struct sof_dev_desc cnl_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) static const struct sof_dev_desc cfl_desc = { - .machines = snd_soc_acpi_intel_cnl_machines, + .machines = snd_soc_acpi_intel_cfl_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -122,7 +122,7 @@ static const struct sof_dev_desc cfl_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_fw_filename = "sof-cfl.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -133,7 +133,7 @@ static const struct sof_dev_desc cfl_desc = { IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) static const struct sof_dev_desc cml_desc = { - .machines = snd_soc_acpi_intel_cnl_machines, + .machines = snd_soc_acpi_intel_cml_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -142,7 +142,7 @@ static const struct sof_dev_desc cml_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_fw_filename = "sof-cml.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops -- cgit From 1f24d93c4f4ec0bb0b73c5b020060aa2d9faa756 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 11 Nov 2019 16:28:59 -0600 Subject: ASoC: Intel: acpi-match: split CNL tables in three Due to firmware manifest/signature differences, we have to use different firmware names, so split CNL machine table in three (CNL, CFL, CML). The CFL table is currently empty since all known platforms use HDaudio, but let's plan ahead. Reviewed-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111222901.19892-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/Makefile | 3 +- sound/soc/intel/common/soc-acpi-intel-cfl-match.c | 18 ++++++++ sound/soc/intel/common/soc-acpi-intel-cml-match.c | 56 +++++++++++++++++++++++ sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 38 --------------- 4 files changed, 76 insertions(+), 39 deletions(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-cfl-match.c create mode 100644 sound/soc/intel/common/soc-acpi-intel-cml-match.c (limited to 'sound') diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index eafe95ead49b..bd352878f89a 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -7,7 +7,8 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ - soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ + soc-acpi-intel-cnl-match.o soc-acpi-intel-cfl-match.o \ + soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-jsl-match.o \ soc-acpi-intel-hda-match.o diff --git a/sound/soc/intel/common/soc-acpi-intel-cfl-match.c b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c new file mode 100644 index 000000000000..d6fd2026d0b8 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-cfl-match.c - tables and support for CFL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cfl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c new file mode 100644 index 000000000000..5d08ae066738 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-acpi-intel-cml-match.c - tables and support for CML ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +static struct snd_soc_acpi_codecs cml_codecs = { + .num_codecs = 1, + .codecs = {"10EC5682"} +}; + +static struct snd_soc_acpi_codecs cml_spk_codecs = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { + { + .id = "DLGS7219", + .drv_name = "cml_da7219_max98357a", + .quirk_data = &cml_spk_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", + }, + { + .id = "MX98357A", + .drv_name = "sof_rt5682", + .quirk_data = &cml_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", + }, + { + .id = "10EC1011", + .drv_name = "cml_rt1011_rt5682", + .quirk_data = &cml_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", + }, + { + .id = "10EC5682", + .drv_name = "sof_rt5682", + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt5682.tplg", + }, + + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 16d0bae8b316..27588841c8b0 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -14,16 +14,6 @@ static struct skl_machine_pdata cnl_pdata = { .use_tplg_pcm = true, }; -static struct snd_soc_acpi_codecs cml_codecs = { - .num_codecs = 1, - .codecs = {"10EC5682"} -}; - -static struct snd_soc_acpi_codecs cml_spk_codecs = { - .num_codecs = 1, - .codecs = {"MX98357A"} -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { { .id = "INT34C2", @@ -33,34 +23,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt274.tplg", }, - { - .id = "DLGS7219", - .drv_name = "cml_da7219_max98357a", - .quirk_data = &cml_spk_codecs, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", - }, - { - .id = "MX98357A", - .drv_name = "sof_rt5682", - .quirk_data = &cml_codecs, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", - }, - { - .id = "10EC1011", - .drv_name = "cml_rt1011_rt5682", - .quirk_data = &cml_codecs, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", - }, - { - .id = "10EC5682", - .drv_name = "sof_rt5682", - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682.tplg", - }, - {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); -- cgit From 0af237d51a4e734db959a158185f79019f022f59 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 11 Nov 2019 16:29:01 -0600 Subject: ASoC: SOF: Intel: hda: use fallback for firmware name We have platforms such as CFL with no known I2S codec being used, and the ACPI tables are currently empty, so fall-back to using the firmware filename used in nocodec mode Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111222901.19892-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7dc0018dc4c3..91bd88fddac7 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -415,9 +415,16 @@ static int hda_init_caps(struct snd_sof_dev *sdev) pdata->tplg_filename = hda_mach->sof_tplg_filename; - /* firmware: pick the first in machine list */ + /* + * firmware: pick the first in machine list, + * or use nocodec firmware name if list is empty + */ mach = pdata->desc->machines; - pdata->fw_filename = mach->sof_fw_filename; + if (mach->id[0]) + pdata->fw_filename = mach->sof_fw_filename; + else + pdata->fw_filename = + pdata->desc->nocodec_fw_filename; dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); -- cgit From 74b4dd04b19cc03e1cc369d9c371cf4206367df4 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Mon, 11 Nov 2019 16:33:40 -0600 Subject: ASoC: SOF: PM: add state machine to comments Add Audio DSP state machine with comments. Note that the 'D0<-->runtime D0I3' part is not implemented yet. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111223343.19986-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pm.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 560a937e0484..3204c92f0e7d 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -428,6 +428,38 @@ int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, } EXPORT_SYMBOL(snd_sof_set_d0_substate); +/* + * Audio DSP states may transform as below:- + * + * D0I3 compatible stream + * Runtime +---------------------+ opened only, timeout + * suspend | +--------------------+ + * +------------+ D0(active) | | + * | | <---------------+ | + * | +--------> | | | + * | |Runtime +--^--+---------^--+--+ The last | | + * | |resume | | | | opened D0I3 | | + * | | | | | | compatible | | + * | | resume| | | | stream closed | | + * | | from | | D3 | | | | + * | | D3 | |suspend | | d0i3 | | + * | | | | | |suspend | | + * | | | | | | | | + * | | | | | | | | + * +-v---+-----------+--v-------+ | | +------+----v----+ + * | | | +-----------> | + * | D3 (suspended) | | | D0I3 +-----+ + * | | +--------------+ | | + * | | resume from | | | + * +-------------------^--------+ d0i3 suspend +----------------+ | + * | | + * | D3 suspend | + * +------------------------------------------------+ + * + * d0i3_suspend = s0_suspend && D0I3 stream opened, + * D3 suspend = !d0i3_suspend, + */ + int snd_sof_resume(struct device *dev) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); -- cgit From 58a972efd21bb5adadd97f2546693ec64bfc99b9 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Mon, 11 Nov 2019 16:33:41 -0600 Subject: ASoC: SOF: PM: add check before setting d0_substate Add check before seeting d0_substate and return success if Audio DSP is already in the target substate. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111223343.19986-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 3204c92f0e7d..b89810bf3230 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -416,6 +416,9 @@ int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, { int ret; + if (sdev->d0_substate == d0_substate) + return 0; + /* do platform specific set_state */ ret = snd_sof_dsp_set_power_state(sdev, d0_substate); if (ret < 0) -- cgit From a77e5d573f847d2f984c38eb711351326bc55258 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Mon, 11 Nov 2019 16:33:42 -0600 Subject: ASoC: SOF: add helper to check if we should enter d0i3 suspend Add helper to check if the DSP should be put in D0i3. This function returns true if a stream has ignored the SUSPEND trigger to keep the pipelines running in the DSP. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111223343.19986-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 13 +++++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 15 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 8661c2cca76b..805918d3bcc0 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -132,6 +132,19 @@ struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, return NULL; } +bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev) +{ + struct snd_sof_pcm *spcm; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || + spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) + return true; + } + + return false; +} + /* * FW Panic/fault handling. */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6408ac88a3e5..c7c2c70ee4d0 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -553,6 +553,8 @@ struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, return NULL; } +bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev); + struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, const char *name); struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, -- cgit From 5e35d5f4224adb24c2bfa814b9fb562050aba3ea Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Mon, 11 Nov 2019 16:33:43 -0600 Subject: ASoC: SOF: PM: only suspend to D0I3 when needed We should suspend audio to D3 by default, for the sake of power saving, change the condition of D0I3 suspending here to that when there is stream with suspend_ignored specified. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111223343.19986-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index b89810bf3230..0fd5567237a8 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -468,7 +468,7 @@ int snd_sof_resume(struct device *dev) struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret; - if (sdev->s0_suspend) { + if (snd_sof_dsp_d0i3_on_suspend(sdev)) { /* resume from D0I3 */ dev_dbg(sdev->dev, "DSP will exit from D0i3...\n"); ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I0); @@ -497,7 +497,7 @@ int snd_sof_suspend(struct device *dev) struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret; - if (sdev->s0_suspend) { + if (snd_sof_dsp_d0i3_on_suspend(sdev)) { /* suspend to D0i3 */ dev_dbg(sdev->dev, "DSP is trying to enter D0i3...\n"); ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I3); -- cgit From 509526706e68e4fb47519f02f78b48c818869d4e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Nov 2019 15:32:43 +0100 Subject: ALSA: au88x0: Fix incorrect device pointer for preallocation The code change in commit 6974f8ad4494 ("ALSA: pci: Avoid non-standard macro usage") contained an incorrect conversion, which left the invalid pointer passed to the allocator for au88x0 driver. Fix it. Fixes: 6974f8ad4494 ("ALSA: pci: Avoid non-standard macro usage") Link: https://lore.kernel.org/r/20191112143243.22216-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0_pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 1012e8da29e7..a2dcf43beedf 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -637,7 +637,7 @@ static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) /* pre-allocation of Scatter-Gather buffers */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - &chip->pci_dev, + &chip->pci_dev->dev, 0x10000, 0x10000); switch (VORTEX_PCM_TYPE(pcm)) { -- cgit From 1b4efdaf6d6053c8944cee0edba0969dc1be7d4b Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Mon, 11 Nov 2019 16:20:38 -0600 Subject: ASoC: SOF: topology: free kcontrol memory on error The volume and bytes kcontrols are currently not freeing their memory on initialization failures. When an error occurs, all the widgets loaded so far are unloaded via sof_widget_unload(). But this only happens for the widgets that got successfully loaded. Fix that by kfree()-ing the allocated memory on load error. Fixes: 311ce4fe7637d ("ASoC: SOF: Add support for loading topologies") Reviewed-by: Paul Olaru Reviewed-by: Ranjani Sridharan Signed-off-by: Dragos Tarcatu Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111222039.19651-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 67 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 6096731e89ce..d82ab981e840 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -942,18 +942,22 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, struct sof_ipc_ctrl_data *cdata; int tlv[TLV_ITEMS]; unsigned int i; - int ret; + int ret = 0; /* validate topology data */ - if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) - return -EINVAL; + if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) { + ret = -EINVAL; + goto out; + } /* init the volume get/put data */ scontrol->size = struct_size(scontrol->control_data, chanv, le32_to_cpu(mc->num_channels)); scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); - if (!scontrol->control_data) - return -ENOMEM; + if (!scontrol->control_data) { + ret = -ENOMEM; + goto out; + } scontrol->comp_id = sdev->next_comp_id; scontrol->min_volume_step = le32_to_cpu(mc->min); @@ -963,7 +967,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, /* set cmd for mixer control */ if (le32_to_cpu(mc->max) == 1) { scontrol->cmd = SOF_CTRL_CMD_SWITCH; - goto out; + goto skip; } scontrol->cmd = SOF_CTRL_CMD_VOLUME; @@ -971,14 +975,15 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, /* extract tlv data */ if (get_tlv_data(kc->tlv.p, tlv) < 0) { dev_err(sdev->dev, "error: invalid TLV data\n"); - return -EINVAL; + ret = -EINVAL; + goto out_free; } /* set up volume table */ ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); if (ret < 0) { dev_err(sdev->dev, "error: setting up volume table\n"); - return ret; + goto out_free; } /* set default volume values to 0dB in control */ @@ -988,7 +993,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, cdata->chanv[i].value = VOL_ZERO_DB; } -out: +skip: /* set up possible led control from mixer private data */ ret = sof_parse_tokens(scomp, &scontrol->led_ctl, led_tokens, ARRAY_SIZE(led_tokens), mc->priv.array, @@ -996,13 +1001,21 @@ out: if (ret != 0) { dev_err(sdev->dev, "error: parse led tokens failed %d\n", le32_to_cpu(mc->priv.size)); - return ret; + goto out_free_table; } dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); - return 0; + return ret; + +out_free_table: + if (le32_to_cpu(mc->max) > 1) + kfree(scontrol->volume_table); +out_free: + kfree(scontrol->control_data); +out: + return ret; } static int sof_control_load_enum(struct snd_soc_component *scomp, @@ -1047,6 +1060,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; int max_size = sbe->max; + int ret = 0; /* init the get/put bytes data */ scontrol->size = sizeof(struct sof_ipc_ctrl_data) + @@ -1055,13 +1069,16 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, if (scontrol->size > max_size) { dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", scontrol->size, max_size); - return -EINVAL; + ret = -EINVAL; + goto out; } scontrol->control_data = kzalloc(max_size, GFP_KERNEL); cdata = scontrol->control_data; - if (!scontrol->control_data) - return -ENOMEM; + if (!scontrol->control_data) { + ret = -ENOMEM; + goto out; + } scontrol->comp_id = sdev->next_comp_id; scontrol->cmd = SOF_CTRL_CMD_BINARY; @@ -1076,23 +1093,32 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, if (cdata->data->magic != SOF_ABI_MAGIC) { dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", cdata->data->magic); - return -EINVAL; + ret = -EINVAL; + goto out_free; } if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { dev_err(sdev->dev, "error: Incompatible ABI version 0x%08x.\n", cdata->data->abi); - return -EINVAL; + ret = -EINVAL; + goto out_free; } if (cdata->data->size + sizeof(const struct sof_abi_hdr) != le32_to_cpu(control->priv.size)) { dev_err(sdev->dev, "error: Conflict in bytes vs. priv size.\n"); - return -EINVAL; + ret = -EINVAL; + goto out_free; } } - return 0; + + return ret; + +out_free: + kfree(scontrol->control_data); +out: + return ret; } /* external kcontrol init - used for any driver specific init */ @@ -1150,6 +1176,11 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, return 0; } + if (ret < 0) { + kfree(scontrol); + return ret; + } + dobj->private = scontrol; list_add(&scontrol->list, &sdev->kcontrol_list); return ret; -- cgit From 8f157d4ff039e03e2ed4cb602eeed2fd4687a58f Mon Sep 17 00:00:00 2001 From: Pawel Harlozinski Date: Tue, 12 Nov 2019 14:02:36 +0100 Subject: ASoC: Jack: Fix NULL pointer dereference in snd_soc_jack_report Check for existance of jack before tracing. NULL pointer dereference has been reported by KASAN while unloading machine driver (snd_soc_cnl_rt274). Signed-off-by: Pawel Harlozinski Link: https://lore.kernel.org/r/20191112130237.10141-1-pawel.harlozinski@linux.intel.com Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/soc-jack.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index a71d2340eb05..b5748dcd490f 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -82,10 +82,9 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) unsigned int sync = 0; int enable; - trace_snd_soc_jack_report(jack, mask, status); - if (!jack) return; + trace_snd_soc_jack_report(jack, mask, status); dapm = &jack->card->dapm; -- cgit From 0d18a7caa654ea1a0c02b3a253adfd5c10723871 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Nov 2019 10:07:07 +0900 Subject: ASoC: soc-core: remove soc_is_dai_link_bound() Because complex separeted "card pre-listed component" and "topology added component" duplicated operation is now becoming simple, we don't need to check already bound dai_link which is not exist anymore. This patch removes soc_is_dai_link_bound(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v9rxhkxw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 55014e7ae0d8..c6885adbdc8b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -953,19 +953,6 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_find_dai_link); -static bool soc_is_dai_link_bound(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link) -{ - struct snd_soc_pcm_runtime *rtd; - - for_each_card_rtds(card, rtd) { - if (rtd->dai_link == dai_link) - return true; - } - - return false; -} - static int soc_dai_link_sanity_check(struct snd_soc_card *card, struct snd_soc_dai_link *link) { @@ -1085,12 +1072,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name); - if (soc_is_dai_link_bound(card, dai_link)) { - dev_dbg(card->dev, "ASoC: dai link %s already bound\n", - dai_link->name); - return 0; - } - ret = soc_dai_link_sanity_check(card, dai_link); if (ret < 0) return ret; -- cgit From 7ca24386a7c2fb3828303b7c694cb0b4af1eac5c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Nov 2019 10:07:17 +0900 Subject: ASoC: soc-core: merge snd_soc_register_dai() and soc_add_dai() We don't need to separete snd_soc_register_dai() and soc_add_dai() anymore. Let's merge these Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tv7hhkxm.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c6885adbdc8b..b2544c7ff0f4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2517,16 +2517,27 @@ static void soc_del_dai(struct snd_soc_dai *dai) list_del(&dai->list); } -/* Create a DAI and add it to the component's DAI list */ -static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, - bool legacy_dai_naming) +/** + * snd_soc_register_dai - Register a DAI dynamically & create its widgets + * + * @component: The component the DAIs are registered for + * @dai_drv: DAI driver to use for the DAI + * + * Topology can use this API to register DAIs when probing a component. + * These DAIs's widgets will be freed in the card cleanup and the DAIs + * will be freed in the component cleanup. + */ +struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming) { struct device *dev = component->dev; struct snd_soc_dai *dai; dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev)); + lockdep_assert_held(&client_mutex); + dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL); if (dai == NULL) return NULL; @@ -2565,6 +2576,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); return dai; } +EXPORT_SYMBOL_GPL(snd_soc_register_dai); void snd_soc_unregister_dai(struct snd_soc_dai *dai) { @@ -2572,29 +2584,6 @@ void snd_soc_unregister_dai(struct snd_soc_dai *dai) } EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); -/** - * snd_soc_register_dai - Register a DAI dynamically & create its widgets - * - * @component: The component the DAIs are registered for - * @dai_drv: DAI driver to use for the DAI - * - * Topology can use this API to register DAIs when probing a component. - * These DAIs's widgets will be freed in the card cleanup and the DAIs - * will be freed in the component cleanup. - */ -struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, - bool legacy_dai_naming) -{ - struct device *dev = component->dev; - - dev_dbg(dev, "ASoC: dai register %s\n", dai_drv->name); - - lockdep_assert_held(&client_mutex); - return soc_add_dai(component, dai_drv, legacy_dai_naming); -} -EXPORT_SYMBOL_GPL(snd_soc_register_dai); - /** * snd_soc_unregister_dai - Unregister DAIs from the ASoC core * -- cgit From ffdbca0be6c78ea32b9243eea976270441210f2f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Nov 2019 10:07:23 +0900 Subject: ASoC: soc-core: merge snd_soc_unregister_dai() and soc_del_dai() We don't need to separete snd_soc_unregister_dai() and soc_del_dai() anymore. Let's merge these Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgn1hkxg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b2544c7ff0f4..01a8fb28b48f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2511,11 +2511,12 @@ static inline char *fmt_multiple_name(struct device *dev, return devm_kstrdup(dev, dai_drv->name, GFP_KERNEL); } -static void soc_del_dai(struct snd_soc_dai *dai) +void snd_soc_unregister_dai(struct snd_soc_dai *dai) { dev_dbg(dai->dev, "ASoC: Unregistered DAI '%s'\n", dai->name); list_del(&dai->list); } +EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); /** * snd_soc_register_dai - Register a DAI dynamically & create its widgets @@ -2576,13 +2577,6 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); return dai; } -EXPORT_SYMBOL_GPL(snd_soc_register_dai); - -void snd_soc_unregister_dai(struct snd_soc_dai *dai) -{ - soc_del_dai(dai); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); /** * snd_soc_unregister_dai - Unregister DAIs from the ASoC core -- cgit From 63dc47da1f396fecd2373e41928e275f9ca3d924 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Nov 2019 10:07:31 +0900 Subject: ASoC: soc-core: merge snd_soc_add_dai_link() and soc_bind_dai_link() We don't need to separete snd_soc_add_dai_link() and soc_bind_dai_link() anymore. Let's merge these. One note is that before this patch, it adds list (A) eventhough if it had dai_link->ignore (1), or already bounded dai_link (2). But I guess it is wrong. This patch also solve this issue. /* BEFORE */ int soc_bind_dai_link(...) { ... (1) if (dai_link->ignore) return 0; (2) if (soc_is_dai_link_bound(...)) return 0; ... } int snd_soc_add_dai_link(...) { ... => ret = soc_bind_dai_link(...); => if (ret < 0) => return ret; (A) list_add_tail(&dai_link->list, &card->dai_link_list); ... } /* AFTER */ int snd_soc_add_dai_link(...) { ... (1) if (dai_link->ignore) return 0; (2) if (soc_is_dai_link_bound(...)) return 0; ... (A) list_add_tail(&dai_link->list, &card->dai_link_list); return 0; } Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r22lhkx8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 62 +++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 37 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 01a8fb28b48f..8add98431881 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1059,14 +1059,33 @@ static void soc_unbind_dai_link(struct snd_soc_card *card, soc_free_pcm_runtime(rtd); } -static int soc_bind_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link) +/** + * snd_soc_add_dai_link - Add a DAI link dynamically + * @card: The ASoC card to which the DAI link is added + * @dai_link: The new DAI link to add + * + * This function adds a DAI link to the ASoC card's link list. + * + * Note: Topology can use this API to add DAI links when probing the + * topology component. And machine drivers can still define static + * DAI links in dai_link array. + */ +int snd_soc_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codec, *platform; struct snd_soc_component *component; int i, ret; + lockdep_assert_held(&client_mutex); + + /* + * Notify the machine driver for extra initialization + */ + if (card->add_dai_link) + card->add_dai_link(card, dai_link); + if (dai_link->ignore) return 0; @@ -1115,12 +1134,16 @@ static int soc_bind_dai_link(struct snd_soc_card *card, } } + /* see for_each_card_links */ + list_add_tail(&dai_link->list, &card->dai_link_list); + return 0; _err_defer: soc_free_pcm_runtime(rtd); return -EPROBE_DEFER; } +EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); static void soc_set_of_name_prefix(struct snd_soc_component *component) { @@ -1411,41 +1434,6 @@ void snd_soc_disconnect_sync(struct device *dev) } EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync); -/** - * snd_soc_add_dai_link - Add a DAI link dynamically - * @card: The ASoC card to which the DAI link is added - * @dai_link: The new DAI link to add - * - * This function adds a DAI link to the ASoC card's link list. - * - * Note: Topology can use this API to add DAI links when probing the - * topology component. And machine drivers can still define static - * DAI links in dai_link array. - */ -int snd_soc_add_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link) -{ - int ret; - - lockdep_assert_held(&client_mutex); - - /* - * Notify the machine driver for extra initialization - */ - if (card->add_dai_link) - card->add_dai_link(card, dai_link); - - ret = soc_bind_dai_link(card, dai_link); - if (ret < 0) - return ret; - - /* see for_each_card_links */ - list_add_tail(&dai_link->list, &card->dai_link_list); - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); - /** * snd_soc_remove_dai_link - Remove a DAI link from the list * @card: The ASoC card that owns the link -- cgit From da704f26ba376bd93ac5234fa4605c4a8e4a5648 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Nov 2019 10:07:38 +0900 Subject: ASoC: soc-core: merge snd_soc_remove_dai_link() and soc_unbind_dai_link() We don't need to separete snd_soc_remove_dai_link() and soc_unbind_dai_link() anymore. Let's merge these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pni5hkx1.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 52 +++++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8add98431881..d80d485f46d1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1049,15 +1049,36 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card, return 0; } -static void soc_unbind_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link) +/** + * snd_soc_remove_dai_link - Remove a DAI link from the list + * @card: The ASoC card that owns the link + * @dai_link: The DAI link to remove + * + * This function removes a DAI link from the ASoC card's link list. + * + * For DAI links previously added by topology, topology should + * remove them by using the dobj embedded in the link. + */ +void snd_soc_remove_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; + lockdep_assert_held(&client_mutex); + + /* + * Notify the machine driver for extra destruction + */ + if (card->remove_dai_link) + card->remove_dai_link(card, dai_link); + + list_del(&dai_link->list); + rtd = snd_soc_get_pcm_runtime(card, dai_link->name); if (rtd) soc_free_pcm_runtime(rtd); } +EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); /** * snd_soc_add_dai_link - Add a DAI link dynamically @@ -1434,33 +1455,6 @@ void snd_soc_disconnect_sync(struct device *dev) } EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync); -/** - * snd_soc_remove_dai_link - Remove a DAI link from the list - * @card: The ASoC card that owns the link - * @dai_link: The DAI link to remove - * - * This function removes a DAI link from the ASoC card's link list. - * - * For DAI links previously added by topology, topology should - * remove them by using the dobj embedded in the link. - */ -void snd_soc_remove_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link) -{ - lockdep_assert_held(&client_mutex); - - /* - * Notify the machine driver for extra destruction - */ - if (card->remove_dai_link) - card->remove_dai_link(card, dai_link); - - list_del(&dai_link->list); - - soc_unbind_dai_link(card, dai_link); -} -EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); - static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, struct snd_soc_pcm_runtime *rtd) { -- cgit From c6619b729814c855fc7bfa5a6936f5ea94d60dfd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Nov 2019 10:07:46 +0900 Subject: ASoC: soc-core: merge soc_remove_component() and soc_cleanup_component() having both soc_remove_component() and soc_cleanup_component() is very confusable. Let's merge these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o8xphkwt.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d80d485f46d1..11cbd7915154 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1201,8 +1201,16 @@ static void soc_set_name_prefix(struct snd_soc_card *card, soc_set_of_name_prefix(component); } -static void soc_cleanup_component(struct snd_soc_component *component) +static void soc_remove_component(struct snd_soc_component *component, + int probed) { + + if (!component->card) + return; + + if (probed) + snd_soc_component_remove(component); + /* For framework level robustness */ snd_soc_component_set_jack(component, NULL, NULL); @@ -1213,22 +1221,13 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_component_module_put_when_remove(component); } -static void soc_remove_component(struct snd_soc_component *component) -{ - if (!component->card) - return; - - snd_soc_component_remove(component); - - soc_cleanup_component(component); -} - static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct snd_soc_dai *dai; + int probed = 0; int ret; if (!strcmp(component->name, "snd-soc-dummy")) @@ -1284,6 +1283,7 @@ static int soc_probe_component(struct snd_soc_card *card, dapm->bias_level != SND_SOC_BIAS_OFF, "codec %s can not start from non-off bias with idle_bias_off==1\n", component->name); + probed = 1; /* machine specific init */ if (component->init) { @@ -1312,7 +1312,7 @@ static int soc_probe_component(struct snd_soc_card *card, err_probe: if (ret < 0) - soc_cleanup_component(component); + soc_remove_component(component, probed); return ret; } @@ -1414,7 +1414,7 @@ static void soc_remove_link_components(struct snd_soc_card *card) if (component->driver->remove_order != order) continue; - soc_remove_component(component); + soc_remove_component(component, 1); } } } @@ -1608,7 +1608,7 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) for_each_comp_order(order) { for_each_card_auxs_safe(card, comp, _comp) { if (comp->driver->remove_order == order) - soc_remove_component(comp); + soc_remove_component(comp, 1); } } } -- cgit From ed90c013a773b5f9e06089d0eed6714761152d14 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Nov 2019 10:07:56 +0900 Subject: ASoC: soc-core: merge snd_soc_bind_card() and snd_soc_instantiate_card() having both soc_bind_card() and snd_soc_instantiate_card() is very confusable. Let's merge these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87mud9hkwj.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 11cbd7915154..f3d33a908fbc 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1974,7 +1974,7 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) card->remove(card); } -static int snd_soc_instantiate_card(struct snd_soc_card *card) +static int snd_soc_bind_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *dai_link; @@ -2106,6 +2106,19 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); + /* deactivate pins to sleep state */ + for_each_card_rtds(card, rtd) { + struct snd_soc_dai *dai; + + for_each_rtd_codec_dai(rtd, i, dai) { + if (!dai->active) + pinctrl_pm_select_sleep_state(dai->dev); + } + + if (!rtd->cpu_dai->active) + pinctrl_pm_select_sleep_state(rtd->cpu_dai->dev); + } + probe_end: if (ret < 0) soc_cleanup_card_resources(card); @@ -2338,33 +2351,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); -static int snd_soc_bind_card(struct snd_soc_card *card) -{ - struct snd_soc_pcm_runtime *rtd; - int ret; - - ret = snd_soc_instantiate_card(card); - if (ret != 0) - return ret; - - /* deactivate pins to sleep state */ - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai; - int j; - - for_each_rtd_codec_dai(rtd, j, codec_dai) { - if (!codec_dai->active) - pinctrl_pm_select_sleep_state(codec_dai->dev); - } - - if (!cpu_dai->active) - pinctrl_pm_select_sleep_state(cpu_dai->dev); - } - - return ret; -} - /** * snd_soc_register_card - Register a card with the ASoC core * -- cgit From 74bd3f92d0d173fe4c0a12cf736c505ceb15576a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Nov 2019 10:08:06 +0900 Subject: ASoC: soc-core: tidyup soc_probe_aux_devices() snd_soc_bind_card() is calling many initialize functions for each card / link / dai / aux etc, etc, etc... When error happen, the message is indicated at snd_soc_bind_card(), not at each functions. But, only soc_probe_aux_devices() case is indicating error at functions, not at snd_soc_bind_card(). It is not an issue, but unbalanced. This patch moves error message to snd_soc_bind_card(). Also avoids deep-nested code. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfsthkw9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f3d33a908fbc..92260a9569a2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1579,21 +1579,18 @@ static int soc_bind_aux_dev(struct snd_soc_card *card) static int soc_probe_aux_devices(struct snd_soc_card *card) { - struct snd_soc_component *comp; + struct snd_soc_component *component; int order; int ret; for_each_comp_order(order) { - for_each_card_auxs(card, comp) { - if (comp->driver->probe_order == order) { - ret = soc_probe_component(card, comp); - if (ret < 0) { - dev_err(card->dev, - "ASoC: failed to probe aux component %s %d\n", - comp->name, ret); - return ret; - } - } + for_each_card_auxs(card, component) { + if (component->driver->probe_order != order) + continue; + + ret = soc_probe_component(card, component); + if (ret < 0) + return ret; } } @@ -2042,8 +2039,11 @@ static int snd_soc_bind_card(struct snd_soc_card *card) /* probe auxiliary components */ ret = soc_probe_aux_devices(card); - if (ret < 0) + if (ret < 0) { + dev_err(card->dev, + "ASoC: failed to probe aux component %d\n", ret); goto probe_end; + } /* probe all DAI links on this card */ ret = soc_probe_link_dais(card); -- cgit From cb45722b289b54476b68883985c2824c69a7fba9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Nov 2019 20:09:37 +0100 Subject: ALSA: hda/hdmi - Clean up Intel platform-specific fixup checks Introduce a new flag in hdmi_spec to indicate the Intel platform- specific fixups so that we can get rid of the lengthy codec ID checks. The flag is set in intel_hsw_common_init() commonly. Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20191111190937.19186-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d24bd95c6e95..69d1a6e41f0d 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -37,25 +37,6 @@ static bool static_hdmi_pcm; module_param(static_hdmi_pcm, bool, 0644); MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); -#define is_haswell(codec) ((codec)->core.vendor_id == 0x80862807) -#define is_broadwell(codec) ((codec)->core.vendor_id == 0x80862808) -#define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809) -#define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a) -#define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b) -#define is_geminilake(codec) (((codec)->core.vendor_id == 0x8086280d) || \ - ((codec)->core.vendor_id == 0x80862800)) -#define is_cannonlake(codec) ((codec)->core.vendor_id == 0x8086280c) -#define is_icelake(codec) ((codec)->core.vendor_id == 0x8086280f) -#define is_tigerlake(codec) ((codec)->core.vendor_id == 0x80862812) -#define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \ - || is_skylake(codec) || is_broxton(codec) \ - || is_kabylake(codec) || is_geminilake(codec) \ - || is_cannonlake(codec) || is_icelake(codec) \ - || is_tigerlake(codec)) -#define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882) -#define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883) -#define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec)) - struct hdmi_spec_per_cvt { hda_nid_t cvt_nid; int assigned; @@ -162,6 +143,7 @@ struct hdmi_spec { bool dyn_pin_out; bool dyn_pcm_assign; + bool intel_hsw_fixup; /* apply Intel platform-specific fixups */ /* * Non-generic VIA/NVIDIA specific */ @@ -925,7 +907,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, return err; } - if (is_haswell_plus(codec)) { + if (spec->intel_hsw_fixup) { /* * on recent platforms IEC Coding Type is required for HBR @@ -1709,7 +1691,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) * To simplify the implementation, malloc all * the virtual pins in the initialization statically */ - if (is_haswell_plus(codec)) { + if (spec->intel_hsw_fixup) { /* * On Intel platforms, device entries number is * changed dynamically. If there is a DP MST @@ -1758,7 +1740,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) per_pin->dev_id = i; per_pin->non_pcm = false; snd_hda_set_dev_select(codec, pin_nid, i); - if (is_haswell_plus(codec)) + if (spec->intel_hsw_fixup) intel_haswell_fixup_connect_list(codec, pin_nid); err = hdmi_read_pin_conn(codec, pin_idx); if (err < 0) @@ -2825,6 +2807,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, spec->vendor_nid = vendor_nid; spec->port_map = port_map; spec->port_num = port_num; + spec->intel_hsw_fixup = true; intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); -- cgit From f35ef592477c5347b8f780a5f0d4970671e22c61 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Nov 2019 17:56:13 +0100 Subject: ALSA: usb-audio: Add skip_validation option The unit descriptor validation may lead to a probe error when the device provides a buggy descriptor or the validator detected incorrectly. For identifying such an error and band-aiding, give a new module option, skip_validation. With this option, the driver ignores the validation errors with the hexdump of the unit descriptor, so we can check it in a bit more details. Link: https://lore.kernel.org/r/20191114165613.7422-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 3 +++ sound/usb/usbaudio.h | 1 + sound/usb/validate.c | 23 ++++++++++++++++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index db91dc76cc91..9f743ebae615 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -74,6 +74,7 @@ static bool autoclock = true; static char *quirk_alias[SNDRV_CARDS]; bool snd_usb_use_vmalloc = true; +bool snd_usb_skip_validation; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); @@ -96,6 +97,8 @@ module_param_array(quirk_alias, charp, NULL, 0444); MODULE_PARM_DESC(quirk_alias, "Quirk aliases, e.g. 0123abcd:5678beef."); module_param_named(use_vmalloc, snd_usb_use_vmalloc, bool, 0444); MODULE_PARM_DESC(use_vmalloc, "Use vmalloc for PCM intermediate buffers (default: yes)."); +module_param_named(skip_validation, snd_usb_skip_validation, bool, 0444); +MODULE_PARM_DESC(skip_validation, "Skip unit descriptor validation (default: no)."); /* * we keep the snd_usb_audio_t instances by ourselves for merging diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index feb30f9c1716..ff3cbf653de8 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -120,5 +120,6 @@ int snd_usb_lock_shutdown(struct snd_usb_audio *chip); void snd_usb_unlock_shutdown(struct snd_usb_audio *chip); extern bool snd_usb_use_vmalloc; +extern bool snd_usb_skip_validation; #endif /* __USBAUDIO_H */ diff --git a/sound/usb/validate.c b/sound/usb/validate.c index 389e8657434a..36ae78c3da3d 100644 --- a/sound/usb/validate.c +++ b/sound/usb/validate.c @@ -322,11 +322,28 @@ static bool validate_desc(unsigned char *hdr, int protocol, bool snd_usb_validate_audio_desc(void *p, int protocol) { - return validate_desc(p, protocol, audio_validators); + unsigned char *c = p; + bool valid; + + valid = validate_desc(p, protocol, audio_validators); + if (!valid && snd_usb_skip_validation) { + print_hex_dump(KERN_ERR, "USB-audio: buggy audio desc: ", + DUMP_PREFIX_NONE, 16, 1, c, c[0], true); + valid = true; + } + return valid; } bool snd_usb_validate_midi_desc(void *p) { - return validate_desc(p, UAC_VERSION_1, midi_validators); + unsigned char *c = p; + bool valid; + + valid = validate_desc(p, UAC_VERSION_1, midi_validators); + if (!valid && snd_usb_skip_validation) { + print_hex_dump(KERN_ERR, "USB-audio: buggy midi desc: ", + DUMP_PREFIX_NONE, 16, 1, c, c[0], true); + valid = true; + } + return valid; } - -- cgit From e9149b8c00d25dbaef1aa174fc604bed207e576d Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 12 Nov 2019 23:36:29 +0100 Subject: ASoC: wm8904: fix regcache handling The current code assumes that the power is turned off in SND_SOC_BIAS_OFF. If there are no actual regulator the codec isn't turned off and the registers are not reset to their default values but the regcache is still marked as dirty. Thus a value might not be written to the hardware if it is set to the default value. Do a software reset before turning off the power to make sure the registers are always reset to their default states. Signed-off-by: Michael Walle Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20191112223629.21867-1-michael@walle.cc Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index bcb3c9d5abf0..9e8c564f6e9c 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1917,6 +1917,7 @@ static int wm8904_set_bias_level(struct snd_soc_component *component, snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0, WM8904_BIAS_ENA, 0); + snd_soc_component_write(component, WM8904_SW_RESET_AND_ID, 0); regcache_cache_only(wm8904->regmap, true); regcache_mark_dirty(wm8904->regmap); -- cgit From fe23be2d85b05f561431d75acddec726ea807d2a Mon Sep 17 00:00:00 2001 From: Jacob Rasmussen Date: Thu, 14 Nov 2019 16:20:11 -0700 Subject: ASoC: rt5645: Fixed typo for buddy jack support. Had a typo in e7cfd867fd98 that resulted in buddy jack support not being fixed. Fixes: e7cfd867fd98 ("ASoC: rt5645: Fixed buddy jack support.") Signed-off-by: Jacob Rasmussen Reviewed-by: Ross Zwisler Cc: CC: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191114232011.165762-1-jacobraz@google.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 902ac98a3fbe..19662ee330d6 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3271,7 +3271,7 @@ static void rt5645_jack_detect_work(struct work_struct *work) report, SND_JACK_MICROPHONE); return; case 4: - val = snd_soc_component_read32(rt5645->component, RT5645_A_JD_CTRL1) & 0x002; + val = snd_soc_component_read32(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; break; default: /* read rt5645 jd1_1 status */ val = snd_soc_component_read32(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000; -- cgit From b26eb5173c85082eec7d6e18369f6f9d96bf0b21 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 12 Nov 2019 19:02:18 +0000 Subject: ASoC: tas2770: clean up an indentation issue There is a block that is indented too deeply, remove the extraneous tabs. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20191112190218.282337-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2770.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index ad76f22fcfac..54c8135fe43c 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -761,12 +761,12 @@ static int tas2770_i2c_probe(struct i2c_client *client, tas2770->reset_gpio = devm_gpiod_get_optional(tas2770->dev, "reset-gpio", GPIOD_OUT_HIGH); - if (IS_ERR(tas2770->reset_gpio)) { - if (PTR_ERR(tas2770->reset_gpio) == -EPROBE_DEFER) { - tas2770->reset_gpio = NULL; - return -EPROBE_DEFER; - } + if (IS_ERR(tas2770->reset_gpio)) { + if (PTR_ERR(tas2770->reset_gpio) == -EPROBE_DEFER) { + tas2770->reset_gpio = NULL; + return -EPROBE_DEFER; } + } tas2770->channel_size = 0; tas2770->slot_width = 0; -- cgit From 2a6f0892bda954dc2688b002060093ee0fe38528 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 13 Nov 2019 10:16:29 +0900 Subject: ASoC: soc-core: call snd_soc_dapm_shutdown() at soc_cleanup_card_resources() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. snd_soc_bind_card() is calling snd_soc_dapm_init() for both card and component. Let's call paired snd_soc_dapm_shutdown() at paired soc_cleanup_card_resources(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r22c4lub.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 92260a9569a2..216000ae3e20 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1953,6 +1953,8 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) card->snd_card = NULL; } + snd_soc_dapm_shutdown(card); + /* remove and free each DAI */ soc_remove_link_dais(card); @@ -2389,7 +2391,6 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) { if (card->instantiated) { card->instantiated = false; - snd_soc_dapm_shutdown(card); snd_soc_flush_all_delayed_work(card); soc_cleanup_card_resources(card); -- cgit From 2cc1afcfc617b33b72e409360ba5dd7c3fc2492d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 13 Nov 2019 10:16:34 +0900 Subject: ASoC: soc-core: move snd_soc_unbind_card() next to snd_soc_bind_card() To makes code readable, this patch moves snd_soc_unbind_card() next to snd_soc_bind_card(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pnhw4lu5.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 216000ae3e20..a149697e705d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1973,6 +1973,21 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) card->remove(card); } +static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) +{ + if (card->instantiated) { + card->instantiated = false; + snd_soc_flush_all_delayed_work(card); + + soc_cleanup_card_resources(card); + if (!unregister) + list_add(&card->list, &unbind_card_list); + } else { + if (unregister) + list_del(&card->list); + } +} + static int snd_soc_bind_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -2387,21 +2402,6 @@ int snd_soc_register_card(struct snd_soc_card *card) } EXPORT_SYMBOL_GPL(snd_soc_register_card); -static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) -{ - if (card->instantiated) { - card->instantiated = false; - snd_soc_flush_all_delayed_work(card); - - soc_cleanup_card_resources(card); - if (!unregister) - list_add(&card->list, &unbind_card_list); - } else { - if (unregister) - list_del(&card->list); - } -} - /** * snd_soc_unregister_card - Unregister a card with the ASoC core * -- cgit From ce21401c9d30e81824e864dc25824ebeb9690801 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 13 Nov 2019 10:16:48 +0900 Subject: ASoC: soc-core: care card_probed at soc_cleanup_card_resources() soc_cleanup_card_resources() will call card->remove(), but it should be called if card->probe() or card->late_probe() are called. snd_soc_bind_card() might be error before calling card->probe() / card->late_probe(). In that time, card->remove() will be called. This patch adds card_probed parameter to judge it. Fixes: bfce78a559655 ("ASoC: soc-core: tidyup soc_init_dai_link()") Signed-off-by: Kuninori Morimoto Tested-by: Jon Hunter Link: https://lore.kernel.org/r/87o8xg4ltr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a149697e705d..977a7bfad519 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1940,7 +1940,8 @@ static void __soc_setup_card_name(char *name, int len, } } -static void soc_cleanup_card_resources(struct snd_soc_card *card) +static void soc_cleanup_card_resources(struct snd_soc_card *card, + int card_probed) { struct snd_soc_dai_link *link, *_link; @@ -1969,17 +1970,19 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) soc_cleanup_card_debugfs(card); /* remove the card */ - if (card->remove) + if (card_probed && card->remove) card->remove(card); } static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) { if (card->instantiated) { + int card_probed = 1; + card->instantiated = false; snd_soc_flush_all_delayed_work(card); - soc_cleanup_card_resources(card); + soc_cleanup_card_resources(card, card_probed); if (!unregister) list_add(&card->list, &unbind_card_list); } else { @@ -1992,7 +1995,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *dai_link; - int ret, i; + int ret, i, card_probed = 0; mutex_lock(&client_mutex); mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); @@ -2044,6 +2047,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) ret = card->probe(card); if (ret < 0) goto probe_end; + card_probed = 1; } /* probe all components used by DAI links on this card */ @@ -2109,6 +2113,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) goto probe_end; } } + card_probed = 1; snd_soc_dapm_new_widgets(card); @@ -2138,7 +2143,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) probe_end: if (ret < 0) - soc_cleanup_card_resources(card); + soc_cleanup_card_resources(card, card_probed); mutex_unlock(&card->mutex); mutex_unlock(&client_mutex); -- cgit From de8cf95231102f0b1d71499b89c93902c9bb7908 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:54:44 +0200 Subject: ASoC: dmaengine: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191113095445.3211-2-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/soc-generic-dmaengine-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index f4c755209e03..a428ff393ea2 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -387,7 +387,7 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, name = dmaengine_pcm_dma_channel_names[i]; if (config && config->chan_names[i]) name = config->chan_names[i]; - chan = dma_request_slave_channel_reason(dev, name); + chan = dma_request_chan(dev, name); if (IS_ERR(chan)) { if (PTR_ERR(chan) == -EPROBE_DEFER) return -EPROBE_DEFER; -- cgit From f0c97131b946fe77e22eddbd7e7d92fb6459f497 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 11:54:45 +0200 Subject: ASoC: ti: davinci-mcasp: Use dma_request_chan() directly for channel request dma_request_slave_channel_reason() is: #define dma_request_slave_channel_reason(dev, name) \ dma_request_chan(dev, name) Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191113095445.3211-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 7aa3c32e4a49..8e5371801d88 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -1867,7 +1867,7 @@ static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) return PCM_EDMA; tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; - chan = dma_request_slave_channel_reason(mcasp->dev, tmp); + chan = dma_request_chan(mcasp->dev, tmp); if (IS_ERR(chan)) { if (PTR_ERR(chan) != -EPROBE_DEFER) dev_err(mcasp->dev, -- cgit From d577cf76fa3192f9e656bb101aa54d25a6a71347 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 15 Nov 2019 14:44:47 +0200 Subject: ALSA: hda: hdmi - fix port numbering for ICL and TGL platforms Semantics of port#0 differ between ICL and TGL: ICL port#0 -> never used for HDAudio ICL port#1 -> should be mapped to first pin (0x04) TGL port#0 -> typically not used, but HW has the support, so should be mapped to first pin (0x04) TGL port#1 -> should be mapped to 2nd pin (0x06) Refactor the port mapping logic to allow to take the above differences into account. Fixes issues with HDAudio on some TGL platforms. Co-developed-by: Pan Xiuli Signed-off-by: Pan Xiuli Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20191115124449.20512-2-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 69d1a6e41f0d..dec90f931bae 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2664,7 +2664,7 @@ static int intel_pin2port(void *audio_ptr, int pin_nid) */ for (i = 0; i < spec->port_num; i++) { if (pin_nid == spec->port_map[i]) - return i + 1; + return i; } /* return -1 if pin number exceeds our expectation */ @@ -2684,9 +2684,9 @@ static int intel_port2pin(struct hda_codec *codec, int port) return port + intel_base_nid(codec) - 1; } - if (port < 1 || port > spec->port_num) + if (port < 0 || port >= spec->port_num) return 0; - return spec->port_map[port - 1]; + return spec->port_map[port]; } static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) @@ -2838,9 +2838,9 @@ static int patch_i915_icl_hdmi(struct hda_codec *codec) { /* * pin to port mapping table where the value indicate the pin number and - * the index indicate the port number with 1 base. + * the index indicate the port number. */ - static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb}; + static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb}; return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); } @@ -2849,7 +2849,7 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec) { /* * pin to port mapping table where the value indicate the pin number and - * the index indicate the port number with 1 base. + * the index indicate the port number. */ static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; -- cgit From c8e3eb9be57f91751aeb9397118755390dbff9a4 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 15 Nov 2019 14:44:48 +0200 Subject: ALSA: hda: hdmi - remove redundant code comments Remove unnecessary comments related to pin mapping on Intel platforms. Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20191115124449.20512-3-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index dec90f931bae..d3768767625e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2655,7 +2655,7 @@ static int intel_pin2port(void *audio_ptr, int pin_nid) base_nid = intel_base_nid(codec); if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3)) return -1; - return pin_nid - base_nid + 1; /* intel port is 1-based */ + return pin_nid - base_nid + 1; } /* @@ -2667,7 +2667,6 @@ static int intel_pin2port(void *audio_ptr, int pin_nid) return i; } - /* return -1 if pin number exceeds our expectation */ codec_info(codec, "Can't find the HDMI/DP port for pin %d\n", pin_nid); return -1; } @@ -2680,7 +2679,6 @@ static int intel_port2pin(struct hda_codec *codec, int port) /* we assume only from port-B to port-D */ if (port < 1 || port > 3) return 0; - /* intel port is 1-based */ return port + intel_base_nid(codec) - 1; } @@ -2856,7 +2854,6 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec) return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); } - /* Intel Baytrail and Braswell; with eld notifier */ static int patch_i915_byt_hdmi(struct hda_codec *codec) { -- cgit From ee906c6b9c6e7e4ad749f5cfdf65768455f4bf43 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 15 Nov 2019 14:44:49 +0200 Subject: ALSA: hda - remove forced polling workaround for CFL and CNL Remove the workarounds added in commit fa763f1b2858 ("ALSA: hda - Force polling mode on CNL for fixing codec communication") and commit a8d7bde23e71 ("ALSA: hda - Force polling mode on CFL for fixing codec communication"). The workarounds are no longer needed after the more generic change done in commit 2756d9143aa5 ("ALSA: hda - Fix intermittent CORB/RIRB stall on Intel chips"). This change applies to a larger set of hardware and covers CFL and CNL as well. Similar change was already done to SOF DSP HDA driver with no regressions detected. Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20191115124449.20512-4-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8981109e3565..e76a0bb6d3cf 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -369,8 +369,6 @@ enum { ((pci)->device == 0x160c)) #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) -#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) -#define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8) static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", @@ -1763,10 +1761,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, if (!azx_snoop(chip)) azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_UC; - /* Workaround for a communication error on CFL (bko#199007) and CNL */ - if (IS_CFL(pci) || IS_CNL(pci)) - azx_bus(chip)->polling_mode = 1; - if (chip->driver_type == AZX_DRIVER_NVIDIA) { dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); chip->bus.needs_damn_long_delay = 1; -- cgit From 44d13f6c2a0b739a7c4df3c478c8070320c4fd45 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 18 Nov 2019 17:16:24 +0800 Subject: ASoC: rt5682: fix the charge pump capacitor discharges Due to switching the HV to LV mode while stopping playback, the charge pump capacitor will be discharged to the source of the pump circuit. Therefore, this patch removed the event control. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20191118091624.18699-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 62b8ed412bd1..5370e4b00104 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1451,28 +1451,6 @@ static const struct snd_kcontrol_new hpor_switch = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1, RT5682_R_MUTE_SFT, 1, 1); -static int rt5682_charge_pump_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_component *component = - snd_soc_dapm_to_component(w->dapm); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - snd_soc_component_update_bits(component, - RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_HV); - break; - case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, - RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_LV); - break; - default: - return 0; - } - - return 0; -} - static int rt5682_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1756,8 +1734,7 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1, RT5682_PWR_HA_R_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5682_DEPOP_1, - RT5682_PUMP_EN_SFT, 0, rt5682_charge_pump_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + RT5682_PUMP_EN_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5682_DEPOP_1, RT5682_CAPLESS_EN_SFT, 0, NULL, 0), @@ -2655,6 +2632,8 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA); regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1, RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ); + regmap_update_bits(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, + RT5682_PM_HP_MASK, RT5682_PM_HP_HV); INIT_DELAYED_WORK(&rt5682->jack_detect_work, rt5682_jack_detect_handler); -- cgit From a3b9ed55775eb18ca9f1641f13328f479a3653cb Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Thu, 14 Nov 2019 23:33:04 +0800 Subject: ASoC: rt5677: rt5677_check_hotword() can be static Fixes: 21c00e5df439 ("ASoC: rt5677: Enable jack detect while DSP is running") Signed-off-by: kbuild test robot Link: https://lore.kernel.org/r/20191114153304.n4pyix7qadu76tx4@4978f4969bb8 Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index f2f763b4c399..e9a051a50ab2 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5307,7 +5307,7 @@ static const struct rt5677_irq_desc rt5677_irq_descs[] = { }, }; -bool rt5677_check_hotword(struct rt5677_priv *rt5677) +static bool rt5677_check_hotword(struct rt5677_priv *rt5677) { int reg_gpio; -- cgit From 51d2584a98942a6b4a0dfa183f4a9afcb8a04073 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 15 Nov 2019 15:57:04 +0530 Subject: ASoC: qcom: q6asm: add support to flac config Qualcomm DSPs expect flac config to be set for flac decoders, so add the API to program the flac config to the DSP Signed-off-by: Srinivas Kandagatla Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20191115102705.649976-3-vkoul@kernel.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6asm.h | 15 ++++++++++++ 2 files changed, 70 insertions(+) (limited to 'sound') diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index e8141a33a55e..36e0eab13a98 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -38,6 +38,7 @@ #define ASM_SESSION_CMD_RUN_V2 0x00010DAA #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5 #define ASM_MEDIA_FMT_MP3 0x00010BE9 +#define ASM_MEDIA_FMT_FLAC 0x00010C16 #define ASM_DATA_CMD_WRITE_V2 0x00010DAB #define ASM_DATA_CMD_READ_V2 0x00010DAC #define ASM_SESSION_CMD_SUSPEND 0x00010DEC @@ -89,6 +90,20 @@ struct asm_multi_channel_pcm_fmt_blk_v2 { u8 channel_mapping[PCM_MAX_NUM_CHANNEL]; } __packed; +struct asm_flac_fmt_blk_v2 { + struct asm_data_cmd_media_fmt_update_v2 fmt_blk; + u16 is_stream_info_present; + u16 num_channels; + u16 min_blk_size; + u16 max_blk_size; + u16 md5_sum[8]; + u32 sample_rate; + u32 min_frame_size; + u32 max_frame_size; + u16 sample_size; + u16 reserved; +} __packed; + struct asm_stream_cmd_set_encdec_param { u32 param_id; u32 param_size; @@ -876,6 +891,9 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format, case FORMAT_LINEAR_PCM: open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; break; + case SND_AUDIOCODEC_FLAC: + open->dec_fmt_id = ASM_MEDIA_FMT_FLAC; + break; default: dev_err(ac->dev, "Invalid format 0x%x\n", format); rc = -EINVAL; @@ -1021,6 +1039,42 @@ err: } EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm); + +int q6asm_stream_media_format_block_flac(struct audio_client *ac, + struct q6asm_flac_cfg *cfg) +{ + struct asm_flac_fmt_blk_v2 *fmt; + struct apr_pkt *pkt; + void *p; + int rc, pkt_size; + + pkt_size = APR_HDR_SIZE + sizeof(*fmt); + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + fmt = p + APR_HDR_SIZE; + + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); + fmt->is_stream_info_present = cfg->stream_info_present; + fmt->num_channels = cfg->ch_cfg; + fmt->min_blk_size = cfg->min_blk_size; + fmt->max_blk_size = cfg->max_blk_size; + fmt->sample_rate = cfg->sample_rate; + fmt->min_frame_size = cfg->min_frame_size; + fmt->max_frame_size = cfg->max_frame_size; + fmt->sample_size = cfg->sample_size; + + rc = q6asm_ac_send_cmd_sync(ac, pkt); + kfree(pkt); + + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac); /** * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture * @@ -1075,6 +1129,7 @@ err: } EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support); + /** * q6asm_read() - read data of period size from audio client * diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h index 9f5fb573e4a0..6764f55f7078 100644 --- a/sound/soc/qcom/qdsp6/q6asm.h +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -32,6 +32,19 @@ enum { #define NO_TIMESTAMP 0xFF00 #define FORMAT_LINEAR_PCM 0x0000 +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; +}; + typedef void (*q6asm_cb) (uint32_t opcode, uint32_t token, void *payload, void *priv); struct audio_client; @@ -54,6 +67,8 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, u8 channel_map[PCM_MAX_NUM_CHANNEL], uint16_t bits_per_sample); +int q6asm_stream_media_format_block_flac(struct audio_client *ac, + struct q6asm_flac_cfg *cfg); int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts); int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, -- cgit From baddcee989931e304eeb90c101751c2f7f9b5045 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 15 Nov 2019 15:57:05 +0530 Subject: ASoC: qcom: q6asm-dai: add support to flac decoder Qualcomm DSPs also support the flac decoder, so add support for FLAC decoder and convert the snd_dec_flac params to qdsp format. Co-developed-by: Srinivas Kandagatla Signed-off-by: Srinivas Kandagatla Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20191115102705.649976-4-vkoul@kernel.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm-dai.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index f59353f510b8..8150c10f081e 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -626,8 +626,14 @@ static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream, struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME); int dir = stream->direction; struct q6asm_dai_data *pdata; + struct q6asm_flac_cfg flac_cfg; struct device *dev = c->dev; int ret; + union snd_codec_options *codec_options; + struct snd_dec_flac *flac; + + codec_options = &(prtd->codec_param.codec.options); + memcpy(&prtd->codec_param, params, sizeof(*params)); @@ -664,6 +670,32 @@ static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream, return ret; } + switch (params->codec.id) { + case SND_AUDIOCODEC_FLAC: + + memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg)); + flac = &codec_options->flac_d; + + flac_cfg.ch_cfg = params->codec.ch_in; + flac_cfg.sample_rate = params->codec.sample_rate; + flac_cfg.stream_info_present = 1; + flac_cfg.sample_size = flac->sample_size; + flac_cfg.min_blk_size = flac->min_blk_size; + flac_cfg.max_blk_size = flac->max_blk_size; + flac_cfg.max_frame_size = flac->max_frame_size; + flac_cfg.min_frame_size = flac->min_frame_size; + + ret = q6asm_stream_media_format_block_flac(prtd->audio_client, + &flac_cfg); + if (ret < 0) { + dev_err(dev, "FLAC CMD Format block failed:%d\n", ret); + return -EIO; + } + break; + default: + break; + } + ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys, (prtd->pcm_size / prtd->periods), prtd->periods); @@ -759,8 +791,9 @@ static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream, caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE; caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS; caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS; - caps->num_codecs = 1; + caps->num_codecs = 2; caps->codecs[0] = SND_AUDIOCODEC_MP3; + caps->codecs[1] = SND_AUDIOCODEC_FLAC; return 0; } -- cgit From 2dab09be49a1e7a4dd13cb47d3a1441a2ef33a87 Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Mon, 18 Nov 2019 15:36:33 +0800 Subject: ASoC: wm2200: add missed operations in remove and probe failure This driver misses calls to pm_runtime_disable and regulator_bulk_disable in remove and a call to free_irq in probe failure. Add the calls to fix it. Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20191118073633.28237-1-hslester96@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index cf64e109c658..7b087d94141b 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2410,6 +2410,8 @@ static int wm2200_i2c_probe(struct i2c_client *i2c, err_pm_runtime: pm_runtime_disable(&i2c->dev); + if (i2c->irq) + free_irq(i2c->irq, wm2200); err_reset: if (wm2200->pdata.reset) gpio_set_value_cansleep(wm2200->pdata.reset, 0); @@ -2426,12 +2428,15 @@ static int wm2200_i2c_remove(struct i2c_client *i2c) { struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c); + pm_runtime_disable(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm2200); if (wm2200->pdata.reset) gpio_set_value_cansleep(wm2200->pdata.reset, 0); if (wm2200->pdata.ldo_ena) gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); + regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); return 0; } -- cgit From b1176bbb70866f24099cd2720283c7219fb4a81c Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Mon, 18 Nov 2019 15:37:07 +0800 Subject: ASoC: wm5100: add missed pm_runtime_disable The driver forgets to call pm_runtime_disable in remove and probe failure. Add the calls to fix it. Signed-off-by: Chuhong Yuan Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20191118073707.28298-1-hslester96@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm5100.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4af0e519e623..91cc63c5a51f 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2617,6 +2617,7 @@ static int wm5100_i2c_probe(struct i2c_client *i2c, return ret; err_reset: + pm_runtime_disable(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm5100); wm5100_free_gpio(i2c); @@ -2640,6 +2641,7 @@ static int wm5100_i2c_remove(struct i2c_client *i2c) { struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); + pm_runtime_disable(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm5100); wm5100_free_gpio(i2c); -- cgit From 79f6c108c87b470aacf25fc25a86f48694d03ae8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Nov 2019 14:47:34 +0200 Subject: ASoC: pcm3168a: Add support for optional RST gpio handling In case the RST line is connected to a GPIO line it needs to be pulled high when the driver probes to be able to use the codec. Add support also for cases when more than one codec is is controlled by the same GPIO line by requesting the gpio with GPIOD_FLAGS_BIT_NONEXCLUSIVE. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191113124734.27984-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 313500ab36df..f3475134b519 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -9,7 +9,9 @@ #include #include +#include #include +#include #include #include @@ -59,6 +61,7 @@ struct pcm3168a_priv { struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES]; struct regmap *regmap; struct clk *scki; + struct gpio_desc *gpio_rst; unsigned long sysclk; struct pcm3168a_io_params io_params[2]; @@ -643,6 +646,7 @@ static bool pcm3168a_readable_register(struct device *dev, unsigned int reg) static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { + case PCM3168A_RST_SMODE: case PCM3168A_DAC_ZERO: case PCM3168A_ADC_OV: return true; @@ -702,6 +706,21 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) dev_set_drvdata(dev, pcm3168a); + /* + * Request the RST gpio line as non exclusive as the same reset line + * might be connected to multiple pcm3168a codec + */ + pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "rst", + GPIOD_OUT_HIGH | + GPIOD_FLAGS_BIT_NONEXCLUSIVE); + if (IS_ERR(pcm3168a->gpio_rst)) { + ret = PTR_ERR(pcm3168a->gpio_rst); + if (ret != -EPROBE_DEFER ) + dev_err(dev, "failed to acquire RST gpio: %d\n", ret); + + return ret; + } + pcm3168a->scki = devm_clk_get(dev, "scki"); if (IS_ERR(pcm3168a->scki)) { ret = PTR_ERR(pcm3168a->scki); @@ -743,10 +762,18 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) goto err_regulator; } - ret = pcm3168a_reset(pcm3168a); - if (ret) { - dev_err(dev, "Failed to reset device: %d\n", ret); - goto err_regulator; + if (pcm3168a->gpio_rst) { + /* + * The device is taken out from reset via GPIO line, wait for + * 3846 SCKI clock cycles for the internal reset de-assertion + */ + msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk)); + } else { + ret = pcm3168a_reset(pcm3168a); + if (ret) { + dev_err(dev, "Failed to reset device: %d\n", ret); + goto err_regulator; + } } pm_runtime_set_active(dev); @@ -785,6 +812,9 @@ static void pcm3168a_disable(struct device *dev) void pcm3168a_remove(struct device *dev) { + struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); + + gpiod_set_value_cansleep(pcm3168a->gpio_rst, 0); pm_runtime_disable(dev); #ifndef CONFIG_PM pcm3168a_disable(dev); -- cgit From 302ee055af0201e61be7670f957c1622d6ce176e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 18 Nov 2019 15:52:47 +0000 Subject: ASoC: SOF: Intel: Fix build break Commit 130d3e9077 (Fix CFL and CML FW nocodec binary names.) broke the build in some configurations as it depends on changes in the development branch, revert it. Reported-by: Stephen Rothwell Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 2ef927371b23..d66412a77873 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -113,7 +113,7 @@ static const struct sof_dev_desc cnl_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) static const struct sof_dev_desc cfl_desc = { - .machines = snd_soc_acpi_intel_cfl_machines, + .machines = snd_soc_acpi_intel_cnl_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -122,7 +122,7 @@ static const struct sof_dev_desc cfl_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-cfl.ri", + .nocodec_fw_filename = "sof-cnl.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -133,7 +133,7 @@ static const struct sof_dev_desc cfl_desc = { IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) static const struct sof_dev_desc cml_desc = { - .machines = snd_soc_acpi_intel_cml_machines, + .machines = snd_soc_acpi_intel_cnl_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -142,7 +142,7 @@ static const struct sof_dev_desc cml_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-cml.ri", + .nocodec_fw_filename = "sof-cnl.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops -- cgit From 653c28afa76b45c570370c3c3a89975c68c5fc8e Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 11 Nov 2019 16:29:00 -0600 Subject: ASoC: SOF: Intel: Fix CFL and CML FW nocodec binary names. The manifest information is different between CNL, CML and CFL platforms hence we need to load different files. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111222901.19892-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 4de90d04a91b..3252dbe277c8 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -119,7 +119,7 @@ static const struct sof_dev_desc cnl_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) static const struct sof_dev_desc cfl_desc = { - .machines = snd_soc_acpi_intel_cnl_machines, + .machines = snd_soc_acpi_intel_cfl_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -128,7 +128,7 @@ static const struct sof_dev_desc cfl_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_fw_filename = "sof-cfl.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -139,7 +139,7 @@ static const struct sof_dev_desc cfl_desc = { IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) static const struct sof_dev_desc cml_desc = { - .machines = snd_soc_acpi_intel_cnl_machines, + .machines = snd_soc_acpi_intel_cml_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -148,7 +148,7 @@ static const struct sof_dev_desc cml_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_fw_filename = "sof-cml.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops -- cgit From e48fdb53bd1fa50796b5a050e6e31fde3891a2c8 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 18 Nov 2019 16:12:06 +0100 Subject: ASoC: tlv320aic31xx: configure output common-mode voltage The tlv320aic31xx devices allow to adjust the output common-mode voltage for best analog performance. The datasheet states that the common mode voltage should be set to be <= AVDD/2. This changes allows to configure the output common-mode voltage via a DT property. If the property is absent the voltage is automatically chosen as the highest voltage below/equal to AVDD/2. Signed-off-by: Lucas Stach Link: https://lore.kernel.org/r/20191118151207.28576-1-l.stach@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 45 ++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tlv320aic31xx.h | 8 +++++++ 2 files changed, 53 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index df627a08def9..f6f19fdc72f5 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -171,6 +171,7 @@ struct aic31xx_priv { int rate_div_line; bool master_dapm_route_applied; int irq; + u8 ocmv; /* output common-mode voltage */ }; struct aic31xx_rate_divs { @@ -1312,6 +1313,11 @@ static int aic31xx_codec_probe(struct snd_soc_component *component) if (ret) return ret; + /* set output common-mode voltage */ + snd_soc_component_update_bits(component, AIC31XX_HPDRIVER, + AIC31XX_HPD_OCMV_MASK, + aic31xx->ocmv << AIC31XX_HPD_OCMV_SHIFT); + return 0; } @@ -1501,6 +1507,43 @@ exit: return IRQ_NONE; } +static void aic31xx_configure_ocmv(struct aic31xx_priv *priv) +{ + struct device *dev = priv->dev; + int dvdd, avdd; + u32 value; + + if (dev->fwnode && + fwnode_property_read_u32(dev->fwnode, "ai31xx-ocmv", &value)) { + /* OCMV setting is forced by DT */ + if (value <= 3) { + priv->ocmv = value; + return; + } + } + + avdd = regulator_get_voltage(priv->supplies[3].consumer); + dvdd = regulator_get_voltage(priv->supplies[5].consumer); + + if (avdd > 3600000 || dvdd > 1950000) { + dev_warn(dev, + "Too high supply voltage(s) AVDD: %d, DVDD: %d\n", + avdd, dvdd); + } else if (avdd == 3600000 && dvdd == 1950000) { + priv->ocmv = AIC31XX_HPD_OCMV_1_8V; + } else if (avdd >= 3300000 && dvdd >= 1800000) { + priv->ocmv = AIC31XX_HPD_OCMV_1_65V; + } else if (avdd >= 3000000 && dvdd >= 1650000) { + priv->ocmv = AIC31XX_HPD_OCMV_1_5V; + } else if (avdd >= 2700000 && dvdd >= 1525000) { + priv->ocmv = AIC31XX_HPD_OCMV_1_35V; + } else { + dev_warn(dev, + "Invalid supply voltage(s) AVDD: %d, DVDD: %d\n", + avdd, dvdd); + } +} + static int aic31xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1570,6 +1613,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; } + aic31xx_configure_ocmv(aic31xx); + if (aic31xx->irq > 0) { regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1, AIC31XX_GPIO1_FUNC_MASK, diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index cb024955c978..83a8c7604cc3 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -232,6 +232,14 @@ struct aic31xx_pdata { #define AIC31XX_HSD_HP 0x01 #define AIC31XX_HSD_HS 0x03 +/* AIC31XX_HPDRIVER */ +#define AIC31XX_HPD_OCMV_MASK GENMASK(4, 3) +#define AIC31XX_HPD_OCMV_SHIFT 3 +#define AIC31XX_HPD_OCMV_1_35V 0x0 +#define AIC31XX_HPD_OCMV_1_5V 0x1 +#define AIC31XX_HPD_OCMV_1_65V 0x2 +#define AIC31XX_HPD_OCMV_1_8V 0x3 + /* AIC31XX_MICBIAS */ #define AIC31XX_MICBIAS_MASK GENMASK(1, 0) #define AIC31XX_MICBIAS_SHIFT 0 -- cgit From eb65ccdb083639f8a9b6919c94d1df570396a9a1 Mon Sep 17 00:00:00 2001 From: Li Xu Date: Fri, 15 Nov 2019 13:54:13 -0600 Subject: ASoC: wm_adsp: Expose mixer control API Expose mixer control API for reading and writing controls from the kernel. This API can be used by ALSA kernel drivers with ADSP support to read and write firmware-defined memory regions. Signed-off-by: Li Xu Signed-off-by: David Rhodes Acked-by: Charles Keepax Link: https://lore.kernel.org/r/1573847653-17094-2-git-send-email-david.rhodes@cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 81 +++++++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/wm_adsp.h | 4 +++ 2 files changed, 84 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 9b8bb7bbe945..2a9b610f6d43 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -599,6 +599,9 @@ struct wm_coeff_ctl_ops { struct wm_coeff_ctl { const char *name; const char *fw_name; + /* Subname is needed to match with firmware */ + const char *subname; + unsigned int subname_len; struct wm_adsp_alg_region alg_region; struct wm_coeff_ctl_ops ops; struct wm_adsp *dsp; @@ -1399,6 +1402,7 @@ static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl) { kfree(ctl->cache); kfree(ctl->name); + kfree(ctl->subname); kfree(ctl); } @@ -1472,6 +1476,15 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, ret = -ENOMEM; goto err_ctl; } + if (subname) { + ctl->subname_len = subname_len; + ctl->subname = kmemdup(subname, + strlen(subname) + 1, GFP_KERNEL); + if (!ctl->subname) { + ret = -ENOMEM; + goto err_ctl_name; + } + } ctl->enabled = 1; ctl->set = 0; ctl->ops.xget = wm_coeff_get; @@ -1485,7 +1498,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, ctl->cache = kzalloc(ctl->len, GFP_KERNEL); if (!ctl->cache) { ret = -ENOMEM; - goto err_ctl_name; + goto err_ctl_subname; } list_add(&ctl->list, &dsp->ctl_list); @@ -1508,6 +1521,8 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, err_ctl_cache: kfree(ctl->cache); +err_ctl_subname: + kfree(ctl->subname); err_ctl_name: kfree(ctl->name); err_ctl: @@ -1995,6 +2010,70 @@ out: return ret; } +/* + * Find wm_coeff_ctl with input name as its subname + * If not found, return NULL + */ +static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp, + const char *name, int type, + unsigned int alg) +{ + struct wm_coeff_ctl *pos, *rslt = NULL; + + list_for_each_entry(pos, &dsp->ctl_list, list) { + if (!pos->subname) + continue; + if (strncmp(pos->subname, name, pos->subname_len) == 0 && + pos->alg_region.alg == alg && + pos->alg_region.type == type) { + rslt = pos; + break; + } + } + + return rslt; +} + +int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, + unsigned int alg, void *buf, size_t len) +{ + struct wm_coeff_ctl *ctl; + struct snd_kcontrol *kcontrol; + int ret; + + ctl = wm_adsp_get_ctl(dsp, name, type, alg); + if (!ctl) + return -EINVAL; + + if (len > ctl->len) + return -EINVAL; + + ret = wm_coeff_write_control(ctl, buf, len); + + kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl->name); + snd_ctl_notify(dsp->component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); + +int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, + unsigned int alg, void *buf, size_t len) +{ + struct wm_coeff_ctl *ctl; + + ctl = wm_adsp_get_ctl(dsp, name, type, alg); + if (!ctl) + return -EINVAL; + + if (len > ctl->len) + return -EINVAL; + + return wm_coeff_read_control(ctl, buf, len); +} +EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); + static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp, const struct wm_adsp_alg_region *alg_region) { diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index aa634ef6c9f5..4c481cf20275 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -201,5 +201,9 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, struct snd_compr_tstamp *tstamp); int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf, size_t count); +int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, + unsigned int alg, void *buf, size_t len); +int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, + unsigned int alg, void *buf, size_t len); #endif -- cgit From 80b917a8dd8f62ca00178d5a74d05d7471f21b47 Mon Sep 17 00:00:00 2001 From: Nikhil Mahale Date: Tue, 19 Nov 2019 14:17:07 +0530 Subject: ALSA: hda - Rename snd_hda_pin_sense to snd_hda_jack_pin_sense s/snd_hda_pin_sense/snd_hda_jack_pin_sense/g This aligns the snd_hda_pin_sense function name with the names of other functions in hda_jack.h. Signed-off-by: Nikhil Mahale Reviewed-by: Aaron Plattner Link: https://lore.kernel.org/r/20191119084710.29267-2-nmahale@nvidia.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_jack.c | 8 ++++---- sound/pci/hda/hda_jack.h | 2 +- sound/pci/hda/patch_hdmi.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 1fb7b06457ae..1ea42447278f 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -191,14 +191,14 @@ void snd_hda_jack_set_dirty_all(struct hda_codec *codec) EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); /** - * snd_hda_pin_sense - execute pin sense measurement + * snd_hda_jack_pin_sense - execute pin sense measurement * @codec: the CODEC to sense * @nid: the pin NID to sense * * Execute necessary pin sense measurement and return its Presence Detect, * Impedance, ELD Valid etc. status bits. */ -u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) +u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid) { struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); if (jack) { @@ -207,7 +207,7 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) } return read_pin_sense(codec, nid); } -EXPORT_SYMBOL_GPL(snd_hda_pin_sense); +EXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); /** * snd_hda_jack_detect_state - query pin Presence Detect status @@ -222,7 +222,7 @@ int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); if (jack && jack->phantom_jack) return HDA_JACK_PHANTOM; - else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) + else if (snd_hda_jack_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) return HDA_JACK_PRESENT; else return HDA_JACK_NOT_PRESENT; diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 22fe7ee43e82..cd9b47f51fab 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -65,7 +65,7 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid); -u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); +u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid); /* the jack state returned from snd_hda_jack_detect_state() */ enum { diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d3768767625e..3b1b978201a9 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1505,7 +1505,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, bool ret; bool do_repoll = false; - present = snd_hda_pin_sense(codec, pin_nid); + present = snd_hda_jack_pin_sense(codec, pin_nid); mutex_lock(&per_pin->lock); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); -- cgit From 5204a05d70d9354e6dd27219275c4b6725443dc4 Mon Sep 17 00:00:00 2001 From: Nikhil Mahale Date: Tue, 19 Nov 2019 14:17:08 +0530 Subject: ALSA: hda - Add DP-MST jack support This patch adds DP-MST jack support which will be used on NVIDIA platforms. Today, DP-MST audio is supported only if the codec has acomp support. This patch makes it possible to add DP-MST support for non-acomp codecs. For the codecs supporting DP-MST audio, each pin can contain several device entries. Each device entry is a virtual pin, described by pin_nid and dev_id in struct hdmi_spec_per_pin. For monitor hotplug event handling, non-acomp codecs enable and register jack-detection for every hdmi_spec_per_pin. This patch updates every relevant function in hda_jack.h and its implementation in hda_jack.c, to consider dev_id along with pin_nid. Changes to the HD Audio specification to support DP-MST audio are described in the Intel Document Change Notification (DCN) number HDA040-A. From HDA040-A, "For the case of multi stream capable Digital Display Pin Widget, [the Get Pin Sense verb] can be used to read a specific Device Entry state as reported in Get Device List Entry verb." This patch updates the read_pin_sense() function to take the dev_id as an argument and pass it as a parameter to the Get Pin Sense verb. Bits 15 through 20 from the Unsolicited Response for intrinsic events contain the index of the Device Entry that generated the event. This patch updates the Unsolicited Response event handlers to extract the device entry index from the response and pass it to snd_hda_jack_tbl_get_from_tag(). This patch updates snd_hda_jack_tbl_new() to take a dev_id argument and store it in the jack structure, and to make sure not to generate a different tag when called more than once for the same nid. Signed-off-by: Nikhil Mahale Link: https://lore.kernel.org/r/20191119084710.29267-3-nmahale@nvidia.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_jack.c | 147 ++++++++++++++++++++++++++++++++------------- sound/pci/hda/hda_jack.h | 107 +++++++++++++++++++++++++++++---- sound/pci/hda/patch_hdmi.c | 70 ++++++++++++--------- 3 files changed, 244 insertions(+), 80 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 1ea42447278f..bf0255cb0515 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -43,7 +43,7 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) EXPORT_SYMBOL_GPL(is_jack_detectable); /* execute pin sense measurement */ -static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) +static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) { u32 pincap; u32 val; @@ -55,19 +55,20 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) AC_VERB_SET_PIN_SENSE, 0); } val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); + AC_VERB_GET_PIN_SENSE, dev_id); if (codec->inv_jack_detect) val ^= AC_PINSENSE_PRESENCE; return val; } /** - * snd_hda_jack_tbl_get - query the jack-table entry for the given NID + * snd_hda_jack_tbl_get_mst - query the jack-table entry for the given NID * @codec: the HDA codec * @nid: pin NID to refer to + * @dev_id: pin device entry id */ struct hda_jack_tbl * -snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) +snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id) { struct hda_jack_tbl *jack = codec->jacktbl.list; int i; @@ -75,19 +76,21 @@ snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) if (!nid || !jack) return NULL; for (i = 0; i < codec->jacktbl.used; i++, jack++) - if (jack->nid == nid) + if (jack->nid == nid && jack->dev_id == dev_id) return jack; return NULL; } -EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get); +EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_mst); /** * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag * @codec: the HDA codec * @tag: tag value to refer to + * @dev_id: pin device entry id */ struct hda_jack_tbl * -snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag) +snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, + unsigned char tag, int dev_id) { struct hda_jack_tbl *jack = codec->jacktbl.list; int i; @@ -95,29 +98,62 @@ snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag) if (!tag || !jack) return NULL; for (i = 0; i < codec->jacktbl.used; i++, jack++) - if (jack->tag == tag) + if (jack->tag == tag && jack->dev_id == dev_id) return jack; return NULL; } EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); +static struct hda_jack_tbl * +any_jack_tbl_get_from_nid(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i; + + if (!nid || !jack) + return NULL; + for (i = 0; i < codec->jacktbl.used; i++, jack++) + if (jack->nid == nid) + return jack; + return NULL; +} + /** * snd_hda_jack_tbl_new - create a jack-table entry for the given NID * @codec: the HDA codec * @nid: pin NID to assign */ static struct hda_jack_tbl * -snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) +snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid, int dev_id) { - struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + struct hda_jack_tbl *jack = + snd_hda_jack_tbl_get_mst(codec, nid, dev_id); + struct hda_jack_tbl *existing_nid_jack = + any_jack_tbl_get_from_nid(codec, nid); + + WARN_ON(dev_id != 0 && !codec->dp_mst); + if (jack) return jack; jack = snd_array_new(&codec->jacktbl); if (!jack) return NULL; jack->nid = nid; + jack->dev_id = dev_id; jack->jack_dirty = 1; - jack->tag = codec->jacktbl.used; + if (existing_nid_jack) { + jack->tag = existing_nid_jack->tag; + + /* + * Copy jack_detect from existing_nid_jack to avoid + * snd_hda_jack_detect_enable_callback_mst() making multiple + * SET_UNSOLICITED_ENABLE calls on the same pin. + */ + jack->jack_detect = existing_nid_jack->jack_detect; + } else { + jack->tag = codec->jacktbl.used; + } + return jack; } @@ -153,10 +189,12 @@ static void jack_detect_update(struct hda_codec *codec, if (jack->phantom_jack) jack->pin_sense = AC_PINSENSE_PRESENCE; else - jack->pin_sense = read_pin_sense(codec, jack->nid); + jack->pin_sense = read_pin_sense(codec, jack->nid, + jack->dev_id); /* A gating jack indicates the jack is invalid if gating is unplugged */ - if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack)) + if (jack->gating_jack && + !snd_hda_jack_detect_mst(codec, jack->gating_jack, jack->dev_id)) jack->pin_sense &= ~AC_PINSENSE_PRESENCE; jack->jack_dirty = 0; @@ -164,7 +202,8 @@ static void jack_detect_update(struct hda_codec *codec, /* If a jack is gated by this one update it. */ if (jack->gated_jack) { struct hda_jack_tbl *gated = - snd_hda_jack_tbl_get(codec, jack->gated_jack); + snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, + jack->dev_id); if (gated) { gated->jack_dirty = 1; jack_detect_update(codec, gated); @@ -198,56 +237,62 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); * Execute necessary pin sense measurement and return its Presence Detect, * Impedance, ELD Valid etc. status bits. */ -u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid) +u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) { - struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + struct hda_jack_tbl *jack = + snd_hda_jack_tbl_get_mst(codec, nid, dev_id); if (jack) { jack_detect_update(codec, jack); return jack->pin_sense; } - return read_pin_sense(codec, nid); + return read_pin_sense(codec, nid, dev_id); } EXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); /** - * snd_hda_jack_detect_state - query pin Presence Detect status + * snd_hda_jack_detect_state_mst - query pin Presence Detect status * @codec: the CODEC to sense * @nid: the pin NID to sense + * @dev_id: pin device entry id * * Query and return the pin's Presence Detect status, as either * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. */ -int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) +int snd_hda_jack_detect_state_mst(struct hda_codec *codec, + hda_nid_t nid, int dev_id) { - struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + struct hda_jack_tbl *jack = + snd_hda_jack_tbl_get_mst(codec, nid, dev_id); if (jack && jack->phantom_jack) return HDA_JACK_PHANTOM; - else if (snd_hda_jack_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) + else if (snd_hda_jack_pin_sense(codec, nid, dev_id) & + AC_PINSENSE_PRESENCE) return HDA_JACK_PRESENT; else return HDA_JACK_NOT_PRESENT; } -EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state); +EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); /** - * snd_hda_jack_detect_enable - enable the jack-detection + * snd_hda_jack_detect_enable_mst - enable the jack-detection * @codec: the HDA codec * @nid: pin NID to enable * @func: callback function to register + * @dev_id: pin device entry id * * In the case of error, the return value will be a pointer embedded with * errno. Check and handle the return value appropriately with standard * macros such as @IS_ERR() and @PTR_ERR(). */ struct hda_jack_callback * -snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - hda_jack_callback_fn func) +snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id, hda_jack_callback_fn func) { struct hda_jack_tbl *jack; struct hda_jack_callback *callback = NULL; int err; - jack = snd_hda_jack_tbl_new(codec, nid); + jack = snd_hda_jack_tbl_new(codec, nid, dev_id); if (!jack) return ERR_PTR(-ENOMEM); if (func) { @@ -256,6 +301,7 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, return ERR_PTR(-ENOMEM); callback->func = func; callback->nid = jack->nid; + callback->dev_id = jack->dev_id; callback->next = jack->callback; jack->callback = callback; } @@ -272,19 +318,24 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, return ERR_PTR(err); return callback; } -EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback); +EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst); /** * snd_hda_jack_detect_enable - Enable the jack detection on the given pin * @codec: the HDA codec * @nid: pin NID to enable jack detection + * @dev_id: pin device entry id * * Enable the jack detection with the default callback. Returns zero if * successful or a negative error code. */ -int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid) +int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, + int dev_id) { - return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback(codec, nid, NULL)); + return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback_mst(codec, + nid, + dev_id, + NULL)); } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); @@ -299,8 +350,11 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid) { - struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid); - struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid); + struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0); + struct hda_jack_tbl *gating = + snd_hda_jack_tbl_new(codec, gating_nid, 0); + + WARN_ON(codec->dp_mst); if (!gated || !gating) return -EINVAL; @@ -376,9 +430,10 @@ static void hda_free_jack_priv(struct snd_jack *jack) } /** - * snd_hda_jack_add_kctl - Add a kctl for the given pin + * snd_hda_jack_add_kctl_mst - Add a kctl for the given pin * @codec: the HDA codec * @nid: pin NID to assign + * @dev_id : pin device entry id * @name: string name for the jack * @phantom_jack: flag to deal as a phantom jack * @type: jack type bits to be reported, 0 for guessing from pincfg @@ -387,15 +442,15 @@ static void hda_free_jack_priv(struct snd_jack *jack) * This assigns a jack-detection kctl to the given pin. The kcontrol * will have the given name and index. */ -int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, bool phantom_jack, - int type, const struct hda_jack_keymap *keymap) +int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id, const char *name, bool phantom_jack, + int type, const struct hda_jack_keymap *keymap) { struct hda_jack_tbl *jack; const struct hda_jack_keymap *map; int err, state, buttons; - jack = snd_hda_jack_tbl_new(codec, nid); + jack = snd_hda_jack_tbl_new(codec, nid, dev_id); if (!jack) return 0; if (jack->jack) @@ -425,12 +480,12 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, snd_jack_set_key(jack->jack, map->type, map->key); } - state = snd_hda_jack_detect(codec, nid); + state = snd_hda_jack_detect_mst(codec, nid, dev_id); snd_jack_report(jack->jack, state ? jack->type : 0); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl); +EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst); static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, const struct auto_pin_cfg *cfg, @@ -441,6 +496,8 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, int err; bool phantom_jack; + WARN_ON(codec->dp_mst); + if (!nid) return 0; def_conf = snd_hda_codec_get_pincfg(codec, nid); @@ -462,7 +519,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, return err; if (!phantom_jack) - return snd_hda_jack_detect_enable(codec, nid); + return snd_hda_jack_detect_enable(codec, nid, 0); return 0; } @@ -540,7 +597,8 @@ static void call_jack_callback(struct hda_codec *codec, unsigned int res, } if (jack->gated_jack) { struct hda_jack_tbl *gated = - snd_hda_jack_tbl_get(codec, jack->gated_jack); + snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, + jack->dev_id); if (gated) { for (cb = gated->callback; cb; cb = cb->next) { cb->jack = gated; @@ -561,7 +619,14 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) struct hda_jack_tbl *event; int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; - event = snd_hda_jack_tbl_get_from_tag(codec, tag); + if (codec->dp_mst) { + int dev_entry = + (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; + + event = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); + } else { + event = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); + } if (!event) return; event->jack_dirty = 1; diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index cd9b47f51fab..727b6d3ba454 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -19,6 +19,7 @@ typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callba struct hda_jack_callback { hda_nid_t nid; + int dev_id; hda_jack_callback_fn func; unsigned int private_data; /* arbitrary data */ unsigned int unsol_res; /* unsolicited event bits */ @@ -28,6 +29,7 @@ struct hda_jack_callback { struct hda_jack_tbl { hda_nid_t nid; + int dev_id; unsigned char tag; /* unsol event tag */ struct hda_jack_callback *callback; /* jack-detection stuff */ @@ -49,46 +51,129 @@ struct hda_jack_keymap { }; struct hda_jack_tbl * -snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid); +snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id); + +/** + * snd_hda_jack_tbl_get - query the jack-table entry for the given NID + * @codec: the HDA codec + * @nid: pin NID to refer to + */ +static inline struct hda_jack_tbl * +snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_jack_tbl_get_mst(codec, nid, 0); +} + struct hda_jack_tbl * -snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag); +snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, + unsigned char tag, int dev_id); void snd_hda_jack_tbl_clear(struct hda_codec *codec); void snd_hda_jack_set_dirty_all(struct hda_codec *codec); -int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid); +int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, + int dev_id); + struct hda_jack_callback * +snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id, hda_jack_callback_fn cb); + +/** + * snd_hda_jack_detect_enable - enable the jack-detection + * @codec: the HDA codec + * @nid: pin NID to enable + * @func: callback function to register + * + * In the case of error, the return value will be a pointer embedded with + * errno. Check and handle the return value appropriately with standard + * macros such as @IS_ERR() and @PTR_ERR(). + */ +static inline struct hda_jack_callback * snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - hda_jack_callback_fn cb); + hda_jack_callback_fn cb) +{ + return snd_hda_jack_detect_enable_callback_mst(codec, nid, 0, cb); +} int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid); -u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid); +u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id); /* the jack state returned from snd_hda_jack_detect_state() */ enum { HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM, }; -int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid); +int snd_hda_jack_detect_state_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id); + +/** + * snd_hda_jack_detect_state - query pin Presence Detect status + * @codec: the CODEC to sense + * @nid: the pin NID to sense + * + * Query and return the pin's Presence Detect status, as either + * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. + */ +static inline int +snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_jack_detect_state_mst(codec, nid, 0); +} + +/** + * snd_hda_jack_detect_mst - Detect the jack + * @codec: the HDA codec + * @nid: pin NID to check jack detection + * @dev_id: pin device entry id + */ +static inline bool +snd_hda_jack_detect_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id) +{ + return snd_hda_jack_detect_state_mst(codec, nid, dev_id) != + HDA_JACK_NOT_PRESENT; +} /** * snd_hda_jack_detect - Detect the jack * @codec: the HDA codec * @nid: pin NID to check jack detection */ -static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) +static inline bool +snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) { - return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT; + return snd_hda_jack_detect_mst(codec, nid, 0); } bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); -int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, bool phantom_jack, - int type, const struct hda_jack_keymap *keymap); +int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id, const char *name, bool phantom_jack, + int type, const struct hda_jack_keymap *keymap); + +/** + * snd_hda_jack_add_kctl - Add a kctl for the given pin + * @codec: the HDA codec + * @nid: pin NID to assign + * @name: string name for the jack + * @phantom_jack: flag to deal as a phantom jack + * @type: jack type bits to be reported, 0 for guessing from pincfg + * @keymap: optional jack / key mapping + * + * This assigns a jack-detection kctl to the given pin. The kcontrol + * will have the given name and index. + */ +static inline int +snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, + const char *name, bool phantom_jack, + int type, const struct hda_jack_keymap *keymap) +{ + return snd_hda_jack_add_kctl_mst(codec, nid, 0, + name, phantom_jack, type, keymap); +} + int snd_hda_jack_add_kctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 3b1b978201a9..37b4345afdde 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -758,34 +758,32 @@ static void jack_callback(struct hda_codec *codec, if (codec_has_acomp(codec)) return; - /* hda_jack don't support DP MST */ - check_presence_and_report(codec, jack->nid, 0); + check_presence_and_report(codec, jack->nid, jack->dev_id); } static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) { int tag = res >> AC_UNSOL_RES_TAG_SHIFT; struct hda_jack_tbl *jack; - int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; - /* - * assume DP MST uses dyn_pcm_assign and acomp and - * never comes here - * if DP MST supports unsol event, below code need - * consider dev_entry - */ - jack = snd_hda_jack_tbl_get_from_tag(codec, tag); + if (codec->dp_mst) { + int dev_entry = + (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; + + jack = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); + } else { + jack = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); + } if (!jack) return; jack->jack_dirty = 1; codec_dbg(codec, "HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA), + codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA), !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); - /* hda_jack don't support DP MST */ - check_presence_and_report(codec, jack->nid, 0); + check_presence_and_report(codec, jack->nid, jack->dev_id); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -815,11 +813,21 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) { int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; + struct hda_jack_tbl *jack; if (codec_has_acomp(codec)) return; - if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) { + if (codec->dp_mst) { + int dev_entry = + (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; + + jack = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); + } else { + jack = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); + } + + if (!jack) { codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag); return; } @@ -1505,7 +1513,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, bool ret; bool do_repoll = false; - present = snd_hda_jack_pin_sense(codec, pin_nid); + present = snd_hda_jack_pin_sense(codec, pin_nid, per_pin->dev_id); mutex_lock(&per_pin->lock); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); @@ -1538,7 +1546,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, ret = !repoll || !eld->monitor_present || eld->eld_valid; - jack = snd_hda_jack_tbl_get(codec, pin_nid); + jack = snd_hda_jack_tbl_get_mst(codec, pin_nid, per_pin->dev_id); if (jack) { jack->block_report = !ret; jack->pin_sense = (eld->monitor_present && eld->eld_valid) ? @@ -1569,7 +1577,8 @@ static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec, * DP MST will use dyn_pcm_assign, * so DP MST will never come here */ - jack_tbl = snd_hda_jack_tbl_get(codec, per_pin->pin_nid); + jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid, + per_pin->dev_id); if (jack_tbl) jack = jack_tbl->jack; } @@ -1650,7 +1659,8 @@ static void hdmi_repoll_eld(struct work_struct *work) struct hdmi_spec *spec = codec->spec; struct hda_jack_tbl *jack; - jack = snd_hda_jack_tbl_get(codec, per_pin->pin_nid); + jack = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid, + per_pin->dev_id); if (jack) jack->jack_dirty = 1; @@ -2151,11 +2161,13 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx) if (phantom_jack) strncat(hdmi_str, " Phantom", sizeof(hdmi_str) - strlen(hdmi_str) - 1); - ret = snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, - phantom_jack, 0, NULL); + ret = snd_hda_jack_add_kctl_mst(codec, per_pin->pin_nid, + per_pin->dev_id, hdmi_str, phantom_jack, + 0, NULL); if (ret < 0) return ret; - jack = snd_hda_jack_tbl_get(codec, per_pin->pin_nid); + jack = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid, + per_pin->dev_id); if (jack == NULL) return 0; /* assign jack->jack to pcm_rec[].jack to @@ -2264,10 +2276,11 @@ static int generic_hdmi_init(struct hda_codec *codec) if (codec_has_acomp(codec)) continue; if (spec->use_jack_detect) - snd_hda_jack_detect_enable(codec, pin_nid); + snd_hda_jack_detect_enable(codec, pin_nid, dev_id); else - snd_hda_jack_detect_enable_callback(codec, pin_nid, - jack_callback); + snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, + dev_id, + jack_callback); } mutex_unlock(&spec->bind_lock); return 0; @@ -2417,11 +2430,11 @@ static int patch_generic_hdmi(struct hda_codec *codec) /* turn on / off the unsol event jack detection dynamically */ static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid, - bool use_acomp) + int dev_id, bool use_acomp) { struct hda_jack_tbl *tbl; - tbl = snd_hda_jack_tbl_get(codec, nid); + tbl = snd_hda_jack_tbl_get_mst(codec, nid, dev_id); if (tbl) { /* clear unsol even if component notifier is used, or re-enable * if notifier is cleared @@ -2434,7 +2447,7 @@ static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid, * at need (i.e. only when notifier is cleared) */ if (!use_acomp) - snd_hda_jack_detect_enable(codec, nid); + snd_hda_jack_detect_enable(codec, nid, dev_id); } } @@ -2454,6 +2467,7 @@ static void generic_acomp_notifier_set(struct drm_audio_component *acomp, for (i = 0; i < spec->num_pins; i++) reprogram_jack_detect(spec->codec, get_pin(spec, i)->pin_nid, + get_pin(spec, i)->dev_id, use_acomp); } mutex_unlock(&spec->bind_lock); @@ -2959,7 +2973,7 @@ static int simple_playback_init(struct hda_codec *codec) if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - snd_hda_jack_detect_enable(codec, pin); + snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id); return 0; } -- cgit From 9c32fea836928d7a25a83b337f268e533cfc5c3d Mon Sep 17 00:00:00 2001 From: Nikhil Mahale Date: Tue, 19 Nov 2019 14:17:09 +0530 Subject: ALSA: hda - Add DP-MST support for non-acomp codecs This patch make it possible for non-acomp codecs to set dyn_pcm_assign/dp_mst and get DP-MST audio support. Document change notification HDA040-A for the Intel High Definition Audio 1.0a specification introduces a Device Select verb for Digital Display Pin Widgets that are multi-stream capable. This verb selects a Device Entry that is used by subsequent Pin Widget verbs. Once the Device Entry is selected, all subsequent Pin Widget verbs controlling the sink device will be directed to the selected Device Entry until the Device Select verb is updated with a new value. These Pin Widget verbs include: * Connection Select * Get Connection List Entry * Amplifier Gain/Mute * Power State * Pin Widget Control * ELD Data * DIP-Size * DIP-Index * DIP-Data * DIP-XmitCtrl * Content Protection Control * ASP Channel Mapping This patch adds calls to snd_hda_set_dev_select() to direct each of these Pin Widget control verbs to the correct Device Entry. snd_hda_get_connections() does not return per-device connection list, therefore make use snd_hda_get_raw_connections() instead of snd_hda_get_connections(). Signed-off-by: Nikhil Mahale Reviewed-by: Aaron Plattner Link: https://lore.kernel.org/r/20191119084710.29267-4-nmahale@nvidia.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 100 ++++++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 37b4345afdde..0a3045d49297 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -80,16 +80,19 @@ struct hdmi_spec_per_pin { /* operations used by generic code that can be overridden by patches */ struct hdmi_ops { int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid, - unsigned char *buf, int *eld_size); + int dev_id, unsigned char *buf, int *eld_size); void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid, + int dev_id, int ca, int active_channels, int conn_type); /* enable/disable HBR (HD passthrough) */ - int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, bool hbr); + int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, + int dev_id, bool hbr); int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format); + hda_nid_t pin_nid, int dev_id, u32 stream_tag, + int format); void (*pin_cvt_fixup)(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, @@ -636,8 +639,16 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, return true; } +static int hdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid, + int dev_id, unsigned char *buf, int *eld_size) +{ + snd_hda_set_dev_select(codec, nid, dev_id); + + return snd_hdmi_get_eld(codec, nid, buf, eld_size); +} + static void hdmi_pin_setup_infoframe(struct hda_codec *codec, - hda_nid_t pin_nid, + hda_nid_t pin_nid, int dev_id, int ca, int active_channels, int conn_type) { @@ -667,6 +678,8 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, return; } + snd_hda_set_dev_select(codec, pin_nid, dev_id); + /* * sizeof(ai) is used instead of sizeof(*hdmi_ai) or * sizeof(*dp_ai) to avoid partial match/update problems when @@ -692,6 +705,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, struct hdmi_spec *spec = codec->spec; struct hdac_chmap *chmap = &spec->chmap; hda_nid_t pin_nid = per_pin->pin_nid; + int dev_id = per_pin->dev_id; int channels = per_pin->channels; int active_channels; struct hdmi_eld *eld; @@ -700,6 +714,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, if (!channels) return; + snd_hda_set_dev_select(codec, pin_nid, dev_id); + /* some HW (e.g. HSW+) needs reprogramming the amp at each time */ if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin_nid, 0, @@ -725,8 +741,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, pin_nid, non_pcm, ca, channels, per_pin->chmap, per_pin->chmap_set); - spec->ops.pin_setup_infoframe(codec, pin_nid, ca, active_channels, - eld->info.conn_type); + spec->ops.pin_setup_infoframe(codec, pin_nid, dev_id, + ca, active_channels, eld->info.conn_type); per_pin->non_pcm = non_pcm; } @@ -868,11 +884,12 @@ static void haswell_verify_D0(struct hda_codec *codec, ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7) static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, - bool hbr) + int dev_id, bool hbr) { int pinctl, new_pinctl; if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) { + snd_hda_set_dev_select(codec, pin_nid, dev_id); pinctl = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); @@ -902,13 +919,15 @@ static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, } static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format) + hda_nid_t pin_nid, int dev_id, + u32 stream_tag, int format) { struct hdmi_spec *spec = codec->spec; unsigned int param; int err; - err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format)); + err = spec->ops.pin_hbr_setup(codec, pin_nid, dev_id, + is_hbr_format(format)); if (err) { codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n"); @@ -1282,6 +1301,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; + int dev_id = per_pin->dev_id; if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { codec_warn(codec, @@ -1290,10 +1310,12 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) return -EINVAL; } + snd_hda_set_dev_select(codec, pin_nid, dev_id); + /* all the device entries on the same pin have the same conn list */ - per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid, - per_pin->mux_nids, - HDA_MAX_CONNECTIONS); + per_pin->num_mux_nids = + snd_hda_get_raw_connections(codec, pin_nid, per_pin->mux_nids, + HDA_MAX_CONNECTIONS); return 0; } @@ -1501,6 +1523,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->temp_eld; hda_nid_t pin_nid = per_pin->pin_nid; + int dev_id = per_pin->dev_id; /* * Always execute a GetPinSense verb here, even when called from * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited @@ -1513,7 +1536,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, bool ret; bool do_repoll = false; - present = snd_hda_jack_pin_sense(codec, pin_nid, per_pin->dev_id); + present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id); mutex_lock(&per_pin->lock); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); @@ -1527,8 +1550,8 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); if (eld->eld_valid) { - if (spec->ops.pin_get_eld(codec, pin_nid, eld->eld_buffer, - &eld->eld_size) < 0) + if (spec->ops.pin_get_eld(codec, pin_nid, dev_id, + eld->eld_buffer, &eld->eld_size) < 0) eld->eld_valid = false; else { if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, @@ -1865,7 +1888,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hdmi_spec *spec = codec->spec; int pin_idx; struct hdmi_spec_per_pin *per_pin; - hda_nid_t pin_nid; struct snd_pcm_runtime *runtime = substream->runtime; bool non_pcm; int pinctl, stripe; @@ -1889,7 +1911,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, goto unlock; } per_pin = get_pin(spec, pin_idx); - pin_nid = per_pin->pin_nid; /* Verify pin:cvt selections to avoid silent audio after S3. * After S3, the audio driver restores pin:cvt selections @@ -1904,8 +1925,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, /* Call sync_audio_rate to set the N/CTS/M manually if necessary */ /* Todo: add DP1.2 MST audio support later */ if (codec_has_acomp(codec)) - snd_hdac_sync_audio_rate(&codec->core, pin_nid, per_pin->dev_id, - runtime->rate); + snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid, + per_pin->dev_id, runtime->rate); non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); mutex_lock(&per_pin->lock); @@ -1923,16 +1944,18 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); mutex_unlock(&per_pin->lock); if (spec->dyn_pin_out) { - pinctl = snd_hda_codec_read(codec, pin_nid, 0, + snd_hda_set_dev_select(codec, per_pin->pin_nid, + per_pin->dev_id); + pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, pin_nid, 0, + snd_hda_codec_write(codec, per_pin->pin_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl | PIN_OUT); } /* snd_hda_set_dev_select() has been called before */ - err = spec->ops.setup_stream(codec, cvt_nid, pin_nid, - stream_tag, format); + err = spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid, + per_pin->dev_id, stream_tag, format); unlock: mutex_unlock(&spec->pcm_lock); return err; @@ -1984,6 +2007,8 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, per_pin = get_pin(spec, pin_idx); if (spec->dyn_pin_out) { + snd_hda_set_dev_select(codec, per_pin->pin_nid, + per_pin->dev_id); pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); snd_hda_codec_write(codec, per_pin->pin_nid, 0, @@ -2370,7 +2395,7 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { }; static const struct hdmi_ops generic_standard_hdmi_ops = { - .pin_get_eld = snd_hdmi_get_eld, + .pin_get_eld = hdmi_pin_get_eld, .pin_setup_infoframe = hdmi_pin_setup_infoframe, .pin_hbr_setup = hdmi_pin_hbr_setup, .setup_stream = hdmi_setup_stream, @@ -2568,7 +2593,8 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec, hda_nid_t conns[4]; int nconns; - nconns = snd_hda_get_connections(codec, nid, conns, ARRAY_SIZE(conns)); + nconns = snd_hda_get_raw_connections(codec, nid, conns, + ARRAY_SIZE(conns)); if (nconns == spec->num_cvts && !memcmp(conns, spec->cvt_nids, spec->num_cvts * sizeof(hda_nid_t))) return; @@ -2744,10 +2770,12 @@ static void register_i915_notifier(struct hda_codec *codec) /* setup_stream ops override for HSW+ */ static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format) + hda_nid_t pin_nid, int dev_id, u32 stream_tag, + int format) { haswell_verify_D0(codec, cvt_nid, pin_nid); - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); + return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, + stream_tag, format); } /* pin_cvt_fixup ops override for HSW+ and VLV+ */ @@ -3713,16 +3741,19 @@ static int patch_tegra_hdmi(struct hda_codec *codec) #define ATI_HBR_ENABLE 0x10 static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size) + int dev_id, unsigned char *buf, int *eld_size) { + WARN_ON(dev_id != 0); /* call hda_eld.c ATI/AMD-specific function */ return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size, is_amdhdmi_rev3_or_later(codec)); } -static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, hda_nid_t pin_nid, int ca, +static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, + hda_nid_t pin_nid, int dev_id, int ca, int active_channels, int conn_type) { + WARN_ON(dev_id != 0); snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca); } @@ -3913,10 +3944,12 @@ static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, } static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, - bool hbr) + int dev_id, bool hbr) { int hbr_ctl, hbr_ctl_new; + WARN_ON(dev_id != 0); + hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0); if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) { if (hbr) @@ -3942,9 +3975,9 @@ static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, } static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format) + hda_nid_t pin_nid, int dev_id, + u32 stream_tag, int format) { - if (is_amdhdmi_rev3_or_later(codec)) { int ramp_rate = 180; /* default as per AMD spec */ /* disable ramp-up/down for non-pcm as per AMD spec */ @@ -3954,7 +3987,8 @@ static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate); } - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); + return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, + stream_tag, format); } -- cgit From 5398e94fb753d022301825ebfa5f7cf8a660d8eb Mon Sep 17 00:00:00 2001 From: Nikhil Mahale Date: Tue, 19 Nov 2019 14:17:10 +0530 Subject: ALSA: hda - Add DP-MST support for NVIDIA codecs This patch adds DP-MST support for GK104+ NVIDIA codecs. GK104+ NVIDIA codecs support DP-MST audio. These codecs have 4 output converters and 4 pin widgets, with 4 device entries per pin widget for a total of 16 device entries. This patch moves the existing patch_nvhdmi() definition to patch_nvhdmi_legacy(), used by pre-GK104 NVIDIA codecs. Redefine patch_nvhdmi() to enable DP-MST support by setting codec->dp_mst and spec->dyn_pcm_assign. Introduce fresh logic for dynamic pcm assignment, making sure that new pcm assignments are compatible with the legacy static per_pin-pmc assignment that existed in the days before DP-MST. Signed-off-by: Nikhil Mahale Reviewed-by: Aaron Plattner Link: https://lore.kernel.org/r/20191119084710.29267-5-nmahale@nvidia.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 95 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 0a3045d49297..55d20e40a195 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1321,15 +1321,32 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) } static int hdmi_find_pcm_slot(struct hdmi_spec *spec, - struct hdmi_spec_per_pin *per_pin) + struct hdmi_spec_per_pin *per_pin) { int i; - /* try the prefer PCM */ - if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap)) + /* + * generic_hdmi_build_pcms() allocates (num_nids + dev_num - 1) + * number of pcms. + * + * The per_pin of pin_nid_idx=n and dev_id=m prefers to get pcm-n + * if m==0. This guarantees that dynamic pcm assignments are compatible + * with the legacy static per_pin-pmc assignment that existed in the + * days before DP-MST. + * + * per_pin of m!=0 prefers to get pcm=(num_nids + (m - 1)). + */ + if (per_pin->dev_id == 0 && + !test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap)) return per_pin->pin_nid_idx; - /* have a second try; check the "reserved area" over num_pins */ + if (per_pin->dev_id != 0 && + !(test_bit(spec->num_nids + (per_pin->dev_id - 1), + &spec->pcm_bitmap))) { + return spec->num_nids + (per_pin->dev_id - 1); + } + + /* have a second try; check the area over num_nids */ for (i = spec->num_nids; i < spec->pcm_used; i++) { if (!test_bit(i, &spec->pcm_bitmap)) return i; @@ -3510,6 +3527,40 @@ static int patch_nvhdmi(struct hda_codec *codec) struct hdmi_spec *spec; int err; + err = alloc_generic_hdmi(codec); + if (err < 0) + return err; + codec->dp_mst = true; + + spec = codec->spec; + spec->dyn_pcm_assign = true; + + err = hdmi_parse_codec(codec); + if (err < 0) { + generic_spec_free(codec); + return err; + } + + generic_hdmi_init_per_pins(codec); + + spec->dyn_pin_out = true; + + spec->chmap.ops.chmap_cea_alloc_validate_get_type = + nvhdmi_chmap_cea_alloc_validate_get_type; + spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + + codec->link_down_at_suspend = 1; + + generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin); + + return 0; +} + +static int patch_nvhdmi_legacy(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + err = patch_generic_hdmi(codec); if (err) return err; @@ -4118,25 +4169,25 @@ HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI", patch_nvhdmi_8ch_7x), HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi_legacy), /* 17 is known to be absent */ -HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi_legacy), HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi), -- cgit From 0bb887709eb16bdc4b5baddd8337abf3de72917f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 19 Nov 2019 15:51:38 +0100 Subject: ASoC: Intel: bytcr_rt5640: Update quirk for Acer Switch 10 SW5-012 2-in-1 When the Acer Switch 10 SW5-012 quirk was added we did not have jack-detection support yet; and the builtin microphone selection of the original quirk is wrong too. Fix the microphone-input quirk and add jack-detection info so that the internal-microphone and headphone/set jack on the Switch 10 work properly. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191119145138.59162-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 9c1aa4ec9cba..dd2b5ad08659 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -405,10 +405,12 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), }, - .driver_data = (void *)(BYT_RT5640_IN1_MAP | - BYT_RT5640_MCLK_EN | - BYT_RT5640_SSP0_AIF1), - + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), }, { .matches = { -- cgit From b2b2afbb48eac7215f951a8a462aa6837e0d495f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 18 Nov 2019 10:50:32 +0900 Subject: ASoC: soc-component: tidyup snd_soc_pcm_component_new/free() parameter This patch uses rtd instead of pcm at snd_soc_pcm_component_new/free() parameter. This is prepare for dai_link remove bug fix on topology. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pnhqx89j.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-component.c | 8 +++----- sound/soc/soc-pcm.c | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 98ef0666add2..1590e805d016 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -498,9 +498,8 @@ int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, return -EINVAL; } -int snd_soc_pcm_component_new(struct snd_pcm *pcm) +int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_pcm_runtime *rtd = pcm->private_data; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; int ret; @@ -516,13 +515,12 @@ int snd_soc_pcm_component_new(struct snd_pcm *pcm) return 0; } -void snd_soc_pcm_component_free(struct snd_pcm *pcm) +void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_pcm_runtime *rtd = pcm->private_data; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; for_each_rtd_components(rtd, rtdcom, component) if (component->driver->pcm_destruct) - component->driver->pcm_destruct(component, pcm); + component->driver->pcm_destruct(component, rtd->pcm); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4bf71e3211d8..c624d30bfa3c 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2898,7 +2898,7 @@ static void soc_pcm_private_free(struct snd_pcm *pcm) /* need to sync the delayed work before releasing resources */ flush_delayed_work(&rtd->delayed_work); - snd_soc_pcm_component_free(pcm); + snd_soc_pcm_component_free(rtd); } /* create a new pcm */ @@ -3036,7 +3036,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); - ret = snd_soc_pcm_component_new(pcm); + ret = snd_soc_pcm_component_new(rtd); if (ret < 0) { dev_err(rtd->dev, "ASoC: pcm constructor failed: %d\n", ret); return ret; -- cgit From 0ced7b050224b18ca73e38e7068f36be8e708c06 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 18 Nov 2019 10:51:11 +0900 Subject: ASoC: soc-pcm: remove soc_pcm_private_free() soc-topology adds extra dai_link by using snd_soc_add_dai_link(), and removes it by snd_soc_romove_dai_link(). This snd_soc_add/remove_dai_link() and/or its related functions are unbalanced before, and now, these are balance-uped. But, it finds the random operation issue, and it is reported by Pierre-Louis. When card was released, topology will call snd_soc_remove_dai_link() via (A). static void soc_cleanup_card_resources(struct snd_soc_card *card) { struct snd_soc_dai_link *link, *_link; /* This should be called before snd_card_free() */ (A) soc_remove_link_components(card); /* free the ALSA card at first; this syncs with pending operations */ if (card->snd_card) { (B) snd_card_free(card->snd_card); card->snd_card = NULL; } /* remove and free each DAI */ (X) soc_remove_link_dais(card); for_each_card_links_safe(card, link, _link) (C) snd_soc_remove_dai_link(card, link); ... } At (A), topology calls snd_soc_remove_dai_link(). Then topology rtd, and its related all data are freed. Next, (B) is called, and then, pcm->private_free = soc_pcm_private_free() is called. static void soc_pcm_private_free(struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *rtd = pcm->private_data; /* need to sync the delayed work before releasing resources */ flush_delayed_work(&rtd->delayed_work); snd_soc_pcm_component_free(rtd); } Here, it gets rtd via pcm->private_data. But, topology related rtd are already freed at (A). Normal sound card has no damage, becase it frees rtd at (C). These are finalizing rtd related data. Thus, these should be called when rtd was freed, not sound card was freed. It is very natural and understandable. In other words, pcm->private_free = soc_pcm_private_free() is no longer needed. Extra issue is that there is zero chance to call soc_remove_dai() for topology related dai at (X). Because (A) removes rtd connection from card too, and, (X) is based on card connected rtd. This means, (X) need to be called before (C) (= for normal sound) and (A) (= for topology). Now, I want to focus this patch which is the reason why snd_card_free() = (B) is located there. commit 4efda5f2130da033aeedc5b3205569893b910de2 ("ASoC: Fix use-after-free at card unregistration") Original snd_card_free() was called last of this function. But moved to top to avoid use-after-free issue. The issue was happen at soc_pcm_free() which was pcm->private_free, today it is updated/renamed to soc_pcm_private_free(). In other words, (B) need to be called before (C) (= for normal sound) and (A) (= for topology), because it needs (not yet freed) rtd. But, (A) need to be called before (B), because it needs card->snd_card pointer. If we call flush_delayed_work() and snd_soc_pcm_component_free() (= same as soc_pcm_private_free()) when rtd was freed (= (C), (A)), there is no reason to call snd_card_free() at top of this function. It can be called end of this function, again. But, in such case, it will likely break unbind again, as Takashi-san reported. When unbind is performed in a busy state, the code may release still-in-use resources. At least we need to call snd_card_disconnect_sync() at the first place. The final code will be... static void soc_cleanup_card_resources(struct snd_soc_card *card) { struct snd_soc_dai_link *link, *_link; if (card->snd_card) (Z) snd_card_disconnect_sync(card->snd_card); (X) soc_remove_link_dais(card); (A) soc_remove_link_components(card); for_each_card_links_safe(card, link, _link) (C) snd_soc_remove_dai_link(card, link); ... if (card->snd_card) { (B) snd_card_free(card->snd_card); card->snd_card = NULL; } } To avoid release still-in-use resources, call snd_card_disconnect_sync() at (Z). (X) is needed for both non-topology and topology. topology removes rtd via (A), and non topology removes rtd via (C). snd_card_free() is no longer related to use-after-free issue. Thus, locating (B) is no problem. Fixes: df95a16d2a9626 ("ASoC: soc-core: fix RIP warning on card removal") Fixes: bc7a9091e5b927 ("ASoC: soc-core: add soc_unbind_dai_link()") Reported-by: Pierre-Louis Bossart Signed-off-by: Kuninori Morimoto Tested-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/87o8xax88g.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 19 +++++++++++-------- sound/soc/soc-pcm.c | 10 ---------- 2 files changed, 11 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 977a7bfad519..e3a53ef1db04 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -419,6 +419,9 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) list_del(&rtd->list); + flush_delayed_work(&rtd->delayed_work); + snd_soc_pcm_component_free(rtd); + /* * we don't need to call kfree() for rtd->dev * see @@ -1945,19 +1948,14 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card, { struct snd_soc_dai_link *link, *_link; - /* This should be called before snd_card_free() */ - soc_remove_link_components(card); - - /* free the ALSA card at first; this syncs with pending operations */ - if (card->snd_card) { - snd_card_free(card->snd_card); - card->snd_card = NULL; - } + if (card->snd_card) + snd_card_disconnect_sync(card->snd_card); snd_soc_dapm_shutdown(card); /* remove and free each DAI */ soc_remove_link_dais(card); + soc_remove_link_components(card); for_each_card_links_safe(card, link, _link) snd_soc_remove_dai_link(card, link); @@ -1972,6 +1970,11 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card, /* remove the card */ if (card_probed && card->remove) card->remove(card); + + if (card->snd_card) { + snd_card_free(card->snd_card); + card->snd_card = NULL; + } } static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c624d30bfa3c..2c4f50c44591 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2892,15 +2892,6 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) return ret; } -static void soc_pcm_private_free(struct snd_pcm *pcm) -{ - struct snd_soc_pcm_runtime *rtd = pcm->private_data; - - /* need to sync the delayed work before releasing resources */ - flush_delayed_work(&rtd->delayed_work); - snd_soc_pcm_component_free(rtd); -} - /* create a new pcm */ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) { @@ -3042,7 +3033,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) return ret; } - pcm->private_free = soc_pcm_private_free; pcm->no_device_suspend = true; out: dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", -- cgit From e190de6941db14813032af87873f5550ad5764fe Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Wed, 20 Nov 2019 16:20:35 +0800 Subject: ALSA: hda - Add mute led support for HP ProBook 645 G4 Mic mute led does not work on HP ProBook 645 G4. We can use CXT_FIXUP_MUTE_LED_GPIO fixup to support it. Signed-off-by: Kai-Heng Feng Cc: Link: https://lore.kernel.org/r/20191120082035.18937-1-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 968d3caab6ac..90aa0f400a57 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -910,6 +910,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE), -- cgit From dc73d73aa7145f55412611f3eead1e85ae026785 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 19 Nov 2019 18:49:32 +0100 Subject: ASoC: add control components management This ASCII string can carry additional information about soundcard components or configuration. Add the possibility to set this string via the ASoC card. Signed-off-by: Jaroslav Kysela Cc: Mark Brown Link: https://lore.kernel.org/r/20191119174933.25526-1-perex@perex.cz Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e3a53ef1db04..cc0ef0fcc005 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2108,6 +2108,19 @@ static int snd_soc_bind_card(struct snd_soc_card *card) soc_setup_card_name(card->snd_card->driver, card->driver_name, card->name, 1); + if (card->components) { + /* the current implementation of snd_component_add() accepts */ + /* multiple components in the string separated by space, */ + /* but the string collision (identical string) check might */ + /* not work correctly */ + ret = snd_component_add(card->snd_card, card->components); + if (ret < 0) { + dev_err(card->dev, "ASoC: %s snd_component_add() failed: %d\n", + card->name, ret); + goto probe_end; + } + } + if (card->late_probe) { ret = card->late_probe(card); if (ret < 0) { -- cgit From 4ec48e7cbe6e70352c802b5cb172b00ebd8af8e0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 20 Nov 2019 15:17:53 +0200 Subject: ASoC: pcm3168a: Update the RST gpio handling to align with documentation The RST (reset-gpios) is low active so the driver must handle it accordingly. Add comments to explain clearly how the line is used. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191120131753.6831-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index f3475134b519..9711fab296eb 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -707,11 +707,15 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) dev_set_drvdata(dev, pcm3168a); /* - * Request the RST gpio line as non exclusive as the same reset line - * might be connected to multiple pcm3168a codec + * Request the reset (connected to RST pin) gpio line as non exclusive + * as the same reset line might be connected to multiple pcm3168a codec + * + * The RST is low active, we want the GPIO line to be high initially, so + * request the initial level to LOW which in practice means DEASSERTED: + * The deasserted level of GPIO_ACTIVE_LOW is HIGH. */ - pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "rst", - GPIOD_OUT_HIGH | + pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); if (IS_ERR(pcm3168a->gpio_rst)) { ret = PTR_ERR(pcm3168a->gpio_rst); @@ -814,7 +818,13 @@ void pcm3168a_remove(struct device *dev) { struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); - gpiod_set_value_cansleep(pcm3168a->gpio_rst, 0); + /* + * The RST is low active, we want the GPIO line to be low when the + * driver is removed, so set level to 1 which in practice means + * ASSERTED: + * The asserted level of GPIO_ACTIVE_LOW is LOW. + */ + gpiod_set_value_cansleep(pcm3168a->gpio_rst, 1); pm_runtime_disable(dev); #ifndef CONFIG_PM pcm3168a_disable(dev); -- cgit From 5cca59516de5df9de6bdecb328dd55fb5bcccb41 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 12 Nov 2019 18:46:42 +0800 Subject: ASoC: soc-pcm: check symmetry before hw_params This reverts commit 957ce0c6b8a1f (ASoC: soc-pcm: check symmetry after hw_params). That commit cause soc_pcm_params_symmetry can't take effect. cpu_dai->rate, cpu_dai->channels and cpu_dai->sample_bits are updated in the middle of soc_pcm_hw_params, so move soc_pcm_params_symmetry to the end of soc_pcm_hw_params is not a good solution, for judgement of symmetry in the function is always true. FIXME: According to the comments of that commit, I think the case described in the commit should disable symmetric_rates in Back-End, rather than changing the position of soc_pcm_params_symmetry. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1573555602-5403-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2c4f50c44591..01eb8700c3de 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -861,6 +861,11 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, int i, ret = 0; mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + + ret = soc_pcm_params_symmetry(substream, params); + if (ret) + goto out; + if (rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { @@ -940,9 +945,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } component = NULL; - ret = soc_pcm_params_symmetry(substream, params); - if (ret) - goto component_err; out: mutex_unlock(&rtd->card->pcm_mutex); return ret; -- cgit From 3efd72330543da44e82e9371dfb639802c886f6c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 20 Nov 2019 21:32:52 +0800 Subject: ASoC: Fix Kconfig indentation Adjust indentation from spaces to tab (+optional two spaces) as in coding style with command like: $ sed -e 's/^ /\t/' -i */Kconfig Signed-off-by: Krzysztof Kozlowski Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191120133252.6365-1-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 24 ++++++++++++------------ sound/soc/sof/intel/Kconfig | 10 +++++----- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index dfa2c365379f..6c9fd9ad566e 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -441,18 +441,18 @@ config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH If unsure select "N". config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH - tristate "CML with RT1011 and RT5682 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT1011 - select SND_SOC_RT5682 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC machine driver for SOF platform with - RT1011 + RT5682 I2S codec. - Say Y if you have such a device. - If unsure select "N". + tristate "CML with RT1011 and RT5682 in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT1011 + select SND_SOC_RT5682 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC machine driver for SOF platform with + RT1011 + RT5682 I2S codec. + Say Y if you have such a device. + If unsure select "N". endif ## SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 04d4929cf91f..92f7485b6994 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -264,16 +264,16 @@ config SND_SOC_SOF_ELKHARTLAKE config SND_SOC_SOF_JASPERLAKE_SUPPORT bool "SOF support for JasperLake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the JasperLake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the JasperLake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_JASPERLAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_HDA_COMMON -- cgit From 97dda3da20732df8010090dd6d749b9d5b86bffe Mon Sep 17 00:00:00 2001 From: Timo Wischer Date: Wed, 20 Nov 2019 11:49:49 -0600 Subject: ALSA: aloop: Describe units of variables Describe the unit of the variables used to calculate the hw pointer depending on jiffies ticks. Signed-off-by: Timo Wischer Signed-off-by: Andrew Gabbasov Link: https://lore.kernel.org/r/20191120174955.6410-2-andrew_gabbasov@mentor.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 54f8b17476a1..573b06cf7cf5 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -102,8 +102,10 @@ struct loopback_pcm { /* flags */ unsigned int period_update_pending :1; /* timer stuff */ - unsigned int irq_pos; /* fractional IRQ position */ - unsigned int period_size_frac; + unsigned int irq_pos; /* fractional IRQ position in jiffies + * ticks + */ + unsigned int period_size_frac; /* period size in jiffies ticks */ unsigned int last_drift; unsigned long last_jiffies; struct timer_list timer; -- cgit From 09419f1ace213284823ad835d28b239c33daeb71 Mon Sep 17 00:00:00 2001 From: Timo Wischer Date: Wed, 20 Nov 2019 11:49:50 -0600 Subject: ALSA: aloop: Support return of error code for timer start and stop This is required for additional timer implementations which could detect errors and want to throw them. Signed-off-by: Timo Wischer Signed-off-by: Andrew Gabbasov Link: https://lore.kernel.org/r/20191120174955.6410-3-andrew_gabbasov@mentor.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 573b06cf7cf5..7919006f70a5 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -155,7 +155,7 @@ static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) } /* call in cable->lock */ -static void loopback_timer_start(struct loopback_pcm *dpcm) +static int loopback_timer_start(struct loopback_pcm *dpcm) { unsigned long tick; unsigned int rate_shift = get_rate_shift(dpcm); @@ -171,18 +171,24 @@ static void loopback_timer_start(struct loopback_pcm *dpcm) tick = dpcm->period_size_frac - dpcm->irq_pos; tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; mod_timer(&dpcm->timer, jiffies + tick); + + return 0; } /* call in cable->lock */ -static inline void loopback_timer_stop(struct loopback_pcm *dpcm) +static inline int loopback_timer_stop(struct loopback_pcm *dpcm) { del_timer(&dpcm->timer); dpcm->timer.expires = 0; + + return 0; } -static inline void loopback_timer_stop_sync(struct loopback_pcm *dpcm) +static inline int loopback_timer_stop_sync(struct loopback_pcm *dpcm) { del_timer_sync(&dpcm->timer); + + return 0; } #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) @@ -251,7 +257,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_pcm_runtime *runtime = substream->runtime; struct loopback_pcm *dpcm = runtime->private_data; struct loopback_cable *cable = dpcm->cable; - int err, stream = 1 << substream->stream; + int err = 0, stream = 1 << substream->stream; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -264,7 +270,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); cable->running |= stream; cable->pause &= ~stream; - loopback_timer_start(dpcm); + err = loopback_timer_start(dpcm); spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -273,7 +279,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); cable->running &= ~stream; cable->pause &= ~stream; - loopback_timer_stop(dpcm); + err = loopback_timer_stop(dpcm); spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -282,7 +288,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_SUSPEND: spin_lock(&cable->lock); cable->pause |= stream; - loopback_timer_stop(dpcm); + err = loopback_timer_stop(dpcm); spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -292,7 +298,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); dpcm->last_jiffies = jiffies; cable->pause &= ~stream; - loopback_timer_start(dpcm); + err = loopback_timer_start(dpcm); spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -300,7 +306,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) default: return -EINVAL; } - return 0; + return err; } static void params_change(struct snd_pcm_substream *substream) @@ -321,9 +327,11 @@ static int loopback_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct loopback_pcm *dpcm = runtime->private_data; struct loopback_cable *cable = dpcm->cable; - int bps, salign; + int err, bps, salign; - loopback_timer_stop_sync(dpcm); + err = loopback_timer_stop_sync(dpcm); + if (err < 0) + return err; salign = (snd_pcm_format_physical_width(runtime->format) * runtime->channels) / 8; -- cgit From 133f37593eb6db43158bafd52937974acccd1d29 Mon Sep 17 00:00:00 2001 From: Timo Wischer Date: Wed, 20 Nov 2019 11:49:51 -0600 Subject: ALSA: aloop: Use callback functions for timer specific implementations This commit only refactors the implementation. It does not change the behaviour. It is required to support other timers (e.g sound timer). Signed-off-by: Timo Wischer Signed-off-by: Andrew Gabbasov Link: https://lore.kernel.org/r/20191120174955.6410-4-andrew_gabbasov@mentor.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 113 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 7919006f70a5..3bfd7c32803c 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -55,8 +55,39 @@ MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels change #define NO_PITCH 100000 +struct loopback_cable; struct loopback_pcm; +struct loopback_ops { + /* optional + * call in loopback->cable_lock + */ + int (*open)(struct loopback_pcm *dpcm); + /* required + * call in cable->lock + */ + int (*start)(struct loopback_pcm *dpcm); + /* required + * call in cable->lock + */ + int (*stop)(struct loopback_pcm *dpcm); + /* optional */ + int (*stop_sync)(struct loopback_pcm *dpcm); + /* optional */ + int (*close_substream)(struct loopback_pcm *dpcm); + /* optional + * call in loopback->cable_lock + */ + int (*close_cable)(struct loopback_pcm *dpcm); + /* optional + * call in cable->lock + */ + unsigned int (*pos_update)(struct loopback_cable *cable); + /* optional */ + void (*dpcm_info)(struct loopback_pcm *dpcm, + struct snd_info_buffer *buffer); +}; + struct loopback_cable { spinlock_t lock; struct loopback_pcm *streams[2]; @@ -65,6 +96,8 @@ struct loopback_cable { unsigned int valid; unsigned int running; unsigned int pause; + /* timer specific */ + struct loopback_ops *ops; }; struct loopback_setup { @@ -270,7 +303,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); cable->running |= stream; cable->pause &= ~stream; - err = loopback_timer_start(dpcm); + err = cable->ops->start(dpcm); spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -279,7 +312,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); cable->running &= ~stream; cable->pause &= ~stream; - err = loopback_timer_stop(dpcm); + err = cable->ops->stop(dpcm); spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -288,7 +321,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_SUSPEND: spin_lock(&cable->lock); cable->pause |= stream; - err = loopback_timer_stop(dpcm); + err = cable->ops->stop(dpcm); spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -298,7 +331,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); dpcm->last_jiffies = jiffies; cable->pause &= ~stream; - err = loopback_timer_start(dpcm); + err = cable->ops->start(dpcm); spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -329,9 +362,11 @@ static int loopback_prepare(struct snd_pcm_substream *substream) struct loopback_cable *cable = dpcm->cable; int err, bps, salign; - err = loopback_timer_stop_sync(dpcm); - if (err < 0) - return err; + if (cable->ops->stop_sync) { + err = cable->ops->stop_sync(dpcm); + if (err < 0) + return err; + } salign = (snd_pcm_format_physical_width(runtime->format) * runtime->channels) / 8; @@ -539,6 +574,18 @@ static void loopback_timer_function(struct timer_list *t) spin_unlock_irqrestore(&dpcm->cable->lock, flags); } +static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm, + struct snd_info_buffer *buffer) +{ + snd_iprintf(buffer, " update_pending:\t%u\n", + dpcm->period_update_pending); + snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); + snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); + snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", + dpcm->last_jiffies, jiffies); + snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); +} + static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -546,7 +593,8 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t pos; spin_lock(&dpcm->cable->lock); - loopback_pos_update(dpcm->cable); + if (dpcm->cable->ops->pos_update) + dpcm->cable->ops->pos_update(dpcm->cable); pos = dpcm->buf_pos; spin_unlock(&dpcm->cable->lock); return bytes_to_frames(runtime, pos); @@ -671,12 +719,33 @@ static void free_cable(struct snd_pcm_substream *substream) cable->streams[substream->stream] = NULL; spin_unlock_irq(&cable->lock); } else { + struct loopback_pcm *dpcm = substream->runtime->private_data; + + if (cable->ops && cable->ops->close_cable && dpcm) + cable->ops->close_cable(dpcm); /* free the cable */ loopback->cables[substream->number][dev] = NULL; kfree(cable); } } +static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm) +{ + timer_setup(&dpcm->timer, loopback_timer_function, 0); + + return 0; +} + +static struct loopback_ops loopback_jiffies_timer_ops = { + .open = loopback_jiffies_timer_open, + .start = loopback_timer_start, + .stop = loopback_timer_stop, + .stop_sync = loopback_timer_stop_sync, + .close_substream = loopback_timer_stop_sync, + .pos_update = loopback_pos_update, + .dpcm_info = loopback_jiffies_timer_dpcm_info, +}; + static int loopback_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -694,7 +763,6 @@ static int loopback_open(struct snd_pcm_substream *substream) } dpcm->loopback = loopback; dpcm->substream = substream; - timer_setup(&dpcm->timer, loopback_timer_function, 0); cable = loopback->cables[substream->number][dev]; if (!cable) { @@ -705,9 +773,17 @@ static int loopback_open(struct snd_pcm_substream *substream) } spin_lock_init(&cable->lock); cable->hw = loopback_pcm_hardware; + cable->ops = &loopback_jiffies_timer_ops; loopback->cables[substream->number][dev] = cable; } dpcm->cable = cable; + runtime->private_data = dpcm; + + if (cable->ops->open) { + err = cable->ops->open(dpcm); + if (err < 0) + goto unlock; + } snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); @@ -733,7 +809,9 @@ static int loopback_open(struct snd_pcm_substream *substream) if (err < 0) goto unlock; - runtime->private_data = dpcm; + /* loopback_runtime_free() has not to be called if kfree(dpcm) was + * already called here. Otherwise it will end up with a double free. + */ runtime->private_free = loopback_runtime_free; if (get_notify(dpcm)) runtime->hw = loopback_pcm_hardware; @@ -757,12 +835,14 @@ static int loopback_close(struct snd_pcm_substream *substream) { struct loopback *loopback = substream->private_data; struct loopback_pcm *dpcm = substream->runtime->private_data; + int err = 0; - loopback_timer_stop_sync(dpcm); + if (dpcm->cable->ops->close_substream) + err = dpcm->cable->ops->close_substream(dpcm); mutex_lock(&loopback->cable_lock); free_cable(substream); mutex_unlock(&loopback->cable_lock); - return 0; + return err; } static const struct snd_pcm_ops loopback_pcm_ops = { @@ -1086,13 +1166,8 @@ static void print_dpcm_info(struct snd_info_buffer *buffer, snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps); snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign); snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift); - snd_iprintf(buffer, " update_pending:\t%u\n", - dpcm->period_update_pending); - snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); - snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); - snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", - dpcm->last_jiffies, jiffies); - snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); + if (dpcm->cable->ops->dpcm_info) + dpcm->cable->ops->dpcm_info(dpcm, buffer); } static void print_substream_info(struct snd_info_buffer *buffer, -- cgit From 8e3bf7cde43339507f9ce15fc10ff329e76ad649 Mon Sep 17 00:00:00 2001 From: Timo Wischer Date: Wed, 20 Nov 2019 11:49:52 -0600 Subject: ALSA: aloop: Rename all jiffies timer specific functions This commit does not change the behaviour. It only separates the jiffies timer specific implementation from the generic part. Signed-off-by: Timo Wischer Signed-off-by: Andrew Gabbasov Link: https://lore.kernel.org/r/20191120174955.6410-5-andrew_gabbasov@mentor.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 3bfd7c32803c..2f208aaa54cf 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -188,7 +188,7 @@ static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) } /* call in cable->lock */ -static int loopback_timer_start(struct loopback_pcm *dpcm) +static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm) { unsigned long tick; unsigned int rate_shift = get_rate_shift(dpcm); @@ -209,7 +209,7 @@ static int loopback_timer_start(struct loopback_pcm *dpcm) } /* call in cable->lock */ -static inline int loopback_timer_stop(struct loopback_pcm *dpcm) +static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm) { del_timer(&dpcm->timer); dpcm->timer.expires = 0; @@ -217,7 +217,7 @@ static inline int loopback_timer_stop(struct loopback_pcm *dpcm) return 0; } -static inline int loopback_timer_stop_sync(struct loopback_pcm *dpcm) +static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm) { del_timer_sync(&dpcm->timer); @@ -502,7 +502,8 @@ static inline void bytepos_finish(struct loopback_pcm *dpcm, } /* call in cable->lock */ -static unsigned int loopback_pos_update(struct loopback_cable *cable) +static unsigned int loopback_jiffies_timer_pos_update + (struct loopback_cable *cable) { struct loopback_pcm *dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; @@ -555,14 +556,15 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) return running; } -static void loopback_timer_function(struct timer_list *t) +static void loopback_jiffies_timer_function(struct timer_list *t) { struct loopback_pcm *dpcm = from_timer(dpcm, t, timer); unsigned long flags; spin_lock_irqsave(&dpcm->cable->lock, flags); - if (loopback_pos_update(dpcm->cable) & (1 << dpcm->substream->stream)) { - loopback_timer_start(dpcm); + if (loopback_jiffies_timer_pos_update(dpcm->cable) & + (1 << dpcm->substream->stream)) { + loopback_jiffies_timer_start(dpcm); if (dpcm->period_update_pending) { dpcm->period_update_pending = 0; spin_unlock_irqrestore(&dpcm->cable->lock, flags); @@ -731,18 +733,18 @@ static void free_cable(struct snd_pcm_substream *substream) static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm) { - timer_setup(&dpcm->timer, loopback_timer_function, 0); + timer_setup(&dpcm->timer, loopback_jiffies_timer_function, 0); return 0; } static struct loopback_ops loopback_jiffies_timer_ops = { .open = loopback_jiffies_timer_open, - .start = loopback_timer_start, - .stop = loopback_timer_stop, - .stop_sync = loopback_timer_stop_sync, - .close_substream = loopback_timer_stop_sync, - .pos_update = loopback_pos_update, + .start = loopback_jiffies_timer_start, + .stop = loopback_jiffies_timer_stop, + .stop_sync = loopback_jiffies_timer_stop_sync, + .close_substream = loopback_jiffies_timer_stop_sync, + .pos_update = loopback_jiffies_timer_pos_update, .dpcm_info = loopback_jiffies_timer_dpcm_info, }; -- cgit From fd1f7c743d30938d3befb1af038a510c003a6a27 Mon Sep 17 00:00:00 2001 From: Timo Wischer Date: Wed, 20 Nov 2019 11:49:53 -0600 Subject: ALSA: aloop: Move CABLE_VALID_BOTH to the top of file so all functions can use the same. Signed-off-by: Timo Wischer Signed-off-by: Andrew Gabbasov Link: https://lore.kernel.org/r/20191120174955.6410-6-andrew_gabbasov@mentor.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 2f208aaa54cf..0eacaa9d7862 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -55,6 +55,10 @@ MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels change #define NO_PITCH 100000 +#define CABLE_VALID_PLAYBACK BIT(SNDRV_PCM_STREAM_PLAYBACK) +#define CABLE_VALID_CAPTURE BIT(SNDRV_PCM_STREAM_CAPTURE) +#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK | CABLE_VALID_CAPTURE) + struct loopback_cable; struct loopback_pcm; @@ -224,10 +228,6 @@ static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm) return 0; } -#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) -#define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE) -#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE) - static int loopback_check_format(struct loopback_cable *cable, int stream) { struct snd_pcm_runtime *runtime, *cruntime; -- cgit From 26c53379f98d22d6a3e50bb146651dc7824334d7 Mon Sep 17 00:00:00 2001 From: Timo Wischer Date: Wed, 20 Nov 2019 11:49:54 -0600 Subject: ALSA: aloop: Support selection of snd_timer instead of jiffies to do synchronous audio forwarding between hardware sound card and aloop devices. Such an audio route could look like the following: Sound card -> Loopback application -> ALSA loop device -> arecord In this case the loopback device should use the sound timer of the sound card. Without this patch the loopback application has to implement an adaptive sample rate converter to align the different clocks of the different ALSA devices. The used timer can be selected by referring to a sound card, its device and subdevice, when loading the module: $ modprobe snd_aloop enable=1 timer_source=[[.[.]]] is the name (id) of the sound card or a card number. and are device and subdevice numbers (defaults are 0). Empty string as a value of timer_source= parameter enables previous functionality (using jiffies timer). Signed-off-by: Timo Wischer Signed-off-by: Andrew Gabbasov Link: https://lore.kernel.org/r/20191120174955.6410-7-andrew_gabbasov@mentor.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 477 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 476 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 0eacaa9d7862..e8a85f887222 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -28,6 +28,7 @@ #include #include #include +#include MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("A loopback soundcard"); @@ -41,6 +42,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; static int pcm_notify[SNDRV_CARDS]; +static char *timer_source[SNDRV_CARDS]; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for loopback soundcard."); @@ -52,6 +54,8 @@ module_param_array(pcm_substreams, int, NULL, 0444); MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver."); module_param_array(pcm_notify, int, NULL, 0444); MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes."); +module_param_array(timer_source, charp, NULL, 0444); +MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default]."); #define NO_PITCH 100000 @@ -102,6 +106,13 @@ struct loopback_cable { unsigned int pause; /* timer specific */ struct loopback_ops *ops; + /* If sound timer is used */ + struct { + int stream; + struct snd_timer_id id; + struct tasklet_struct event_tasklet; + struct snd_timer_instance *instance; + } snd_timer; }; struct loopback_setup { @@ -122,6 +133,7 @@ struct loopback { struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2]; struct snd_pcm *pcm[2]; struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2]; + const char *timer_source; }; struct loopback_pcm { @@ -145,6 +157,7 @@ struct loopback_pcm { unsigned int period_size_frac; /* period size in jiffies ticks */ unsigned int last_drift; unsigned long last_jiffies; + /* If jiffies timer is used */ struct timer_list timer; }; @@ -212,6 +225,35 @@ static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm) return 0; } +/* call in cable->lock */ +static int loopback_snd_timer_start(struct loopback_pcm *dpcm) +{ + struct loopback_cable *cable = dpcm->cable; + int err; + + /* Loopback device has to use same period as timer card. Therefore + * wake up for each snd_pcm_period_elapsed() call of timer card. + */ + err = snd_timer_start(cable->snd_timer.instance, 1); + if (err < 0) { + /* do not report error if trying to start but already + * running. For example called by opposite substream + * of the same cable + */ + if (err == -EBUSY) + return 0; + + pcm_err(dpcm->substream->pcm, + "snd_timer_start(%d,%d,%d) failed with %d", + cable->snd_timer.id.card, + cable->snd_timer.id.device, + cable->snd_timer.id.subdevice, + err); + } + + return err; +} + /* call in cable->lock */ static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm) { @@ -221,6 +263,29 @@ static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm) return 0; } +/* call in cable->lock */ +static int loopback_snd_timer_stop(struct loopback_pcm *dpcm) +{ + struct loopback_cable *cable = dpcm->cable; + int err; + + /* only stop if both devices (playback and capture) are not running */ + if (cable->running ^ cable->pause) + return 0; + + err = snd_timer_stop(cable->snd_timer.instance); + if (err < 0) { + pcm_err(dpcm->substream->pcm, + "snd_timer_stop(%d,%d,%d) failed with %d", + cable->snd_timer.id.card, + cable->snd_timer.id.device, + cable->snd_timer.id.subdevice, + err); + } + + return err; +} + static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm) { del_timer_sync(&dpcm->timer); @@ -228,6 +293,30 @@ static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm) return 0; } +/* call in loopback->cable_lock */ +static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm) +{ + struct loopback_cable *cable = dpcm->cable; + + /* snd_timer was not opened */ + if (!cable->snd_timer.instance) + return 0; + + /* wait till drain tasklet has finished if requested */ + tasklet_kill(&cable->snd_timer.event_tasklet); + + /* will only be called from free_cable() when other stream was + * already closed. Other stream cannot be reopened as long as + * loopback->cable_lock is locked. Therefore no need to lock + * cable->lock; + */ + snd_timer_close(cable->snd_timer.instance); + snd_timer_instance_free(cable->snd_timer.instance); + memset(&cable->snd_timer, 0, sizeof(cable->snd_timer)); + + return 0; +} + static int loopback_check_format(struct loopback_cable *cable, int stream) { struct snd_pcm_runtime *runtime, *cruntime; @@ -353,6 +442,13 @@ static void params_change(struct snd_pcm_substream *substream) cable->hw.rate_max = runtime->rate; cable->hw.channels_min = runtime->channels; cable->hw.channels_max = runtime->channels; + + if (cable->snd_timer.instance) { + cable->hw.period_bytes_min = + frames_to_bytes(runtime, runtime->period_size); + cable->hw.period_bytes_max = cable->hw.period_bytes_min; + } + } static int loopback_prepare(struct snd_pcm_substream *substream) @@ -576,6 +672,167 @@ static void loopback_jiffies_timer_function(struct timer_list *t) spin_unlock_irqrestore(&dpcm->cable->lock, flags); } +/* call in cable->lock */ +static int loopback_snd_timer_check_resolution(struct snd_pcm_runtime *runtime, + unsigned long resolution) +{ + if (resolution != runtime->timer_resolution) { + struct loopback_pcm *dpcm = runtime->private_data; + struct loopback_cable *cable = dpcm->cable; + /* Worst case estimation of possible values for resolution + * resolution <= (512 * 1024) frames / 8kHz in nsec + * resolution <= 65.536.000.000 nsec + * + * period_size <= 65.536.000.000 nsec / 1000nsec/usec * 192kHz + + * 500.000 + * period_size <= 12.582.912.000.000 <64bit + * / 1.000.000 usec/sec + */ + snd_pcm_uframes_t period_size_usec = + resolution / 1000 * runtime->rate; + /* round to nearest sample rate */ + snd_pcm_uframes_t period_size = + (period_size_usec + 500 * 1000) / (1000 * 1000); + + pcm_err(dpcm->substream->pcm, + "Period size (%lu frames) of loopback device is not corresponding to timer resolution (%lu nsec = %lu frames) of card timer %d,%d,%d. Use period size of %lu frames for loopback device.", + runtime->period_size, resolution, period_size, + cable->snd_timer.id.card, + cable->snd_timer.id.device, + cable->snd_timer.id.subdevice, + period_size); + return -EINVAL; + } + return 0; +} + +static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable, + int event, + unsigned long resolution) +{ + struct loopback_pcm *dpcm_play, *dpcm_capt; + struct snd_pcm_substream *substream_play, *substream_capt; + struct snd_pcm_runtime *valid_runtime; + unsigned int running, elapsed_bytes; + unsigned long flags; + + spin_lock_irqsave(&cable->lock, flags); + running = cable->running ^ cable->pause; + /* no need to do anything if no stream is running */ + if (!running) { + spin_unlock_irqrestore(&cable->lock, flags); + return; + } + + dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; + dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; + substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? + dpcm_play->substream : NULL; + substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ? + dpcm_capt->substream : NULL; + + if (event == SNDRV_TIMER_EVENT_MSTOP) { + if (!dpcm_play || + dpcm_play->substream->runtime->status->state != + SNDRV_PCM_STATE_DRAINING) { + spin_unlock_irqrestore(&cable->lock, flags); + return; + } + } + + valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? + dpcm_play->substream->runtime : + dpcm_capt->substream->runtime; + + /* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */ + if (event == SNDRV_TIMER_EVENT_TICK) { + /* The hardware rules guarantee that playback and capture period + * are the same. Therefore only one device has to be checked + * here. + */ + if (loopback_snd_timer_check_resolution(valid_runtime, + resolution) < 0) { + spin_unlock_irqrestore(&cable->lock, flags); + if (substream_play) + snd_pcm_stop_xrun(substream_play); + if (substream_capt) + snd_pcm_stop_xrun(substream_capt); + return; + } + } + + elapsed_bytes = frames_to_bytes(valid_runtime, + valid_runtime->period_size); + /* The same timer interrupt is used for playback and capture device */ + if ((running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) && + (running & (1 << SNDRV_PCM_STREAM_CAPTURE))) { + copy_play_buf(dpcm_play, dpcm_capt, elapsed_bytes); + bytepos_finish(dpcm_play, elapsed_bytes); + bytepos_finish(dpcm_capt, elapsed_bytes); + } else if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { + bytepos_finish(dpcm_play, elapsed_bytes); + } else if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { + clear_capture_buf(dpcm_capt, elapsed_bytes); + bytepos_finish(dpcm_capt, elapsed_bytes); + } + spin_unlock_irqrestore(&cable->lock, flags); + + if (substream_play) + snd_pcm_period_elapsed(substream_play); + if (substream_capt) + snd_pcm_period_elapsed(substream_capt); +} + +static void loopback_snd_timer_function(struct snd_timer_instance *timeri, + unsigned long resolution, + unsigned long ticks) +{ + struct loopback_cable *cable = timeri->callback_data; + + loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_TICK, + resolution); +} + +static void loopback_snd_timer_tasklet(unsigned long arg) +{ + struct snd_timer_instance *timeri = (struct snd_timer_instance *)arg; + struct loopback_cable *cable = timeri->callback_data; + + loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_MSTOP, 0); +} + +static void loopback_snd_timer_event(struct snd_timer_instance *timeri, + int event, + struct timespec *tstamp, + unsigned long resolution) +{ + /* Do not lock cable->lock here because timer->lock is already hold. + * There are other functions which first lock cable->lock and than + * timer->lock e.g. + * loopback_trigger() + * spin_lock(&cable->lock) + * loopback_snd_timer_start() + * snd_timer_start() + * spin_lock(&timer->lock) + * Therefore when using the oposit order of locks here it could result + * in a deadlock. + */ + + if (event == SNDRV_TIMER_EVENT_MSTOP) { + struct loopback_cable *cable = timeri->callback_data; + + /* sound card of the timer was stopped. Therefore there will not + * be any further timer callbacks. Due to this forward audio + * data from here if in draining state. When still in running + * state the streaming will be aborted by the usual timeout. It + * should not be aborted here because may be the timer sound + * card does only a recovery and the timer is back soon. + * This tasklet triggers loopback_snd_timer_tasklet() + */ + tasklet_schedule(&cable->snd_timer.event_tasklet); + } +} + static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm, struct snd_info_buffer *buffer) { @@ -588,6 +845,20 @@ static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm, snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); } +static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm, + struct snd_info_buffer *buffer) +{ + struct loopback_cable *cable = dpcm->cable; + + snd_iprintf(buffer, " sound timer:\thw:%d,%d,%d\n", + cable->snd_timer.id.card, + cable->snd_timer.id.device, + cable->snd_timer.id.subdevice); + snd_iprintf(buffer, " timer open:\t\t%s\n", + (cable->snd_timer.stream == SNDRV_PCM_STREAM_CAPTURE) ? + "capture" : "playback"); +} + static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -706,6 +977,23 @@ static int rule_channels(struct snd_pcm_hw_params *params, return snd_interval_refine(hw_param_interval(params, rule->var), &t); } +static int rule_period_bytes(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct loopback_pcm *dpcm = rule->private; + struct loopback_cable *cable = dpcm->cable; + struct snd_interval t; + + mutex_lock(&dpcm->loopback->cable_lock); + t.min = cable->hw.period_bytes_min; + t.max = cable->hw.period_bytes_max; + mutex_unlock(&dpcm->loopback->cable_lock); + t.openmin = 0; + t.openmax = 0; + t.integer = 0; + return snd_interval_refine(hw_param_interval(params, rule->var), &t); +} + static void free_cable(struct snd_pcm_substream *substream) { struct loopback *loopback = substream->private_data; @@ -748,6 +1036,163 @@ static struct loopback_ops loopback_jiffies_timer_ops = { .dpcm_info = loopback_jiffies_timer_dpcm_info, }; +static int loopback_parse_timer_id(const char *str, + struct snd_timer_id *tid) +{ + /* [:](|)[{.,}[{.,}]] */ + const char * const sep_dev = ".,"; + const char * const sep_pref = ":"; + const char *name = str; + char *sep, save = '\0'; + int card_idx = 0, dev = 0, subdev = 0; + int err; + + sep = strpbrk(str, sep_pref); + if (sep) + name = sep + 1; + sep = strpbrk(name, sep_dev); + if (sep) { + save = *sep; + *sep = '\0'; + } + err = kstrtoint(name, 0, &card_idx); + if (err == -EINVAL) { + /* Must be the name, not number */ + for (card_idx = 0; card_idx < snd_ecards_limit; card_idx++) { + struct snd_card *card = snd_card_ref(card_idx); + + if (card) { + if (!strcmp(card->id, name)) + err = 0; + snd_card_unref(card); + } + if (!err) + break; + } + } + if (sep) { + *sep = save; + if (!err) { + char *sep2, save2 = '\0'; + + sep2 = strpbrk(sep + 1, sep_dev); + if (sep2) { + save2 = *sep2; + *sep2 = '\0'; + } + err = kstrtoint(sep + 1, 0, &dev); + if (sep2) { + *sep2 = save2; + if (!err) + err = kstrtoint(sep2 + 1, 0, &subdev); + } + } + } + if (!err && tid) { + tid->card = card_idx; + tid->device = dev; + tid->subdevice = subdev; + } + return err; +} + +/* call in loopback->cable_lock */ +static int loopback_snd_timer_open(struct loopback_pcm *dpcm) +{ + int err = 0; + struct snd_timer_id tid = { + .dev_class = SNDRV_TIMER_CLASS_PCM, + .dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION, + }; + struct snd_timer_instance *timeri; + struct loopback_cable *cable = dpcm->cable; + + spin_lock_irq(&cable->lock); + + /* check if timer was already opened. It is only opened once + * per playback and capture subdevice (aka cable). + */ + if (cable->snd_timer.instance) + goto unlock; + + err = loopback_parse_timer_id(dpcm->loopback->timer_source, &tid); + if (err < 0) { + pcm_err(dpcm->substream->pcm, + "Parsing timer source \'%s\' failed with %d", + dpcm->loopback->timer_source, err); + goto unlock; + } + + cable->snd_timer.stream = dpcm->substream->stream; + cable->snd_timer.id = tid; + + timeri = snd_timer_instance_new(dpcm->loopback->card->id); + if (!timeri) { + err = -ENOMEM; + goto unlock; + } + /* The callback has to be called from another tasklet. If + * SNDRV_TIMER_IFLG_FAST is specified it will be called from the + * snd_pcm_period_elapsed() call of the selected sound card. + * snd_pcm_period_elapsed() helds snd_pcm_stream_lock_irqsave(). + * Due to our callback loopback_snd_timer_function() also calls + * snd_pcm_period_elapsed() which calls snd_pcm_stream_lock_irqsave(). + * This would end up in a dead lock. + */ + timeri->flags |= SNDRV_TIMER_IFLG_AUTO; + timeri->callback = loopback_snd_timer_function; + timeri->callback_data = (void *)cable; + timeri->ccallback = loopback_snd_timer_event; + + /* initialise a tasklet used for draining */ + tasklet_init(&cable->snd_timer.event_tasklet, + loopback_snd_timer_tasklet, (unsigned long)timeri); + + /* snd_timer_close() and snd_timer_open() should not be called with + * locked spinlock because both functions can block on a mutex. The + * mutex loopback->cable_lock is kept locked. Therefore snd_timer_open() + * cannot be called a second time by the other device of the same cable. + * Therefore the following issue cannot happen: + * [proc1] Call loopback_timer_open() -> + * Unlock cable->lock for snd_timer_close/open() call + * [proc2] Call loopback_timer_open() -> snd_timer_open(), + * snd_timer_start() + * [proc1] Call snd_timer_open() and overwrite running timer + * instance + */ + spin_unlock_irq(&cable->lock); + err = snd_timer_open(timeri, &cable->snd_timer.id, current->pid); + spin_lock_irq(&cable->lock); + if (err < 0) { + pcm_err(dpcm->substream->pcm, + "snd_timer_open (%d,%d,%d) failed with %d", + cable->snd_timer.id.card, + cable->snd_timer.id.device, + cable->snd_timer.id.subdevice, + err); + snd_timer_instance_free(timeri); + goto unlock; + } + + cable->snd_timer.instance = timeri; + +unlock: + spin_unlock_irq(&cable->lock); + + return err; +} + +/* stop_sync() is not required for sound timer because it does not need to be + * restarted in loopback_prepare() on Xrun recovery + */ +static struct loopback_ops loopback_snd_timer_ops = { + .open = loopback_snd_timer_open, + .start = loopback_snd_timer_start, + .stop = loopback_snd_timer_stop, + .close_cable = loopback_snd_timer_close_cable, + .dpcm_info = loopback_snd_timer_dpcm_info, +}; + static int loopback_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -775,7 +1220,10 @@ static int loopback_open(struct snd_pcm_substream *substream) } spin_lock_init(&cable->lock); cable->hw = loopback_pcm_hardware; - cable->ops = &loopback_jiffies_timer_ops; + if (loopback->timer_source) + cable->ops = &loopback_snd_timer_ops; + else + cable->ops = &loopback_jiffies_timer_ops; loopback->cables[substream->number][dev] = cable; } dpcm->cable = cable; @@ -811,6 +1259,19 @@ static int loopback_open(struct snd_pcm_substream *substream) if (err < 0) goto unlock; + /* In case of sound timer the period time of both devices of the same + * loop has to be the same. + * This rule only takes effect if a sound timer was chosen + */ + if (cable->snd_timer.instance) { + err = snd_pcm_hw_rule_add(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + rule_period_bytes, dpcm, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1); + if (err < 0) + goto unlock; + } + /* loopback_runtime_free() has not to be called if kfree(dpcm) was * already called here. Otherwise it will end up with a double free. */ @@ -1214,6 +1675,18 @@ static int loopback_proc_new(struct loopback *loopback, int cidx) print_cable_info); } +static void loopback_set_timer_source(struct loopback *loopback, + const char *value) +{ + if (loopback->timer_source) { + devm_kfree(loopback->card->dev, loopback->timer_source); + loopback->timer_source = NULL; + } + if (value && *value) + loopback->timer_source = devm_kstrdup(loopback->card->dev, + value, GFP_KERNEL); +} + static int loopback_probe(struct platform_device *devptr) { struct snd_card *card; @@ -1233,6 +1706,8 @@ static int loopback_probe(struct platform_device *devptr) pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; loopback->card = card; + loopback_set_timer_source(loopback, timer_source[dev]); + mutex_init(&loopback->cable_lock); err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]); -- cgit From c6ae99605633cade7dc61a2b35b04dda90302dad Mon Sep 17 00:00:00 2001 From: Andrew Gabbasov Date: Wed, 20 Nov 2019 11:49:55 -0600 Subject: ALSA: aloop: Support runtime change of snd_timer via info interface Show and change sound card timer source with read-write info file in proc filesystem. Initial string can still be set as module parameter. The timer source string value can be changed at any time, but it is latched by PCM substream open callback (the first one for a particular cable). At this point it is actually used, that is the string is parsed, and the timer is looked up and opened. The timer source is set for a loopback card (the same as initial setting by module parameter), but every cable uses the value, current at the moment of open. Setting the value to empty string switches the timer to jiffies. Signed-off-by: Andrew Gabbasov Link: https://lore.kernel.org/r/20191120174955.6410-8-andrew_gabbasov@mentor.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index e8a85f887222..1408403f727a 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -1666,7 +1666,7 @@ static void print_cable_info(struct snd_info_entry *entry, mutex_unlock(&loopback->cable_lock); } -static int loopback_proc_new(struct loopback *loopback, int cidx) +static int loopback_cable_proc_new(struct loopback *loopback, int cidx) { char name[32]; @@ -1687,6 +1687,36 @@ static void loopback_set_timer_source(struct loopback *loopback, value, GFP_KERNEL); } +static void print_timer_source_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct loopback *loopback = entry->private_data; + + mutex_lock(&loopback->cable_lock); + snd_iprintf(buffer, "%s\n", + loopback->timer_source ? loopback->timer_source : ""); + mutex_unlock(&loopback->cable_lock); +} + +static void change_timer_source_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct loopback *loopback = entry->private_data; + char line[64]; + + mutex_lock(&loopback->cable_lock); + if (!snd_info_get_line(buffer, line, sizeof(line))) + loopback_set_timer_source(loopback, strim(line)); + mutex_unlock(&loopback->cable_lock); +} + +static int loopback_timer_source_proc_new(struct loopback *loopback) +{ + return snd_card_rw_proc_new(loopback->card, "timer_source", loopback, + print_timer_source_info, + change_timer_source_info); +} + static int loopback_probe(struct platform_device *devptr) { struct snd_card *card; @@ -1719,8 +1749,9 @@ static int loopback_probe(struct platform_device *devptr) err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); if (err < 0) goto __nodev; - loopback_proc_new(loopback, 0); - loopback_proc_new(loopback, 1); + loopback_cable_proc_new(loopback, 0); + loopback_cable_proc_new(loopback, 1); + loopback_timer_source_proc_new(loopback); strcpy(card->driver, "Loopback"); strcpy(card->shortname, "Loopback"); sprintf(card->longname, "Loopback %i", dev + 1); -- cgit From 0dba808eae2627f40024872d2f02f75f0d2b0790 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 17 Nov 2019 09:53:01 +0100 Subject: ALSA: pcm: Introduce managed buffer allocation mode This patch adds the support for the feature to automatically allocate and free PCM buffers, so called "managed buffer allocation" mode. It's set up via new PCM helpers, snd_pcm_set_managed_buffer() and snd_pcm_set_managed_buffer_all(), both of which correspond to the existing preallocator helpers, snd_pcm_lib_preallocate_pages() and snd_pcm_lib_preallocate_pages_for_all(). When the new helper is used, it not only performs the pre-allocation of buffers, but also it manages to call snd_pcm_lib_malloc_pages() before the PCM hw_params ops and snd_lib_pcm_free() after the PCM hw_free ops inside PCM core, respectively. This allows drivers to drop the explicit calls of the memory allocation / release functions, and it will be a good amount of code reduction in the end of this patch series. When the PCM substream is set to the managed buffer allocation mode, the managed_buffer_alloc flag is set in the substream object. Since some drivers want to know when a buffer is newly allocated or re-allocated at hw_params callback (e.g. want to set up the additional stuff for the given buffer only at allocation time), now PCM core turns on buffer_changed flag when the buffer has changed. The standard conversions to use the new API will be straightforward: - Replace snd_pcm_lib_preallocate*() calls with the corresponding snd_pcm_set_managed_buffer*(); the arguments should be unchanged - Drop superfluous snd_pcm_lib_malloc() and snd_pcm_lib_free() calls; the check of snd_pcm_lib_malloc() returns should be replaced with the check of runtime->buffer_changed flag. - If hw_params or hw_free becomes empty, drop them from PCM ops Link: https://lore.kernel.org/r/20191117085308.23915-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_memory.c | 83 +++++++++++++++++++++++++++++++++++++++++-------- sound/core/pcm_native.c | 12 +++++++ 2 files changed, 82 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 286f333f8e4c..73b770db2372 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -193,9 +193,15 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) /* * pre-allocate the buffer and create a proc file for the substream */ -static void snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, - size_t size, size_t max) +static void preallocate_pages(struct snd_pcm_substream *substream, + int type, struct device *data, + size_t size, size_t max, bool managed) { + if (snd_BUG_ON(substream->dma_buffer.dev.type)) + return; + + substream->dma_buffer.dev.type = type; + substream->dma_buffer.dev.dev = data; if (size > 0 && preallocate_dma && substream->number < maximum_substreams) preallocate_pcm_pages(substream, size); @@ -205,8 +211,23 @@ static void snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, substream->dma_max = max; if (max > 0) preallocate_info_init(substream); + if (managed) + substream->managed_buffer_alloc = 1; } +static void preallocate_pages_for_all(struct snd_pcm *pcm, int type, + void *data, size_t size, size_t max, + bool managed) +{ + struct snd_pcm_substream *substream; + int stream; + + for (stream = 0; stream < 2; stream++) + for (substream = pcm->streams[stream].substream; substream; + substream = substream->next) + preallocate_pages(substream, type, data, size, max, + managed); +} /** * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type @@ -222,11 +243,7 @@ void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, int type, struct device *data, size_t size, size_t max) { - if (snd_BUG_ON(substream->dma_buffer.dev.type)) - return; - substream->dma_buffer.dev.type = type; - substream->dma_buffer.dev.dev = data; - snd_pcm_lib_preallocate_pages1(substream, size, max); + preallocate_pages(substream, type, data, size, max, false); } EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); @@ -245,15 +262,55 @@ void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int type, void *data, size_t size, size_t max) { - struct snd_pcm_substream *substream; - int stream; - - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - snd_pcm_lib_preallocate_pages(substream, type, data, size, max); + preallocate_pages_for_all(pcm, type, data, size, max, false); } EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); +/** + * snd_pcm_set_managed_buffer - set up buffer management for a substream + * @substream: the pcm substream instance + * @type: DMA type (SNDRV_DMA_TYPE_*) + * @data: DMA type dependent data + * @size: the requested pre-allocation size in bytes + * @max: the max. allowed pre-allocation size + * + * Do pre-allocation for the given DMA buffer type, and set the managed + * buffer allocation mode to the given substream. + * In this mode, PCM core will allocate a buffer automatically before PCM + * hw_params ops call, and release the buffer after PCM hw_free ops call + * as well, so that the driver doesn't need to invoke the allocation and + * the release explicitly in its callback. + * When a buffer is actually allocated before the PCM hw_params call, it + * turns on the runtime buffer_changed flag for drivers changing their h/w + * parameters accordingly. + */ +void snd_pcm_set_managed_buffer(struct snd_pcm_substream *substream, int type, + struct device *data, size_t size, size_t max) +{ + preallocate_pages(substream, type, data, size, max, true); +} +EXPORT_SYMBOL(snd_pcm_set_managed_buffer); + +/** + * snd_pcm_set_managed_buffer_all - set up buffer management for all substreams + * for all substreams + * @pcm: the pcm instance + * @type: DMA type (SNDRV_DMA_TYPE_*) + * @data: DMA type dependent data + * @size: the requested pre-allocation size in bytes + * @max: the max. allowed pre-allocation size + * + * Do pre-allocation to all substreams of the given pcm for the specified DMA + * type and size, and set the managed_buffer_alloc flag to each substream. + */ +void snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type, + struct device *data, + size_t size, size_t max) +{ + preallocate_pages_for_all(pcm, type, data, size, max, true); +} +EXPORT_SYMBOL(snd_pcm_set_managed_buffer_all); + #ifdef CONFIG_SND_DMA_SGBUF /* * snd_pcm_sgbuf_ops_page - get the page struct at the given offset diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 0c27009dc3df..f1646735bde6 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -662,6 +662,14 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto _error; + if (substream->managed_buffer_alloc) { + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(params)); + if (err < 0) + goto _error; + runtime->buffer_changed = err > 0; + } + if (substream->ops->hw_params != NULL) { err = substream->ops->hw_params(substream, params); if (err < 0) @@ -723,6 +731,8 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); if (substream->ops->hw_free != NULL) substream->ops->hw_free(substream); + if (substream->managed_buffer_alloc) + snd_pcm_lib_free_pages(substream); return err; } @@ -769,6 +779,8 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) return -EBADFD; if (substream->ops->hw_free) result = substream->ops->hw_free(substream); + if (substream->managed_buffer_alloc) + snd_pcm_lib_free_pages(substream); snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); pm_qos_remove_request(&substream->latency_pm_qos_req); return result; -- cgit From fc033cbf6fb75452f03774ca5adccac8cf9bc84f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 17 Nov 2019 09:53:03 +0100 Subject: ALSA: pcm: Allow NULL ioctl ops Currently PCM ioctl ops is a mandatory field but almost all drivers simply pass snd_pcm_lib_ioctl. For simplicity, allow to set NULL in the field and call snd_pcm_lib_ioctl() as default. Link: https://lore.kernel.org/r/20191117085308.23915-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f1646735bde6..704ea75199e4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -178,6 +178,16 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); +/* Run PCM ioctl ops */ +static int snd_pcm_ops_ioctl(struct snd_pcm_substream *substream, + unsigned cmd, void *arg) +{ + if (substream->ops->ioctl) + return substream->ops->ioctl(substream, cmd, arg); + else + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) { struct snd_pcm *pcm = substream->pcm; @@ -448,8 +458,9 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); if (snd_mask_single(m) && snd_interval_single(i)) { - err = substream->ops->ioctl(substream, - SNDRV_PCM_IOCTL1_FIFO_SIZE, params); + err = snd_pcm_ops_ioctl(substream, + SNDRV_PCM_IOCTL1_FIFO_SIZE, + params); if (err < 0) return err; } @@ -971,7 +982,7 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream, return -EINVAL; memset(info, 0, sizeof(*info)); info->channel = channel; - return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info); + return snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info); } static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream, @@ -1647,7 +1658,7 @@ static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, int state) static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) { struct snd_pcm_runtime *runtime = substream->runtime; - int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); + int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); if (err < 0) return err; runtime->hw_ptr_base = 0; -- cgit From 0821fd77a1129cf4848d82d9275fb4e90e02edf8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 17 Nov 2019 11:05:12 +0100 Subject: ALSA: pcm: Move PCM_RUNTIME_CHECK() macro into local header It should be used only in the PCM core code locally. Link: https://lore.kernel.org/r/20191117085308.23915-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_local.h | 2 ++ sound/core/pcm_memory.c | 1 + 2 files changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index 5565e1c4196a..384efd002984 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h @@ -72,4 +72,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset); #endif +#define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime) + #endif /* __SOUND_CORE_PCM_LOCAL_H */ diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 73b770db2372..d4702cc1d376 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -15,6 +15,7 @@ #include #include #include +#include "pcm_local.h" static int preallocate_dma = 1; module_param(preallocate_dma, int, 0444); -- cgit From 1e850beea2781d30418743dd99250291cef37919 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 17 Nov 2019 09:53:06 +0100 Subject: ALSA: pcm: Add the support for sync-stop operation The standard programming model of a PCM sound driver is to process snd_pcm_period_elapsed() from an interrupt handler. When a running stream is stopped, PCM core calls the trigger-STOP PCM ops, sets the stream state to SETUP, and moves on to the next step. This is performed in an atomic manner -- this could be called from the interrupt context, after all. The problem is that, if the stream goes further and reaches to the CLOSE state immediately, the stream might be still being processed in snd_pcm_period_elapsed() in the interrupt context, and hits a NULL dereference. Such a crash happens because of the atomic operation, and we can't wait until the stream-stop finishes. For addressing such a problem, this commit adds a new PCM ops, sync_stop. This gets called at the appropriate places that need a sync with the stream-stop, i.e. at hw_params, prepare and hw_free. Some drivers already have a similar mechanism implemented locally, and we'll refactor the code later. Link: https://lore.kernel.org/r/20191117085308.23915-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 704ea75199e4..163d621ff238 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -568,6 +568,15 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream, #endif } +static void snd_pcm_sync_stop(struct snd_pcm_substream *substream) +{ + if (substream->runtime->stop_operating) { + substream->runtime->stop_operating = false; + if (substream->ops->sync_stop) + substream->ops->sync_stop(substream); + } +} + /** * snd_pcm_hw_param_choose - choose a configuration defined by @params * @pcm: PCM instance @@ -660,6 +669,8 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if (atomic_read(&substream->mmap_count)) return -EBADFD; + snd_pcm_sync_stop(substream); + params->rmask = ~0U; err = snd_pcm_hw_refine(substream, params); if (err < 0) @@ -788,6 +799,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) snd_pcm_stream_unlock_irq(substream); if (atomic_read(&substream->mmap_count)) return -EBADFD; + snd_pcm_sync_stop(substream); if (substream->ops->hw_free) result = substream->ops->hw_free(substream); if (substream->managed_buffer_alloc) @@ -1313,6 +1325,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) runtime->status->state = state; snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTOP); } + runtime->stop_operating = true; wake_up(&runtime->sleep); wake_up(&runtime->tsleep); } @@ -1589,6 +1602,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state) snd_pcm_trigger_tstamp(substream); runtime->status->state = runtime->status->suspended_state; snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME); + snd_pcm_sync_stop(substream); } static const struct action_ops snd_pcm_action_resume = { @@ -1709,6 +1723,7 @@ static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, int state) { int err; + snd_pcm_sync_stop(substream); err = substream->ops->prepare(substream); if (err < 0) return err; -- cgit From fabb26dcd104027b971c018275fe40f2ebe09ae3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 17 Nov 2019 09:53:07 +0100 Subject: ALSA: pcm: Add card sync_irq field Many PCI and other drivers performs snd_pcm_period_elapsed() simply in its interrupt handler, so the sync_stop operation is just to call synchronize_irq(). Instead of putting this call multiple times, introduce the common card->sync_irq field. When this field is set, PCM core performs synchronize_irq() for sync-stop operation. Each driver just needs to copy its local IRQ number to card->sync_irq, and that's all we need. Link: https://lore.kernel.org/r/20191117085308.23915-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/init.c | 1 + sound/core/pcm_native.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/core/init.c b/sound/core/init.c index db99b7fad6ad..faa9f03c01ca 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -215,6 +215,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid, init_waitqueue_head(&card->power_sleep); #endif init_waitqueue_head(&card->remove_sleep); + card->sync_irq = -1; device_initialize(&card->card_dev); card->card_dev.parent = parent; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 163d621ff238..1fe581167b7b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -574,6 +574,8 @@ static void snd_pcm_sync_stop(struct snd_pcm_substream *substream) substream->runtime->stop_operating = false; if (substream->ops->sync_stop) substream->ops->sync_stop(substream); + else if (substream->pcm->card->sync_irq > 0) + synchronize_irq(substream->pcm->card->sync_irq); } } -- cgit From aed8c7f40882015aad45088256231babcbc24482 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 21 Nov 2019 10:26:43 +0800 Subject: ALSA: hda/realtek - Move some alc256 pintbls to fallback table We have a new Dell machine which needs to apply the quirk ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, try to use the fallback table to fix it this time. And we could remove all pintbls of alc256 for applying DELL1_MIC_NO_PRESENCE on Dell machines. Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20191121022644.8078-1-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 80f66ba85f87..4c83ed4b0d5c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7608,38 +7608,6 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x1b, 0x01011020}, {0x21, 0x02211010}), - SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0x90a60130}, - {0x14, 0x90170110}, - {0x1b, 0x01011020}, - {0x21, 0x0221101f}), - SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0x90a60160}, - {0x14, 0x90170120}, - {0x21, 0x02211030}), - SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0x90a60170}, - {0x14, 0x90170120}, - {0x21, 0x02211030}), - SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell Inspiron 5468", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0x90a60180}, - {0x14, 0x90170120}, - {0x21, 0x02211030}), - SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0xb7a60130}, - {0x14, 0x90170110}, - {0x21, 0x02211020}), - SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0x90a60130}, - {0x14, 0x90170110}, - {0x14, 0x01011020}, - {0x21, 0x0221101f}), - SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC256_STANDARD_PINS), - SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x14, 0x90170110}, - {0x1b, 0x01011020}, - {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC, {0x14, 0x90170110}, {0x1b, 0x90a70130}, @@ -7852,6 +7820,9 @@ static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, {0x19, 0x40000000}, {0x1b, 0x40000000}), + SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x19, 0x40000000}, + {0x1a, 0x40000000}), {} }; -- cgit From d64ebdbfd4f71406f58210f5ccb16977b4cd31d2 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 21 Nov 2019 10:26:44 +0800 Subject: ALSA: hda/realtek - Move some alc236 pintbls to fallback table We have a new Dell machine which needs to apply the quirk ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, try to use the fallback table to fix it this time. And we could remove all pintbls of alc236 for applying DELL1_MIC_NO_PRESENCE on Dell machines. Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20191121022644.8078-2-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4c83ed4b0d5c..4ebe104cb592 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7512,20 +7512,6 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x19, 0x02a11020}, {0x1a, 0x02a11030}, {0x21, 0x0221101f}), - SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0x90a60140}, - {0x14, 0x90170110}, - {0x21, 0x02211020}), - SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0x90a60140}, - {0x14, 0x90170150}, - {0x21, 0x02211020}), - SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x21, 0x02211020}), - SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0x40000000}, - {0x14, 0x90170110}, - {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x14, 0x90170110}, {0x21, 0x02211020}), @@ -7823,6 +7809,9 @@ static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x19, 0x40000000}, {0x1a, 0x40000000}), + SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x19, 0x40000000}, + {0x1a, 0x40000000}), {} }; -- cgit From 695d1ec3994f9de2cefae80ee2087c95d2e5a2f3 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 21 Nov 2019 10:54:27 +0800 Subject: ALSA: hda/realtek - Enable the headset-mic on a Xiaomi's laptop The headset on this machine is not defined, after applying the quirk ALC256_FIXUP_ASUS_HEADSET_MIC, the headset-mic works well BugLink: https://bugs.launchpad.net/bugs/1846148 Cc: Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20191121025427.8856-1-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4ebe104cb592..bd0c767981b1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7248,6 +7248,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS), SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ + SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), #if 0 -- cgit From ce3cba788a1b7b8aed9380c3035d9e850884bd2d Mon Sep 17 00:00:00 2001 From: "Geoffrey D. Bennett" Date: Mon, 11 Nov 2019 00:13:56 +1030 Subject: ALSA: usb-audio: Fix Scarlett 6i6 Gen 2 port data The s6i6_gen2_info.ports[] array had the Mixer and PCM port type entries in the wrong place. Use designators to explicitly specify the array elements being set. Fixes: 9e4d5c1be21f ("ALSA: usb-audio: Scarlett Gen 2 mixer interface") Signed-off-by: Geoffrey D. Bennett Tested-by: Alex Fellows Tested-by: Markus Schroetter Cc: Link: https://lore.kernel.org/r/20191110134356.GA31589@b4.vu Signed-off-by: Takashi Iwai --- sound/usb/mixer_scarlett_gen2.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 7d460b1f1735..94b903d95afa 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -261,34 +261,34 @@ static const struct scarlett2_device_info s6i6_gen2_info = { }, .ports = { - { + [SCARLETT2_PORT_TYPE_NONE] = { .id = 0x000, .num = { 1, 0, 8, 8, 8 }, .src_descr = "Off", .src_num_offset = 0, }, - { + [SCARLETT2_PORT_TYPE_ANALOGUE] = { .id = 0x080, .num = { 4, 4, 4, 4, 4 }, .src_descr = "Analogue %d", .src_num_offset = 1, .dst_descr = "Analogue Output %02d Playback" }, - { + [SCARLETT2_PORT_TYPE_SPDIF] = { .id = 0x180, .num = { 2, 2, 2, 2, 2 }, .src_descr = "S/PDIF %d", .src_num_offset = 1, .dst_descr = "S/PDIF Output %d Playback" }, - { + [SCARLETT2_PORT_TYPE_MIX] = { .id = 0x300, .num = { 10, 18, 18, 18, 18 }, .src_descr = "Mix %c", .src_num_offset = 65, .dst_descr = "Mixer Input %02d Capture" }, - { + [SCARLETT2_PORT_TYPE_PCM] = { .id = 0x600, .num = { 6, 6, 6, 6, 6 }, .src_descr = "PCM %d", @@ -317,44 +317,44 @@ static const struct scarlett2_device_info s18i8_gen2_info = { }, .ports = { - { + [SCARLETT2_PORT_TYPE_NONE] = { .id = 0x000, .num = { 1, 0, 8, 8, 4 }, .src_descr = "Off", .src_num_offset = 0, }, - { + [SCARLETT2_PORT_TYPE_ANALOGUE] = { .id = 0x080, .num = { 8, 6, 6, 6, 6 }, .src_descr = "Analogue %d", .src_num_offset = 1, .dst_descr = "Analogue Output %02d Playback" }, - { + [SCARLETT2_PORT_TYPE_SPDIF] = { + .id = 0x180, /* S/PDIF outputs aren't available at 192KHz * but are included in the USB mux I/O * assignment message anyway */ - .id = 0x180, .num = { 2, 2, 2, 2, 2 }, .src_descr = "S/PDIF %d", .src_num_offset = 1, .dst_descr = "S/PDIF Output %d Playback" }, - { + [SCARLETT2_PORT_TYPE_ADAT] = { .id = 0x200, .num = { 8, 0, 0, 0, 0 }, .src_descr = "ADAT %d", .src_num_offset = 1, }, - { + [SCARLETT2_PORT_TYPE_MIX] = { .id = 0x300, .num = { 10, 18, 18, 18, 18 }, .src_descr = "Mix %c", .src_num_offset = 65, .dst_descr = "Mixer Input %02d Capture" }, - { + [SCARLETT2_PORT_TYPE_PCM] = { .id = 0x600, .num = { 20, 18, 18, 14, 10 }, .src_descr = "PCM %d", @@ -387,20 +387,20 @@ static const struct scarlett2_device_info s18i20_gen2_info = { }, .ports = { - { + [SCARLETT2_PORT_TYPE_NONE] = { .id = 0x000, .num = { 1, 0, 8, 8, 6 }, .src_descr = "Off", .src_num_offset = 0, }, - { + [SCARLETT2_PORT_TYPE_ANALOGUE] = { .id = 0x080, .num = { 8, 10, 10, 10, 10 }, .src_descr = "Analogue %d", .src_num_offset = 1, .dst_descr = "Analogue Output %02d Playback" }, - { + [SCARLETT2_PORT_TYPE_SPDIF] = { /* S/PDIF outputs aren't available at 192KHz * but are included in the USB mux I/O * assignment message anyway @@ -411,21 +411,21 @@ static const struct scarlett2_device_info s18i20_gen2_info = { .src_num_offset = 1, .dst_descr = "S/PDIF Output %d Playback" }, - { + [SCARLETT2_PORT_TYPE_ADAT] = { .id = 0x200, .num = { 8, 8, 8, 4, 0 }, .src_descr = "ADAT %d", .src_num_offset = 1, .dst_descr = "ADAT Output %d Playback" }, - { + [SCARLETT2_PORT_TYPE_MIX] = { .id = 0x300, .num = { 10, 18, 18, 18, 18 }, .src_descr = "Mix %c", .src_num_offset = 65, .dst_descr = "Mixer Input %02d Capture" }, - { + [SCARLETT2_PORT_TYPE_PCM] = { .id = 0x600, .num = { 20, 18, 18, 14, 10 }, .src_descr = "PCM %d", -- cgit From 9435f2bb66874a0c4dd25e7c978957a7ca2c93b1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 22 Nov 2019 12:28:40 +0100 Subject: ALSA: usb-audio: Fix NULL dereference at parsing BADD snd_usb_mixer_controls_badd() that parses UAC3 BADD profiles misses a NULL check for the given interfaces. When a malformed USB descriptor is passed, this may lead to an Oops, as spotted by syzkaller. Skip the iteration if the interface doesn't exist for avoiding the crash. Fixes: 17156f23e93c ("ALSA: usb: add UAC3 BADD profiles support") Reported-by: syzbot+a36ab65c6653d7ccdd62@syzkaller.appspotmail.com Suggested-by: Dan Carpenter Cc: Link: https://lore.kernel.org/r/20191122112840.24797-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 45eee5cc312e..6cd4ff09c5ee 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2930,6 +2930,9 @@ static int snd_usb_mixer_controls_badd(struct usb_mixer_interface *mixer, continue; iface = usb_ifnum_to_if(dev, intf); + if (!iface) + continue; + num = iface->num_altsetting; if (num < 2) -- cgit From d60229d84846a8399257006af9c5444599f64361 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 22 Nov 2019 13:13:54 +0000 Subject: ALSA: cs4236: fix error return comparison of an unsigned integer The return from pnp_irq is an unsigned integer type resource_size_t and hence the error check for a positive non-error code is always going to be true. A check for a non-failure return from pnp_irq should in fact be for (resource_size_t)-1 rather than >= 0. Addresses-Coverity: ("Unsigned compared against 0") Fixes: a9824c868a2c ("[ALSA] Add CS4232 PnP BIOS support") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20191122131354.58042-1-colin.king@canonical.com Signed-off-by: Takashi Iwai --- sound/isa/cs423x/cs4236.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 78dd213589b4..fa3c39cff5f8 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -278,7 +278,8 @@ static int snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev) } else { mpu_port[dev] = pnp_port_start(pdev, 0); if (mpu_irq[dev] >= 0 && - pnp_irq_valid(pdev, 0) && pnp_irq(pdev, 0) >= 0) { + pnp_irq_valid(pdev, 0) && + pnp_irq(pdev, 0) != (resource_size_t)-1) { mpu_irq[dev] = pnp_irq(pdev, 0); } else { mpu_irq[dev] = -1; /* disable interrupt */ -- cgit From 5a858e79c911330678b5a9be91a24830e94a0dc9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 22 Nov 2019 14:20:00 +0100 Subject: ALSA: hda - Disable audio component for legacy Nvidia HDMI codecs The old Nvidia chips have multiple HD-audio codecs on the same HD-audio controller, and this doesn't work as expected with the current audio component binding that is implemented under the one-codec-per- controller assumption; at the probe time, the driver leads to several kernel WARNING messages. For the proper support, we may change the pin2port and port2pin to traverse the codec list per the given pin number, but this needs more development and testing. As a quick workaround, instead, this patch drops the binding in the audio side for these legacy chips since the audio component support in nouveau graphics driver is still not merged (hence it's basically unused). BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=205625 Fixes: ade49db337a9 ("ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI") Link: https://lore.kernel.org/r/20191122132000.4460-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 55d20e40a195..9063bf88689f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -3574,8 +3574,6 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec) codec->link_down_at_suspend = 1; - generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin); - return 0; } -- cgit From 10a9594563415855bd99678ea4f91dea792e5499 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 22 Nov 2019 14:26:24 +0100 Subject: ALSA: hda/hdmi - Clear codec->relaxed_resume flag at unbinding The HDMI codec may leave codec->relaxed_resume flag set even after unbinding. Clear it unconditionally. It's very unlikely that this actually matters in the real use case, so just a fix for consistency. Fixes: ade49db337a9 ("ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI") Link: https://lore.kernel.org/r/20191122132624.5482-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 9063bf88689f..bffde594e204 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2361,8 +2361,8 @@ static void generic_hdmi_free(struct hda_codec *codec) snd_hdac_acomp_exit(&codec->bus->core); } else if (codec_has_acomp(codec)) { snd_hdac_acomp_register_notifier(&codec->bus->core, NULL); - codec->relaxed_resume = 0; } + codec->relaxed_resume = 0; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); -- cgit From 3b1c952c951d5ae91821386d692bc291e87a17b1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Nov 2019 20:07:08 +0100 Subject: ASoC: pcm: Make ioctl ops optional Now PCM core accepts the NULL ioctl ops as default, and passing a proper ioctl ops is no longer mandatory. Adjust soc_new_pcm() to allow also the NULL for component ioctl ops, too. Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191121190709.29121-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/soc-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 493a2e80e893..4dd13c9249ab 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -3005,7 +3005,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.hw_free = dpcm_fe_dai_hw_free; rtd->ops.close = dpcm_fe_dai_close; rtd->ops.pointer = soc_pcm_pointer; - rtd->ops.ioctl = snd_soc_pcm_component_ioctl; } else { rtd->ops.open = soc_pcm_open; rtd->ops.hw_params = soc_pcm_hw_params; @@ -3014,12 +3013,13 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.hw_free = soc_pcm_hw_free; rtd->ops.close = soc_pcm_close; rtd->ops.pointer = soc_pcm_pointer; - rtd->ops.ioctl = snd_soc_pcm_component_ioctl; } for_each_rtd_components(rtd, rtdcom, component) { const struct snd_soc_component_driver *drv = component->driver; + if (drv->ioctl) + rtd->ops.ioctl = snd_soc_pcm_component_ioctl; if (drv->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; if (drv->page) -- cgit From 1e5ddb6ba73894e6186e6379dde870979852af6d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Nov 2019 20:07:09 +0100 Subject: ASoC: component: Add sync_stop PCM ops Add the support of the new PCM sync_stop ops in ASoC component. It's optional and can be NULL unless you need the sync operation. Acked-by: Mark Brown Link: https://lore.kernel.org/r/20191121190709.29121-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/soc-component.c | 19 +++++++++++++++++++ sound/soc/soc-pcm.c | 2 ++ 2 files changed, 21 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 98ef0666add2..58c1320a3521 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -444,6 +444,25 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl(substream, cmd, arg); } +int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + struct snd_soc_rtdcom_list *rtdcom; + int ret; + + for_each_rtd_components(rtd, rtdcom, component) { + if (component->driver->ioctl) { + ret = component->driver->sync_stop(component, + substream); + if (ret < 0) + return ret; + } + } + + return 0; +} + int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, int channel, unsigned long pos, void __user *buf, unsigned long bytes) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4dd13c9249ab..4457ac374a0e 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -3020,6 +3020,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (drv->ioctl) rtd->ops.ioctl = snd_soc_pcm_component_ioctl; + if (drv->sync_stop) + rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop; if (drv->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; if (drv->page) -- cgit From c037239c2373f79613dac32d0fb20c07f12f719b Mon Sep 17 00:00:00 2001 From: Andrew Gabbasov Date: Fri, 22 Nov 2019 11:52:17 -0600 Subject: ALSA: aloop: Remove redundant locking in timer open function loopback_parse_timer_id() uses snd_card_ref(), that can lock on mutex, also snd_timer_instance_new() uses non-atomic allocation, that can sleep. So, both functions can not be called from loopback_snd_timer_open() with cable->lock spinlock locked. Moreover, most part of loopback_snd_timer_open() function body works when the opposite stream of the same cable does not yet exist, and the current stream is not yet completely open and can't be running, so existing locking of loopback->cable_lock mutex is enough to protect from conflicts with simultaneous opening or closing. Locking of cable->lock spinlock is not needed in this case. Fixes: 26c53379f98d ("ALSA: aloop: Support selection of snd_timer instead of jiffies") Signed-off-by: Andrew Gabbasov Link: https://lore.kernel.org/r/20191122175218.17187-1-andrew_gabbasov@mentor.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 1408403f727a..6408932f5f72 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -1107,20 +1107,18 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm) struct snd_timer_instance *timeri; struct loopback_cable *cable = dpcm->cable; - spin_lock_irq(&cable->lock); - /* check if timer was already opened. It is only opened once * per playback and capture subdevice (aka cable). */ if (cable->snd_timer.instance) - goto unlock; + goto exit; err = loopback_parse_timer_id(dpcm->loopback->timer_source, &tid); if (err < 0) { pcm_err(dpcm->substream->pcm, "Parsing timer source \'%s\' failed with %d", dpcm->loopback->timer_source, err); - goto unlock; + goto exit; } cable->snd_timer.stream = dpcm->substream->stream; @@ -1129,7 +1127,7 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm) timeri = snd_timer_instance_new(dpcm->loopback->card->id); if (!timeri) { err = -ENOMEM; - goto unlock; + goto exit; } /* The callback has to be called from another tasklet. If * SNDRV_TIMER_IFLG_FAST is specified it will be called from the @@ -1148,10 +1146,9 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm) tasklet_init(&cable->snd_timer.event_tasklet, loopback_snd_timer_tasklet, (unsigned long)timeri); - /* snd_timer_close() and snd_timer_open() should not be called with - * locked spinlock because both functions can block on a mutex. The - * mutex loopback->cable_lock is kept locked. Therefore snd_timer_open() - * cannot be called a second time by the other device of the same cable. + /* The mutex loopback->cable_lock is kept locked. + * Therefore snd_timer_open() cannot be called a second time + * by the other device of the same cable. * Therefore the following issue cannot happen: * [proc1] Call loopback_timer_open() -> * Unlock cable->lock for snd_timer_close/open() call @@ -1160,9 +1157,7 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm) * [proc1] Call snd_timer_open() and overwrite running timer * instance */ - spin_unlock_irq(&cable->lock); err = snd_timer_open(timeri, &cable->snd_timer.id, current->pid); - spin_lock_irq(&cable->lock); if (err < 0) { pcm_err(dpcm->substream->pcm, "snd_timer_open (%d,%d,%d) failed with %d", @@ -1171,14 +1166,12 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm) cable->snd_timer.id.subdevice, err); snd_timer_instance_free(timeri); - goto unlock; + goto exit; } cable->snd_timer.instance = timeri; -unlock: - spin_unlock_irq(&cable->lock); - +exit: return err; } -- cgit From 9314e44f455c8b46d08b2d379cb9e8fba5767207 Mon Sep 17 00:00:00 2001 From: Andrew Gabbasov Date: Fri, 22 Nov 2019 11:52:18 -0600 Subject: ALSA: aloop: Avoid unexpected timer event callback tasklets loopback_snd_timer_close_cable() function waits until all scheduled tasklets are completed, but the timer is closed after that and can generate more event callbacks, scheduling new tasklets, that will not be synchronized with cable closing. Move tasklet_kill() call to be executed after snd_timer_close() call to avoid such case. Fixes: 26c53379f98d ("ALSA: aloop: Support selection of snd_timer instead of jiffies") Signed-off-by: Andrew Gabbasov Link: https://lore.kernel.org/r/20191122175218.17187-2-andrew_gabbasov@mentor.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 6408932f5f72..0ebfbe70db00 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -302,15 +302,16 @@ static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm) if (!cable->snd_timer.instance) return 0; - /* wait till drain tasklet has finished if requested */ - tasklet_kill(&cable->snd_timer.event_tasklet); - /* will only be called from free_cable() when other stream was * already closed. Other stream cannot be reopened as long as * loopback->cable_lock is locked. Therefore no need to lock * cable->lock; */ snd_timer_close(cable->snd_timer.instance); + + /* wait till drain tasklet has finished if requested */ + tasklet_kill(&cable->snd_timer.event_tasklet); + snd_timer_instance_free(cable->snd_timer.instance); memset(&cable->snd_timer, 0, sizeof(cable->snd_timer)); -- cgit From ef8e14794308a428b194f8b06ad9ae06b43466e4 Mon Sep 17 00:00:00 2001 From: Nilkanth Ahirrao Date: Thu, 21 Nov 2019 12:10:23 +0100 Subject: ASoC: rsnd: fix DALIGN register for SSIU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current driver only sets 0x76543210 and 0x67452301 for DALIGN. This doesn’t work well for TDM split and ex-split mode for all SSIU. This patch programs the DALIGN registers based on the SSIU number. Cc: Kuninori Morimoto Cc: Jiada Wang Cc: Andrew Gabbasov Fixes: a914e44693d41b ("ASoC: rsnd: more clear rsnd_get_dalign() for DALIGN") Signed-off-by: Nilkanth Ahirrao Signed-off-by: Eugeniu Rosca Acked-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20191121111023.10976-1-erosca@de.adit-jv.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index e9596c2096cd..a6c1cf987e6e 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -376,6 +376,17 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) */ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { + static const u32 dalign_values[8][2] = { + {0x76543210, 0x67452301}, + {0x00000032, 0x00000023}, + {0x00007654, 0x00006745}, + {0x00000076, 0x00000067}, + {0xfedcba98, 0xefcdab89}, + {0x000000ba, 0x000000ab}, + {0x0000fedc, 0x0000efcd}, + {0x000000fe, 0x000000ef}, + }; + int id = 0, inv; struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); @@ -411,13 +422,18 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) target = cmd ? cmd : ssiu; } + if (mod == ssiu) + id = rsnd_mod_id_sub(mod); + /* Non target mod or non 16bit needs normal DALIGN */ if ((snd_pcm_format_width(runtime->format) != 16) || (mod != target)) - return 0x76543210; + inv = 0; /* Target mod needs inverted DALIGN when 16bit */ else - return 0x67452301; + inv = 1; + + return dalign_values[id][inv]; } u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) -- cgit From 4e01e5dbba96f731119f3f1a6bf51b54c98c5940 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 20 Nov 2019 18:44:34 +0100 Subject: ASoC: improve the DMI long card code in asoc-core Add append_dmi_string() function and make the code more readable. Signed-off-by: Jaroslav Kysela Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191120174435.30920-1-perex@perex.cz Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 66 ++++++++++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cc0ef0fcc005..a1f4d64a0a18 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1718,6 +1718,23 @@ static int is_dmi_valid(const char *field) return 1; } +/* + * Append a string to card->dmi_longname with character cleanups. + */ +static void append_dmi_string(struct snd_soc_card *card, const char *str) +{ + char *dst = card->dmi_longname; + size_t dst_len = sizeof(card->dmi_longname); + size_t len; + + len = strlen(dst); + snprintf(dst + len, dst_len - len, "-%s", str); + + len++; /* skip the separator "-" */ + if (len < dst_len) + cleanup_dmi_name(dst + len); +} + /** * snd_soc_set_dmi_name() - Register DMI names to card * @card: The card to register DMI names @@ -1752,61 +1769,36 @@ static int is_dmi_valid(const char *field) int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) { const char *vendor, *product, *product_version, *board; - size_t longname_buf_size = sizeof(card->snd_card->longname); - size_t len; if (card->long_name) return 0; /* long name already set by driver or from DMI */ - /* make up dmi long name as: vendor.product.version.board */ + /* make up dmi long name as: vendor-product-version-board */ vendor = dmi_get_system_info(DMI_BOARD_VENDOR); if (!vendor || !is_dmi_valid(vendor)) { dev_warn(card->dev, "ASoC: no DMI vendor name!\n"); return 0; } - snprintf(card->dmi_longname, sizeof(card->snd_card->longname), - "%s", vendor); + snprintf(card->dmi_longname, sizeof(card->dmi_longname), "%s", vendor); cleanup_dmi_name(card->dmi_longname); product = dmi_get_system_info(DMI_PRODUCT_NAME); if (product && is_dmi_valid(product)) { - len = strlen(card->dmi_longname); - snprintf(card->dmi_longname + len, - longname_buf_size - len, - "-%s", product); - - len++; /* skip the separator "-" */ - if (len < longname_buf_size) - cleanup_dmi_name(card->dmi_longname + len); + append_dmi_string(card, product); /* * some vendors like Lenovo may only put a self-explanatory * name in the product version field */ product_version = dmi_get_system_info(DMI_PRODUCT_VERSION); - if (product_version && is_dmi_valid(product_version)) { - len = strlen(card->dmi_longname); - snprintf(card->dmi_longname + len, - longname_buf_size - len, - "-%s", product_version); - - len++; - if (len < longname_buf_size) - cleanup_dmi_name(card->dmi_longname + len); - } + if (product_version && is_dmi_valid(product_version)) + append_dmi_string(card, product_version); } board = dmi_get_system_info(DMI_BOARD_NAME); if (board && is_dmi_valid(board)) { - len = strlen(card->dmi_longname); - snprintf(card->dmi_longname + len, - longname_buf_size - len, - "-%s", board); - - len++; - if (len < longname_buf_size) - cleanup_dmi_name(card->dmi_longname + len); + append_dmi_string(card, board); } else if (!product) { /* fall back to using legacy name */ dev_warn(card->dev, "ASoC: no DMI board/product name!\n"); @@ -1814,16 +1806,8 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) } /* Add flavour to dmi long name */ - if (flavour) { - len = strlen(card->dmi_longname); - snprintf(card->dmi_longname + len, - longname_buf_size - len, - "-%s", flavour); - - len++; - if (len < longname_buf_size) - cleanup_dmi_name(card->dmi_longname + len); - } + if (flavour) + append_dmi_string(card, flavour); /* set the card long name */ card->long_name = card->dmi_longname; -- cgit From 39870b0dec68ed7dd814beb697e541670975c7d8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 20 Nov 2019 18:44:35 +0100 Subject: ASoC: DMI long name - avoid to add board name if matches with product name Current code: LENOVO-20QE000VMC-ThinkPadX1Carbon7th-20QE000VMC With the patch: LENOVO-20QE000VMC-ThinkPadX1Carbon7th Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20191120174435.30920-2-perex@perex.cz Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a1f4d64a0a18..062653ab03a3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1798,7 +1798,8 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) board = dmi_get_system_info(DMI_BOARD_NAME); if (board && is_dmi_valid(board)) { - append_dmi_string(card, board); + if (!product || strcasecmp(board, product)) + append_dmi_string(card, board); } else if (!product) { /* fall back to using legacy name */ dev_warn(card->dev, "ASoC: no DMI board/product name!\n"); -- cgit From c6b6fc206586cc07a18595d2a3d815a806a057d0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 24 Nov 2019 09:39:24 +0100 Subject: ALSA: aloop: Fix dependency on timer API An explicit Kconfig dependency is missing for the recent addition of the timer support. CONFIG_SND_TIMER isn't always selected by SND_PCM. Fixes: 26c53379f98d ("ALSA: aloop: Support selection of snd_timer instead of jiffies") Reported-by: kbuild test robot Link: https://lore.kernel.org/r/20191124083924.14049-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 15d6d46acf9c..577c8e03ec4d 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -92,6 +92,7 @@ config SND_DUMMY config SND_ALOOP tristate "Generic loopback driver (PCM)" select SND_PCM + select SND_TIMER help Say 'Y' or 'M' to include support for the PCM loopback device. This module returns played samples back to the user space using -- cgit From 436e25505f3458cc92c7f3c985e9cbc198a98209 Mon Sep 17 00:00:00 2001 From: Jian-Hong Pan Date: Mon, 25 Nov 2019 17:34:06 +0800 Subject: ALSA: hda/realtek - Enable internal speaker of ASUS UX431FLC Laptops like ASUS UX431FLC and UX431FL can share the same audio quirks. But UX431FLC needs one more step to enable the internal speaker: Pull the GPIO from CODEC to initialize the AMP. Fixes: 60083f9e94b2 ("ALSA: hda/realtek - Enable internal speaker & headset mic of ASUS UX431FL") Signed-off-by: Jian-Hong Pan Cc: Link: https://lore.kernel.org/r/20191125093405.5702-1-jian-hong@endlessm.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bd0c767981b1..d2bf70a1d2fd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5892,6 +5892,7 @@ enum { ALC299_FIXUP_PREDATOR_SPK, ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC, ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, + ALC294_FIXUP_ASUS_INTSPK_GPIO, }; static const struct hda_fixup alc269_fixups[] = { @@ -6982,6 +6983,13 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE }, + [ALC294_FIXUP_ASUS_INTSPK_GPIO] = { + .type = HDA_FIXUP_FUNC, + /* The GPIO must be pulled to initialize the AMP */ + .v.func = alc_fixup_gpio4, + .chained = true, + .chain_id = ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -7141,7 +7149,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_INTSPK_GPIO), SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC), -- cgit From bf2aa5cadd1c7bb91af4b5b1218e643cfffb5c9a Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Sun, 24 Nov 2019 13:35:44 +0100 Subject: ALSA: usb-audio: Fix Focusrite Scarlett 6i6 gen1 - input handling The Scarlett 6i6 has no padding on rear inputs 3/4 but a gainstage. This patch introduces this functionality as to be seen in the mac or windows scarlett control. The correct address could already be found in the dump info, but was never used. Without this patch inputs 3/4 are quite unusable else. Signed-off-by: Jens Verwiebe Link: https://lore.kernel.org/r/384d65cd-5e87-91eb-9fc3-e57226f534c6@jensverwiebe.de Signed-off-by: Takashi Iwai --- sound/usb/mixer_scarlett.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c index 83715fd8dfd6..9d10cbf1b5ed 100644 --- a/sound/usb/mixer_scarlett.c +++ b/sound/usb/mixer_scarlett.c @@ -142,6 +142,7 @@ enum { SCARLETT_OUTPUTS, SCARLETT_SWITCH_IMPEDANCE, SCARLETT_SWITCH_PAD, + SCARLETT_SWITCH_GAIN, }; enum { @@ -192,6 +193,15 @@ static const struct scarlett_mixer_elem_enum_info opt_pad = { } }; +static const struct scarlett_mixer_elem_enum_info opt_gain = { + .start = 0, + .len = 2, + .offsets = {}, + .names = (char const * const []){ + "Lo", "Hi" + } +}; + static const struct scarlett_mixer_elem_enum_info opt_impedance = { .start = 0, .len = 2, @@ -652,8 +662,8 @@ static struct scarlett_device_info s6i6_info = { { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, - { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, - { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 3, .type = SCARLETT_SWITCH_GAIN, .name = NULL}, + { .num = 4, .type = SCARLETT_SWITCH_GAIN, .name = NULL}, }, .matrix_mux_init = { @@ -883,6 +893,15 @@ static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, if (err < 0) return err; break; + case SCARLETT_SWITCH_GAIN: + sprintf(mx, "Input %d Gain Switch", ctl->num); + err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, + scarlett_ctl_enum_resume, 0x01, + 0x08, ctl->num, USB_MIXER_S16, 1, mx, + &opt_gain, &elem); + if (err < 0) + return err; + break; } } -- cgit