[PATCH v4 4/6] ALSA: hda/tas2781: Add tas2781 HDA driver

From: Shenghao Ding
Date: Sat May 27 2023 - 18:36:18 EST


Add tas2781 configs for Lenovo Laptops. All of the tas2781s in the laptop
will be aggregated as one codec.

Signed-off-by: Shenghao Ding <13916275206@xxxxxxx>

---
Changes in v4:
- Add tiwai@xxxxxxx into Cc list
- remove useless index
- combine ALC287_FIXUP_TAS2781_I2C_2 and ALC287_FIXUP_TAS2781_I2C_4 together as
ALC287_FIXUP_TAS2781_I2C, The code view all the tas2781s in the laptop as one instance.
Changes to be committed:
modified: sound/pci/hda/patch_realtek.c
---
sound/pci/hda/patch_realtek.c | 98 +++++++++++++++++++++++++++++++++--
1 file changed, 95 insertions(+), 3 deletions(-)

diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7b5f194513c7..7a333443296f 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6705,7 +6705,7 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_
}
}

-struct cs35l41_dev_name {
+struct scodec_dev_name {
const char *bus;
const char *hid;
int index;
@@ -6714,7 +6714,7 @@ struct cs35l41_dev_name {
/* match the device name in a slightly relaxed manner */
static int comp_match_cs35l41_dev_name(struct device *dev, void *data)
{
- struct cs35l41_dev_name *p = data;
+ struct scodec_dev_name *p = data;
const char *d = dev_name(dev);
int n = strlen(p->bus);
char tmp[32];
@@ -6730,12 +6730,32 @@ static int comp_match_cs35l41_dev_name(struct device *dev, void *data)
return !strcmp(d + n, tmp);
}

+static int comp_match_tas2781_dev_name(struct device *dev,
+ void *data)
+{
+ struct scodec_dev_name *p = data;
+ const char *d = dev_name(dev);
+ int n = strlen(p->bus);
+ char tmp[32];
+
+ /* check the bus name */
+ if (strncmp(d, p->bus, n))
+ return 0;
+ /* skip the bus number */
+ if (isdigit(d[n]))
+ n++;
+ /* the rest must be exact matching */
+ snprintf(tmp, sizeof(tmp), "-%s:00", p->hid);
+
+ return !strcmp(d + n, tmp);
+}
+
static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
const char *hid, int count)
{
struct device *dev = hda_codec_dev(cdc);
struct alc_spec *spec = cdc->spec;
- struct cs35l41_dev_name *rec;
+ struct scodec_dev_name *rec;
int ret, i;

switch (action) {
@@ -6760,6 +6780,38 @@ static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char
}
}

+static void tas2781_generic_fixup(struct hda_codec *cdc, int action,
+ const char *bus, const char *hid)
+{
+ struct device *dev = hda_codec_dev(cdc);
+ struct alc_spec *spec = cdc->spec;
+ struct scodec_dev_name *rec;
+ int ret;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL);
+ if (!rec)
+ return;
+ rec->bus = bus;
+ rec->hid = hid;
+ rec->index = 0;
+ spec->comps[0].codec = cdc;
+ component_match_add(dev, &spec->match,
+ comp_match_tas2781_dev_name, rec);
+ ret = component_master_add_with_match(dev, &comp_master_ops,
+ spec->match);
+ if (ret)
+ codec_err(cdc,
+ "Fail to register component aggregator %d\n",
+ ret);
+ else
+ spec->gen.pcm_playback_hook =
+ comp_generic_playback_hook;
+ break;
+ }
+}
+
static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 2);
@@ -6787,6 +6839,12 @@ static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const st
cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0101", 2);
}

+static void tas2781_fixup_i2c(struct hda_codec *cdc,
+ const struct hda_fixup *fix, int action)
+{
+ tas2781_generic_fixup(cdc, action, "i2c", "TIAS2781");
+}
+
/* for alc295_fixup_hp_top_speakers */
#include "hp_x360_helper.c"

@@ -7203,6 +7261,7 @@ enum {
ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS,
ALC236_FIXUP_DELL_DUAL_CODECS,
+ ALC287_FIXUP_TAS2781_I2C,
};

/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -9207,6 +9266,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
},
+ [ALC287_FIXUP_TAS2781_I2C] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = tas2781_fixup_i2c,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+ },
};

static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -9754,6 +9819,33 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3881, "YB9 dual powe mode2 YC",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3884, "Y780 YG DUAL",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38c3, "Y980 DUAL", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38cb, "Y790 YG DUAL",
+ ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38cd, "Y790 VECO DUAL",
+ ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
--
2.34.1