diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 534c8795e7e85d..61e89a63cf3b60 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -16,6 +16,7 @@ #include #include #include "cadence_master.h" +#include "bus.h" #include "intel.h" #include "intel_auxdevice.h" @@ -363,6 +364,47 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx) } EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT); +static int intel_disable_runtime_pm_child_device(struct device *dev, void *data) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + unsigned long time; + + if (!slave->probed) { + dev_dbg(dev, "skipping device, no probed driver\n"); + return 0; + } + if (!slave->dev_num_sticky) { + dev_dbg(dev, "skipping device, never detected on bus\n"); + return 0; + } + + pm_runtime_disable(dev); + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(5000)); + + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + return -ETIMEDOUT; + } + return 0; +} + +void sdw_intel_pre_exit(struct sdw_intel_ctx *ctx) +{ + struct sdw_intel_link_res *link; + + list_for_each_entry(link, &ctx->link_list, list) { + struct sdw_bus *bus = &link->cdns->bus; + int ret; + + ret = device_for_each_child(bus->dev, NULL, intel_disable_runtime_pm_child_device); + if (ret < 0) + dev_err(bus->dev, "%s: intel_disable_runtime_pm_child_device failed: %d\n", + __func__, ret); + } +} +EXPORT_SYMBOL_NS(sdw_intel_pre_exit, SOUNDWIRE_INTEL_INIT); + void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx) { struct sdw_intel_link_dev *ldev; diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 8e78417156e3c6..1b3562815b1425 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -373,6 +373,7 @@ sdw_intel_probe(struct sdw_intel_res *res); int sdw_intel_startup(struct sdw_intel_ctx *ctx); void sdw_intel_exit(struct sdw_intel_ctx *ctx); +void sdw_intel_pre_exit(struct sdw_intel_ctx *ctx); irqreturn_t sdw_intel_thread(int irq, void *dev_id); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 66126fb31d52db..c7710606b8df4c 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -220,6 +220,9 @@ static int hda_sdw_exit(struct snd_sof_dev *sdev) hdev = sdev->pdata->hw_pdata; + if (hdev->sdw) + sdw_intel_pre_exit(hdev->sdw); + hda_sdw_int_enable(sdev, false); if (hdev->sdw)