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

TOMOYO Linux Cross Reference
Linux/sound/soc/intel/sst-baytrail-pcm.c

Version: ~ [ linux-5.9-rc6 ] ~ [ linux-5.8.10 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.66 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.146 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.198 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.236 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.236 ] ~ [ 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.85 ] ~ [ 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-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  * Intel Baytrail SST PCM Support
  3  * Copyright (c) 2014, Intel Corporation.
  4  *
  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.
  8  *
  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
 12  * more details.
 13  */
 14 
 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"
 24 #include "sst-dsp.h"
 25 
 26 #define BYT_PCM_COUNT           2
 27 
 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_FORMAT_S24_LE,
 36         .period_bytes_min       = 384,
 37         .period_bytes_max       = 48000,
 38         .periods_min            = 2,
 39         .periods_max            = 250,
 40         .buffer_bytes_max       = 96000,
 41 };
 42 
 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;
 47         struct mutex mutex;
 48 };
 49 
 50 /* private data for the driver */
 51 struct sst_byt_priv_data {
 52         /* runtime DSP */
 53         struct sst_byt *byt;
 54 
 55         /* DAI data */
 56         struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
 57 };
 58 
 59 /* this may get called several times by oss emulation */
 60 static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
 61                                  struct snd_pcm_hw_params *params)
 62 {
 63         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 64         struct sst_byt_priv_data *pdata =
 65                 snd_soc_platform_get_drvdata(rtd->platform);
 66         struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
 67         struct sst_byt *byt = pdata->byt;
 68         u32 rate, bits;
 69         u8 channels;
 70         int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 71 
 72         dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);
 73 
 74         ret = sst_byt_stream_type(byt, pcm_data->stream,
 75                                   1, 1, !playback);
 76         if (ret < 0) {
 77                 dev_err(rtd->dev, "failed to set stream format %d\n", ret);
 78                 return ret;
 79         }
 80 
 81         rate = params_rate(params);
 82         ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
 83         if (ret < 0) {
 84                 dev_err(rtd->dev, "could not set rate %d\n", rate);
 85                 return ret;
 86         }
 87 
 88         bits = snd_pcm_format_width(params_format(params));
 89         ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
 90         if (ret < 0) {
 91                 dev_err(rtd->dev, "could not set formats %d\n",
 92                         params_rate(params));
 93                 return ret;
 94         }
 95 
 96         channels = (u8)(params_channels(params) & 0xF);
 97         ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
 98         if (ret < 0) {
 99                 dev_err(rtd->dev, "could not set channels %d\n",
100                         params_rate(params));
101                 return ret;
102         }
103 
104         snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
105 
106         ret = sst_byt_stream_buffer(byt, pcm_data->stream,
107                                     substream->dma_buffer.addr,
108                                     params_buffer_bytes(params));
109         if (ret < 0) {
110                 dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
111                 return ret;
112         }
113 
114         ret = sst_byt_stream_commit(byt, pcm_data->stream);
115         if (ret < 0) {
116                 dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
117                 return ret;
118         }
119 
120         return 0;
121 }
122 
123 static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
124 {
125         struct snd_soc_pcm_runtime *rtd = substream->private_data;
126 
127         dev_dbg(rtd->dev, "PCM: hw_free\n");
128         snd_pcm_lib_free_pages(substream);
129 
130         return 0;
131 }
132 
133 static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
134 {
135         struct snd_soc_pcm_runtime *rtd = substream->private_data;
136         struct sst_byt_priv_data *pdata =
137                 snd_soc_platform_get_drvdata(rtd->platform);
138         struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
139         struct sst_byt *byt = pdata->byt;
140 
141         dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
142 
143         switch (cmd) {
144         case SNDRV_PCM_TRIGGER_START:
145                 sst_byt_stream_start(byt, pcm_data->stream);
146                 break;
147         case SNDRV_PCM_TRIGGER_RESUME:
148         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
149                 sst_byt_stream_resume(byt, pcm_data->stream);
150                 break;
151         case SNDRV_PCM_TRIGGER_STOP:
152                 sst_byt_stream_stop(byt, pcm_data->stream);
153                 break;
154         case SNDRV_PCM_TRIGGER_SUSPEND:
155         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
156                 sst_byt_stream_pause(byt, pcm_data->stream);
157                 break;
158         default:
159                 break;
160         }
161 
162         return 0;
163 }
164 
165 static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
166 {
167         struct sst_byt_pcm_data *pcm_data = data;
168         struct snd_pcm_substream *substream = pcm_data->substream;
169         struct snd_pcm_runtime *runtime = substream->runtime;
170         struct snd_soc_pcm_runtime *rtd = substream->private_data;
171         u32 pos;
172 
173         pos = frames_to_bytes(runtime,
174                               (runtime->control->appl_ptr %
175                                runtime->buffer_size));
176 
177         dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
178 
179         snd_pcm_period_elapsed(substream);
180         return pos;
181 }
182 
183 static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
184 {
185         struct snd_soc_pcm_runtime *rtd = substream->private_data;
186         struct snd_pcm_runtime *runtime = substream->runtime;
187         struct sst_byt_priv_data *pdata =
188                 snd_soc_platform_get_drvdata(rtd->platform);
189         struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
190         struct sst_byt *byt = pdata->byt;
191         snd_pcm_uframes_t offset;
192         int pos;
193 
194         pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
195                                        snd_pcm_lib_buffer_bytes(substream));
196         offset = bytes_to_frames(runtime, pos);
197 
198         dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
199                 frames_to_bytes(runtime, (u32)offset));
200         return offset;
201 }
202 
203 static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
204 {
205         struct snd_soc_pcm_runtime *rtd = substream->private_data;
206         struct sst_byt_priv_data *pdata =
207                 snd_soc_platform_get_drvdata(rtd->platform);
208         struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
209         struct sst_byt *byt = pdata->byt;
210 
211         dev_dbg(rtd->dev, "PCM: open\n");
212 
213         pcm_data = &pdata->pcm[rtd->cpu_dai->id];
214         mutex_lock(&pcm_data->mutex);
215 
216         snd_soc_pcm_set_drvdata(rtd, pcm_data);
217         pcm_data->substream = substream;
218 
219         snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
220 
221         pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1,
222                                               byt_notify_pointer, pcm_data);
223         if (pcm_data->stream == NULL) {
224                 dev_err(rtd->dev, "failed to create stream\n");
225                 mutex_unlock(&pcm_data->mutex);
226                 return -EINVAL;
227         }
228 
229         mutex_unlock(&pcm_data->mutex);
230         return 0;
231 }
232 
233 static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
234 {
235         struct snd_soc_pcm_runtime *rtd = substream->private_data;
236         struct sst_byt_priv_data *pdata =
237                 snd_soc_platform_get_drvdata(rtd->platform);
238         struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
239         struct sst_byt *byt = pdata->byt;
240         int ret;
241 
242         dev_dbg(rtd->dev, "PCM: close\n");
243 
244         mutex_lock(&pcm_data->mutex);
245         ret = sst_byt_stream_free(byt, pcm_data->stream);
246         if (ret < 0) {
247                 dev_dbg(rtd->dev, "Free stream fail\n");
248                 goto out;
249         }
250         pcm_data->stream = NULL;
251 
252 out:
253         mutex_unlock(&pcm_data->mutex);
254         return ret;
255 }
256 
257 static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
258                             struct vm_area_struct *vma)
259 {
260         struct snd_soc_pcm_runtime *rtd = substream->private_data;
261 
262         dev_dbg(rtd->dev, "PCM: mmap\n");
263         return snd_pcm_lib_default_mmap(substream, vma);
264 }
265 
266 static struct snd_pcm_ops sst_byt_pcm_ops = {
267         .open           = sst_byt_pcm_open,
268         .close          = sst_byt_pcm_close,
269         .ioctl          = snd_pcm_lib_ioctl,
270         .hw_params      = sst_byt_pcm_hw_params,
271         .hw_free        = sst_byt_pcm_hw_free,
272         .trigger        = sst_byt_pcm_trigger,
273         .pointer        = sst_byt_pcm_pointer,
274         .mmap           = sst_byt_pcm_mmap,
275 };
276 
277 static void sst_byt_pcm_free(struct snd_pcm *pcm)
278 {
279         snd_pcm_lib_preallocate_free_for_all(pcm);
280 }
281 
282 static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
283 {
284         struct snd_pcm *pcm = rtd->pcm;
285         size_t size;
286         int ret = 0;
287 
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 ||
293             pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
294                 size = sst_byt_pcm_hardware.buffer_bytes_max;
295                 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
296                                                             SNDRV_DMA_TYPE_DEV,
297                                                             rtd->card->dev,
298                                                             size, size);
299                 if (ret) {
300                         dev_err(rtd->dev, "dma buffer allocation failed %d\n",
301                                 ret);
302                         return ret;
303                 }
304         }
305 
306         return ret;
307 }
308 
309 static struct snd_soc_dai_driver byt_dais[] = {
310         {
311                 .name  = "Front-cpu-dai",
312                 .playback = {
313                         .stream_name = "System Playback",
314                         .channels_min = 2,
315                         .channels_max = 2,
316                         .rates = SNDRV_PCM_RATE_48000,
317                         .formats = SNDRV_PCM_FMTBIT_S24_3LE |
318                                    SNDRV_PCM_FMTBIT_S16_LE,
319                 },
320         },
321         {
322                 .name  = "Mic1-cpu-dai",
323                 .capture = {
324                         .stream_name = "Analog Capture",
325                         .channels_min = 2,
326                         .channels_max = 2,
327                         .rates = SNDRV_PCM_RATE_48000,
328                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
329                 },
330         },
331 };
332 
333 static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
334 {
335         struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
336         struct sst_byt_priv_data *priv_data;
337         int i;
338 
339         if (!plat_data)
340                 return -ENODEV;
341 
342         priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
343                                  GFP_KERNEL);
344         priv_data->byt = plat_data->dsp;
345         snd_soc_platform_set_drvdata(platform, priv_data);
346 
347         for (i = 0; i < ARRAY_SIZE(byt_dais); i++)
348                 mutex_init(&priv_data->pcm[i].mutex);
349 
350         return 0;
351 }
352 
353 static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
354 {
355         return 0;
356 }
357 
358 static struct snd_soc_platform_driver byt_soc_platform = {
359         .probe          = sst_byt_pcm_probe,
360         .remove         = sst_byt_pcm_remove,
361         .ops            = &sst_byt_pcm_ops,
362         .pcm_new        = sst_byt_pcm_new,
363         .pcm_free       = sst_byt_pcm_free,
364 };
365 
366 static const struct snd_soc_component_driver byt_dai_component = {
367         .name           = "byt-dai",
368 };
369 
370 static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
371 {
372         struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
373         int ret;
374 
375         ret = sst_byt_dsp_init(&pdev->dev, sst_pdata);
376         if (ret < 0)
377                 return -ENODEV;
378 
379         ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
380         if (ret < 0)
381                 goto err_plat;
382 
383         ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
384                                          byt_dais, ARRAY_SIZE(byt_dais));
385         if (ret < 0)
386                 goto err_comp;
387 
388         return 0;
389 
390 err_comp:
391         snd_soc_unregister_platform(&pdev->dev);
392 err_plat:
393         sst_byt_dsp_free(&pdev->dev, sst_pdata);
394         return ret;
395 }
396 
397 static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
398 {
399         struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
400 
401         snd_soc_unregister_platform(&pdev->dev);
402         snd_soc_unregister_component(&pdev->dev);
403         sst_byt_dsp_free(&pdev->dev, sst_pdata);
404 
405         return 0;
406 }
407 
408 static struct platform_driver sst_byt_pcm_driver = {
409         .driver = {
410                 .name = "baytrail-pcm-audio",
411                 .owner = THIS_MODULE,
412         },
413 
414         .probe = sst_byt_pcm_dev_probe,
415         .remove = sst_byt_pcm_dev_remove,
416 };
417 module_platform_driver(sst_byt_pcm_driver);
418 
419 MODULE_AUTHOR("Jarkko Nikula");
420 MODULE_DESCRIPTION("Baytrail PCM");
421 MODULE_LICENSE("GPL v2");
422 MODULE_ALIAS("platform:baytrail-pcm-audio");
423 

~ [ 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