Unverified Commit 1decead8 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC/soundwire: log actual PING status on resume issues

Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>:

we've been stuck with problems in the dual-amplifier configurations where
one of the two devices seems to become UNATTACHED and never regains sync,
see https://github.com/thesofproject/linux/issues/3638.

This is a rather infrequent issue that may happen once or twice per month,
but still it remains a concern.

One possibility is that the device does lose sync but somehow our hardware
detection fails to see it resync.

This series just adds a basic read directly from the PING frames to help
confirm if yes/no the device regain sync.
parents 26bdcc4b 917df025
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -297,6 +297,38 @@ int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg)
	return ret;
}

/**
 * sdw_show_ping_status() - Direct report of PING status, to be used by Peripheral drivers
 * @bus: SDW bus
 * @sync_delay: Delay before reading status
 */
void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay)
{
	u32 status;

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

	/*
	 * wait for peripheral to sync if desired. 10-15ms should be more than
	 * enough in most cases.
	 */
	if (sync_delay)
		usleep_range(10000, 15000);

	mutex_lock(&bus->msg_lock);

	status = bus->ops->read_ping_status(bus);

	mutex_unlock(&bus->msg_lock);

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

/**
 * sdw_transfer_defer() - Asynchronously transfer message to a SDW Slave device
 * @bus: SDW bus
+8 −0
Original line number Diff line number Diff line
@@ -756,6 +756,14 @@ cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num)
}
EXPORT_SYMBOL(cdns_reset_page_addr);

u32 cdns_read_ping_status(struct sdw_bus *bus)
{
	struct sdw_cdns *cdns = bus_to_cdns(bus);

	return cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
}
EXPORT_SYMBOL(cdns_read_ping_status);

/*
 * IRQ handling
 */
+2 −0
Original line number Diff line number Diff line
@@ -177,6 +177,8 @@ enum sdw_command_response
cdns_xfer_msg_defer(struct sdw_bus *bus,
		    struct sdw_msg *msg, struct sdw_defer *defer);

u32 cdns_read_ping_status(struct sdw_bus *bus);

int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params);

int cdns_set_sdw_stream(struct snd_soc_dai *dai,
+1 −0
Original line number Diff line number Diff line
@@ -1262,6 +1262,7 @@ static struct sdw_master_ops sdw_intel_ops = {
	.set_bus_conf = cdns_bus_conf,
	.pre_bank_switch = intel_pre_bank_switch,
	.post_bank_switch = intel_post_bank_switch,
	.read_ping_status = cdns_read_ping_status,
};

static int intel_init(struct sdw_intel *sdw)
+5 −0
Original line number Diff line number Diff line
@@ -839,6 +839,8 @@ struct sdw_defer {
 * @set_bus_conf: Set the bus configuration
 * @pre_bank_switch: Callback for pre bank switch
 * @post_bank_switch: Callback for post bank switch
 * @read_ping_status: Read status from PING frames, reported with two bits per Device.
 * Bits 31:24 are reserved.
 */
struct sdw_master_ops {
	int (*read_prop)(struct sdw_bus *bus);
@@ -855,6 +857,7 @@ struct sdw_master_ops {
			struct sdw_bus_params *params);
	int (*pre_bank_switch)(struct sdw_bus *bus);
	int (*post_bank_switch)(struct sdw_bus *bus);
	u32 (*read_ping_status)(struct sdw_bus *bus);

};

@@ -919,6 +922,8 @@ 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);

/**
 * sdw_port_config: Master or Slave Port configuration
 *
Loading