Commit 40b1c2f9 authored by Richard Fitzgerald's avatar Richard Fitzgerald Committed by Takashi Iwai
Browse files

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: default avatarRichard Fitzgerald <rf@opensource.cirrus.com>
Reported-by: default avatarBrian Howard <blhoward2@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220228
Link: https://patch.msgid.link/20250714110154.204740-1-rf@opensource.cirrus.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 47227273
Loading
Loading
Loading
Loading
+82 −28
Original line number Diff line number Diff line
@@ -873,6 +873,52 @@ static int cs35l56_hda_system_resume(struct device *dev)
	return 0;
}

static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr)
{
	/* The cirrus,dev-index property has the wrong values */
	switch (*bus_addr) {
	case 0x30:
		cs35l56->index = 1;
		return 0;
	case 0x31:
		cs35l56->index = 0;
		return 0;
	default:
		/* There is a pseudo-address for broadcast to both amps - ignore it */
		dev_dbg(cs35l56->base.dev, "Ignoring I2C address %#x\n", *bus_addr);
		return 0;
	}
}

static const struct {
	const char *sub;
	int (*fixup_fn)(struct cs35l56_hda *cs35l56, int *bus_addr);
} cs35l56_hda_fixups[] = {
	{
		.sub = "17AA390B", /* Lenovo Yoga Book 9i GenX */
		.fixup_fn = cs35l56_hda_fixup_yoga9,
	},
};

static int cs35l56_hda_apply_platform_fixups(struct cs35l56_hda *cs35l56, const char *sub,
					     int *bus_addr)
{
	int i;

	if (IS_ERR(sub))
		return 0;

	for (i = 0; i < ARRAY_SIZE(cs35l56_hda_fixups); i++) {
		if (strcasecmp(cs35l56_hda_fixups[i].sub, sub) == 0) {
			dev_dbg(cs35l56->base.dev, "Applying fixup for %s\n",
				cs35l56_hda_fixups[i].sub);
			return (cs35l56_hda_fixups[i].fixup_fn)(cs35l56, bus_addr);
		}
	}

	return 0;
}

static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
{
	u32 values[HDA_MAX_COMPONENTS];
@@ -897,6 +943,15 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
		ACPI_COMPANION_SET(cs35l56->base.dev, adev);
	}

	/* Initialize things that could be overwritten by a fixup */
	cs35l56->index = -1;

	sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
	ret = cs35l56_hda_apply_platform_fixups(cs35l56, sub, &id);
	if (ret)
		return ret;

	if (cs35l56->index == -1) {
		property = "cirrus,dev-index";
		ret = device_property_count_u32(cs35l56->base.dev, property);
		if (ret <= 0)
@@ -912,13 +967,13 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
		if (ret)
			goto err;

	cs35l56->index = -1;
		for (i = 0; i < nval; i++) {
			if (values[i] == id) {
				cs35l56->index = i;
				break;
			}
		}

		/*
		 * It's not an error for the ID to be missing: for I2C there can be
		 * an alias address that is not a real device. So reject silently.
@@ -928,8 +983,7 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
			ret = -ENODEV;
			goto err;
		}

	sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
	}

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