From cb073a016ccec9a7e7f015cd1e87b9372e08a0bb Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 8 Nov 2019 17:35:44 +0800 Subject: [PATCH] soundwire: intel: add support for jack detection in clock stop mode 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 special hardware. The bus message for jack event is processed by this special hardware, which will tigger a interrupt to ACPI system and 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. Signed-off-by: Rander Wang --- drivers/soundwire/intel.c | 38 +++++++++++++++++++++++++++++ include/linux/soundwire/sdw_intel.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index efa6db7e43b64a..0a8ff1391b2a0c 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -401,6 +401,44 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) } } +void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx) +{ + struct sdw_intel_link_res *link; + struct sdw_master_device *md; + struct sdw_slave *slave; + struct sdw_bus *bus; + + list_for_each_entry(link, &ctx->link_list, list) { + struct sdw_intel *sdw; + u16 wake_sts; + + md = link->md; + bus = &link->cdns->bus; + sdw = cdns_to_intel(link->cdns); + wake_sts = intel_readw(sdw->link_res->shim, SDW_SHIM_WAKESTS); + + /* disable WAKEEN interrupt ASAP to prevent interrupt flood */ + intel_shim_wake(sdw, false); + + if (!(wake_sts & BIT(sdw->instance))) + continue; + + /* + * wake up master and slave so that slave can notify master + * the wakeen event and let codec driver check codec status + */ + list_for_each_entry(slave, &bus->slaves, node) { + if (slave->prop.wake_capable) { + if (slave->status != SDW_SLAVE_ATTACHED) + continue; + + pm_request_resume(&slave->dev); + } + } + } +} +EXPORT_SYMBOL(sdw_intel_process_wakeen_event); + static int intel_link_power_down(struct sdw_intel *sdw) { int link_control, spa_mask, cpa_mask, ret; diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 9a9ce9fd1d71b2..d79c5c2090bc71 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -122,6 +122,8 @@ struct sdw_intel_res { int sdw_intel_acpi_scan(acpi_handle *parent_handle, struct sdw_intel_acpi_info *info); +void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx); + struct sdw_intel_ctx * sdw_intel_probe(struct sdw_intel_res *res);