diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 3d1f9ce1eab734..ff2be403354f3f 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,62 @@ static void generic_new_peripheral_assigned(struct sdw_bus *bus, sdw->link_res->hw_ops->program_sdi(sdw, dev_num); } +/* + * Board-level overrides for the vendor-specific ACTMCTL timing fields. + * + * The _DSD values are patched in from NVS by the BIOS at _INI time and + * some boards ship values the attached peripherals cannot follow. On the + * HP OmniBook Ultra 14 (board 8EB4, BIOS F.06) the four TAS2783 amplifiers + * on links 1 and 2 only enumerate reliably with DOAIS=1 and DOAISE2=1; + * the BIOS provides DOAIS=3 and DOAISE2=0, with which three of the four + * amplifiers drop off the bus within a few hundred ms of attaching. + */ +struct sdw_intel_actmctl_quirk { + u8 link_mask; + u16 doais; + u16 doaise2; +}; + +static const struct sdw_intel_actmctl_quirk hp_omnibook_ultra_14_actmctl = { + .link_mask = BIT(1) | BIT(2), + .doais = 1, + .doaise2 = 1, +}; + +static const struct dmi_system_id sdw_intel_actmctl_quirk_table[] = { + { + /* HP OmniBook Ultra 14 (kd0xxx), 4x TAS2783 on links 1/2 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_BOARD_NAME, "8EB4"), + }, + .driver_data = (void *)&hp_omnibook_ultra_14_actmctl, + }, + {} +}; + +static void sdw_intel_apply_actmctl_quirk(struct sdw_bus *bus, + struct sdw_intel_prop *intel_prop) +{ + const struct sdw_intel_actmctl_quirk *quirk; + const struct dmi_system_id *id; + + id = dmi_first_match(sdw_intel_actmctl_quirk_table); + if (!id) + return; + + quirk = id->driver_data; + if (!(quirk->link_mask & BIT(bus->link_id))) + return; + + dev_info(bus->dev, "ACTMCTL quirk: doais %#x -> %#x, doaise2 %#x -> %#x\n", + intel_prop->doais, quirk->doais, + intel_prop->doaise2, quirk->doaise2); + + intel_prop->doais = quirk->doais; + intel_prop->doaise2 = quirk->doaise2; +} + static int sdw_master_read_intel_prop(struct sdw_bus *bus) { struct sdw_master_prop *prop = &bus->prop; @@ -238,6 +295,9 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) fwnode_property_read_u16(link, "intel-sdw-dods", &intel_prop->dods); + + sdw_intel_apply_actmctl_quirk(bus, intel_prop); + bus->vendor_specific_prop = intel_prop; dev_dbg(bus->dev, "doaise %#x doais %#x dodse %#x dods %#x\n", diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index e01d91eb3cc812..113f6643d2d182 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -87,6 +87,26 @@ static const char *get_sdca_function_name(u32 function_type) } } +/* + * Some platform firmware declares the Function Topology control (0x05) + * with a read-only access mode and no DisCo constant, so the function + * type can only be learned by reading it from the hardware. Fall back to + * a table of known peripherals in that case. + * + * HP OmniBook Ultra 14 (board 8EB4) does this for its four TI TAS2783 + * amplifiers, while its RT712 provides a DC value. + */ +static int sdca_fallback_function_type(struct sdw_slave *slave, u32 *function_type) +{ + /* Texas Instruments TAS2783 smart amplifier */ + if (slave->id.mfg_id == 0x0102 && slave->id.part_id == 0x0000) { + *function_type = SDCA_FUNCTION_TYPE_SMART_AMP; + return 0; + } + + return -ENODEV; +} + static int find_sdca_function(struct acpi_device *adev, void *data) { struct fwnode_handle *function_node = acpi_fwnode_handle(adev); @@ -135,8 +155,11 @@ static int find_sdca_function(struct acpi_device *adev, void *data) fwnode_handle_put(control5); if (ret < 0) { - dev_err(dev, "function type only supported as DisCo constant\n"); - return ret; + if (sdca_fallback_function_type(slave, &function_type)) { + dev_err(dev, "function type only supported as DisCo constant\n"); + return ret; + } + dev_info(dev, "function type not a DisCo constant, using fallback for known peripheral\n"); } if (!sdca_device_quirk_match(slave, SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING)) {