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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 24 ++++++++---------------- 2 files changed, 8 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index f264c6509f00..d93cb46c536d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1148,7 +1148,6 @@ struct snd_soc_pcm_runtime { struct list_head component_list; /* list of connected components */ /* bit field */ - unsigned int dev_registered:1; unsigned int pop_wait:1; unsigned int fe_compr:1; /* for Dynamic PCM */ }; 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/dmaengine_pcm.h | 5 +++ sound/core/pcm_dmaengine.c | 83 +++++++++++++++++++++++++++++++++++ sound/soc/soc-generic-dmaengine-pcm.c | 61 +++---------------------- 3 files changed, 94 insertions(+), 55 deletions(-) (limited to 'sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index c679f6116580..b65220685920 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -83,6 +83,11 @@ void snd_dmaengine_pcm_set_config_from_dai_data( const struct snd_dmaengine_dai_dma_data *dma_data, struct dma_slave_config *config); +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); /* * Try to request the DMA channel using compat_request_channel or 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc-component.h | 34 ++++++++++++++++++++++++++++ sound/soc/soc-component.c | 52 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 9 ++++---- 3 files changed, 91 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 1a832695f69c..a6a3b696d5b0 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -70,6 +70,40 @@ struct snd_soc_component_driver { int (*set_bias_level)(struct snd_soc_component *component, enum snd_soc_bias_level level); + int (*open)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*close)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*ioctl)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned int cmd, void *arg); + int (*hw_params)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); + int (*hw_free)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*prepare)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*trigger)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd); + snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*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); + int (*copy_user)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int channel, + unsigned long pos, void __user *buf, + unsigned long bytes); + struct page *(*page)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned long offset); + int (*mmap)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma); + const struct snd_pcm_ops *ops; const struct snd_compr_ops *compr_ops; 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 v1.2.3 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 --- include/sound/soc-component.h | 6 ++++++ sound/soc/soc-component.c | 11 +++++++++++ 2 files changed, 17 insertions(+) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index a6a3b696d5b0..aa2e2cbc1ee5 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -46,10 +46,16 @@ struct snd_soc_component_driver { int (*write)(struct snd_soc_component *component, unsigned int reg, unsigned int val); + /* remove me */ /* pcm creation and destruction */ int (*pcm_new)(struct snd_soc_pcm_runtime *rtd); void (*pcm_free)(struct snd_pcm *pcm); + int (*pcm_construct)(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd); + void (*pcm_destruct)(struct snd_soc_component *component, + struct snd_pcm *pcm); + /* component wide operations */ int (*set_sysclk)(struct snd_soc_component *component, int clk_id, int source, unsigned int freq, int dir); 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 v1.2.3 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 --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 12 ++++++++++++ 2 files changed, 17 insertions(+) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index d93cb46c536d..32748f78060a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1390,6 +1390,11 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm) mutex_unlock(&dapm->card->dapm_mutex); } +/* bypass */ +int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned int cmd, void *arg); + #include #endif 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/pxa2xx-lib.h | 26 +++++++++++++-- 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 ++++++-- 6 files changed, 135 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/include/sound/pxa2xx-lib.h b/include/sound/pxa2xx-lib.h index 6758fc12fa84..0feaf16e6ac0 100644 --- a/include/sound/pxa2xx-lib.h +++ b/include/sound/pxa2xx-lib.h @@ -10,6 +10,7 @@ struct snd_pcm_substream; struct snd_pcm_hw_params; struct snd_soc_pcm_runtime; struct snd_pcm; +struct snd_soc_component; extern int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); @@ -23,8 +24,29 @@ extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); extern int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream); extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm); -extern int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd); -extern const struct snd_pcm_ops pxa2xx_pcm_ops; +extern void pxa2xx_soc_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm); +extern int pxa2xx_soc_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd); +extern int pxa2xx_soc_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +extern int pxa2xx_soc_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd); +extern snd_pcm_uframes_t +pxa2xx_soc_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma); /* AC97 */ 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc-component.h | 5 --- sound/soc/soc-component.c | 77 ------------------------------------------- sound/soc/soc-pcm.c | 10 ++---- 3 files changed, 3 insertions(+), 89 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index aa2e2cbc1ee5..6aa3ecb7b6d3 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -46,11 +46,7 @@ struct snd_soc_component_driver { int (*write)(struct snd_soc_component *component, unsigned int reg, unsigned int val); - /* remove me */ /* pcm creation and destruction */ - int (*pcm_new)(struct snd_soc_pcm_runtime *rtd); - void (*pcm_free)(struct snd_pcm *pcm); - int (*pcm_construct)(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd); void (*pcm_destruct)(struct snd_soc_component *component, @@ -110,7 +106,6 @@ struct snd_soc_component_driver { struct snd_pcm_substream *substream, struct vm_area_struct *vma); - const struct snd_pcm_ops *ops; const struct snd_compr_ops *compr_ops; /* probe ordering - for components with runtime dependencies */ 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 v1.2.3 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 v1.2.3 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 --- MAINTAINERS | 1 + 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 ++ 7 files changed, 770 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/MAINTAINERS b/MAINTAINERS index 296de2b51c83..8ba47cac8e83 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1002,6 +1002,7 @@ F: drivers/media/i2c/adv7842* ANALOG DEVICES INC ASOC CODEC DRIVERS M: Lars-Peter Clausen +M: Nuno Sá L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://wiki.analog.com/ W: http://ez.analog.com/community/linux-device-drivers 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/uapi/sound/sof/tokens.h | 4 ++++ sound/soc/sof/control.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 9 +++++++++ sound/soc/sof/topology.c | 13 +++++++++++++ 4 files changed, 58 insertions(+) (limited to 'sound') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index da18c9de1056..d65406f34361 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -113,4 +113,8 @@ /* ESAI */ #define SOF_TKN_IMX_ESAI_MCLK_ID 1100 +/* Led control for mute switches */ +#define SOF_TKN_MUTE_LED_USE 1300 +#define SOF_TKN_MUTE_LED_DIRECTION 1301 + #endif 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- drivers/platform/chrome/cros_ec_trace.c | 2 +- include/linux/platform_data/cros_ec_commands.h | 120 +++--- sound/soc/codecs/cros_ec_codec.c | 502 ++++++++++--------------- 3 files changed, 251 insertions(+), 373 deletions(-) (limited to 'sound') diff --git a/drivers/platform/chrome/cros_ec_trace.c b/drivers/platform/chrome/cros_ec_trace.c index 6f80ff4532ae..901850004b2b 100644 --- a/drivers/platform/chrome/cros_ec_trace.c +++ b/drivers/platform/chrome/cros_ec_trace.c @@ -98,7 +98,7 @@ TRACE_SYMBOL(EC_CMD_SB_READ_BLOCK), \ TRACE_SYMBOL(EC_CMD_SB_WRITE_BLOCK), \ TRACE_SYMBOL(EC_CMD_BATTERY_VENDOR_PARAM), \ - TRACE_SYMBOL(EC_CMD_CODEC_I2S), \ + TRACE_SYMBOL(EC_CMD_EC_CODEC_I2S_RX), \ TRACE_SYMBOL(EC_CMD_REBOOT_EC), \ TRACE_SYMBOL(EC_CMD_GET_PANIC_INFO), \ TRACE_SYMBOL(EC_CMD_ACPI_READ), \ diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 43b8f7dae4cc..261ac83bd007 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4466,92 +4466,74 @@ enum mkbp_cec_event { /*****************************************************************************/ -/* Commands for I2S recording on audio codec. */ - -#define EC_CMD_CODEC_I2S 0x00BC -#define EC_WOV_I2S_SAMPLE_RATE 48000 - -enum ec_codec_i2s_subcmd { - EC_CODEC_SET_SAMPLE_DEPTH = 0x0, - EC_CODEC_SET_GAIN = 0x1, - EC_CODEC_GET_GAIN = 0x2, - EC_CODEC_I2S_ENABLE = 0x3, - EC_CODEC_I2S_SET_CONFIG = 0x4, - EC_CODEC_I2S_SET_TDM_CONFIG = 0x5, - EC_CODEC_I2S_SET_BCLK = 0x6, - EC_CODEC_I2S_SUBCMD_COUNT = 0x7, +/* Commands for I2S RX on audio codec. */ + +#define EC_CMD_EC_CODEC_I2S_RX 0x00BC + +enum ec_codec_i2s_rx_subcmd { + EC_CODEC_I2S_RX_ENABLE = 0x0, + EC_CODEC_I2S_RX_DISABLE = 0x1, + EC_CODEC_I2S_RX_SET_GAIN = 0x2, + EC_CODEC_I2S_RX_GET_GAIN = 0x3, + EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH = 0x4, + EC_CODEC_I2S_RX_SET_DAIFMT = 0x5, + EC_CODEC_I2S_RX_SET_BCLK = 0x6, + EC_CODEC_I2S_RX_SUBCMD_COUNT, }; -enum ec_sample_depth_value { - EC_CODEC_SAMPLE_DEPTH_16 = 0, - EC_CODEC_SAMPLE_DEPTH_24 = 1, +enum ec_codec_i2s_rx_sample_depth { + EC_CODEC_I2S_RX_SAMPLE_DEPTH_16 = 0x0, + EC_CODEC_I2S_RX_SAMPLE_DEPTH_24 = 0x1, + EC_CODEC_I2S_RX_SAMPLE_DEPTH_COUNT, }; -enum ec_i2s_config { - EC_DAI_FMT_I2S = 0, - EC_DAI_FMT_RIGHT_J = 1, - EC_DAI_FMT_LEFT_J = 2, - EC_DAI_FMT_PCM_A = 3, - EC_DAI_FMT_PCM_B = 4, - EC_DAI_FMT_PCM_TDM = 5, +enum ec_codec_i2s_rx_daifmt { + EC_CODEC_I2S_RX_DAIFMT_I2S = 0x0, + EC_CODEC_I2S_RX_DAIFMT_RIGHT_J = 0x1, + EC_CODEC_I2S_RX_DAIFMT_LEFT_J = 0x2, + EC_CODEC_I2S_RX_DAIFMT_COUNT, }; -/* - * For subcommand EC_CODEC_GET_GAIN. - */ -struct __ec_align1 ec_codec_i2s_gain { +struct __ec_align1 ec_param_ec_codec_i2s_rx_set_sample_depth { + uint8_t depth; + uint8_t reserved[3]; +}; + +struct __ec_align1 ec_param_ec_codec_i2s_rx_set_gain { uint8_t left; uint8_t right; + uint8_t reserved[2]; }; -struct __ec_todo_unpacked ec_param_codec_i2s_tdm { - int16_t ch0_delay; /* 0 to 496 */ - int16_t ch1_delay; /* -1 to 496 */ - uint8_t adjacent_to_ch0; - uint8_t adjacent_to_ch1; +struct __ec_align1 ec_param_ec_codec_i2s_rx_set_daifmt { + uint8_t daifmt; + uint8_t reserved[3]; }; -struct __ec_todo_packed ec_param_codec_i2s { - /* enum ec_codec_i2s_subcmd */ - uint8_t cmd; - union { - /* - * EC_CODEC_SET_SAMPLE_DEPTH - * Value should be one of ec_sample_depth_value. - */ - uint8_t depth; - - /* - * EC_CODEC_SET_GAIN - * Value should be 0~43 for both channels. - */ - struct ec_codec_i2s_gain gain; - - /* - * EC_CODEC_I2S_ENABLE - * 1 to enable, 0 to disable. - */ - uint8_t i2s_enable; - - /* - * EC_CODEC_I2S_SET_CONFIG - * Value should be one of ec_i2s_config. - */ - uint8_t i2s_config; +struct __ec_align4 ec_param_ec_codec_i2s_rx_set_bclk { + uint32_t bclk; +}; - /* - * EC_CODEC_I2S_SET_TDM_CONFIG - * Value should be one of ec_i2s_config. - */ - struct ec_param_codec_i2s_tdm tdm_param; +struct __ec_align4 ec_param_ec_codec_i2s_rx { + uint8_t cmd; /* enum ec_codec_i2s_rx_subcmd */ + uint8_t reserved[3]; - /* - * EC_CODEC_I2S_SET_BCLK - */ - uint32_t bclk; + union { + struct ec_param_ec_codec_i2s_rx_set_sample_depth + set_sample_depth_param; + struct ec_param_ec_codec_i2s_rx_set_gain + set_gain_param; + struct ec_param_ec_codec_i2s_rx_set_daifmt + set_daifmt_param; + struct ec_param_ec_codec_i2s_rx_set_bclk + set_bclk_param; }; }; +struct __ec_align1 ec_response_ec_codec_i2s_rx_get_gain { + uint8_t left; + uint8_t right; +}; /*****************************************************************************/ /* System commands */ 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 v1.2.3 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 --- drivers/platform/chrome/cros_ec_trace.c | 1 + include/linux/platform_data/cros_ec_commands.h | 49 ++++++++++++++++------ sound/soc/codecs/cros_ec_codec.c | 57 ++++++++++++++------------ 3 files changed, 68 insertions(+), 39 deletions(-) (limited to 'sound') diff --git a/drivers/platform/chrome/cros_ec_trace.c b/drivers/platform/chrome/cros_ec_trace.c index 901850004b2b..e73bb6a8b00e 100644 --- a/drivers/platform/chrome/cros_ec_trace.c +++ b/drivers/platform/chrome/cros_ec_trace.c @@ -98,6 +98,7 @@ TRACE_SYMBOL(EC_CMD_SB_READ_BLOCK), \ TRACE_SYMBOL(EC_CMD_SB_WRITE_BLOCK), \ TRACE_SYMBOL(EC_CMD_BATTERY_VENDOR_PARAM), \ + TRACE_SYMBOL(EC_CMD_EC_CODEC_DMIC), \ TRACE_SYMBOL(EC_CMD_EC_CODEC_I2S_RX), \ TRACE_SYMBOL(EC_CMD_REBOOT_EC), \ TRACE_SYMBOL(EC_CMD_GET_PANIC_INFO), \ diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 261ac83bd007..58e460c015ef 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4466,18 +4466,48 @@ enum mkbp_cec_event { /*****************************************************************************/ +/* Commands for DMIC on audio codec. */ +#define EC_CMD_EC_CODEC_DMIC 0x00BC + +enum ec_codec_dmic_subcmd { + EC_CODEC_DMIC_SET_GAIN = 0x0, + EC_CODEC_DMIC_GET_GAIN = 0x1, + EC_CODEC_DMIC_SUBCMD_COUNT, +}; + +struct __ec_align1 ec_param_ec_codec_dmic_set_gain { + uint8_t left; + uint8_t right; + uint8_t reserved[2]; +}; + +struct __ec_align4 ec_param_ec_codec_dmic { + uint8_t cmd; /* enum ec_codec_dmic_subcmd */ + uint8_t reserved[3]; + + union { + struct ec_param_ec_codec_dmic_set_gain + set_gain_param; + }; +}; + +struct __ec_align1 ec_response_ec_codec_dmic_get_gain { + uint8_t left; + uint8_t right; +}; + +/*****************************************************************************/ + /* Commands for I2S RX on audio codec. */ -#define EC_CMD_EC_CODEC_I2S_RX 0x00BC +#define EC_CMD_EC_CODEC_I2S_RX 0x00BD enum ec_codec_i2s_rx_subcmd { EC_CODEC_I2S_RX_ENABLE = 0x0, EC_CODEC_I2S_RX_DISABLE = 0x1, - EC_CODEC_I2S_RX_SET_GAIN = 0x2, - EC_CODEC_I2S_RX_GET_GAIN = 0x3, - EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH = 0x4, - EC_CODEC_I2S_RX_SET_DAIFMT = 0x5, - EC_CODEC_I2S_RX_SET_BCLK = 0x6, + EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH = 0x2, + EC_CODEC_I2S_RX_SET_DAIFMT = 0x3, + EC_CODEC_I2S_RX_SET_BCLK = 0x4, EC_CODEC_I2S_RX_SUBCMD_COUNT, }; @@ -4521,8 +4551,6 @@ struct __ec_align4 ec_param_ec_codec_i2s_rx { union { struct ec_param_ec_codec_i2s_rx_set_sample_depth set_sample_depth_param; - struct ec_param_ec_codec_i2s_rx_set_gain - set_gain_param; struct ec_param_ec_codec_i2s_rx_set_daifmt set_daifmt_param; struct ec_param_ec_codec_i2s_rx_set_bclk @@ -4530,11 +4558,6 @@ struct __ec_align4 ec_param_ec_codec_i2s_rx { }; }; -struct __ec_align1 ec_response_ec_codec_i2s_rx_get_gain { - uint8_t left; - uint8_t right; -}; - /*****************************************************************************/ /* System commands */ 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- .../bindings/sound/google,cros-ec-codec.txt | 4 +- include/linux/platform_data/cros_ec_commands.h | 43 ++++++++++++++---- sound/soc/codecs/cros_ec_codec.c | 53 ++++++++++++++++------ 3 files changed, 73 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt index 1084f7f22eea..0ce9fafc78e2 100644 --- a/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt +++ b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt @@ -1,4 +1,4 @@ -* Audio codec controlled by ChromeOS EC +Audio codec controlled by ChromeOS EC Google's ChromeOS EC codec is a digital mic codec provided by the Embedded Controller (EC) and is controlled via a host-command interface. @@ -9,7 +9,6 @@ Documentation/devicetree/bindings/mfd/cros-ec.txt). Required properties: - compatible: Must contain "google,cros-ec-codec" - #sound-dai-cells: Should be 1. The cell specifies number of DAIs. -- max-dmic-gain: A number for maximum gain in dB on digital microphone. Example: @@ -21,6 +20,5 @@ cros-ec@0 { cros_ec_codec: ec-codec { compatible = "google,cros-ec-codec"; #sound-dai-cells = <1>; - max-dmic-gain = <43>; }; }; diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 3ca0fa9e92a7..21db0d4d4025 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4530,30 +4530,53 @@ struct __ec_align4 ec_response_ec_codec_get_shm_addr { #define EC_CMD_EC_CODEC_DMIC 0x00BD enum ec_codec_dmic_subcmd { - EC_CODEC_DMIC_SET_GAIN = 0x0, - EC_CODEC_DMIC_GET_GAIN = 0x1, + EC_CODEC_DMIC_GET_MAX_GAIN = 0x0, + EC_CODEC_DMIC_SET_GAIN_IDX = 0x1, + EC_CODEC_DMIC_GET_GAIN_IDX = 0x2, EC_CODEC_DMIC_SUBCMD_COUNT, }; -struct __ec_align1 ec_param_ec_codec_dmic_set_gain { - uint8_t left; - uint8_t right; +enum ec_codec_dmic_channel { + EC_CODEC_DMIC_CHANNEL_0 = 0x0, + EC_CODEC_DMIC_CHANNEL_1 = 0x1, + EC_CODEC_DMIC_CHANNEL_2 = 0x2, + EC_CODEC_DMIC_CHANNEL_3 = 0x3, + EC_CODEC_DMIC_CHANNEL_4 = 0x4, + EC_CODEC_DMIC_CHANNEL_5 = 0x5, + EC_CODEC_DMIC_CHANNEL_6 = 0x6, + EC_CODEC_DMIC_CHANNEL_7 = 0x7, + EC_CODEC_DMIC_CHANNEL_COUNT, +}; + +struct __ec_align1 ec_param_ec_codec_dmic_set_gain_idx { + uint8_t channel; /* enum ec_codec_dmic_channel */ + uint8_t gain; uint8_t reserved[2]; }; +struct __ec_align1 ec_param_ec_codec_dmic_get_gain_idx { + uint8_t channel; /* enum ec_codec_dmic_channel */ + uint8_t reserved[3]; +}; + struct __ec_align4 ec_param_ec_codec_dmic { uint8_t cmd; /* enum ec_codec_dmic_subcmd */ uint8_t reserved[3]; union { - struct ec_param_ec_codec_dmic_set_gain - set_gain_param; + struct ec_param_ec_codec_dmic_set_gain_idx + set_gain_idx_param; + struct ec_param_ec_codec_dmic_get_gain_idx + get_gain_idx_param; }; }; -struct __ec_align1 ec_response_ec_codec_dmic_get_gain { - uint8_t left; - uint8_t right; +struct __ec_align1 ec_response_ec_codec_dmic_get_max_gain { + uint8_t max_gain; +}; + +struct __ec_align1 ec_response_ec_codec_dmic_get_gain_idx { + uint8_t gain; }; /*****************************************************************************/ 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 v1.2.3 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 v1.2.3 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 --- drivers/platform/chrome/cros_ec_trace.c | 1 + include/linux/platform_data/cros_ec_commands.h | 69 +++ sound/soc/codecs/Kconfig | 2 + sound/soc/codecs/cros_ec_codec.c | 700 ++++++++++++++++++++++++- 4 files changed, 770 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/drivers/platform/chrome/cros_ec_trace.c b/drivers/platform/chrome/cros_ec_trace.c index 2ea0d4e0d54d..5af1d66d9eca 100644 --- a/drivers/platform/chrome/cros_ec_trace.c +++ b/drivers/platform/chrome/cros_ec_trace.c @@ -101,6 +101,7 @@ TRACE_SYMBOL(EC_CMD_EC_CODEC), \ TRACE_SYMBOL(EC_CMD_EC_CODEC_DMIC), \ TRACE_SYMBOL(EC_CMD_EC_CODEC_I2S_RX), \ + TRACE_SYMBOL(EC_CMD_EC_CODEC_WOV), \ TRACE_SYMBOL(EC_CMD_REBOOT_EC), \ TRACE_SYMBOL(EC_CMD_GET_PANIC_INFO), \ TRACE_SYMBOL(EC_CMD_ACPI_READ), \ diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 21db0d4d4025..69210881ebac 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -556,6 +556,9 @@ enum host_event_code { /* Keyboard recovery combo with hardware reinitialization */ EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT = 30, + /* WoV */ + EC_HOST_EVENT_WOV = 31, + /* * The high bit of the event mask is not used as a host event code. If * it reads back as set, then the entire event mask should be @@ -4477,10 +4480,14 @@ enum ec_codec_subcmd { }; enum ec_codec_cap { + EC_CODEC_CAP_WOV_AUDIO_SHM = 0, + EC_CODEC_CAP_WOV_LANG_SHM = 1, EC_CODEC_CAP_LAST = 32, }; enum ec_codec_shm_id { + EC_CODEC_SHM_ID_WOV_AUDIO = 0x0, + EC_CODEC_SHM_ID_WOV_LANG = 0x1, EC_CODEC_SHM_ID_LAST, }; @@ -4641,6 +4648,68 @@ struct __ec_align4 ec_param_ec_codec_i2s_rx { }; }; +/*****************************************************************************/ +/* Commands for WoV on audio codec. */ + +#define EC_CMD_EC_CODEC_WOV 0x00BF + +enum ec_codec_wov_subcmd { + EC_CODEC_WOV_SET_LANG = 0x0, + EC_CODEC_WOV_SET_LANG_SHM = 0x1, + EC_CODEC_WOV_GET_LANG = 0x2, + EC_CODEC_WOV_ENABLE = 0x3, + EC_CODEC_WOV_DISABLE = 0x4, + EC_CODEC_WOV_READ_AUDIO = 0x5, + EC_CODEC_WOV_READ_AUDIO_SHM = 0x6, + EC_CODEC_WOV_SUBCMD_COUNT, +}; + +/* + * @hash is SHA256 of the whole language model. + * @total_len indicates the length of whole language model. + * @offset is the cursor from the beginning of the model. + * @buf is the packet buffer. + * @len denotes how many bytes in the buf. + */ +struct __ec_align4 ec_param_ec_codec_wov_set_lang { + uint8_t hash[32]; + uint32_t total_len; + uint32_t offset; + uint8_t buf[128]; + uint32_t len; +}; + +struct __ec_align4 ec_param_ec_codec_wov_set_lang_shm { + uint8_t hash[32]; + uint32_t total_len; +}; + +struct __ec_align4 ec_param_ec_codec_wov { + uint8_t cmd; /* enum ec_codec_wov_subcmd */ + uint8_t reserved[3]; + + union { + struct ec_param_ec_codec_wov_set_lang + set_lang_param; + struct ec_param_ec_codec_wov_set_lang_shm + set_lang_shm_param; + }; +}; + +struct __ec_align4 ec_response_ec_codec_wov_get_lang { + uint8_t hash[32]; +}; + +struct __ec_align4 ec_response_ec_codec_wov_read_audio { + uint8_t buf[128]; + uint32_t len; +}; + +struct __ec_align4 ec_response_ec_codec_wov_read_audio_shm { + uint32_t offset; + uint32_t len; +}; + /*****************************************************************************/ /* System commands */ 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc.h | 8 ++++++-- sound/soc/soc-component.c | 43 +++++++++++---------------------------- sound/soc/soc-compress.c | 52 ++++++++++++----------------------------------- sound/soc/soc-core.c | 22 ++++++++------------ sound/soc/soc-pcm.c | 49 +++++++++++++------------------------------- 5 files changed, 54 insertions(+), 120 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index d730883626dc..320dcd440dab 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -739,8 +739,12 @@ struct snd_soc_rtdcom_list { struct snd_soc_component* snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, const char *driver_name); -#define for_each_rtdcom(rtd, rtdcom) \ - list_for_each_entry(rtdcom, &(rtd)->component_list, list) +#define for_each_rtd_components(rtd, rtdcom, _component) \ + for (rtdcom = list_first_entry(&(rtd)->component_list, \ + typeof(*rtdcom), list); \ + (&rtdcom->list != &(rtd)->component_list) && \ + (_component = rtdcom->component); \ + rtdcom = list_next_entry(rtdcom, list)) struct snd_soc_dai_link_component { const char *name; 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 1 + sound/soc/intel/common/soc-acpi-intel-jsl-match.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 sound/soc/intel/common/soc-acpi-intel-jsl-match.c (limited to 'sound') diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 6c9929abd90b..4e44782862df 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -27,6 +27,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/wm8904.h | 2 +- sound/soc/codecs/cx2072x.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h index 14074405f501..88ac1870510e 100644 --- a/include/sound/wm8904.h +++ b/include/sound/wm8904.h @@ -120,7 +120,7 @@ * DRC configurations are specified with a label and a set of register * values to write (the enable bits will be ignored). At runtime an * enumerated control will be presented for each DRC block allowing - * the user to choose the configration to use. + * the user to choose the configuration to use. * * Configurations may be generated by hand or by using the DRC control * panel provided by the WISCE - see http://www.wolfsonmicro.com/wisce/ 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/uapi/sound/sof/tokens.h | 4 ++++ sound/soc/sof/topology.c | 10 ++++++++++ 2 files changed, 14 insertions(+) (limited to 'sound') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index d65406f34361..76883e6fb750 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -113,6 +113,10 @@ /* ESAI */ #define SOF_TKN_IMX_ESAI_MCLK_ID 1100 +/* Stream */ +#define SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3 1200 +#define SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3 1201 + /* Led control for mute switches */ #define SOF_TKN_MUTE_LED_USE 1300 #define SOF_TKN_MUTE_LED_DIRECTION 1301 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/hda_codec.h | 1 + sound/pci/hda/patch_hdmi.c | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 9a0393cf024c..ac18f428eda6 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -254,6 +254,7 @@ struct hda_codec { unsigned int force_pin_prefix:1; /* Add location prefix */ unsigned int link_down_at_suspend:1; /* link down at runtime suspend */ unsigned int relaxed_resume:1; /* don't resume forcibly for jack */ + unsigned int mst_no_extra_pcms:1; /* no backup PCMs for DP-MST */ #ifdef CONFIG_PM unsigned long power_on_acct; 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc-acpi.h | 2 + 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 + 7 files changed, 150 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/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index c0fb71c7b3ad..c4c997bd0379 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -60,12 +60,14 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) * @acpi_ipc_irq_index: used for BYT-CR detection * @platform: string used for HDaudio codec support * @codec_mask: used for HDAudio support + * @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver */ struct snd_soc_acpi_mach_params { u32 acpi_ipc_irq_index; const char *platform; u32 codec_mask; u32 dmic_num; + bool common_hdmi_codec_drv; }; /** 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/rt5682.h | 1 + sound/soc/codecs/rt5682.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'sound') diff --git a/include/sound/rt5682.h b/include/sound/rt5682.h index bf2ee75aabb1..bc2c31734df1 100644 --- a/include/sound/rt5682.h +++ b/include/sound/rt5682.h @@ -31,6 +31,7 @@ struct rt5682_platform_data { enum rt5682_dmic1_data_pin dmic1_data_pin; enum rt5682_dmic1_clk_pin dmic1_clk_pin; enum rt5682_jd_src jd_src; + unsigned int btndet_delay; }; #endif 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc.h | 1 + sound/soc/soc-core.c | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 320dcd440dab..daa0e100ecd9 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1328,6 +1328,7 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, int snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv); +void snd_soc_unregister_dai(struct snd_soc_dai *dai); struct snd_soc_dai *snd_soc_find_dai( const struct snd_soc_dai_link_component *dlc); 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 v1.2.3 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 --- include/sound/soc.h | 3 ++- sound/soc/soc-core.c | 5 +++-- sound/soc/soc-topology.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index daa0e100ecd9..766fa81494c3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1327,7 +1327,8 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, const char *stream_name); 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); void snd_soc_unregister_dai(struct snd_soc_dai *dai); struct snd_soc_dai *snd_soc_find_dai( 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 v1.2.3 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 --- include/sound/soc.h | 6 +++--- sound/soc/soc-core.c | 29 +++++------------------------ sound/soc/soc-topology.c | 17 ++++++++++++++++- 3 files changed, 24 insertions(+), 28 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 766fa81494c3..4e38ee656c4b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1326,9 +1326,9 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, int id, const char *name, const char *stream_name); -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); void snd_soc_unregister_dai(struct snd_soc_dai *dai); struct snd_soc_dai *snd_soc_find_dai( 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc-acpi-intel-match.h | 2 + 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 --------------- 5 files changed, 78 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/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 4e44782862df..20c0bee3b959 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -24,6 +24,8 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 --- .../devicetree/bindings/sound/tlv320aic31xx.txt | 5 +++ sound/soc/codecs/tlv320aic31xx.c | 45 ++++++++++++++++++++++ sound/soc/codecs/tlv320aic31xx.h | 8 ++++ 3 files changed, 58 insertions(+) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt index 5b3c33bb99e5..e372303697dc 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt @@ -29,6 +29,11 @@ Optional properties: 3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD If this node is not mentioned or if the value is unknown, then micbias is set to 2.0V. +- ai31xx-ocmv - output common-mode voltage setting + 0 - 1.35V, + 1 - 1.5V, + 2 - 1.65V, + 3 - 1.8V Deprecated properties: 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc-component.h | 4 ++-- sound/soc/soc-component.c | 8 +++----- sound/soc/soc-pcm.c | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 6aa3ecb7b6d3..f8fadf0e696a 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -412,7 +412,7 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, unsigned long offset); int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); -int snd_soc_pcm_component_new(struct snd_pcm *pcm); -void snd_soc_pcm_component_free(struct snd_pcm *pcm); +int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd); +void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd); #endif /* __SOC_COMPONENT_H */ 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 v1.2.3 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 v1.2.3 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 --- include/sound/soc.h | 1 + sound/soc/soc-core.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index e0855dc08d30..bd943b5d7d45 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -982,6 +982,7 @@ struct snd_soc_card { const char *name; const char *long_name; const char *driver_name; + const char *components; char dmi_longname[80]; char topology_shortname[32]; 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3