ASoC: Intel: Skylake: Flush pending D0i3 request on suspend
authorJayachandran B <jayachandran.b@intel.com>
Thu, 3 Nov 2016 11:37:21 +0000 (17:07 +0530)
committerMark Brown <broonie@kernel.org>
Wed, 9 Nov 2016 15:22:48 +0000 (15:22 +0000)
While going to suspend, if we have any pending D0i3 work scheduled,
flush that and force the DSP to goto D0i3 mode before going to suspend.

Signed-off-by: Jayachandran B <jayachandran.b@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h

index 87fc647fa04cda4dc40ab1cce0a50a4a0e721f3e..4ae021aabc3a181e4464937d254a70a7bb6f5185 100644 (file)
@@ -294,6 +294,33 @@ int skl_free_dsp(struct skl *skl)
        return 0;
 }
 
+/*
+ * In the case of "suspend_active" i.e, the Audio IP being active
+ * during system suspend, immediately excecute any pending D0i3 work
+ * before suspending. This is needed for the IP to work in low power
+ * mode during system suspend. In the case of normal suspend, cancel
+ * any pending D0i3 work.
+ */
+int skl_suspend_late_dsp(struct skl *skl)
+{
+       struct skl_sst *ctx = skl->skl_sst;
+       struct delayed_work *dwork;
+
+       if (!ctx)
+               return 0;
+
+       dwork = &ctx->d0i3.work;
+
+       if (dwork->work.func) {
+               if (skl->supend_active)
+                       flush_delayed_work(dwork);
+               else
+                       cancel_delayed_work_sync(dwork);
+       }
+
+       return 0;
+}
+
 int skl_suspend_dsp(struct skl *skl)
 {
        struct skl_sst *ctx = skl->skl_sst;
index ed59783e98461ba8fc9281c246aaf931de32a420..61a484888cfafc6968e08525bdc6e32bef4d832a 100644 (file)
@@ -228,6 +228,15 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
        return 0;
 }
 
+static int skl_suspend_late(struct device *dev)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+       struct skl *skl = ebus_to_skl(ebus);
+
+       return skl_suspend_late_dsp(skl);
+}
+
 #ifdef CONFIG_PM
 static int _skl_suspend(struct hdac_ext_bus *ebus)
 {
@@ -390,6 +399,7 @@ static int skl_runtime_resume(struct device *dev)
 static const struct dev_pm_ops skl_pm = {
        SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume)
        SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL)
+       .suspend_late = skl_suspend_late,
 };
 
 /*
index 88ba54ba5f7269ff9c621bdff093a18f7768bdb9..4986e3929dd3a77f4ed637a6fec130f1b5efb555 100644 (file)
@@ -124,6 +124,7 @@ int skl_get_dmic_geo(struct skl *skl);
 int skl_nhlt_update_topology_bin(struct skl *skl);
 int skl_init_dsp(struct skl *skl);
 int skl_free_dsp(struct skl *skl);
+int skl_suspend_late_dsp(struct skl *skl);
 int skl_suspend_dsp(struct skl *skl);
 int skl_resume_dsp(struct skl *skl);
 void skl_cleanup_resources(struct skl *skl);