aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/intel
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-03-23 08:14:02 -0400
committerTakashi Iwai <tiwai@suse.de>2015-03-23 08:14:02 -0400
commit3372dbdd8ca11f51be8c6a30b2bc79eb04c4a902 (patch)
treed4499bf5a5665b4820ffaf96bce55bf6b895195e /sound/soc/intel
parentbc465aa9d045feb0e13b4a8f32cc33c1943f62d6 (diff)
parent967b1307b69b8ada8b331e01046ad1ef83742e99 (diff)
Merge branch 'for-next' into topic/hda-core
Diffstat (limited to 'sound/soc/intel')
-rw-r--r--sound/soc/intel/broadwell.c16
-rw-r--r--sound/soc/intel/byt-max98090.c11
-rw-r--r--sound/soc/intel/bytcr_dpcm_rt5640.c4
-rw-r--r--sound/soc/intel/cht_bsw_rt5645.c16
-rw-r--r--sound/soc/intel/cht_bsw_rt5672.c9
-rw-r--r--sound/soc/intel/haswell.c4
-rw-r--r--sound/soc/intel/mfld_machine.c24
-rw-r--r--sound/soc/intel/sst-mfld-platform-pcm.c60
-rw-r--r--sound/soc/intel/sst-mfld-platform.h1
-rw-r--r--sound/soc/intel/sst/sst.c128
-rw-r--r--sound/soc/intel/sst/sst.h12
-rw-r--r--sound/soc/intel/sst/sst_drv_interface.c65
-rw-r--r--sound/soc/intel/sst/sst_loader.c10
13 files changed, 291 insertions, 69 deletions
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c
index 9cf7d01479ad..fc5542034b9b 100644
--- a/sound/soc/intel/broadwell.c
+++ b/sound/soc/intel/broadwell.c
@@ -80,15 +80,9 @@ static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
80{ 80{
81 struct snd_soc_codec *codec = rtd->codec; 81 struct snd_soc_codec *codec = rtd->codec;
82 int ret = 0; 82 int ret = 0;
83 ret = snd_soc_jack_new(codec, "Headset", 83 ret = snd_soc_card_jack_new(rtd->card, "Headset",
84 SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset); 84 SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
85 85 broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins));
86 if (ret)
87 return ret;
88
89 ret = snd_soc_jack_add_pins(&broadwell_headset,
90 ARRAY_SIZE(broadwell_headset_pins),
91 broadwell_headset_pins);
92 if (ret) 86 if (ret)
93 return ret; 87 return ret;
94 88
@@ -110,9 +104,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
110 channels->min = channels->max = 2; 104 channels->min = channels->max = 2;
111 105
112 /* set SSP0 to 16 bit */ 106 /* set SSP0 to 16 bit */
113 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT - 107 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
114 SNDRV_PCM_HW_PARAM_FIRST_MASK],
115 SNDRV_PCM_FORMAT_S16_LE);
116 return 0; 108 return 0;
117} 109}
118 110
diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c
index 9832afe7d22c..d8b1f038da1c 100644
--- a/sound/soc/intel/byt-max98090.c
+++ b/sound/soc/intel/byt-max98090.c
@@ -84,7 +84,6 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = {
84static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) 84static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
85{ 85{
86 int ret; 86 int ret;
87 struct snd_soc_codec *codec = runtime->codec;
88 struct snd_soc_card *card = runtime->card; 87 struct snd_soc_card *card = runtime->card;
89 struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card); 88 struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card);
90 struct snd_soc_jack *jack = &drv->jack; 89 struct snd_soc_jack *jack = &drv->jack;
@@ -100,13 +99,9 @@ static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
100 } 99 }
101 100
102 /* Enable jack detection */ 101 /* Enable jack detection */
103 ret = snd_soc_jack_new(codec, "Headset", 102 ret = snd_soc_card_jack_new(runtime->card, "Headset",
104 SND_JACK_LINEOUT | SND_JACK_HEADSET, jack); 103 SND_JACK_LINEOUT | SND_JACK_HEADSET, jack,
105 if (ret) 104 hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
106 return ret;
107
108 ret = snd_soc_jack_add_pins(jack, ARRAY_SIZE(hs_jack_pins),
109 hs_jack_pins);
110 if (ret) 105 if (ret)
111 return ret; 106 return ret;
112 107
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c
index 59308629043e..3b262d01c1b3 100644
--- a/sound/soc/intel/bytcr_dpcm_rt5640.c
+++ b/sound/soc/intel/bytcr_dpcm_rt5640.c
@@ -113,9 +113,7 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
113 channels->min = channels->max = 2; 113 channels->min = channels->max = 2;
114 114
115 /* set SSP2 to 24-bit */ 115 /* set SSP2 to 24-bit */
116 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT - 116 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
117 SNDRV_PCM_HW_PARAM_FIRST_MASK],
118 SNDRV_PCM_FORMAT_S24_LE);
119 return 0; 117 return 0;
120} 118}
121 119
diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c
index bd29617a9ab9..012227997ed9 100644
--- a/sound/soc/intel/cht_bsw_rt5645.c
+++ b/sound/soc/intel/cht_bsw_rt5645.c
@@ -169,17 +169,17 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
169 return ret; 169 return ret;
170 } 170 }
171 171
172 ret = snd_soc_jack_new(codec, "Headphone Jack", 172 ret = snd_soc_card_jack_new(runtime->card, "Headphone Jack",
173 SND_JACK_HEADPHONE, 173 SND_JACK_HEADPHONE, &ctx->hp_jack,
174 &ctx->hp_jack); 174 NULL, 0);
175 if (ret) { 175 if (ret) {
176 dev_err(runtime->dev, "HP jack creation failed %d\n", ret); 176 dev_err(runtime->dev, "HP jack creation failed %d\n", ret);
177 return ret; 177 return ret;
178 } 178 }
179 179
180 ret = snd_soc_jack_new(codec, "Mic Jack", 180 ret = snd_soc_card_jack_new(runtime->card, "Mic Jack",
181 SND_JACK_MICROPHONE, 181 SND_JACK_MICROPHONE, &ctx->mic_jack,
182 &ctx->mic_jack); 182 NULL, 0);
183 if (ret) { 183 if (ret) {
184 dev_err(runtime->dev, "Mic jack creation failed %d\n", ret); 184 dev_err(runtime->dev, "Mic jack creation failed %d\n", ret);
185 return ret; 185 return ret;
@@ -203,9 +203,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
203 channels->min = channels->max = 2; 203 channels->min = channels->max = 2;
204 204
205 /* set SSP2 to 24-bit */ 205 /* set SSP2 to 24-bit */
206 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT - 206 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
207 SNDRV_PCM_HW_PARAM_FIRST_MASK],
208 SNDRV_PCM_FORMAT_S24_LE);
209 return 0; 207 return 0;
210} 208}
211 209
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c
index ff016621583a..bc8dcacd5e6a 100644
--- a/sound/soc/intel/cht_bsw_rt5672.c
+++ b/sound/soc/intel/cht_bsw_rt5672.c
@@ -178,9 +178,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
178 channels->min = channels->max = 2; 178 channels->min = channels->max = 2;
179 179
180 /* set SSP2 to 24-bit */ 180 /* set SSP2 to 24-bit */
181 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT - 181 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
182 SNDRV_PCM_HW_PARAM_FIRST_MASK],
183 SNDRV_PCM_FORMAT_S24_LE);
184 return 0; 182 return 0;
185} 183}
186 184
@@ -217,7 +215,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
217 .codec_dai_name = "snd-soc-dummy-dai", 215 .codec_dai_name = "snd-soc-dummy-dai",
218 .codec_name = "snd-soc-dummy", 216 .codec_name = "snd-soc-dummy",
219 .platform_name = "sst-mfld-platform", 217 .platform_name = "sst-mfld-platform",
220 .ignore_suspend = 1, 218 .nonatomic = true,
221 .dynamic = 1, 219 .dynamic = 1,
222 .dpcm_playback = 1, 220 .dpcm_playback = 1,
223 .dpcm_capture = 1, 221 .dpcm_capture = 1,
@@ -240,13 +238,13 @@ static struct snd_soc_dai_link cht_dailink[] = {
240 .cpu_dai_name = "ssp2-port", 238 .cpu_dai_name = "ssp2-port",
241 .platform_name = "sst-mfld-platform", 239 .platform_name = "sst-mfld-platform",
242 .no_pcm = 1, 240 .no_pcm = 1,
241 .nonatomic = true,
243 .codec_dai_name = "rt5670-aif1", 242 .codec_dai_name = "rt5670-aif1",
244 .codec_name = "i2c-10EC5670:00", 243 .codec_name = "i2c-10EC5670:00",
245 .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF 244 .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
246 | SND_SOC_DAIFMT_CBS_CFS, 245 | SND_SOC_DAIFMT_CBS_CFS,
247 .init = cht_codec_init, 246 .init = cht_codec_init,
248 .be_hw_params_fixup = cht_codec_fixup, 247 .be_hw_params_fixup = cht_codec_fixup,
249 .ignore_suspend = 1,
250 .dpcm_playback = 1, 248 .dpcm_playback = 1,
251 .dpcm_capture = 1, 249 .dpcm_capture = 1,
252 .ops = &cht_be_ssp2_ops, 250 .ops = &cht_be_ssp2_ops,
@@ -285,7 +283,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
285static struct platform_driver snd_cht_mc_driver = { 283static struct platform_driver snd_cht_mc_driver = {
286 .driver = { 284 .driver = {
287 .name = "cht-bsw-rt5672", 285 .name = "cht-bsw-rt5672",
288 .pm = &snd_soc_pm_ops,
289 }, 286 },
290 .probe = snd_cht_mc_probe, 287 .probe = snd_cht_mc_probe,
291}; 288};
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c
index 35edf51a52aa..00fddd3f5dfb 100644
--- a/sound/soc/intel/haswell.c
+++ b/sound/soc/intel/haswell.c
@@ -56,9 +56,7 @@ static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
56 channels->min = channels->max = 2; 56 channels->min = channels->max = 2;
57 57
58 /* set SSP0 to 16 bit */ 58 /* set SSP0 to 16 bit */
59 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT - 59 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
60 SNDRV_PCM_HW_PARAM_FIRST_MASK],
61 SNDRV_PCM_FORMAT_S16_LE);
62 return 0; 60 return 0;
63} 61}
64 62
diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c
index 90b7a57713a0..49c09a0add79 100644
--- a/sound/soc/intel/mfld_machine.c
+++ b/sound/soc/intel/mfld_machine.c
@@ -228,10 +228,13 @@ static void mfld_jack_check(unsigned int intr_status)
228{ 228{
229 struct mfld_jack_data jack_data; 229 struct mfld_jack_data jack_data;
230 230
231 if (!mfld_codec)
232 return;
233
231 jack_data.mfld_jack = &mfld_jack; 234 jack_data.mfld_jack = &mfld_jack;
232 jack_data.intr_id = intr_status; 235 jack_data.intr_id = intr_status;
233 236
234 sn95031_jack_detection(&jack_data); 237 sn95031_jack_detection(mfld_codec, &jack_data);
235 /* TODO: add american headset detection post gpiolib support */ 238 /* TODO: add american headset detection post gpiolib support */
236} 239}
237 240
@@ -240,8 +243,6 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
240 struct snd_soc_dapm_context *dapm = &runtime->card->dapm; 243 struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
241 int ret_val; 244 int ret_val;
242 245
243 mfld_codec = runtime->codec;
244
245 /* default is earpiece pin, userspace sets it explcitly */ 246 /* default is earpiece pin, userspace sets it explcitly */
246 snd_soc_dapm_disable_pin(dapm, "Headphones"); 247 snd_soc_dapm_disable_pin(dapm, "Headphones");
247 /* default is lineout NC, userspace sets it explcitly */ 248 /* default is lineout NC, userspace sets it explcitly */
@@ -254,20 +255,15 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
254 snd_soc_dapm_disable_pin(dapm, "LINEINR"); 255 snd_soc_dapm_disable_pin(dapm, "LINEINR");
255 256
256 /* Headset and button jack detection */ 257 /* Headset and button jack detection */
257 ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack", 258 ret_val = snd_soc_card_jack_new(runtime->card,
258 SND_JACK_HEADSET | SND_JACK_BTN_0 | 259 "Intel(R) MID Audio Jack", SND_JACK_HEADSET |
259 SND_JACK_BTN_1, &mfld_jack); 260 SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack,
261 mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins));
260 if (ret_val) { 262 if (ret_val) {
261 pr_err("jack creation failed\n"); 263 pr_err("jack creation failed\n");
262 return ret_val; 264 return ret_val;
263 } 265 }
264 266
265 ret_val = snd_soc_jack_add_pins(&mfld_jack,
266 ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins);
267 if (ret_val) {
268 pr_err("adding jack pins failed\n");
269 return ret_val;
270 }
271 ret_val = snd_soc_jack_add_zones(&mfld_jack, 267 ret_val = snd_soc_jack_add_zones(&mfld_jack,
272 ARRAY_SIZE(mfld_zones), mfld_zones); 268 ARRAY_SIZE(mfld_zones), mfld_zones);
273 if (ret_val) { 269 if (ret_val) {
@@ -275,6 +271,8 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
275 return ret_val; 271 return ret_val;
276 } 272 }
277 273
274 mfld_codec = runtime->codec;
275
278 /* we want to check if anything is inserted at boot, 276 /* we want to check if anything is inserted at boot,
279 * so send a fake event to codec and it will read adc 277 * so send a fake event to codec and it will read adc
280 * to find if anything is there or not */ 278 * to find if anything is there or not */
@@ -359,8 +357,6 @@ static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
359{ 357{
360 struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data; 358 struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
361 359
362 if (mfld_jack.codec == NULL)
363 return IRQ_HANDLED;
364 mfld_jack_check(mc_drv_ctx->interrupt_status); 360 mfld_jack_check(mc_drv_ctx->interrupt_status);
365 361
366 return IRQ_HANDLED; 362 return IRQ_HANDLED;
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c
index 7523cbef8780..2fbaf2c75d17 100644
--- a/sound/soc/intel/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/sst-mfld-platform-pcm.c
@@ -594,11 +594,13 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
594 ret_val = stream->ops->stream_drop(sst->dev, str_id); 594 ret_val = stream->ops->stream_drop(sst->dev, str_id);
595 break; 595 break;
596 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 596 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
597 case SNDRV_PCM_TRIGGER_SUSPEND:
597 dev_dbg(rtd->dev, "sst: in pause\n"); 598 dev_dbg(rtd->dev, "sst: in pause\n");
598 status = SST_PLATFORM_PAUSED; 599 status = SST_PLATFORM_PAUSED;
599 ret_val = stream->ops->stream_pause(sst->dev, str_id); 600 ret_val = stream->ops->stream_pause(sst->dev, str_id);
600 break; 601 break;
601 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 602 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
603 case SNDRV_PCM_TRIGGER_RESUME:
602 dev_dbg(rtd->dev, "sst: in pause release\n"); 604 dev_dbg(rtd->dev, "sst: in pause release\n");
603 status = SST_PLATFORM_RUNNING; 605 status = SST_PLATFORM_RUNNING;
604 ret_val = stream->ops->stream_pause_release(sst->dev, str_id); 606 ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
@@ -665,6 +667,9 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
665 667
666static int sst_soc_probe(struct snd_soc_platform *platform) 668static int sst_soc_probe(struct snd_soc_platform *platform)
667{ 669{
670 struct sst_data *drv = dev_get_drvdata(platform->dev);
671
672 drv->soc_card = platform->component.card;
668 return sst_dsp_init_v2_dpcm(platform); 673 return sst_dsp_init_v2_dpcm(platform);
669} 674}
670 675
@@ -727,9 +732,64 @@ static int sst_platform_remove(struct platform_device *pdev)
727 return 0; 732 return 0;
728} 733}
729 734
735#ifdef CONFIG_PM_SLEEP
736
737static int sst_soc_prepare(struct device *dev)
738{
739 struct sst_data *drv = dev_get_drvdata(dev);
740 int i;
741
742 /* suspend all pcms first */
743 snd_soc_suspend(drv->soc_card->dev);
744 snd_soc_poweroff(drv->soc_card->dev);
745
746 /* set the SSPs to idle */
747 for (i = 0; i < drv->soc_card->num_rtd; i++) {
748 struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
749
750 if (dai->active) {
751 send_ssp_cmd(dai, dai->name, 0);
752 sst_handle_vb_timer(dai, false);
753 }
754 }
755
756 return 0;
757}
758
759static void sst_soc_complete(struct device *dev)
760{
761 struct sst_data *drv = dev_get_drvdata(dev);
762 int i;
763
764 /* restart SSPs */
765 for (i = 0; i < drv->soc_card->num_rtd; i++) {
766 struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
767
768 if (dai->active) {
769 sst_handle_vb_timer(dai, true);
770 send_ssp_cmd(dai, dai->name, 1);
771 }
772 }
773 snd_soc_resume(drv->soc_card->dev);
774}
775
776#else
777
778#define sst_soc_prepare NULL
779#define sst_soc_complete NULL
780
781#endif
782
783
784static const struct dev_pm_ops sst_platform_pm = {
785 .prepare = sst_soc_prepare,
786 .complete = sst_soc_complete,
787};
788
730static struct platform_driver sst_platform_driver = { 789static struct platform_driver sst_platform_driver = {
731 .driver = { 790 .driver = {
732 .name = "sst-mfld-platform", 791 .name = "sst-mfld-platform",
792 .pm = &sst_platform_pm,
733 }, 793 },
734 .probe = sst_platform_probe, 794 .probe = sst_platform_probe,
735 .remove = sst_platform_remove, 795 .remove = sst_platform_remove,
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h
index 79c8d1246a8f..9094314be2b0 100644
--- a/sound/soc/intel/sst-mfld-platform.h
+++ b/sound/soc/intel/sst-mfld-platform.h
@@ -174,6 +174,7 @@ struct sst_data {
174 struct sst_platform_data *pdata; 174 struct sst_platform_data *pdata;
175 struct snd_sst_bytes_v2 *byte_stream; 175 struct snd_sst_bytes_v2 *byte_stream;
176 struct mutex lock; 176 struct mutex lock;
177 struct snd_soc_card *soc_card;
177}; 178};
178int sst_register_dsp(struct sst_device *sst); 179int sst_register_dsp(struct sst_device *sst);
179int sst_unregister_dsp(struct sst_device *sst); 180int sst_unregister_dsp(struct sst_device *sst);
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c
index 11c578651c1c..1a7eeec444b1 100644
--- a/sound/soc/intel/sst/sst.c
+++ b/sound/soc/intel/sst/sst.c
@@ -423,23 +423,135 @@ static int intel_sst_runtime_suspend(struct device *dev)
423 return ret; 423 return ret;
424} 424}
425 425
426static int intel_sst_runtime_resume(struct device *dev) 426static int intel_sst_suspend(struct device *dev)
427{ 427{
428 int ret = 0;
429 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 428 struct intel_sst_drv *ctx = dev_get_drvdata(dev);
429 struct sst_fw_save *fw_save;
430 int i, ret = 0;
430 431
431 if (ctx->sst_state == SST_RESET) { 432 /* check first if we are already in SW reset */
432 ret = sst_load_fw(ctx); 433 if (ctx->sst_state == SST_RESET)
433 if (ret) { 434 return 0;
434 dev_err(dev, "FW download fail %d\n", ret); 435
435 sst_set_fw_state_locked(ctx, SST_RESET); 436 /*
437 * check if any stream is active and running
438 * they should already by suspend by soc_suspend
439 */
440 for (i = 1; i <= ctx->info.max_streams; i++) {
441 struct stream_info *stream = &ctx->streams[i];
442
443 if (stream->status == STREAM_RUNNING) {
444 dev_err(dev, "stream %d is running, cant susupend, abort\n", i);
445 return -EBUSY;
436 } 446 }
437 } 447 }
448 synchronize_irq(ctx->irq_num);
449 flush_workqueue(ctx->post_msg_wq);
450
451 /* Move the SST state to Reset */
452 sst_set_fw_state_locked(ctx, SST_RESET);
453
454 /* tell DSP we are suspending */
455 if (ctx->ops->save_dsp_context(ctx))
456 return -EBUSY;
457
458 /* save the memories */
459 fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL);
460 if (!fw_save)
461 return -ENOMEM;
462 fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
463 if (!fw_save->iram) {
464 ret = -ENOMEM;
465 goto iram;
466 }
467 fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
468 if (!fw_save->dram) {
469 ret = -ENOMEM;
470 goto dram;
471 }
472 fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
473 if (!fw_save->sram) {
474 ret = -ENOMEM;
475 goto sram;
476 }
477
478 fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
479 if (!fw_save->ddr) {
480 ret = -ENOMEM;
481 goto ddr;
482 }
483
484 memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base);
485 memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base);
486 memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE);
487 memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base);
488
489 ctx->fw_save = fw_save;
490 ctx->ops->reset(ctx);
491 return 0;
492ddr:
493 kfree(fw_save->sram);
494sram:
495 kfree(fw_save->dram);
496dram:
497 kfree(fw_save->iram);
498iram:
499 kfree(fw_save);
500 return ret;
501}
502
503static int intel_sst_resume(struct device *dev)
504{
505 struct intel_sst_drv *ctx = dev_get_drvdata(dev);
506 struct sst_fw_save *fw_save = ctx->fw_save;
507 int ret = 0;
508 struct sst_block *block;
509
510 if (!fw_save)
511 return 0;
512
513 sst_set_fw_state_locked(ctx, SST_FW_LOADING);
514
515 /* we have to restore the memory saved */
516 ctx->ops->reset(ctx);
517
518 ctx->fw_save = NULL;
519
520 memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base);
521 memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base);
522 memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE);
523 memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base);
524
525 kfree(fw_save->sram);
526 kfree(fw_save->dram);
527 kfree(fw_save->iram);
528 kfree(fw_save->ddr);
529 kfree(fw_save);
530
531 block = sst_create_block(ctx, 0, FW_DWNL_ID);
532 if (block == NULL)
533 return -ENOMEM;
534
535
536 /* start and wait for ack */
537 ctx->ops->start(ctx);
538 ret = sst_wait_timeout(ctx, block);
539 if (ret) {
540 dev_err(ctx->dev, "fw download failed %d\n", ret);
541 /* FW download failed due to timeout */
542 ret = -EBUSY;
543
544 } else {
545 sst_set_fw_state_locked(ctx, SST_FW_RUNNING);
546 }
547
548 sst_free_block(ctx, block);
438 return ret; 549 return ret;
439} 550}
440 551
441const struct dev_pm_ops intel_sst_pm = { 552const struct dev_pm_ops intel_sst_pm = {
553 .suspend = intel_sst_suspend,
554 .resume = intel_sst_resume,
442 .runtime_suspend = intel_sst_runtime_suspend, 555 .runtime_suspend = intel_sst_runtime_suspend,
443 .runtime_resume = intel_sst_runtime_resume,
444}; 556};
445EXPORT_SYMBOL_GPL(intel_sst_pm); 557EXPORT_SYMBOL_GPL(intel_sst_pm);
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h
index 562bc483d6b7..3f493862e98d 100644
--- a/sound/soc/intel/sst/sst.h
+++ b/sound/soc/intel/sst/sst.h
@@ -337,6 +337,13 @@ struct sst_shim_regs64 {
337 u64 csr2; 337 u64 csr2;
338}; 338};
339 339
340struct sst_fw_save {
341 void *iram;
342 void *dram;
343 void *sram;
344 void *ddr;
345};
346
340/** 347/**
341 * struct intel_sst_drv - driver ops 348 * struct intel_sst_drv - driver ops
342 * 349 *
@@ -428,6 +435,8 @@ struct intel_sst_drv {
428 * persistent till worker thread gets called 435 * persistent till worker thread gets called
429 */ 436 */
430 char firmware_name[FW_NAME_SIZE]; 437 char firmware_name[FW_NAME_SIZE];
438
439 struct sst_fw_save *fw_save;
431}; 440};
432 441
433/* misc definitions */ 442/* misc definitions */
@@ -544,4 +553,7 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx,
544int sst_context_init(struct intel_sst_drv *ctx); 553int sst_context_init(struct intel_sst_drv *ctx);
545void sst_context_cleanup(struct intel_sst_drv *ctx); 554void sst_context_cleanup(struct intel_sst_drv *ctx);
546void sst_configure_runtime_pm(struct intel_sst_drv *ctx); 555void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
556void memcpy32_toio(void __iomem *dst, const void *src, int count);
557void memcpy32_fromio(void *dst, const void __iomem *src, int count);
558
547#endif 559#endif
diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c
index 5f75ef3cdd22..f0e4b99b3aeb 100644
--- a/sound/soc/intel/sst/sst_drv_interface.c
+++ b/sound/soc/intel/sst/sst_drv_interface.c
@@ -138,12 +138,36 @@ int sst_get_stream(struct intel_sst_drv *ctx,
138static int sst_power_control(struct device *dev, bool state) 138static int sst_power_control(struct device *dev, bool state)
139{ 139{
140 struct intel_sst_drv *ctx = dev_get_drvdata(dev); 140 struct intel_sst_drv *ctx = dev_get_drvdata(dev);
141 141 int ret = 0;
142 dev_dbg(ctx->dev, "state:%d", state); 142 int usage_count = 0;
143 if (state == true) 143
144 return pm_runtime_get_sync(dev); 144#ifdef CONFIG_PM
145 else 145 usage_count = atomic_read(&dev->power.usage_count);
146#else
147 usage_count = 1;
148#endif
149
150 if (state == true) {
151 ret = pm_runtime_get_sync(dev);
152
153 dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
154 if (ret < 0) {
155 dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
156 return ret;
157 }
158 if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) {
159 ret = sst_load_fw(ctx);
160 if (ret) {
161 dev_err(dev, "FW download fail %d\n", ret);
162 sst_set_fw_state_locked(ctx, SST_RESET);
163 ret = sst_pm_runtime_put(ctx);
164 }
165 }
166 } else {
167 dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count);
146 return sst_pm_runtime_put(ctx); 168 return sst_pm_runtime_put(ctx);
169 }
170 return ret;
147} 171}
148 172
149/* 173/*
@@ -572,6 +596,35 @@ static int sst_stream_drop(struct device *dev, int str_id)
572 return sst_drop_stream(ctx, str_id); 596 return sst_drop_stream(ctx, str_id);
573} 597}
574 598
599static int sst_stream_pause(struct device *dev, int str_id)
600{
601 struct stream_info *str_info;
602 struct intel_sst_drv *ctx = dev_get_drvdata(dev);
603
604 if (ctx->sst_state != SST_FW_RUNNING)
605 return 0;
606
607 str_info = get_stream_info(ctx, str_id);
608 if (!str_info)
609 return -EINVAL;
610
611 return sst_pause_stream(ctx, str_id);
612}
613
614static int sst_stream_resume(struct device *dev, int str_id)
615{
616 struct stream_info *str_info;
617 struct intel_sst_drv *ctx = dev_get_drvdata(dev);
618
619 if (ctx->sst_state != SST_FW_RUNNING)
620 return 0;
621
622 str_info = get_stream_info(ctx, str_id);
623 if (!str_info)
624 return -EINVAL;
625 return sst_resume_stream(ctx, str_id);
626}
627
575static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) 628static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info)
576{ 629{
577 int str_id = 0; 630 int str_id = 0;
@@ -633,6 +686,8 @@ static struct sst_ops pcm_ops = {
633 .stream_init = sst_stream_init, 686 .stream_init = sst_stream_init,
634 .stream_start = sst_stream_start, 687 .stream_start = sst_stream_start,
635 .stream_drop = sst_stream_drop, 688 .stream_drop = sst_stream_drop,
689 .stream_pause = sst_stream_pause,
690 .stream_pause_release = sst_stream_resume,
636 .stream_read_tstamp = sst_read_timestamp, 691 .stream_read_tstamp = sst_read_timestamp,
637 .send_byte_stream = sst_send_byte_stream, 692 .send_byte_stream = sst_send_byte_stream,
638 .close = sst_close_pcm_stream, 693 .close = sst_close_pcm_stream,
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c
index 7888cd707853..e88907ae8b15 100644
--- a/sound/soc/intel/sst/sst_loader.c
+++ b/sound/soc/intel/sst/sst_loader.c
@@ -39,7 +39,15 @@
39#include "sst.h" 39#include "sst.h"
40#include "../sst-dsp.h" 40#include "../sst-dsp.h"
41 41
42static inline void memcpy32_toio(void __iomem *dst, const void *src, int count) 42void memcpy32_toio(void __iomem *dst, const void *src, int count)
43{
44 /* __iowrite32_copy uses 32-bit count values so divide by 4 for
45 * right count in words
46 */
47 __iowrite32_copy(dst, src, count/4);
48}
49
50void memcpy32_fromio(void *dst, const void __iomem *src, int count)
43{ 51{
44 /* __iowrite32_copy uses 32-bit count values so divide by 4 for 52 /* __iowrite32_copy uses 32-bit count values so divide by 4 for
45 * right count in words 53 * right count in words