Skip to content

Commit 40b1c2f

Browse files
rfvirgiltiwai
authored andcommitted
ALSA: hda/cs35l56: Workaround bad dev-index on Lenovo Yoga Book 9i GenX
The Lenovo Yoga Book 9i GenX has the wrong values in the cirrus,dev-index _DSD property. Add a fixup for this model to ignore the property and hardcode the index from the I2C bus address. The error in the cirrus,dev-index property would prevent the second amp instance from probing. The component binding would never see all the required instances and so there would not be a binding between patch_realtek.c and the cs35l56 driver. Signed-off-by: Richard Fitzgerald <[email protected]> Reported-by: Brian Howard <[email protected]> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220228 Link: https://patch.msgid.link/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 4722727 commit 40b1c2f

File tree

1 file changed

+82
-28
lines changed

1 file changed

+82
-28
lines changed

sound/pci/hda/cs35l56_hda.c

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,52 @@ static int cs35l56_hda_system_resume(struct device *dev)
873873
return 0;
874874
}
875875

876+
static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr)
877+
{
878+
/* The cirrus,dev-index property has the wrong values */
879+
switch (*bus_addr) {
880+
case 0x30:
881+
cs35l56->index = 1;
882+
return 0;
883+
case 0x31:
884+
cs35l56->index = 0;
885+
return 0;
886+
default:
887+
/* There is a pseudo-address for broadcast to both amps - ignore it */
888+
dev_dbg(cs35l56->base.dev, "Ignoring I2C address %#x\n", *bus_addr);
889+
return 0;
890+
}
891+
}
892+
893+
static const struct {
894+
const char *sub;
895+
int (*fixup_fn)(struct cs35l56_hda *cs35l56, int *bus_addr);
896+
} cs35l56_hda_fixups[] = {
897+
{
898+
.sub = "17AA390B", /* Lenovo Yoga Book 9i GenX */
899+
.fixup_fn = cs35l56_hda_fixup_yoga9,
900+
},
901+
};
902+
903+
static int cs35l56_hda_apply_platform_fixups(struct cs35l56_hda *cs35l56, const char *sub,
904+
int *bus_addr)
905+
{
906+
int i;
907+
908+
if (IS_ERR(sub))
909+
return 0;
910+
911+
for (i = 0; i < ARRAY_SIZE(cs35l56_hda_fixups); i++) {
912+
if (strcasecmp(cs35l56_hda_fixups[i].sub, sub) == 0) {
913+
dev_dbg(cs35l56->base.dev, "Applying fixup for %s\n",
914+
cs35l56_hda_fixups[i].sub);
915+
return (cs35l56_hda_fixups[i].fixup_fn)(cs35l56, bus_addr);
916+
}
917+
}
918+
919+
return 0;
920+
}
921+
876922
static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
877923
{
878924
u32 values[HDA_MAX_COMPONENTS];
@@ -897,39 +943,47 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
897943
ACPI_COMPANION_SET(cs35l56->base.dev, adev);
898944
}
899945

900-
property = "cirrus,dev-index";
901-
ret = device_property_count_u32(cs35l56->base.dev, property);
902-
if (ret <= 0)
903-
goto err;
904-
905-
if (ret > ARRAY_SIZE(values)) {
906-
ret = -EINVAL;
907-
goto err;
908-
}
909-
nval = ret;
946+
/* Initialize things that could be overwritten by a fixup */
947+
cs35l56->index = -1;
910948

911-
ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
949+
sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
950+
ret = cs35l56_hda_apply_platform_fixups(cs35l56, sub, &id);
912951
if (ret)
913-
goto err;
952+
return ret;
914953

915-
cs35l56->index = -1;
916-
for (i = 0; i < nval; i++) {
917-
if (values[i] == id) {
918-
cs35l56->index = i;
919-
break;
920-
}
921-
}
922-
/*
923-
* It's not an error for the ID to be missing: for I2C there can be
924-
* an alias address that is not a real device. So reject silently.
925-
*/
926954
if (cs35l56->index == -1) {
927-
dev_dbg(cs35l56->base.dev, "No index found in %s\n", property);
928-
ret = -ENODEV;
929-
goto err;
930-
}
955+
property = "cirrus,dev-index";
956+
ret = device_property_count_u32(cs35l56->base.dev, property);
957+
if (ret <= 0)
958+
goto err;
931959

932-
sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
960+
if (ret > ARRAY_SIZE(values)) {
961+
ret = -EINVAL;
962+
goto err;
963+
}
964+
nval = ret;
965+
966+
ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
967+
if (ret)
968+
goto err;
969+
970+
for (i = 0; i < nval; i++) {
971+
if (values[i] == id) {
972+
cs35l56->index = i;
973+
break;
974+
}
975+
}
976+
977+
/*
978+
* It's not an error for the ID to be missing: for I2C there can be
979+
* an alias address that is not a real device. So reject silently.
980+
*/
981+
if (cs35l56->index == -1) {
982+
dev_dbg(cs35l56->base.dev, "No index found in %s\n", property);
983+
ret = -ENODEV;
984+
goto err;
985+
}
986+
}
933987

934988
if (IS_ERR(sub)) {
935989
dev_info(cs35l56->base.dev,

0 commit comments

Comments
 (0)