From c1f848f12103920ca165758aedb1c10904e193e1 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 9 Aug 2023 19:19:31 +0200 Subject: [PATCH 1/7] ASoC: meson: axg-tdm-formatter: fix channel slot allocation When the tdm lane mask is computed, the driver currently fills the 1st lane before moving on to the next. If the stream has less channels than the lanes can accommodate, slots will be disabled on the last lanes. Unfortunately, the HW distribute channels in a different way. It distribute channels in pair on each lanes before moving on the next slots. This difference leads to problems if a device has an interface with more than 1 lane and with more than 2 slots per lane. For example: a playback interface with 2 lanes and 4 slots each (total 8 slots - zero based numbering) - Playing a 8ch stream: - All slots activated by the driver - channel #2 will be played on lane #1 - slot #0 following HW placement - Playing a 4ch stream: - Lane #1 disabled by the driver - channel #2 will be played on lane #0 - slot #2 This behaviour is obviously not desirable. Change the way slots are activated on the TDM lanes to follow what the HW does and make sure each channel always get mapped to the same slot/lane. Fixes: 1a11d88f499c ("ASoC: meson: add tdm formatter base driver") Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20230809171931.1244502-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-tdm-formatter.c | 42 ++++++++++++++++++----------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index 9883dc777f63..63333a2b0a9c 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -30,27 +30,32 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map, struct axg_tdm_stream *ts, unsigned int offset) { - unsigned int val, ch = ts->channels; - unsigned long mask; - int i, j; + unsigned int ch = ts->channels; + u32 val[AXG_TDM_NUM_LANES]; + int i, j, k; + + /* + * We need to mimick the slot distribution used by the HW to keep the + * channel placement consistent regardless of the number of channel + * in the stream. This is why the odd algorithm below is used. + */ + memset(val, 0, sizeof(*val) * AXG_TDM_NUM_LANES); /* * Distribute the channels of the stream over the available slots - * of each TDM lane + * of each TDM lane. We need to go over the 32 slots ... */ - for (i = 0; i < AXG_TDM_NUM_LANES; i++) { - val = 0; - mask = ts->mask[i]; - - for (j = find_first_bit(&mask, 32); - (j < 32) && ch; - j = find_next_bit(&mask, 32, j + 1)) { - val |= 1 << j; - ch -= 1; + for (i = 0; (i < 32) && ch; i += 2) { + /* ... of all the lanes ... */ + for (j = 0; j < AXG_TDM_NUM_LANES; j++) { + /* ... then distribute the channels in pairs */ + for (k = 0; k < 2; k++) { + if ((BIT(i + k) & ts->mask[j]) && ch) { + val[j] |= BIT(i + k); + ch -= 1; + } + } } - - regmap_write(map, offset, val); - offset += regmap_get_reg_stride(map); } /* @@ -63,6 +68,11 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map, return -EINVAL; } + for (i = 0; i < AXG_TDM_NUM_LANES; i++) { + regmap_write(map, offset, val[i]); + offset += regmap_get_reg_stride(map); + } + return 0; } EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks); From 37aba3190891d4de189bd5192ee95220e295f34d Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 11 Aug 2023 17:38:22 +0800 Subject: [PATCH 2/7] ASoC: rt1308-sdw: fix random louder sound This patch uses a vendor register to check whether the system hibernated ever. The driver will only set the preset when the driver brings up or the system hibernated. It will avoid the unknown issue that makes the speaker output louder and can't control the volume. Signed-off-by: Shuming Fan hw_init) return 0; @@ -242,6 +243,10 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_get_noresume(&slave->dev); + regmap_read(rt1308->regmap, 0xcf01, &hibernation_flag); + if ((hibernation_flag != 0x00) && rt1308->first_hw_init) + goto _preset_ready_; + /* sw reset */ regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0); @@ -282,6 +287,12 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1308->regmap, 0xc100, 0xd7); regmap_write(rt1308->regmap, 0xc101, 0xd7); + /* apply BQ params */ + rt1308_apply_bq_params(rt1308); + + regmap_write(rt1308->regmap, 0xcf01, 0x01); + +_preset_ready_: if (rt1308->first_hw_init) { regcache_cache_bypass(rt1308->regmap, false); regcache_mark_dirty(rt1308->regmap); From 0fc7769e54e747c8fd1b4899af2ac43cb68daa1c Mon Sep 17 00:00:00 2001 From: Kevin-Lu Date: Tue, 15 Aug 2023 17:56:31 +0800 Subject: [PATCH 3/7] MAINTAINERS: Add entries for TEXAS INSTRUMENTS ASoC DRIVERS Add the MAINTAINERS entries for TEXAS INSTRUMENTS ASoC DRIVERS. Signed-off-by: Kevin-Lu Link: https://lore.kernel.org/r/20230815095631.1655-1-kevin-lu@ti.com Signed-off-by: Mark Brown --- MAINTAINERS | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 53b7ca804465..88174736be51 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21063,6 +21063,39 @@ S: Maintained F: Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml F: sound/soc/ti/ +TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS +M: Shenghao Ding +M: Kevin Lu +M: Baojun Xu +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/sound/tas2552.txt +F: Documentation/devicetree/bindings/sound/tas2562.yaml +F: Documentation/devicetree/bindings/sound/tas2770.yaml +F: Documentation/devicetree/bindings/sound/tas27xx.yaml +F: Documentation/devicetree/bindings/sound/ti,pcm1681.txt +F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml +F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml +F: Documentation/devicetree/bindings/sound/tlv320adcx140.yaml +F: Documentation/devicetree/bindings/sound/tlv320aic31xx.txt +F: Documentation/devicetree/bindings/sound/tpa6130a2.txt +F: include/sound/tas2*.h +F: include/sound/tlv320*.h +F: include/sound/tpa6130a2-plat.h +F: sound/pci/hda/tas2781_hda_i2c.c +F: sound/soc/codecs/pcm1681.c +F: sound/soc/codecs/pcm1789*.* +F: sound/soc/codecs/pcm179x*.* +F: sound/soc/codecs/pcm186x*.* +F: sound/soc/codecs/pcm3008.* +F: sound/soc/codecs/pcm3060*.* +F: sound/soc/codecs/pcm3168a*.* +F: sound/soc/codecs/pcm5102a.c +F: sound/soc/codecs/pcm512x*.* +F: sound/soc/codecs/tas2*.* +F: sound/soc/codecs/tlv320*.* +F: sound/soc/codecs/tpa6130a2.* + TEXAS INSTRUMENTS DMA DRIVERS M: Peter Ujfalusi L: dmaengine@vger.kernel.org From 2d218b45848b92b03b220bf4d9bef29f058f866f Mon Sep 17 00:00:00 2001 From: Chao Song Date: Wed, 16 Aug 2023 16:33:11 +0300 Subject: [PATCH 4/7] ASoC: SOF: ipc4-pcm: fix possible null pointer deference The call to snd_sof_find_spcm_dai() could return NULL, add nullable check for the return value to avoid null pointer defenrece. Fixes: 7cb19007baba ("ASoC: SOF: ipc4-pcm: add hw_params") Signed-off-by: Chao Song Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230816133311.7523-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-pcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 0c905bd0fab4..027416eb2f50 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -708,6 +708,9 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, struct snd_sof_pcm *spcm; spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + time_info = spcm->stream[substream->stream].private; /* delay calculation is not supported by current fw_reg ABI */ if (!time_info) From 897a6b5a030e62c21566551c870d81740f82ca13 Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Thu, 17 Aug 2023 12:27:11 +0100 Subject: [PATCH 5/7] ASoC: cs35l56: Read firmware uuid from a device property instead of _SUB Use a device property "cirrus,firmware-uid" to get the unique firmware identifier instead of using ACPI _SUB. There aren't any products that use _SUB. There will not usually be a _SUB in Soundwire nodes. The ACPI can use a _DSD section for custom properties. There is also a need to support instantiating this driver using software nodes. This is for systems where the CS35L56 is a back-end device and the ACPI refers only to the front-end audio device - there will not be any ACPI references to CS35L56. Fixes: e49611252900 ("ASoC: cs35l56: Add driver for Cirrus Logic CS35L56") Signed-off-by: Maciej Strozek Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230817112712.16637-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index c03f9d3c9a13..fd06b9f9d496 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -5,7 +5,6 @@ // Copyright (C) 2023 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. -#include #include #include #include @@ -1354,26 +1353,22 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56) return 0; } -static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56) +static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56) { - acpi_handle handle = ACPI_HANDLE(cs35l56->dev); - const char *sub; + struct device *dev = cs35l56->dev; + const char *prop; + int ret; - /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */ - if (!handle) + ret = device_property_read_string(dev, "cirrus,firmware-uid", &prop); + /* If bad sw node property, return 0 and fallback to legacy firmware path */ + if (ret < 0) return 0; - sub = acpi_get_subsystem_id(handle); - if (IS_ERR(sub)) { - /* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */ - if (PTR_ERR(sub) == -ENODATA) - return 0; - else - return PTR_ERR(sub); - } + cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL); + if (cs35l56->dsp.system_name == NULL) + return -ENOMEM; - cs35l56->dsp.system_name = sub; - dev_dbg(cs35l56->dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name); + dev_dbg(dev, "Firmware UID: %s\n", cs35l56->dsp.system_name); return 0; } @@ -1417,7 +1412,7 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) gpiod_set_value_cansleep(cs35l56->reset_gpio, 1); } - ret = cs35l56_acpi_get_name(cs35l56); + ret = cs35l56_get_firmware_uid(cs35l56); if (ret != 0) goto err; @@ -1604,8 +1599,6 @@ void cs35l56_remove(struct cs35l56_private *cs35l56) regcache_cache_only(cs35l56->regmap, true); - kfree(cs35l56->dsp.system_name); - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); } From e8500a70270334b9abad72fea504ef38a2952274 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Thu, 17 Aug 2023 12:27:12 +0100 Subject: [PATCH 6/7] ASoC: cs35l56: Add an ACPI match table An ACPI ID has been allocated for CS35L56 ASoC devices so that they can be instantiated from ACPI Device entries. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230817112712.16637-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56-i2c.c | 9 +++++++++ sound/soc/codecs/cs35l56-spi.c | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c index ed2a41943d97..40666e6698ba 100644 --- a/sound/soc/codecs/cs35l56-i2c.c +++ b/sound/soc/codecs/cs35l56-i2c.c @@ -62,10 +62,19 @@ static const struct i2c_device_id cs35l56_id_i2c[] = { }; MODULE_DEVICE_TABLE(i2c, cs35l56_id_i2c); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l56_asoc_acpi_match[] = { + { "CSC355C", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match); +#endif + static struct i2c_driver cs35l56_i2c_driver = { .driver = { .name = "cs35l56", .pm = &cs35l56_pm_ops_i2c_spi, + .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match), }, .id_table = cs35l56_id_i2c, .probe = cs35l56_i2c_probe, diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c index 996aab10500e..302f9c47407a 100644 --- a/sound/soc/codecs/cs35l56-spi.c +++ b/sound/soc/codecs/cs35l56-spi.c @@ -59,10 +59,19 @@ static const struct spi_device_id cs35l56_id_spi[] = { }; MODULE_DEVICE_TABLE(spi, cs35l56_id_spi); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l56_asoc_acpi_match[] = { + { "CSC355C", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match); +#endif + static struct spi_driver cs35l56_spi_driver = { .driver = { .name = "cs35l56", .pm = &cs35l56_pm_ops_i2c_spi, + .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match), }, .id_table = cs35l56_id_spi, .probe = cs35l56_spi_probe, From 3d521f9f3663ba7a22e56d339c6632f0ca787371 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Thu, 17 Aug 2023 17:32:56 +0800 Subject: [PATCH 7/7] ASoC: tas2781: fixed register access error when switching to other chips fixed register access error when switching to other tas2781 -- refresh the page inside regmap on the switched tas2781 Signed-off-by: Shenghao Ding Link: https://lore.kernel.org/r/20230817093257.951-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2781-comlib.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index a88c6c28a394..ffb26e4a7e2f 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -57,16 +57,17 @@ static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv, if (client->addr != tasdev->dev_addr) { client->addr = tasdev->dev_addr; - if (tasdev->cur_book == book) { - ret = regmap_write(map, - TASDEVICE_PAGE_SELECT, 0); - if (ret < 0) { - dev_err(tas_priv->dev, "%s, E=%d\n", - __func__, ret); - goto out; - } + /* All tas2781s share the same regmap, clear the page + * inside regmap once switching to another tas2781. + * Register 0 at any pages and any books inside tas2781 + * is the same one for page-switching. + */ + ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d\n", + __func__, ret); + goto out; } - goto out; } if (tasdev->cur_book != book) {