]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
soundwire: intel: Add basic power management support
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Tue, 21 Jul 2020 20:37:11 +0000 (04:37 +0800)
committerVinod Koul <vkoul@kernel.org>
Mon, 17 Aug 2020 12:01:18 +0000 (17:31 +0530)
Implement suspend/resume capabilities (not runtime_pm for now)
The resume part is essentially a full-blown re-enumeration.

When S0ix is supported, we will select clock stop mode when the ACPI
target state is S0, and tear down the link for S3.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20200721203723.18305-2-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/soundwire/intel.c

index a283670659a92ccf5d49a68d0cb13a14e33a6551..88aeef8b7c0c7af72da750e5a9e75887c6129538 100644 (file)
@@ -463,7 +463,7 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
        mutex_unlock(sdw->link_res->shim_lock);
 }
 
-static int __maybe_unused intel_link_power_down(struct sdw_intel *sdw)
+static int intel_link_power_down(struct sdw_intel *sdw)
 {
        int link_control, spa_mask, cpa_mask;
        unsigned int link_id = sdw->instance;
@@ -1376,12 +1376,89 @@ int intel_master_process_wakeen_event(struct platform_device *pdev)
        return 0;
 }
 
+/*
+ * PM calls
+ */
+
+#ifdef CONFIG_PM
+
+static int intel_suspend(struct device *dev)
+{
+       struct sdw_cdns *cdns = dev_get_drvdata(dev);
+       struct sdw_intel *sdw = cdns_to_intel(cdns);
+       struct sdw_bus *bus = &cdns->bus;
+       int ret;
+
+       if (bus->prop.hw_disabled) {
+               dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
+                       bus->link_id);
+               return 0;
+       }
+
+       ret = sdw_cdns_enable_interrupt(cdns, false);
+       if (ret < 0) {
+               dev_err(dev, "cannot disable interrupts on suspend\n");
+               return ret;
+       }
+
+       ret = intel_link_power_down(sdw);
+       if (ret) {
+               dev_err(dev, "Link power down failed: %d", ret);
+               return ret;
+       }
+
+       intel_shim_wake(sdw, false);
+
+       return 0;
+}
+
+static int intel_resume(struct device *dev)
+{
+       struct sdw_cdns *cdns = dev_get_drvdata(dev);
+       struct sdw_intel *sdw = cdns_to_intel(cdns);
+       struct sdw_bus *bus = &cdns->bus;
+       int ret;
+
+       if (bus->prop.hw_disabled) {
+               dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
+                       bus->link_id);
+               return 0;
+       }
+
+       ret = intel_init(sdw);
+       if (ret) {
+               dev_err(dev, "%s failed: %d", __func__, ret);
+               return ret;
+       }
+
+       ret = sdw_cdns_enable_interrupt(cdns, true);
+       if (ret < 0) {
+               dev_err(dev, "cannot enable interrupts during resume\n");
+               return ret;
+       }
+
+       ret = sdw_cdns_exit_reset(cdns);
+       if (ret < 0) {
+               dev_err(dev, "unable to exit bus reset sequence during resume\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+#endif
+
+static const struct dev_pm_ops intel_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
+};
+
 static struct platform_driver sdw_intel_drv = {
        .probe = intel_master_probe,
        .remove = intel_master_remove,
        .driver = {
                .name = "intel-sdw",
-       },
+               .pm = &intel_pm,
+       }
 };
 
 module_platform_driver(sdw_intel_drv);