2 * Intel Baytrail SST PCM Support
3 * Copyright (c) 2014, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 #include <linux/module.h>
16 #include <linux/dma-mapping.h>
17 #include <linux/slab.h>
18 #include <sound/core.h>
19 #include <sound/pcm.h>
20 #include <sound/pcm_params.h>
21 #include <sound/soc.h>
22 #include "sst-baytrail-ipc.h"
23 #include "sst-dsp-priv.h"
26 #define BYT_PCM_COUNT 2
28 static const struct snd_pcm_hardware sst_byt_pcm_hardware
= {
29 .info
= SNDRV_PCM_INFO_MMAP
|
30 SNDRV_PCM_INFO_MMAP_VALID
|
31 SNDRV_PCM_INFO_INTERLEAVED
|
32 SNDRV_PCM_INFO_PAUSE
|
33 SNDRV_PCM_INFO_RESUME
,
34 .formats
= SNDRV_PCM_FMTBIT_S16_LE
|
35 SNDRV_PCM_FMTBIT_S24_LE
,
36 .period_bytes_min
= 384,
37 .period_bytes_max
= 48000,
40 .buffer_bytes_max
= 96000,
43 /* private data for each PCM DSP stream */
44 struct sst_byt_pcm_data
{
45 struct sst_byt_stream
*stream
;
46 struct snd_pcm_substream
*substream
;
49 /* latest DSP DMA hw pointer */
52 struct work_struct work
;
55 /* private data for the driver */
56 struct sst_byt_priv_data
{
61 struct sst_byt_pcm_data pcm
[BYT_PCM_COUNT
];
63 /* flag indicating is stream context restore needed after suspend */
67 /* this may get called several times by oss emulation */
68 static int sst_byt_pcm_hw_params(struct snd_pcm_substream
*substream
,
69 struct snd_pcm_hw_params
*params
)
71 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
72 struct sst_byt_priv_data
*pdata
=
73 snd_soc_platform_get_drvdata(rtd
->platform
);
74 struct sst_byt_pcm_data
*pcm_data
= &pdata
->pcm
[substream
->stream
];
75 struct sst_byt
*byt
= pdata
->byt
;
78 int ret
, playback
= (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
);
80 dev_dbg(rtd
->dev
, "PCM: hw_params, pcm_data %p\n", pcm_data
);
82 ret
= sst_byt_stream_type(byt
, pcm_data
->stream
,
85 dev_err(rtd
->dev
, "failed to set stream format %d\n", ret
);
89 rate
= params_rate(params
);
90 ret
= sst_byt_stream_set_rate(byt
, pcm_data
->stream
, rate
);
92 dev_err(rtd
->dev
, "could not set rate %d\n", rate
);
96 bits
= snd_pcm_format_width(params_format(params
));
97 ret
= sst_byt_stream_set_bits(byt
, pcm_data
->stream
, bits
);
99 dev_err(rtd
->dev
, "could not set formats %d\n",
100 params_rate(params
));
104 channels
= (u8
)(params_channels(params
) & 0xF);
105 ret
= sst_byt_stream_set_channels(byt
, pcm_data
->stream
, channels
);
107 dev_err(rtd
->dev
, "could not set channels %d\n",
108 params_rate(params
));
112 snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
114 ret
= sst_byt_stream_buffer(byt
, pcm_data
->stream
,
115 substream
->dma_buffer
.addr
,
116 params_buffer_bytes(params
));
118 dev_err(rtd
->dev
, "PCM: failed to set DMA buffer %d\n", ret
);
122 ret
= sst_byt_stream_commit(byt
, pcm_data
->stream
);
124 dev_err(rtd
->dev
, "PCM: failed stream commit %d\n", ret
);
131 static int sst_byt_pcm_hw_free(struct snd_pcm_substream
*substream
)
133 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
135 dev_dbg(rtd
->dev
, "PCM: hw_free\n");
136 snd_pcm_lib_free_pages(substream
);
141 static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream
*substream
)
143 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
144 struct sst_byt_priv_data
*pdata
=
145 snd_soc_platform_get_drvdata(rtd
->platform
);
146 struct sst_byt_pcm_data
*pcm_data
= &pdata
->pcm
[substream
->stream
];
147 struct sst_byt
*byt
= pdata
->byt
;
150 /* commit stream using existing stream params */
151 ret
= sst_byt_stream_commit(byt
, pcm_data
->stream
);
153 dev_err(rtd
->dev
, "PCM: failed stream commit %d\n", ret
);
157 sst_byt_stream_start(byt
, pcm_data
->stream
, pcm_data
->hw_ptr
);
159 dev_dbg(rtd
->dev
, "stream context restored at offset %d\n",
165 static void sst_byt_pcm_work(struct work_struct
*work
)
167 struct sst_byt_pcm_data
*pcm_data
=
168 container_of(work
, struct sst_byt_pcm_data
, work
);
170 if (snd_pcm_running(pcm_data
->substream
))
171 sst_byt_pcm_restore_stream_context(pcm_data
->substream
);
174 static int sst_byt_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
176 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
177 struct sst_byt_priv_data
*pdata
=
178 snd_soc_platform_get_drvdata(rtd
->platform
);
179 struct sst_byt_pcm_data
*pcm_data
= &pdata
->pcm
[substream
->stream
];
180 struct sst_byt
*byt
= pdata
->byt
;
182 dev_dbg(rtd
->dev
, "PCM: trigger %d\n", cmd
);
185 case SNDRV_PCM_TRIGGER_START
:
186 pcm_data
->hw_ptr
= 0;
187 sst_byt_stream_start(byt
, pcm_data
->stream
, 0);
189 case SNDRV_PCM_TRIGGER_RESUME
:
190 if (pdata
->restore_stream
== true)
191 schedule_work(&pcm_data
->work
);
193 sst_byt_stream_resume(byt
, pcm_data
->stream
);
195 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
196 sst_byt_stream_resume(byt
, pcm_data
->stream
);
198 case SNDRV_PCM_TRIGGER_STOP
:
199 sst_byt_stream_stop(byt
, pcm_data
->stream
);
201 case SNDRV_PCM_TRIGGER_SUSPEND
:
202 pdata
->restore_stream
= false;
203 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
204 sst_byt_stream_pause(byt
, pcm_data
->stream
);
213 static u32
byt_notify_pointer(struct sst_byt_stream
*stream
, void *data
)
215 struct sst_byt_pcm_data
*pcm_data
= data
;
216 struct snd_pcm_substream
*substream
= pcm_data
->substream
;
217 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
218 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
219 struct sst_byt_priv_data
*pdata
=
220 snd_soc_platform_get_drvdata(rtd
->platform
);
221 struct sst_byt
*byt
= pdata
->byt
;
224 hw_pos
= sst_byt_get_dsp_position(byt
, pcm_data
->stream
,
225 snd_pcm_lib_buffer_bytes(substream
));
226 pcm_data
->hw_ptr
= hw_pos
;
227 pos
= frames_to_bytes(runtime
,
228 (runtime
->control
->appl_ptr
%
229 runtime
->buffer_size
));
231 dev_dbg(rtd
->dev
, "PCM: App/DMA pointer %u/%u bytes\n", pos
, hw_pos
);
233 snd_pcm_period_elapsed(substream
);
237 static snd_pcm_uframes_t
sst_byt_pcm_pointer(struct snd_pcm_substream
*substream
)
239 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
240 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
241 struct sst_byt_priv_data
*pdata
=
242 snd_soc_platform_get_drvdata(rtd
->platform
);
243 struct sst_byt_pcm_data
*pcm_data
= &pdata
->pcm
[substream
->stream
];
245 dev_dbg(rtd
->dev
, "PCM: DMA pointer %u bytes\n", pcm_data
->hw_ptr
);
247 return bytes_to_frames(runtime
, pcm_data
->hw_ptr
);
250 static int sst_byt_pcm_open(struct snd_pcm_substream
*substream
)
252 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
253 struct sst_byt_priv_data
*pdata
=
254 snd_soc_platform_get_drvdata(rtd
->platform
);
255 struct sst_byt_pcm_data
*pcm_data
= &pdata
->pcm
[substream
->stream
];
256 struct sst_byt
*byt
= pdata
->byt
;
258 dev_dbg(rtd
->dev
, "PCM: open\n");
260 mutex_lock(&pcm_data
->mutex
);
262 pcm_data
->substream
= substream
;
264 snd_soc_set_runtime_hwparams(substream
, &sst_byt_pcm_hardware
);
266 pcm_data
->stream
= sst_byt_stream_new(byt
, substream
->stream
+ 1,
267 byt_notify_pointer
, pcm_data
);
268 if (pcm_data
->stream
== NULL
) {
269 dev_err(rtd
->dev
, "failed to create stream\n");
270 mutex_unlock(&pcm_data
->mutex
);
274 mutex_unlock(&pcm_data
->mutex
);
278 static int sst_byt_pcm_close(struct snd_pcm_substream
*substream
)
280 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
281 struct sst_byt_priv_data
*pdata
=
282 snd_soc_platform_get_drvdata(rtd
->platform
);
283 struct sst_byt_pcm_data
*pcm_data
= &pdata
->pcm
[substream
->stream
];
284 struct sst_byt
*byt
= pdata
->byt
;
287 dev_dbg(rtd
->dev
, "PCM: close\n");
289 cancel_work_sync(&pcm_data
->work
);
290 mutex_lock(&pcm_data
->mutex
);
291 ret
= sst_byt_stream_free(byt
, pcm_data
->stream
);
293 dev_dbg(rtd
->dev
, "Free stream fail\n");
296 pcm_data
->stream
= NULL
;
299 mutex_unlock(&pcm_data
->mutex
);
303 static int sst_byt_pcm_mmap(struct snd_pcm_substream
*substream
,
304 struct vm_area_struct
*vma
)
306 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
308 dev_dbg(rtd
->dev
, "PCM: mmap\n");
309 return snd_pcm_lib_default_mmap(substream
, vma
);
312 static struct snd_pcm_ops sst_byt_pcm_ops
= {
313 .open
= sst_byt_pcm_open
,
314 .close
= sst_byt_pcm_close
,
315 .ioctl
= snd_pcm_lib_ioctl
,
316 .hw_params
= sst_byt_pcm_hw_params
,
317 .hw_free
= sst_byt_pcm_hw_free
,
318 .trigger
= sst_byt_pcm_trigger
,
319 .pointer
= sst_byt_pcm_pointer
,
320 .mmap
= sst_byt_pcm_mmap
,
323 static void sst_byt_pcm_free(struct snd_pcm
*pcm
)
325 snd_pcm_lib_preallocate_free_for_all(pcm
);
328 static int sst_byt_pcm_new(struct snd_soc_pcm_runtime
*rtd
)
330 struct snd_pcm
*pcm
= rtd
->pcm
;
332 struct snd_soc_platform
*platform
= rtd
->platform
;
333 struct sst_pdata
*pdata
= dev_get_platdata(platform
->dev
);
336 if (pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
||
337 pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
) {
338 size
= sst_byt_pcm_hardware
.buffer_bytes_max
;
339 ret
= snd_pcm_lib_preallocate_pages_for_all(pcm
,
344 dev_err(rtd
->dev
, "dma buffer allocation failed %d\n",
353 static struct snd_soc_dai_driver byt_dais
[] = {
355 .name
= "Baytrail PCM",
357 .stream_name
= "System Playback",
360 .rates
= SNDRV_PCM_RATE_48000
,
361 .formats
= SNDRV_PCM_FMTBIT_S24_3LE
|
362 SNDRV_PCM_FMTBIT_S16_LE
,
365 .stream_name
= "Analog Capture",
368 .rates
= SNDRV_PCM_RATE_48000
,
369 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
374 static int sst_byt_pcm_probe(struct snd_soc_platform
*platform
)
376 struct sst_pdata
*plat_data
= dev_get_platdata(platform
->dev
);
377 struct sst_byt_priv_data
*priv_data
;
383 priv_data
= devm_kzalloc(platform
->dev
, sizeof(*priv_data
),
385 priv_data
->byt
= plat_data
->dsp
;
386 snd_soc_platform_set_drvdata(platform
, priv_data
);
388 for (i
= 0; i
< BYT_PCM_COUNT
; i
++) {
389 mutex_init(&priv_data
->pcm
[i
].mutex
);
390 INIT_WORK(&priv_data
->pcm
[i
].work
, sst_byt_pcm_work
);
396 static int sst_byt_pcm_remove(struct snd_soc_platform
*platform
)
401 static struct snd_soc_platform_driver byt_soc_platform
= {
402 .probe
= sst_byt_pcm_probe
,
403 .remove
= sst_byt_pcm_remove
,
404 .ops
= &sst_byt_pcm_ops
,
405 .pcm_new
= sst_byt_pcm_new
,
406 .pcm_free
= sst_byt_pcm_free
,
409 static const struct snd_soc_component_driver byt_dai_component
= {
414 static int sst_byt_pcm_dev_suspend_late(struct device
*dev
)
416 struct sst_pdata
*sst_pdata
= dev_get_platdata(dev
);
417 struct sst_byt_priv_data
*priv_data
= dev_get_drvdata(dev
);
420 dev_dbg(dev
, "suspending late\n");
422 ret
= sst_byt_dsp_suspend_late(dev
, sst_pdata
);
424 dev_err(dev
, "failed to suspend %d\n", ret
);
428 priv_data
->restore_stream
= true;
433 static int sst_byt_pcm_dev_resume_early(struct device
*dev
)
435 struct sst_pdata
*sst_pdata
= dev_get_platdata(dev
);
438 dev_dbg(dev
, "resume early\n");
440 /* load fw and boot DSP */
441 ret
= sst_byt_dsp_boot(dev
, sst_pdata
);
445 /* wait for FW to finish booting */
446 return sst_byt_dsp_wait_for_ready(dev
, sst_pdata
);
449 static const struct dev_pm_ops sst_byt_pm_ops
= {
450 .suspend_late
= sst_byt_pcm_dev_suspend_late
,
451 .resume_early
= sst_byt_pcm_dev_resume_early
,
454 #define SST_BYT_PM_OPS (&sst_byt_pm_ops)
456 #define SST_BYT_PM_OPS NULL
459 static int sst_byt_pcm_dev_probe(struct platform_device
*pdev
)
461 struct sst_pdata
*sst_pdata
= dev_get_platdata(&pdev
->dev
);
464 ret
= sst_byt_dsp_init(&pdev
->dev
, sst_pdata
);
468 ret
= snd_soc_register_platform(&pdev
->dev
, &byt_soc_platform
);
472 ret
= snd_soc_register_component(&pdev
->dev
, &byt_dai_component
,
473 byt_dais
, ARRAY_SIZE(byt_dais
));
480 snd_soc_unregister_platform(&pdev
->dev
);
482 sst_byt_dsp_free(&pdev
->dev
, sst_pdata
);
486 static int sst_byt_pcm_dev_remove(struct platform_device
*pdev
)
488 struct sst_pdata
*sst_pdata
= dev_get_platdata(&pdev
->dev
);
490 snd_soc_unregister_platform(&pdev
->dev
);
491 snd_soc_unregister_component(&pdev
->dev
);
492 sst_byt_dsp_free(&pdev
->dev
, sst_pdata
);
497 static struct platform_driver sst_byt_pcm_driver
= {
499 .name
= "baytrail-pcm-audio",
500 .pm
= SST_BYT_PM_OPS
,
503 .probe
= sst_byt_pcm_dev_probe
,
504 .remove
= sst_byt_pcm_dev_remove
,
506 module_platform_driver(sst_byt_pcm_driver
);
508 MODULE_AUTHOR("Jarkko Nikula");
509 MODULE_DESCRIPTION("Baytrail PCM");
510 MODULE_LICENSE("GPL v2");
511 MODULE_ALIAS("platform:baytrail-pcm-audio");