~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/intel/atom/sst-mfld-platform-pcm.c

Version: ~ [ linux-5.2 ] ~ [ linux-5.1.16 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.57 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.132 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.184 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.184 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.69 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  sst_mfld_platform.c - Intel MID Platform driver
  3  *
  4  *  Copyright (C) 2010-2014 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  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 19  */
 20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 21 
 22 #include <linux/slab.h>
 23 #include <linux/io.h>
 24 #include <linux/module.h>
 25 #include <sound/core.h>
 26 #include <sound/pcm.h>
 27 #include <sound/pcm_params.h>
 28 #include <sound/soc.h>
 29 #include <sound/compress_driver.h>
 30 #include <asm/platform_sst_audio.h>
 31 #include "sst-mfld-platform.h"
 32 #include "sst-atom-controls.h"
 33 
 34 struct sst_device *sst;
 35 static DEFINE_MUTEX(sst_lock);
 36 
 37 int sst_register_dsp(struct sst_device *dev)
 38 {
 39         if (WARN_ON(!dev))
 40                 return -EINVAL;
 41         if (!try_module_get(dev->dev->driver->owner))
 42                 return -ENODEV;
 43         mutex_lock(&sst_lock);
 44         if (sst) {
 45                 dev_err(dev->dev, "we already have a device %s\n", sst->name);
 46                 module_put(dev->dev->driver->owner);
 47                 mutex_unlock(&sst_lock);
 48                 return -EEXIST;
 49         }
 50         dev_dbg(dev->dev, "registering device %s\n", dev->name);
 51         sst = dev;
 52         mutex_unlock(&sst_lock);
 53         return 0;
 54 }
 55 EXPORT_SYMBOL_GPL(sst_register_dsp);
 56 
 57 int sst_unregister_dsp(struct sst_device *dev)
 58 {
 59         if (WARN_ON(!dev))
 60                 return -EINVAL;
 61         if (dev != sst)
 62                 return -EINVAL;
 63 
 64         mutex_lock(&sst_lock);
 65 
 66         if (!sst) {
 67                 mutex_unlock(&sst_lock);
 68                 return -EIO;
 69         }
 70 
 71         module_put(sst->dev->driver->owner);
 72         dev_dbg(dev->dev, "unreg %s\n", sst->name);
 73         sst = NULL;
 74         mutex_unlock(&sst_lock);
 75         return 0;
 76 }
 77 EXPORT_SYMBOL_GPL(sst_unregister_dsp);
 78 
 79 static struct snd_pcm_hardware sst_platform_pcm_hw = {
 80         .info = (SNDRV_PCM_INFO_INTERLEAVED |
 81                         SNDRV_PCM_INFO_DOUBLE |
 82                         SNDRV_PCM_INFO_PAUSE |
 83                         SNDRV_PCM_INFO_RESUME |
 84                         SNDRV_PCM_INFO_MMAP|
 85                         SNDRV_PCM_INFO_MMAP_VALID |
 86                         SNDRV_PCM_INFO_BLOCK_TRANSFER |
 87                         SNDRV_PCM_INFO_SYNC_START),
 88         .buffer_bytes_max = SST_MAX_BUFFER,
 89         .period_bytes_min = SST_MIN_PERIOD_BYTES,
 90         .period_bytes_max = SST_MAX_PERIOD_BYTES,
 91         .periods_min = SST_MIN_PERIODS,
 92         .periods_max = SST_MAX_PERIODS,
 93         .fifo_size = SST_FIFO_SIZE,
 94 };
 95 
 96 static struct sst_dev_stream_map dpcm_strm_map[] = {
 97         {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* Reserved, not in use */
 98         {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0},
 99         {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0},
100         {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0},
101 };
102 
103 static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
104 {
105 
106         return sst_send_pipe_gains(dai, stream, mute);
107 }
108 
109 /* helper functions */
110 void sst_set_stream_status(struct sst_runtime_stream *stream,
111                                         int state)
112 {
113         unsigned long flags;
114         spin_lock_irqsave(&stream->status_lock, flags);
115         stream->stream_status = state;
116         spin_unlock_irqrestore(&stream->status_lock, flags);
117 }
118 
119 static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
120 {
121         int state;
122         unsigned long flags;
123 
124         spin_lock_irqsave(&stream->status_lock, flags);
125         state = stream->stream_status;
126         spin_unlock_irqrestore(&stream->status_lock, flags);
127         return state;
128 }
129 
130 static void sst_fill_alloc_params(struct snd_pcm_substream *substream,
131                                 struct snd_sst_alloc_params_ext *alloc_param)
132 {
133         unsigned int channels;
134         snd_pcm_uframes_t period_size;
135         ssize_t periodbytes;
136         ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
137         u32 buffer_addr = virt_to_phys(substream->dma_buffer.area);
138 
139         channels = substream->runtime->channels;
140         period_size = substream->runtime->period_size;
141         periodbytes = samples_to_bytes(substream->runtime, period_size);
142         alloc_param->ring_buf_info[0].addr = buffer_addr;
143         alloc_param->ring_buf_info[0].size = buffer_bytes;
144         alloc_param->sg_count = 1;
145         alloc_param->reserved = 0;
146         alloc_param->frag_size = periodbytes * channels;
147 
148 }
149 static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
150                                 struct snd_sst_stream_params *param)
151 {
152         param->uc.pcm_params.num_chan = (u8) substream->runtime->channels;
153         param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
154         param->uc.pcm_params.sfreq = substream->runtime->rate;
155 
156         /* PCM stream via ALSA interface */
157         param->uc.pcm_params.use_offload_path = 0;
158         param->uc.pcm_params.reserved2 = 0;
159         memset(param->uc.pcm_params.channel_map, 0, sizeof(u8));
160 
161 }
162 
163 static int sst_get_stream_mapping(int dev, int sdev, int dir,
164         struct sst_dev_stream_map *map, int size)
165 {
166         int i;
167 
168         if (map == NULL)
169                 return -EINVAL;
170 
171 
172         /* index 0 is not used in stream map */
173         for (i = 1; i < size; i++) {
174                 if ((map[i].dev_num == dev) && (map[i].direction == dir))
175                         return i;
176         }
177         return 0;
178 }
179 
180 int sst_fill_stream_params(void *substream,
181         const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress)
182 {
183         int map_size;
184         int index;
185         struct sst_dev_stream_map *map;
186         struct snd_pcm_substream *pstream = NULL;
187         struct snd_compr_stream *cstream = NULL;
188 
189         map = ctx->pdata->pdev_strm_map;
190         map_size = ctx->pdata->strm_map_size;
191 
192         if (is_compress == true)
193                 cstream = (struct snd_compr_stream *)substream;
194         else
195                 pstream = (struct snd_pcm_substream *)substream;
196 
197         str_params->stream_type = SST_STREAM_TYPE_MUSIC;
198 
199         /* For pcm streams */
200         if (pstream) {
201                 index = sst_get_stream_mapping(pstream->pcm->device,
202                                           pstream->number, pstream->stream,
203                                           map, map_size);
204                 if (index <= 0)
205                         return -EINVAL;
206 
207                 str_params->stream_id = index;
208                 str_params->device_type = map[index].device_id;
209                 str_params->task = map[index].task_id;
210 
211                 str_params->ops = (u8)pstream->stream;
212         }
213 
214         if (cstream) {
215                 index = sst_get_stream_mapping(cstream->device->device,
216                                                0, cstream->direction,
217                                                map, map_size);
218                 if (index <= 0)
219                         return -EINVAL;
220                 str_params->stream_id = index;
221                 str_params->device_type = map[index].device_id;
222                 str_params->task = map[index].task_id;
223 
224                 str_params->ops = (u8)cstream->direction;
225         }
226         return 0;
227 }
228 
229 static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
230                 struct snd_soc_dai *dai)
231 {
232         struct sst_runtime_stream *stream =
233                         substream->runtime->private_data;
234         struct snd_sst_stream_params param = {{{0,},},};
235         struct snd_sst_params str_params = {0};
236         struct snd_sst_alloc_params_ext alloc_params = {0};
237         int ret_val = 0;
238         struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
239 
240         /* set codec params and inform SST driver the same */
241         sst_fill_pcm_params(substream, &param);
242         sst_fill_alloc_params(substream, &alloc_params);
243         substream->runtime->dma_area = substream->dma_buffer.area;
244         str_params.sparams = param;
245         str_params.aparams = alloc_params;
246         str_params.codec = SST_CODEC_TYPE_PCM;
247 
248         /* fill the device type and stream id to pass to SST driver */
249         ret_val = sst_fill_stream_params(substream, ctx, &str_params, false);
250         if (ret_val < 0)
251                 return ret_val;
252 
253         stream->stream_info.str_id = str_params.stream_id;
254 
255         ret_val = stream->ops->open(sst->dev, &str_params);
256         if (ret_val <= 0)
257                 return ret_val;
258 
259 
260         return ret_val;
261 }
262 
263 static void sst_period_elapsed(void *arg)
264 {
265         struct snd_pcm_substream *substream = arg;
266         struct sst_runtime_stream *stream;
267         int status;
268 
269         if (!substream || !substream->runtime)
270                 return;
271         stream = substream->runtime->private_data;
272         if (!stream)
273                 return;
274         status = sst_get_stream_status(stream);
275         if (status != SST_PLATFORM_RUNNING)
276                 return;
277         snd_pcm_period_elapsed(substream);
278 }
279 
280 static int sst_platform_init_stream(struct snd_pcm_substream *substream)
281 {
282         struct sst_runtime_stream *stream =
283                         substream->runtime->private_data;
284         struct snd_soc_pcm_runtime *rtd = substream->private_data;
285         int ret_val;
286 
287         dev_dbg(rtd->dev, "setting buffer ptr param\n");
288         sst_set_stream_status(stream, SST_PLATFORM_INIT);
289         stream->stream_info.period_elapsed = sst_period_elapsed;
290         stream->stream_info.arg = substream;
291         stream->stream_info.buffer_ptr = 0;
292         stream->stream_info.sfreq = substream->runtime->rate;
293         ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
294         if (ret_val)
295                 dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
296         return ret_val;
297 
298 }
299 
300 static int power_up_sst(struct sst_runtime_stream *stream)
301 {
302         return stream->ops->power(sst->dev, true);
303 }
304 
305 static void power_down_sst(struct sst_runtime_stream *stream)
306 {
307         stream->ops->power(sst->dev, false);
308 }
309 
310 static int sst_media_open(struct snd_pcm_substream *substream,
311                 struct snd_soc_dai *dai)
312 {
313         int ret_val = 0;
314         struct snd_pcm_runtime *runtime = substream->runtime;
315         struct sst_runtime_stream *stream;
316 
317         stream = kzalloc(sizeof(*stream), GFP_KERNEL);
318         if (!stream)
319                 return -ENOMEM;
320         spin_lock_init(&stream->status_lock);
321 
322         /* get the sst ops */
323         mutex_lock(&sst_lock);
324         if (!sst ||
325             !try_module_get(sst->dev->driver->owner)) {
326                 dev_err(dai->dev, "no device available to run\n");
327                 ret_val = -ENODEV;
328                 goto out_ops;
329         }
330         stream->ops = sst->ops;
331         mutex_unlock(&sst_lock);
332 
333         stream->stream_info.str_id = 0;
334 
335         stream->stream_info.arg = substream;
336         /* allocate memory for SST API set */
337         runtime->private_data = stream;
338 
339         ret_val = power_up_sst(stream);
340         if (ret_val < 0)
341                 return ret_val;
342 
343         /* Make sure, that the period size is always even */
344         snd_pcm_hw_constraint_step(substream->runtime, 0,
345                            SNDRV_PCM_HW_PARAM_PERIODS, 2);
346 
347         return snd_pcm_hw_constraint_integer(runtime,
348                          SNDRV_PCM_HW_PARAM_PERIODS);
349 out_ops:
350         kfree(stream);
351         mutex_unlock(&sst_lock);
352         return ret_val;
353 }
354 
355 static void sst_media_close(struct snd_pcm_substream *substream,
356                 struct snd_soc_dai *dai)
357 {
358         struct sst_runtime_stream *stream;
359         int ret_val = 0, str_id;
360 
361         stream = substream->runtime->private_data;
362         power_down_sst(stream);
363 
364         str_id = stream->stream_info.str_id;
365         if (str_id)
366                 ret_val = stream->ops->close(sst->dev, str_id);
367         module_put(sst->dev->driver->owner);
368         kfree(stream);
369 }
370 
371 static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
372                                                struct snd_pcm_substream *substream)
373 {
374         struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
375         struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
376         struct sst_runtime_stream *stream =
377                         substream->runtime->private_data;
378         u32 str_id = stream->stream_info.str_id;
379         unsigned int pipe_id;
380 
381         pipe_id = map[str_id].device_id;
382 
383         dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
384                         pipe_id, str_id);
385         return pipe_id;
386 }
387 
388 static int sst_media_prepare(struct snd_pcm_substream *substream,
389                 struct snd_soc_dai *dai)
390 {
391         struct sst_runtime_stream *stream;
392         int ret_val = 0, str_id;
393 
394         stream = substream->runtime->private_data;
395         str_id = stream->stream_info.str_id;
396         if (stream->stream_info.str_id) {
397                 ret_val = stream->ops->stream_drop(sst->dev, str_id);
398                 return ret_val;
399         }
400 
401         ret_val = sst_platform_alloc_stream(substream, dai);
402         if (ret_val <= 0)
403                 return ret_val;
404         snprintf(substream->pcm->id, sizeof(substream->pcm->id),
405                         "%d", stream->stream_info.str_id);
406 
407         ret_val = sst_platform_init_stream(substream);
408         if (ret_val)
409                 return ret_val;
410         substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
411         return ret_val;
412 }
413 
414 static int sst_media_hw_params(struct snd_pcm_substream *substream,
415                                 struct snd_pcm_hw_params *params,
416                                 struct snd_soc_dai *dai)
417 {
418         snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
419         memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
420         return 0;
421 }
422 
423 static int sst_media_hw_free(struct snd_pcm_substream *substream,
424                 struct snd_soc_dai *dai)
425 {
426         return snd_pcm_lib_free_pages(substream);
427 }
428 
429 static int sst_enable_ssp(struct snd_pcm_substream *substream,
430                         struct snd_soc_dai *dai)
431 {
432         int ret = 0;
433 
434         if (!dai->active) {
435                 ret = sst_handle_vb_timer(dai, true);
436                 sst_fill_ssp_defaults(dai);
437         }
438         return ret;
439 }
440 
441 static int sst_be_hw_params(struct snd_pcm_substream *substream,
442                                 struct snd_pcm_hw_params *params,
443                                 struct snd_soc_dai *dai)
444 {
445         int ret = 0;
446 
447         if (dai->active == 1)
448                 ret = send_ssp_cmd(dai, dai->name, 1);
449         return ret;
450 }
451 
452 static int sst_set_format(struct snd_soc_dai *dai, unsigned int fmt)
453 {
454         int ret = 0;
455 
456         if (!dai->active)
457                 return 0;
458 
459         ret = sst_fill_ssp_config(dai, fmt);
460         if (ret < 0)
461                 dev_err(dai->dev, "sst_set_format failed..\n");
462 
463         return ret;
464 }
465 
466 static int sst_platform_set_ssp_slot(struct snd_soc_dai *dai,
467                         unsigned int tx_mask, unsigned int rx_mask,
468                         int slots, int slot_width) {
469         int ret = 0;
470 
471         if (!dai->active)
472                 return ret;
473 
474         ret = sst_fill_ssp_slot(dai, tx_mask, rx_mask, slots, slot_width);
475         if (ret < 0)
476                 dev_err(dai->dev, "sst_fill_ssp_slot failed..%d\n", ret);
477 
478         return ret;
479 }
480 
481 static void sst_disable_ssp(struct snd_pcm_substream *substream,
482                         struct snd_soc_dai *dai)
483 {
484         if (!dai->active) {
485                 send_ssp_cmd(dai, dai->name, 0);
486                 sst_handle_vb_timer(dai, false);
487         }
488 }
489 
490 static struct snd_soc_dai_ops sst_media_dai_ops = {
491         .startup = sst_media_open,
492         .shutdown = sst_media_close,
493         .prepare = sst_media_prepare,
494         .hw_params = sst_media_hw_params,
495         .hw_free = sst_media_hw_free,
496         .mute_stream = sst_media_digital_mute,
497 };
498 
499 static struct snd_soc_dai_ops sst_compr_dai_ops = {
500         .mute_stream = sst_media_digital_mute,
501 };
502 
503 static struct snd_soc_dai_ops sst_be_dai_ops = {
504         .startup = sst_enable_ssp,
505         .hw_params = sst_be_hw_params,
506         .set_fmt = sst_set_format,
507         .set_tdm_slot = sst_platform_set_ssp_slot,
508         .shutdown = sst_disable_ssp,
509 };
510 
511 static struct snd_soc_dai_driver sst_platform_dai[] = {
512 {
513         .name = "media-cpu-dai",
514         .ops = &sst_media_dai_ops,
515         .playback = {
516                 .stream_name = "Headset Playback",
517                 .channels_min = SST_STEREO,
518                 .channels_max = SST_STEREO,
519                 .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
520                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
521         },
522         .capture = {
523                 .stream_name = "Headset Capture",
524                 .channels_min = 1,
525                 .channels_max = 2,
526                 .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
527                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
528         },
529 },
530 {
531         .name = "compress-cpu-dai",
532         .compress_dai = 1,
533         .ops = &sst_compr_dai_ops,
534         .playback = {
535                 .stream_name = "Compress Playback",
536                 .channels_min = SST_STEREO,
537                 .channels_max = SST_STEREO,
538                 .rates = SNDRV_PCM_RATE_48000,
539                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
540         },
541 },
542 /* BE CPU  Dais */
543 {
544         .name = "ssp0-port",
545         .ops = &sst_be_dai_ops,
546         .playback = {
547                 .stream_name = "ssp0 Tx",
548                 .channels_min = SST_STEREO,
549                 .channels_max = SST_STEREO,
550                 .rates = SNDRV_PCM_RATE_48000,
551                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
552         },
553         .capture = {
554                 .stream_name = "ssp0 Rx",
555                 .channels_min = SST_STEREO,
556                 .channels_max = SST_STEREO,
557                 .rates = SNDRV_PCM_RATE_48000,
558                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
559         },
560 },
561 {
562         .name = "ssp1-port",
563         .ops = &sst_be_dai_ops,
564         .playback = {
565                 .stream_name = "ssp1 Tx",
566                 .channels_min = SST_STEREO,
567                 .channels_max = SST_STEREO,
568                 .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
569                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
570         },
571         .capture = {
572                 .stream_name = "ssp1 Rx",
573                 .channels_min = SST_STEREO,
574                 .channels_max = SST_STEREO,
575                 .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
576                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
577         },
578 },
579 {
580         .name = "ssp2-port",
581         .ops = &sst_be_dai_ops,
582         .playback = {
583                 .stream_name = "ssp2 Tx",
584                 .channels_min = SST_STEREO,
585                 .channels_max = SST_STEREO,
586                 .rates = SNDRV_PCM_RATE_48000,
587                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
588         },
589         .capture = {
590                 .stream_name = "ssp2 Rx",
591                 .channels_min = SST_STEREO,
592                 .channels_max = SST_STEREO,
593                 .rates = SNDRV_PCM_RATE_48000,
594                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
595         },
596 },
597 };
598 
599 static int sst_platform_open(struct snd_pcm_substream *substream)
600 {
601         struct snd_pcm_runtime *runtime;
602 
603         if (substream->pcm->internal)
604                 return 0;
605 
606         runtime = substream->runtime;
607         runtime->hw = sst_platform_pcm_hw;
608         return 0;
609 }
610 
611 static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
612                                         int cmd)
613 {
614         int ret_val = 0, str_id;
615         struct sst_runtime_stream *stream;
616         int status;
617         struct snd_soc_pcm_runtime *rtd = substream->private_data;
618 
619         dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
620         if (substream->pcm->internal)
621                 return 0;
622         stream = substream->runtime->private_data;
623         str_id = stream->stream_info.str_id;
624         switch (cmd) {
625         case SNDRV_PCM_TRIGGER_START:
626                 dev_dbg(rtd->dev, "sst: Trigger Start\n");
627                 status = SST_PLATFORM_RUNNING;
628                 stream->stream_info.arg = substream;
629                 ret_val = stream->ops->stream_start(sst->dev, str_id);
630                 break;
631         case SNDRV_PCM_TRIGGER_STOP:
632                 dev_dbg(rtd->dev, "sst: in stop\n");
633                 status = SST_PLATFORM_DROPPED;
634                 ret_val = stream->ops->stream_drop(sst->dev, str_id);
635                 break;
636         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
637         case SNDRV_PCM_TRIGGER_SUSPEND:
638                 dev_dbg(rtd->dev, "sst: in pause\n");
639                 status = SST_PLATFORM_PAUSED;
640                 ret_val = stream->ops->stream_pause(sst->dev, str_id);
641                 break;
642         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
643         case SNDRV_PCM_TRIGGER_RESUME:
644                 dev_dbg(rtd->dev, "sst: in pause release\n");
645                 status = SST_PLATFORM_RUNNING;
646                 ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
647                 break;
648         default:
649                 return -EINVAL;
650         }
651 
652         if (!ret_val)
653                 sst_set_stream_status(stream, status);
654 
655         return ret_val;
656 }
657 
658 
659 static snd_pcm_uframes_t sst_platform_pcm_pointer
660                         (struct snd_pcm_substream *substream)
661 {
662         struct sst_runtime_stream *stream;
663         int ret_val, status;
664         struct pcm_stream_info *str_info;
665         struct snd_soc_pcm_runtime *rtd = substream->private_data;
666 
667         stream = substream->runtime->private_data;
668         status = sst_get_stream_status(stream);
669         if (status == SST_PLATFORM_INIT)
670                 return 0;
671         str_info = &stream->stream_info;
672         ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
673         if (ret_val) {
674                 dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
675                 return ret_val;
676         }
677         substream->runtime->delay = str_info->pcm_delay;
678         return str_info->buffer_ptr;
679 }
680 
681 static struct snd_pcm_ops sst_platform_ops = {
682         .open = sst_platform_open,
683         .ioctl = snd_pcm_lib_ioctl,
684         .trigger = sst_platform_pcm_trigger,
685         .pointer = sst_platform_pcm_pointer,
686 };
687 
688 static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
689 {
690         struct snd_soc_dai *dai = rtd->cpu_dai;
691         struct snd_pcm *pcm = rtd->pcm;
692         int retval = 0;
693 
694         if (dai->driver->playback.channels_min ||
695                         dai->driver->capture.channels_min) {
696                 retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
697                         SNDRV_DMA_TYPE_CONTINUOUS,
698                         snd_dma_continuous_data(GFP_DMA),
699                         SST_MIN_BUFFER, SST_MAX_BUFFER);
700                 if (retval) {
701                         dev_err(rtd->dev, "dma buffer allocationf fail\n");
702                         return retval;
703                 }
704         }
705         return retval;
706 }
707 
708 static int sst_soc_probe(struct snd_soc_platform *platform)
709 {
710         struct sst_data *drv = dev_get_drvdata(platform->dev);
711 
712         drv->soc_card = platform->component.card;
713         return sst_dsp_init_v2_dpcm(platform);
714 }
715 
716 static struct snd_soc_platform_driver sst_soc_platform_drv  = {
717         .probe          = sst_soc_probe,
718         .ops            = &sst_platform_ops,
719         .compr_ops      = &sst_platform_compr_ops,
720         .pcm_new        = sst_pcm_new,
721 };
722 
723 static const struct snd_soc_component_driver sst_component = {
724         .name           = "sst",
725 };
726 
727 
728 static int sst_platform_probe(struct platform_device *pdev)
729 {
730         struct sst_data *drv;
731         int ret;
732         struct sst_platform_data *pdata;
733 
734         drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
735         if (drv == NULL) {
736                 return -ENOMEM;
737         }
738 
739         pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
740         if (pdata == NULL) {
741                 return -ENOMEM;
742         }
743 
744         pdata->pdev_strm_map = dpcm_strm_map;
745         pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map);
746         drv->pdata = pdata;
747         drv->pdev = pdev;
748         mutex_init(&drv->lock);
749         dev_set_drvdata(&pdev->dev, drv);
750 
751         ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
752         if (ret) {
753                 dev_err(&pdev->dev, "registering soc platform failed\n");
754                 return ret;
755         }
756 
757         ret = snd_soc_register_component(&pdev->dev, &sst_component,
758                                 sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
759         if (ret) {
760                 dev_err(&pdev->dev, "registering cpu dais failed\n");
761                 snd_soc_unregister_platform(&pdev->dev);
762         }
763         return ret;
764 }
765 
766 static int sst_platform_remove(struct platform_device *pdev)
767 {
768 
769         snd_soc_unregister_component(&pdev->dev);
770         snd_soc_unregister_platform(&pdev->dev);
771         dev_dbg(&pdev->dev, "sst_platform_remove success\n");
772         return 0;
773 }
774 
775 #ifdef CONFIG_PM_SLEEP
776 
777 static int sst_soc_prepare(struct device *dev)
778 {
779         struct sst_data *drv = dev_get_drvdata(dev);
780         int i;
781 
782         /* suspend all pcms first */
783         snd_soc_suspend(drv->soc_card->dev);
784         snd_soc_poweroff(drv->soc_card->dev);
785 
786         /* set the SSPs to idle */
787         for (i = 0; i < drv->soc_card->num_rtd; i++) {
788                 struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
789 
790                 if (dai->active) {
791                         send_ssp_cmd(dai, dai->name, 0);
792                         sst_handle_vb_timer(dai, false);
793                 }
794         }
795 
796         return 0;
797 }
798 
799 static void sst_soc_complete(struct device *dev)
800 {
801         struct sst_data *drv = dev_get_drvdata(dev);
802         int i;
803 
804         /* restart SSPs */
805         for (i = 0; i < drv->soc_card->num_rtd; i++) {
806                 struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
807 
808                 if (dai->active) {
809                         sst_handle_vb_timer(dai, true);
810                         send_ssp_cmd(dai, dai->name, 1);
811                 }
812         }
813         snd_soc_resume(drv->soc_card->dev);
814 }
815 
816 #else
817 
818 #define sst_soc_prepare NULL
819 #define sst_soc_complete NULL
820 
821 #endif
822 
823 
824 static const struct dev_pm_ops sst_platform_pm = {
825         .prepare        = sst_soc_prepare,
826         .complete       = sst_soc_complete,
827 };
828 
829 static struct platform_driver sst_platform_driver = {
830         .driver         = {
831                 .name           = "sst-mfld-platform",
832                 .pm             = &sst_platform_pm,
833         },
834         .probe          = sst_platform_probe,
835         .remove         = sst_platform_remove,
836 };
837 
838 module_platform_driver(sst_platform_driver);
839 
840 MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
841 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
842 MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
843 MODULE_LICENSE("GPL v2");
844 MODULE_ALIAS("platform:sst-mfld-platform");
845 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp