|
@@ -152,6 +152,23 @@ static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context)
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
|
+static int sst_save_dsp_context_v2(struct intel_sst_drv *sst)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ ret = sst_prepare_and_post_msg(sst, SST_TASK_ID_MEDIA, IPC_CMD,
|
|
|
+ IPC_PREP_D3, PIPE_RSVD, 0, NULL, NULL,
|
|
|
+ true, true, false, true);
|
|
|
+
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(sst->dev, "not suspending FW!!, Err: %d\n", ret);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static struct intel_sst_ops mrfld_ops = {
|
|
|
.interrupt = intel_sst_interrupt_mrfld,
|
|
|
.irq_thread = intel_sst_irq_thread_mrfld,
|
|
@@ -160,6 +177,7 @@ static struct intel_sst_ops mrfld_ops = {
|
|
|
.reset = intel_sst_reset_dsp_mrfld,
|
|
|
.post_message = sst_post_message_mrfld,
|
|
|
.process_reply = sst_process_reply_mrfld,
|
|
|
+ .save_dsp_context = sst_save_dsp_context_v2,
|
|
|
.alloc_stream = sst_alloc_stream_mrfld,
|
|
|
.post_download = sst_post_download_mrfld,
|
|
|
};
|
|
@@ -418,6 +436,50 @@ static void intel_sst_remove(struct pci_dev *pci)
|
|
|
pci_set_drvdata(pci, NULL);
|
|
|
}
|
|
|
|
|
|
+static int intel_sst_runtime_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ if (ctx->sst_state == SST_RESET) {
|
|
|
+ dev_dbg(dev, "LPE is already in RESET state, No action\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ /* save fw context */
|
|
|
+ if (ctx->ops->save_dsp_context(ctx))
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ /* Move the SST state to Reset */
|
|
|
+ sst_set_fw_state_locked(ctx, SST_RESET);
|
|
|
+
|
|
|
+ synchronize_irq(ctx->irq_num);
|
|
|
+ flush_workqueue(ctx->post_msg_wq);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int intel_sst_runtime_resume(struct device *dev)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ mutex_lock(&ctx->sst_lock);
|
|
|
+ if (ctx->sst_state == SST_RESET) {
|
|
|
+ ret = sst_load_fw(ctx);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev, "FW download fail %d\n", ret);
|
|
|
+ ctx->sst_state = SST_RESET;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mutex_unlock(&ctx->sst_lock);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct dev_pm_ops intel_sst_pm = {
|
|
|
+ .runtime_suspend = intel_sst_runtime_suspend,
|
|
|
+ .runtime_resume = intel_sst_runtime_resume,
|
|
|
+};
|
|
|
+
|
|
|
/* PCI Routines */
|
|
|
static struct pci_device_id intel_sst_ids[] = {
|
|
|
{ PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
|
|
@@ -429,6 +491,11 @@ static struct pci_driver sst_driver = {
|
|
|
.id_table = intel_sst_ids,
|
|
|
.probe = intel_sst_probe,
|
|
|
.remove = intel_sst_remove,
|
|
|
+#ifdef CONFIG_PM
|
|
|
+ .driver = {
|
|
|
+ .pm = &intel_sst_pm,
|
|
|
+ },
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
module_pci_driver(sst_driver);
|