diff options
Diffstat (limited to 'sound/soc/intel/sst-mfld-platform-pcm.c')
-rw-r--r-- | sound/soc/intel/sst-mfld-platform-pcm.c | 319 |
1 files changed, 230 insertions, 89 deletions
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 7c790f51d259..706212a6a68c 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * sst_mfld_platform.c - Intel MID Platform driver | 2 | * sst_mfld_platform.c - Intel MID Platform driver |
3 | * | 3 | * |
4 | * Copyright (C) 2010-2013 Intel Corp | 4 | * Copyright (C) 2010-2014 Intel Corp |
5 | * Author: Vinod Koul <vinod.koul@intel.com> | 5 | * Author: Vinod Koul <vinod.koul@intel.com> |
6 | * Author: Harsha Priya <priya.harsha@intel.com> | 6 | * Author: Harsha Priya <priya.harsha@intel.com> |
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
@@ -27,7 +27,9 @@ | |||
27 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
28 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
29 | #include <sound/compress_driver.h> | 29 | #include <sound/compress_driver.h> |
30 | #include <asm/platform_sst_audio.h> | ||
30 | #include "sst-mfld-platform.h" | 31 | #include "sst-mfld-platform.h" |
32 | #include "sst-atom-controls.h" | ||
31 | 33 | ||
32 | struct sst_device *sst; | 34 | struct sst_device *sst; |
33 | static DEFINE_MUTEX(sst_lock); | 35 | static DEFINE_MUTEX(sst_lock); |
@@ -92,6 +94,13 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = { | |||
92 | .fifo_size = SST_FIFO_SIZE, | 94 | .fifo_size = SST_FIFO_SIZE, |
93 | }; | 95 | }; |
94 | 96 | ||
97 | static struct sst_dev_stream_map dpcm_strm_map[] = { | ||
98 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* Reserved, not in use */ | ||
99 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0}, | ||
100 | {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0}, | ||
101 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0}, | ||
102 | }; | ||
103 | |||
95 | /* MFLD - MSIC */ | 104 | /* MFLD - MSIC */ |
96 | static struct snd_soc_dai_driver sst_platform_dai[] = { | 105 | static struct snd_soc_dai_driver sst_platform_dai[] = { |
97 | { | 106 | { |
@@ -143,58 +152,142 @@ static inline int sst_get_stream_status(struct sst_runtime_stream *stream) | |||
143 | return state; | 152 | return state; |
144 | } | 153 | } |
145 | 154 | ||
155 | static void sst_fill_alloc_params(struct snd_pcm_substream *substream, | ||
156 | struct snd_sst_alloc_params_ext *alloc_param) | ||
157 | { | ||
158 | unsigned int channels; | ||
159 | snd_pcm_uframes_t period_size; | ||
160 | ssize_t periodbytes; | ||
161 | ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream); | ||
162 | u32 buffer_addr = virt_to_phys(substream->dma_buffer.area); | ||
163 | |||
164 | channels = substream->runtime->channels; | ||
165 | period_size = substream->runtime->period_size; | ||
166 | periodbytes = samples_to_bytes(substream->runtime, period_size); | ||
167 | alloc_param->ring_buf_info[0].addr = buffer_addr; | ||
168 | alloc_param->ring_buf_info[0].size = buffer_bytes; | ||
169 | alloc_param->sg_count = 1; | ||
170 | alloc_param->reserved = 0; | ||
171 | alloc_param->frag_size = periodbytes * channels; | ||
172 | |||
173 | } | ||
146 | static void sst_fill_pcm_params(struct snd_pcm_substream *substream, | 174 | static void sst_fill_pcm_params(struct snd_pcm_substream *substream, |
147 | struct sst_pcm_params *param) | 175 | struct snd_sst_stream_params *param) |
148 | { | 176 | { |
177 | param->uc.pcm_params.num_chan = (u8) substream->runtime->channels; | ||
178 | param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits; | ||
179 | param->uc.pcm_params.sfreq = substream->runtime->rate; | ||
180 | |||
181 | /* PCM stream via ALSA interface */ | ||
182 | param->uc.pcm_params.use_offload_path = 0; | ||
183 | param->uc.pcm_params.reserved2 = 0; | ||
184 | memset(param->uc.pcm_params.channel_map, 0, sizeof(u8)); | ||
149 | 185 | ||
150 | param->num_chan = (u8) substream->runtime->channels; | ||
151 | param->pcm_wd_sz = substream->runtime->sample_bits; | ||
152 | param->reserved = 0; | ||
153 | param->sfreq = substream->runtime->rate; | ||
154 | param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream); | ||
155 | param->period_count = substream->runtime->period_size; | ||
156 | param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area); | ||
157 | pr_debug("period_cnt = %d\n", param->period_count); | ||
158 | pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz); | ||
159 | } | 186 | } |
160 | 187 | ||
161 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream) | 188 | static int sst_get_stream_mapping(int dev, int sdev, int dir, |
189 | struct sst_dev_stream_map *map, int size) | ||
190 | { | ||
191 | int i; | ||
192 | |||
193 | if (map == NULL) | ||
194 | return -EINVAL; | ||
195 | |||
196 | |||
197 | /* index 0 is not used in stream map */ | ||
198 | for (i = 1; i < size; i++) { | ||
199 | if ((map[i].dev_num == dev) && (map[i].direction == dir)) | ||
200 | return i; | ||
201 | } | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | int sst_fill_stream_params(void *substream, | ||
206 | const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress) | ||
207 | { | ||
208 | int map_size; | ||
209 | int index; | ||
210 | struct sst_dev_stream_map *map; | ||
211 | struct snd_pcm_substream *pstream = NULL; | ||
212 | struct snd_compr_stream *cstream = NULL; | ||
213 | |||
214 | map = ctx->pdata->pdev_strm_map; | ||
215 | map_size = ctx->pdata->strm_map_size; | ||
216 | |||
217 | if (is_compress == true) | ||
218 | cstream = (struct snd_compr_stream *)substream; | ||
219 | else | ||
220 | pstream = (struct snd_pcm_substream *)substream; | ||
221 | |||
222 | str_params->stream_type = SST_STREAM_TYPE_MUSIC; | ||
223 | |||
224 | /* For pcm streams */ | ||
225 | if (pstream) { | ||
226 | index = sst_get_stream_mapping(pstream->pcm->device, | ||
227 | pstream->number, pstream->stream, | ||
228 | map, map_size); | ||
229 | if (index <= 0) | ||
230 | return -EINVAL; | ||
231 | |||
232 | str_params->stream_id = index; | ||
233 | str_params->device_type = map[index].device_id; | ||
234 | str_params->task = map[index].task_id; | ||
235 | |||
236 | str_params->ops = (u8)pstream->stream; | ||
237 | } | ||
238 | |||
239 | if (cstream) { | ||
240 | index = sst_get_stream_mapping(cstream->device->device, | ||
241 | 0, cstream->direction, | ||
242 | map, map_size); | ||
243 | if (index <= 0) | ||
244 | return -EINVAL; | ||
245 | str_params->stream_id = index; | ||
246 | str_params->device_type = map[index].device_id; | ||
247 | str_params->task = map[index].task_id; | ||
248 | |||
249 | str_params->ops = (u8)cstream->direction; | ||
250 | } | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, | ||
255 | struct snd_soc_platform *platform) | ||
162 | { | 256 | { |
163 | struct sst_runtime_stream *stream = | 257 | struct sst_runtime_stream *stream = |
164 | substream->runtime->private_data; | 258 | substream->runtime->private_data; |
165 | struct sst_pcm_params param = {0}; | 259 | struct snd_sst_stream_params param = {{{0,},},}; |
166 | struct sst_stream_params str_params = {0}; | 260 | struct snd_sst_params str_params = {0}; |
167 | int ret_val; | 261 | struct snd_sst_alloc_params_ext alloc_params = {0}; |
262 | int ret_val = 0; | ||
263 | struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); | ||
168 | 264 | ||
169 | /* set codec params and inform SST driver the same */ | 265 | /* set codec params and inform SST driver the same */ |
170 | sst_fill_pcm_params(substream, ¶m); | 266 | sst_fill_pcm_params(substream, ¶m); |
267 | sst_fill_alloc_params(substream, &alloc_params); | ||
171 | substream->runtime->dma_area = substream->dma_buffer.area; | 268 | substream->runtime->dma_area = substream->dma_buffer.area; |
172 | str_params.sparams = param; | 269 | str_params.sparams = param; |
173 | str_params.codec = param.codec; | 270 | str_params.aparams = alloc_params; |
174 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 271 | str_params.codec = SST_CODEC_TYPE_PCM; |
175 | str_params.ops = STREAM_OPS_PLAYBACK; | 272 | |
176 | str_params.device_type = substream->pcm->device + 1; | 273 | /* fill the device type and stream id to pass to SST driver */ |
177 | pr_debug("Playbck stream,Device %d\n", | 274 | ret_val = sst_fill_stream_params(substream, ctx, &str_params, false); |
178 | substream->pcm->device); | ||
179 | } else { | ||
180 | str_params.ops = STREAM_OPS_CAPTURE; | ||
181 | str_params.device_type = SND_SST_DEVICE_CAPTURE; | ||
182 | pr_debug("Capture stream,Device %d\n", | ||
183 | substream->pcm->device); | ||
184 | } | ||
185 | ret_val = stream->ops->open(&str_params); | ||
186 | pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val); | ||
187 | if (ret_val < 0) | 275 | if (ret_val < 0) |
188 | return ret_val; | 276 | return ret_val; |
189 | 277 | ||
190 | stream->stream_info.str_id = ret_val; | 278 | stream->stream_info.str_id = str_params.stream_id; |
191 | pr_debug("str id : %d\n", stream->stream_info.str_id); | 279 | |
280 | ret_val = stream->ops->open(&str_params); | ||
281 | if (ret_val <= 0) | ||
282 | return ret_val; | ||
283 | |||
284 | |||
192 | return ret_val; | 285 | return ret_val; |
193 | } | 286 | } |
194 | 287 | ||
195 | static void sst_period_elapsed(void *mad_substream) | 288 | static void sst_period_elapsed(void *arg) |
196 | { | 289 | { |
197 | struct snd_pcm_substream *substream = mad_substream; | 290 | struct snd_pcm_substream *substream = arg; |
198 | struct sst_runtime_stream *stream; | 291 | struct sst_runtime_stream *stream; |
199 | int status; | 292 | int status; |
200 | 293 | ||
@@ -218,7 +311,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) | |||
218 | pr_debug("setting buffer ptr param\n"); | 311 | pr_debug("setting buffer ptr param\n"); |
219 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | 312 | sst_set_stream_status(stream, SST_PLATFORM_INIT); |
220 | stream->stream_info.period_elapsed = sst_period_elapsed; | 313 | stream->stream_info.period_elapsed = sst_period_elapsed; |
221 | stream->stream_info.mad_substream = substream; | 314 | stream->stream_info.arg = substream; |
222 | stream->stream_info.buffer_ptr = 0; | 315 | stream->stream_info.buffer_ptr = 0; |
223 | stream->stream_info.sfreq = substream->runtime->rate; | 316 | stream->stream_info.sfreq = substream->runtime->rate; |
224 | ret_val = stream->ops->device_control( | 317 | ret_val = stream->ops->device_control( |
@@ -230,19 +323,12 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) | |||
230 | } | 323 | } |
231 | /* end -- helper functions */ | 324 | /* end -- helper functions */ |
232 | 325 | ||
233 | static int sst_platform_open(struct snd_pcm_substream *substream) | 326 | static int sst_media_open(struct snd_pcm_substream *substream, |
327 | struct snd_soc_dai *dai) | ||
234 | { | 328 | { |
329 | int ret_val = 0; | ||
235 | struct snd_pcm_runtime *runtime = substream->runtime; | 330 | struct snd_pcm_runtime *runtime = substream->runtime; |
236 | struct sst_runtime_stream *stream; | 331 | struct sst_runtime_stream *stream; |
237 | int ret_val; | ||
238 | |||
239 | pr_debug("sst_platform_open called\n"); | ||
240 | |||
241 | snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw); | ||
242 | ret_val = snd_pcm_hw_constraint_integer(runtime, | ||
243 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
244 | if (ret_val < 0) | ||
245 | return ret_val; | ||
246 | 332 | ||
247 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | 333 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
248 | if (!stream) | 334 | if (!stream) |
@@ -251,50 +337,69 @@ static int sst_platform_open(struct snd_pcm_substream *substream) | |||
251 | 337 | ||
252 | /* get the sst ops */ | 338 | /* get the sst ops */ |
253 | mutex_lock(&sst_lock); | 339 | mutex_lock(&sst_lock); |
254 | if (!sst) { | 340 | if (!sst || |
341 | !try_module_get(sst->dev->driver->owner)) { | ||
255 | pr_err("no device available to run\n"); | 342 | pr_err("no device available to run\n"); |
256 | mutex_unlock(&sst_lock); | 343 | ret_val = -ENODEV; |
257 | kfree(stream); | 344 | goto out_ops; |
258 | return -ENODEV; | ||
259 | } | ||
260 | if (!try_module_get(sst->dev->driver->owner)) { | ||
261 | mutex_unlock(&sst_lock); | ||
262 | kfree(stream); | ||
263 | return -ENODEV; | ||
264 | } | 345 | } |
265 | stream->ops = sst->ops; | 346 | stream->ops = sst->ops; |
266 | mutex_unlock(&sst_lock); | 347 | mutex_unlock(&sst_lock); |
267 | 348 | ||
268 | stream->stream_info.str_id = 0; | 349 | stream->stream_info.str_id = 0; |
269 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | 350 | |
270 | stream->stream_info.mad_substream = substream; | 351 | stream->stream_info.arg = substream; |
271 | /* allocate memory for SST API set */ | 352 | /* allocate memory for SST API set */ |
272 | runtime->private_data = stream; | 353 | runtime->private_data = stream; |
273 | 354 | ||
274 | return 0; | 355 | /* Make sure, that the period size is always even */ |
356 | snd_pcm_hw_constraint_step(substream->runtime, 0, | ||
357 | SNDRV_PCM_HW_PARAM_PERIODS, 2); | ||
358 | |||
359 | return snd_pcm_hw_constraint_integer(runtime, | ||
360 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
361 | out_ops: | ||
362 | kfree(stream); | ||
363 | mutex_unlock(&sst_lock); | ||
364 | return ret_val; | ||
275 | } | 365 | } |
276 | 366 | ||
277 | static int sst_platform_close(struct snd_pcm_substream *substream) | 367 | static void sst_media_close(struct snd_pcm_substream *substream, |
368 | struct snd_soc_dai *dai) | ||
278 | { | 369 | { |
279 | struct sst_runtime_stream *stream; | 370 | struct sst_runtime_stream *stream; |
280 | int ret_val = 0, str_id; | 371 | int ret_val = 0, str_id; |
281 | 372 | ||
282 | pr_debug("sst_platform_close called\n"); | ||
283 | stream = substream->runtime->private_data; | 373 | stream = substream->runtime->private_data; |
284 | str_id = stream->stream_info.str_id; | 374 | str_id = stream->stream_info.str_id; |
285 | if (str_id) | 375 | if (str_id) |
286 | ret_val = stream->ops->close(str_id); | 376 | ret_val = stream->ops->close(str_id); |
287 | module_put(sst->dev->driver->owner); | 377 | module_put(sst->dev->driver->owner); |
288 | kfree(stream); | 378 | kfree(stream); |
289 | return ret_val; | ||
290 | } | 379 | } |
291 | 380 | ||
292 | static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | 381 | static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform, |
382 | struct snd_pcm_substream *substream) | ||
383 | { | ||
384 | struct sst_data *sst = snd_soc_platform_get_drvdata(platform); | ||
385 | struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map; | ||
386 | struct sst_runtime_stream *stream = | ||
387 | substream->runtime->private_data; | ||
388 | u32 str_id = stream->stream_info.str_id; | ||
389 | unsigned int pipe_id; | ||
390 | pipe_id = map[str_id].device_id; | ||
391 | |||
392 | pr_debug("%s: got pipe_id = %#x for str_id = %d\n", | ||
393 | __func__, pipe_id, str_id); | ||
394 | return pipe_id; | ||
395 | } | ||
396 | |||
397 | static int sst_media_prepare(struct snd_pcm_substream *substream, | ||
398 | struct snd_soc_dai *dai) | ||
293 | { | 399 | { |
294 | struct sst_runtime_stream *stream; | 400 | struct sst_runtime_stream *stream; |
295 | int ret_val = 0, str_id; | 401 | int ret_val = 0, str_id; |
296 | 402 | ||
297 | pr_debug("sst_platform_pcm_prepare called\n"); | ||
298 | stream = substream->runtime->private_data; | 403 | stream = substream->runtime->private_data; |
299 | str_id = stream->stream_info.str_id; | 404 | str_id = stream->stream_info.str_id; |
300 | if (stream->stream_info.str_id) { | 405 | if (stream->stream_info.str_id) { |
@@ -303,8 +408,8 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | |||
303 | return ret_val; | 408 | return ret_val; |
304 | } | 409 | } |
305 | 410 | ||
306 | ret_val = sst_platform_alloc_stream(substream); | 411 | ret_val = sst_platform_alloc_stream(substream, dai->platform); |
307 | if (ret_val < 0) | 412 | if (ret_val <= 0) |
308 | return ret_val; | 413 | return ret_val; |
309 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), | 414 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), |
310 | "%d", stream->stream_info.str_id); | 415 | "%d", stream->stream_info.str_id); |
@@ -316,6 +421,41 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | |||
316 | return ret_val; | 421 | return ret_val; |
317 | } | 422 | } |
318 | 423 | ||
424 | static int sst_media_hw_params(struct snd_pcm_substream *substream, | ||
425 | struct snd_pcm_hw_params *params, | ||
426 | struct snd_soc_dai *dai) | ||
427 | { | ||
428 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
429 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static int sst_media_hw_free(struct snd_pcm_substream *substream, | ||
434 | struct snd_soc_dai *dai) | ||
435 | { | ||
436 | return snd_pcm_lib_free_pages(substream); | ||
437 | } | ||
438 | |||
439 | static struct snd_soc_dai_ops sst_media_dai_ops = { | ||
440 | .startup = sst_media_open, | ||
441 | .shutdown = sst_media_close, | ||
442 | .prepare = sst_media_prepare, | ||
443 | .hw_params = sst_media_hw_params, | ||
444 | .hw_free = sst_media_hw_free, | ||
445 | }; | ||
446 | |||
447 | static int sst_platform_open(struct snd_pcm_substream *substream) | ||
448 | { | ||
449 | struct snd_pcm_runtime *runtime; | ||
450 | |||
451 | if (substream->pcm->internal) | ||
452 | return 0; | ||
453 | |||
454 | runtime = substream->runtime; | ||
455 | runtime->hw = sst_platform_pcm_hw; | ||
456 | return 0; | ||
457 | } | ||
458 | |||
319 | static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | 459 | static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, |
320 | int cmd) | 460 | int cmd) |
321 | { | 461 | { |
@@ -331,7 +471,7 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | |||
331 | pr_debug("sst: Trigger Start\n"); | 471 | pr_debug("sst: Trigger Start\n"); |
332 | str_cmd = SST_SND_START; | 472 | str_cmd = SST_SND_START; |
333 | status = SST_PLATFORM_RUNNING; | 473 | status = SST_PLATFORM_RUNNING; |
334 | stream->stream_info.mad_substream = substream; | 474 | stream->stream_info.arg = substream; |
335 | break; | 475 | break; |
336 | case SNDRV_PCM_TRIGGER_STOP: | 476 | case SNDRV_PCM_TRIGGER_STOP: |
337 | pr_debug("sst: in stop\n"); | 477 | pr_debug("sst: in stop\n"); |
@@ -377,32 +517,15 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer | |||
377 | pr_err("sst: error code = %d\n", ret_val); | 517 | pr_err("sst: error code = %d\n", ret_val); |
378 | return ret_val; | 518 | return ret_val; |
379 | } | 519 | } |
380 | return stream->stream_info.buffer_ptr; | 520 | substream->runtime->delay = str_info->pcm_delay; |
381 | } | 521 | return str_info->buffer_ptr; |
382 | |||
383 | static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, | ||
384 | struct snd_pcm_hw_params *params) | ||
385 | { | ||
386 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
387 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream) | ||
393 | { | ||
394 | return snd_pcm_lib_free_pages(substream); | ||
395 | } | 522 | } |
396 | 523 | ||
397 | static struct snd_pcm_ops sst_platform_ops = { | 524 | static struct snd_pcm_ops sst_platform_ops = { |
398 | .open = sst_platform_open, | 525 | .open = sst_platform_open, |
399 | .close = sst_platform_close, | ||
400 | .ioctl = snd_pcm_lib_ioctl, | 526 | .ioctl = snd_pcm_lib_ioctl, |
401 | .prepare = sst_platform_pcm_prepare, | ||
402 | .trigger = sst_platform_pcm_trigger, | 527 | .trigger = sst_platform_pcm_trigger, |
403 | .pointer = sst_platform_pcm_pointer, | 528 | .pointer = sst_platform_pcm_pointer, |
404 | .hw_params = sst_platform_pcm_hw_params, | ||
405 | .hw_free = sst_platform_pcm_hw_free, | ||
406 | }; | 529 | }; |
407 | 530 | ||
408 | static void sst_pcm_free(struct snd_pcm *pcm) | 531 | static void sst_pcm_free(struct snd_pcm *pcm) |
@@ -413,15 +536,15 @@ static void sst_pcm_free(struct snd_pcm *pcm) | |||
413 | 536 | ||
414 | static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) | 537 | static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) |
415 | { | 538 | { |
539 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
416 | struct snd_pcm *pcm = rtd->pcm; | 540 | struct snd_pcm *pcm = rtd->pcm; |
417 | int retval = 0; | 541 | int retval = 0; |
418 | 542 | ||
419 | pr_debug("sst_pcm_new called\n"); | 543 | if (dai->driver->playback.channels_min || |
420 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || | 544 | dai->driver->capture.channels_min) { |
421 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | ||
422 | retval = snd_pcm_lib_preallocate_pages_for_all(pcm, | 545 | retval = snd_pcm_lib_preallocate_pages_for_all(pcm, |
423 | SNDRV_DMA_TYPE_CONTINUOUS, | 546 | SNDRV_DMA_TYPE_CONTINUOUS, |
424 | snd_dma_continuous_data(GFP_KERNEL), | 547 | snd_dma_continuous_data(GFP_DMA), |
425 | SST_MIN_BUFFER, SST_MAX_BUFFER); | 548 | SST_MIN_BUFFER, SST_MAX_BUFFER); |
426 | if (retval) { | 549 | if (retval) { |
427 | pr_err("dma buffer allocationf fail\n"); | 550 | pr_err("dma buffer allocationf fail\n"); |
@@ -445,10 +568,28 @@ static const struct snd_soc_component_driver sst_component = { | |||
445 | 568 | ||
446 | static int sst_platform_probe(struct platform_device *pdev) | 569 | static int sst_platform_probe(struct platform_device *pdev) |
447 | { | 570 | { |
571 | struct sst_data *drv; | ||
448 | int ret; | 572 | int ret; |
573 | struct sst_platform_data *pdata; | ||
574 | |||
575 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); | ||
576 | if (drv == NULL) { | ||
577 | pr_err("kzalloc failed\n"); | ||
578 | return -ENOMEM; | ||
579 | } | ||
580 | |||
581 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
582 | if (pdata == NULL) { | ||
583 | pr_err("kzalloc failed for pdata\n"); | ||
584 | return -ENOMEM; | ||
585 | } | ||
586 | |||
587 | pdata->pdev_strm_map = dpcm_strm_map; | ||
588 | pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map); | ||
589 | drv->pdata = pdata; | ||
590 | mutex_init(&drv->lock); | ||
591 | dev_set_drvdata(&pdev->dev, drv); | ||
449 | 592 | ||
450 | pr_debug("sst_platform_probe called\n"); | ||
451 | sst = NULL; | ||
452 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); | 593 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); |
453 | if (ret) { | 594 | if (ret) { |
454 | pr_err("registering soc platform failed\n"); | 595 | pr_err("registering soc platform failed\n"); |