summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorRichard Fitzgerald <rf@opensource.cirrus.com>2024-01-29 16:27:32 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-10-17 15:24:07 +0200
commite905bc71e7ed093bbfe7cd15c6742afba7304c58 (patch)
tree903741ba00437000aeecb2e48f7488a16747c32f /sound/soc
parent9790a7acc3527f5cd2dd3b273f6df8e02e432793 (diff)
downloadlinux-e905bc71e7ed093bbfe7cd15c6742afba7304c58.tar.gz
linux-e905bc71e7ed093bbfe7cd15c6742afba7304c58.tar.bz2
linux-e905bc71e7ed093bbfe7cd15c6742afba7304c58.zip
ASoC: cs35l56: Load tunings for the correct speaker models
[ Upstream commit 245eeff18d7a37693815250ae15979ce98c3d190 ] If the "spk-id-gpios" property is present it points to GPIOs whose value must be used to select the correct bin file to match the speakers. Some manufacturers use multiple sources of speakers, which need different tunings for best performance. On these models the type of speaker fitted is indicated by the values of one or more GPIOs. The number formed by the GPIOs identifies the tuning required. The speaker ID must be used in combination with the subsystem ID (either from PCI SSID or cirrus,firmware-uid property), because the GPIOs can only indicate variants of a specific model. Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Fixes: 1a1c3d794ef6 ("ASoC: cs35l56: Use PCI SSID as the firmware UID") Link: https://msgid.link/r/20240129162737.497-14-rf@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/cs35l56-shared.c36
-rw-r--r--sound/soc/codecs/cs35l56.c32
-rw-r--r--sound/soc/codecs/cs35l56.h1
3 files changed, 64 insertions, 5 deletions
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index 69c951e30584..d3db89c93b33 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -5,6 +5,7 @@
// Copyright (C) 2023 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
+#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
@@ -695,6 +696,41 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
}
EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED);
+int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base)
+{
+ struct gpio_descs *descs;
+ int speaker_id;
+ int i, ret;
+
+ /* Read the speaker type qualifier from the motherboard GPIOs */
+ descs = gpiod_get_array_optional(cs35l56_base->dev, "spk-id", GPIOD_IN);
+ if (!descs) {
+ return -ENOENT;
+ } else if (IS_ERR(descs)) {
+ ret = PTR_ERR(descs);
+ return dev_err_probe(cs35l56_base->dev, ret, "Failed to get spk-id-gpios\n");
+ }
+
+ speaker_id = 0;
+ for (i = 0; i < descs->ndescs; i++) {
+ ret = gpiod_get_value_cansleep(descs->desc[i]);
+ if (ret < 0) {
+ dev_err_probe(cs35l56_base->dev, ret, "Failed to read spk-id[%d]\n", i);
+ goto err;
+ }
+
+ speaker_id |= (ret << i);
+ }
+
+ dev_dbg(cs35l56_base->dev, "Speaker ID = %d\n", speaker_id);
+ ret = speaker_id;
+err:
+ gpiod_put_array(descs);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, SND_SOC_CS35L56_SHARED);
+
static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = {
[0x0C] = 128000,
[0x0F] = 256000,
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index c855ef3ec665..015269f0db54 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -941,10 +941,19 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
if (!cs35l56->dsp.system_name &&
(snd_soc_card_get_pci_ssid(component->card, &vendor, &device) == 0)) {
- cs35l56->dsp.system_name = devm_kasprintf(cs35l56->base.dev,
- GFP_KERNEL,
- "%04x%04x",
- vendor, device);
+ /* Append a speaker qualifier if there is a speaker ID */
+ if (cs35l56->speaker_id >= 0) {
+ cs35l56->dsp.system_name = devm_kasprintf(cs35l56->base.dev,
+ GFP_KERNEL,
+ "%04x%04x-spkid%d",
+ vendor, device,
+ cs35l56->speaker_id);
+ } else {
+ cs35l56->dsp.system_name = devm_kasprintf(cs35l56->base.dev,
+ GFP_KERNEL,
+ "%04x%04x",
+ vendor, device);
+ }
if (!cs35l56->dsp.system_name)
return -ENOMEM;
}
@@ -1230,7 +1239,13 @@ static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
if (ret < 0)
return 0;
- cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL);
+ /* Append a speaker qualifier if there is a speaker ID */
+ if (cs35l56->speaker_id >= 0)
+ cs35l56->dsp.system_name = devm_kasprintf(dev, GFP_KERNEL, "%s-spkid%d",
+ prop, cs35l56->speaker_id);
+ else
+ cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL);
+
if (cs35l56->dsp.system_name == NULL)
return -ENOMEM;
@@ -1245,6 +1260,7 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
init_completion(&cs35l56->init_completion);
mutex_init(&cs35l56->base.irq_lock);
+ cs35l56->speaker_id = -ENOENT;
dev_set_drvdata(cs35l56->base.dev, cs35l56);
@@ -1281,6 +1297,12 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
}
+ ret = cs35l56_get_speaker_id(&cs35l56->base);
+ if ((ret < 0) && (ret != -ENOENT))
+ goto err;
+
+ cs35l56->speaker_id = ret;
+
ret = cs35l56_get_firmware_uid(cs35l56);
if (ret != 0)
goto err;
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index d9fbf568a195..b000e7365e40 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -44,6 +44,7 @@ struct cs35l56_private {
bool sdw_attached;
struct completion init_completion;
+ int speaker_id;
u32 rx_mask;
u32 tx_mask;
u8 asp_slot_width;