c2bf172a196e08efd8e684af0e9f1d576d541e36
[firefly-linux-kernel-4.4.55.git] / sound / soc / mid-x86 / sst_platform.c
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 <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 "sst_platform.h"
36
37 static struct sst_device *sst;
38 static DEFINE_MUTEX(sst_lock);
39
40 int sst_register_dsp(struct sst_device *dev)
41 {
42         BUG_ON(!dev);
43         if (!try_module_get(dev->dev->driver->owner))
44                 return -ENODEV;
45         mutex_lock(&sst_lock);
46         if (sst) {
47                 pr_err("we already have a device %s\n", sst->name);
48                 module_put(dev->dev->driver->owner);
49                 mutex_unlock(&sst_lock);
50                 return -EEXIST;
51         }
52         pr_debug("registering device %s\n", dev->name);
53         sst = dev;
54         mutex_unlock(&sst_lock);
55         return 0;
56 }
57 EXPORT_SYMBOL_GPL(sst_register_dsp);
58
59 int sst_unregister_dsp(struct sst_device *dev)
60 {
61         BUG_ON(!dev);
62         if (dev != sst)
63                 return -EINVAL;
64
65         mutex_lock(&sst_lock);
66
67         if (!sst) {
68                 mutex_unlock(&sst_lock);
69                 return -EIO;
70         }
71
72         module_put(sst->dev->driver->owner);
73         pr_debug("unreg %s\n", sst->name);
74         sst = NULL;
75         mutex_unlock(&sst_lock);
76         return 0;
77 }
78 EXPORT_SYMBOL_GPL(sst_unregister_dsp);
79
80 static struct snd_pcm_hardware sst_platform_pcm_hw = {
81         .info = (SNDRV_PCM_INFO_INTERLEAVED |
82                         SNDRV_PCM_INFO_DOUBLE |
83                         SNDRV_PCM_INFO_PAUSE |
84                         SNDRV_PCM_INFO_RESUME |
85                         SNDRV_PCM_INFO_MMAP|
86                         SNDRV_PCM_INFO_MMAP_VALID |
87                         SNDRV_PCM_INFO_BLOCK_TRANSFER |
88                         SNDRV_PCM_INFO_SYNC_START),
89         .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |
90                         SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |
91                         SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32),
92         .rates = (SNDRV_PCM_RATE_8000|
93                         SNDRV_PCM_RATE_44100 |
94                         SNDRV_PCM_RATE_48000),
95         .rate_min = SST_MIN_RATE,
96         .rate_max = SST_MAX_RATE,
97         .channels_min = SST_MIN_CHANNEL,
98         .channels_max = SST_MAX_CHANNEL,
99         .buffer_bytes_max = SST_MAX_BUFFER,
100         .period_bytes_min = SST_MIN_PERIOD_BYTES,
101         .period_bytes_max = SST_MAX_PERIOD_BYTES,
102         .periods_min = SST_MIN_PERIODS,
103         .periods_max = SST_MAX_PERIODS,
104         .fifo_size = SST_FIFO_SIZE,
105 };
106
107 /* MFLD - MSIC */
108 static struct snd_soc_dai_driver sst_platform_dai[] = {
109 {
110         .name = "Headset-cpu-dai",
111         .id = 0,
112         .playback = {
113                 .channels_min = SST_STEREO,
114                 .channels_max = SST_STEREO,
115                 .rates = SNDRV_PCM_RATE_48000,
116                 .formats = SNDRV_PCM_FMTBIT_S24_LE,
117         },
118         .capture = {
119                 .channels_min = 1,
120                 .channels_max = 5,
121                 .rates = SNDRV_PCM_RATE_48000,
122                 .formats = SNDRV_PCM_FMTBIT_S24_LE,
123         },
124 },
125 {
126         .name = "Speaker-cpu-dai",
127         .id = 1,
128         .playback = {
129                 .channels_min = SST_MONO,
130                 .channels_max = SST_STEREO,
131                 .rates = SNDRV_PCM_RATE_48000,
132                 .formats = SNDRV_PCM_FMTBIT_S24_LE,
133         },
134 },
135 {
136         .name = "Vibra1-cpu-dai",
137         .id = 2,
138         .playback = {
139                 .channels_min = SST_MONO,
140                 .channels_max = SST_MONO,
141                 .rates = SNDRV_PCM_RATE_48000,
142                 .formats = SNDRV_PCM_FMTBIT_S24_LE,
143         },
144 },
145 {
146         .name = "Vibra2-cpu-dai",
147         .id = 3,
148         .playback = {
149                 .channels_min = SST_MONO,
150                 .channels_max = SST_STEREO,
151                 .rates = SNDRV_PCM_RATE_48000,
152                 .formats = SNDRV_PCM_FMTBIT_S24_LE,
153         },
154 },
155 };
156
157 /* helper functions */
158 static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
159                                         int state)
160 {
161         unsigned long flags;
162         spin_lock_irqsave(&stream->status_lock, flags);
163         stream->stream_status = state;
164         spin_unlock_irqrestore(&stream->status_lock, flags);
165 }
166
167 static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
168 {
169         int state;
170         unsigned long flags;
171
172         spin_lock_irqsave(&stream->status_lock, flags);
173         state = stream->stream_status;
174         spin_unlock_irqrestore(&stream->status_lock, flags);
175         return state;
176 }
177
178 static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
179                                 struct sst_pcm_params *param)
180 {
181
182         param->codec = SST_CODEC_TYPE_PCM;
183         param->num_chan = (u8) substream->runtime->channels;
184         param->pcm_wd_sz = substream->runtime->sample_bits;
185         param->reserved = 0;
186         param->sfreq = substream->runtime->rate;
187         param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream);
188         param->period_count = substream->runtime->period_size;
189         param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area);
190         pr_debug("period_cnt = %d\n", param->period_count);
191         pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz);
192 }
193
194 static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
195 {
196         struct sst_runtime_stream *stream =
197                         substream->runtime->private_data;
198         struct sst_pcm_params param = {0};
199         struct sst_stream_params str_params = {0};
200         int ret_val;
201
202         /* set codec params and inform SST driver the same */
203         sst_fill_pcm_params(substream, &param);
204         substream->runtime->dma_area = substream->dma_buffer.area;
205         str_params.sparams = param;
206         str_params.codec =  param.codec;
207         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
208                 str_params.ops = STREAM_OPS_PLAYBACK;
209                 str_params.device_type = substream->pcm->device + 1;
210                 pr_debug("Playbck stream,Device %d\n",
211                                         substream->pcm->device);
212         } else {
213                 str_params.ops = STREAM_OPS_CAPTURE;
214                 str_params.device_type = SND_SST_DEVICE_CAPTURE;
215                 pr_debug("Capture stream,Device %d\n",
216                                         substream->pcm->device);
217         }
218         ret_val = stream->ops->open(&str_params);
219         pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
220         if (ret_val < 0)
221                 return ret_val;
222
223         stream->stream_info.str_id = ret_val;
224         pr_debug("str id :  %d\n", stream->stream_info.str_id);
225         return ret_val;
226 }
227
228 static void sst_period_elapsed(void *mad_substream)
229 {
230         struct snd_pcm_substream *substream = mad_substream;
231         struct sst_runtime_stream *stream;
232         int status;
233
234         if (!substream || !substream->runtime)
235                 return;
236         stream = substream->runtime->private_data;
237         if (!stream)
238                 return;
239         status = sst_get_stream_status(stream);
240         if (status != SST_PLATFORM_RUNNING)
241                 return;
242         snd_pcm_period_elapsed(substream);
243 }
244
245 static int sst_platform_init_stream(struct snd_pcm_substream *substream)
246 {
247         struct sst_runtime_stream *stream =
248                         substream->runtime->private_data;
249         int ret_val;
250
251         pr_debug("setting buffer ptr param\n");
252         sst_set_stream_status(stream, SST_PLATFORM_INIT);
253         stream->stream_info.period_elapsed = sst_period_elapsed;
254         stream->stream_info.mad_substream = substream;
255         stream->stream_info.buffer_ptr = 0;
256         stream->stream_info.sfreq = substream->runtime->rate;
257         ret_val = stream->ops->device_control(
258                         SST_SND_STREAM_INIT, &stream->stream_info);
259         if (ret_val)
260                 pr_err("control_set ret error %d\n", ret_val);
261         return ret_val;
262
263 }
264 /* end -- helper functions */
265
266 static int sst_platform_open(struct snd_pcm_substream *substream)
267 {
268         struct snd_pcm_runtime *runtime = substream->runtime;
269         struct sst_runtime_stream *stream;
270         int ret_val;
271
272         pr_debug("sst_platform_open called\n");
273
274         snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw);
275         ret_val = snd_pcm_hw_constraint_integer(runtime,
276                                                 SNDRV_PCM_HW_PARAM_PERIODS);
277         if (ret_val < 0)
278                 return ret_val;
279
280         stream = kzalloc(sizeof(*stream), GFP_KERNEL);
281         if (!stream)
282                 return -ENOMEM;
283         spin_lock_init(&stream->status_lock);
284
285         /* get the sst ops */
286         mutex_lock(&sst_lock);
287         if (!sst) {
288                 pr_err("no device available to run\n");
289                 mutex_unlock(&sst_lock);
290                 kfree(stream);
291                 return -ENODEV;
292         }
293         if (!try_module_get(sst->dev->driver->owner)) {
294                 mutex_unlock(&sst_lock);
295                 kfree(stream);
296                 return -ENODEV;
297         }
298         stream->ops = sst->ops;
299         mutex_unlock(&sst_lock);
300
301         stream->stream_info.str_id = 0;
302         sst_set_stream_status(stream, SST_PLATFORM_INIT);
303         stream->stream_info.mad_substream = substream;
304         /* allocate memory for SST API set */
305         runtime->private_data = stream;
306
307         return 0;
308 }
309
310 static int sst_platform_close(struct snd_pcm_substream *substream)
311 {
312         struct sst_runtime_stream *stream;
313         int ret_val = 0, str_id;
314
315         pr_debug("sst_platform_close called\n");
316         stream = substream->runtime->private_data;
317         str_id = stream->stream_info.str_id;
318         if (str_id)
319                 ret_val = stream->ops->close(str_id);
320         module_put(sst->dev->driver->owner);
321         kfree(stream);
322         return ret_val;
323 }
324
325 static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
326 {
327         struct sst_runtime_stream *stream;
328         int ret_val = 0, str_id;
329
330         pr_debug("sst_platform_pcm_prepare called\n");
331         stream = substream->runtime->private_data;
332         str_id = stream->stream_info.str_id;
333         if (stream->stream_info.str_id) {
334                 ret_val = stream->ops->device_control(
335                                 SST_SND_DROP, &str_id);
336                 return ret_val;
337         }
338
339         ret_val = sst_platform_alloc_stream(substream);
340         if (ret_val < 0)
341                 return ret_val;
342         snprintf(substream->pcm->id, sizeof(substream->pcm->id),
343                         "%d", stream->stream_info.str_id);
344
345         ret_val = sst_platform_init_stream(substream);
346         if (ret_val)
347                 return ret_val;
348         substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
349         return ret_val;
350 }
351
352 static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
353                                         int cmd)
354 {
355         int ret_val = 0, str_id;
356         struct sst_runtime_stream *stream;
357         int str_cmd, status;
358
359         pr_debug("sst_platform_pcm_trigger called\n");
360         stream = substream->runtime->private_data;
361         str_id = stream->stream_info.str_id;
362         switch (cmd) {
363         case SNDRV_PCM_TRIGGER_START:
364                 pr_debug("sst: Trigger Start\n");
365                 str_cmd = SST_SND_START;
366                 status = SST_PLATFORM_RUNNING;
367                 stream->stream_info.mad_substream = substream;
368                 break;
369         case SNDRV_PCM_TRIGGER_STOP:
370                 pr_debug("sst: in stop\n");
371                 str_cmd = SST_SND_DROP;
372                 status = SST_PLATFORM_DROPPED;
373                 break;
374         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
375                 pr_debug("sst: in pause\n");
376                 str_cmd = SST_SND_PAUSE;
377                 status = SST_PLATFORM_PAUSED;
378                 break;
379         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
380                 pr_debug("sst: in pause release\n");
381                 str_cmd = SST_SND_RESUME;
382                 status = SST_PLATFORM_RUNNING;
383                 break;
384         default:
385                 return -EINVAL;
386         }
387         ret_val = stream->ops->device_control(str_cmd, &str_id);
388         if (!ret_val)
389                 sst_set_stream_status(stream, status);
390
391         return ret_val;
392 }
393
394
395 static snd_pcm_uframes_t sst_platform_pcm_pointer
396                         (struct snd_pcm_substream *substream)
397 {
398         struct sst_runtime_stream *stream;
399         int ret_val, status;
400         struct pcm_stream_info *str_info;
401
402         stream = substream->runtime->private_data;
403         status = sst_get_stream_status(stream);
404         if (status == SST_PLATFORM_INIT)
405                 return 0;
406         str_info = &stream->stream_info;
407         ret_val = stream->ops->device_control(
408                                 SST_SND_BUFFER_POINTER, str_info);
409         if (ret_val) {
410                 pr_err("sst: error code = %d\n", ret_val);
411                 return ret_val;
412         }
413         return stream->stream_info.buffer_ptr;
414 }
415
416 static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
417                 struct snd_pcm_hw_params *params)
418 {
419         snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
420         memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
421
422         return 0;
423 }
424
425 static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
426 {
427         return snd_pcm_lib_free_pages(substream);
428 }
429
430 static struct snd_pcm_ops sst_platform_ops = {
431         .open = sst_platform_open,
432         .close = sst_platform_close,
433         .ioctl = snd_pcm_lib_ioctl,
434         .prepare = sst_platform_pcm_prepare,
435         .trigger = sst_platform_pcm_trigger,
436         .pointer = sst_platform_pcm_pointer,
437         .hw_params = sst_platform_pcm_hw_params,
438         .hw_free = sst_platform_pcm_hw_free,
439 };
440
441 static void sst_pcm_free(struct snd_pcm *pcm)
442 {
443         pr_debug("sst_pcm_free called\n");
444         snd_pcm_lib_preallocate_free_for_all(pcm);
445 }
446
447 static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
448 {
449         struct snd_soc_dai *dai = rtd->cpu_dai;
450         struct snd_pcm *pcm = rtd->pcm;
451         int retval = 0;
452
453         pr_debug("sst_pcm_new called\n");
454         if (dai->driver->playback.channels_min ||
455                         dai->driver->capture.channels_min) {
456                 retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
457                         SNDRV_DMA_TYPE_CONTINUOUS,
458                         snd_dma_continuous_data(GFP_KERNEL),
459                         SST_MIN_BUFFER, SST_MAX_BUFFER);
460                 if (retval) {
461                         pr_err("dma buffer allocationf fail\n");
462                         return retval;
463                 }
464         }
465         return retval;
466 }
467 static struct snd_soc_platform_driver sst_soc_platform_drv = {
468         .ops            = &sst_platform_ops,
469         .pcm_new        = sst_pcm_new,
470         .pcm_free       = sst_pcm_free,
471 };
472
473 static int sst_platform_probe(struct platform_device *pdev)
474 {
475         int ret;
476
477         pr_debug("sst_platform_probe called\n");
478         sst = NULL;
479         ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
480         if (ret) {
481                 pr_err("registering soc platform failed\n");
482                 return ret;
483         }
484
485         ret = snd_soc_register_dais(&pdev->dev,
486                                 sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
487         if (ret) {
488                 pr_err("registering cpu dais failed\n");
489                 snd_soc_unregister_platform(&pdev->dev);
490         }
491         return ret;
492 }
493
494 static int sst_platform_remove(struct platform_device *pdev)
495 {
496
497         snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai));
498         snd_soc_unregister_platform(&pdev->dev);
499         pr_debug("sst_platform_remove success\n");
500         return 0;
501 }
502
503 static struct platform_driver sst_platform_driver = {
504         .driver         = {
505                 .name           = "sst-platform",
506                 .owner          = THIS_MODULE,
507         },
508         .probe          = sst_platform_probe,
509         .remove         = sst_platform_remove,
510 };
511
512 module_platform_driver(sst_platform_driver);
513
514 MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
515 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
516 MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
517 MODULE_LICENSE("GPL v2");
518 MODULE_ALIAS("platform:sst-platform");