aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/intel/sst-baytrail-pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/sst-baytrail-pcm.c')
-rw-r--r--sound/soc/intel/sst-baytrail-pcm.c162
1 files changed, 132 insertions, 30 deletions
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
index 6d101f3813b4..3af38576e91e 100644
--- a/sound/soc/intel/sst-baytrail-pcm.c
+++ b/sound/soc/intel/sst-baytrail-pcm.c
@@ -45,6 +45,11 @@ struct sst_byt_pcm_data {
45 struct sst_byt_stream *stream; 45 struct sst_byt_stream *stream;
46 struct snd_pcm_substream *substream; 46 struct snd_pcm_substream *substream;
47 struct mutex mutex; 47 struct mutex mutex;
48
49 /* latest DSP DMA hw pointer */
50 u32 hw_ptr;
51
52 struct work_struct work;
48}; 53};
49 54
50/* private data for the driver */ 55/* private data for the driver */
@@ -63,7 +68,7 @@ static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
63 struct snd_soc_pcm_runtime *rtd = substream->private_data; 68 struct snd_soc_pcm_runtime *rtd = substream->private_data;
64 struct sst_byt_priv_data *pdata = 69 struct sst_byt_priv_data *pdata =
65 snd_soc_platform_get_drvdata(rtd->platform); 70 snd_soc_platform_get_drvdata(rtd->platform);
66 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); 71 struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
67 struct sst_byt *byt = pdata->byt; 72 struct sst_byt *byt = pdata->byt;
68 u32 rate, bits; 73 u32 rate, bits;
69 u8 channels; 74 u8 channels;
@@ -130,21 +135,56 @@ static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
130 return 0; 135 return 0;
131} 136}
132 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 = &pdata->pcm[substream->stream];
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 if (snd_pcm_running(pcm_data->substream))
168 sst_byt_pcm_restore_stream_context(pcm_data->substream);
169}
170
133static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 171static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
134{ 172{
135 struct snd_soc_pcm_runtime *rtd = substream->private_data; 173 struct snd_soc_pcm_runtime *rtd = substream->private_data;
136 struct sst_byt_priv_data *pdata = 174 struct sst_byt_priv_data *pdata =
137 snd_soc_platform_get_drvdata(rtd->platform); 175 snd_soc_platform_get_drvdata(rtd->platform);
138 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); 176 struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
139 struct sst_byt *byt = pdata->byt; 177 struct sst_byt *byt = pdata->byt;
140 178
141 dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd); 179 dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
142 180
143 switch (cmd) { 181 switch (cmd) {
144 case SNDRV_PCM_TRIGGER_START: 182 case SNDRV_PCM_TRIGGER_START:
145 sst_byt_stream_start(byt, pcm_data->stream); 183 sst_byt_stream_start(byt, pcm_data->stream, 0);
146 break; 184 break;
147 case SNDRV_PCM_TRIGGER_RESUME: 185 case SNDRV_PCM_TRIGGER_RESUME:
186 schedule_work(&pcm_data->work);
187 break;
148 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 188 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
149 sst_byt_stream_resume(byt, pcm_data->stream); 189 sst_byt_stream_resume(byt, pcm_data->stream);
150 break; 190 break;
@@ -168,13 +208,19 @@ static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
168 struct snd_pcm_substream *substream = pcm_data->substream; 208 struct snd_pcm_substream *substream = pcm_data->substream;
169 struct snd_pcm_runtime *runtime = substream->runtime; 209 struct snd_pcm_runtime *runtime = substream->runtime;
170 struct snd_soc_pcm_runtime *rtd = substream->private_data; 210 struct snd_soc_pcm_runtime *rtd = substream->private_data;
171 u32 pos; 211 struct sst_byt_priv_data *pdata =
212 snd_soc_platform_get_drvdata(rtd->platform);
213 struct sst_byt *byt = pdata->byt;
214 u32 pos, hw_pos;
172 215
216 hw_pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
217 snd_pcm_lib_buffer_bytes(substream));
218 pcm_data->hw_ptr = hw_pos;
173 pos = frames_to_bytes(runtime, 219 pos = frames_to_bytes(runtime,
174 (runtime->control->appl_ptr % 220 (runtime->control->appl_ptr %
175 runtime->buffer_size)); 221 runtime->buffer_size));
176 222
177 dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); 223 dev_dbg(rtd->dev, "PCM: App/DMA pointer %u/%u bytes\n", pos, hw_pos);
178 224
179 snd_pcm_period_elapsed(substream); 225 snd_pcm_period_elapsed(substream);
180 return pos; 226 return pos;
@@ -186,18 +232,11 @@ static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream
186 struct snd_pcm_runtime *runtime = substream->runtime; 232 struct snd_pcm_runtime *runtime = substream->runtime;
187 struct sst_byt_priv_data *pdata = 233 struct sst_byt_priv_data *pdata =
188 snd_soc_platform_get_drvdata(rtd->platform); 234 snd_soc_platform_get_drvdata(rtd->platform);
189 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); 235 struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
190 struct sst_byt *byt = pdata->byt;
191 snd_pcm_uframes_t offset;
192 int pos;
193 236
194 pos = sst_byt_get_dsp_position(byt, pcm_data->stream, 237 dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
195 snd_pcm_lib_buffer_bytes(substream));
196 offset = bytes_to_frames(runtime, pos);
197 238
198 dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", 239 return bytes_to_frames(runtime, pcm_data->hw_ptr);
199 frames_to_bytes(runtime, (u32)offset));
200 return offset;
201} 240}
202 241
203static int sst_byt_pcm_open(struct snd_pcm_substream *substream) 242static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
@@ -205,20 +244,18 @@ static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
205 struct snd_soc_pcm_runtime *rtd = substream->private_data; 244 struct snd_soc_pcm_runtime *rtd = substream->private_data;
206 struct sst_byt_priv_data *pdata = 245 struct sst_byt_priv_data *pdata =
207 snd_soc_platform_get_drvdata(rtd->platform); 246 snd_soc_platform_get_drvdata(rtd->platform);
208 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); 247 struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
209 struct sst_byt *byt = pdata->byt; 248 struct sst_byt *byt = pdata->byt;
210 249
211 dev_dbg(rtd->dev, "PCM: open\n"); 250 dev_dbg(rtd->dev, "PCM: open\n");
212 251
213 pcm_data = &pdata->pcm[rtd->cpu_dai->id];
214 mutex_lock(&pcm_data->mutex); 252 mutex_lock(&pcm_data->mutex);
215 253
216 snd_soc_pcm_set_drvdata(rtd, pcm_data);
217 pcm_data->substream = substream; 254 pcm_data->substream = substream;
218 255
219 snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware); 256 snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
220 257
221 pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1, 258 pcm_data->stream = sst_byt_stream_new(byt, substream->stream + 1,
222 byt_notify_pointer, pcm_data); 259 byt_notify_pointer, pcm_data);
223 if (pcm_data->stream == NULL) { 260 if (pcm_data->stream == NULL) {
224 dev_err(rtd->dev, "failed to create stream\n"); 261 dev_err(rtd->dev, "failed to create stream\n");
@@ -235,12 +272,13 @@ static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
235 struct snd_soc_pcm_runtime *rtd = substream->private_data; 272 struct snd_soc_pcm_runtime *rtd = substream->private_data;
236 struct sst_byt_priv_data *pdata = 273 struct sst_byt_priv_data *pdata =
237 snd_soc_platform_get_drvdata(rtd->platform); 274 snd_soc_platform_get_drvdata(rtd->platform);
238 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); 275 struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
239 struct sst_byt *byt = pdata->byt; 276 struct sst_byt *byt = pdata->byt;
240 int ret; 277 int ret;
241 278
242 dev_dbg(rtd->dev, "PCM: close\n"); 279 dev_dbg(rtd->dev, "PCM: close\n");
243 280
281 cancel_work_sync(&pcm_data->work);
244 mutex_lock(&pcm_data->mutex); 282 mutex_lock(&pcm_data->mutex);
245 ret = sst_byt_stream_free(byt, pcm_data->stream); 283 ret = sst_byt_stream_free(byt, pcm_data->stream);
246 if (ret < 0) { 284 if (ret < 0) {
@@ -283,18 +321,16 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
283{ 321{
284 struct snd_pcm *pcm = rtd->pcm; 322 struct snd_pcm *pcm = rtd->pcm;
285 size_t size; 323 size_t size;
324 struct snd_soc_platform *platform = rtd->platform;
325 struct sst_pdata *pdata = dev_get_platdata(platform->dev);
286 int ret = 0; 326 int ret = 0;
287 327
288 ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
289 if (ret)
290 return ret;
291
292 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || 328 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
293 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 329 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
294 size = sst_byt_pcm_hardware.buffer_bytes_max; 330 size = sst_byt_pcm_hardware.buffer_bytes_max;
295 ret = snd_pcm_lib_preallocate_pages_for_all(pcm, 331 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
296 SNDRV_DMA_TYPE_DEV, 332 SNDRV_DMA_TYPE_DEV,
297 rtd->card->dev, 333 pdata->dma_dev,
298 size, size); 334 size, size);
299 if (ret) { 335 if (ret) {
300 dev_err(rtd->dev, "dma buffer allocation failed %d\n", 336 dev_err(rtd->dev, "dma buffer allocation failed %d\n",
@@ -308,7 +344,7 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
308 344
309static struct snd_soc_dai_driver byt_dais[] = { 345static struct snd_soc_dai_driver byt_dais[] = {
310 { 346 {
311 .name = "Front-cpu-dai", 347 .name = "Baytrail PCM",
312 .playback = { 348 .playback = {
313 .stream_name = "System Playback", 349 .stream_name = "System Playback",
314 .channels_min = 2, 350 .channels_min = 2,
@@ -317,9 +353,6 @@ static struct snd_soc_dai_driver byt_dais[] = {
317 .formats = SNDRV_PCM_FMTBIT_S24_3LE | 353 .formats = SNDRV_PCM_FMTBIT_S24_3LE |
318 SNDRV_PCM_FMTBIT_S16_LE, 354 SNDRV_PCM_FMTBIT_S16_LE,
319 }, 355 },
320 },
321 {
322 .name = "Mic1-cpu-dai",
323 .capture = { 356 .capture = {
324 .stream_name = "Analog Capture", 357 .stream_name = "Analog Capture",
325 .channels_min = 2, 358 .channels_min = 2,
@@ -344,8 +377,10 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
344 priv_data->byt = plat_data->dsp; 377 priv_data->byt = plat_data->dsp;
345 snd_soc_platform_set_drvdata(platform, priv_data); 378 snd_soc_platform_set_drvdata(platform, priv_data);
346 379
347 for (i = 0; i < ARRAY_SIZE(byt_dais); i++) 380 for (i = 0; i < BYT_PCM_COUNT; i++) {
348 mutex_init(&priv_data->pcm[i].mutex); 381 mutex_init(&priv_data->pcm[i].mutex);
382 INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
383 }
349 384
350 return 0; 385 return 0;
351} 386}
@@ -367,6 +402,72 @@ static const struct snd_soc_component_driver byt_dai_component = {
367 .name = "byt-dai", 402 .name = "byt-dai",
368}; 403};
369 404
405#ifdef CONFIG_PM
406static int sst_byt_pcm_dev_suspend_noirq(struct device *dev)
407{
408 struct sst_pdata *sst_pdata = dev_get_platdata(dev);
409 int ret;
410
411 dev_dbg(dev, "suspending noirq\n");
412
413 /* at this point all streams will be stopped and context saved */
414 ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata);
415 if (ret < 0) {
416 dev_err(dev, "failed to suspend %d\n", ret);
417 return ret;
418 }
419
420 return ret;
421}
422
423static int sst_byt_pcm_dev_suspend_late(struct device *dev)
424{
425 struct sst_pdata *sst_pdata = dev_get_platdata(dev);
426 int ret;
427
428 dev_dbg(dev, "suspending late\n");
429
430 ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
431 if (ret < 0) {
432 dev_err(dev, "failed to suspend %d\n", ret);
433 return ret;
434 }
435
436 return ret;
437}
438
439static int sst_byt_pcm_dev_resume_early(struct device *dev)
440{
441 struct sst_pdata *sst_pdata = dev_get_platdata(dev);
442
443 dev_dbg(dev, "resume early\n");
444
445 /* load fw and boot DSP */
446 return sst_byt_dsp_boot(dev, sst_pdata);
447}
448
449static int sst_byt_pcm_dev_resume(struct device *dev)
450{
451 struct sst_pdata *sst_pdata = dev_get_platdata(dev);
452
453 dev_dbg(dev, "resume\n");
454
455 /* wait for FW to finish booting */
456 return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
457}
458
459static const struct dev_pm_ops sst_byt_pm_ops = {
460 .suspend_noirq = sst_byt_pcm_dev_suspend_noirq,
461 .suspend_late = sst_byt_pcm_dev_suspend_late,
462 .resume_early = sst_byt_pcm_dev_resume_early,
463 .resume = sst_byt_pcm_dev_resume,
464};
465
466#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
467#else
468#define SST_BYT_PM_OPS NULL
469#endif
470
370static int sst_byt_pcm_dev_probe(struct platform_device *pdev) 471static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
371{ 472{
372 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); 473 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
@@ -409,6 +510,7 @@ static struct platform_driver sst_byt_pcm_driver = {
409 .driver = { 510 .driver = {
410 .name = "baytrail-pcm-audio", 511 .name = "baytrail-pcm-audio",
411 .owner = THIS_MODULE, 512 .owner = THIS_MODULE,
513 .pm = SST_BYT_PM_OPS,
412 }, 514 },
413 515
414 .probe = sst_byt_pcm_dev_probe, 516 .probe = sst_byt_pcm_dev_probe,