Commit ab2c9132 authored by Rander Wang's avatar Rander Wang Committed by Vinod Koul

soundwire: intel: add wake interrupt support

When system is suspended in clock stop mode on intel platforms, both
master and slave are in clock stop mode and soundwire bus is taken
over by a glue hardware. The bus message for jack event is processed
by this glue hardware, which will trigger an interrupt to resume audio
pci device. Then audio pci driver will resume soundwire master and slave,
transfer bus ownership to master, finally slave will report jack event
to master and codec driver is triggered to check jack status.

if a slave has been attached to a bus, the slave->dev_num_sticky
should be non-zero, so we can check this value to skip the
ghost devices defined in ACPI table but not populated in hardware.
Signed-off-by: default avatarRander Wang <rander.wang@intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20200716150947.22119-9-yung-chuan.liao@linux.intel.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 4a98a6b2
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw.h>
...@@ -436,7 +437,7 @@ static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop) ...@@ -436,7 +437,7 @@ static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop)
return ret; return ret;
} }
static void __maybe_unused intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
{ {
void __iomem *shim = sdw->link_res->shim; void __iomem *shim = sdw->link_res->shim;
unsigned int link_id = sdw->instance; unsigned int link_id = sdw->instance;
...@@ -1337,6 +1338,43 @@ static int intel_master_remove(struct platform_device *pdev) ...@@ -1337,6 +1338,43 @@ static int intel_master_remove(struct platform_device *pdev)
return 0; return 0;
} }
int intel_master_process_wakeen_event(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sdw_intel *sdw;
struct sdw_bus *bus;
void __iomem *shim;
u16 wake_sts;
sdw = platform_get_drvdata(pdev);
bus = &sdw->cdns.bus;
if (bus->prop.hw_disabled) {
dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", bus->link_id);
return 0;
}
shim = sdw->link_res->shim;
wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
if (!(wake_sts & BIT(sdw->instance)))
return 0;
/* disable WAKEEN interrupt ASAP to prevent interrupt flood */
intel_shim_wake(sdw, false);
/*
* resume the Master, which will generate a bus reset and result in
* Slaves re-attaching and be re-enumerated. The SoundWire physical
* device which generated the wake will trigger an interrupt, which
* will in turn cause the corresponding Linux Slave device to be
* resumed and the Slave codec driver to check the status.
*/
pm_request_resume(dev);
return 0;
}
static struct platform_driver sdw_intel_drv = { static struct platform_driver sdw_intel_drv = {
.probe = intel_master_probe, .probe = intel_master_probe,
.remove = intel_master_remove, .remove = intel_master_remove,
......
...@@ -47,5 +47,6 @@ struct sdw_intel { ...@@ -47,5 +47,6 @@ struct sdw_intel {
#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1) #define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1)
int intel_master_startup(struct platform_device *pdev); int intel_master_startup(struct platform_device *pdev);
int intel_master_process_wakeen_event(struct platform_device *pdev);
#endif /* __SDW_INTEL_LOCAL_H */ #endif /* __SDW_INTEL_LOCAL_H */
...@@ -415,5 +415,27 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx) ...@@ -415,5 +415,27 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx)
} }
EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT); EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT);
void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx)
{
struct sdw_intel_link_res *link;
u32 link_mask;
int i;
if (!ctx->links)
return;
link = ctx->links;
link_mask = ctx->link_mask;
/* Startup SDW Master devices */
for (i = 0; i < ctx->count; i++, link++) {
if (!(link_mask & BIT(i)))
continue;
intel_master_process_wakeen_event(link->pdev);
}
}
EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT);
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Intel Soundwire Init Library"); MODULE_DESCRIPTION("Intel Soundwire Init Library");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment