blob: ce86749457b105f9ce7f143e91ed37f1d9221152 [file] [log] [blame]
Sidipotu Ashok5c6855b2019-01-08 15:58:37 +05301/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13
14#include <linux/init.h>
15#include <linux/err.h>
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/time.h>
Ajit Pandey3d7b9a22019-09-05 16:26:01 +053019#include <linux/mutex.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053020#include <linux/wait.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <sound/core.h>
24#include <sound/soc.h>
25#include <sound/soc-dapm.h>
26#include <sound/pcm.h>
27#include <sound/initval.h>
28#include <sound/control.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053029#include <sound/timer.h>
30#include <asm/dma.h>
31#include <linux/dma-mapping.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053032#include <linux/msm_audio.h>
33
34#include <linux/of_device.h>
35#include <sound/tlv.h>
36#include <sound/pcm_params.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053037#include <dsp/msm_audio_ion.h>
38#include <dsp/q6audio-v2.h>
Dieter Lueckingdfe01252018-09-28 15:03:01 +020039#include <dsp/q6core.h>
40#include <dsp/q6asm-v2.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053041
42#include "msm-pcm-q6-v2.h"
43#include "msm-pcm-routing-v2.h"
44#include "msm-qti-pp-config.h"
45
46enum stream_state {
47 IDLE = 0,
48 STOPPED,
49 RUNNING,
50};
51
52static struct audio_locks the_locks;
53
54#define PCM_MASTER_VOL_MAX_STEPS 0x2000
55static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
56 PCM_MASTER_VOL_MAX_STEPS);
57
58struct snd_msm {
59 struct snd_card *card;
60 struct snd_pcm *pcm;
61};
62
63#define CMD_EOS_MIN_TIMEOUT_LENGTH 50
64#define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50)
65#define MAX_PB_COPY_RETRIES 3
66
67static struct snd_pcm_hardware msm_pcm_hardware_capture = {
68 .info = (SNDRV_PCM_INFO_MMAP |
69 SNDRV_PCM_INFO_BLOCK_TRANSFER |
70 SNDRV_PCM_INFO_MMAP_VALID |
71 SNDRV_PCM_INFO_INTERLEAVED |
72 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
73 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
74 SNDRV_PCM_FMTBIT_S24_LE |
75 SNDRV_PCM_FMTBIT_S24_3LE |
76 SNDRV_PCM_FMTBIT_S32_LE),
77 .rates = SNDRV_PCM_RATE_8000_384000,
78 .rate_min = 8000,
79 .rate_max = 384000,
80 .channels_min = 1,
Soumya Managoli760f1482019-05-14 16:41:53 +053081 .channels_max = 8,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053082 .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
83 CAPTURE_MAX_PERIOD_SIZE,
84 .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
85 .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
86 .periods_min = CAPTURE_MIN_NUM_PERIODS,
87 .periods_max = CAPTURE_MAX_NUM_PERIODS,
88 .fifo_size = 0,
89};
90
91static struct snd_pcm_hardware msm_pcm_hardware_playback = {
92 .info = (SNDRV_PCM_INFO_MMAP |
93 SNDRV_PCM_INFO_BLOCK_TRANSFER |
94 SNDRV_PCM_INFO_MMAP_VALID |
95 SNDRV_PCM_INFO_INTERLEAVED |
96 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
97 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
98 SNDRV_PCM_FMTBIT_S24_LE |
99 SNDRV_PCM_FMTBIT_S24_3LE |
100 SNDRV_PCM_FMTBIT_S32_LE),
101 .rates = SNDRV_PCM_RATE_8000_384000,
102 .rate_min = 8000,
103 .rate_max = 384000,
104 .channels_min = 1,
105 .channels_max = 8,
106 .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS *
107 PLAYBACK_MAX_PERIOD_SIZE,
108 .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
109 .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
110 .periods_min = PLAYBACK_MIN_NUM_PERIODS,
111 .periods_max = PLAYBACK_MAX_NUM_PERIODS,
112 .fifo_size = 0,
113};
114
115/* Conventional and unconventional sample rate supported */
116static unsigned int supported_sample_rates[] = {
117 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
118 88200, 96000, 176400, 192000, 352800, 384000
119};
120
121static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
122 .count = ARRAY_SIZE(supported_sample_rates),
123 .list = supported_sample_rates,
124 .mask = 0,
125};
126
127static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
128 void *priv_data)
129{
130 struct msm_audio *prtd = priv_data;
131
132 WARN_ON(!prtd);
133
134 pr_debug("%s: event %x\n", __func__, event);
135
136 switch (event) {
137 case MSM_PCM_RT_EVT_BUF_RECFG:
138 q6asm_cmd(prtd->audio_client, CMD_PAUSE);
139 q6asm_cmd(prtd->audio_client, CMD_FLUSH);
140 q6asm_run(prtd->audio_client, 0, 0, 0);
141 /* fallthrough */
142 default:
143 break;
144 }
145}
146
147static void event_handler(uint32_t opcode,
148 uint32_t token, uint32_t *payload, void *priv)
149{
150 struct msm_audio *prtd = priv;
151 struct snd_pcm_substream *substream = prtd->substream;
152 uint32_t *ptrmem = (uint32_t *)payload;
153 uint32_t idx = 0;
154 uint32_t size = 0;
155 uint8_t buf_index;
156 struct snd_soc_pcm_runtime *rtd;
157 int ret = 0;
158
159 switch (opcode) {
160 case ASM_DATA_EVENT_WRITE_DONE_V2: {
161 pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
162 pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
163 prtd->pcm_irq_pos += prtd->pcm_count;
164 if (atomic_read(&prtd->start))
165 snd_pcm_period_elapsed(substream);
166 atomic_inc(&prtd->out_count);
167 wake_up(&the_locks.write_wait);
168 if (!atomic_read(&prtd->start))
169 break;
170 if (!prtd->mmap_flag || prtd->reset_event)
171 break;
172 if (q6asm_is_cpu_buf_avail_nolock(IN,
173 prtd->audio_client,
174 &size, &idx)) {
175 pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
176 __func__, prtd->pcm_count);
177 q6asm_write_nolock(prtd->audio_client,
178 prtd->pcm_count, 0, 0, NO_TIMESTAMP);
179 }
180 break;
181 }
182 case ASM_DATA_EVENT_RENDERED_EOS:
183 pr_debug("ASM_DATA_EVENT_RENDERED_EOS\n");
184 clear_bit(CMD_EOS, &prtd->cmd_pending);
185 wake_up(&the_locks.eos_wait);
186 break;
187 case ASM_DATA_EVENT_READ_DONE_V2: {
188 pr_debug("ASM_DATA_EVENT_READ_DONE_V2\n");
189 buf_index = q6asm_get_buf_index_from_token(token);
Vignesh Kulothungan3817b182017-12-04 15:56:05 -0800190 if (buf_index >= CAPTURE_MAX_NUM_PERIODS) {
191 pr_err("%s: buffer index %u is out of range.\n",
192 __func__, buf_index);
193 return;
194 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530195 pr_debug("%s: token=0x%08x buf_index=0x%08x\n",
196 __func__, token, buf_index);
197 prtd->in_frame_info[buf_index].size = payload[4];
198 prtd->in_frame_info[buf_index].offset = payload[5];
199 /* assume data size = 0 during flushing */
200 if (prtd->in_frame_info[buf_index].size) {
201 prtd->pcm_irq_pos +=
202 prtd->in_frame_info[buf_index].size;
203 pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
204 if (atomic_read(&prtd->start))
205 snd_pcm_period_elapsed(substream);
206 if (atomic_read(&prtd->in_count) <= prtd->periods)
207 atomic_inc(&prtd->in_count);
208 wake_up(&the_locks.read_wait);
209 if (prtd->mmap_flag &&
210 q6asm_is_cpu_buf_avail_nolock(OUT,
211 prtd->audio_client,
212 &size, &idx) &&
213 (substream->runtime->status->state ==
214 SNDRV_PCM_STATE_RUNNING))
215 q6asm_read_nolock(prtd->audio_client);
216 } else {
217 pr_debug("%s: reclaim flushed buf in_count %x\n",
218 __func__, atomic_read(&prtd->in_count));
219 prtd->pcm_irq_pos += prtd->pcm_count;
220 if (prtd->mmap_flag) {
221 if (q6asm_is_cpu_buf_avail_nolock(OUT,
222 prtd->audio_client,
223 &size, &idx) &&
224 (substream->runtime->status->state ==
225 SNDRV_PCM_STATE_RUNNING))
226 q6asm_read_nolock(prtd->audio_client);
227 } else {
228 atomic_inc(&prtd->in_count);
229 }
230 if (atomic_read(&prtd->in_count) == prtd->periods) {
231 pr_info("%s: reclaimed all bufs\n", __func__);
232 if (atomic_read(&prtd->start))
233 snd_pcm_period_elapsed(substream);
234 wake_up(&the_locks.read_wait);
235 }
236 }
237 break;
238 }
239 case ASM_STREAM_PP_EVENT:
240 case ASM_STREAM_CMD_ENCDEC_EVENTS: {
241 pr_debug("%s: ASM_STREAM_EVENT (0x%x)\n", __func__, opcode);
242 if (!substream) {
243 pr_err("%s: substream is NULL.\n", __func__);
244 return;
245 }
246
247 rtd = substream->private_data;
248 if (!rtd) {
249 pr_err("%s: rtd is NULL\n", __func__);
250 return;
251 }
252
253 ret = msm_adsp_inform_mixer_ctl(rtd, payload);
254 if (ret) {
255 pr_err("%s: failed to inform mixer ctl. err = %d\n",
256 __func__, ret);
257 return;
258 }
259
260 break;
261 }
262 case APR_BASIC_RSP_RESULT: {
263 switch (payload[0]) {
264 case ASM_SESSION_CMD_RUN_V2:
265 if (substream->stream
266 != SNDRV_PCM_STREAM_PLAYBACK) {
267 atomic_set(&prtd->start, 1);
268 break;
269 }
270 if (prtd->mmap_flag) {
271 pr_debug("%s:writing %d bytes of buffer to dsp\n",
272 __func__,
273 prtd->pcm_count);
274 q6asm_write_nolock(prtd->audio_client,
275 prtd->pcm_count,
276 0, 0, NO_TIMESTAMP);
277 } else {
278 while (atomic_read(&prtd->out_needed)) {
279 pr_debug("%s:writing %d bytes of buffer to dsp\n",
280 __func__,
281 prtd->pcm_count);
282 q6asm_write_nolock(prtd->audio_client,
283 prtd->pcm_count,
284 0, 0, NO_TIMESTAMP);
285 atomic_dec(&prtd->out_needed);
286 wake_up(&the_locks.write_wait);
287 };
288 }
289 atomic_set(&prtd->start, 1);
290 break;
291 case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
292 pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
293 __func__);
294 break;
295 default:
296 pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
297 __func__, payload[0], payload[1]);
298 break;
299 }
300 }
301 break;
302 case RESET_EVENTS:
303 pr_debug("%s RESET_EVENTS\n", __func__);
304 prtd->pcm_irq_pos += prtd->pcm_count;
305 atomic_inc(&prtd->out_count);
306 atomic_inc(&prtd->in_count);
307 prtd->reset_event = true;
308 if (atomic_read(&prtd->start))
309 snd_pcm_period_elapsed(substream);
310 wake_up(&the_locks.eos_wait);
311 wake_up(&the_locks.write_wait);
312 wake_up(&the_locks.read_wait);
313 break;
314 default:
315 pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
316 break;
317 }
318}
319
320static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
321{
322 struct snd_pcm_runtime *runtime = substream->runtime;
323 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
324 struct msm_audio *prtd = runtime->private_data;
325 struct msm_plat_data *pdata;
326 struct snd_pcm_hw_params *params;
327 int ret;
328 uint32_t fmt_type = FORMAT_LINEAR_PCM;
329 uint16_t bits_per_sample;
330 uint16_t sample_word_size;
331
332 pdata = (struct msm_plat_data *)
333 dev_get_drvdata(soc_prtd->platform->dev);
334 if (!pdata) {
335 pr_err("%s: platform data not populated\n", __func__);
336 return -EINVAL;
337 }
338 if (!prtd || !prtd->audio_client) {
339 pr_err("%s: private data null or audio client freed\n",
340 __func__);
341 return -EINVAL;
342 }
343 params = &soc_prtd->dpcm[substream->stream].hw_params;
344
345 pr_debug("%s\n", __func__);
346 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
347 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
348 prtd->pcm_irq_pos = 0;
349 /* rate and channels are sent to audio driver */
350 prtd->samp_rate = runtime->rate;
351 prtd->channel_mode = runtime->channels;
352 if (prtd->enabled)
353 return 0;
354
355 prtd->audio_client->perf_mode = pdata->perf_mode;
356 pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode);
357
358 switch (params_format(params)) {
359 case SNDRV_PCM_FORMAT_S32_LE:
360 bits_per_sample = 32;
361 sample_word_size = 32;
362 break;
363 case SNDRV_PCM_FORMAT_S24_LE:
364 bits_per_sample = 24;
365 sample_word_size = 32;
366 break;
367 case SNDRV_PCM_FORMAT_S24_3LE:
368 bits_per_sample = 24;
369 sample_word_size = 24;
370 break;
371 case SNDRV_PCM_FORMAT_S16_LE:
372 default:
373 bits_per_sample = 16;
374 sample_word_size = 16;
375 break;
376 }
377 if (prtd->compress_enable) {
378 fmt_type = FORMAT_GEN_COMPR;
379 pr_debug("%s: Compressed enabled!\n", __func__);
380 ret = q6asm_open_write_compressed(prtd->audio_client, fmt_type,
381 COMPRESSED_PASSTHROUGH_GEN);
382 if (ret < 0) {
383 pr_err("%s: q6asm_open_write_compressed failed (%d)\n",
384 __func__, ret);
385 q6asm_audio_client_free(prtd->audio_client);
386 prtd->audio_client = NULL;
387 return -ENOMEM;
388 }
389 } else {
Dieter Lueckingdfe01252018-09-28 15:03:01 +0200390 if (q6core_get_avcs_api_version_per_service(
391 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
392 ADSP_ASM_API_VERSION_V2)
393 ret = q6asm_open_write_v5(prtd->audio_client,
394 fmt_type, bits_per_sample);
395 else
396 ret = q6asm_open_write_v4(prtd->audio_client,
397 fmt_type, bits_per_sample);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530398
399 if (ret < 0) {
Dieter Lueckingdfe01252018-09-28 15:03:01 +0200400 pr_err("%s: q6asm_open_write failed (%d)\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530401 __func__, ret);
402 q6asm_audio_client_free(prtd->audio_client);
403 prtd->audio_client = NULL;
404 return -ENOMEM;
405 }
406
407 ret = q6asm_send_cal(prtd->audio_client);
408 if (ret < 0)
409 pr_debug("%s : Send cal failed : %d", __func__, ret);
410 }
411 pr_debug("%s: session ID %d\n", __func__,
412 prtd->audio_client->session);
413 prtd->session_id = prtd->audio_client->session;
414
415 if (prtd->compress_enable) {
416 ret = msm_pcm_routing_reg_phy_compr_stream(
417 soc_prtd->dai_link->id,
418 prtd->audio_client->perf_mode,
419 prtd->session_id,
420 SNDRV_PCM_STREAM_PLAYBACK,
421 COMPRESSED_PASSTHROUGH_GEN);
422 } else {
423 ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id,
424 prtd->audio_client->perf_mode,
425 prtd->session_id, substream->stream);
426 }
427 if (ret) {
428 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
429 return ret;
430 }
431 if (prtd->compress_enable) {
432 ret = q6asm_media_format_block_gen_compr(
433 prtd->audio_client, runtime->rate,
434 runtime->channels, !prtd->set_channel_map,
435 prtd->channel_map, bits_per_sample);
436 } else {
Dieter Lueckingdfe01252018-09-28 15:03:01 +0200437
438 if (q6core_get_avcs_api_version_per_service(
439 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
440 ADSP_ASM_API_VERSION_V2) {
441
442 ret = q6asm_media_format_block_multi_ch_pcm_v5(
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530443 prtd->audio_client, runtime->rate,
444 runtime->channels, !prtd->set_channel_map,
445 prtd->channel_map, bits_per_sample,
446 sample_word_size, ASM_LITTLE_ENDIAN,
447 DEFAULT_QF);
Dieter Lueckingdfe01252018-09-28 15:03:01 +0200448 } else {
449 ret = q6asm_media_format_block_multi_ch_pcm_v4(
450 prtd->audio_client, runtime->rate,
451 runtime->channels, !prtd->set_channel_map,
452 prtd->channel_map, bits_per_sample,
453 sample_word_size, ASM_LITTLE_ENDIAN,
454 DEFAULT_QF);
455 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530456 }
457 if (ret < 0)
458 pr_info("%s: CMD Format block failed\n", __func__);
459
460 atomic_set(&prtd->out_count, runtime->periods);
461
462 prtd->enabled = 1;
463 prtd->cmd_pending = 0;
464 prtd->cmd_interrupt = 0;
465
466 return 0;
467}
468
469static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
470{
471 struct snd_pcm_runtime *runtime = substream->runtime;
472 struct msm_audio *prtd = runtime->private_data;
473 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
474 struct msm_plat_data *pdata;
475 struct snd_pcm_hw_params *params;
476 struct msm_pcm_routing_evt event;
477 int ret = 0;
478 int i = 0;
479 uint16_t bits_per_sample = 16;
480 uint16_t sample_word_size;
481
482 pdata = (struct msm_plat_data *)
483 dev_get_drvdata(soc_prtd->platform->dev);
484 if (!pdata) {
485 pr_err("%s: platform data not populated\n", __func__);
486 return -EINVAL;
487 }
488 if (!prtd || !prtd->audio_client) {
489 pr_err("%s: private data null or audio client freed\n",
490 __func__);
491 return -EINVAL;
492 }
493
494 if (prtd->enabled == IDLE) {
495 pr_debug("%s:perf_mode=%d periods=%d\n", __func__,
496 pdata->perf_mode, runtime->periods);
497 params = &soc_prtd->dpcm[substream->stream].hw_params;
498 if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) ||
499 (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE))
500 bits_per_sample = 24;
501 else if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
502 bits_per_sample = 32;
503
504 /* ULL mode is not supported in capture path */
505 if (pdata->perf_mode == LEGACY_PCM_MODE)
506 prtd->audio_client->perf_mode = LEGACY_PCM_MODE;
507 else
508 prtd->audio_client->perf_mode = LOW_LATENCY_PCM_MODE;
509
510 pr_debug("%s Opening %d-ch PCM read stream, perf_mode %d\n",
511 __func__, params_channels(params),
512 prtd->audio_client->perf_mode);
513
Dieter Lueckingdfe01252018-09-28 15:03:01 +0200514 if (q6core_get_avcs_api_version_per_service(
515 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
516 ADSP_ASM_API_VERSION_V2)
517 ret = q6asm_open_read_v5(prtd->audio_client,
518 FORMAT_LINEAR_PCM,
519 bits_per_sample, false, ENC_CFG_ID_NONE);
520 else
521 ret = q6asm_open_read_v4(prtd->audio_client,
522 FORMAT_LINEAR_PCM,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530523 bits_per_sample, false);
524 if (ret < 0) {
525 pr_err("%s: q6asm_open_read failed\n", __func__);
526 q6asm_audio_client_free(prtd->audio_client);
527 prtd->audio_client = NULL;
528 return -ENOMEM;
529 }
530
531 ret = q6asm_send_cal(prtd->audio_client);
532 if (ret < 0)
533 pr_debug("%s : Send cal failed : %d", __func__, ret);
534
535 pr_debug("%s: session ID %d\n",
536 __func__, prtd->audio_client->session);
537 prtd->session_id = prtd->audio_client->session;
538 event.event_func = msm_pcm_route_event_handler;
539 event.priv_data = (void *) prtd;
540 ret = msm_pcm_routing_reg_phy_stream_v2(
541 soc_prtd->dai_link->id,
542 prtd->audio_client->perf_mode,
543 prtd->session_id, substream->stream,
544 event);
545 if (ret) {
546 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
547 return ret;
548 }
549 }
550
551 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
552 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
553 prtd->pcm_irq_pos = 0;
554 /* rate and channels are sent to audio driver */
555 prtd->samp_rate = runtime->rate;
556 prtd->channel_mode = runtime->channels;
557
558 if (prtd->enabled == IDLE || prtd->enabled == STOPPED) {
559 for (i = 0; i < runtime->periods; i++)
560 q6asm_read(prtd->audio_client);
561 prtd->periods = runtime->periods;
562 }
563
564 if (prtd->enabled != IDLE)
565 return 0;
566
567 switch (runtime->format) {
568 case SNDRV_PCM_FORMAT_S32_LE:
569 bits_per_sample = 32;
570 sample_word_size = 32;
571 break;
572 case SNDRV_PCM_FORMAT_S24_LE:
573 bits_per_sample = 24;
574 sample_word_size = 32;
575 break;
576 case SNDRV_PCM_FORMAT_S24_3LE:
577 bits_per_sample = 24;
578 sample_word_size = 24;
579 break;
580 case SNDRV_PCM_FORMAT_S16_LE:
581 default:
582 bits_per_sample = 16;
583 sample_word_size = 16;
584 break;
585 }
586
587 pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n",
588 __func__, prtd->samp_rate, prtd->channel_mode,
589 bits_per_sample, sample_word_size);
Dieter Lueckingdfe01252018-09-28 15:03:01 +0200590
591 if (q6core_get_avcs_api_version_per_service(
592 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
593 ADSP_ASM_API_VERSION_V2)
594 ret = q6asm_enc_cfg_blk_pcm_format_support_v5(
595 prtd->audio_client,
596 prtd->samp_rate,
597 prtd->channel_mode,
598 bits_per_sample,
599 sample_word_size,
600 ASM_LITTLE_ENDIAN,
601 DEFAULT_QF);
602 else
603 ret = q6asm_enc_cfg_blk_pcm_format_support_v4(
604 prtd->audio_client,
605 prtd->samp_rate,
606 prtd->channel_mode,
607 bits_per_sample,
608 sample_word_size,
609 ASM_LITTLE_ENDIAN,
610 DEFAULT_QF);
611
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530612 if (ret < 0)
613 pr_debug("%s: cmd cfg pcm was block failed", __func__);
614
615 prtd->enabled = RUNNING;
616
617 return ret;
618}
619
620static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
621{
622 int ret = 0;
623 struct snd_pcm_runtime *runtime = substream->runtime;
624 struct msm_audio *prtd = runtime->private_data;
625
626 switch (cmd) {
627 case SNDRV_PCM_TRIGGER_START:
628 case SNDRV_PCM_TRIGGER_RESUME:
629 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
630 pr_debug("%s: Trigger start\n", __func__);
631 ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
632 break;
633 case SNDRV_PCM_TRIGGER_STOP:
634 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
635 atomic_set(&prtd->start, 0);
636 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
637 prtd->enabled = STOPPED;
638 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
Sidipotu Ashok5c6855b2019-01-08 15:58:37 +0530639 if (!ret)
640 ret = q6asm_cmd_nowait(prtd->audio_client,
641 CMD_FLUSH);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530642 break;
643 }
644 /* pending CMD_EOS isn't expected */
645 WARN_ON_ONCE(test_bit(CMD_EOS, &prtd->cmd_pending));
646 set_bit(CMD_EOS, &prtd->cmd_pending);
647 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
648 if (ret)
649 clear_bit(CMD_EOS, &prtd->cmd_pending);
650 break;
651 case SNDRV_PCM_TRIGGER_SUSPEND:
652 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
653 pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
654 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
655 atomic_set(&prtd->start, 0);
656 break;
657 default:
658 ret = -EINVAL;
659 break;
660 }
661
662 return ret;
663}
664
665static int msm_pcm_open(struct snd_pcm_substream *substream)
666{
667 struct snd_pcm_runtime *runtime = substream->runtime;
668 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
669 struct msm_audio *prtd;
Banajit Goswami616e68c2017-10-27 01:31:19 -0700670 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530671 int ret = 0;
672
Banajit Goswami616e68c2017-10-27 01:31:19 -0700673 pdata = (struct msm_plat_data *)
674 dev_get_drvdata(soc_prtd->platform->dev);
675 if (!pdata) {
676 pr_err("%s: platform data not populated\n", __func__);
677 return -EINVAL;
678 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530679 prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
680 if (prtd == NULL)
681 return -ENOMEM;
682
683 prtd->substream = substream;
684 prtd->audio_client = q6asm_audio_client_alloc(
685 (app_cb)event_handler, prtd);
686 if (!prtd->audio_client) {
687 pr_info("%s: Could not allocate memory\n", __func__);
688 kfree(prtd);
Vatsal Bucha321a7442018-06-01 12:05:25 +0530689 prtd = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530690 return -ENOMEM;
691 }
692
693 prtd->audio_client->dev = soc_prtd->platform->dev;
694
695 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
696 runtime->hw = msm_pcm_hardware_playback;
697
698 /* Capture path */
699 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
700 runtime->hw = msm_pcm_hardware_capture;
701 else {
702 pr_err("Invalid Stream type %d\n", substream->stream);
703 return -EINVAL;
704 }
705
706 ret = snd_pcm_hw_constraint_list(runtime, 0,
707 SNDRV_PCM_HW_PARAM_RATE,
708 &constraints_sample_rates);
709 if (ret < 0)
710 pr_info("snd_pcm_hw_constraint_list failed\n");
711 /* Ensure that buffer size is a multiple of period size */
712 ret = snd_pcm_hw_constraint_integer(runtime,
713 SNDRV_PCM_HW_PARAM_PERIODS);
714 if (ret < 0)
715 pr_info("snd_pcm_hw_constraint_integer failed\n");
716
717 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
718 ret = snd_pcm_hw_constraint_minmax(runtime,
719 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
720 PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
721 PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
722 if (ret < 0) {
723 pr_err("constraint for buffer bytes min max ret = %d\n",
724 ret);
725 }
726 }
727
728 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
729 ret = snd_pcm_hw_constraint_minmax(runtime,
730 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
731 CAPTURE_MIN_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
732 CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
733 if (ret < 0) {
734 pr_err("constraint for buffer bytes min max ret = %d\n",
735 ret);
736 }
737 }
738 ret = snd_pcm_hw_constraint_step(runtime, 0,
739 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
740 if (ret < 0) {
741 pr_err("constraint for period bytes step ret = %d\n",
742 ret);
743 }
744 ret = snd_pcm_hw_constraint_step(runtime, 0,
745 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
746 if (ret < 0) {
747 pr_err("constraint for buffer bytes step ret = %d\n",
748 ret);
749 }
750
751 prtd->enabled = IDLE;
752 prtd->dsp_cnt = 0;
753 prtd->set_channel_map = false;
754 prtd->reset_event = false;
755 runtime->private_data = prtd;
756 msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
Banajit Goswami616e68c2017-10-27 01:31:19 -0700757 /* Vote to update the Rx thread priority to RT Thread for playback */
758 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
759 (pdata->perf_mode == LOW_LATENCY_PCM_MODE))
760 apr_start_rx_rt(prtd->audio_client->apr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530761
762 return 0;
763}
764
765static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
766 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
767{
768 int ret = 0;
769 int fbytes = 0;
770 int xfer = 0;
771 char *bufptr = NULL;
772 void *data = NULL;
773 uint32_t idx = 0;
774 uint32_t size = 0;
775 uint32_t retries = 0;
776
777 struct snd_pcm_runtime *runtime = substream->runtime;
778 struct msm_audio *prtd = runtime->private_data;
779
780 fbytes = frames_to_bytes(runtime, frames);
781 pr_debug("%s: prtd->out_count = %d\n",
782 __func__, atomic_read(&prtd->out_count));
783
784 while ((fbytes > 0) && (retries < MAX_PB_COPY_RETRIES)) {
785 if (prtd->reset_event) {
786 pr_err("%s: In SSR return ENETRESET before wait\n",
787 __func__);
788 return -ENETRESET;
789 }
790
791 ret = wait_event_timeout(the_locks.write_wait,
792 (atomic_read(&prtd->out_count)), 5 * HZ);
793 if (!ret) {
794 pr_err("%s: wait_event_timeout failed\n", __func__);
795 ret = -ETIMEDOUT;
796 goto fail;
797 }
798 ret = 0;
799
800 if (prtd->reset_event) {
801 pr_err("%s: In SSR return ENETRESET after wait\n",
802 __func__);
803 return -ENETRESET;
804 }
805
806 if (!atomic_read(&prtd->out_count)) {
807 pr_err("%s: pcm stopped out_count 0\n", __func__);
808 return 0;
809 }
810
811 data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size,
812 &idx);
813 if (data == NULL) {
814 retries++;
815 continue;
816 } else {
817 retries = 0;
818 }
819
820 if (fbytes > size)
821 xfer = size;
822 else
823 xfer = fbytes;
824
825 bufptr = data;
826 if (bufptr) {
827 pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
828 __func__, fbytes, xfer, size);
829 if (copy_from_user(bufptr, buf, xfer)) {
830 ret = -EFAULT;
831 pr_err("%s: copy_from_user failed\n",
832 __func__);
833 q6asm_cpu_buf_release(IN, prtd->audio_client);
834 goto fail;
835 }
836 buf += xfer;
837 fbytes -= xfer;
838 pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes,
839 xfer);
840 if (atomic_read(&prtd->start)) {
841 pr_debug("%s:writing %d bytes of buffer to dsp\n",
842 __func__, xfer);
843 ret = q6asm_write(prtd->audio_client, xfer,
844 0, 0, NO_TIMESTAMP);
845 if (ret < 0) {
846 ret = -EFAULT;
847 q6asm_cpu_buf_release(IN,
848 prtd->audio_client);
849 goto fail;
850 }
851 } else
852 atomic_inc(&prtd->out_needed);
853 atomic_dec(&prtd->out_count);
854 }
855 }
856fail:
857 if (retries >= MAX_PB_COPY_RETRIES)
858 ret = -ENOMEM;
859
860 return ret;
861}
862
863static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
864{
865 struct snd_pcm_runtime *runtime = substream->runtime;
866 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
867 struct msm_audio *prtd = runtime->private_data;
Banajit Goswami616e68c2017-10-27 01:31:19 -0700868 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530869 uint32_t timeout;
870 int dir = 0;
871 int ret = 0;
872
873 pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
874
Ajit Pandey3d7b9a22019-09-05 16:26:01 +0530875 pdata = (struct msm_plat_data *)
876 dev_get_drvdata(soc_prtd->platform->dev);
877 if (!pdata) {
878 pr_err("%s: platform data is NULL\n", __func__);
879 return -EINVAL;
880 }
881
882 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530883 if (prtd->audio_client) {
884 dir = IN;
885
Banajit Goswami616e68c2017-10-27 01:31:19 -0700886 /*
887 * Unvote to downgrade the Rx thread priority from
888 * RT Thread for Low-Latency use case.
889 */
890 pdata = (struct msm_plat_data *)
891 dev_get_drvdata(soc_prtd->platform->dev);
892 if (pdata) {
893 if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
894 apr_end_rx_rt(prtd->audio_client->apr);
895 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530896 /* determine timeout length */
897 if (runtime->frame_bits == 0 || runtime->rate == 0) {
898 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
899 } else {
900 timeout = (runtime->period_size *
901 CMD_EOS_TIMEOUT_MULTIPLIER) /
902 ((runtime->frame_bits / 8) *
903 runtime->rate);
904 if (timeout < CMD_EOS_MIN_TIMEOUT_LENGTH)
905 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
906 }
907 pr_debug("%s: CMD_EOS timeout is %d\n", __func__, timeout);
908
909 ret = wait_event_timeout(the_locks.eos_wait,
910 !test_bit(CMD_EOS, &prtd->cmd_pending),
911 timeout);
912 if (!ret)
913 pr_err("%s: CMD_EOS failed, cmd_pending 0x%lx\n",
914 __func__, prtd->cmd_pending);
915 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
916 q6asm_audio_client_buf_free_contiguous(dir,
917 prtd->audio_client);
918 q6asm_audio_client_free(prtd->audio_client);
919 }
920 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
921 SNDRV_PCM_STREAM_PLAYBACK);
922 msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
923 kfree(prtd);
924 runtime->private_data = NULL;
Ajit Pandey3d7b9a22019-09-05 16:26:01 +0530925 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530926
927 return 0;
928}
929
930static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
931 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
932 snd_pcm_uframes_t frames)
933{
934 int ret = 0;
935 int fbytes = 0;
936 int xfer;
937 char *bufptr;
938 void *data = NULL;
Vignesh Kulothungan60630ed2019-05-22 11:53:08 -0700939 uint32_t idx = 0;
940 uint32_t size = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530941 uint32_t offset = 0;
942 struct snd_pcm_runtime *runtime = substream->runtime;
943 struct msm_audio *prtd = substream->runtime->private_data;
944
945
946 pr_debug("%s\n", __func__);
947 fbytes = frames_to_bytes(runtime, frames);
948
949 pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
950 pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
951 pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
952
953 if (prtd->reset_event) {
954 pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
955 return -ENETRESET;
956 }
957 ret = wait_event_timeout(the_locks.read_wait,
958 (atomic_read(&prtd->in_count)), 5 * HZ);
959 if (!ret) {
960 pr_debug("%s: wait_event_timeout failed\n", __func__);
961 goto fail;
962 }
963 if (prtd->reset_event) {
964 pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
965 return -ENETRESET;
966 }
967 if (!atomic_read(&prtd->in_count)) {
968 pr_debug("%s: pcm stopped in_count 0\n", __func__);
969 return 0;
970 }
971 pr_debug("Checking if valid buffer is available...%pK\n",
972 data);
973 data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
974 bufptr = data;
975 pr_debug("Size = %d\n", size);
976 pr_debug("fbytes = %d\n", fbytes);
977 pr_debug("idx = %d\n", idx);
978 if (bufptr) {
979 xfer = fbytes;
980 if (xfer > size)
981 xfer = size;
982 offset = prtd->in_frame_info[idx].offset;
983 pr_debug("Offset value = %d\n", offset);
984 if (copy_to_user(buf, bufptr+offset, xfer)) {
985 pr_err("Failed to copy buf to user\n");
986 ret = -EFAULT;
987 q6asm_cpu_buf_release(OUT, prtd->audio_client);
988 goto fail;
989 }
990 fbytes -= xfer;
991 size -= xfer;
992 prtd->in_frame_info[idx].offset += xfer;
993 pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
994 __func__, fbytes, size, xfer);
995 pr_debug(" Sending next buffer to dsp\n");
996 memset(&prtd->in_frame_info[idx], 0,
997 sizeof(struct msm_audio_in_frame_info));
998 atomic_dec(&prtd->in_count);
999 ret = q6asm_read(prtd->audio_client);
1000 if (ret < 0) {
1001 pr_err("q6asm read failed\n");
1002 ret = -EFAULT;
1003 q6asm_cpu_buf_release(OUT, prtd->audio_client);
1004 goto fail;
1005 }
1006 } else
1007 pr_err("No valid buffer\n");
1008
1009 pr_debug("Returning from capture_copy... %d\n", ret);
1010fail:
1011 return ret;
1012}
1013
1014static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
1015{
1016 struct snd_pcm_runtime *runtime = substream->runtime;
1017 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
1018 struct msm_audio *prtd = runtime->private_data;
1019 int dir = OUT;
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301020 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301021
1022 pr_debug("%s\n", __func__);
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301023
1024 pdata = (struct msm_plat_data *)
1025 dev_get_drvdata(soc_prtd->platform->dev);
1026 if (!pdata) {
1027 pr_err("%s: platform data is NULL\n", __func__);
1028 return -EINVAL;
1029 }
1030
1031 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301032 if (prtd->audio_client) {
1033 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
1034 q6asm_audio_client_buf_free_contiguous(dir,
1035 prtd->audio_client);
1036 q6asm_audio_client_free(prtd->audio_client);
1037 }
1038
1039 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
1040 SNDRV_PCM_STREAM_CAPTURE);
1041 kfree(prtd);
1042 runtime->private_data = NULL;
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301043 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301044
1045 return 0;
1046}
1047
1048static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
1049 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
1050{
1051 int ret = 0;
1052
1053 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1054 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
1055 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1056 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
1057 return ret;
1058}
1059
1060static int msm_pcm_close(struct snd_pcm_substream *substream)
1061{
1062 int ret = 0;
1063
1064 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1065 ret = msm_pcm_playback_close(substream);
1066 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1067 ret = msm_pcm_capture_close(substream);
1068 return ret;
1069}
1070
1071static int msm_pcm_prepare(struct snd_pcm_substream *substream)
1072{
1073 int ret = 0;
1074
1075 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1076 ret = msm_pcm_playback_prepare(substream);
1077 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1078 ret = msm_pcm_capture_prepare(substream);
1079 return ret;
1080}
1081
1082static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
1083{
1084
1085 struct snd_pcm_runtime *runtime = substream->runtime;
1086 struct msm_audio *prtd = runtime->private_data;
1087
1088 if (prtd->pcm_irq_pos >= prtd->pcm_size)
1089 prtd->pcm_irq_pos = 0;
1090
1091 pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
1092 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
1093}
1094
1095static int msm_pcm_mmap(struct snd_pcm_substream *substream,
1096 struct vm_area_struct *vma)
1097{
1098 struct snd_pcm_runtime *runtime = substream->runtime;
1099 struct msm_audio *prtd = runtime->private_data;
1100 struct audio_client *ac = prtd->audio_client;
1101 struct audio_port_data *apd = ac->port;
1102 struct audio_buffer *ab;
1103 int dir = -1;
1104
1105 prtd->mmap_flag = 1;
1106
1107 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1108 dir = IN;
1109 else
1110 dir = OUT;
1111 ab = &(apd[dir].buf[0]);
1112
1113 return msm_audio_ion_mmap(ab, vma);
1114}
1115
1116static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
1117 struct snd_pcm_hw_params *params)
1118{
1119 struct snd_pcm_runtime *runtime = substream->runtime;
1120 struct msm_audio *prtd = runtime->private_data;
1121 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
1122 struct audio_buffer *buf;
1123 int dir, ret;
1124
1125 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1126 dir = IN;
1127 else
1128 dir = OUT;
1129 ret = q6asm_audio_client_buf_alloc_contiguous(dir,
1130 prtd->audio_client,
1131 (params_buffer_bytes(params) / params_periods(params)),
1132 params_periods(params));
1133 if (ret < 0) {
1134 pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
1135 ret);
1136 return -ENOMEM;
1137 }
1138 buf = prtd->audio_client->port[dir].buf;
1139 if (buf == NULL || buf[0].data == NULL)
1140 return -ENOMEM;
1141
1142 pr_debug("%s:buf = %pK\n", __func__, buf);
1143 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
1144 dma_buf->dev.dev = substream->pcm->card->dev;
1145 dma_buf->private_data = NULL;
1146 dma_buf->area = buf[0].data;
1147 dma_buf->addr = buf[0].phys;
1148 dma_buf->bytes = params_buffer_bytes(params);
1149 if (!dma_buf->area)
1150 return -ENOMEM;
1151
1152 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
1153 return 0;
1154}
1155
1156static const struct snd_pcm_ops msm_pcm_ops = {
1157 .open = msm_pcm_open,
1158 .copy = msm_pcm_copy,
1159 .hw_params = msm_pcm_hw_params,
1160 .close = msm_pcm_close,
1161 .ioctl = snd_pcm_lib_ioctl,
1162 .prepare = msm_pcm_prepare,
1163 .trigger = msm_pcm_trigger,
1164 .pointer = msm_pcm_pointer,
1165 .mmap = msm_pcm_mmap,
1166};
1167
1168static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
1169 struct snd_ctl_elem_value *ucontrol)
1170{
1171 struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
1172 struct snd_soc_platform *platform = snd_soc_component_to_platform(pcm);
1173 struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
1174 struct snd_pcm_substream *substream;
1175 struct msm_audio *prtd;
1176 int ret = 0;
1177 struct msm_adsp_event_data *event_data = NULL;
Aditya Bavanari2e3341d2018-02-23 12:58:57 +05301178 uint64_t actual_payload_len = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301179
1180 if (!pdata) {
1181 pr_err("%s pdata is NULL\n", __func__);
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301182 return -ENODEV;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301183 }
1184
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301185 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301186 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1187 if (!substream) {
1188 pr_err("%s substream not found\n", __func__);
1189 ret = -EINVAL;
1190 goto done;
1191 }
1192
1193 if (!substream->runtime) {
1194 pr_err("%s substream runtime not found\n", __func__);
1195 ret = -EINVAL;
1196 goto done;
1197 }
1198
1199 prtd = substream->runtime->private_data;
Vatsal Bucha321a7442018-06-01 12:05:25 +05301200 if (prtd == NULL) {
1201 pr_err("%s prtd is null.\n", __func__);
1202 ret = -EINVAL;
1203 goto done;
1204 }
1205
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301206 if (prtd->audio_client == NULL) {
1207 pr_err("%s prtd is null.\n", __func__);
1208 ret = -EINVAL;
1209 goto done;
1210 }
1211
1212 event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
1213 if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
1214 (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
1215 pr_err("%s: invalid event_type=%d",
1216 __func__, event_data->event_type);
1217 ret = -EINVAL;
1218 goto done;
1219 }
1220
Aditya Bavanari2e3341d2018-02-23 12:58:57 +05301221 actual_payload_len = sizeof(struct msm_adsp_event_data) +
1222 event_data->payload_len;
1223 if (actual_payload_len >= U32_MAX) {
1224 pr_err("%s payload length 0x%X exceeds limit",
1225 __func__, event_data->payload_len);
1226 ret = -EINVAL;
1227 goto done;
1228 }
1229
Xiaojun Sangae3d8862018-03-23 08:57:33 +08001230 if (event_data->payload_len > sizeof(ucontrol->value.bytes.data)
1231 - sizeof(struct msm_adsp_event_data)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301232 pr_err("%s param length=%d exceeds limit",
1233 __func__, event_data->payload_len);
1234 ret = -EINVAL;
1235 goto done;
1236 }
1237
1238 ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
1239 if (ret < 0)
1240 pr_err("%s: failed to send stream event cmd, err = %d\n",
1241 __func__, ret);
1242done:
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301243 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301244 return ret;
1245}
1246
1247static int msm_pcm_add_audio_adsp_stream_cmd_control(
1248 struct snd_soc_pcm_runtime *rtd)
1249{
1250 const char *mixer_ctl_name = DSP_STREAM_CMD;
1251 const char *deviceNo = "NN";
1252 char *mixer_str = NULL;
1253 int ctl_len = 0, ret = 0;
1254 struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
1255 {
1256 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1257 .name = "?",
1258 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1259 .info = msm_adsp_stream_cmd_info,
1260 .put = msm_pcm_adsp_stream_cmd_put,
1261 .private_value = 0,
1262 }
1263 };
1264
1265 if (!rtd) {
1266 pr_err("%s rtd is NULL\n", __func__);
1267 ret = -EINVAL;
1268 goto done;
1269 }
1270
1271 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1272 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1273 if (!mixer_str) {
1274 ret = -ENOMEM;
1275 goto done;
1276 }
1277
1278 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1279 fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
1280 fe_audio_adsp_stream_cmd_config_control[0].private_value =
1281 rtd->dai_link->id;
1282 pr_debug("Registering new mixer ctl %s\n", mixer_str);
1283 ret = snd_soc_add_platform_controls(rtd->platform,
1284 fe_audio_adsp_stream_cmd_config_control,
1285 ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
1286 if (ret < 0)
1287 pr_err("%s: failed add ctl %s. err = %d\n",
1288 __func__, mixer_str, ret);
1289
1290 kfree(mixer_str);
1291done:
1292 return ret;
1293}
1294
1295static int msm_pcm_add_audio_adsp_stream_callback_control(
1296 struct snd_soc_pcm_runtime *rtd)
1297{
1298 const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
1299 const char *deviceNo = "NN";
1300 char *mixer_str = NULL;
1301 int ctl_len = 0, ret = 0;
1302 struct snd_kcontrol *kctl;
1303
1304 struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
1305 {
1306 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1307 .name = "?",
1308 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1309 .info = msm_adsp_stream_callback_info,
1310 .get = msm_adsp_stream_callback_get,
1311 .private_value = 0,
1312 }
1313 };
1314
1315 if (!rtd) {
1316 pr_err("%s NULL rtd\n", __func__);
1317 ret = -EINVAL;
1318 goto done;
1319 }
1320
1321 pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
1322 __func__, rtd->dai_link->name, rtd->dai_link->id,
1323 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
1324 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1325 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1326 if (!mixer_str) {
1327 ret = -ENOMEM;
1328 goto done;
1329 }
1330
1331 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1332 fe_audio_adsp_callback_config_control[0].name = mixer_str;
1333 fe_audio_adsp_callback_config_control[0].private_value =
1334 rtd->dai_link->id;
1335 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1336 ret = snd_soc_add_platform_controls(rtd->platform,
1337 fe_audio_adsp_callback_config_control,
1338 ARRAY_SIZE(fe_audio_adsp_callback_config_control));
1339 if (ret < 0) {
1340 pr_err("%s: failed to add ctl %s. err = %d\n",
1341 __func__, mixer_str, ret);
1342 ret = -EINVAL;
1343 goto free_mixer_str;
1344 }
1345
1346 kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
1347 if (!kctl) {
1348 pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
1349 ret = -EINVAL;
1350 goto free_mixer_str;
1351 }
1352
1353 kctl->private_data = NULL;
1354
1355free_mixer_str:
1356 kfree(mixer_str);
1357done:
1358 return ret;
1359}
1360
1361static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
1362{
1363 int rc = 0;
1364
1365 if (prtd && prtd->audio_client) {
1366 pr_debug("%s: channels %d volume 0x%x\n", __func__,
1367 prtd->channel_mode, volume);
1368 rc = q6asm_set_volume(prtd->audio_client, volume);
1369 if (rc < 0) {
1370 pr_err("%s: Send Volume command failed rc=%d\n",
1371 __func__, rc);
1372 }
1373 }
1374 return rc;
1375}
1376
1377static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
1378 struct snd_ctl_elem_value *ucontrol)
1379{
1380 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301381 struct msm_plat_data *pdata = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301382 struct snd_pcm_substream *substream =
Haynes Mathew Georged00e1062018-04-06 18:18:51 -07001383 vol->pcm->streams[vol->stream].substream;
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301384 struct snd_soc_pcm_runtime *soc_prtd = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301385 struct msm_audio *prtd;
1386
1387 pr_debug("%s\n", __func__);
1388 if (!substream) {
1389 pr_err("%s substream not found\n", __func__);
1390 return -ENODEV;
1391 }
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301392 soc_prtd = substream->private_data;
1393 if (!substream->runtime || !soc_prtd) {
1394 pr_debug("%s substream runtime or private_data not found\n",
1395 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301396 return 0;
1397 }
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301398
1399 pdata = (struct msm_plat_data *)
1400 dev_get_drvdata(soc_prtd->platform->dev);
1401 if (!pdata) {
1402 pr_err("%s: pdata not found\n", __func__);
1403 return -ENODEV;
1404 }
1405
1406 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301407 prtd = substream->runtime->private_data;
1408 if (prtd)
1409 ucontrol->value.integer.value[0] = prtd->volume;
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301410 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301411 return 0;
1412}
1413
1414static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
1415 struct snd_ctl_elem_value *ucontrol)
1416{
1417 int rc = 0;
1418 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
1419 struct snd_pcm_substream *substream =
Haynes Mathew Georged00e1062018-04-06 18:18:51 -07001420 vol->pcm->streams[vol->stream].substream;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301421 struct msm_audio *prtd;
1422 int volume = ucontrol->value.integer.value[0];
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301423 struct msm_plat_data *pdata = NULL;
1424 struct snd_soc_pcm_runtime *soc_prtd = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301425
1426 pr_debug("%s: volume : 0x%x\n", __func__, volume);
1427 if (!substream) {
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301428 pr_err("%s: substream not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301429 return -ENODEV;
1430 }
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301431 soc_prtd = substream->private_data;
1432 if (!substream->runtime || !soc_prtd) {
1433 pr_err("%s: substream runtime or private_data not found\n",
1434 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301435 return 0;
1436 }
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301437
1438 pdata = (struct msm_plat_data *)
1439 dev_get_drvdata(soc_prtd->platform->dev);
1440 if (!pdata) {
1441 pr_err("%s: pdata not found\n", __func__);
1442 return -ENODEV;
1443 }
1444
1445 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301446 prtd = substream->runtime->private_data;
1447 if (prtd) {
1448 rc = msm_pcm_set_volume(prtd, volume);
1449 prtd->volume = volume;
1450 }
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301451 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301452 return rc;
1453}
1454
Haynes Mathew Georged00e1062018-04-06 18:18:51 -07001455static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd,
1456 int stream)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301457{
1458 int ret = 0;
1459 struct snd_pcm *pcm = rtd->pcm;
1460 struct snd_pcm_volume *volume_info;
1461 struct snd_kcontrol *kctl;
1462
Haynes Mathew Georged00e1062018-04-06 18:18:51 -07001463 dev_dbg(rtd->dev, "%s, volume control add\n", __func__);
1464 ret = snd_pcm_add_volume_ctls(pcm, stream,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301465 NULL, 1, rtd->dai_link->id,
1466 &volume_info);
1467 if (ret < 0) {
1468 pr_err("%s volume control failed ret %d\n", __func__, ret);
1469 return ret;
1470 }
1471 kctl = volume_info->kctl;
1472 kctl->put = msm_pcm_volume_ctl_put;
1473 kctl->get = msm_pcm_volume_ctl_get;
1474 kctl->tlv.p = msm_pcm_vol_gain;
1475 return 0;
1476}
1477
1478static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
1479 struct snd_ctl_elem_info *uinfo)
1480{
1481 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1482 uinfo->count = 1;
1483 uinfo->value.integer.min = 0;
1484 uinfo->value.integer.max = 0x2000;
1485 return 0;
1486}
1487
1488static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
1489 struct snd_ctl_elem_value *ucontrol)
1490{
1491 struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
1492 struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
1493 struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
1494 struct snd_pcm_substream *substream;
1495 struct msm_audio *prtd;
1496
1497 if (!pdata) {
1498 pr_err("%s pdata is NULL\n", __func__);
1499 return -ENODEV;
1500 }
1501 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1502 if (!substream) {
1503 pr_err("%s substream not found\n", __func__);
1504 return -EINVAL;
1505 }
1506 if (!substream->runtime) {
1507 pr_err("%s substream runtime not found\n", __func__);
1508 return 0;
1509 }
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301510 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301511 prtd = substream->runtime->private_data;
1512 if (prtd)
1513 ucontrol->value.integer.value[0] = prtd->compress_enable;
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301514 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301515 return 0;
1516}
1517
1518static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
1519 struct snd_ctl_elem_value *ucontrol)
1520{
1521 int rc = 0;
1522 struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
1523 struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
1524 struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
1525 struct snd_pcm_substream *substream;
1526 struct msm_audio *prtd;
1527 int compress = ucontrol->value.integer.value[0];
1528
1529 if (!pdata) {
1530 pr_err("%s pdata is NULL\n", __func__);
1531 return -ENODEV;
1532 }
1533 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1534 pr_debug("%s: compress : 0x%x\n", __func__, compress);
1535 if (!substream) {
1536 pr_err("%s substream not found\n", __func__);
1537 return -EINVAL;
1538 }
1539 if (!substream->runtime) {
1540 pr_err("%s substream runtime not found\n", __func__);
1541 return 0;
1542 }
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301543 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301544 prtd = substream->runtime->private_data;
1545 if (prtd) {
1546 pr_debug("%s: setting compress flag to 0x%x\n",
1547 __func__, compress);
1548 prtd->compress_enable = compress;
1549 }
Prasad Kumpatlaade35f02019-10-15 15:06:44 +05301550 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301551 return rc;
1552}
1553
1554static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
1555{
1556 const char *mixer_ctl_name = "Playback ";
1557 const char *mixer_ctl_end_name = " Compress";
1558 const char *deviceNo = "NN";
1559 char *mixer_str = NULL;
1560 int ctl_len;
1561 int ret = 0;
1562 struct msm_plat_data *pdata;
1563 struct snd_kcontrol_new pcm_compress_control[1] = {
1564 {
1565 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1566 .name = "?",
1567 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1568 .info = msm_pcm_compress_ctl_info,
1569 .get = msm_pcm_compress_ctl_get,
1570 .put = msm_pcm_compress_ctl_put,
1571 .private_value = 0,
1572 }
1573 };
1574
1575 if (!rtd) {
1576 pr_err("%s: NULL rtd\n", __func__);
1577 return -EINVAL;
1578 }
1579
1580 ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
1581 strlen(mixer_ctl_end_name) + 1;
1582 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1583
1584 if (!mixer_str)
1585 return -ENOMEM;
1586
1587 snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
1588 rtd->pcm->device, mixer_ctl_end_name);
1589
1590 pcm_compress_control[0].name = mixer_str;
1591 pcm_compress_control[0].private_value = rtd->dai_link->id;
1592 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1593 pdata = dev_get_drvdata(rtd->platform->dev);
1594 if (pdata) {
1595 if (!pdata->pcm) {
1596 pdata->pcm = rtd->pcm;
1597 snd_soc_add_platform_controls(rtd->platform,
1598 pcm_compress_control,
1599 ARRAY_SIZE
1600 (pcm_compress_control));
1601 pr_debug("%s: add control success plt = %pK\n",
1602 __func__, rtd->platform);
1603 }
1604 } else {
1605 pr_err("%s: NULL pdata\n", __func__);
1606 ret = -EINVAL;
1607 }
1608 kfree(mixer_str);
1609 return ret;
1610}
1611
1612static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1613 struct snd_ctl_elem_value *ucontrol)
1614{
1615 int i;
1616 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1617 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1618 struct snd_pcm_substream *substream;
1619 struct msm_audio *prtd;
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301620 struct snd_soc_pcm_runtime *rtd = NULL;
1621 struct msm_plat_data *pdata = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301622
1623 pr_debug("%s", __func__);
1624 substream = snd_pcm_chmap_substream(info, idx);
1625 if (!substream)
1626 return -ENODEV;
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301627
1628 rtd = substream->private_data;
1629 if (rtd) {
1630 pdata = (struct msm_plat_data *)
1631 dev_get_drvdata(rtd->platform->dev);
1632 if (!pdata) {
1633 pr_err("%s: pdata not found\n", __func__);
1634 return -ENODEV;
1635 }
1636 }
1637
1638 if (!substream->runtime || !rtd)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301639 return 0;
1640
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301641 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301642 prtd = substream->runtime->private_data;
1643 if (prtd) {
1644 prtd->set_channel_map = true;
Dieter Lueckingdfe01252018-09-28 15:03:01 +02001645 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301646 prtd->channel_map[i] =
1647 (char)(ucontrol->value.integer.value[i]);
1648 }
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301649 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301650 return 0;
1651}
1652
1653static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
1654 struct snd_ctl_elem_value *ucontrol)
1655{
1656 int i;
1657 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1658 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1659 struct snd_pcm_substream *substream;
1660 struct msm_audio *prtd;
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301661 struct snd_soc_pcm_runtime *rtd = NULL;
1662 struct msm_plat_data *pdata = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301663
1664 pr_debug("%s", __func__);
1665 substream = snd_pcm_chmap_substream(info, idx);
1666 if (!substream)
1667 return -ENODEV;
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301668
1669 rtd = substream->private_data;
1670 if (rtd) {
1671 pdata = (struct msm_plat_data *)
1672 dev_get_drvdata(rtd->platform->dev);
1673 if (!pdata) {
1674 pr_err("%s: pdata not found\n", __func__);
1675 return -ENODEV;
1676 }
1677 }
1678
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301679 memset(ucontrol->value.integer.value, 0,
1680 sizeof(ucontrol->value.integer.value));
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301681 if (!substream->runtime || !rtd)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301682 return 0; /* no channels set */
1683
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301684 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301685 prtd = substream->runtime->private_data;
1686
1687 if (prtd && prtd->set_channel_map == true) {
Dieter Lueckingdfe01252018-09-28 15:03:01 +02001688 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301689 ucontrol->value.integer.value[i] =
1690 (int)prtd->channel_map[i];
1691 } else {
Dieter Lueckingdfe01252018-09-28 15:03:01 +02001692 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301693 ucontrol->value.integer.value[i] = 0;
1694 }
1695
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05301696 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301697 return 0;
1698}
1699
1700static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
1701{
1702 struct snd_pcm *pcm = rtd->pcm;
1703 struct snd_pcm_chmap *chmap_info;
1704 struct snd_kcontrol *kctl;
1705 char device_num[12];
1706 int i, ret = 0;
1707
1708 pr_debug("%s, Channel map cntrl add\n", __func__);
1709 ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1710 snd_pcm_std_chmaps,
Dieter Lueckingdfe01252018-09-28 15:03:01 +02001711 PCM_FORMAT_MAX_NUM_CHANNEL_V8, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301712 &chmap_info);
1713 if (ret < 0) {
1714 pr_err("%s, channel map cntrl add failed\n", __func__);
1715 return ret;
1716 }
1717 kctl = chmap_info->kctl;
1718 for (i = 0; i < kctl->count; i++)
1719 kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
1720 snprintf(device_num, sizeof(device_num), "%d", pcm->device);
1721 strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
1722 pr_debug("%s, Overwriting channel map control name to: %s\n",
1723 __func__, kctl->id.name);
1724 kctl->put = msm_pcm_chmap_ctl_put;
1725 kctl->get = msm_pcm_chmap_ctl_get;
1726 return 0;
1727}
1728
1729static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1730 struct snd_ctl_elem_value *ucontrol)
1731{
1732 u64 fe_id = kcontrol->private_value;
1733 int session_type = SESSION_TYPE_RX;
1734 int be_id = ucontrol->value.integer.value[3];
1735 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1736 int ret = 0;
1737
1738 cfg_data.app_type = ucontrol->value.integer.value[0];
1739 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1740 if (ucontrol->value.integer.value[2] != 0)
1741 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1742 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1743 __func__, fe_id, session_type, be_id,
1744 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1745 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1746 be_id, &cfg_data);
1747 if (ret < 0)
1748 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1749 __func__, ret);
1750
1751 return ret;
1752}
1753
1754static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1755 struct snd_ctl_elem_value *ucontrol)
1756{
1757 u64 fe_id = kcontrol->private_value;
1758 int session_type = SESSION_TYPE_RX;
1759 int be_id = 0;
1760 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1761 int ret = 0;
1762
1763 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1764 &be_id, &cfg_data);
1765 if (ret < 0) {
1766 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1767 __func__, ret);
1768 goto done;
1769 }
1770
1771 ucontrol->value.integer.value[0] = cfg_data.app_type;
1772 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1773 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1774 ucontrol->value.integer.value[3] = be_id;
1775 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1776 __func__, fe_id, session_type, be_id,
1777 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1778done:
1779 return ret;
1780}
1781
1782static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1783 struct snd_ctl_elem_value *ucontrol)
1784{
1785 u64 fe_id = kcontrol->private_value;
1786 int session_type = SESSION_TYPE_TX;
1787 int be_id = ucontrol->value.integer.value[3];
1788 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1789 int ret = 0;
1790
1791 cfg_data.app_type = ucontrol->value.integer.value[0];
1792 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1793 if (ucontrol->value.integer.value[2] != 0)
1794 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1795 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1796 __func__, fe_id, session_type, be_id,
1797 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1798 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1799 be_id, &cfg_data);
1800 if (ret < 0)
1801 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1802 __func__, ret);
1803
1804 return ret;
1805}
1806
1807static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1808 struct snd_ctl_elem_value *ucontrol)
1809{
1810 u64 fe_id = kcontrol->private_value;
1811 int session_type = SESSION_TYPE_TX;
1812 int be_id = 0;
1813 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1814 int ret = 0;
1815
1816 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1817 &be_id, &cfg_data);
1818 if (ret < 0) {
1819 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1820 __func__, ret);
1821 goto done;
1822 }
1823
1824 ucontrol->value.integer.value[0] = cfg_data.app_type;
1825 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1826 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1827 ucontrol->value.integer.value[3] = be_id;
1828 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1829 __func__, fe_id, session_type, be_id,
1830 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1831done:
1832 return ret;
1833}
1834
1835static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
1836{
1837 struct snd_pcm *pcm = rtd->pcm;
1838 struct snd_pcm_usr *app_type_info;
1839 struct snd_kcontrol *kctl;
1840 const char *playback_mixer_ctl_name = "Audio Stream";
1841 const char *capture_mixer_ctl_name = "Audio Stream Capture";
1842 const char *deviceNo = "NN";
1843 const char *suffix = "App Type Cfg";
1844 int ctl_len, ret = 0;
1845
1846 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
1847 ctl_len = strlen(playback_mixer_ctl_name) + 1 +
1848 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1849 pr_debug("%s: Playback app type cntrl add\n", __func__);
1850 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1851 NULL, 1, ctl_len, rtd->dai_link->id,
1852 &app_type_info);
1853 if (ret < 0) {
1854 pr_err("%s: playback app type cntrl add failed: %d\n",
1855 __func__, ret);
1856 return ret;
1857 }
1858 kctl = app_type_info->kctl;
1859 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1860 playback_mixer_ctl_name, rtd->pcm->device, suffix);
1861 kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
1862 kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
1863 }
1864
1865 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
1866 ctl_len = strlen(capture_mixer_ctl_name) + 1 +
1867 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1868 pr_debug("%s: Capture app type cntrl add\n", __func__);
1869 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
1870 NULL, 1, ctl_len, rtd->dai_link->id,
1871 &app_type_info);
1872 if (ret < 0) {
1873 pr_err("%s: capture app type cntrl add failed: %d\n",
1874 __func__, ret);
1875 return ret;
1876 }
1877 kctl = app_type_info->kctl;
1878 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1879 capture_mixer_ctl_name, rtd->pcm->device, suffix);
1880 kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
1881 kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
1882 }
1883
1884 return 0;
1885}
1886
Dhanalakshmi Siddani040e0262018-11-26 23:01:26 +05301887static int msm_pcm_chmix_cfg_ctl_info(struct snd_kcontrol *kcontrol,
1888 struct snd_ctl_elem_info *uinfo)
1889{
1890 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1891 uinfo->count = 128;
1892 uinfo->value.integer.min = 0;
1893 uinfo->value.integer.max = 0xFFFFFFFF;
1894 return 0;
1895}
1896
1897static int msm_pcm_chmix_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1898 struct snd_ctl_elem_value *ucontrol)
1899{
1900 struct snd_soc_component *usr_info = snd_kcontrol_chip(kcontrol);
1901 struct snd_soc_platform *platform;
1902 struct msm_plat_data *pdata;
1903 struct snd_pcm_substream *substream;
1904 struct msm_audio *prtd;
1905 u64 fe_id = kcontrol->private_value;
1906 int ip_channel_cnt, op_channel_cnt;
1907 int i, index = 0, ret = 0;
1908 int ch_coeff[PCM_FORMAT_MAX_NUM_CHANNEL * PCM_FORMAT_MAX_NUM_CHANNEL];
1909 bool use_default_chmap = true;
1910 char *ch_map = NULL;
1911
1912 pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
1913 if (fe_id >= MSM_FRONTEND_DAI_MAX) {
1914 pr_err("%s: Received out of bounds fe_id %llu\n",
1915 __func__, fe_id);
1916 ret = -EINVAL;
1917 goto done;
1918 }
1919
1920 if (!usr_info) {
1921 pr_err("%s: usr_info is null\n", __func__);
1922 ret = -EINVAL;
1923 goto done;
1924 }
1925 platform = snd_soc_component_to_platform(usr_info);
1926 if (!platform) {
1927 pr_err("%s: platform is null\n", __func__);
1928 ret = -EINVAL;
1929 goto done;
1930 }
1931 pdata = dev_get_drvdata(platform->dev);
1932 if (!pdata) {
1933 pr_err("%s: pdata is null\n", __func__);
1934 ret = -EINVAL;
1935 goto done;
1936 }
1937 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1938
1939 if (!substream) {
1940 pr_err("%s substream not found\n", __func__);
1941 return -ENODEV;
1942 }
1943 if (!substream->runtime) {
1944 pr_err("%s substream runtime not found\n", __func__);
1945 ret = -EINVAL;
1946 goto done;
1947 }
1948 prtd = substream->runtime->private_data;
1949 if (!prtd) {
1950 pr_err("%s: stream inactive\n", __func__);
1951 ret = -EINVAL;
1952 goto done;
1953 }
1954 use_default_chmap = !prtd->set_channel_map;
1955 ch_map = prtd->channel_map;
1956 ip_channel_cnt = ucontrol->value.integer.value[index++];
1957 op_channel_cnt = ucontrol->value.integer.value[index++];
1958 /*
1959 * wght coeff of first out channel corresponding to each in channel
1960 * are sent followed by second out channel for each in channel etc.
1961 */
1962 memset(ch_coeff, 0, sizeof(ch_coeff));
1963 for (i = 0; i < op_channel_cnt * ip_channel_cnt; i++) {
1964 ch_coeff[i] =
1965 ucontrol->value.integer.value[index++];
1966 }
1967
1968 msm_pcm_routing_send_chmix_cfg(fe_id, ip_channel_cnt, op_channel_cnt,
1969 ch_coeff, SESSION_TYPE_RX, use_default_chmap, ch_map);
1970done:
1971 return ret;
1972}
1973
1974static int msm_pcm_chmix_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1975 struct snd_ctl_elem_value *ucontrol)
1976{
1977 return 0;
1978}
1979
1980static int msm_pcm_add_chmix_cfg_controls(struct snd_soc_pcm_runtime *rtd)
1981{
1982 const char *mixer_ctl_name = "Audio Stream";
1983 const char *deviceNo = "NN";
1984 const char *suffix = "Channel Mix Cfg";
1985 char *mixer_str = NULL;
1986 int ctl_len = 0;
1987 struct msm_plat_data *pdata;
1988 struct snd_kcontrol_new chmix_cfg_controls[1] = {
1989 {
1990 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1991 .name = "?",
1992 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1993 .info = msm_pcm_chmix_cfg_ctl_info,
1994 .get = msm_pcm_chmix_cfg_ctl_get,
1995 .put = msm_pcm_chmix_cfg_ctl_put,
1996 .private_value = 0,
1997 }
1998 };
1999
2000 if (!rtd) {
2001 pr_err("%s: NULL rtd\n", __func__);
2002 return -EINVAL;
2003 }
2004
2005 ctl_len = strlen(mixer_ctl_name) + 1 +
2006 strlen(deviceNo) + 1 + strlen(suffix) + 1;
2007 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
2008 if (!mixer_str)
2009 return -ENOMEM;
2010
2011 snprintf(mixer_str, ctl_len, "%s %d %s",
2012 mixer_ctl_name, rtd->pcm->device, suffix);
2013 chmix_cfg_controls[0].name = mixer_str;
2014 chmix_cfg_controls[0].private_value = rtd->dai_link->id;
2015 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
2016 pdata = dev_get_drvdata(rtd->platform->dev);
2017 if (pdata) {
2018 if (!pdata->pcm)
2019 pdata->pcm = rtd->pcm;
2020 snd_soc_add_platform_controls(rtd->platform,
2021 chmix_cfg_controls,
2022 ARRAY_SIZE(chmix_cfg_controls));
2023 } else {
2024 pr_err("%s: NULL pdata\n", __func__);
2025 return -EINVAL;
2026 }
2027 kfree(mixer_str);
2028 return 0;
2029}
2030
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302031static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
2032{
2033 int ret = 0;
2034
2035 pr_debug("%s\n", __func__);
2036 ret = msm_pcm_add_chmap_controls(rtd);
2037 if (ret)
2038 pr_err("%s: pcm add controls failed:%d\n", __func__, ret);
2039 ret = msm_pcm_add_app_type_controls(rtd);
2040 if (ret)
2041 pr_err("%s: pcm add app type controls failed:%d\n",
2042 __func__, ret);
Dhanalakshmi Siddani040e0262018-11-26 23:01:26 +05302043 ret = msm_pcm_add_chmix_cfg_controls(rtd);
2044 if (ret)
2045 pr_err("%s: add chmix cfg controls failed:%d\n", __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302046 return ret;
2047}
2048
2049static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
2050{
2051 struct snd_card *card = rtd->card->snd_card;
2052 int ret = 0;
2053
2054 if (!card->dev->coherent_dma_mask)
2055 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
2056
2057 ret = msm_pcm_add_controls(rtd);
2058 if (ret) {
2059 pr_err("%s, kctl add failed:%d\n", __func__, ret);
2060 return ret;
2061 }
2062
Haynes Mathew Georged00e1062018-04-06 18:18:51 -07002063 ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_PLAYBACK);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302064 if (ret)
2065 pr_err("%s: Could not add pcm Volume Control %d\n",
2066 __func__, ret);
Haynes Mathew Georged00e1062018-04-06 18:18:51 -07002067 ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_CAPTURE);
2068 if (ret)
2069 pr_err("%s: Could not add pcm Volume Control %d\n",
2070 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302071 ret = msm_pcm_add_compress_control(rtd);
2072 if (ret)
2073 pr_err("%s: Could not add pcm Compress Control %d\n",
2074 __func__, ret);
2075
2076 ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
2077 if (ret)
2078 pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
2079 __func__);
2080
2081 ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
2082 if (ret)
2083 pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
2084 __func__);
2085
2086 return ret;
2087}
2088
2089static snd_pcm_sframes_t msm_pcm_delay_blk(struct snd_pcm_substream *substream,
2090 struct snd_soc_dai *dai)
2091{
2092 struct snd_pcm_runtime *runtime = substream->runtime;
2093 struct msm_audio *prtd = runtime->private_data;
2094 struct audio_client *ac = prtd->audio_client;
2095 snd_pcm_sframes_t frames;
2096 int ret;
2097
2098 ret = q6asm_get_path_delay(prtd->audio_client);
2099 if (ret) {
2100 pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
2101 return 0;
2102 }
2103
2104 /* convert microseconds to frames */
2105 frames = ac->path_delay / 1000 * runtime->rate / 1000;
2106
2107 /* also convert the remainder from the initial division */
2108 frames += ac->path_delay % 1000 * runtime->rate / 1000000;
2109
2110 /* overcompensate for the loss of precision (empirical) */
2111 frames += 2;
2112
2113 return frames;
2114}
2115
2116static struct snd_soc_platform_driver msm_soc_platform = {
2117 .ops = &msm_pcm_ops,
2118 .pcm_new = msm_asoc_pcm_new,
2119 .delay_blk = msm_pcm_delay_blk,
2120};
2121
2122static int msm_pcm_probe(struct platform_device *pdev)
2123{
2124 int rc;
2125 int id;
2126 struct msm_plat_data *pdata;
2127 const char *latency_level;
2128
2129 rc = of_property_read_u32(pdev->dev.of_node,
2130 "qcom,msm-pcm-dsp-id", &id);
2131 if (rc) {
2132 dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
2133 __func__);
2134 return rc;
2135 }
2136
2137 pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
2138 if (!pdata)
2139 return -ENOMEM;
2140
2141 if (of_property_read_bool(pdev->dev.of_node,
2142 "qcom,msm-pcm-low-latency")) {
2143
2144 pdata->perf_mode = LOW_LATENCY_PCM_MODE;
2145 rc = of_property_read_string(pdev->dev.of_node,
2146 "qcom,latency-level", &latency_level);
2147 if (!rc) {
2148 if (!strcmp(latency_level, "ultra"))
2149 pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
2150 else if (!strcmp(latency_level, "ull-pp"))
2151 pdata->perf_mode =
2152 ULL_POST_PROCESSING_PCM_MODE;
2153 }
2154 } else {
2155 pdata->perf_mode = LEGACY_PCM_MODE;
2156 }
2157
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05302158 mutex_init(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302159 dev_set_drvdata(&pdev->dev, pdata);
2160
2161
2162 dev_dbg(&pdev->dev, "%s: dev name %s\n",
2163 __func__, dev_name(&pdev->dev));
2164 return snd_soc_register_platform(&pdev->dev,
2165 &msm_soc_platform);
2166}
2167
2168static int msm_pcm_remove(struct platform_device *pdev)
2169{
2170 struct msm_plat_data *pdata;
2171
2172 pdata = dev_get_drvdata(&pdev->dev);
Ajit Pandey3d7b9a22019-09-05 16:26:01 +05302173 mutex_destroy(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302174 kfree(pdata);
2175 snd_soc_unregister_platform(&pdev->dev);
2176 return 0;
2177}
2178static const struct of_device_id msm_pcm_dt_match[] = {
2179 {.compatible = "qcom,msm-pcm-dsp"},
2180 {}
2181};
2182MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
2183
2184static struct platform_driver msm_pcm_driver = {
2185 .driver = {
2186 .name = "msm-pcm-dsp",
2187 .owner = THIS_MODULE,
2188 .of_match_table = msm_pcm_dt_match,
2189 },
2190 .probe = msm_pcm_probe,
2191 .remove = msm_pcm_remove,
2192};
2193
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302194int __init msm_pcm_dsp_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302195{
2196 init_waitqueue_head(&the_locks.enable_wait);
2197 init_waitqueue_head(&the_locks.eos_wait);
2198 init_waitqueue_head(&the_locks.write_wait);
2199 init_waitqueue_head(&the_locks.read_wait);
2200
2201 return platform_driver_register(&msm_pcm_driver);
2202}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302203
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05302204void msm_pcm_dsp_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302205{
2206 platform_driver_unregister(&msm_pcm_driver);
2207}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302208
2209MODULE_DESCRIPTION("PCM module platform driver");
2210MODULE_LICENSE("GPL v2");