blob: 0f707b531673cfa2ea92568022d05901fb7e285a [file] [log] [blame]
Vinod Kould927fda2011-01-04 20:16:32 +05301/*
Mark Browna4b12992014-03-12 23:04:35 +00002 * sst_mfld_platform.c - Intel MID Platform driver
Vinod Kould927fda2011-01-04 20:16:32 +05303 *
Vinod Koul0cd57512013-03-29 23:41:42 +05304 * Copyright (C) 2010-2013 Intel Corp
Vinod Kould927fda2011-01-04 20:16:32 +05305 * 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>
Paul Gortmakerda155d52011-07-15 12:38:28 -040030#include <linux/module.h>
Vinod Kould927fda2011-01-04 20:16:32 +053031#include <sound/core.h>
32#include <sound/pcm.h>
33#include <sound/pcm_params.h>
34#include <sound/soc.h>
Vinod Koulc514a912012-08-16 17:10:42 +053035#include <sound/compress_driver.h>
Mark Browna4b12992014-03-12 23:04:35 +000036#include "sst-mfld-platform.h"
Vinod Kould927fda2011-01-04 20:16:32 +053037
Vinod Koul03c33042011-12-05 19:13:41 +053038static struct sst_device *sst;
39static DEFINE_MUTEX(sst_lock);
40
41int sst_register_dsp(struct sst_device *dev)
42{
Takashi Iwai656a22a2013-11-05 18:40:01 +010043 if (WARN_ON(!dev))
44 return -EINVAL;
Vinod Koul03c33042011-12-05 19:13:41 +053045 if (!try_module_get(dev->dev->driver->owner))
46 return -ENODEV;
47 mutex_lock(&sst_lock);
48 if (sst) {
49 pr_err("we already have a device %s\n", sst->name);
50 module_put(dev->dev->driver->owner);
51 mutex_unlock(&sst_lock);
52 return -EEXIST;
53 }
54 pr_debug("registering device %s\n", dev->name);
55 sst = dev;
56 mutex_unlock(&sst_lock);
57 return 0;
58}
59EXPORT_SYMBOL_GPL(sst_register_dsp);
60
61int sst_unregister_dsp(struct sst_device *dev)
62{
Takashi Iwai656a22a2013-11-05 18:40:01 +010063 if (WARN_ON(!dev))
64 return -EINVAL;
Vinod Koul03c33042011-12-05 19:13:41 +053065 if (dev != sst)
66 return -EINVAL;
67
68 mutex_lock(&sst_lock);
69
70 if (!sst) {
71 mutex_unlock(&sst_lock);
72 return -EIO;
73 }
74
75 module_put(sst->dev->driver->owner);
76 pr_debug("unreg %s\n", sst->name);
77 sst = NULL;
78 mutex_unlock(&sst_lock);
79 return 0;
80}
81EXPORT_SYMBOL_GPL(sst_unregister_dsp);
82
Vinod Kould927fda2011-01-04 20:16:32 +053083static struct snd_pcm_hardware sst_platform_pcm_hw = {
84 .info = (SNDRV_PCM_INFO_INTERLEAVED |
85 SNDRV_PCM_INFO_DOUBLE |
86 SNDRV_PCM_INFO_PAUSE |
87 SNDRV_PCM_INFO_RESUME |
88 SNDRV_PCM_INFO_MMAP|
89 SNDRV_PCM_INFO_MMAP_VALID |
90 SNDRV_PCM_INFO_BLOCK_TRANSFER |
91 SNDRV_PCM_INFO_SYNC_START),
Vinod Kould927fda2011-01-04 20:16:32 +053092 .buffer_bytes_max = SST_MAX_BUFFER,
93 .period_bytes_min = SST_MIN_PERIOD_BYTES,
94 .period_bytes_max = SST_MAX_PERIOD_BYTES,
95 .periods_min = SST_MIN_PERIODS,
96 .periods_max = SST_MAX_PERIODS,
97 .fifo_size = SST_FIFO_SIZE,
98};
99
100/* MFLD - MSIC */
Axel Lind1b73282011-09-27 10:38:50 +0800101static struct snd_soc_dai_driver sst_platform_dai[] = {
Vinod Kould927fda2011-01-04 20:16:32 +0530102{
103 .name = "Headset-cpu-dai",
104 .id = 0,
105 .playback = {
106 .channels_min = SST_STEREO,
107 .channels_max = SST_STEREO,
108 .rates = SNDRV_PCM_RATE_48000,
109 .formats = SNDRV_PCM_FMTBIT_S24_LE,
110 },
Harsha Priyaa7bffdf2011-01-28 22:27:26 +0530111 .capture = {
112 .channels_min = 1,
113 .channels_max = 5,
114 .rates = SNDRV_PCM_RATE_48000,
115 .formats = SNDRV_PCM_FMTBIT_S24_LE,
116 },
Vinod Kould927fda2011-01-04 20:16:32 +0530117},
118{
119 .name = "Speaker-cpu-dai",
120 .id = 1,
121 .playback = {
122 .channels_min = SST_MONO,
123 .channels_max = SST_STEREO,
124 .rates = SNDRV_PCM_RATE_48000,
125 .formats = SNDRV_PCM_FMTBIT_S24_LE,
126 },
127},
128{
129 .name = "Vibra1-cpu-dai",
130 .id = 2,
131 .playback = {
132 .channels_min = SST_MONO,
133 .channels_max = SST_MONO,
134 .rates = SNDRV_PCM_RATE_48000,
135 .formats = SNDRV_PCM_FMTBIT_S24_LE,
136 },
137},
138{
139 .name = "Vibra2-cpu-dai",
140 .id = 3,
141 .playback = {
142 .channels_min = SST_MONO,
143 .channels_max = SST_STEREO,
144 .rates = SNDRV_PCM_RATE_48000,
145 .formats = SNDRV_PCM_FMTBIT_S24_LE,
146 },
147},
Vinod Koulc514a912012-08-16 17:10:42 +0530148{
149 .name = "Compress-cpu-dai",
150 .compress_dai = 1,
151 .playback = {
152 .channels_min = SST_STEREO,
153 .channels_max = SST_STEREO,
154 .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
155 .formats = SNDRV_PCM_FMTBIT_S16_LE,
156 },
157},
Vinod Kould927fda2011-01-04 20:16:32 +0530158};
Harsha Priya5c685362011-01-11 14:50:35 +0530159
Vinod Kould927fda2011-01-04 20:16:32 +0530160/* helper functions */
Harsha Priya5c685362011-01-11 14:50:35 +0530161static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
162 int state)
163{
Lu Guanqund89b0a12011-04-08 15:38:48 +0800164 unsigned long flags;
165 spin_lock_irqsave(&stream->status_lock, flags);
Harsha Priya5c685362011-01-11 14:50:35 +0530166 stream->stream_status = state;
Lu Guanqund89b0a12011-04-08 15:38:48 +0800167 spin_unlock_irqrestore(&stream->status_lock, flags);
Harsha Priya5c685362011-01-11 14:50:35 +0530168}
169
170static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
171{
172 int state;
Lu Guanqund89b0a12011-04-08 15:38:48 +0800173 unsigned long flags;
Harsha Priya5c685362011-01-11 14:50:35 +0530174
Lu Guanqund89b0a12011-04-08 15:38:48 +0800175 spin_lock_irqsave(&stream->status_lock, flags);
Harsha Priya5c685362011-01-11 14:50:35 +0530176 state = stream->stream_status;
Lu Guanqund89b0a12011-04-08 15:38:48 +0800177 spin_unlock_irqrestore(&stream->status_lock, flags);
Harsha Priya5c685362011-01-11 14:50:35 +0530178 return state;
179}
180
181static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
Vinod Koul03c33042011-12-05 19:13:41 +0530182 struct sst_pcm_params *param)
Harsha Priya5c685362011-01-11 14:50:35 +0530183{
184
Vinod Koul03c33042011-12-05 19:13:41 +0530185 param->codec = SST_CODEC_TYPE_PCM;
186 param->num_chan = (u8) substream->runtime->channels;
187 param->pcm_wd_sz = substream->runtime->sample_bits;
188 param->reserved = 0;
189 param->sfreq = substream->runtime->rate;
190 param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream);
191 param->period_count = substream->runtime->period_size;
192 param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area);
193 pr_debug("period_cnt = %d\n", param->period_count);
194 pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz);
Harsha Priya5c685362011-01-11 14:50:35 +0530195}
196
Vinod Kould927fda2011-01-04 20:16:32 +0530197static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
198{
199 struct sst_runtime_stream *stream =
200 substream->runtime->private_data;
Vinod Koul03c33042011-12-05 19:13:41 +0530201 struct sst_pcm_params param = {0};
202 struct sst_stream_params str_params = {0};
Vinod Kould927fda2011-01-04 20:16:32 +0530203 int ret_val;
204
205 /* set codec params and inform SST driver the same */
Harsha Priya5c685362011-01-11 14:50:35 +0530206 sst_fill_pcm_params(substream, &param);
Vinod Kould927fda2011-01-04 20:16:32 +0530207 substream->runtime->dma_area = substream->dma_buffer.area;
Vinod Kould927fda2011-01-04 20:16:32 +0530208 str_params.sparams = param;
Vinod Koul03c33042011-12-05 19:13:41 +0530209 str_params.codec = param.codec;
Vinod Kould927fda2011-01-04 20:16:32 +0530210 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
211 str_params.ops = STREAM_OPS_PLAYBACK;
212 str_params.device_type = substream->pcm->device + 1;
213 pr_debug("Playbck stream,Device %d\n",
214 substream->pcm->device);
215 } else {
216 str_params.ops = STREAM_OPS_CAPTURE;
217 str_params.device_type = SND_SST_DEVICE_CAPTURE;
218 pr_debug("Capture stream,Device %d\n",
219 substream->pcm->device);
220 }
Vinod Koul03c33042011-12-05 19:13:41 +0530221 ret_val = stream->ops->open(&str_params);
Vinod Kould927fda2011-01-04 20:16:32 +0530222 pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
223 if (ret_val < 0)
224 return ret_val;
225
226 stream->stream_info.str_id = ret_val;
227 pr_debug("str id : %d\n", stream->stream_info.str_id);
Vinod Kould927fda2011-01-04 20:16:32 +0530228 return ret_val;
229}
230
Vinod Kould927fda2011-01-04 20:16:32 +0530231static void sst_period_elapsed(void *mad_substream)
232{
233 struct snd_pcm_substream *substream = mad_substream;
234 struct sst_runtime_stream *stream;
Harsha Priya5c685362011-01-11 14:50:35 +0530235 int status;
Vinod Kould927fda2011-01-04 20:16:32 +0530236
237 if (!substream || !substream->runtime)
238 return;
239 stream = substream->runtime->private_data;
240 if (!stream)
241 return;
Harsha Priya5c685362011-01-11 14:50:35 +0530242 status = sst_get_stream_status(stream);
243 if (status != SST_PLATFORM_RUNNING)
Vinod Kould927fda2011-01-04 20:16:32 +0530244 return;
Vinod Kould927fda2011-01-04 20:16:32 +0530245 snd_pcm_period_elapsed(substream);
Vinod Kould927fda2011-01-04 20:16:32 +0530246}
247
248static int sst_platform_init_stream(struct snd_pcm_substream *substream)
249{
250 struct sst_runtime_stream *stream =
251 substream->runtime->private_data;
252 int ret_val;
253
254 pr_debug("setting buffer ptr param\n");
Harsha Priya5c685362011-01-11 14:50:35 +0530255 sst_set_stream_status(stream, SST_PLATFORM_INIT);
Vinod Kould927fda2011-01-04 20:16:32 +0530256 stream->stream_info.period_elapsed = sst_period_elapsed;
257 stream->stream_info.mad_substream = substream;
258 stream->stream_info.buffer_ptr = 0;
259 stream->stream_info.sfreq = substream->runtime->rate;
Vinod Koul03c33042011-12-05 19:13:41 +0530260 ret_val = stream->ops->device_control(
Harsha Priyaa2117012011-01-11 14:50:59 +0530261 SST_SND_STREAM_INIT, &stream->stream_info);
Vinod Kould927fda2011-01-04 20:16:32 +0530262 if (ret_val)
263 pr_err("control_set ret error %d\n", ret_val);
264 return ret_val;
265
266}
267/* end -- helper functions */
268
269static int sst_platform_open(struct snd_pcm_substream *substream)
270{
Lu Guanqun22be5042011-09-06 15:21:38 +0800271 struct snd_pcm_runtime *runtime = substream->runtime;
Vinod Kould927fda2011-01-04 20:16:32 +0530272 struct sst_runtime_stream *stream;
Joerg Roedelc45471ea2011-12-15 18:24:54 +0100273 int ret_val;
Vinod Kould927fda2011-01-04 20:16:32 +0530274
275 pr_debug("sst_platform_open called\n");
Lu Guanqun22be5042011-09-06 15:21:38 +0800276
277 snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw);
Lu Guanqun283e42e2011-09-06 15:21:43 +0800278 ret_val = snd_pcm_hw_constraint_integer(runtime,
279 SNDRV_PCM_HW_PARAM_PERIODS);
280 if (ret_val < 0)
281 return ret_val;
Lu Guanqun22be5042011-09-06 15:21:38 +0800282
Vinod Kould927fda2011-01-04 20:16:32 +0530283 stream = kzalloc(sizeof(*stream), GFP_KERNEL);
284 if (!stream)
285 return -ENOMEM;
Vinod Kould927fda2011-01-04 20:16:32 +0530286 spin_lock_init(&stream->status_lock);
Vinod Koul03c33042011-12-05 19:13:41 +0530287
288 /* get the sst ops */
289 mutex_lock(&sst_lock);
290 if (!sst) {
291 pr_err("no device available to run\n");
292 mutex_unlock(&sst_lock);
293 kfree(stream);
294 return -ENODEV;
295 }
296 if (!try_module_get(sst->dev->driver->owner)) {
297 mutex_unlock(&sst_lock);
298 kfree(stream);
299 return -ENODEV;
300 }
301 stream->ops = sst->ops;
302 mutex_unlock(&sst_lock);
303
Vinod Kould927fda2011-01-04 20:16:32 +0530304 stream->stream_info.str_id = 0;
Harsha Priya5c685362011-01-11 14:50:35 +0530305 sst_set_stream_status(stream, SST_PLATFORM_INIT);
Vinod Kould927fda2011-01-04 20:16:32 +0530306 stream->stream_info.mad_substream = substream;
307 /* allocate memory for SST API set */
Vinod Kould927fda2011-01-04 20:16:32 +0530308 runtime->private_data = stream;
Lu Guanqun283e42e2011-09-06 15:21:43 +0800309
310 return 0;
Vinod Kould927fda2011-01-04 20:16:32 +0530311}
312
313static int sst_platform_close(struct snd_pcm_substream *substream)
314{
315 struct sst_runtime_stream *stream;
316 int ret_val = 0, str_id;
317
318 pr_debug("sst_platform_close called\n");
Vinod Kould927fda2011-01-04 20:16:32 +0530319 stream = substream->runtime->private_data;
320 str_id = stream->stream_info.str_id;
Vinod Kould927fda2011-01-04 20:16:32 +0530321 if (str_id)
Vinod Koul03c33042011-12-05 19:13:41 +0530322 ret_val = stream->ops->close(str_id);
323 module_put(sst->dev->driver->owner);
Vinod Kould927fda2011-01-04 20:16:32 +0530324 kfree(stream);
325 return ret_val;
326}
327
328static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
329{
330 struct sst_runtime_stream *stream;
331 int ret_val = 0, str_id;
332
333 pr_debug("sst_platform_pcm_prepare called\n");
Vinod Kould927fda2011-01-04 20:16:32 +0530334 stream = substream->runtime->private_data;
335 str_id = stream->stream_info.str_id;
336 if (stream->stream_info.str_id) {
Vinod Koul03c33042011-12-05 19:13:41 +0530337 ret_val = stream->ops->device_control(
338 SST_SND_DROP, &str_id);
Vinod Kould927fda2011-01-04 20:16:32 +0530339 return ret_val;
340 }
341
342 ret_val = sst_platform_alloc_stream(substream);
343 if (ret_val < 0)
344 return ret_val;
345 snprintf(substream->pcm->id, sizeof(substream->pcm->id),
346 "%d", stream->stream_info.str_id);
347
348 ret_val = sst_platform_init_stream(substream);
349 if (ret_val)
350 return ret_val;
351 substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
352 return ret_val;
353}
354
355static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
356 int cmd)
357{
358 int ret_val = 0, str_id;
359 struct sst_runtime_stream *stream;
Harsha Priyaa2117012011-01-11 14:50:59 +0530360 int str_cmd, status;
Vinod Kould927fda2011-01-04 20:16:32 +0530361
362 pr_debug("sst_platform_pcm_trigger called\n");
Vinod Kould927fda2011-01-04 20:16:32 +0530363 stream = substream->runtime->private_data;
Vinod Kould927fda2011-01-04 20:16:32 +0530364 str_id = stream->stream_info.str_id;
Vinod Kould927fda2011-01-04 20:16:32 +0530365 switch (cmd) {
366 case SNDRV_PCM_TRIGGER_START:
367 pr_debug("sst: Trigger Start\n");
Harsha Priyaa2117012011-01-11 14:50:59 +0530368 str_cmd = SST_SND_START;
369 status = SST_PLATFORM_RUNNING;
Vinod Kould927fda2011-01-04 20:16:32 +0530370 stream->stream_info.mad_substream = substream;
371 break;
372 case SNDRV_PCM_TRIGGER_STOP:
373 pr_debug("sst: in stop\n");
Harsha Priyaa2117012011-01-11 14:50:59 +0530374 str_cmd = SST_SND_DROP;
375 status = SST_PLATFORM_DROPPED;
Vinod Kould927fda2011-01-04 20:16:32 +0530376 break;
377 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
378 pr_debug("sst: in pause\n");
Harsha Priyaa2117012011-01-11 14:50:59 +0530379 str_cmd = SST_SND_PAUSE;
380 status = SST_PLATFORM_PAUSED;
Vinod Kould927fda2011-01-04 20:16:32 +0530381 break;
382 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
383 pr_debug("sst: in pause release\n");
Harsha Priyaa2117012011-01-11 14:50:59 +0530384 str_cmd = SST_SND_RESUME;
385 status = SST_PLATFORM_RUNNING;
Vinod Kould927fda2011-01-04 20:16:32 +0530386 break;
387 default:
Harsha Priyaa2117012011-01-11 14:50:59 +0530388 return -EINVAL;
Vinod Kould927fda2011-01-04 20:16:32 +0530389 }
Vinod Koul03c33042011-12-05 19:13:41 +0530390 ret_val = stream->ops->device_control(str_cmd, &str_id);
Harsha Priyaa2117012011-01-11 14:50:59 +0530391 if (!ret_val)
392 sst_set_stream_status(stream, status);
393
Vinod Kould927fda2011-01-04 20:16:32 +0530394 return ret_val;
395}
396
397
398static snd_pcm_uframes_t sst_platform_pcm_pointer
399 (struct snd_pcm_substream *substream)
400{
401 struct sst_runtime_stream *stream;
Harsha Priya5c685362011-01-11 14:50:35 +0530402 int ret_val, status;
Vinod Kould927fda2011-01-04 20:16:32 +0530403 struct pcm_stream_info *str_info;
404
Vinod Kould927fda2011-01-04 20:16:32 +0530405 stream = substream->runtime->private_data;
Harsha Priya5c685362011-01-11 14:50:35 +0530406 status = sst_get_stream_status(stream);
407 if (status == SST_PLATFORM_INIT)
Vinod Kould927fda2011-01-04 20:16:32 +0530408 return 0;
Vinod Kould927fda2011-01-04 20:16:32 +0530409 str_info = &stream->stream_info;
Vinod Koul03c33042011-12-05 19:13:41 +0530410 ret_val = stream->ops->device_control(
Vinod Kould927fda2011-01-04 20:16:32 +0530411 SST_SND_BUFFER_POINTER, str_info);
412 if (ret_val) {
413 pr_err("sst: error code = %d\n", ret_val);
414 return ret_val;
415 }
Vinod Kould927fda2011-01-04 20:16:32 +0530416 return stream->stream_info.buffer_ptr;
417}
418
Vinod Koul5b499f82011-02-15 18:28:54 +0530419static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
420 struct snd_pcm_hw_params *params)
421{
422 snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
423 memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
424
425 return 0;
426}
Vinod Kould927fda2011-01-04 20:16:32 +0530427
xingchao9ab88432011-04-27 16:58:54 -0400428static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
429{
430 return snd_pcm_lib_free_pages(substream);
431}
432
Vinod Kould927fda2011-01-04 20:16:32 +0530433static struct snd_pcm_ops sst_platform_ops = {
434 .open = sst_platform_open,
435 .close = sst_platform_close,
436 .ioctl = snd_pcm_lib_ioctl,
437 .prepare = sst_platform_pcm_prepare,
438 .trigger = sst_platform_pcm_trigger,
439 .pointer = sst_platform_pcm_pointer,
Vinod Koul5b499f82011-02-15 18:28:54 +0530440 .hw_params = sst_platform_pcm_hw_params,
xingchao9ab88432011-04-27 16:58:54 -0400441 .hw_free = sst_platform_pcm_hw_free,
Vinod Kould927fda2011-01-04 20:16:32 +0530442};
443
444static void sst_pcm_free(struct snd_pcm *pcm)
445{
446 pr_debug("sst_pcm_free called\n");
447 snd_pcm_lib_preallocate_free_for_all(pcm);
448}
449
Axel Lin8faa8c12011-12-13 17:13:45 +0800450static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
Vinod Kould927fda2011-01-04 20:16:32 +0530451{
Liam Girdwood552d1ef2011-06-07 16:08:33 +0100452 struct snd_pcm *pcm = rtd->pcm;
Vinod Kould927fda2011-01-04 20:16:32 +0530453 int retval = 0;
454
455 pr_debug("sst_pcm_new called\n");
Joachim Eastwood25e9e752012-01-01 01:58:44 +0100456 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
457 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
Vinod Kould927fda2011-01-04 20:16:32 +0530458 retval = snd_pcm_lib_preallocate_pages_for_all(pcm,
459 SNDRV_DMA_TYPE_CONTINUOUS,
460 snd_dma_continuous_data(GFP_KERNEL),
461 SST_MIN_BUFFER, SST_MAX_BUFFER);
462 if (retval) {
463 pr_err("dma buffer allocationf fail\n");
464 return retval;
465 }
466 }
Vinod Kould927fda2011-01-04 20:16:32 +0530467 return retval;
468}
Vinod Koulc514a912012-08-16 17:10:42 +0530469
470/* compress stream operations */
471static void sst_compr_fragment_elapsed(void *arg)
472{
473 struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
474
475 pr_debug("fragment elapsed by driver\n");
476 if (cstream)
477 snd_compr_fragment_elapsed(cstream);
478}
479
480static int sst_platform_compr_open(struct snd_compr_stream *cstream)
481{
482
483 int ret_val = 0;
484 struct snd_compr_runtime *runtime = cstream->runtime;
485 struct sst_runtime_stream *stream;
486
487 stream = kzalloc(sizeof(*stream), GFP_KERNEL);
488 if (!stream)
489 return -ENOMEM;
490
491 spin_lock_init(&stream->status_lock);
492
493 /* get the sst ops */
494 if (!sst || !try_module_get(sst->dev->driver->owner)) {
495 pr_err("no device available to run\n");
496 ret_val = -ENODEV;
497 goto out_ops;
498 }
499 stream->compr_ops = sst->compr_ops;
500
501 stream->id = 0;
502 sst_set_stream_status(stream, SST_PLATFORM_INIT);
503 runtime->private_data = stream;
504 return 0;
505out_ops:
506 kfree(stream);
507 return ret_val;
508}
509
510static int sst_platform_compr_free(struct snd_compr_stream *cstream)
511{
512 struct sst_runtime_stream *stream;
513 int ret_val = 0, str_id;
514
515 stream = cstream->runtime->private_data;
516 /*need to check*/
517 str_id = stream->id;
518 if (str_id)
519 ret_val = stream->compr_ops->close(str_id);
520 module_put(sst->dev->driver->owner);
521 kfree(stream);
522 pr_debug("%s: %d\n", __func__, ret_val);
523 return 0;
524}
525
526static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
527 struct snd_compr_params *params)
528{
529 struct sst_runtime_stream *stream;
530 int retval;
531 struct snd_sst_params str_params;
532 struct sst_compress_cb cb;
533
534 stream = cstream->runtime->private_data;
535 /* construct fw structure for this*/
536 memset(&str_params, 0, sizeof(str_params));
537
538 str_params.ops = STREAM_OPS_PLAYBACK;
539 str_params.stream_type = SST_STREAM_TYPE_MUSIC;
540 str_params.device_type = SND_SST_DEVICE_COMPRESS;
541
542 switch (params->codec.id) {
543 case SND_AUDIOCODEC_MP3: {
544 str_params.codec = SST_CODEC_TYPE_MP3;
545 str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3;
546 str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
547 str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
548 break;
549 }
550
551 case SND_AUDIOCODEC_AAC: {
552 str_params.codec = SST_CODEC_TYPE_AAC;
553 str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC;
554 str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
555 str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
556 if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
557 str_params.sparams.uc.aac_params.bs_format =
558 AAC_BIT_STREAM_ADTS;
559 else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
560 str_params.sparams.uc.aac_params.bs_format =
561 AAC_BIT_STREAM_RAW;
562 else {
563 pr_err("Undefined format%d\n", params->codec.format);
564 return -EINVAL;
565 }
566 str_params.sparams.uc.aac_params.externalsr =
567 params->codec.sample_rate;
568 break;
569 }
570
571 default:
572 pr_err("codec not supported, id =%d\n", params->codec.id);
573 return -EINVAL;
574 }
575
576 str_params.aparams.ring_buf_info[0].addr =
577 virt_to_phys(cstream->runtime->buffer);
578 str_params.aparams.ring_buf_info[0].size =
579 cstream->runtime->buffer_size;
580 str_params.aparams.sg_count = 1;
581 str_params.aparams.frag_size = cstream->runtime->fragment_size;
582
583 cb.param = cstream;
584 cb.compr_cb = sst_compr_fragment_elapsed;
585
586 retval = stream->compr_ops->open(&str_params, &cb);
587 if (retval < 0) {
588 pr_err("stream allocation failed %d\n", retval);
589 return retval;
590 }
591
592 stream->id = retval;
593 return 0;
594}
595
596static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
597{
598 struct sst_runtime_stream *stream =
599 cstream->runtime->private_data;
600
601 return stream->compr_ops->control(cmd, stream->id);
602}
603
604static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
605 struct snd_compr_tstamp *tstamp)
606{
607 struct sst_runtime_stream *stream;
608
609 stream = cstream->runtime->private_data;
610 stream->compr_ops->tstamp(stream->id, tstamp);
611 tstamp->byte_offset = tstamp->copied_total %
612 (u32)cstream->runtime->buffer_size;
613 pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
614 return 0;
615}
616
617static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
618 size_t bytes)
619{
620 struct sst_runtime_stream *stream;
621
622 stream = cstream->runtime->private_data;
623 stream->compr_ops->ack(stream->id, (unsigned long)bytes);
624 stream->bytes_written += bytes;
625
626 return 0;
627}
628
629static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
630 struct snd_compr_caps *caps)
631{
632 struct sst_runtime_stream *stream =
633 cstream->runtime->private_data;
634
635 return stream->compr_ops->get_caps(caps);
636}
637
638static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
639 struct snd_compr_codec_caps *codec)
640{
641 struct sst_runtime_stream *stream =
642 cstream->runtime->private_data;
643
644 return stream->compr_ops->get_codec_caps(codec);
645}
646
Vinod Koul0cd57512013-03-29 23:41:42 +0530647static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
648 struct snd_compr_metadata *metadata)
649{
650 struct sst_runtime_stream *stream =
651 cstream->runtime->private_data;
652
653 return stream->compr_ops->set_metadata(stream->id, metadata);
654}
655
Vinod Koulc514a912012-08-16 17:10:42 +0530656static struct snd_compr_ops sst_platform_compr_ops = {
657
658 .open = sst_platform_compr_open,
659 .free = sst_platform_compr_free,
660 .set_params = sst_platform_compr_set_params,
Vinod Koul0cd57512013-03-29 23:41:42 +0530661 .set_metadata = sst_platform_compr_set_metadata,
Vinod Koulc514a912012-08-16 17:10:42 +0530662 .trigger = sst_platform_compr_trigger,
663 .pointer = sst_platform_compr_pointer,
664 .ack = sst_platform_compr_ack,
665 .get_caps = sst_platform_compr_get_caps,
666 .get_codec_caps = sst_platform_compr_get_codec_caps,
667};
668
Axel Lin8faa8c12011-12-13 17:13:45 +0800669static struct snd_soc_platform_driver sst_soc_platform_drv = {
Vinod Kould927fda2011-01-04 20:16:32 +0530670 .ops = &sst_platform_ops,
Vinod Koulc514a912012-08-16 17:10:42 +0530671 .compr_ops = &sst_platform_compr_ops,
Vinod Kould927fda2011-01-04 20:16:32 +0530672 .pcm_new = sst_pcm_new,
673 .pcm_free = sst_pcm_free,
674};
675
Vinod Koul2b4c78d2014-05-05 22:19:25 +0530676static const struct snd_soc_component_driver sst_component = {
677 .name = "sst",
678};
679
680
Vinod Kould927fda2011-01-04 20:16:32 +0530681static int sst_platform_probe(struct platform_device *pdev)
682{
683 int ret;
684
685 pr_debug("sst_platform_probe called\n");
Vinod Koul03c33042011-12-05 19:13:41 +0530686 sst = NULL;
Vinod Kould927fda2011-01-04 20:16:32 +0530687 ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
688 if (ret) {
689 pr_err("registering soc platform failed\n");
690 return ret;
691 }
Harsha Priya5c685362011-01-11 14:50:35 +0530692
Kuninori Morimotob1c36862013-03-21 03:32:50 -0700693 ret = snd_soc_register_component(&pdev->dev, &sst_component,
Vinod Kould927fda2011-01-04 20:16:32 +0530694 sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
695 if (ret) {
696 pr_err("registering cpu dais failed\n");
697 snd_soc_unregister_platform(&pdev->dev);
698 }
699 return ret;
700}
701
702static int sst_platform_remove(struct platform_device *pdev)
703{
704
Kuninori Morimotob1c36862013-03-21 03:32:50 -0700705 snd_soc_unregister_component(&pdev->dev);
Vinod Kould927fda2011-01-04 20:16:32 +0530706 snd_soc_unregister_platform(&pdev->dev);
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300707 pr_debug("sst_platform_remove success\n");
Vinod Kould927fda2011-01-04 20:16:32 +0530708 return 0;
709}
710
711static struct platform_driver sst_platform_driver = {
712 .driver = {
Mark Browna4b12992014-03-12 23:04:35 +0000713 .name = "sst-mfld-platform",
Vinod Kould927fda2011-01-04 20:16:32 +0530714 .owner = THIS_MODULE,
715 },
716 .probe = sst_platform_probe,
717 .remove = sst_platform_remove,
718};
719
Axel Lin29515d62011-11-24 11:51:56 +0800720module_platform_driver(sst_platform_driver);
Vinod Kould927fda2011-01-04 20:16:32 +0530721
722MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
723MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
724MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
725MODULE_LICENSE("GPL v2");
Mark Browna4b12992014-03-12 23:04:35 +0000726MODULE_ALIAS("platform:sst-mfld-platform");