ASoC: SOF: PM: Add support for DSP D0i3 state when entering S0ix
authorKeyon Jie <yang.jie@linux.intel.com>
Fri, 25 Oct 2019 22:41:21 +0000 (17:41 -0500)
committerMark Brown <broonie@kernel.org>
Mon, 28 Oct 2019 14:46:39 +0000 (14:46 +0000)
When system is entering into S0ix, the PCI device may transition to the
D0i3 substate instead of D3. In D0i3, some always-on functionality can
be enabled, such as acoustic event detection, voice activity detection
or hotwording. When an event is detected, the DSP firmware can wake-up
the device for a transition to D0 with an interrupt.

Signed-off-by: Keyon Jie <yang.jie@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191025224122.7718-26-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/pm.c

index 99e4e6ffff74f3816eb06f06248865858131fb30..560a937e048420853436032d1640f57c98cf64af 100644 (file)
@@ -430,12 +430,58 @@ EXPORT_SYMBOL(snd_sof_set_d0_substate);
 
 int snd_sof_resume(struct device *dev)
 {
+       struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+       int ret;
+
+       if (sdev->s0_suspend) {
+               /* resume from D0I3 */
+               dev_dbg(sdev->dev, "DSP will exit from D0i3...\n");
+               ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I0);
+               if (ret == -ENOTSUPP) {
+                       /* fallback to resume from D3 */
+                       dev_dbg(sdev->dev, "D0i3 not supported, fall back to resume from D3...\n");
+                       goto d3_resume;
+               } else if (ret < 0) {
+                       dev_err(sdev->dev, "error: failed to exit from D0I3 %d\n",
+                               ret);
+                       return ret;
+               }
+
+               /* platform-specific resume from D0i3 */
+               return snd_sof_dsp_resume(sdev);
+       }
+
+d3_resume:
+       /* resume from D3 */
        return sof_resume(dev, false);
 }
 EXPORT_SYMBOL(snd_sof_resume);
 
 int snd_sof_suspend(struct device *dev)
 {
+       struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+       int ret;
+
+       if (sdev->s0_suspend) {
+               /* suspend to D0i3 */
+               dev_dbg(sdev->dev, "DSP is trying to enter D0i3...\n");
+               ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I3);
+               if (ret == -ENOTSUPP) {
+                       /* fallback to D3 suspend */
+                       dev_dbg(sdev->dev, "D0i3 not supported, fall back to D3...\n");
+                       goto d3_suspend;
+               } else if (ret < 0) {
+                       dev_err(sdev->dev, "error: failed to enter D0I3, %d\n",
+                               ret);
+                       return ret;
+               }
+
+               /* platform-specific suspend to D0i3 */
+               return snd_sof_dsp_suspend(sdev);
+       }
+
+d3_suspend:
+       /* suspend to D3 */
        return sof_suspend(dev, false);
 }
 EXPORT_SYMBOL(snd_sof_suspend);