Merge remote-tracking branches 'asoc/fix/rcar', 'asoc/fix/rt5670' and 'asoc/fix/wm894...
[cascardo/linux.git] / 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                 break;
186         case SNDRV_PCM_TRIGGER_STOP:
187                 if (stream->compr_ops->stream_drop)
188                         return stream->compr_ops->stream_drop(sst->dev, stream->id);
189                 break;
190         case SND_COMPR_TRIGGER_DRAIN:
191                 if (stream->compr_ops->stream_drain)
192                         return stream->compr_ops->stream_drain(sst->dev, stream->id);
193                 break;
194         case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
195                 if (stream->compr_ops->stream_partial_drain)
196                         return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
197                 break;
198         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
199                 if (stream->compr_ops->stream_pause)
200                         return stream->compr_ops->stream_pause(sst->dev, stream->id);
201                 break;
202         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
203                 if (stream->compr_ops->stream_pause_release)
204                         return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
205                 break;
206         }
207         return -EINVAL;
208 }
209
210 static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
211                                         struct snd_compr_tstamp *tstamp)
212 {
213         struct sst_runtime_stream *stream;
214
215         stream  = cstream->runtime->private_data;
216         stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
217         tstamp->byte_offset = tstamp->copied_total %
218                                  (u32)cstream->runtime->buffer_size;
219         pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
220         return 0;
221 }
222
223 static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
224                                         size_t bytes)
225 {
226         struct sst_runtime_stream *stream;
227
228         stream  = cstream->runtime->private_data;
229         stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
230         stream->bytes_written += bytes;
231
232         return 0;
233 }
234
235 static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
236                                         struct snd_compr_caps *caps)
237 {
238         struct sst_runtime_stream *stream =
239                 cstream->runtime->private_data;
240
241         return stream->compr_ops->get_caps(caps);
242 }
243
244 static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
245                                         struct snd_compr_codec_caps *codec)
246 {
247         struct sst_runtime_stream *stream =
248                 cstream->runtime->private_data;
249
250         return stream->compr_ops->get_codec_caps(codec);
251 }
252
253 static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
254                                         struct snd_compr_metadata *metadata)
255 {
256         struct sst_runtime_stream *stream  =
257                  cstream->runtime->private_data;
258
259         return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
260 }
261
262 struct snd_compr_ops sst_platform_compr_ops = {
263
264         .open = sst_platform_compr_open,
265         .free = sst_platform_compr_free,
266         .set_params = sst_platform_compr_set_params,
267         .set_metadata = sst_platform_compr_set_metadata,
268         .trigger = sst_platform_compr_trigger,
269         .pointer = sst_platform_compr_pointer,
270         .ack = sst_platform_compr_ack,
271         .get_caps = sst_platform_compr_get_caps,
272         .get_codec_caps = sst_platform_compr_get_codec_caps,
273 };