Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions drivers/soundwire/intel_auxdevice.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <linux/acpi.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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",
Expand Down
27 changes: 25 additions & 2 deletions sound/soc/sdca/sdca_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)) {
Expand Down