Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / sound / soc / intel / atom / sst-mfld-platform-compress.c
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  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; version 2 of the License.
11  *
12  *  This program is distributed in the hope that it will be useful, but
13  *  WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  General Public License for more details.
16  *
17  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18  */
19 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21 #include <linux/slab.h>
22 #include <linux/io.h>
23 #include <linux/module.h>
24 #include <sound/core.h>
25 #include <sound/pcm.h>
26 #include <sound/pcm_params.h>
27 #include <sound/soc.h>
28 #include <sound/compress_driver.h>
29 #include "sst-mfld-platform.h"
30
31 /* compress stream operations */
32 static void sst_compr_fragment_elapsed(void *arg)
33 {
34         struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
35
36         pr_debug("fragment elapsed by driver\n");
37         if (cstream)
38                 snd_compr_fragment_elapsed(cstream);
39 }
40
41 static void sst_drain_notify(void *arg)
42 {
43         struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
44
45         pr_debug("drain notify by driver\n");
46         if (cstream)
47                 snd_compr_drain_notify(cstream);
48 }
49
50 static int sst_platform_compr_open(struct snd_compr_stream *cstream)
51 {
52
53         int ret_val = 0;
54         struct snd_compr_runtime *runtime = cstream->runtime;
55         struct sst_runtime_stream *stream;
56
57         stream = kzalloc(sizeof(*stream), GFP_KERNEL);
58         if (!stream)
59                 return -ENOMEM;
60
61         spin_lock_init(&stream->status_lock);
62
63         /* get the sst ops */
64         if (!sst || !try_module_get(sst->dev->driver->owner)) {
65                 pr_err("no device available to run\n");
66                 ret_val = -ENODEV;
67                 goto out_ops;
68         }
69         stream->compr_ops = sst->compr_ops;
70         stream->id = 0;
71
72         /* Turn on LPE */
73         sst->compr_ops->power(sst->dev, true);
74
75         sst_set_stream_status(stream, SST_PLATFORM_INIT);
76         runtime->private_data = stream;
77         return 0;
78 out_ops:
79         kfree(stream);
80         return ret_val;
81 }
82
83 static int sst_platform_compr_free(struct snd_compr_stream *cstream)
84 {
85         struct sst_runtime_stream *stream;
86         int ret_val = 0, str_id;
87
88         stream = cstream->runtime->private_data;
89         /* Turn off LPE */
90         sst->compr_ops->power(sst->dev, false);
91
92         /*need to check*/
93         str_id = stream->id;
94         if (str_id)
95                 ret_val = stream->compr_ops->close(sst->dev, str_id);
96         module_put(sst->dev->driver->owner);
97         kfree(stream);
98         pr_debug("%s: %d\n", __func__, ret_val);
99         return 0;
100 }
101
102 static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
103                                         struct snd_compr_params *params)
104 {
105         struct sst_runtime_stream *stream;
106         int retval;
107         struct snd_sst_params str_params;
108         struct sst_compress_cb cb;
109         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
110         struct snd_soc_platform *platform = rtd->platform;
111         struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
112
113         stream = cstream->runtime->private_data;
114         /* construct fw structure for this*/
115         memset(&str_params, 0, sizeof(str_params));
116
117         /* fill the device type and stream id to pass to SST driver */
118         retval = sst_fill_stream_params(cstream, ctx, &str_params, true);
119         pr_debug("compr_set_params: fill stream params ret_val = 0x%x\n", retval);
120         if (retval < 0)
121                 return retval;
122
123         switch (params->codec.id) {
124         case SND_AUDIOCODEC_MP3: {
125                 str_params.codec = SST_CODEC_TYPE_MP3;
126                 str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
127                 str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
128                 break;
129         }
130
131         case SND_AUDIOCODEC_AAC: {
132                 str_params.codec = SST_CODEC_TYPE_AAC;
133                 str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
134                 str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
135                 if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
136                         str_params.sparams.uc.aac_params.bs_format =
137                                                         AAC_BIT_STREAM_ADTS;
138                 else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
139                         str_params.sparams.uc.aac_params.bs_format =
140                                                         AAC_BIT_STREAM_RAW;
141                 else {
142                         pr_err("Undefined format%d\n", params->codec.format);
143                         return -EINVAL;
144                 }
145                 str_params.sparams.uc.aac_params.externalsr =
146                                                 params->codec.sample_rate;
147                 break;
148         }
149
150         default:
151                 pr_err("codec not supported, id =%d\n", params->codec.id);
152                 return -EINVAL;
153         }
154
155         str_params.aparams.ring_buf_info[0].addr  =
156                                         virt_to_phys(cstream->runtime->buffer);
157         str_params.aparams.ring_buf_info[0].size =
158                                         cstream->runtime->buffer_size;
159         str_params.aparams.sg_count = 1;
160         str_params.aparams.frag_size = cstream->runtime->fragment_size;
161
162         cb.param = cstream;
163         cb.compr_cb = sst_compr_fragment_elapsed;
164         cb.drain_cb_param = cstream;
165         cb.drain_notify = sst_drain_notify;
166
167         retval = stream->compr_ops->open(sst->dev, &str_params, &cb);
168         if (retval < 0) {
169                 pr_err("stream allocation failed %d\n", retval);
170                 return retval;
171         }
172
173         stream->id = retval;
174         return 0;
175 }
176
177 static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
178 {
179         struct sst_runtime_stream *stream = cstream->runtime->private_data;
180
181         switch (cmd) {
182         case SNDRV_PCM_TRIGGER_START:
183                 if (stream->compr_ops->stream_start)
184                         return stream->compr_ops->stream_start(sst->dev, stream->id);
185         case SNDRV_PCM_TRIGGER_STOP:
186                 if (stream->compr_ops->stream_drop)
187                         return stream->compr_ops->stream_drop(sst->dev, stream->id);
188         case SND_COMPR_TRIGGER_DRAIN:
189                 if (stream->compr_ops->stream_drain)
190                         return stream->compr_ops->stream_drain(sst->dev, stream->id);
191         case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
192                 if (stream->compr_ops->stream_partial_drain)
193                         return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
194         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
195                 if (stream->compr_ops->stream_pause)
196                         return stream->compr_ops->stream_pause(sst->dev, stream->id);
197         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
198                 if (stream->compr_ops->stream_pause_release)
199                         return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
200         default:
201                 return -EINVAL;
202         }
203 }
204
205 static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
206                                         struct snd_compr_tstamp *tstamp)
207 {
208         struct sst_runtime_stream *stream;
209
210         stream  = cstream->runtime->private_data;
211         stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
212         tstamp->byte_offset = tstamp->copied_total %
213                                  (u32)cstream->runtime->buffer_size;
214         pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
215         return 0;
216 }
217
218 static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
219                                         size_t bytes)
220 {
221         struct sst_runtime_stream *stream;
222
223         stream  = cstream->runtime->private_data;
224         stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
225         stream->bytes_written += bytes;
226
227         return 0;
228 }
229
230 static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
231                                         struct snd_compr_caps *caps)
232 {
233         struct sst_runtime_stream *stream =
234                 cstream->runtime->private_data;
235
236         return stream->compr_ops->get_caps(caps);
237 }
238
239 static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
240                                         struct snd_compr_codec_caps *codec)
241 {
242         struct sst_runtime_stream *stream =
243                 cstream->runtime->private_data;
244
245         return stream->compr_ops->get_codec_caps(codec);
246 }
247
248 static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
249                                         struct snd_compr_metadata *metadata)
250 {
251         struct sst_runtime_stream *stream  =
252                  cstream->runtime->private_data;
253
254         return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
255 }
256
257 struct snd_compr_ops sst_platform_compr_ops = {
258
259         .open = sst_platform_compr_open,
260         .free = sst_platform_compr_free,
261         .set_params = sst_platform_compr_set_params,
262         .set_metadata = sst_platform_compr_set_metadata,
263         .trigger = sst_platform_compr_trigger,
264         .pointer = sst_platform_compr_pointer,
265         .ack = sst_platform_compr_ack,
266         .get_caps = sst_platform_compr_get_caps,
267         .get_codec_caps = sst_platform_compr_get_codec_caps,
268 };