From 3f4b57ad07d9237acf1b8cff3f8bf530cacef87a Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 20 Sep 2021 16:49:39 +0200 Subject: [PATCH 01/27] ASoC: pcm512x: Mend accesses to the I2S_1 and I2S_2 registers Commit 25d27c4f68d2 ("ASoC: pcm512x: Add support for more data formats") breaks the TSE-850 device, which is using a pcm5142 in I2S and CBM_CFS mode (maybe not relevant). Without this fix, the result is: pcm512x 0-004c: Failed to set data format: -16 And after that, no sound. This fix is not 100% correct. The datasheet of at least the pcm5142 states that four bits (0xcc) in the I2S_1 register are "RSV" ("Reserved. Do not access.") and no hint is given as to what the initial values are supposed to be. So, specifying defaults for these bits is wrong. But perhaps better than a broken driver? Fixes: 25d27c4f68d2 ("ASoC: pcm512x: Add support for more data formats") Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Kirill Marinushkin Cc: Peter Ujfalusi Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Peter Rosin Signed-off-by: Peter Ujfalusi Reviewed-by: Peter Ujfalusi Link: https://lore.kernel.org/r/2d221984-7a2e-7006-0f8a-ffb5f64ee885@axentia.se Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 4dc844f3c1fc..60dee41816dc 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -116,6 +116,8 @@ static const struct reg_default pcm512x_reg_defaults[] = { { PCM512x_FS_SPEED_MODE, 0x00 }, { PCM512x_IDAC_1, 0x01 }, { PCM512x_IDAC_2, 0x00 }, + { PCM512x_I2S_1, 0x02 }, + { PCM512x_I2S_2, 0x00 }, }; static bool pcm512x_readable(struct device *dev, unsigned int reg) From 74b7ee0e7b61838a0a161a84d105aeff0d042646 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 10 Sep 2021 17:18:30 +0800 Subject: [PATCH 02/27] ASoC: fsl_xcvr: Fix channel swap issue with ARC With pause and resume test for ARC, there is occasionally channel swap issue. The reason is that currently driver set the DPATH out of reset first, then start the DMA, the first data got from FIFO may not be the Left channel. Moving DPATH out of reset operation after the dma enablement to fix this issue. Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1631265510-27384-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_xcvr.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 7ba2fd15132d..d0556c79fdb1 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -487,8 +487,9 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream, return ret; } - /* clear DPATH RESET */ + /* set DPATH RESET */ m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); + v_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, v_ctl); if (ret < 0) { dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret); @@ -590,10 +591,6 @@ static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream, val |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx); } - /* set DPATH RESET */ - mask |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); - val |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val); if (ret < 0) { dev_err(dai->dev, "Err setting DPATH RESET: %d\n", ret); @@ -643,6 +640,16 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, dev_err(dai->dev, "Failed to enable DMA: %d\n", ret); return ret; } + + /* clear DPATH RESET */ + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_DPTH_RESET(tx), + 0); + if (ret < 0) { + dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret); + return ret; + } + break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: From ceef3240f9b7e592dd8d10d619c312c7336117fa Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 24 Sep 2021 20:49:56 +0100 Subject: [PATCH 03/27] ASoC: pcm179x: Add missing entries SPI to device ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding SPI IDs for parts that only have a compatible listed. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20210924194956.46079-1-broonie@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/pcm179x-spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/pcm179x-spi.c b/sound/soc/codecs/pcm179x-spi.c index 0a542924ec5f..ebf63ea90a1c 100644 --- a/sound/soc/codecs/pcm179x-spi.c +++ b/sound/soc/codecs/pcm179x-spi.c @@ -36,6 +36,7 @@ static const struct of_device_id pcm179x_of_match[] = { MODULE_DEVICE_TABLE(of, pcm179x_of_match); static const struct spi_device_id pcm179x_spi_ids[] = { + { "pcm1792a", 0 }, { "pcm179x", 0 }, { }, }; From 0cc3687eadd0971d5d38ff90d14819d88f854960 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 24 Sep 2021 20:48:44 +0100 Subject: [PATCH 04/27] ASoC: cs4341: Add SPI device ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding SPI IDs for parts that only have a compatible listed. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Cc: patches@opensource.cirrus.com Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20210924194844.45974-1-broonie@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs4341.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c index 7d3e54d8eef3..29d05e32d341 100644 --- a/sound/soc/codecs/cs4341.c +++ b/sound/soc/codecs/cs4341.c @@ -305,12 +305,19 @@ static int cs4341_spi_probe(struct spi_device *spi) return cs4341_probe(&spi->dev); } +static const struct spi_device_id cs4341_spi_ids[] = { + { "cs4341a" }, + { } +}; +MODULE_DEVICE_TABLE(spi, cs4341_spi_ids); + static struct spi_driver cs4341_spi_driver = { .driver = { .name = "cs4341-spi", .of_match_table = of_match_ptr(cs4341_dt_ids), }, .probe = cs4341_spi_probe, + .id_table = cs4341_spi_ids, }; #endif From 42871e95a3afea8956d8cc567ea725b33a837775 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 29 Sep 2021 22:15:12 +0200 Subject: [PATCH 05/27] ASoC: nau8824: Fix headphone vs headset, button-press detection no longer working Commit 1d25684e2251 ("ASoC: nau8824: Fix open coded prefix handling") replaced the nau8824_dapm_enable_pin() helper with direct calls to snd_soc_dapm_enable_pin(), but the helper was using snd_soc_dapm_force_enable_pin() and not forcing the MICBIAS + SAR supplies on breaks headphone vs headset and button-press detection. Replace the snd_soc_dapm_enable_pin() calls with snd_soc_dapm_force_enable_pin() to fix this. Cc: stable@vger.kernel.org Fixes: 1d25684e2251 ("ASoC: nau8824: Fix open coded prefix handling") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210929201512.460360-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8824.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index db88be48c998..f946ef65a4c1 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -867,8 +867,8 @@ static void nau8824_jdet_work(struct work_struct *work) struct regmap *regmap = nau8824->regmap; int adc_value, event = 0, event_mask = 0; - snd_soc_dapm_enable_pin(dapm, "MICBIAS"); - snd_soc_dapm_enable_pin(dapm, "SAR"); + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS"); + snd_soc_dapm_force_enable_pin(dapm, "SAR"); snd_soc_dapm_sync(dapm); msleep(100); From db0767b8a6e620b99459d2e688c1983c2e5add0d Mon Sep 17 00:00:00 2001 From: Srinivasa Rao Mandadapu Date: Thu, 7 Oct 2021 19:20:19 +0530 Subject: [PATCH 06/27] ASoC: wcd938x: Fix jack detection issue This patch is to fix audio 3.5mm jack detection failure on wcd938x codec based target. Fixes: bcee7ed09b8e (ASoC: codecs: wcd938x: add Multi Button Headset Control support) Signed-off-by: Venkata Prasad Potturu Signed-off-by: Srinivasa Rao Mandadapu Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/1633614619-27026-1-git-send-email-srivasam@codeaurora.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index f0daf8defcf1..52de7d14b139 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -4144,10 +4144,10 @@ static int wcd938x_codec_set_jack(struct snd_soc_component *comp, { struct wcd938x_priv *wcd = dev_get_drvdata(comp->dev); - if (!jack) + if (jack) return wcd_mbhc_start(wcd->wcd_mbhc, &wcd->mbhc_cfg, jack); - - wcd_mbhc_stop(wcd->wcd_mbhc); + else + wcd_mbhc_stop(wcd->wcd_mbhc); return 0; } From 2577b868a48ef3601116908738efbe570451e605 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 6 Oct 2021 18:04:25 +0300 Subject: [PATCH 07/27] ASoC: Intel: bytcht_es8316: Get platform data via dev_get_platdata() Access to platform data via dev_get_platdata() getter to make code cleaner. Signed-off-by: Andy Shevchenko Acked-by: Pierre-Louis Bossart Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211006150428.16434-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 055248f104b2..b1f9c9cb3355 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -456,12 +456,12 @@ static const struct dmi_system_id byt_cht_es8316_quirk_table[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; static const char * const mic_name[] = { "in1", "in2" }; + struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); struct property_entry props[MAX_NO_PROPS] = {}; struct byt_cht_es8316_private *priv; const struct dmi_system_id *dmi_id; - struct device *dev = &pdev->dev; - struct snd_soc_acpi_mach *mach; struct fwnode_handle *fwnode; const char *platform_name; struct acpi_device *adev; @@ -476,7 +476,6 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - mach = dev->platform_data; /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { if (!strcmp(byt_cht_es8316_dais[i].codecs->name, From 6f32c521061b704c0198be3ba9834f5a64ea5605 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 6 Oct 2021 18:04:26 +0300 Subject: [PATCH 08/27] ASoC: Intel: bytcht_es8316: Use temporary variable for struct device Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211006150428.16434-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index b1f9c9cb3355..efd71e6e42b3 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -493,7 +493,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) put_device(&adev->dev); byt_cht_es8316_dais[dai_index].codecs->name = codec_name; } else { - dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); return -ENXIO; } @@ -596,7 +596,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_card.long_name = long_name; #endif - sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + sof_parent = snd_soc_acpi_sof_parent(dev); /* set card and driver name */ if (sof_parent) { From 10f4a96543b744c8cc7ef8b0799af21d911dd37d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 6 Oct 2021 18:04:27 +0300 Subject: [PATCH 09/27] ASoC: Intel: bytcht_es8316: Switch to use gpiod_get_optional() First of all, replace indexed API by plain one since we have index 0. Second, switch to optional variant and drop duplicated code. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211006150428.16434-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index efd71e6e42b3..421a04d96d84 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -566,16 +566,12 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); priv->speaker_en_gpio = - gpiod_get_index(codec_dev, "speaker-enable", 0, - /* see comment in byt_cht_es8316_resume */ - GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); - + gpiod_get_optional(codec_dev, "speaker-enable", + /* see comment in byt_cht_es8316_resume() */ + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); if (IS_ERR(priv->speaker_en_gpio)) { ret = PTR_ERR(priv->speaker_en_gpio); switch (ret) { - case -ENOENT: - priv->speaker_en_gpio = NULL; - break; default: dev_err(dev, "get speaker GPIO failed: %d\n", ret); fallthrough; From c25d4546ca452b2e8c03bc735e4c65bc6dd751dd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 6 Oct 2021 18:04:28 +0300 Subject: [PATCH 10/27] ASoC: Intel: bytcht_es8316: Utilize dev_err_probe() to avoid log saturation dev_err_probe() avoids printing into log when the deferred probe is invoked. This is possible when clock provider is pending to appear. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211006150428.16434-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 421a04d96d84..4d313d0d0f23 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -532,11 +532,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* get the clock */ priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); - if (IS_ERR(priv->mclk)) { - ret = PTR_ERR(priv->mclk); - dev_err(dev, "clk_get pmc_plt_clk_3 failed: %d\n", ret); - return ret; - } + if (IS_ERR(priv->mclk)) + return dev_err_probe(dev, PTR_ERR(priv->mclk), "clk_get pmc_plt_clk_3 failed\n"); /* get speaker enable GPIO */ codec_dev = acpi_get_first_physical_node(adev); @@ -570,14 +567,9 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* see comment in byt_cht_es8316_resume() */ GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); if (IS_ERR(priv->speaker_en_gpio)) { - ret = PTR_ERR(priv->speaker_en_gpio); - switch (ret) { - default: - dev_err(dev, "get speaker GPIO failed: %d\n", ret); - fallthrough; - case -EPROBE_DEFER: - goto err_put_codec; - } + ret = dev_err_probe(dev, PTR_ERR(priv->speaker_en_gpio), + "get speaker GPIO failed\n"); + goto err_put_codec; } snprintf(components_string, sizeof(components_string), From 5af82c81b2c49cfb1cad84d9eb6eab0e3d1c4842 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 6 Oct 2021 16:17:12 +0200 Subject: [PATCH 11/27] ASoC: DAPM: Fix missing kctl change notifications The put callback of a kcontrol is supposed to return 1 when the value is changed, and this will be notified to user-space. However, some DAPM kcontrols always return 0 (except for errors), hence the user-space misses the update of a control value. This patch corrects the behavior by properly returning 1 when the value gets updated. Reported-and-tested-by: Hans de Goede Cc: Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20211006141712.2439-1-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7b67f1e19ae9..59d07648a7e7 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2561,6 +2561,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, const char *pin, int status) { struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); + int ret = 0; dapm_assert_locked(dapm); @@ -2573,13 +2574,14 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, dapm_mark_dirty(w, "pin configuration"); dapm_widget_invalidate_input_paths(w); dapm_widget_invalidate_output_paths(w); + ret = 1; } w->connected = status; if (status == 0) w->force = 0; - return 0; + return ret; } /** @@ -3583,14 +3585,15 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, { struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); const char *pin = (const char *)kcontrol->private_value; + int ret; if (ucontrol->value.integer.value[0]) - snd_soc_dapm_enable_pin(&card->dapm, pin); + ret = snd_soc_dapm_enable_pin(&card->dapm, pin); else - snd_soc_dapm_disable_pin(&card->dapm, pin); + ret = snd_soc_dapm_disable_pin(&card->dapm, pin); snd_soc_dapm_sync(&card->dapm); - return 0; + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); @@ -4023,7 +4026,7 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol, rtd->params_select = ucontrol->value.enumerated.item[0]; - return 0; + return 1; } static void From 214174d9f56c7f81f4860a26b6b8b961a6b92654 Mon Sep 17 00:00:00 2001 From: Srinivasa Rao Mandadapu Date: Thu, 7 Oct 2021 19:21:15 +0530 Subject: [PATCH 12/27] ASoC: codec: wcd938x: Add irq config support This patch fixes compilation error in wcd98x codec driver. Fixes: 045442228868 ("ASoC: codecs: wcd938x: add audio routing and Kconfig") Signed-off-by: Venkata Prasad Potturu Signed-off-by: Srinivasa Rao Mandadapu Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/1633614675-27122-1-git-send-email-srivasam@codeaurora.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 82ee233a269d..216cea04ad70 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1583,6 +1583,7 @@ config SND_SOC_WCD938X_SDW tristate "WCD9380/WCD9385 Codec - SDW" select SND_SOC_WCD938X select SND_SOC_WCD_MBHC + select REGMAP_IRQ depends on SOUNDWIRE select REGMAP_SOUNDWIRE help From c448b7aa3e66042fc0f849d9a0fb90d1af82e948 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Sat, 9 Oct 2021 14:58:40 +0800 Subject: [PATCH 13/27] ASoC: soc-core: fix null-ptr-deref in snd_soc_del_component_unlocked() 'component' is allocated in snd_soc_register_component(), but component->list is not initalized, this may cause snd_soc_del_component_unlocked() deref null ptr in the error handing case. KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: 0010:__list_del_entry_valid+0x81/0xf0 Call Trace: snd_soc_del_component_unlocked+0x69/0x1b0 [snd_soc_core] snd_soc_add_component.cold+0x54/0x6c [snd_soc_core] snd_soc_register_component+0x70/0x90 [snd_soc_core] devm_snd_soc_register_component+0x5e/0xd0 [snd_soc_core] tas2552_probe+0x265/0x320 [snd_soc_tas2552] ? tas2552_component_probe+0x1e0/0x1e0 [snd_soc_tas2552] i2c_device_probe+0xa31/0xbe0 Fix by adding INIT_LIST_HEAD() to snd_soc_component_initialize(). Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20211009065840.3196239-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c830e96afba2..80ca260595fd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2599,6 +2599,7 @@ int snd_soc_component_initialize(struct snd_soc_component *component, INIT_LIST_HEAD(&component->dai_list); INIT_LIST_HEAD(&component->dobj_list); INIT_LIST_HEAD(&component->card_list); + INIT_LIST_HEAD(&component->list); mutex_init(&component->io_mutex); component->name = fmt_single_name(dev, &component->id); From aa18457c4af7a9dad1f2b150b11beae1d8ab57aa Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 11 Oct 2021 15:49:03 +0100 Subject: [PATCH 14/27] ASoC: cs42l42: Ensure 0dB full scale volume is used for headsets Ensure the default 0dB playback path is always used. The code that set FULL_SCALE_VOL based on LOAD_DET_RCSTAT was spurious, and resulted in a -6dB attenuation being accidentally inserted into the playback path. Signed-off-by: Stefan Binding Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211011144903.28915-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index fb1e4c33e27d..9a463ab54bdd 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -922,7 +922,6 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) struct snd_soc_component *component = dai->component; struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); unsigned int regval; - u8 fullScaleVol; int ret; if (mute) { @@ -993,20 +992,11 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) cs42l42->stream_use |= 1 << stream; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* Read the headphone load */ - regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT); - if (((regval & CS42L42_RLA_STAT_MASK) >> CS42L42_RLA_STAT_SHIFT) == - CS42L42_RLA_STAT_15_OHM) { - fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK; - } else { - fullScaleVol = 0; - } - - /* Un-mute the headphone, set the full scale volume flag */ + /* Un-mute the headphone */ snd_soc_component_update_bits(component, CS42L42_HP_CTL, CS42L42_HP_ANA_AMUTE_MASK | - CS42L42_HP_ANA_BMUTE_MASK | - CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol); + CS42L42_HP_ANA_BMUTE_MASK, + 0); } } From 6b9b546dc00797c74bef491668ce5431ff54e1e2 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 13 Oct 2021 13:17:04 +0800 Subject: [PATCH 15/27] ASoC: wm8960: Fix clock configuration on slave mode There is a noise issue for 8kHz sample rate on slave mode. Compared with master mode, the difference is the DACDIV setting, after correcting the DACDIV, the noise is gone. There is no noise issue for 48kHz sample rate, because the default value of DACDIV is correct for 48kHz. So wm8960_configure_clocking() should be functional for ADC and DAC function even if it is slave mode. In order to be compatible for old use case, just add condition for checking that sysclk is zero with slave mode. Fixes: 0e50b51aa22f ("ASoC: wm8960: Let wm8960 driver configure its bit clock and frame clock") Signed-off-by: Shengjiu Wang Acked-by: Charles Keepax Link: https://lore.kernel.org/r/1634102224-3922-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 9e621a254392..499604f1e178 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -742,9 +742,16 @@ static int wm8960_configure_clocking(struct snd_soc_component *component) int i, j, k; int ret; - if (!(iface1 & (1<<6))) { - dev_dbg(component->dev, - "Codec is slave mode, no need to configure clock\n"); + /* + * For Slave mode clocking should still be configured, + * so this if statement should be removed, but some platform + * may not work if the sysclk is not configured, to avoid such + * compatible issue, just add '!wm8960->sysclk' condition in + * this if statement. + */ + if (!(iface1 & (1 << 6)) && !wm8960->sysclk) { + dev_warn(component->dev, + "slave mode, but proceeding with no clock configuration\n"); return 0; } From 06441c82f0cd836402ca5fa4162d28ed07cfb0ed Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:04 +0100 Subject: [PATCH 16/27] ASoC: cs42l42: Don't reconfigure the PLL while it is running When capture and playback substreams are both running at the same time, cs42l42_pcm_hw_params() would be called for each direction. The first call will configure the PLL. The second call must not write the PLL configuration registers again if the first substream is already running, as this could destabilize the PLL. The DAI is marked symmetric sample bits and sample rate, so the two directions will always have the same SCLK (I2S always has 2 channel slots so the DAI does not need to require symmetric channels to guarantee the same SCLK). However, since cs42l42_pll_config() is checking for an active stream it may as well test that the requested SCLK is the same as the currently active configuration. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211015133619.4698-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 9a463ab54bdd..cdcb6d81d900 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -618,6 +618,14 @@ static int cs42l42_pll_config(struct snd_soc_component *component) else clk = cs42l42->sclk; + /* Don't reconfigure if there is an audio stream running */ + if (cs42l42->stream_use) { + if (pll_ratio_table[cs42l42->pll_config].sclk == clk) + return 0; + else + return -EBUSY; + } + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { if (pll_ratio_table[i].sclk == clk) { cs42l42->pll_config = i; From 6e6825801ab926360f7f4f2dbcfd107d5ab8f025 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:05 +0100 Subject: [PATCH 17/27] ASoC: cs42l42: Always configure both ASP TX channels An I2S frame always has two slots (left and right) even when sending mono. The right channel (channel 2) of ASP TX will always have the same bit width as the left channel and will always be on the high phase of LRCLK. The previous implementation always passed the field masks for both channels to snd_soc_component_update_bits() but for mono the written value only contained the settings for channel 1. The result was that for mono channel 2 was set to 8-bit (which is an invalid configuration) with both channels on the low phase of LRCLK. Signed-off-by: Richard Fitzgerald Fixes: 585e7079de0e ("ASoC: cs42l42: Add Capture Support") Link: https://lore.kernel.org/r/20211015133619.4698-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index cdcb6d81d900..914257180c01 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -861,11 +861,10 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, switch(substream->stream) { case SNDRV_PCM_STREAM_CAPTURE: - if (channels == 2) { - val |= CS42L42_ASP_TX_CH2_AP_MASK; - val |= width << CS42L42_ASP_TX_CH2_RES_SHIFT; - } - val |= width << CS42L42_ASP_TX_CH1_RES_SHIFT; + /* channel 2 on high LRCLK */ + val = CS42L42_ASP_TX_CH2_AP_MASK | + (width << CS42L42_ASP_TX_CH2_RES_SHIFT) | + (width << CS42L42_ASP_TX_CH1_RES_SHIFT); snd_soc_component_update_bits(component, CS42L42_ASP_TX_CH_AP_RES, CS42L42_ASP_TX_CH1_AP_MASK | CS42L42_ASP_TX_CH2_AP_MASK | From d591d4b32aa9552af14a0c7c586a2d3fe9ecc6e0 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:06 +0100 Subject: [PATCH 18/27] ASoC: cs42l42: Correct some register default values Some registers had wrong default values in cs42l42_reg_defaults[]. Signed-off-by: Richard Fitzgerald Fixes: 2c394ca79604 ("ASoC: Add support for CS42L42 codec") Link: https://lore.kernel.org/r/20211015133619.4698-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 914257180c01..a45026809aa4 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -93,7 +93,7 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_ASP_RX_INT_MASK, 0x1F }, { CS42L42_ASP_TX_INT_MASK, 0x0F }, { CS42L42_CODEC_INT_MASK, 0x03 }, - { CS42L42_SRCPL_INT_MASK, 0xFF }, + { CS42L42_SRCPL_INT_MASK, 0x7F }, { CS42L42_VPMON_INT_MASK, 0x01 }, { CS42L42_PLL_LOCK_INT_MASK, 0x01 }, { CS42L42_TSRS_PLUG_INT_MASK, 0x0F }, @@ -130,7 +130,7 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_MIXER_CHA_VOL, 0x3F }, { CS42L42_MIXER_ADC_VOL, 0x3F }, { CS42L42_MIXER_CHB_VOL, 0x3F }, - { CS42L42_EQ_COEF_IN0, 0x22 }, + { CS42L42_EQ_COEF_IN0, 0x00 }, { CS42L42_EQ_COEF_IN1, 0x00 }, { CS42L42_EQ_COEF_IN2, 0x00 }, { CS42L42_EQ_COEF_IN3, 0x00 }, From 917d5758014b37cf97b946dd130aad9353c354dc Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:07 +0100 Subject: [PATCH 19/27] ASoC: cs42l42: Don't set defaults for volatile registers Volatile registers don't need a default value. Signed-off-by: Richard Fitzgerald Fixes: 2c394ca79604 ("ASoC: Add support for CS42L42 codec") Link: https://lore.kernel.org/r/20211015133619.4698-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index a45026809aa4..e5a97e904d40 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -41,7 +41,6 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_FRZ_CTL, 0x00 }, { CS42L42_SRC_CTL, 0x10 }, - { CS42L42_MCLK_STATUS, 0x02 }, { CS42L42_MCLK_CTL, 0x02 }, { CS42L42_SFTRAMP_RATE, 0xA4 }, { CS42L42_I2C_DEBOUNCE, 0x88 }, @@ -57,11 +56,9 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_RSENSE_CTL3, 0x1B }, { CS42L42_TSENSE_CTL, 0x1B }, { CS42L42_TSRS_INT_DISABLE, 0x00 }, - { CS42L42_TRSENSE_STATUS, 0x00 }, { CS42L42_HSDET_CTL1, 0x77 }, { CS42L42_HSDET_CTL2, 0x00 }, { CS42L42_HS_SWITCH_CTL, 0xF3 }, - { CS42L42_HS_DET_STATUS, 0x00 }, { CS42L42_HS_CLAMP_DISABLE, 0x00 }, { CS42L42_MCLK_SRC_SEL, 0x00 }, { CS42L42_SPDIF_CLK_CFG, 0x00 }, @@ -75,18 +72,6 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_IN_ASRC_CLK, 0x00 }, { CS42L42_OUT_ASRC_CLK, 0x00 }, { CS42L42_PLL_DIV_CFG1, 0x00 }, - { CS42L42_ADC_OVFL_STATUS, 0x00 }, - { CS42L42_MIXER_STATUS, 0x00 }, - { CS42L42_SRC_STATUS, 0x00 }, - { CS42L42_ASP_RX_STATUS, 0x00 }, - { CS42L42_ASP_TX_STATUS, 0x00 }, - { CS42L42_CODEC_STATUS, 0x00 }, - { CS42L42_DET_INT_STATUS1, 0x00 }, - { CS42L42_DET_INT_STATUS2, 0x00 }, - { CS42L42_SRCPL_INT_STATUS, 0x00 }, - { CS42L42_VPMON_STATUS, 0x00 }, - { CS42L42_PLL_LOCK_STATUS, 0x00 }, - { CS42L42_TSRS_PLUG_STATUS, 0x00 }, { CS42L42_ADC_OVFL_INT_MASK, 0x01 }, { CS42L42_MIXER_INT_MASK, 0x0F }, { CS42L42_SRC_INT_MASK, 0x0F }, @@ -105,8 +90,6 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_PLL_CTL3, 0x10 }, { CS42L42_PLL_CAL_RATIO, 0x80 }, { CS42L42_PLL_CTL4, 0x03 }, - { CS42L42_LOAD_DET_RCSTAT, 0x00 }, - { CS42L42_LOAD_DET_DONE, 0x00 }, { CS42L42_LOAD_DET_EN, 0x00 }, { CS42L42_HSBIAS_SC_AUTOCTL, 0x03 }, { CS42L42_WAKE_CTL, 0xC0 }, @@ -115,8 +98,6 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_MISC_DET_CTL, 0x03 }, { CS42L42_MIC_DET_CTL1, 0x1F }, { CS42L42_MIC_DET_CTL2, 0x2F }, - { CS42L42_DET_STATUS1, 0x00 }, - { CS42L42_DET_STATUS2, 0x00 }, { CS42L42_DET_INT1_MASK, 0xE0 }, { CS42L42_DET_INT2_MASK, 0xFF }, { CS42L42_HS_BIAS_CTL, 0xC2 }, @@ -182,7 +163,6 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_ASP_RX_DAI1_CH2_AP_RES, 0x03 }, { CS42L42_ASP_RX_DAI1_CH2_BIT_MSB, 0x00 }, { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 }, - { CS42L42_SUB_REVID, 0x03 }, }; static bool cs42l42_readable_register(struct device *dev, unsigned int reg) From 0306988789d9d91a18ff70bd2bf165d3ae0ef1dd Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:08 +0100 Subject: [PATCH 20/27] ASoC: cs42l42: Defer probe if request_threaded_irq() returns EPROBE_DEFER The driver can run without an interrupt so if devm_request_threaded_irq() failed, the probe() just carried on. But if this was EPROBE_DEFER the driver would continue without an interrupt instead of deferring to wait for the interrupt to become available. Fixes: 2c394ca79604 ("ASoC: Add support for CS42L42 codec") Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211015133619.4698-6-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index e5a97e904d40..dc84b3de3da3 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1935,8 +1935,9 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, NULL, cs42l42_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, "cs42l42", cs42l42); - - if (ret != 0) + if (ret == -EPROBE_DEFER) + goto err_disable; + else if (ret != 0) dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); From 2a031a99428bafba089437e9044b8fd5dc6e7551 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:13 +0100 Subject: [PATCH 21/27] ASoC: cs42l42: Don't claim to support 192k The driver currently only supports configuring for sample rates <= 96k and it isn't possible to setup a configuration that will support all sample rates up to 192k. For sample rates up to 96k MCLK is in the 12MHz group. However, although 192k only requires an I2S clock in the 12MHz group, the cs42l42 audio path is not natively 192k so the audio must be resampled. But for 192k the SRC requires a 24MHz MCLK. It is not possible to switch MCLK between 12MHz and 24MHz groups on-the-fly. The 12MHz group supports all sample rates up to 96k. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211015133619.4698-11-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index dc84b3de3da3..71390c20e7a1 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -812,7 +812,7 @@ static int cs42l42_dai_startup(struct snd_pcm_substream *substream, struct snd_s /* Machine driver has not set a SCLK, limit bottom end to 44.1 kHz */ return snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, - 44100, 192000); + 44100, 96000); } static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, @@ -1008,14 +1008,14 @@ static struct snd_soc_dai_driver cs42l42_dai = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_96000, .formats = CS42L42_FORMATS, }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_96000, .formats = CS42L42_FORMATS, }, .symmetric_rate = 1, From 3c211cb7db2905221f9f006aa66b8af17bfcd480 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:14 +0100 Subject: [PATCH 22/27] ASoC: cs42l42: Use PLL for SCLK > 12.288MHz It isn't possible to switch MCLK between 12MHz and 24MHz rate groups on-the-fly - this can only be done when cs42l42 is powered-down. All "normal" SCLK rates use an MCLK in the 12MHz group, so change the configs for SCLK > 12.288 MHz to use the PLL to generate an MCLK in the 12MHz group. As this means MCLK_DIV is always 0 it can be removed from the pll configuration setup. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211015133619.4698-12-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 41 +++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 71390c20e7a1..4ec7fdcedca7 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -549,7 +549,6 @@ static const struct reg_sequence cs42l42_to_osc_seq[] = { struct cs42l42_pll_params { u32 sclk; - u8 mclk_div; u8 mclk_src_sel; u8 sclk_prediv; u8 pll_div_int; @@ -566,24 +565,24 @@ struct cs42l42_pll_params { * Table 4-5 from the Datasheet */ static const struct cs42l42_pll_params pll_ratio_table[] = { - { 1411200, 0, 1, 0x00, 0x80, 0x000000, 0x03, 0x10, 11289600, 128, 2}, - { 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125, 2}, - { 2304000, 0, 1, 0x00, 0x55, 0xC00000, 0x02, 0x10, 12288000, 85, 2}, - { 2400000, 0, 1, 0x00, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2}, - { 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1}, - { 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1}, - { 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1}, - { 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96, 1}, - { 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94, 1}, - { 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1}, - { 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1}, - { 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1}, - { 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0, 1}, - { 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0, 1}, - { 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0, 1}, - { 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0, 1}, - { 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0, 1}, - { 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0, 1} + { 1411200, 1, 0x00, 0x80, 0x000000, 0x03, 0x10, 11289600, 128, 2}, + { 1536000, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125, 2}, + { 2304000, 1, 0x00, 0x55, 0xC00000, 0x02, 0x10, 12288000, 85, 2}, + { 2400000, 1, 0x00, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2}, + { 2822400, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1}, + { 3000000, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1}, + { 3072000, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1}, + { 4000000, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96, 1}, + { 4096000, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94, 1}, + { 5644800, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1}, + { 6000000, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1}, + { 6144000, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1}, + { 11289600, 0, 0, 0, 0, 0, 0, 11289600, 0, 1}, + { 12000000, 0, 0, 0, 0, 0, 0, 12000000, 0, 1}, + { 12288000, 0, 0, 0, 0, 0, 0, 12288000, 0, 1}, + { 22579200, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1}, + { 24000000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1}, + { 24576000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12288000, 128, 1} }; static int cs42l42_pll_config(struct snd_soc_component *component) @@ -619,10 +618,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component) 24000000)) << CS42L42_INTERNAL_FS_SHIFT); - snd_soc_component_update_bits(component, CS42L42_MCLK_SRC_SEL, - CS42L42_MCLKDIV_MASK, - (pll_ratio_table[i].mclk_div << - CS42L42_MCLKDIV_SHIFT)); /* Set up the LRCLK */ fsync = clk / cs42l42->srate; if (((fsync * cs42l42->srate) != clk) From 4ae1d8f911d6fc20baefd5eb061bf6964fa22a32 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:15 +0100 Subject: [PATCH 23/27] ASoC: cs42l42: Allow time for HP/ADC to power-up after enable After enabling the HP or ADC by writing the corresponding PDN=0, it takes around 20 milliseconds for it to power up and the midrail supply to be stable. Add this wait into a DAPM widget callback. If HP and ADC are both powering up in a DAPM sequence, there's no need to do the wait twice. The widget will perform one wait in the POST_PMU if there was a PRE_PMU for one or both. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211015133619.4698-13-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 31 +++++++++++++++++++++++++++++-- sound/soc/codecs/cs42l42.h | 2 ++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 4ec7fdcedca7..d6d74a7bbde9 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -435,10 +435,36 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = { 0x3f, 1, mixer_tlv) }; +static int cs42l42_hp_adc_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); + struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + cs42l42->hp_adc_up_pending = true; + break; + case SND_SOC_DAPM_POST_PMU: + /* Only need one delay if HP and ADC are both powering-up */ + if (cs42l42->hp_adc_up_pending) { + usleep_range(CS42L42_HP_ADC_EN_TIME_US, + CS42L42_HP_ADC_EN_TIME_US + 1000); + cs42l42->hp_adc_up_pending = false; + } + break; + default: + break; + } + + return 0; +} + static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = { /* Playback Path */ SND_SOC_DAPM_OUTPUT("HP"), - SND_SOC_DAPM_DAC("DAC", NULL, CS42L42_PWR_CTL1, CS42L42_HP_PDN_SHIFT, 1), + SND_SOC_DAPM_DAC_E("DAC", NULL, CS42L42_PWR_CTL1, CS42L42_HP_PDN_SHIFT, 1, + cs42l42_hp_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_MIXER("MIXER", CS42L42_PWR_CTL1, CS42L42_MIXER_PDN_SHIFT, 1, NULL, 0), SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, SND_SOC_NOPM, 0, 0), @@ -448,7 +474,8 @@ static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = { /* Capture Path */ SND_SOC_DAPM_INPUT("HS"), - SND_SOC_DAPM_ADC("ADC", NULL, CS42L42_PWR_CTL1, CS42L42_ADC_PDN_SHIFT, 1), + SND_SOC_DAPM_ADC_E("ADC", NULL, CS42L42_PWR_CTL1, CS42L42_ADC_PDN_SHIFT, 1, + cs42l42_hp_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_AIF_OUT("SDOUT1", NULL, 0, CS42L42_ASP_TX_CH_EN, CS42L42_ASP_TX0_CH1_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("SDOUT2", NULL, 1, CS42L42_ASP_TX_CH_EN, CS42L42_ASP_TX0_CH2_SHIFT, 0), diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 8734f6828f3e..ded61af6ea8b 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -761,6 +761,7 @@ #define CS42L42_CLOCK_SWITCH_DELAY_US 150 #define CS42L42_PLL_LOCK_POLL_US 250 #define CS42L42_PLL_LOCK_TIMEOUT_US 1250 +#define CS42L42_HP_ADC_EN_TIME_US 20000 static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { "VA", @@ -794,6 +795,7 @@ struct cs42l42_private { u8 hs_bias_ramp_time; u8 hs_bias_sense_en; u8 stream_use; + bool hp_adc_up_pending; }; #endif /* __CS42L42_H__ */ From fdbd256175a1e11c1ba827112d56b9a3952e1219 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:16 +0100 Subject: [PATCH 24/27] ASoC: cs42l42: Set correct SRC MCLK According to the datasheet the SRC MCLK must be as near as possible to (125 * sample rate). This means it should be ~6MHz for rates up to 48k and ~12MHz for rates above that. As per datasheet table 4-21. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211015133619.4698-14-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 58 +++++++++++++++++++++++++++----------- sound/soc/codecs/cs42l42.h | 1 + 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index d6d74a7bbde9..d62272d0ab8c 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -678,22 +678,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component) CS42L42_FSYNC_PULSE_WIDTH_MASK, CS42L42_FRAC1_VAL(fsync - 1) << CS42L42_FSYNC_PULSE_WIDTH_SHIFT); - /* Set the sample rates (96k or lower) */ - snd_soc_component_update_bits(component, CS42L42_FS_RATE_EN, - CS42L42_FS_EN_MASK, - (CS42L42_FS_EN_IASRC_96K | - CS42L42_FS_EN_OASRC_96K) << - CS42L42_FS_EN_SHIFT); - /* Set the input/output internal MCLK clock ~12 MHz */ - snd_soc_component_update_bits(component, CS42L42_IN_ASRC_CLK, - CS42L42_CLK_IASRC_SEL_MASK, - CS42L42_CLK_IASRC_SEL_12 << - CS42L42_CLK_IASRC_SEL_SHIFT); - snd_soc_component_update_bits(component, - CS42L42_OUT_ASRC_CLK, - CS42L42_CLK_OASRC_SEL_MASK, - CS42L42_CLK_OASRC_SEL_12 << - CS42L42_CLK_OASRC_SEL_SHIFT); if (pll_ratio_table[i].mclk_src_sel == 0) { /* Pass the clock straight through */ snd_soc_component_update_bits(component, @@ -756,6 +740,39 @@ static int cs42l42_pll_config(struct snd_soc_component *component) return -EINVAL; } +static void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample_rate) +{ + struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); + unsigned int fs; + + /* Don't reconfigure if there is an audio stream running */ + if (cs42l42->stream_use) + return; + + /* SRC MCLK must be as close as possible to 125 * sample rate */ + if (sample_rate <= 48000) + fs = CS42L42_CLK_IASRC_SEL_6; + else + fs = CS42L42_CLK_IASRC_SEL_12; + + /* Set the sample rates (96k or lower) */ + snd_soc_component_update_bits(component, + CS42L42_FS_RATE_EN, + CS42L42_FS_EN_MASK, + (CS42L42_FS_EN_IASRC_96K | + CS42L42_FS_EN_OASRC_96K) << + CS42L42_FS_EN_SHIFT); + + snd_soc_component_update_bits(component, + CS42L42_IN_ASRC_CLK, + CS42L42_CLK_IASRC_SEL_MASK, + fs << CS42L42_CLK_IASRC_SEL_SHIFT); + snd_soc_component_update_bits(component, + CS42L42_OUT_ASRC_CLK, + CS42L42_CLK_OASRC_SEL_MASK, + fs << CS42L42_CLK_OASRC_SEL_SHIFT); +} + static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_component *component = codec_dai->component; @@ -846,6 +863,7 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, unsigned int channels = params_channels(params); unsigned int width = (params_width(params) / 8) - 1; unsigned int val = 0; + int ret; cs42l42->srate = params_rate(params); cs42l42->bclk = snd_soc_params_to_bclk(params); @@ -899,7 +917,13 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, break; } - return cs42l42_pll_config(component); + ret = cs42l42_pll_config(component); + if (ret) + return ret; + + cs42l42_src_config(component, params_rate(params)); + + return 0; } static int cs42l42_set_sysclk(struct snd_soc_dai *dai, diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index ded61af6ea8b..d13749e9d8c5 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -288,6 +288,7 @@ #define CS42L42_IN_ASRC_CLK (CS42L42_PAGE_12 + 0x0A) #define CS42L42_CLK_IASRC_SEL_SHIFT 0 #define CS42L42_CLK_IASRC_SEL_MASK (1 << CS42L42_CLK_IASRC_SEL_SHIFT) +#define CS42L42_CLK_IASRC_SEL_6 0 #define CS42L42_CLK_IASRC_SEL_12 1 #define CS42L42_OUT_ASRC_CLK (CS42L42_PAGE_12 + 0x0B) From 0c3d6c6ff75aa6b21cd4ac872dd3050b6525c75c Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:17 +0100 Subject: [PATCH 25/27] ASoC: cs42l42: Mark OSC_SWITCH_STATUS register volatile OSC_SWITCH_STATUS is a volatile register indicating the current state of the clock switch logic. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211015133619.4698-15-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index d62272d0ab8c..390cd7ea3a7f 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -52,7 +52,6 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_RSENSE_CTL1, 0x40 }, { CS42L42_RSENSE_CTL2, 0x00 }, { CS42L42_OSC_SWITCH, 0x00 }, - { CS42L42_OSC_SWITCH_STATUS, 0x05 }, { CS42L42_RSENSE_CTL3, 0x1B }, { CS42L42_TSENSE_CTL, 0x1B }, { CS42L42_TSRS_INT_DISABLE, 0x00 }, @@ -331,6 +330,7 @@ static bool cs42l42_volatile_register(struct device *dev, unsigned int reg) case CS42L42_DEVID_CD: case CS42L42_DEVID_E: case CS42L42_MCLK_STATUS: + case CS42L42_OSC_SWITCH_STATUS: case CS42L42_TRSENSE_STATUS: case CS42L42_HS_DET_STATUS: case CS42L42_ADC_OVFL_STATUS: From 4c8d49bc476c7cf1fb7377b469ced43ced470027 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:18 +0100 Subject: [PATCH 26/27] ASoC: cs42l42: Fix WARN in remove() if running without an interrupt The driver must free the IRQ in remove() to prevent the potential race where an IRQ starts to be handled while the driver is being removed but devres has not yet called free_irq(). However, the driver can run without an interrupt but devm_free_irq() will hit a WARN() if no devres-managed interrupt was ever created. Fix this by only attempting to create the interrupt handler if the hardware config specified an interrupt, and failing probe() if the interrupt could not be created. This means that in cs42l42_remove() an interrupt must have been registered if the irq number is valid and therefore it is safe to call devm_free_irq(). Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211015133619.4698-16-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 390cd7ea3a7f..c6d91ad996e0 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1975,17 +1975,21 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, } usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); - /* Request IRQ */ - ret = devm_request_threaded_irq(&i2c_client->dev, - i2c_client->irq, - NULL, cs42l42_irq_thread, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "cs42l42", cs42l42); - if (ret == -EPROBE_DEFER) - goto err_disable; - else if (ret != 0) - dev_err(&i2c_client->dev, - "Failed to request IRQ: %d\n", ret); + /* Request IRQ if one was specified */ + if (i2c_client->irq) { + ret = devm_request_threaded_irq(&i2c_client->dev, + i2c_client->irq, + NULL, cs42l42_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs42l42", cs42l42); + if (ret == -EPROBE_DEFER) { + goto err_disable; + } else if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request IRQ: %d\n", ret); + goto err_disable; + } + } /* initialize codec */ devid = cirrus_read_device_id(cs42l42->regmap, CS42L42_DEVID_AB); @@ -2056,7 +2060,9 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client) { struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client); - devm_free_irq(&i2c_client->dev, i2c_client->irq, cs42l42); + if (i2c_client->irq) + devm_free_irq(&i2c_client->dev, i2c_client->irq, cs42l42); + pm_runtime_suspend(&i2c_client->dev); pm_runtime_disable(&i2c_client->dev); From 4ca239f33737198827c7f4ac68a1f6fc8a9d79ba Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 15 Oct 2021 14:36:19 +0100 Subject: [PATCH 27/27] ASoC: cs42l42: Always enable TS_PLUG and TS_UNPLUG interrupts The headset type detection must run to set the analogue switches correctly for the attached headset type. Without this only headsets with wiring matching the chip default will have a functioning mic. commit c26a5289e865 ("ASoC: cs42l42: Add support for set_jack calls") moved the interrupt unmasking to the component set_jack() callback. But it's not mandatory for a machine driver to register a struct snd_soc_jack handler. Without a registered handler the type detection would not have run and so the mic would not work on some types of headset. This patch restores the unmasking of TS_PLUG and TS_UNPLUG interrupts during probe. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211015133619.4698-17-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index c6d91ad996e0..ac145915445a 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -524,12 +524,6 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ cs42l42->jack = jk; - regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, - CS42L42_RS_PLUG_MASK | CS42L42_RS_UNPLUG_MASK | - CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK, - (1 << CS42L42_RS_PLUG_SHIFT) | (1 << CS42L42_RS_UNPLUG_SHIFT) | - (0 << CS42L42_TS_PLUG_SHIFT) | (0 << CS42L42_TS_UNPLUG_SHIFT)); - return 0; } @@ -1691,8 +1685,8 @@ static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42) CS42L42_TS_UNPLUG_MASK, (1 << CS42L42_RS_PLUG_SHIFT) | (1 << CS42L42_RS_UNPLUG_SHIFT) | - (1 << CS42L42_TS_PLUG_SHIFT) | - (1 << CS42L42_TS_UNPLUG_SHIFT)); + (0 << CS42L42_TS_PLUG_SHIFT) | + (0 << CS42L42_TS_UNPLUG_SHIFT)); } static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42)