/* boot */
        wait_queue_head_t boot_wait;
        bool boot_complete;
+       struct sst_fw *fw;
 
        /* IPC messaging */
        struct list_head tx_list;
        .ops = &sst_byt_ops,
 };
 
+int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+
+       dev_dbg(byt->dev, "dsp reset\n");
+       sst_dsp_reset(byt->dsp);
+       sst_byt_drop_all(byt);
+       dev_dbg(byt->dev, "dsp in reset\n");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq);
+
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+
+       dev_dbg(byt->dev, "free all blocks and unload fw\n");
+       sst_fw_unload(byt->fw);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late);
+
+int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+       int ret;
+
+       dev_dbg(byt->dev, "reload dsp fw\n");
+
+       sst_dsp_reset(byt->dsp);
+
+       ret = sst_fw_reload(byt->fw);
+       if (ret <  0) {
+               dev_err(dev, "error: failed to reload firmware\n");
+               return ret;
+       }
+
+       /* wait for DSP boot completion */
+       byt->boot_complete = false;
+       sst_dsp_boot(byt->dsp);
+       dev_dbg(byt->dev, "dsp booting...\n");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_boot);
+
+int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+       int err;
+
+       dev_dbg(byt->dev, "wait for dsp reboot\n");
+
+       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
+                                msecs_to_jiffies(IPC_BOOT_MSECS));
+       if (err == 0) {
+               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
+               return -EIO;
+       }
+
+       dev_dbg(byt->dev, "dsp rebooted\n");
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
+
 int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
 {
        struct sst_byt *byt;
        }
 
        pdata->dsp = byt;
+       byt->fw = byt_sst_fw;
 
        return 0;
 
 
 
        /* latest DSP DMA hw pointer */
        u32 hw_ptr;
+
+       struct work_struct work;
 };
 
 /* private data for the driver */
        return 0;
 }
 
+static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_byt *byt = pdata->byt;
+       int ret;
+
+       /* commit stream using existing stream params */
+       ret = sst_byt_stream_commit(byt, pcm_data->stream);
+       if (ret < 0) {
+               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
+               return ret;
+       }
+
+       sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
+
+       dev_dbg(rtd->dev, "stream context restored at offset %d\n",
+               pcm_data->hw_ptr);
+
+       return 0;
+}
+
+static void sst_byt_pcm_work(struct work_struct *work)
+{
+       struct sst_byt_pcm_data *pcm_data =
+               container_of(work, struct sst_byt_pcm_data, work);
+
+       sst_byt_pcm_restore_stream_context(pcm_data->substream);
+}
+
 static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
                sst_byt_stream_start(byt, pcm_data->stream, 0);
                break;
        case SNDRV_PCM_TRIGGER_RESUME:
+               schedule_work(&pcm_data->work);
+               break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                sst_byt_stream_resume(byt, pcm_data->stream);
                break;
        priv_data->byt = plat_data->dsp;
        snd_soc_platform_set_drvdata(platform, priv_data);
 
-       for (i = 0; i < ARRAY_SIZE(byt_dais); i++)
+       for (i = 0; i < ARRAY_SIZE(byt_dais); i++) {
                mutex_init(&priv_data->pcm[i].mutex);
+               INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
+       }
 
        return 0;
 }
        .name           = "byt-dai",
 };
 
+#ifdef CONFIG_PM
+static int sst_byt_pcm_dev_suspend_noirq(struct device *dev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       int ret;
+
+       dev_dbg(dev, "suspending noirq\n");
+
+       /* at this point all streams will be stopped and context saved */
+       ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata);
+       if (ret < 0) {
+               dev_err(dev, "failed to suspend %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int sst_byt_pcm_dev_suspend_late(struct device *dev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       int ret;
+
+       dev_dbg(dev, "suspending late\n");
+
+       ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
+       if (ret < 0) {
+               dev_err(dev, "failed to suspend %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int sst_byt_pcm_dev_resume_early(struct device *dev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+
+       dev_dbg(dev, "resume early\n");
+
+       /* load fw and boot DSP */
+       return sst_byt_dsp_boot(dev, sst_pdata);
+}
+
+static int sst_byt_pcm_dev_resume(struct device *dev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+
+       dev_dbg(dev, "resume\n");
+
+       /* wait for FW to finish booting */
+       return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
+}
+
+static const struct dev_pm_ops sst_byt_pm_ops = {
+       .suspend_noirq = sst_byt_pcm_dev_suspend_noirq,
+       .suspend_late = sst_byt_pcm_dev_suspend_late,
+       .resume_early = sst_byt_pcm_dev_resume_early,
+       .resume = sst_byt_pcm_dev_resume,
+};
+
+#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
+#else
+#define SST_BYT_PM_OPS NULL
+#endif
+
 static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
 {
        struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
        .driver = {
                .name = "baytrail-pcm-audio",
                .owner = THIS_MODULE,
+               .pm = SST_BYT_PM_OPS,
        },
 
        .probe = sst_byt_pcm_dev_probe,