2 * sst_platform.c - Intel MID Platform driver
4 * Copyright (C) 2010-2012 Intel Corp
5 * Author: Vinod Koul <vinod.koul@intel.com>
6 * Author: Harsha Priya <priya.harsha@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28 #include <linux/slab.h>
30 #include <linux/module.h>
31 #include <sound/core.h>
32 #include <sound/pcm.h>
33 #include <sound/pcm_params.h>
34 #include <sound/soc.h>
35 #include <sound/compress_driver.h>
36 #include "sst_platform.h"
38 static struct sst_device
*sst
;
39 static DEFINE_MUTEX(sst_lock
);
41 int sst_register_dsp(struct sst_device
*dev
)
44 if (!try_module_get(dev
->dev
->driver
->owner
))
46 mutex_lock(&sst_lock
);
48 pr_err("we already have a device %s\n", sst
->name
);
49 module_put(dev
->dev
->driver
->owner
);
50 mutex_unlock(&sst_lock
);
53 pr_debug("registering device %s\n", dev
->name
);
55 mutex_unlock(&sst_lock
);
58 EXPORT_SYMBOL_GPL(sst_register_dsp
);
60 int sst_unregister_dsp(struct sst_device
*dev
)
66 mutex_lock(&sst_lock
);
69 mutex_unlock(&sst_lock
);
73 module_put(sst
->dev
->driver
->owner
);
74 pr_debug("unreg %s\n", sst
->name
);
76 mutex_unlock(&sst_lock
);
79 EXPORT_SYMBOL_GPL(sst_unregister_dsp
);
81 static struct snd_pcm_hardware sst_platform_pcm_hw
= {
82 .info
= (SNDRV_PCM_INFO_INTERLEAVED
|
83 SNDRV_PCM_INFO_DOUBLE
|
84 SNDRV_PCM_INFO_PAUSE
|
85 SNDRV_PCM_INFO_RESUME
|
87 SNDRV_PCM_INFO_MMAP_VALID
|
88 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
89 SNDRV_PCM_INFO_SYNC_START
),
90 .formats
= (SNDRV_PCM_FMTBIT_S16
| SNDRV_PCM_FMTBIT_U16
|
91 SNDRV_PCM_FMTBIT_S24
| SNDRV_PCM_FMTBIT_U24
|
92 SNDRV_PCM_FMTBIT_S32
| SNDRV_PCM_FMTBIT_U32
),
93 .rates
= (SNDRV_PCM_RATE_8000
|
94 SNDRV_PCM_RATE_44100
|
95 SNDRV_PCM_RATE_48000
),
96 .rate_min
= SST_MIN_RATE
,
97 .rate_max
= SST_MAX_RATE
,
98 .channels_min
= SST_MIN_CHANNEL
,
99 .channels_max
= SST_MAX_CHANNEL
,
100 .buffer_bytes_max
= SST_MAX_BUFFER
,
101 .period_bytes_min
= SST_MIN_PERIOD_BYTES
,
102 .period_bytes_max
= SST_MAX_PERIOD_BYTES
,
103 .periods_min
= SST_MIN_PERIODS
,
104 .periods_max
= SST_MAX_PERIODS
,
105 .fifo_size
= SST_FIFO_SIZE
,
109 static struct snd_soc_dai_driver sst_platform_dai
[] = {
111 .name
= "Headset-cpu-dai",
114 .channels_min
= SST_STEREO
,
115 .channels_max
= SST_STEREO
,
116 .rates
= SNDRV_PCM_RATE_48000
,
117 .formats
= SNDRV_PCM_FMTBIT_S24_LE
,
122 .rates
= SNDRV_PCM_RATE_48000
,
123 .formats
= SNDRV_PCM_FMTBIT_S24_LE
,
127 .name
= "Speaker-cpu-dai",
130 .channels_min
= SST_MONO
,
131 .channels_max
= SST_STEREO
,
132 .rates
= SNDRV_PCM_RATE_48000
,
133 .formats
= SNDRV_PCM_FMTBIT_S24_LE
,
137 .name
= "Vibra1-cpu-dai",
140 .channels_min
= SST_MONO
,
141 .channels_max
= SST_MONO
,
142 .rates
= SNDRV_PCM_RATE_48000
,
143 .formats
= SNDRV_PCM_FMTBIT_S24_LE
,
147 .name
= "Vibra2-cpu-dai",
150 .channels_min
= SST_MONO
,
151 .channels_max
= SST_STEREO
,
152 .rates
= SNDRV_PCM_RATE_48000
,
153 .formats
= SNDRV_PCM_FMTBIT_S24_LE
,
157 .name
= "Compress-cpu-dai",
160 .channels_min
= SST_STEREO
,
161 .channels_max
= SST_STEREO
,
162 .rates
= SNDRV_PCM_RATE_44100
|SNDRV_PCM_RATE_48000
,
163 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
168 /* helper functions */
169 static inline void sst_set_stream_status(struct sst_runtime_stream
*stream
,
173 spin_lock_irqsave(&stream
->status_lock
, flags
);
174 stream
->stream_status
= state
;
175 spin_unlock_irqrestore(&stream
->status_lock
, flags
);
178 static inline int sst_get_stream_status(struct sst_runtime_stream
*stream
)
183 spin_lock_irqsave(&stream
->status_lock
, flags
);
184 state
= stream
->stream_status
;
185 spin_unlock_irqrestore(&stream
->status_lock
, flags
);
189 static void sst_fill_pcm_params(struct snd_pcm_substream
*substream
,
190 struct sst_pcm_params
*param
)
193 param
->codec
= SST_CODEC_TYPE_PCM
;
194 param
->num_chan
= (u8
) substream
->runtime
->channels
;
195 param
->pcm_wd_sz
= substream
->runtime
->sample_bits
;
197 param
->sfreq
= substream
->runtime
->rate
;
198 param
->ring_buffer_size
= snd_pcm_lib_buffer_bytes(substream
);
199 param
->period_count
= substream
->runtime
->period_size
;
200 param
->ring_buffer_addr
= virt_to_phys(substream
->dma_buffer
.area
);
201 pr_debug("period_cnt = %d\n", param
->period_count
);
202 pr_debug("sfreq= %d, wd_sz = %d\n", param
->sfreq
, param
->pcm_wd_sz
);
205 static int sst_platform_alloc_stream(struct snd_pcm_substream
*substream
)
207 struct sst_runtime_stream
*stream
=
208 substream
->runtime
->private_data
;
209 struct sst_pcm_params param
= {0};
210 struct sst_stream_params str_params
= {0};
213 /* set codec params and inform SST driver the same */
214 sst_fill_pcm_params(substream
, ¶m
);
215 substream
->runtime
->dma_area
= substream
->dma_buffer
.area
;
216 str_params
.sparams
= param
;
217 str_params
.codec
= param
.codec
;
218 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
219 str_params
.ops
= STREAM_OPS_PLAYBACK
;
220 str_params
.device_type
= substream
->pcm
->device
+ 1;
221 pr_debug("Playbck stream,Device %d\n",
222 substream
->pcm
->device
);
224 str_params
.ops
= STREAM_OPS_CAPTURE
;
225 str_params
.device_type
= SND_SST_DEVICE_CAPTURE
;
226 pr_debug("Capture stream,Device %d\n",
227 substream
->pcm
->device
);
229 ret_val
= stream
->ops
->open(&str_params
);
230 pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val
);
234 stream
->stream_info
.str_id
= ret_val
;
235 pr_debug("str id : %d\n", stream
->stream_info
.str_id
);
239 static void sst_period_elapsed(void *mad_substream
)
241 struct snd_pcm_substream
*substream
= mad_substream
;
242 struct sst_runtime_stream
*stream
;
245 if (!substream
|| !substream
->runtime
)
247 stream
= substream
->runtime
->private_data
;
250 status
= sst_get_stream_status(stream
);
251 if (status
!= SST_PLATFORM_RUNNING
)
253 snd_pcm_period_elapsed(substream
);
256 static int sst_platform_init_stream(struct snd_pcm_substream
*substream
)
258 struct sst_runtime_stream
*stream
=
259 substream
->runtime
->private_data
;
262 pr_debug("setting buffer ptr param\n");
263 sst_set_stream_status(stream
, SST_PLATFORM_INIT
);
264 stream
->stream_info
.period_elapsed
= sst_period_elapsed
;
265 stream
->stream_info
.mad_substream
= substream
;
266 stream
->stream_info
.buffer_ptr
= 0;
267 stream
->stream_info
.sfreq
= substream
->runtime
->rate
;
268 ret_val
= stream
->ops
->device_control(
269 SST_SND_STREAM_INIT
, &stream
->stream_info
);
271 pr_err("control_set ret error %d\n", ret_val
);
275 /* end -- helper functions */
277 static int sst_platform_open(struct snd_pcm_substream
*substream
)
279 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
280 struct sst_runtime_stream
*stream
;
283 pr_debug("sst_platform_open called\n");
285 snd_soc_set_runtime_hwparams(substream
, &sst_platform_pcm_hw
);
286 ret_val
= snd_pcm_hw_constraint_integer(runtime
,
287 SNDRV_PCM_HW_PARAM_PERIODS
);
291 stream
= kzalloc(sizeof(*stream
), GFP_KERNEL
);
294 spin_lock_init(&stream
->status_lock
);
296 /* get the sst ops */
297 mutex_lock(&sst_lock
);
299 pr_err("no device available to run\n");
300 mutex_unlock(&sst_lock
);
304 if (!try_module_get(sst
->dev
->driver
->owner
)) {
305 mutex_unlock(&sst_lock
);
309 stream
->ops
= sst
->ops
;
310 mutex_unlock(&sst_lock
);
312 stream
->stream_info
.str_id
= 0;
313 sst_set_stream_status(stream
, SST_PLATFORM_INIT
);
314 stream
->stream_info
.mad_substream
= substream
;
315 /* allocate memory for SST API set */
316 runtime
->private_data
= stream
;
321 static int sst_platform_close(struct snd_pcm_substream
*substream
)
323 struct sst_runtime_stream
*stream
;
324 int ret_val
= 0, str_id
;
326 pr_debug("sst_platform_close called\n");
327 stream
= substream
->runtime
->private_data
;
328 str_id
= stream
->stream_info
.str_id
;
330 ret_val
= stream
->ops
->close(str_id
);
331 module_put(sst
->dev
->driver
->owner
);
336 static int sst_platform_pcm_prepare(struct snd_pcm_substream
*substream
)
338 struct sst_runtime_stream
*stream
;
339 int ret_val
= 0, str_id
;
341 pr_debug("sst_platform_pcm_prepare called\n");
342 stream
= substream
->runtime
->private_data
;
343 str_id
= stream
->stream_info
.str_id
;
344 if (stream
->stream_info
.str_id
) {
345 ret_val
= stream
->ops
->device_control(
346 SST_SND_DROP
, &str_id
);
350 ret_val
= sst_platform_alloc_stream(substream
);
353 snprintf(substream
->pcm
->id
, sizeof(substream
->pcm
->id
),
354 "%d", stream
->stream_info
.str_id
);
356 ret_val
= sst_platform_init_stream(substream
);
359 substream
->runtime
->hw
.info
= SNDRV_PCM_INFO_BLOCK_TRANSFER
;
363 static int sst_platform_pcm_trigger(struct snd_pcm_substream
*substream
,
366 int ret_val
= 0, str_id
;
367 struct sst_runtime_stream
*stream
;
370 pr_debug("sst_platform_pcm_trigger called\n");
371 stream
= substream
->runtime
->private_data
;
372 str_id
= stream
->stream_info
.str_id
;
374 case SNDRV_PCM_TRIGGER_START
:
375 pr_debug("sst: Trigger Start\n");
376 str_cmd
= SST_SND_START
;
377 status
= SST_PLATFORM_RUNNING
;
378 stream
->stream_info
.mad_substream
= substream
;
380 case SNDRV_PCM_TRIGGER_STOP
:
381 pr_debug("sst: in stop\n");
382 str_cmd
= SST_SND_DROP
;
383 status
= SST_PLATFORM_DROPPED
;
385 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
386 pr_debug("sst: in pause\n");
387 str_cmd
= SST_SND_PAUSE
;
388 status
= SST_PLATFORM_PAUSED
;
390 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
391 pr_debug("sst: in pause release\n");
392 str_cmd
= SST_SND_RESUME
;
393 status
= SST_PLATFORM_RUNNING
;
398 ret_val
= stream
->ops
->device_control(str_cmd
, &str_id
);
400 sst_set_stream_status(stream
, status
);
406 static snd_pcm_uframes_t sst_platform_pcm_pointer
407 (struct snd_pcm_substream
*substream
)
409 struct sst_runtime_stream
*stream
;
411 struct pcm_stream_info
*str_info
;
413 stream
= substream
->runtime
->private_data
;
414 status
= sst_get_stream_status(stream
);
415 if (status
== SST_PLATFORM_INIT
)
417 str_info
= &stream
->stream_info
;
418 ret_val
= stream
->ops
->device_control(
419 SST_SND_BUFFER_POINTER
, str_info
);
421 pr_err("sst: error code = %d\n", ret_val
);
424 return stream
->stream_info
.buffer_ptr
;
427 static int sst_platform_pcm_hw_params(struct snd_pcm_substream
*substream
,
428 struct snd_pcm_hw_params
*params
)
430 snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
431 memset(substream
->runtime
->dma_area
, 0, params_buffer_bytes(params
));
436 static int sst_platform_pcm_hw_free(struct snd_pcm_substream
*substream
)
438 return snd_pcm_lib_free_pages(substream
);
441 static struct snd_pcm_ops sst_platform_ops
= {
442 .open
= sst_platform_open
,
443 .close
= sst_platform_close
,
444 .ioctl
= snd_pcm_lib_ioctl
,
445 .prepare
= sst_platform_pcm_prepare
,
446 .trigger
= sst_platform_pcm_trigger
,
447 .pointer
= sst_platform_pcm_pointer
,
448 .hw_params
= sst_platform_pcm_hw_params
,
449 .hw_free
= sst_platform_pcm_hw_free
,
452 static void sst_pcm_free(struct snd_pcm
*pcm
)
454 pr_debug("sst_pcm_free called\n");
455 snd_pcm_lib_preallocate_free_for_all(pcm
);
458 static int sst_pcm_new(struct snd_soc_pcm_runtime
*rtd
)
460 struct snd_pcm
*pcm
= rtd
->pcm
;
463 pr_debug("sst_pcm_new called\n");
464 if (pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
||
465 pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
) {
466 retval
= snd_pcm_lib_preallocate_pages_for_all(pcm
,
467 SNDRV_DMA_TYPE_CONTINUOUS
,
468 snd_dma_continuous_data(GFP_KERNEL
),
469 SST_MIN_BUFFER
, SST_MAX_BUFFER
);
471 pr_err("dma buffer allocationf fail\n");
478 /* compress stream operations */
479 static void sst_compr_fragment_elapsed(void *arg
)
481 struct snd_compr_stream
*cstream
= (struct snd_compr_stream
*)arg
;
483 pr_debug("fragment elapsed by driver\n");
485 snd_compr_fragment_elapsed(cstream
);
488 static int sst_platform_compr_open(struct snd_compr_stream
*cstream
)
492 struct snd_compr_runtime
*runtime
= cstream
->runtime
;
493 struct sst_runtime_stream
*stream
;
495 stream
= kzalloc(sizeof(*stream
), GFP_KERNEL
);
499 spin_lock_init(&stream
->status_lock
);
501 /* get the sst ops */
502 if (!sst
|| !try_module_get(sst
->dev
->driver
->owner
)) {
503 pr_err("no device available to run\n");
507 stream
->compr_ops
= sst
->compr_ops
;
510 sst_set_stream_status(stream
, SST_PLATFORM_INIT
);
511 runtime
->private_data
= stream
;
518 static int sst_platform_compr_free(struct snd_compr_stream
*cstream
)
520 struct sst_runtime_stream
*stream
;
521 int ret_val
= 0, str_id
;
523 stream
= cstream
->runtime
->private_data
;
527 ret_val
= stream
->compr_ops
->close(str_id
);
528 module_put(sst
->dev
->driver
->owner
);
530 pr_debug("%s: %d\n", __func__
, ret_val
);
534 static int sst_platform_compr_set_params(struct snd_compr_stream
*cstream
,
535 struct snd_compr_params
*params
)
537 struct sst_runtime_stream
*stream
;
539 struct snd_sst_params str_params
;
540 struct sst_compress_cb cb
;
542 stream
= cstream
->runtime
->private_data
;
543 /* construct fw structure for this*/
544 memset(&str_params
, 0, sizeof(str_params
));
546 str_params
.ops
= STREAM_OPS_PLAYBACK
;
547 str_params
.stream_type
= SST_STREAM_TYPE_MUSIC
;
548 str_params
.device_type
= SND_SST_DEVICE_COMPRESS
;
550 switch (params
->codec
.id
) {
551 case SND_AUDIOCODEC_MP3
: {
552 str_params
.codec
= SST_CODEC_TYPE_MP3
;
553 str_params
.sparams
.uc
.mp3_params
.codec
= SST_CODEC_TYPE_MP3
;
554 str_params
.sparams
.uc
.mp3_params
.num_chan
= params
->codec
.ch_in
;
555 str_params
.sparams
.uc
.mp3_params
.pcm_wd_sz
= 16;
559 case SND_AUDIOCODEC_AAC
: {
560 str_params
.codec
= SST_CODEC_TYPE_AAC
;
561 str_params
.sparams
.uc
.aac_params
.codec
= SST_CODEC_TYPE_AAC
;
562 str_params
.sparams
.uc
.aac_params
.num_chan
= params
->codec
.ch_in
;
563 str_params
.sparams
.uc
.aac_params
.pcm_wd_sz
= 16;
564 if (params
->codec
.format
== SND_AUDIOSTREAMFORMAT_MP4ADTS
)
565 str_params
.sparams
.uc
.aac_params
.bs_format
=
567 else if (params
->codec
.format
== SND_AUDIOSTREAMFORMAT_RAW
)
568 str_params
.sparams
.uc
.aac_params
.bs_format
=
571 pr_err("Undefined format%d\n", params
->codec
.format
);
574 str_params
.sparams
.uc
.aac_params
.externalsr
=
575 params
->codec
.sample_rate
;
580 pr_err("codec not supported, id =%d\n", params
->codec
.id
);
584 str_params
.aparams
.ring_buf_info
[0].addr
=
585 virt_to_phys(cstream
->runtime
->buffer
);
586 str_params
.aparams
.ring_buf_info
[0].size
=
587 cstream
->runtime
->buffer_size
;
588 str_params
.aparams
.sg_count
= 1;
589 str_params
.aparams
.frag_size
= cstream
->runtime
->fragment_size
;
592 cb
.compr_cb
= sst_compr_fragment_elapsed
;
594 retval
= stream
->compr_ops
->open(&str_params
, &cb
);
596 pr_err("stream allocation failed %d\n", retval
);
604 static int sst_platform_compr_trigger(struct snd_compr_stream
*cstream
, int cmd
)
606 struct sst_runtime_stream
*stream
=
607 cstream
->runtime
->private_data
;
609 return stream
->compr_ops
->control(cmd
, stream
->id
);
612 static int sst_platform_compr_pointer(struct snd_compr_stream
*cstream
,
613 struct snd_compr_tstamp
*tstamp
)
615 struct sst_runtime_stream
*stream
;
617 stream
= cstream
->runtime
->private_data
;
618 stream
->compr_ops
->tstamp(stream
->id
, tstamp
);
619 tstamp
->byte_offset
= tstamp
->copied_total
%
620 (u32
)cstream
->runtime
->buffer_size
;
621 pr_debug("calc bytes offset/copied bytes as %d\n", tstamp
->byte_offset
);
625 static int sst_platform_compr_ack(struct snd_compr_stream
*cstream
,
628 struct sst_runtime_stream
*stream
;
630 stream
= cstream
->runtime
->private_data
;
631 stream
->compr_ops
->ack(stream
->id
, (unsigned long)bytes
);
632 stream
->bytes_written
+= bytes
;
637 static int sst_platform_compr_get_caps(struct snd_compr_stream
*cstream
,
638 struct snd_compr_caps
*caps
)
640 struct sst_runtime_stream
*stream
=
641 cstream
->runtime
->private_data
;
643 return stream
->compr_ops
->get_caps(caps
);
646 static int sst_platform_compr_get_codec_caps(struct snd_compr_stream
*cstream
,
647 struct snd_compr_codec_caps
*codec
)
649 struct sst_runtime_stream
*stream
=
650 cstream
->runtime
->private_data
;
652 return stream
->compr_ops
->get_codec_caps(codec
);
655 static struct snd_compr_ops sst_platform_compr_ops
= {
657 .open
= sst_platform_compr_open
,
658 .free
= sst_platform_compr_free
,
659 .set_params
= sst_platform_compr_set_params
,
660 .trigger
= sst_platform_compr_trigger
,
661 .pointer
= sst_platform_compr_pointer
,
662 .ack
= sst_platform_compr_ack
,
663 .get_caps
= sst_platform_compr_get_caps
,
664 .get_codec_caps
= sst_platform_compr_get_codec_caps
,
667 static struct snd_soc_platform_driver sst_soc_platform_drv
= {
668 .ops
= &sst_platform_ops
,
669 .compr_ops
= &sst_platform_compr_ops
,
670 .pcm_new
= sst_pcm_new
,
671 .pcm_free
= sst_pcm_free
,
674 static int sst_platform_probe(struct platform_device
*pdev
)
678 pr_debug("sst_platform_probe called\n");
680 ret
= snd_soc_register_platform(&pdev
->dev
, &sst_soc_platform_drv
);
682 pr_err("registering soc platform failed\n");
686 ret
= snd_soc_register_dais(&pdev
->dev
,
687 sst_platform_dai
, ARRAY_SIZE(sst_platform_dai
));
689 pr_err("registering cpu dais failed\n");
690 snd_soc_unregister_platform(&pdev
->dev
);
695 static int sst_platform_remove(struct platform_device
*pdev
)
698 snd_soc_unregister_dais(&pdev
->dev
, ARRAY_SIZE(sst_platform_dai
));
699 snd_soc_unregister_platform(&pdev
->dev
);
700 pr_debug("sst_platform_remove success\n");
704 static struct platform_driver sst_platform_driver
= {
706 .name
= "sst-platform",
707 .owner
= THIS_MODULE
,
709 .probe
= sst_platform_probe
,
710 .remove
= sst_platform_remove
,
713 module_platform_driver(sst_platform_driver
);
715 MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
716 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
717 MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
718 MODULE_LICENSE("GPL v2");
719 MODULE_ALIAS("platform:sst-platform");