aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/mid-x86
diff options
context:
space:
mode:
authorVinod Koul <vinod.koul@intel.com>2011-01-04 09:46:32 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-01-06 08:48:58 -0500
commitd927fdae5cb2ca36f0c5b61e528078e8c1261607 (patch)
tree31d3ec92c2bb91a4314357b9935518b96ff79df5 /sound/soc/mid-x86
parent4dc69be22163bab880384858f30cb8cc76ad47f9 (diff)
ASoC: sst v2: Add mid platform driver
This patch adds the platform driver for mid asoc drivers. This platfrom driver sends commands to sst dsp engine driver for the dai operations. For this purpose it depends on intel_sst driver which is currently in staging tree Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Harsha Priya <priya.harsha@intel.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/mid-x86')
-rw-r--r--sound/soc/mid-x86/sst_platform.c484
-rw-r--r--sound/soc/mid-x86/sst_platform.h63
2 files changed, 547 insertions, 0 deletions
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c
new file mode 100644
index 000000000000..189d546fbf94
--- /dev/null
+++ b/sound/soc/mid-x86/sst_platform.c
@@ -0,0 +1,484 @@
1/*
2 * sst_platform.c - Intel MID Platform driver
3 *
4 * Copyright (C) 2010 Intel Corp
5 * Author: Vinod Koul <vinod.koul@intel.com>
6 * Author: Harsha Priya <priya.harsha@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
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.
12 *
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.
17 *
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.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 *
24 *
25 */
26#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
27
28#include <linux/slab.h>
29#include <linux/io.h>
30#include <sound/core.h>
31#include <sound/pcm.h>
32#include <sound/pcm_params.h>
33#include <sound/soc.h>
34#include "../../../drivers/staging/intel_sst/intel_sst_ioctl.h"
35#include "../../../drivers/staging/intel_sst/intel_sst.h"
36#include "sst_platform.h"
37
38static struct snd_pcm_hardware sst_platform_pcm_hw = {
39 .info = (SNDRV_PCM_INFO_INTERLEAVED |
40 SNDRV_PCM_INFO_DOUBLE |
41 SNDRV_PCM_INFO_PAUSE |
42 SNDRV_PCM_INFO_RESUME |
43 SNDRV_PCM_INFO_MMAP|
44 SNDRV_PCM_INFO_MMAP_VALID |
45 SNDRV_PCM_INFO_BLOCK_TRANSFER |
46 SNDRV_PCM_INFO_SYNC_START),
47 .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |
48 SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |
49 SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32),
50 .rates = (SNDRV_PCM_RATE_8000|
51 SNDRV_PCM_RATE_44100 |
52 SNDRV_PCM_RATE_48000),
53 .rate_min = SST_MIN_RATE,
54 .rate_max = SST_MAX_RATE,
55 .channels_min = SST_MIN_CHANNEL,
56 .channels_max = SST_MAX_CHANNEL,
57 .buffer_bytes_max = SST_MAX_BUFFER,
58 .period_bytes_min = SST_MIN_PERIOD_BYTES,
59 .period_bytes_max = SST_MAX_PERIOD_BYTES,
60 .periods_min = SST_MIN_PERIODS,
61 .periods_max = SST_MAX_PERIODS,
62 .fifo_size = SST_FIFO_SIZE,
63};
64
65/* MFLD - MSIC */
66struct snd_soc_dai_driver sst_platform_dai[] = {
67{
68 .name = "Headset-cpu-dai",
69 .id = 0,
70 .playback = {
71 .channels_min = SST_STEREO,
72 .channels_max = SST_STEREO,
73 .rates = SNDRV_PCM_RATE_48000,
74 .formats = SNDRV_PCM_FMTBIT_S24_LE,
75 },
76},
77{
78 .name = "Speaker-cpu-dai",
79 .id = 1,
80 .playback = {
81 .channels_min = SST_MONO,
82 .channels_max = SST_STEREO,
83 .rates = SNDRV_PCM_RATE_48000,
84 .formats = SNDRV_PCM_FMTBIT_S24_LE,
85 },
86},
87{
88 .name = "Vibra1-cpu-dai",
89 .id = 2,
90 .playback = {
91 .channels_min = SST_MONO,
92 .channels_max = SST_MONO,
93 .rates = SNDRV_PCM_RATE_48000,
94 .formats = SNDRV_PCM_FMTBIT_S24_LE,
95 },
96},
97{
98 .name = "Vibra2-cpu-dai",
99 .id = 3,
100 .playback = {
101 .channels_min = SST_MONO,
102 .channels_max = SST_STEREO,
103 .rates = SNDRV_PCM_RATE_48000,
104 .formats = SNDRV_PCM_FMTBIT_S24_LE,
105 },
106},
107};
108/* helper functions */
109static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
110{
111 struct sst_runtime_stream *stream =
112 substream->runtime->private_data;
113 struct snd_sst_stream_params param = {{{0,},},};
114 struct snd_sst_params str_params = {0};
115 int ret_val;
116
117 /* set codec params and inform SST driver the same */
118
119 param.uc.pcm_params.codec = SST_CODEC_TYPE_PCM;
120 param.uc.pcm_params.num_chan = (u8) substream->runtime->channels;
121 param.uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
122 param.uc.pcm_params.reserved = 0;
123 param.uc.pcm_params.sfreq = substream->runtime->rate;
124 param.uc.pcm_params.ring_buffer_size =
125 snd_pcm_lib_buffer_bytes(substream);
126 param.uc.pcm_params.period_count = substream->runtime->period_size;
127 param.uc.pcm_params.ring_buffer_addr =
128 virt_to_phys(substream->dma_buffer.area);
129 substream->runtime->dma_area = substream->dma_buffer.area;
130
131 pr_debug("period_cnt = %d\n", param.uc.pcm_params.period_count);
132 pr_debug("sfreq= %d, wd_sz = %d\n",
133 param.uc.pcm_params.sfreq, param.uc.pcm_params.pcm_wd_sz);
134
135 str_params.sparams = param;
136 str_params.codec = SST_CODEC_TYPE_PCM;
137
138 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
139 str_params.ops = STREAM_OPS_PLAYBACK;
140 str_params.device_type = substream->pcm->device + 1;
141 pr_debug("Playbck stream,Device %d\n",
142 substream->pcm->device);
143 } else {
144 str_params.ops = STREAM_OPS_CAPTURE;
145 str_params.device_type = SND_SST_DEVICE_CAPTURE;
146 pr_debug("Capture stream,Device %d\n",
147 substream->pcm->device);
148 }
149 ret_val = stream->sstdrv_ops->control_set(SST_SND_ALLOC, &str_params);
150 pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
151 if (ret_val < 0)
152 return ret_val;
153
154 stream->stream_info.str_id = ret_val;
155 pr_debug("str id : %d\n", stream->stream_info.str_id);
156
157 return ret_val;
158}
159
160
161static void sst_period_elapsed(void *mad_substream)
162{
163 struct snd_pcm_substream *substream = mad_substream;
164 struct sst_runtime_stream *stream;
165
166 if (!substream || !substream->runtime)
167 return;
168 stream = substream->runtime->private_data;
169 if (!stream)
170 return;
171
172 spin_lock(&stream->status_lock);
173 if (stream->stream_status != SST_PLATFORM_RUNNING) {
174 spin_unlock(&stream->status_lock);
175 return;
176 }
177 spin_unlock(&stream->status_lock);
178 snd_pcm_period_elapsed(substream);
179 return;
180}
181
182static int sst_platform_init_stream(struct snd_pcm_substream *substream)
183{
184 struct sst_runtime_stream *stream =
185 substream->runtime->private_data;
186 int ret_val;
187
188 pr_debug("setting buffer ptr param\n");
189 spin_lock(&stream->status_lock);
190 stream->stream_status = SST_PLATFORM_INIT;
191 spin_unlock(&stream->status_lock);
192 stream->stream_info.period_elapsed = sst_period_elapsed;
193 stream->stream_info.mad_substream = substream;
194 stream->stream_info.buffer_ptr = 0;
195 stream->stream_info.sfreq = substream->runtime->rate;
196 ret_val = stream->sstdrv_ops->control_set(SST_SND_STREAM_INIT,
197 &stream->stream_info);
198 if (ret_val)
199 pr_err("control_set ret error %d\n", ret_val);
200 return ret_val;
201
202}
203/* end -- helper functions */
204
205static int sst_platform_open(struct snd_pcm_substream *substream)
206{
207 struct snd_pcm_runtime *runtime;
208 struct sst_runtime_stream *stream;
209 int ret_val = 0;
210
211 pr_debug("sst_platform_open called\n");
212
213 runtime = substream->runtime;
214 runtime->hw = sst_platform_pcm_hw;
215
216 stream = kzalloc(sizeof(*stream), GFP_KERNEL);
217 if (!stream)
218 return -ENOMEM;
219
220 spin_lock_init(&stream->status_lock);
221 stream->stream_info.str_id = 0;
222
223 spin_lock(&stream->status_lock);
224 stream->stream_status = SST_PLATFORM_INIT;
225 spin_unlock(&stream->status_lock);
226
227 stream->stream_info.mad_substream = substream;
228 /* allocate memory for SST API set */
229 stream->sstdrv_ops = kzalloc(sizeof(*stream->sstdrv_ops),
230 GFP_KERNEL);
231 if (!stream->sstdrv_ops) {
232 pr_err("sst: mem allocation for ops fail\n");
233 kfree(stream);
234 return -ENOMEM;
235 }
236 stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID;
237
238 /* registering with SST driver to get access to SST APIs to use */
239 ret_val = register_sst_card(stream->sstdrv_ops);
240 if (ret_val) {
241 pr_err("sst: sst card registration failed\n");
242 return ret_val;
243 }
244 runtime->private_data = stream;
245 return snd_pcm_hw_constraint_integer(runtime,
246 SNDRV_PCM_HW_PARAM_PERIODS);
247}
248
249static int sst_platform_close(struct snd_pcm_substream *substream)
250{
251 struct sst_runtime_stream *stream;
252 int ret_val = 0, str_id;
253
254 pr_debug("sst_platform_close called\n");
255
256 stream = substream->runtime->private_data;
257 str_id = stream->stream_info.str_id;
258
259 if (str_id)
260 ret_val = stream->sstdrv_ops->control_set(
261 SST_SND_FREE, &str_id);
262
263 kfree(stream->sstdrv_ops);
264 kfree(stream);
265 return ret_val;
266}
267
268static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
269{
270 struct sst_runtime_stream *stream;
271 int ret_val = 0, str_id;
272
273 pr_debug("sst_platform_pcm_prepare called\n");
274
275 stream = substream->runtime->private_data;
276 str_id = stream->stream_info.str_id;
277 if (stream->stream_info.str_id) {
278 ret_val = stream->sstdrv_ops->control_set(
279 SST_SND_DROP, &str_id);
280 return ret_val;
281 }
282
283 ret_val = sst_platform_alloc_stream(substream);
284 if (ret_val < 0)
285 return ret_val;
286 snprintf(substream->pcm->id, sizeof(substream->pcm->id),
287 "%d", stream->stream_info.str_id);
288
289 ret_val = sst_platform_init_stream(substream);
290 if (ret_val)
291 return ret_val;
292 substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
293 return ret_val;
294}
295
296static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
297 int cmd)
298{
299 int ret_val = 0, str_id;
300 struct sst_runtime_stream *stream;
301
302 pr_debug("sst_platform_pcm_trigger called\n");
303
304 stream = substream->runtime->private_data;
305
306 str_id = stream->stream_info.str_id;
307
308 switch (cmd) {
309 case SNDRV_PCM_TRIGGER_START:
310 pr_debug("sst: Trigger Start\n");
311 ret_val = stream->sstdrv_ops->control_set(
312 SST_SND_START, &str_id);
313 if (ret_val)
314 break;
315 spin_lock(&stream->status_lock);
316 stream->stream_status = SST_PLATFORM_RUNNING;
317 spin_unlock(&stream->status_lock);
318 stream->stream_info.mad_substream = substream;
319 break;
320 case SNDRV_PCM_TRIGGER_STOP:
321 pr_debug("sst: in stop\n");
322 ret_val = stream->sstdrv_ops->control_set(
323 SST_SND_DROP, &str_id);
324 if (ret_val)
325 break;
326 spin_lock(&stream->status_lock);
327 stream->stream_status = SST_PLATFORM_DROPPED;
328 spin_unlock(&stream->status_lock);
329 break;
330 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
331 pr_debug("sst: in pause\n");
332 ret_val = stream->sstdrv_ops->control_set(
333 SST_SND_PAUSE, &str_id);
334 if (ret_val)
335 break;
336 spin_lock(&stream->status_lock);
337 stream->stream_status = SST_PLATFORM_PAUSED;
338 spin_unlock(&stream->status_lock);
339 break;
340 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
341 pr_debug("sst: in pause release\n");
342 ret_val = stream->sstdrv_ops->control_set(
343 SST_SND_RESUME, &str_id);
344 if (ret_val)
345 break;
346 spin_lock(&stream->status_lock);
347 stream->stream_status = SST_PLATFORM_RUNNING;
348 spin_unlock(&stream->status_lock);
349 break;
350 default:
351 ret_val = -EINVAL;
352 }
353 return ret_val;
354}
355
356
357static snd_pcm_uframes_t sst_platform_pcm_pointer
358 (struct snd_pcm_substream *substream)
359{
360 struct sst_runtime_stream *stream;
361 int ret_val;
362 struct pcm_stream_info *str_info;
363
364
365 stream = substream->runtime->private_data;
366 spin_lock(&stream->status_lock);
367 if (stream->stream_status == SST_PLATFORM_INIT) {
368 spin_unlock(&stream->status_lock);
369 return 0;
370 }
371 spin_unlock(&stream->status_lock);
372
373 str_info = &stream->stream_info;
374 ret_val = stream->sstdrv_ops->control_set(
375 SST_SND_BUFFER_POINTER, str_info);
376 if (ret_val) {
377 pr_err("sst: error code = %d\n", ret_val);
378 return ret_val;
379 }
380
381 return stream->stream_info.buffer_ptr;
382}
383
384
385static struct snd_pcm_ops sst_platform_ops = {
386 .open = sst_platform_open,
387 .close = sst_platform_close,
388 .ioctl = snd_pcm_lib_ioctl,
389 .prepare = sst_platform_pcm_prepare,
390 .trigger = sst_platform_pcm_trigger,
391 .pointer = sst_platform_pcm_pointer,
392};
393
394static void sst_pcm_free(struct snd_pcm *pcm)
395{
396 pr_debug("sst_pcm_free called\n");
397 snd_pcm_lib_preallocate_free_for_all(pcm);
398}
399
400int sst_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
401 struct snd_pcm *pcm)
402{
403 int retval = 0;
404
405 pr_debug("sst_pcm_new called\n");
406
407 if (dai->driver->playback.channels_min ||
408 dai->driver->capture.channels_min) {
409 retval = snd_pcm_lib_preallocate_pages_for_all(pcm,
410 SNDRV_DMA_TYPE_CONTINUOUS,
411 snd_dma_continuous_data(GFP_KERNEL),
412 SST_MIN_BUFFER, SST_MAX_BUFFER);
413 if (retval) {
414 pr_err("dma buffer allocationf fail\n");
415 return retval;
416 }
417 }
418
419 return retval;
420}
421struct snd_soc_platform_driver sst_soc_platform_drv = {
422 .ops = &sst_platform_ops,
423 .pcm_new = sst_pcm_new,
424 .pcm_free = sst_pcm_free,
425};
426
427static int sst_platform_probe(struct platform_device *pdev)
428{
429 int ret;
430
431 pr_debug("sst_platform_probe called\n");
432 ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
433 if (ret) {
434 pr_err("registering soc platform failed\n");
435 return ret;
436 }
437 ret = snd_soc_register_dais(&pdev->dev,
438 sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
439 if (ret) {
440 pr_err("registering cpu dais failed\n");
441 snd_soc_unregister_platform(&pdev->dev);
442 }
443 return ret;
444}
445
446static int sst_platform_remove(struct platform_device *pdev)
447{
448
449 snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai));
450
451 snd_soc_unregister_platform(&pdev->dev);
452 pr_debug("sst_platform_remove sucess\n");
453
454 return 0;
455}
456
457static struct platform_driver sst_platform_driver = {
458 .driver = {
459 .name = "sst-platform",
460 .owner = THIS_MODULE,
461 },
462 .probe = sst_platform_probe,
463 .remove = sst_platform_remove,
464};
465
466static int __init sst_soc_platform_init(void)
467{
468 pr_debug("sst_soc_platform_init called\n");
469 return platform_driver_register(&sst_platform_driver);
470}
471module_init(sst_soc_platform_init);
472
473static void __exit sst_soc_platform_exit(void)
474{
475 platform_driver_unregister(&sst_platform_driver);
476 pr_debug("sst_soc_platform_exit sucess\n");
477}
478module_exit(sst_soc_platform_exit);
479
480MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
481MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
482MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
483MODULE_LICENSE("GPL v2");
484MODULE_ALIAS("platfrom: sst-platform");
diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h
new file mode 100644
index 000000000000..df370286694f
--- /dev/null
+++ b/sound/soc/mid-x86/sst_platform.h
@@ -0,0 +1,63 @@
1/*
2 * sst_platform.h - Intel MID Platform driver header file
3 *
4 * Copyright (C) 2010 Intel Corp
5 * Author: Vinod Koul <vinod.koul@intel.com>
6 * Author: Harsha Priya <priya.harsha@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
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.
12 *
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.
17 *
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.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 *
24 *
25 */
26
27#ifndef __SST_PLATFORMDRV_H__
28#define __SST_PLATFORMDRV_H__
29
30#define SST_MONO 1
31#define SST_STEREO 2
32#define SST_MAX_CAP 5
33
34#define SST_MIN_RATE 8000
35#define SST_MAX_RATE 48000
36#define SST_MIN_CHANNEL 1
37#define SST_MAX_CHANNEL 5
38#define SST_MAX_BUFFER (800*1024)
39#define SST_MIN_BUFFER (800*1024)
40#define SST_MIN_PERIOD_BYTES 32
41#define SST_MAX_PERIOD_BYTES SST_MAX_BUFFER
42#define SST_MIN_PERIODS 2
43#define SST_MAX_PERIODS (1024*2)
44#define SST_FIFO_SIZE 0
45#define SST_CARD_NAMES "intel_mid_card"
46#define MSIC_VENDOR_ID 3
47
48struct sst_runtime_stream {
49 int stream_status;
50 struct pcm_stream_info stream_info;
51 struct intel_sst_card_ops *sstdrv_ops;
52 spinlock_t status_lock;
53};
54
55enum sst_drv_status {
56 SST_PLATFORM_INIT = 1,
57 SST_PLATFORM_STARTED,
58 SST_PLATFORM_RUNNING,
59 SST_PLATFORM_PAUSED,
60 SST_PLATFORM_DROPPED,
61};
62
63#endif