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
23 changes: 18 additions & 5 deletions drivers/soundwire/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,13 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
bus->params.curr_dr_freq = bus->params.max_dr_freq;
bus->params.curr_bank = SDW_BANK0;
bus->params.next_bank = SDW_BANK1;
/*
* Set is_present = true by default. It will be set to false when no peripherals
* are attached on the bus.
*/
bus->is_present = true;

init_completion(&bus->enumeration_complete);
return 0;
}
EXPORT_SYMBOL(sdw_bus_master_add);
Expand Down Expand Up @@ -308,13 +314,16 @@ int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg)
* sdw_show_ping_status() - Direct report of PING status, to be used by Peripheral drivers
* @bus: SDW bus
* @sync_delay: Delay before reading status
*
* returns 0 if there is no peripherals attached, 1 if there are peripherals attached
* or a negative error code.
*/
void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay)
int sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay)
{
u32 status;

if (!bus->ops->read_ping_status)
return;
return -ENOTSUPP;

/*
* wait for peripheral to sync if desired. 10-15ms should be more than
Expand All @@ -329,10 +338,13 @@ void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay)

mutex_unlock(&bus->msg_lock);

if (!status)
if (!status) {
dev_warn(bus->dev, "%s: no peripherals attached\n", __func__);
else
dev_dbg(bus->dev, "PING status: %#x\n", status);
return 0;
}

dev_dbg(bus->dev, "PING status: %#x\n", status);
return 1;
}
EXPORT_SYMBOL(sdw_show_ping_status);

Expand Down Expand Up @@ -847,6 +859,7 @@ static int sdw_program_device_num(struct sdw_bus *bus, bool *programmed)
if (ret == -ENODATA) { /* end of device id reads */
dev_dbg(bus->dev, "No more devices to enumerate\n");
ret = 0;
complete_all(&bus->enumeration_complete);
break;
}
if (ret < 0) {
Expand Down
7 changes: 6 additions & 1 deletion include/linux/soundwire/sdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
struct fwnode_handle *fwnode);
void sdw_bus_master_delete(struct sdw_bus *bus);

void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay);
int sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay);

/**
* struct sdw_port_config: Master or Slave Port configuration
Expand Down Expand Up @@ -1001,6 +1001,8 @@ struct sdw_stream_runtime {
* transport and port parameters
* @defer_msg: Defer message
* @params: Current bus parameters
* @enumeration_complete: completion utility to control potential races between
* enumeration completion and peripheral presence checks.
* @stream_refcount: number of streams currently using this bus
* @bpt_stream_refcount: number of BTP streams currently using this bus (should
* be zero or one, multiple streams per link is not supported).
Expand Down Expand Up @@ -1029,6 +1031,7 @@ struct sdw_stream_runtime {
* are supported. This flag is populated by drivers after reading
* appropriate firmware (ACPI/DT).
* @lane_used_bandwidth: how much bandwidth in bits per second is used by each lane
* @is_present: indicates whether any peripheral is present on the bus.
*/
struct sdw_bus {
struct device *dev;
Expand All @@ -1042,6 +1045,7 @@ struct sdw_bus {
struct list_head m_rt_list;
struct sdw_defer defer_msg;
struct sdw_bus_params params;
struct completion enumeration_complete;
int stream_refcount;
int bpt_stream_refcount;
struct sdw_stream_runtime *bpt_stream;
Expand All @@ -1064,6 +1068,7 @@ struct sdw_bus {
#endif
bool multi_link;
unsigned int lane_used_bandwidth[SDW_MAX_LANES];
bool is_present;
};

struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name, enum sdw_stream_type type);
Expand Down
47 changes: 45 additions & 2 deletions sound/soc/sof/intel/hda.c
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,8 @@ static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev,
return adr_dev;
}

#define SDW_ENUM_TIMEOUT_MS 3000

static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
Expand All @@ -1313,7 +1315,9 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
struct sdw_peripherals *peripherals;
struct snd_soc_acpi_mach *mach;
struct sof_intel_hda_dev *hdev;
struct sdw_slave *slave;
int link_index, link_num;
unsigned long time;
int amp_index = 1;
u32 link_mask = 0;
int i;
Expand Down Expand Up @@ -1415,14 +1419,53 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
if (!links)
return NULL;

/*
* Recalculate the link_mask as a link will be empty if all peripherals on the link are
* not enumerated
*/
link_mask = 0;
/* Generate snd_soc_acpi_link_adr struct for each peripheral reported by the ACPI table */
for (i = 0; i < peripherals->num_peripherals; i++) {
slave = peripherals->array[i];

if (!slave->bus->is_present)
continue;

if (link_mask & BIT(slave->bus->link_id)) {
/*
* At least one peripheral is present on the link which means that this
* link has already been enumerated
*/
goto skip_wait_link_enumeration;
}

if (sdw_show_ping_status(slave->bus, true) == 0) {
/* no peripherals attached on this link */
slave->bus->is_present = false;
continue;
}

time = wait_for_completion_timeout(&slave->bus->enumeration_complete,
msecs_to_jiffies(SDW_ENUM_TIMEOUT_MS));
if (!time) {
dev_warn(slave->bus->dev, "No peripheral is present\n");
slave->bus->is_present = false;
continue;
}

skip_wait_link_enumeration:
/* Check if the SoundWire peripheral is present */
if (!slave->dev_num_sticky) {
dev_warn(&slave->dev, "SoundWire peripheral is not present\n");
continue;
}
/* link_index = the number of used links below the current link */
link_index = hweight32(link_mask & (BIT(peripherals->array[i]->bus->link_id) - 1));
links[link_index].adr_d = find_acpi_adr_device(sdev->dev, peripherals->array[i],
link_index = hweight32(link_mask & (BIT(slave->bus->link_id) - 1));
links[link_index].adr_d = find_acpi_adr_device(sdev->dev, slave,
&links[link_index], &amp_index);
if (!links[link_index].adr_d)
return NULL;
link_mask |= BIT(slave->bus->link_id);
}

mach->drv_name = "sof_sdw";
Expand Down
Loading