+static int intel_sst_suspend(struct device *dev)
+{
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+ struct sst_fw_save *fw_save;
+ int i, ret = 0;
+
+ /* check first if we are already in SW reset */
+ if (ctx->sst_state == SST_RESET)
+ return 0;
+
+ /*
+ * check if any stream is active and running
+ * they should already by suspend by soc_suspend
+ */
+ for (i = 1; i <= ctx->info.max_streams; i++) {
+ struct stream_info *stream = &ctx->streams[i];
+
+ if (stream->status == STREAM_RUNNING) {
+ dev_err(dev, "stream %d is running, cant susupend, abort\n", i);
+ return -EBUSY;
+ }
+ }
+ synchronize_irq(ctx->irq_num);
+ flush_workqueue(ctx->post_msg_wq);
+
+ /* Move the SST state to Reset */
+ sst_set_fw_state_locked(ctx, SST_RESET);
+
+ /* tell DSP we are suspending */
+ if (ctx->ops->save_dsp_context(ctx))
+ return -EBUSY;
+
+ /* save the memories */
+ fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL);
+ if (!fw_save)
+ return -ENOMEM;
+ fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
+ if (!fw_save->iram) {
+ ret = -ENOMEM;
+ goto iram;
+ }
+ fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
+ if (!fw_save->dram) {
+ ret = -ENOMEM;
+ goto dram;
+ }
+ fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
+ if (!fw_save->sram) {
+ ret = -ENOMEM;
+ goto sram;
+ }
+
+ fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
+ if (!fw_save->ddr) {
+ ret = -ENOMEM;
+ goto ddr;
+ }
+
+ memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base);
+ memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base);
+ memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE);
+ memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base);
+
+ ctx->fw_save = fw_save;
+ ctx->ops->reset(ctx);
+ return 0;
+ddr:
+ kfree(fw_save->sram);
+sram:
+ kfree(fw_save->dram);
+dram:
+ kfree(fw_save->iram);
+iram:
+ kfree(fw_save);
+ return ret;
+}
+