aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiam Girdwood <liam.r.girdwood@linux.intel.com>2014-05-08 09:07:26 -0400
committerMark Brown <broonie@linaro.org>2014-05-12 17:02:18 -0400
commitaf94aa558be506c5afe106e8cf34362bfce221aa (patch)
treed53557da737bb0840b47b685e5b908f9ef774a3f
parent609a13e5c9229ad4f5c78eeb1aefd583fdee9e58 (diff)
ASoC: Intel: Add Baytrail suspend/resume support
Add suspend and resume support to Baytrail SST DSP. This is implemented by unloading firmware modules and putting DSP into reset prior suspend and restarting DSP again in normal boot state after resume. Context restore for running streams is implemented by scheduling a work from sst_byt_pcm_trigger() that will allocate a stream with existing parameters and start it from last known buffer position before suspend. [Jarkko: Squashed together 5 WIP patches from Liam and 1 from me] Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com> Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.c69
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.h4
-rw-r--r--sound/soc/intel/sst-baytrail-pcm.c107
3 files changed, 179 insertions, 1 deletions
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c
index 029da82f07d7..3e1dad3449bd 100644
--- a/sound/soc/intel/sst-baytrail-ipc.c
+++ b/sound/soc/intel/sst-baytrail-ipc.c
@@ -173,6 +173,7 @@ struct sst_byt {
173 /* boot */ 173 /* boot */
174 wait_queue_head_t boot_wait; 174 wait_queue_head_t boot_wait;
175 bool boot_complete; 175 bool boot_complete;
176 struct sst_fw *fw;
176 177
177 /* IPC messaging */ 178 /* IPC messaging */
178 struct list_head tx_list; 179 struct list_head tx_list;
@@ -789,6 +790,73 @@ static struct sst_dsp_device byt_dev = {
789 .ops = &sst_byt_ops, 790 .ops = &sst_byt_ops,
790}; 791};
791 792
793int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
794{
795 struct sst_byt *byt = pdata->dsp;
796
797 dev_dbg(byt->dev, "dsp reset\n");
798 sst_dsp_reset(byt->dsp);
799 sst_byt_drop_all(byt);
800 dev_dbg(byt->dev, "dsp in reset\n");
801
802 return 0;
803}
804EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq);
805
806int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
807{
808 struct sst_byt *byt = pdata->dsp;
809
810 dev_dbg(byt->dev, "free all blocks and unload fw\n");
811 sst_fw_unload(byt->fw);
812
813 return 0;
814}
815EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late);
816
817int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata)
818{
819 struct sst_byt *byt = pdata->dsp;
820 int ret;
821
822 dev_dbg(byt->dev, "reload dsp fw\n");
823
824 sst_dsp_reset(byt->dsp);
825
826 ret = sst_fw_reload(byt->fw);
827 if (ret < 0) {
828 dev_err(dev, "error: failed to reload firmware\n");
829 return ret;
830 }
831
832 /* wait for DSP boot completion */
833 byt->boot_complete = false;
834 sst_dsp_boot(byt->dsp);
835 dev_dbg(byt->dev, "dsp booting...\n");
836
837 return 0;
838}
839EXPORT_SYMBOL_GPL(sst_byt_dsp_boot);
840
841int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata)
842{
843 struct sst_byt *byt = pdata->dsp;
844 int err;
845
846 dev_dbg(byt->dev, "wait for dsp reboot\n");
847
848 err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
849 msecs_to_jiffies(IPC_BOOT_MSECS));
850 if (err == 0) {
851 dev_err(byt->dev, "ipc: error DSP boot timeout\n");
852 return -EIO;
853 }
854
855 dev_dbg(byt->dev, "dsp rebooted\n");
856 return 0;
857}
858EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
859
792int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) 860int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
793{ 861{
794 struct sst_byt *byt; 862 struct sst_byt *byt;
@@ -855,6 +923,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
855 } 923 }
856 924
857 pdata->dsp = byt; 925 pdata->dsp = byt;
926 byt->fw = byt_sst_fw;
858 927
859 return 0; 928 return 0;
860 929
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h
index b643d9892f60..06a4d202689b 100644
--- a/sound/soc/intel/sst-baytrail-ipc.h
+++ b/sound/soc/intel/sst-baytrail-ipc.h
@@ -66,5 +66,9 @@ int sst_byt_get_dsp_position(struct sst_byt *byt,
66int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata); 66int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
67void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata); 67void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
68struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt); 68struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
69int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata);
70int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
71int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
72int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
69 73
70#endif 74#endif
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
index e2c2540ffff4..00a2118d20f5 100644
--- a/sound/soc/intel/sst-baytrail-pcm.c
+++ b/sound/soc/intel/sst-baytrail-pcm.c
@@ -48,6 +48,8 @@ struct sst_byt_pcm_data {
48 48
49 /* latest DSP DMA hw pointer */ 49 /* latest DSP DMA hw pointer */
50 u32 hw_ptr; 50 u32 hw_ptr;
51
52 struct work_struct work;
51}; 53};
52 54
53/* private data for the driver */ 55/* private data for the driver */
@@ -133,6 +135,38 @@ static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
133 return 0; 135 return 0;
134} 136}
135 137
138static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
139{
140 struct snd_soc_pcm_runtime *rtd = substream->private_data;
141 struct sst_byt_priv_data *pdata =
142 snd_soc_platform_get_drvdata(rtd->platform);
143 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
144 struct sst_byt *byt = pdata->byt;
145 int ret;
146
147 /* commit stream using existing stream params */
148 ret = sst_byt_stream_commit(byt, pcm_data->stream);
149 if (ret < 0) {
150 dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
151 return ret;
152 }
153
154 sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
155
156 dev_dbg(rtd->dev, "stream context restored at offset %d\n",
157 pcm_data->hw_ptr);
158
159 return 0;
160}
161
162static void sst_byt_pcm_work(struct work_struct *work)
163{
164 struct sst_byt_pcm_data *pcm_data =
165 container_of(work, struct sst_byt_pcm_data, work);
166
167 sst_byt_pcm_restore_stream_context(pcm_data->substream);
168}
169
136static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 170static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
137{ 171{
138 struct snd_soc_pcm_runtime *rtd = substream->private_data; 172 struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -148,6 +182,8 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
148 sst_byt_stream_start(byt, pcm_data->stream, 0); 182 sst_byt_stream_start(byt, pcm_data->stream, 0);
149 break; 183 break;
150 case SNDRV_PCM_TRIGGER_RESUME: 184 case SNDRV_PCM_TRIGGER_RESUME:
185 schedule_work(&pcm_data->work);
186 break;
151 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 187 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
152 sst_byt_stream_resume(byt, pcm_data->stream); 188 sst_byt_stream_resume(byt, pcm_data->stream);
153 break; 189 break;
@@ -344,8 +380,10 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
344 priv_data->byt = plat_data->dsp; 380 priv_data->byt = plat_data->dsp;
345 snd_soc_platform_set_drvdata(platform, priv_data); 381 snd_soc_platform_set_drvdata(platform, priv_data);
346 382
347 for (i = 0; i < ARRAY_SIZE(byt_dais); i++) 383 for (i = 0; i < ARRAY_SIZE(byt_dais); i++) {
348 mutex_init(&priv_data->pcm[i].mutex); 384 mutex_init(&priv_data->pcm[i].mutex);
385 INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
386 }
349 387
350 return 0; 388 return 0;
351} 389}
@@ -367,6 +405,72 @@ static const struct snd_soc_component_driver byt_dai_component = {
367 .name = "byt-dai", 405 .name = "byt-dai",
368}; 406};
369 407
408#ifdef CONFIG_PM
409static int sst_byt_pcm_dev_suspend_noirq(struct device *dev)
410{
411 struct sst_pdata *sst_pdata = dev_get_platdata(dev);
412 int ret;
413
414 dev_dbg(dev, "suspending noirq\n");
415
416 /* at this point all streams will be stopped and context saved */
417 ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata);
418 if (ret < 0) {
419 dev_err(dev, "failed to suspend %d\n", ret);
420 return ret;
421 }
422
423 return ret;
424}
425
426static int sst_byt_pcm_dev_suspend_late(struct device *dev)
427{
428 struct sst_pdata *sst_pdata = dev_get_platdata(dev);
429 int ret;
430
431 dev_dbg(dev, "suspending late\n");
432
433 ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
434 if (ret < 0) {
435 dev_err(dev, "failed to suspend %d\n", ret);
436 return ret;
437 }
438
439 return ret;
440}
441
442static int sst_byt_pcm_dev_resume_early(struct device *dev)
443{
444 struct sst_pdata *sst_pdata = dev_get_platdata(dev);
445
446 dev_dbg(dev, "resume early\n");
447
448 /* load fw and boot DSP */
449 return sst_byt_dsp_boot(dev, sst_pdata);
450}
451
452static int sst_byt_pcm_dev_resume(struct device *dev)
453{
454 struct sst_pdata *sst_pdata = dev_get_platdata(dev);
455
456 dev_dbg(dev, "resume\n");
457
458 /* wait for FW to finish booting */
459 return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
460}
461
462static const struct dev_pm_ops sst_byt_pm_ops = {
463 .suspend_noirq = sst_byt_pcm_dev_suspend_noirq,
464 .suspend_late = sst_byt_pcm_dev_suspend_late,
465 .resume_early = sst_byt_pcm_dev_resume_early,
466 .resume = sst_byt_pcm_dev_resume,
467};
468
469#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
470#else
471#define SST_BYT_PM_OPS NULL
472#endif
473
370static int sst_byt_pcm_dev_probe(struct platform_device *pdev) 474static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
371{ 475{
372 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); 476 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
@@ -409,6 +513,7 @@ static struct platform_driver sst_byt_pcm_driver = {
409 .driver = { 513 .driver = {
410 .name = "baytrail-pcm-audio", 514 .name = "baytrail-pcm-audio",
411 .owner = THIS_MODULE, 515 .owner = THIS_MODULE,
516 .pm = SST_BYT_PM_OPS,
412 }, 517 },
413 518
414 .probe = sst_byt_pcm_dev_probe, 519 .probe = sst_byt_pcm_dev_probe,