summaryrefslogtreecommitdiff
path: root/drivers/soundwire
diff options
context:
space:
mode:
authorRander Wang <rander.wang@intel.com>2020-01-14 18:08:42 -0600
committerVinod Koul <vkoul@kernel.org>2020-02-25 15:57:02 +0530
commitaa79293517b395c6094a382779c911689e8c9a8b (patch)
tree18950b9ff25651435abf11a54e9bd241cb52a68f /drivers/soundwire
parentdff70572e9a3a1a01d9dbc2279faa784d95f41b6 (diff)
soundwire: bus: fix io error when processing alert event
There are two types of io errors when processing alert event. a) the Master detects an ALERT status for e.g. a jack event and invokes the implementation-defined function in the Slave driver to check the jack status. At this time the codec is just suspended, so io registers can't be accessed. b) when waking up from clock stop mode1 state, where the bus needs a complete re-enumeration, Slave registers can't be accessed until the enumeration is complete. This patch resumes the Slave device and waits for initialization complete when processing slave alert event, so that registers on the Slave can be accessed without timeouts or io errors. Signed-off-by: Rander Wang <rander.wang@intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/r/20200115000844.14695-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'drivers/soundwire')
-rw-r--r--drivers/soundwire/bus.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 33bb273454cf..23bc24c8e9d1 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -890,12 +890,19 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
sdw_modify_slave_status(slave, SDW_SLAVE_ALERT);
+ ret = pm_runtime_get_sync(&slave->dev);
+ if (ret < 0 && ret != -EACCES) {
+ dev_err(&slave->dev, "Failed to resume device: %d\n", ret);
+ pm_runtime_put_noidle(slave->bus->dev);
+ return ret;
+ }
+
/* Read Instat 1, Instat 2 and Instat 3 registers */
ret = sdw_read(slave, SDW_SCP_INT1);
if (ret < 0) {
dev_err(slave->bus->dev,
"SDW_SCP_INT1 read failed:%d\n", ret);
- return ret;
+ goto io_err;
}
buf = ret;
@@ -903,7 +910,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
if (ret < 0) {
dev_err(slave->bus->dev,
"SDW_SCP_INT2/3 read failed:%d\n", ret);
- return ret;
+ goto io_err;
}
do {
@@ -983,7 +990,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
if (ret < 0) {
dev_err(slave->bus->dev,
"SDW_SCP_INT1 write failed:%d\n", ret);
- return ret;
+ goto io_err;
}
/*
@@ -994,7 +1001,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
if (ret < 0) {
dev_err(slave->bus->dev,
"SDW_SCP_INT1 read failed:%d\n", ret);
- return ret;
+ goto io_err;
}
_buf = ret;
@@ -1002,7 +1009,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
if (ret < 0) {
dev_err(slave->bus->dev,
"SDW_SCP_INT2/3 read failed:%d\n", ret);
- return ret;
+ goto io_err;
}
/* Make sure no interrupts are pending */
@@ -1023,6 +1030,10 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
if (count == SDW_READ_INTR_CLEAR_RETRY)
dev_warn(slave->bus->dev, "Reached MAX_RETRY on alert read\n");
+io_err:
+ pm_runtime_mark_last_busy(&slave->dev);
+ pm_runtime_put_autosuspend(&slave->dev);
+
return ret;
}