aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiam Girdwood <liam.r.girdwood@linux.intel.com>2014-10-29 13:40:43 -0400
committerMark Brown <broonie@kernel.org>2014-10-29 16:50:42 -0400
commit2e4f75919e5a02d605b0d84425251654d48fb056 (patch)
tree781b0e06d9d848c73be4f259936289ca7f1c8a0d
parentaed3c7b77c85ed7060f1f56bfa909d2a86ab2a20 (diff)
ASoC: Intel: Add PM support to HSW/BDW PCM driver
Add PM and RTD3 support to the HSW/BDW PCM driver. The PCM driver will now save DSP context and then power off the DSP when it's not in use. DSP power and context is then restored when it's next used. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/intel/sst-dsp.h3
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c271
2 files changed, 260 insertions, 14 deletions
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h
index 7bb482053489..2753b85ac863 100644
--- a/sound/soc/intel/sst-dsp.h
+++ b/sound/soc/intel/sst-dsp.h
@@ -30,6 +30,9 @@
30#define SST_DMA_TYPE_DW 1 30#define SST_DMA_TYPE_DW 1
31#define SST_DMA_TYPE_MID 2 31#define SST_DMA_TYPE_MID 2
32 32
33/* autosuspend delay 5s*/
34#define SST_RUNTIME_SUSPEND_DELAY (5 * 1000)
35
33/* SST Shim register map 36/* SST Shim register map
34 * The register naming can differ between products. Some products also 37 * The register naming can differ between products. Some products also
35 * contain extra functionality. 38 * contain extra functionality.
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 522edef20c86..4489a35e691e 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -18,6 +18,7 @@
18#include <linux/dma-mapping.h> 18#include <linux/dma-mapping.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/delay.h> 20#include <linux/delay.h>
21#include <linux/pm_runtime.h>
21#include <asm/page.h> 22#include <asm/page.h>
22#include <asm/pgtable.h> 23#include <asm/pgtable.h>
23#include <sound/core.h> 24#include <sound/core.h>
@@ -73,6 +74,13 @@ static const u32 volume_map[] = {
73#define HSW_PCM_PERIODS_MAX 64 74#define HSW_PCM_PERIODS_MAX 64
74#define HSW_PCM_PERIODS_MIN 2 75#define HSW_PCM_PERIODS_MIN 2
75 76
77#define HSW_PCM_DAI_ID_SYSTEM 0
78#define HSW_PCM_DAI_ID_OFFLOAD0 1
79#define HSW_PCM_DAI_ID_OFFLOAD1 2
80#define HSW_PCM_DAI_ID_LOOPBACK 3
81#define HSW_PCM_DAI_ID_CAPTURE 4
82
83
76static const struct snd_pcm_hardware hsw_pcm_hardware = { 84static const struct snd_pcm_hardware hsw_pcm_hardware = {
77 .info = SNDRV_PCM_INFO_MMAP | 85 .info = SNDRV_PCM_INFO_MMAP |
78 SNDRV_PCM_INFO_MMAP_VALID | 86 SNDRV_PCM_INFO_MMAP_VALID |
@@ -99,6 +107,8 @@ struct hsw_pcm_data {
99 int dai_id; 107 int dai_id;
100 struct sst_hsw_stream *stream; 108 struct sst_hsw_stream *stream;
101 struct sst_module_runtime *runtime; 109 struct sst_module_runtime *runtime;
110 struct sst_module_runtime_context context;
111 struct snd_pcm *hsw_pcm;
102 u32 volume[2]; 112 u32 volume[2];
103 struct snd_pcm_substream *substream; 113 struct snd_pcm_substream *substream;
104 struct snd_compr_stream *cstream; 114 struct snd_compr_stream *cstream;
@@ -108,10 +118,18 @@ struct hsw_pcm_data {
108 int persistent_offset; 118 int persistent_offset;
109}; 119};
110 120
121enum hsw_pm_state {
122 HSW_PM_STATE_D3 = 0,
123 HSW_PM_STATE_D0 = 1,
124};
125
111/* private data for the driver */ 126/* private data for the driver */
112struct hsw_priv_data { 127struct hsw_priv_data {
113 /* runtime DSP */ 128 /* runtime DSP */
114 struct sst_hsw *hsw; 129 struct sst_hsw *hsw;
130 struct device *dev;
131 enum hsw_pm_state pm_state;
132 struct snd_soc_card *soc_card;
115 133
116 /* page tables */ 134 /* page tables */
117 struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; 135 struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
@@ -145,21 +163,25 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value)
145static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, 163static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
146 struct snd_ctl_elem_value *ucontrol) 164 struct snd_ctl_elem_value *ucontrol)
147{ 165{
148 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 166 struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
149 struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
150 struct soc_mixer_control *mc = 167 struct soc_mixer_control *mc =
151 (struct soc_mixer_control *)kcontrol->private_value; 168 (struct soc_mixer_control *)kcontrol->private_value;
169 struct hsw_priv_data *pdata =
170 snd_soc_platform_get_drvdata(platform);
152 struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; 171 struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
153 struct sst_hsw *hsw = pdata->hsw; 172 struct sst_hsw *hsw = pdata->hsw;
154 u32 volume; 173 u32 volume;
155 174
156 mutex_lock(&pcm_data->mutex); 175 mutex_lock(&pcm_data->mutex);
176 pm_runtime_get_sync(pdata->dev);
157 177
158 if (!pcm_data->stream) { 178 if (!pcm_data->stream) {
159 pcm_data->volume[0] = 179 pcm_data->volume[0] =
160 hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); 180 hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
161 pcm_data->volume[1] = 181 pcm_data->volume[1] =
162 hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); 182 hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
183 pm_runtime_mark_last_busy(pdata->dev);
184 pm_runtime_put_autosuspend(pdata->dev);
163 mutex_unlock(&pcm_data->mutex); 185 mutex_unlock(&pcm_data->mutex);
164 return 0; 186 return 0;
165 } 187 }
@@ -175,6 +197,8 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
175 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume); 197 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume);
176 } 198 }
177 199
200 pm_runtime_mark_last_busy(pdata->dev);
201 pm_runtime_put_autosuspend(pdata->dev);
178 mutex_unlock(&pcm_data->mutex); 202 mutex_unlock(&pcm_data->mutex);
179 return 0; 203 return 0;
180} 204}
@@ -182,21 +206,25 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
182static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, 206static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
183 struct snd_ctl_elem_value *ucontrol) 207 struct snd_ctl_elem_value *ucontrol)
184{ 208{
185 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 209 struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
186 struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
187 struct soc_mixer_control *mc = 210 struct soc_mixer_control *mc =
188 (struct soc_mixer_control *)kcontrol->private_value; 211 (struct soc_mixer_control *)kcontrol->private_value;
212 struct hsw_priv_data *pdata =
213 snd_soc_platform_get_drvdata(platform);
189 struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; 214 struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
190 struct sst_hsw *hsw = pdata->hsw; 215 struct sst_hsw *hsw = pdata->hsw;
191 u32 volume; 216 u32 volume;
192 217
193 mutex_lock(&pcm_data->mutex); 218 mutex_lock(&pcm_data->mutex);
219 pm_runtime_get_sync(pdata->dev);
194 220
195 if (!pcm_data->stream) { 221 if (!pcm_data->stream) {
196 ucontrol->value.integer.value[0] = 222 ucontrol->value.integer.value[0] =
197 hsw_ipc_to_mixer(pcm_data->volume[0]); 223 hsw_ipc_to_mixer(pcm_data->volume[0]);
198 ucontrol->value.integer.value[1] = 224 ucontrol->value.integer.value[1] =
199 hsw_ipc_to_mixer(pcm_data->volume[1]); 225 hsw_ipc_to_mixer(pcm_data->volume[1]);
226 pm_runtime_mark_last_busy(pdata->dev);
227 pm_runtime_put_autosuspend(pdata->dev);
200 mutex_unlock(&pcm_data->mutex); 228 mutex_unlock(&pcm_data->mutex);
201 return 0; 229 return 0;
202 } 230 }
@@ -205,6 +233,9 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
205 ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); 233 ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
206 sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume); 234 sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume);
207 ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); 235 ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
236
237 pm_runtime_mark_last_busy(pdata->dev);
238 pm_runtime_put_autosuspend(pdata->dev);
208 mutex_unlock(&pcm_data->mutex); 239 mutex_unlock(&pcm_data->mutex);
209 240
210 return 0; 241 return 0;
@@ -213,11 +244,13 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
213static int hsw_volume_put(struct snd_kcontrol *kcontrol, 244static int hsw_volume_put(struct snd_kcontrol *kcontrol,
214 struct snd_ctl_elem_value *ucontrol) 245 struct snd_ctl_elem_value *ucontrol)
215{ 246{
216 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 247 struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
217 struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); 248 struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
218 struct sst_hsw *hsw = pdata->hsw; 249 struct sst_hsw *hsw = pdata->hsw;
219 u32 volume; 250 u32 volume;
220 251
252 pm_runtime_get_sync(pdata->dev);
253
221 if (ucontrol->value.integer.value[0] == 254 if (ucontrol->value.integer.value[0] ==
222 ucontrol->value.integer.value[1]) { 255 ucontrol->value.integer.value[1]) {
223 256
@@ -232,23 +265,28 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol,
232 sst_hsw_mixer_set_volume(hsw, 0, 1, volume); 265 sst_hsw_mixer_set_volume(hsw, 0, 1, volume);
233 } 266 }
234 267
268 pm_runtime_mark_last_busy(pdata->dev);
269 pm_runtime_put_autosuspend(pdata->dev);
235 return 0; 270 return 0;
236} 271}
237 272
238static int hsw_volume_get(struct snd_kcontrol *kcontrol, 273static int hsw_volume_get(struct snd_kcontrol *kcontrol,
239 struct snd_ctl_elem_value *ucontrol) 274 struct snd_ctl_elem_value *ucontrol)
240{ 275{
241 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 276 struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
242 struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); 277 struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
243 struct sst_hsw *hsw = pdata->hsw; 278 struct sst_hsw *hsw = pdata->hsw;
244 unsigned int volume = 0; 279 unsigned int volume = 0;
245 280
281 pm_runtime_get_sync(pdata->dev);
246 sst_hsw_mixer_get_volume(hsw, 0, 0, &volume); 282 sst_hsw_mixer_get_volume(hsw, 0, 0, &volume);
247 ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); 283 ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
248 284
249 sst_hsw_mixer_get_volume(hsw, 0, 1, &volume); 285 sst_hsw_mixer_get_volume(hsw, 0, 1, &volume);
250 ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); 286 ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
251 287
288 pm_runtime_mark_last_busy(pdata->dev);
289 pm_runtime_put_autosuspend(pdata->dev);
252 return 0; 290 return 0;
253} 291}
254 292
@@ -577,6 +615,7 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
577 pcm_data = &pdata->pcm[rtd->cpu_dai->id]; 615 pcm_data = &pdata->pcm[rtd->cpu_dai->id];
578 616
579 mutex_lock(&pcm_data->mutex); 617 mutex_lock(&pcm_data->mutex);
618 pm_runtime_get_sync(pdata->dev);
580 619
581 snd_soc_pcm_set_drvdata(rtd, pcm_data); 620 snd_soc_pcm_set_drvdata(rtd, pcm_data);
582 pcm_data->substream = substream; 621 pcm_data->substream = substream;
@@ -587,6 +626,8 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
587 hsw_notify_pointer, pcm_data); 626 hsw_notify_pointer, pcm_data);
588 if (pcm_data->stream == NULL) { 627 if (pcm_data->stream == NULL) {
589 dev_err(rtd->dev, "error: failed to create stream\n"); 628 dev_err(rtd->dev, "error: failed to create stream\n");
629 pm_runtime_mark_last_busy(pdata->dev);
630 pm_runtime_put_autosuspend(pdata->dev);
590 mutex_unlock(&pcm_data->mutex); 631 mutex_unlock(&pcm_data->mutex);
591 return -EINVAL; 632 return -EINVAL;
592 } 633 }
@@ -626,6 +667,8 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
626 pcm_data->stream = NULL; 667 pcm_data->stream = NULL;
627 668
628out: 669out:
670 pm_runtime_mark_last_busy(pdata->dev);
671 pm_runtime_put_autosuspend(pdata->dev);
629 mutex_unlock(&pcm_data->mutex); 672 mutex_unlock(&pcm_data->mutex);
630 return ret; 673 return ret;
631} 674}
@@ -643,11 +686,11 @@ static struct snd_pcm_ops hsw_pcm_ops = {
643 686
644/* static mappings between PCMs and modules - may be dynamic in future */ 687/* static mappings between PCMs and modules - may be dynamic in future */
645static struct hsw_pcm_module_map mod_map[] = { 688static struct hsw_pcm_module_map mod_map[] = {
646 {0, SST_HSW_MODULE_PCM_SYSTEM}, /* "System Pin" */ 689 {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM},
647 {1, SST_HSW_MODULE_PCM}, /* "Offload0 Pin" */ 690 {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM},
648 {2, SST_HSW_MODULE_PCM}, /* "Offload1 Pin" */ 691 {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM},
649 {3, SST_HSW_MODULE_PCM_REFERENCE}, /* "Loopback Pin" */ 692 {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE},
650 {4, SST_HSW_MODULE_PCM_CAPTURE}, /* "Capture Pin" */ 693 {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE},
651}; 694};
652 695
653static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) 696static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
@@ -659,6 +702,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
659 for (i = 0; i < ARRAY_SIZE(mod_map); i++) { 702 for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
660 pcm_data = &pdata->pcm[i]; 703 pcm_data = &pdata->pcm[i];
661 704
705 /* create new runtime module, use same offset if recreated */
662 pcm_data->runtime = sst_hsw_runtime_module_create(hsw, 706 pcm_data->runtime = sst_hsw_runtime_module_create(hsw,
663 mod_map[i].mod_id, pcm_data->persistent_offset); 707 mod_map[i].mod_id, pcm_data->persistent_offset);
664 if (pcm_data->runtime == NULL) 708 if (pcm_data->runtime == NULL)
@@ -700,6 +744,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
700 struct snd_pcm *pcm = rtd->pcm; 744 struct snd_pcm *pcm = rtd->pcm;
701 struct snd_soc_platform *platform = rtd->platform; 745 struct snd_soc_platform *platform = rtd->platform;
702 struct sst_pdata *pdata = dev_get_platdata(platform->dev); 746 struct sst_pdata *pdata = dev_get_platdata(platform->dev);
747 struct hsw_priv_data *priv_data = dev_get_drvdata(platform->dev);
703 struct device *dev = pdata->dma_dev; 748 struct device *dev = pdata->dma_dev;
704 int ret = 0; 749 int ret = 0;
705 750
@@ -716,6 +761,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
716 return ret; 761 return ret;
717 } 762 }
718 } 763 }
764 priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm;
719 765
720 return ret; 766 return ret;
721} 767}
@@ -728,6 +774,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
728static struct snd_soc_dai_driver hsw_dais[] = { 774static struct snd_soc_dai_driver hsw_dais[] = {
729 { 775 {
730 .name = "System Pin", 776 .name = "System Pin",
777 .id = HSW_PCM_DAI_ID_SYSTEM,
731 .playback = { 778 .playback = {
732 .stream_name = "System Playback", 779 .stream_name = "System Playback",
733 .channels_min = 2, 780 .channels_min = 2,
@@ -739,6 +786,7 @@ static struct snd_soc_dai_driver hsw_dais[] = {
739 { 786 {
740 /* PCM */ 787 /* PCM */
741 .name = "Offload0 Pin", 788 .name = "Offload0 Pin",
789 .id = HSW_PCM_DAI_ID_OFFLOAD0,
742 .playback = { 790 .playback = {
743 .stream_name = "Offload0 Playback", 791 .stream_name = "Offload0 Playback",
744 .channels_min = 2, 792 .channels_min = 2,
@@ -750,6 +798,7 @@ static struct snd_soc_dai_driver hsw_dais[] = {
750 { 798 {
751 /* PCM */ 799 /* PCM */
752 .name = "Offload1 Pin", 800 .name = "Offload1 Pin",
801 .id = HSW_PCM_DAI_ID_OFFLOAD1,
753 .playback = { 802 .playback = {
754 .stream_name = "Offload1 Playback", 803 .stream_name = "Offload1 Playback",
755 .channels_min = 2, 804 .channels_min = 2,
@@ -760,6 +809,7 @@ static struct snd_soc_dai_driver hsw_dais[] = {
760 }, 809 },
761 { 810 {
762 .name = "Loopback Pin", 811 .name = "Loopback Pin",
812 .id = HSW_PCM_DAI_ID_LOOPBACK,
763 .capture = { 813 .capture = {
764 .stream_name = "Loopback Capture", 814 .stream_name = "Loopback Capture",
765 .channels_min = 2, 815 .channels_min = 2,
@@ -770,6 +820,7 @@ static struct snd_soc_dai_driver hsw_dais[] = {
770 }, 820 },
771 { 821 {
772 .name = "Capture Pin", 822 .name = "Capture Pin",
823 .id = HSW_PCM_DAI_ID_CAPTURE,
773 .capture = { 824 .capture = {
774 .stream_name = "Analog Capture", 825 .stream_name = "Analog Capture",
775 .channels_min = 2, 826 .channels_min = 2,
@@ -808,9 +859,21 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
808{ 859{
809 struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform); 860 struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform);
810 struct sst_pdata *pdata = dev_get_platdata(platform->dev); 861 struct sst_pdata *pdata = dev_get_platdata(platform->dev);
811 struct device *dma_dev = pdata->dma_dev; 862 struct device *dma_dev, *dev;
812 int i, ret = 0; 863 int i, ret = 0;
813 864
865 if (!pdata)
866 return -ENODEV;
867
868 dev = platform->dev;
869 dma_dev = pdata->dma_dev;
870
871 priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
872 priv_data->hsw = pdata->dsp;
873 priv_data->dev = platform->dev;
874 priv_data->pm_state = HSW_PM_STATE_D0;
875 priv_data->soc_card = platform->component.card;
876
814 /* allocate DSP buffer page tables */ 877 /* allocate DSP buffer page tables */
815 for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { 878 for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
816 879
@@ -836,6 +899,13 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
836 /* allocate runtime modules */ 899 /* allocate runtime modules */
837 hsw_pcm_create_modules(priv_data); 900 hsw_pcm_create_modules(priv_data);
838 901
902 /* enable runtime PM with auto suspend */
903 pm_runtime_set_autosuspend_delay(platform->dev,
904 SST_RUNTIME_SUSPEND_DELAY);
905 pm_runtime_use_autosuspend(platform->dev);
906 pm_runtime_enable(platform->dev);
907 pm_runtime_idle(platform->dev);
908
839 return 0; 909 return 0;
840 910
841err: 911err:
@@ -854,6 +924,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
854 snd_soc_platform_get_drvdata(platform); 924 snd_soc_platform_get_drvdata(platform);
855 int i; 925 int i;
856 926
927 pm_runtime_disable(platform->dev);
928 hsw_pcm_free_modules(priv_data);
929
857 for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { 930 for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
858 if (hsw_dais[i].playback.channels_min) 931 if (hsw_dais[i].playback.channels_min)
859 snd_dma_free_pages(&priv_data->dmab[i][0]); 932 snd_dma_free_pages(&priv_data->dmab[i][0]);
@@ -931,10 +1004,180 @@ static int hsw_pcm_dev_remove(struct platform_device *pdev)
931 return 0; 1004 return 0;
932} 1005}
933 1006
1007#ifdef CONFIG_PM
1008#ifdef CONFIG_PM_RUNTIME
1009
1010static int hsw_pcm_runtime_idle(struct device *dev)
1011{
1012 return 0;
1013}
1014
1015static int hsw_pcm_runtime_suspend(struct device *dev)
1016{
1017 struct hsw_priv_data *pdata = dev_get_drvdata(dev);
1018 struct sst_hsw *hsw = pdata->hsw;
1019
1020 if (pdata->pm_state == HSW_PM_STATE_D3)
1021 return 0;
1022
1023 sst_hsw_dsp_runtime_suspend(hsw);
1024 sst_hsw_dsp_runtime_sleep(hsw);
1025 pdata->pm_state = HSW_PM_STATE_D3;
1026
1027 return 0;
1028}
1029
1030static int hsw_pcm_runtime_resume(struct device *dev)
1031{
1032 struct hsw_priv_data *pdata = dev_get_drvdata(dev);
1033 struct sst_hsw *hsw = pdata->hsw;
1034 int ret;
1035
1036 if (pdata->pm_state == HSW_PM_STATE_D0)
1037 return 0;
1038
1039 ret = sst_hsw_dsp_load(hsw);
1040 if (ret < 0) {
1041 dev_err(dev, "failed to reload %d\n", ret);
1042 return ret;
1043 }
1044
1045 ret = hsw_pcm_create_modules(pdata);
1046 if (ret < 0) {
1047 dev_err(dev, "failed to create modules %d\n", ret);
1048 return ret;
1049 }
1050
1051 ret = sst_hsw_dsp_runtime_resume(hsw);
1052 if (ret < 0)
1053 return ret;
1054 else if (ret == 1) /* no action required */
1055 return 0;
1056
1057 pdata->pm_state = HSW_PM_STATE_D0;
1058 return ret;
1059}
1060
1061static void hsw_pcm_complete(struct device *dev)
1062{
1063 struct hsw_priv_data *pdata = dev_get_drvdata(dev);
1064 struct sst_hsw *hsw = pdata->hsw;
1065 struct hsw_pcm_data *pcm_data;
1066 int i, err;
1067
1068 if (pdata->pm_state == HSW_PM_STATE_D0)
1069 return;
1070
1071 err = sst_hsw_dsp_load(hsw);
1072 if (err < 0) {
1073 dev_err(dev, "failed to reload %d\n", err);
1074 return;
1075 }
1076
1077 err = hsw_pcm_create_modules(pdata);
1078 if (err < 0) {
1079 dev_err(dev, "failed to create modules %d\n", err);
1080 return;
1081 }
1082
1083 for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
1084 pcm_data = &pdata->pcm[i];
1085
1086 if (!pcm_data->substream)
1087 continue;
1088
1089 err = sst_module_runtime_restore(pcm_data->runtime,
1090 &pcm_data->context);
1091 if (err < 0)
1092 dev_err(dev, "failed to restore context for PCM %d\n", i);
1093 }
1094
1095 snd_soc_resume(pdata->soc_card->dev);
1096
1097 err = sst_hsw_dsp_runtime_resume(hsw);
1098 if (err < 0)
1099 return;
1100 else if (err == 1) /* no action required */
1101 return;
1102
1103 pdata->pm_state = HSW_PM_STATE_D0;
1104 return;
1105}
1106
1107static int hsw_pcm_prepare(struct device *dev)
1108{
1109 struct hsw_priv_data *pdata = dev_get_drvdata(dev);
1110 struct sst_hsw *hsw = pdata->hsw;
1111 struct hsw_pcm_data *pcm_data;
1112 int i, err;
1113
1114 if (pdata->pm_state == HSW_PM_STATE_D3)
1115 return 0;
1116 /* suspend all active streams */
1117 for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
1118 pcm_data = &pdata->pcm[i];
1119
1120 if (!pcm_data->substream)
1121 continue;
1122 dev_dbg(dev, "suspending pcm %d\n", i);
1123 snd_pcm_suspend_all(pcm_data->hsw_pcm);
1124
1125 /* We need to wait until the DSP FW stops the streams */
1126 msleep(2);
1127 }
1128
1129 snd_soc_suspend(pdata->soc_card->dev);
1130 snd_soc_poweroff(pdata->soc_card->dev);
1131
1132 /* enter D3 state and stall */
1133 sst_hsw_dsp_runtime_suspend(hsw);
1134
1135 /* preserve persistent memory */
1136 for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
1137 pcm_data = &pdata->pcm[i];
1138
1139 if (!pcm_data->substream)
1140 continue;
1141
1142 dev_dbg(dev, "saving context pcm %d\n", i);
1143 err = sst_module_runtime_save(pcm_data->runtime,
1144 &pcm_data->context);
1145 if (err < 0)
1146 dev_err(dev, "failed to save context for PCM %d\n", i);
1147 }
1148
1149 /* put the DSP to sleep */
1150 sst_hsw_dsp_runtime_sleep(hsw);
1151 pdata->pm_state = HSW_PM_STATE_D3;
1152
1153 return 0;
1154}
1155
1156#else
1157#define hsw_pcm_runtime_idle NULL
1158#define hsw_pcm_runtime_suspend NULL
1159#define hsw_pcm_runtime_resume NULL
1160#define hsw_pcm_runtime_complete NULL
1161#define hsw_pcm_runtime_prepare NULL
1162#endif
1163
1164static const struct dev_pm_ops hsw_pcm_pm = {
1165 .runtime_idle = hsw_pcm_runtime_idle,
1166 .runtime_suspend = hsw_pcm_runtime_suspend,
1167 .runtime_resume = hsw_pcm_runtime_resume,
1168 .prepare = hsw_pcm_prepare,
1169 .complete = hsw_pcm_complete,
1170};
1171#else
1172#define hsw_pcm_pm NULL
1173#endif
1174
934static struct platform_driver hsw_pcm_driver = { 1175static struct platform_driver hsw_pcm_driver = {
935 .driver = { 1176 .driver = {
936 .name = "haswell-pcm-audio", 1177 .name = "haswell-pcm-audio",
937 .owner = THIS_MODULE, 1178 .owner = THIS_MODULE,
1179 .pm = &hsw_pcm_pm,
1180
938 }, 1181 },
939 1182
940 .probe = hsw_pcm_dev_probe, 1183 .probe = hsw_pcm_dev_probe,