blob: 714197487d53b161a5e8afca5b0b3942871651d0 [file] [log] [blame]
Meng Wangac147b72017-10-30 16:46:16 +08001/* Copyright (c) 2012-2018, 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>
19#include <linux/wait.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22#include <sound/core.h>
23#include <sound/soc.h>
24#include <sound/soc-dapm.h>
25#include <sound/pcm.h>
26#include <sound/initval.h>
27#include <sound/control.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053028#include <sound/timer.h>
29#include <asm/dma.h>
30#include <linux/dma-mapping.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053031#include <linux/msm_audio.h>
32
33#include <linux/of_device.h>
34#include <sound/tlv.h>
35#include <sound/pcm_params.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053036#include <dsp/msm_audio_ion.h>
37#include <dsp/q6audio-v2.h>
Dieter Luecking70668fc2018-09-28 15:03:01 +020038#include <dsp/q6core.h>
39#include <dsp/q6asm-v2.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053040
41#include "msm-pcm-q6-v2.h"
42#include "msm-pcm-routing-v2.h"
43#include "msm-qti-pp-config.h"
44
45enum stream_state {
46 IDLE = 0,
47 STOPPED,
48 RUNNING,
49};
50
51static struct audio_locks the_locks;
52
53#define PCM_MASTER_VOL_MAX_STEPS 0x2000
54static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
55 PCM_MASTER_VOL_MAX_STEPS);
56
57struct snd_msm {
58 struct snd_card *card;
59 struct snd_pcm *pcm;
60};
61
62#define CMD_EOS_MIN_TIMEOUT_LENGTH 50
63#define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50)
64#define MAX_PB_COPY_RETRIES 3
65
66static struct snd_pcm_hardware msm_pcm_hardware_capture = {
67 .info = (SNDRV_PCM_INFO_MMAP |
68 SNDRV_PCM_INFO_BLOCK_TRANSFER |
69 SNDRV_PCM_INFO_MMAP_VALID |
70 SNDRV_PCM_INFO_INTERLEAVED |
71 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
72 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
73 SNDRV_PCM_FMTBIT_S24_LE |
74 SNDRV_PCM_FMTBIT_S24_3LE |
75 SNDRV_PCM_FMTBIT_S32_LE),
76 .rates = SNDRV_PCM_RATE_8000_384000,
77 .rate_min = 8000,
78 .rate_max = 384000,
79 .channels_min = 1,
80 .channels_max = 4,
81 .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
82 CAPTURE_MAX_PERIOD_SIZE,
83 .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
84 .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
85 .periods_min = CAPTURE_MIN_NUM_PERIODS,
86 .periods_max = CAPTURE_MAX_NUM_PERIODS,
87 .fifo_size = 0,
88};
89
90static struct snd_pcm_hardware msm_pcm_hardware_playback = {
91 .info = (SNDRV_PCM_INFO_MMAP |
92 SNDRV_PCM_INFO_BLOCK_TRANSFER |
93 SNDRV_PCM_INFO_MMAP_VALID |
94 SNDRV_PCM_INFO_INTERLEAVED |
95 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
96 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
97 SNDRV_PCM_FMTBIT_S24_LE |
98 SNDRV_PCM_FMTBIT_S24_3LE |
99 SNDRV_PCM_FMTBIT_S32_LE),
100 .rates = SNDRV_PCM_RATE_8000_384000,
101 .rate_min = 8000,
102 .rate_max = 384000,
103 .channels_min = 1,
104 .channels_max = 8,
105 .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS *
106 PLAYBACK_MAX_PERIOD_SIZE,
107 .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
108 .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
109 .periods_min = PLAYBACK_MIN_NUM_PERIODS,
110 .periods_max = PLAYBACK_MAX_NUM_PERIODS,
111 .fifo_size = 0,
112};
113
114/* Conventional and unconventional sample rate supported */
115static unsigned int supported_sample_rates[] = {
116 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
117 88200, 96000, 176400, 192000, 352800, 384000
118};
119
120static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
121 .count = ARRAY_SIZE(supported_sample_rates),
122 .list = supported_sample_rates,
123 .mask = 0,
124};
125
126static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
127 void *priv_data)
128{
129 struct msm_audio *prtd = priv_data;
130
131 WARN_ON(!prtd);
132
133 pr_debug("%s: event %x\n", __func__, event);
134
135 switch (event) {
136 case MSM_PCM_RT_EVT_BUF_RECFG:
137 q6asm_cmd(prtd->audio_client, CMD_PAUSE);
138 q6asm_cmd(prtd->audio_client, CMD_FLUSH);
139 q6asm_run(prtd->audio_client, 0, 0, 0);
140 /* fallthrough */
141 default:
142 break;
143 }
144}
145
146static void event_handler(uint32_t opcode,
147 uint32_t token, uint32_t *payload, void *priv)
148{
149 struct msm_audio *prtd = priv;
150 struct snd_pcm_substream *substream = prtd->substream;
151 uint32_t *ptrmem = (uint32_t *)payload;
152 uint32_t idx = 0;
153 uint32_t size = 0;
154 uint8_t buf_index;
155 struct snd_soc_pcm_runtime *rtd;
156 int ret = 0;
157
158 switch (opcode) {
159 case ASM_DATA_EVENT_WRITE_DONE_V2: {
160 pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
161 pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
162 prtd->pcm_irq_pos += prtd->pcm_count;
163 if (atomic_read(&prtd->start))
164 snd_pcm_period_elapsed(substream);
165 atomic_inc(&prtd->out_count);
166 wake_up(&the_locks.write_wait);
167 if (!atomic_read(&prtd->start))
168 break;
169 if (!prtd->mmap_flag || prtd->reset_event)
170 break;
171 if (q6asm_is_cpu_buf_avail_nolock(IN,
172 prtd->audio_client,
173 &size, &idx)) {
174 pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
175 __func__, prtd->pcm_count);
176 q6asm_write_nolock(prtd->audio_client,
177 prtd->pcm_count, 0, 0, NO_TIMESTAMP);
178 }
179 break;
180 }
181 case ASM_DATA_EVENT_RENDERED_EOS:
182 pr_debug("ASM_DATA_EVENT_RENDERED_EOS\n");
183 clear_bit(CMD_EOS, &prtd->cmd_pending);
184 wake_up(&the_locks.eos_wait);
185 break;
186 case ASM_DATA_EVENT_READ_DONE_V2: {
187 pr_debug("ASM_DATA_EVENT_READ_DONE_V2\n");
188 buf_index = q6asm_get_buf_index_from_token(token);
Vignesh Kulothungan3817b182017-12-04 15:56:05 -0800189 if (buf_index >= CAPTURE_MAX_NUM_PERIODS) {
190 pr_err("%s: buffer index %u is out of range.\n",
191 __func__, buf_index);
192 return;
193 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530194 pr_debug("%s: token=0x%08x buf_index=0x%08x\n",
195 __func__, token, buf_index);
196 prtd->in_frame_info[buf_index].size = payload[4];
197 prtd->in_frame_info[buf_index].offset = payload[5];
198 /* assume data size = 0 during flushing */
199 if (prtd->in_frame_info[buf_index].size) {
200 prtd->pcm_irq_pos +=
201 prtd->in_frame_info[buf_index].size;
202 pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
203 if (atomic_read(&prtd->start))
204 snd_pcm_period_elapsed(substream);
205 if (atomic_read(&prtd->in_count) <= prtd->periods)
206 atomic_inc(&prtd->in_count);
207 wake_up(&the_locks.read_wait);
208 if (prtd->mmap_flag &&
209 q6asm_is_cpu_buf_avail_nolock(OUT,
210 prtd->audio_client,
211 &size, &idx) &&
212 (substream->runtime->status->state ==
213 SNDRV_PCM_STATE_RUNNING))
214 q6asm_read_nolock(prtd->audio_client);
215 } else {
216 pr_debug("%s: reclaim flushed buf in_count %x\n",
217 __func__, atomic_read(&prtd->in_count));
218 prtd->pcm_irq_pos += prtd->pcm_count;
219 if (prtd->mmap_flag) {
220 if (q6asm_is_cpu_buf_avail_nolock(OUT,
221 prtd->audio_client,
222 &size, &idx) &&
223 (substream->runtime->status->state ==
224 SNDRV_PCM_STATE_RUNNING))
225 q6asm_read_nolock(prtd->audio_client);
226 } else {
227 atomic_inc(&prtd->in_count);
228 }
229 if (atomic_read(&prtd->in_count) == prtd->periods) {
230 pr_info("%s: reclaimed all bufs\n", __func__);
231 if (atomic_read(&prtd->start))
232 snd_pcm_period_elapsed(substream);
233 wake_up(&the_locks.read_wait);
234 }
235 }
236 break;
237 }
238 case ASM_STREAM_PP_EVENT:
239 case ASM_STREAM_CMD_ENCDEC_EVENTS: {
240 pr_debug("%s: ASM_STREAM_EVENT (0x%x)\n", __func__, opcode);
241 if (!substream) {
242 pr_err("%s: substream is NULL.\n", __func__);
243 return;
244 }
245
246 rtd = substream->private_data;
247 if (!rtd) {
248 pr_err("%s: rtd is NULL\n", __func__);
249 return;
250 }
251
252 ret = msm_adsp_inform_mixer_ctl(rtd, payload);
253 if (ret) {
254 pr_err("%s: failed to inform mixer ctl. err = %d\n",
255 __func__, ret);
256 return;
257 }
258
259 break;
260 }
261 case APR_BASIC_RSP_RESULT: {
262 switch (payload[0]) {
263 case ASM_SESSION_CMD_RUN_V2:
264 if (substream->stream
265 != SNDRV_PCM_STREAM_PLAYBACK) {
266 atomic_set(&prtd->start, 1);
267 break;
268 }
269 if (prtd->mmap_flag) {
270 pr_debug("%s:writing %d bytes of buffer to dsp\n",
271 __func__,
272 prtd->pcm_count);
273 q6asm_write_nolock(prtd->audio_client,
274 prtd->pcm_count,
275 0, 0, NO_TIMESTAMP);
276 } else {
277 while (atomic_read(&prtd->out_needed)) {
278 pr_debug("%s:writing %d bytes of buffer to dsp\n",
279 __func__,
280 prtd->pcm_count);
281 q6asm_write_nolock(prtd->audio_client,
282 prtd->pcm_count,
283 0, 0, NO_TIMESTAMP);
284 atomic_dec(&prtd->out_needed);
285 wake_up(&the_locks.write_wait);
286 };
287 }
288 atomic_set(&prtd->start, 1);
289 break;
290 case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
291 pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
292 __func__);
293 break;
294 default:
295 pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
296 __func__, payload[0], payload[1]);
297 break;
298 }
299 }
300 break;
301 case RESET_EVENTS:
302 pr_debug("%s RESET_EVENTS\n", __func__);
303 prtd->pcm_irq_pos += prtd->pcm_count;
304 atomic_inc(&prtd->out_count);
305 atomic_inc(&prtd->in_count);
306 prtd->reset_event = true;
307 if (atomic_read(&prtd->start))
308 snd_pcm_period_elapsed(substream);
309 wake_up(&the_locks.eos_wait);
310 wake_up(&the_locks.write_wait);
311 wake_up(&the_locks.read_wait);
312 break;
313 default:
314 pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
315 break;
316 }
317}
318
319static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
320{
321 struct snd_pcm_runtime *runtime = substream->runtime;
322 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
323 struct msm_audio *prtd = runtime->private_data;
324 struct msm_plat_data *pdata;
325 struct snd_pcm_hw_params *params;
326 int ret;
327 uint32_t fmt_type = FORMAT_LINEAR_PCM;
328 uint16_t bits_per_sample;
329 uint16_t sample_word_size;
330
331 pdata = (struct msm_plat_data *)
332 dev_get_drvdata(soc_prtd->platform->dev);
333 if (!pdata) {
334 pr_err("%s: platform data not populated\n", __func__);
335 return -EINVAL;
336 }
337 if (!prtd || !prtd->audio_client) {
338 pr_err("%s: private data null or audio client freed\n",
339 __func__);
340 return -EINVAL;
341 }
342 params = &soc_prtd->dpcm[substream->stream].hw_params;
343
344 pr_debug("%s\n", __func__);
345 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
346 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
347 prtd->pcm_irq_pos = 0;
348 /* rate and channels are sent to audio driver */
349 prtd->samp_rate = runtime->rate;
350 prtd->channel_mode = runtime->channels;
351 if (prtd->enabled)
352 return 0;
353
354 prtd->audio_client->perf_mode = pdata->perf_mode;
355 pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode);
356
357 switch (params_format(params)) {
358 case SNDRV_PCM_FORMAT_S32_LE:
359 bits_per_sample = 32;
360 sample_word_size = 32;
361 break;
362 case SNDRV_PCM_FORMAT_S24_LE:
363 bits_per_sample = 24;
364 sample_word_size = 32;
365 break;
366 case SNDRV_PCM_FORMAT_S24_3LE:
367 bits_per_sample = 24;
368 sample_word_size = 24;
369 break;
370 case SNDRV_PCM_FORMAT_S16_LE:
371 default:
372 bits_per_sample = 16;
373 sample_word_size = 16;
374 break;
375 }
376 if (prtd->compress_enable) {
377 fmt_type = FORMAT_GEN_COMPR;
378 pr_debug("%s: Compressed enabled!\n", __func__);
379 ret = q6asm_open_write_compressed(prtd->audio_client, fmt_type,
380 COMPRESSED_PASSTHROUGH_GEN);
381 if (ret < 0) {
382 pr_err("%s: q6asm_open_write_compressed failed (%d)\n",
383 __func__, ret);
384 q6asm_audio_client_free(prtd->audio_client);
385 prtd->audio_client = NULL;
386 return -ENOMEM;
387 }
388 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200389 if (q6core_get_avcs_api_version_per_service(
390 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
391 ADSP_ASM_API_VERSION_V2)
392 ret = q6asm_open_write_v5(prtd->audio_client,
393 fmt_type, bits_per_sample);
394 else
395 ret = q6asm_open_write_v4(prtd->audio_client,
396 fmt_type, bits_per_sample);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530397
398 if (ret < 0) {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200399 pr_err("%s: q6asm_open_write failed (%d)\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530400 __func__, ret);
401 q6asm_audio_client_free(prtd->audio_client);
402 prtd->audio_client = NULL;
403 return -ENOMEM;
404 }
405
406 ret = q6asm_send_cal(prtd->audio_client);
407 if (ret < 0)
408 pr_debug("%s : Send cal failed : %d", __func__, ret);
409 }
410 pr_debug("%s: session ID %d\n", __func__,
411 prtd->audio_client->session);
412 prtd->session_id = prtd->audio_client->session;
413
414 if (prtd->compress_enable) {
415 ret = msm_pcm_routing_reg_phy_compr_stream(
416 soc_prtd->dai_link->id,
417 prtd->audio_client->perf_mode,
418 prtd->session_id,
419 SNDRV_PCM_STREAM_PLAYBACK,
420 COMPRESSED_PASSTHROUGH_GEN);
421 } else {
422 ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id,
423 prtd->audio_client->perf_mode,
424 prtd->session_id, substream->stream);
425 }
426 if (ret) {
427 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
428 return ret;
429 }
430 if (prtd->compress_enable) {
431 ret = q6asm_media_format_block_gen_compr(
432 prtd->audio_client, runtime->rate,
433 runtime->channels, !prtd->set_channel_map,
434 prtd->channel_map, bits_per_sample);
435 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200436
437 if (q6core_get_avcs_api_version_per_service(
438 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
439 ADSP_ASM_API_VERSION_V2) {
440
441 ret = q6asm_media_format_block_multi_ch_pcm_v5(
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530442 prtd->audio_client, runtime->rate,
443 runtime->channels, !prtd->set_channel_map,
444 prtd->channel_map, bits_per_sample,
445 sample_word_size, ASM_LITTLE_ENDIAN,
446 DEFAULT_QF);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200447 } else {
448 ret = q6asm_media_format_block_multi_ch_pcm_v4(
449 prtd->audio_client, runtime->rate,
450 runtime->channels, !prtd->set_channel_map,
451 prtd->channel_map, bits_per_sample,
452 sample_word_size, ASM_LITTLE_ENDIAN,
453 DEFAULT_QF);
454 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530455 }
456 if (ret < 0)
457 pr_info("%s: CMD Format block failed\n", __func__);
458
459 atomic_set(&prtd->out_count, runtime->periods);
460
461 prtd->enabled = 1;
462 prtd->cmd_pending = 0;
463 prtd->cmd_interrupt = 0;
464
465 return 0;
466}
467
468static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
469{
470 struct snd_pcm_runtime *runtime = substream->runtime;
471 struct msm_audio *prtd = runtime->private_data;
472 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
473 struct msm_plat_data *pdata;
474 struct snd_pcm_hw_params *params;
475 struct msm_pcm_routing_evt event;
476 int ret = 0;
477 int i = 0;
478 uint16_t bits_per_sample = 16;
479 uint16_t sample_word_size;
480
481 pdata = (struct msm_plat_data *)
482 dev_get_drvdata(soc_prtd->platform->dev);
483 if (!pdata) {
484 pr_err("%s: platform data not populated\n", __func__);
485 return -EINVAL;
486 }
487 if (!prtd || !prtd->audio_client) {
488 pr_err("%s: private data null or audio client freed\n",
489 __func__);
490 return -EINVAL;
491 }
492
493 if (prtd->enabled == IDLE) {
494 pr_debug("%s:perf_mode=%d periods=%d\n", __func__,
495 pdata->perf_mode, runtime->periods);
496 params = &soc_prtd->dpcm[substream->stream].hw_params;
497 if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) ||
498 (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE))
499 bits_per_sample = 24;
500 else if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
501 bits_per_sample = 32;
502
503 /* ULL mode is not supported in capture path */
504 if (pdata->perf_mode == LEGACY_PCM_MODE)
505 prtd->audio_client->perf_mode = LEGACY_PCM_MODE;
506 else
507 prtd->audio_client->perf_mode = LOW_LATENCY_PCM_MODE;
508
509 pr_debug("%s Opening %d-ch PCM read stream, perf_mode %d\n",
510 __func__, params_channels(params),
511 prtd->audio_client->perf_mode);
512
Dieter Luecking70668fc2018-09-28 15:03:01 +0200513 if (q6core_get_avcs_api_version_per_service(
514 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
515 ADSP_ASM_API_VERSION_V2)
516 ret = q6asm_open_read_v5(prtd->audio_client,
517 FORMAT_LINEAR_PCM,
518 bits_per_sample, false, ENC_CFG_ID_NONE);
519 else
520 ret = q6asm_open_read_v4(prtd->audio_client,
521 FORMAT_LINEAR_PCM,
Vikram Pandurangac712c172017-11-17 17:36:49 -0800522 bits_per_sample, false, ENC_CFG_ID_NONE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530523 if (ret < 0) {
524 pr_err("%s: q6asm_open_read failed\n", __func__);
525 q6asm_audio_client_free(prtd->audio_client);
526 prtd->audio_client = NULL;
527 return -ENOMEM;
528 }
529
530 ret = q6asm_send_cal(prtd->audio_client);
531 if (ret < 0)
532 pr_debug("%s : Send cal failed : %d", __func__, ret);
533
534 pr_debug("%s: session ID %d\n",
535 __func__, prtd->audio_client->session);
536 prtd->session_id = prtd->audio_client->session;
537 event.event_func = msm_pcm_route_event_handler;
538 event.priv_data = (void *) prtd;
539 ret = msm_pcm_routing_reg_phy_stream_v2(
540 soc_prtd->dai_link->id,
541 prtd->audio_client->perf_mode,
542 prtd->session_id, substream->stream,
543 event);
544 if (ret) {
545 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
546 return ret;
547 }
548 }
549
550 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
551 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
552 prtd->pcm_irq_pos = 0;
553 /* rate and channels are sent to audio driver */
554 prtd->samp_rate = runtime->rate;
555 prtd->channel_mode = runtime->channels;
556
557 if (prtd->enabled == IDLE || prtd->enabled == STOPPED) {
558 for (i = 0; i < runtime->periods; i++)
559 q6asm_read(prtd->audio_client);
560 prtd->periods = runtime->periods;
561 }
562
563 if (prtd->enabled != IDLE)
564 return 0;
565
566 switch (runtime->format) {
567 case SNDRV_PCM_FORMAT_S32_LE:
568 bits_per_sample = 32;
569 sample_word_size = 32;
570 break;
571 case SNDRV_PCM_FORMAT_S24_LE:
572 bits_per_sample = 24;
573 sample_word_size = 32;
574 break;
575 case SNDRV_PCM_FORMAT_S24_3LE:
576 bits_per_sample = 24;
577 sample_word_size = 24;
578 break;
579 case SNDRV_PCM_FORMAT_S16_LE:
580 default:
581 bits_per_sample = 16;
582 sample_word_size = 16;
583 break;
584 }
585
586 pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n",
587 __func__, prtd->samp_rate, prtd->channel_mode,
588 bits_per_sample, sample_word_size);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200589
590 if (q6core_get_avcs_api_version_per_service(
591 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
592 ADSP_ASM_API_VERSION_V2)
593 ret = q6asm_enc_cfg_blk_pcm_format_support_v5(
594 prtd->audio_client,
595 prtd->samp_rate,
596 prtd->channel_mode,
597 bits_per_sample,
598 sample_word_size,
599 ASM_LITTLE_ENDIAN,
600 DEFAULT_QF);
601 else
602 ret = q6asm_enc_cfg_blk_pcm_format_support_v4(
603 prtd->audio_client,
604 prtd->samp_rate,
605 prtd->channel_mode,
606 bits_per_sample,
607 sample_word_size,
608 ASM_LITTLE_ENDIAN,
609 DEFAULT_QF);
610
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530611 if (ret < 0)
612 pr_debug("%s: cmd cfg pcm was block failed", __func__);
613
614 prtd->enabled = RUNNING;
615
616 return ret;
617}
618
619static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
620{
621 int ret = 0;
622 struct snd_pcm_runtime *runtime = substream->runtime;
623 struct msm_audio *prtd = runtime->private_data;
624
625 switch (cmd) {
626 case SNDRV_PCM_TRIGGER_START:
627 case SNDRV_PCM_TRIGGER_RESUME:
628 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
629 pr_debug("%s: Trigger start\n", __func__);
630 ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
631 break;
632 case SNDRV_PCM_TRIGGER_STOP:
633 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
634 atomic_set(&prtd->start, 0);
635 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
636 prtd->enabled = STOPPED;
637 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
638 break;
639 }
640 /* pending CMD_EOS isn't expected */
641 WARN_ON_ONCE(test_bit(CMD_EOS, &prtd->cmd_pending));
642 set_bit(CMD_EOS, &prtd->cmd_pending);
643 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
644 if (ret)
645 clear_bit(CMD_EOS, &prtd->cmd_pending);
646 break;
647 case SNDRV_PCM_TRIGGER_SUSPEND:
648 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
649 pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
650 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
651 atomic_set(&prtd->start, 0);
652 break;
653 default:
654 ret = -EINVAL;
655 break;
656 }
657
658 return ret;
659}
660
661static int msm_pcm_open(struct snd_pcm_substream *substream)
662{
663 struct snd_pcm_runtime *runtime = substream->runtime;
664 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
665 struct msm_audio *prtd;
Banajit Goswami616e68c2017-10-27 01:31:19 -0700666 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530667 int ret = 0;
668
Banajit Goswami616e68c2017-10-27 01:31:19 -0700669 pdata = (struct msm_plat_data *)
670 dev_get_drvdata(soc_prtd->platform->dev);
671 if (!pdata) {
672 pr_err("%s: platform data not populated\n", __func__);
673 return -EINVAL;
674 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530675 prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
676 if (prtd == NULL)
677 return -ENOMEM;
678
679 prtd->substream = substream;
680 prtd->audio_client = q6asm_audio_client_alloc(
681 (app_cb)event_handler, prtd);
682 if (!prtd->audio_client) {
683 pr_info("%s: Could not allocate memory\n", __func__);
684 kfree(prtd);
685 return -ENOMEM;
686 }
687
688 prtd->audio_client->dev = soc_prtd->platform->dev;
689
690 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
691 runtime->hw = msm_pcm_hardware_playback;
692
693 /* Capture path */
694 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
695 runtime->hw = msm_pcm_hardware_capture;
696 else {
697 pr_err("Invalid Stream type %d\n", substream->stream);
698 return -EINVAL;
699 }
700
701 ret = snd_pcm_hw_constraint_list(runtime, 0,
702 SNDRV_PCM_HW_PARAM_RATE,
703 &constraints_sample_rates);
704 if (ret < 0)
705 pr_info("snd_pcm_hw_constraint_list failed\n");
706 /* Ensure that buffer size is a multiple of period size */
707 ret = snd_pcm_hw_constraint_integer(runtime,
708 SNDRV_PCM_HW_PARAM_PERIODS);
709 if (ret < 0)
710 pr_info("snd_pcm_hw_constraint_integer failed\n");
711
712 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
713 ret = snd_pcm_hw_constraint_minmax(runtime,
714 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
715 PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
716 PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
717 if (ret < 0) {
718 pr_err("constraint for buffer bytes min max ret = %d\n",
719 ret);
720 }
721 }
722
723 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
724 ret = snd_pcm_hw_constraint_minmax(runtime,
725 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
726 CAPTURE_MIN_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
727 CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
728 if (ret < 0) {
729 pr_err("constraint for buffer bytes min max ret = %d\n",
730 ret);
731 }
732 }
733 ret = snd_pcm_hw_constraint_step(runtime, 0,
734 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
735 if (ret < 0) {
736 pr_err("constraint for period bytes step ret = %d\n",
737 ret);
738 }
739 ret = snd_pcm_hw_constraint_step(runtime, 0,
740 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
741 if (ret < 0) {
742 pr_err("constraint for buffer bytes step ret = %d\n",
743 ret);
744 }
745
746 prtd->enabled = IDLE;
747 prtd->dsp_cnt = 0;
748 prtd->set_channel_map = false;
749 prtd->reset_event = false;
750 runtime->private_data = prtd;
Xiaojun Sangf27e3512018-05-23 17:14:31 +0800751
752 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
753 msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
754
Banajit Goswami616e68c2017-10-27 01:31:19 -0700755 /* Vote to update the Rx thread priority to RT Thread for playback */
756 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
757 (pdata->perf_mode == LOW_LATENCY_PCM_MODE))
758 apr_start_rx_rt(prtd->audio_client->apr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530759
760 return 0;
761}
762
763static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +0800764 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530765{
766 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530767 int xfer = 0;
768 char *bufptr = NULL;
769 void *data = NULL;
770 uint32_t idx = 0;
771 uint32_t size = 0;
772 uint32_t retries = 0;
773
774 struct snd_pcm_runtime *runtime = substream->runtime;
775 struct msm_audio *prtd = runtime->private_data;
776
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530777 pr_debug("%s: prtd->out_count = %d\n",
778 __func__, atomic_read(&prtd->out_count));
779
780 while ((fbytes > 0) && (retries < MAX_PB_COPY_RETRIES)) {
781 if (prtd->reset_event) {
782 pr_err("%s: In SSR return ENETRESET before wait\n",
783 __func__);
784 return -ENETRESET;
785 }
786
787 ret = wait_event_timeout(the_locks.write_wait,
788 (atomic_read(&prtd->out_count)), 5 * HZ);
789 if (!ret) {
790 pr_err("%s: wait_event_timeout failed\n", __func__);
791 ret = -ETIMEDOUT;
792 goto fail;
793 }
794 ret = 0;
795
796 if (prtd->reset_event) {
797 pr_err("%s: In SSR return ENETRESET after wait\n",
798 __func__);
799 return -ENETRESET;
800 }
801
802 if (!atomic_read(&prtd->out_count)) {
803 pr_err("%s: pcm stopped out_count 0\n", __func__);
804 return 0;
805 }
806
807 data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size,
808 &idx);
809 if (data == NULL) {
810 retries++;
811 continue;
812 } else {
813 retries = 0;
814 }
815
816 if (fbytes > size)
817 xfer = size;
818 else
819 xfer = fbytes;
820
821 bufptr = data;
822 if (bufptr) {
Meng Wangac147b72017-10-30 16:46:16 +0800823 pr_debug("%s:fbytes =%lu: xfer=%d size=%d\n",
824 __func__, fbytes, xfer, size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530825 if (copy_from_user(bufptr, buf, xfer)) {
826 ret = -EFAULT;
827 pr_err("%s: copy_from_user failed\n",
828 __func__);
829 q6asm_cpu_buf_release(IN, prtd->audio_client);
830 goto fail;
831 }
832 buf += xfer;
833 fbytes -= xfer;
Meng Wangac147b72017-10-30 16:46:16 +0800834 pr_debug("%s:fbytes = %lu: xfer=%d\n", __func__,
835 fbytes, xfer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530836 if (atomic_read(&prtd->start)) {
837 pr_debug("%s:writing %d bytes of buffer to dsp\n",
838 __func__, xfer);
839 ret = q6asm_write(prtd->audio_client, xfer,
840 0, 0, NO_TIMESTAMP);
841 if (ret < 0) {
842 ret = -EFAULT;
843 q6asm_cpu_buf_release(IN,
844 prtd->audio_client);
845 goto fail;
846 }
847 } else
848 atomic_inc(&prtd->out_needed);
849 atomic_dec(&prtd->out_count);
850 }
851 }
852fail:
853 if (retries >= MAX_PB_COPY_RETRIES)
854 ret = -ENOMEM;
855
856 return ret;
857}
858
859static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
860{
861 struct snd_pcm_runtime *runtime = substream->runtime;
862 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
863 struct msm_audio *prtd = runtime->private_data;
Banajit Goswami616e68c2017-10-27 01:31:19 -0700864 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530865 uint32_t timeout;
866 int dir = 0;
867 int ret = 0;
868
869 pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
870
871 if (prtd->audio_client) {
872 dir = IN;
873
Banajit Goswami616e68c2017-10-27 01:31:19 -0700874 /*
875 * Unvote to downgrade the Rx thread priority from
876 * RT Thread for Low-Latency use case.
877 */
878 pdata = (struct msm_plat_data *)
879 dev_get_drvdata(soc_prtd->platform->dev);
880 if (pdata) {
881 if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
882 apr_end_rx_rt(prtd->audio_client->apr);
883 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530884 /* determine timeout length */
885 if (runtime->frame_bits == 0 || runtime->rate == 0) {
886 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
887 } else {
888 timeout = (runtime->period_size *
889 CMD_EOS_TIMEOUT_MULTIPLIER) /
890 ((runtime->frame_bits / 8) *
891 runtime->rate);
892 if (timeout < CMD_EOS_MIN_TIMEOUT_LENGTH)
893 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
894 }
895 pr_debug("%s: CMD_EOS timeout is %d\n", __func__, timeout);
896
897 ret = wait_event_timeout(the_locks.eos_wait,
898 !test_bit(CMD_EOS, &prtd->cmd_pending),
899 timeout);
900 if (!ret)
901 pr_err("%s: CMD_EOS failed, cmd_pending 0x%lx\n",
902 __func__, prtd->cmd_pending);
903 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
904 q6asm_audio_client_buf_free_contiguous(dir,
905 prtd->audio_client);
906 q6asm_audio_client_free(prtd->audio_client);
907 }
908 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
909 SNDRV_PCM_STREAM_PLAYBACK);
910 msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
911 kfree(prtd);
912 runtime->private_data = NULL;
913
914 return 0;
915}
916
917static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
Meng Wangac147b72017-10-30 16:46:16 +0800918 int channel, unsigned long hwoff, void __user *buf,
919 unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530920{
921 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530922 int xfer;
923 char *bufptr;
924 void *data = NULL;
925 static uint32_t idx;
926 static uint32_t size;
927 uint32_t offset = 0;
928 struct snd_pcm_runtime *runtime = substream->runtime;
929 struct msm_audio *prtd = substream->runtime->private_data;
930
931
932 pr_debug("%s\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530933
934 pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
935 pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
936 pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
937
938 if (prtd->reset_event) {
939 pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
940 return -ENETRESET;
941 }
942 ret = wait_event_timeout(the_locks.read_wait,
943 (atomic_read(&prtd->in_count)), 5 * HZ);
944 if (!ret) {
945 pr_debug("%s: wait_event_timeout failed\n", __func__);
946 goto fail;
947 }
948 if (prtd->reset_event) {
949 pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
950 return -ENETRESET;
951 }
952 if (!atomic_read(&prtd->in_count)) {
953 pr_debug("%s: pcm stopped in_count 0\n", __func__);
954 return 0;
955 }
956 pr_debug("Checking if valid buffer is available...%pK\n",
957 data);
958 data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
959 bufptr = data;
960 pr_debug("Size = %d\n", size);
Meng Wangac147b72017-10-30 16:46:16 +0800961 pr_debug("fbytes = %lu\n", fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530962 pr_debug("idx = %d\n", idx);
963 if (bufptr) {
964 xfer = fbytes;
965 if (xfer > size)
966 xfer = size;
967 offset = prtd->in_frame_info[idx].offset;
968 pr_debug("Offset value = %d\n", offset);
969 if (copy_to_user(buf, bufptr+offset, xfer)) {
970 pr_err("Failed to copy buf to user\n");
971 ret = -EFAULT;
972 q6asm_cpu_buf_release(OUT, prtd->audio_client);
973 goto fail;
974 }
975 fbytes -= xfer;
976 size -= xfer;
977 prtd->in_frame_info[idx].offset += xfer;
Meng Wangac147b72017-10-30 16:46:16 +0800978 pr_debug("%s:fbytes = %lu: size=%d: xfer=%d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530979 __func__, fbytes, size, xfer);
980 pr_debug(" Sending next buffer to dsp\n");
981 memset(&prtd->in_frame_info[idx], 0,
982 sizeof(struct msm_audio_in_frame_info));
983 atomic_dec(&prtd->in_count);
984 ret = q6asm_read(prtd->audio_client);
985 if (ret < 0) {
986 pr_err("q6asm read failed\n");
987 ret = -EFAULT;
988 q6asm_cpu_buf_release(OUT, prtd->audio_client);
989 goto fail;
990 }
991 } else
992 pr_err("No valid buffer\n");
993
994 pr_debug("Returning from capture_copy... %d\n", ret);
995fail:
996 return ret;
997}
998
999static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
1000{
1001 struct snd_pcm_runtime *runtime = substream->runtime;
1002 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
1003 struct msm_audio *prtd = runtime->private_data;
1004 int dir = OUT;
1005
1006 pr_debug("%s\n", __func__);
1007 if (prtd->audio_client) {
1008 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
1009 q6asm_audio_client_buf_free_contiguous(dir,
1010 prtd->audio_client);
1011 q6asm_audio_client_free(prtd->audio_client);
1012 }
1013
1014 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
1015 SNDRV_PCM_STREAM_CAPTURE);
1016 kfree(prtd);
1017 runtime->private_data = NULL;
1018
1019 return 0;
1020}
1021
1022static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +08001023 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301024{
1025 int ret = 0;
1026
1027 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Meng Wangac147b72017-10-30 16:46:16 +08001028 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301029 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
Meng Wangac147b72017-10-30 16:46:16 +08001030 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301031 return ret;
1032}
1033
1034static int msm_pcm_close(struct snd_pcm_substream *substream)
1035{
1036 int ret = 0;
1037
1038 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1039 ret = msm_pcm_playback_close(substream);
1040 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1041 ret = msm_pcm_capture_close(substream);
1042 return ret;
1043}
1044
1045static int msm_pcm_prepare(struct snd_pcm_substream *substream)
1046{
1047 int ret = 0;
1048
1049 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1050 ret = msm_pcm_playback_prepare(substream);
1051 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1052 ret = msm_pcm_capture_prepare(substream);
1053 return ret;
1054}
1055
1056static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
1057{
1058
1059 struct snd_pcm_runtime *runtime = substream->runtime;
1060 struct msm_audio *prtd = runtime->private_data;
1061
1062 if (prtd->pcm_irq_pos >= prtd->pcm_size)
1063 prtd->pcm_irq_pos = 0;
1064
1065 pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
1066 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
1067}
1068
1069static int msm_pcm_mmap(struct snd_pcm_substream *substream,
1070 struct vm_area_struct *vma)
1071{
1072 struct snd_pcm_runtime *runtime = substream->runtime;
1073 struct msm_audio *prtd = runtime->private_data;
1074 struct audio_client *ac = prtd->audio_client;
1075 struct audio_port_data *apd = ac->port;
1076 struct audio_buffer *ab;
1077 int dir = -1;
1078
1079 prtd->mmap_flag = 1;
1080
1081 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1082 dir = IN;
1083 else
1084 dir = OUT;
1085 ab = &(apd[dir].buf[0]);
1086
1087 return msm_audio_ion_mmap(ab, vma);
1088}
1089
1090static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
1091 struct snd_pcm_hw_params *params)
1092{
1093 struct snd_pcm_runtime *runtime = substream->runtime;
1094 struct msm_audio *prtd = runtime->private_data;
1095 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
1096 struct audio_buffer *buf;
1097 int dir, ret;
1098
1099 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1100 dir = IN;
1101 else
1102 dir = OUT;
1103 ret = q6asm_audio_client_buf_alloc_contiguous(dir,
1104 prtd->audio_client,
1105 (params_buffer_bytes(params) / params_periods(params)),
1106 params_periods(params));
1107 if (ret < 0) {
1108 pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
1109 ret);
1110 return -ENOMEM;
1111 }
1112 buf = prtd->audio_client->port[dir].buf;
1113 if (buf == NULL || buf[0].data == NULL)
1114 return -ENOMEM;
1115
1116 pr_debug("%s:buf = %pK\n", __func__, buf);
1117 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
1118 dma_buf->dev.dev = substream->pcm->card->dev;
1119 dma_buf->private_data = NULL;
1120 dma_buf->area = buf[0].data;
1121 dma_buf->addr = buf[0].phys;
1122 dma_buf->bytes = params_buffer_bytes(params);
1123 if (!dma_buf->area)
1124 return -ENOMEM;
1125
1126 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
1127 return 0;
1128}
1129
1130static const struct snd_pcm_ops msm_pcm_ops = {
1131 .open = msm_pcm_open,
Meng Wangac147b72017-10-30 16:46:16 +08001132 .copy_user = msm_pcm_copy,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301133 .hw_params = msm_pcm_hw_params,
1134 .close = msm_pcm_close,
1135 .ioctl = snd_pcm_lib_ioctl,
1136 .prepare = msm_pcm_prepare,
1137 .trigger = msm_pcm_trigger,
1138 .pointer = msm_pcm_pointer,
1139 .mmap = msm_pcm_mmap,
1140};
1141
1142static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
1143 struct snd_ctl_elem_value *ucontrol)
1144{
1145 struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
1146 struct snd_soc_platform *platform = snd_soc_component_to_platform(pcm);
1147 struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
1148 struct snd_pcm_substream *substream;
1149 struct msm_audio *prtd;
1150 int ret = 0;
1151 struct msm_adsp_event_data *event_data = NULL;
1152
1153 if (!pdata) {
1154 pr_err("%s pdata is NULL\n", __func__);
1155 ret = -ENODEV;
1156 goto done;
1157 }
1158
1159 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1160 if (!substream) {
1161 pr_err("%s substream not found\n", __func__);
1162 ret = -EINVAL;
1163 goto done;
1164 }
1165
1166 if (!substream->runtime) {
1167 pr_err("%s substream runtime not found\n", __func__);
1168 ret = -EINVAL;
1169 goto done;
1170 }
1171
1172 prtd = substream->runtime->private_data;
1173 if (prtd->audio_client == NULL) {
1174 pr_err("%s prtd is null.\n", __func__);
1175 ret = -EINVAL;
1176 goto done;
1177 }
1178
1179 event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
1180 if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
1181 (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
1182 pr_err("%s: invalid event_type=%d",
1183 __func__, event_data->event_type);
1184 ret = -EINVAL;
1185 goto done;
1186 }
1187
Xiaojun Sang75642c32018-03-23 08:57:33 +08001188 if (event_data->payload_len > sizeof(ucontrol->value.bytes.data)
1189 - sizeof(struct msm_adsp_event_data)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301190 pr_err("%s param length=%d exceeds limit",
1191 __func__, event_data->payload_len);
1192 ret = -EINVAL;
1193 goto done;
1194 }
1195
1196 ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
1197 if (ret < 0)
1198 pr_err("%s: failed to send stream event cmd, err = %d\n",
1199 __func__, ret);
1200done:
1201 return ret;
1202}
1203
1204static int msm_pcm_add_audio_adsp_stream_cmd_control(
1205 struct snd_soc_pcm_runtime *rtd)
1206{
1207 const char *mixer_ctl_name = DSP_STREAM_CMD;
1208 const char *deviceNo = "NN";
1209 char *mixer_str = NULL;
1210 int ctl_len = 0, ret = 0;
1211 struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
1212 {
1213 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1214 .name = "?",
1215 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1216 .info = msm_adsp_stream_cmd_info,
1217 .put = msm_pcm_adsp_stream_cmd_put,
1218 .private_value = 0,
1219 }
1220 };
1221
1222 if (!rtd) {
1223 pr_err("%s rtd is NULL\n", __func__);
1224 ret = -EINVAL;
1225 goto done;
1226 }
1227
1228 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1229 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1230 if (!mixer_str) {
1231 ret = -ENOMEM;
1232 goto done;
1233 }
1234
1235 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1236 fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
1237 fe_audio_adsp_stream_cmd_config_control[0].private_value =
1238 rtd->dai_link->id;
1239 pr_debug("Registering new mixer ctl %s\n", mixer_str);
1240 ret = snd_soc_add_platform_controls(rtd->platform,
1241 fe_audio_adsp_stream_cmd_config_control,
1242 ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
1243 if (ret < 0)
1244 pr_err("%s: failed add ctl %s. err = %d\n",
1245 __func__, mixer_str, ret);
1246
1247 kfree(mixer_str);
1248done:
1249 return ret;
1250}
1251
1252static int msm_pcm_add_audio_adsp_stream_callback_control(
1253 struct snd_soc_pcm_runtime *rtd)
1254{
1255 const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
1256 const char *deviceNo = "NN";
1257 char *mixer_str = NULL;
1258 int ctl_len = 0, ret = 0;
1259 struct snd_kcontrol *kctl;
1260
1261 struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
1262 {
1263 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1264 .name = "?",
1265 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1266 .info = msm_adsp_stream_callback_info,
1267 .get = msm_adsp_stream_callback_get,
1268 .private_value = 0,
1269 }
1270 };
1271
1272 if (!rtd) {
1273 pr_err("%s NULL rtd\n", __func__);
1274 ret = -EINVAL;
1275 goto done;
1276 }
1277
1278 pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
1279 __func__, rtd->dai_link->name, rtd->dai_link->id,
1280 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
1281 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1282 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1283 if (!mixer_str) {
1284 ret = -ENOMEM;
1285 goto done;
1286 }
1287
1288 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1289 fe_audio_adsp_callback_config_control[0].name = mixer_str;
1290 fe_audio_adsp_callback_config_control[0].private_value =
1291 rtd->dai_link->id;
1292 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1293 ret = snd_soc_add_platform_controls(rtd->platform,
1294 fe_audio_adsp_callback_config_control,
1295 ARRAY_SIZE(fe_audio_adsp_callback_config_control));
1296 if (ret < 0) {
1297 pr_err("%s: failed to add ctl %s. err = %d\n",
1298 __func__, mixer_str, ret);
1299 ret = -EINVAL;
1300 goto free_mixer_str;
1301 }
1302
1303 kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
1304 if (!kctl) {
1305 pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
1306 ret = -EINVAL;
1307 goto free_mixer_str;
1308 }
1309
1310 kctl->private_data = NULL;
1311
1312free_mixer_str:
1313 kfree(mixer_str);
1314done:
1315 return ret;
1316}
1317
1318static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
1319{
1320 int rc = 0;
1321
1322 if (prtd && prtd->audio_client) {
1323 pr_debug("%s: channels %d volume 0x%x\n", __func__,
1324 prtd->channel_mode, volume);
1325 rc = q6asm_set_volume(prtd->audio_client, volume);
1326 if (rc < 0) {
1327 pr_err("%s: Send Volume command failed rc=%d\n",
1328 __func__, rc);
1329 }
1330 }
1331 return rc;
1332}
1333
1334static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
1335 struct snd_ctl_elem_value *ucontrol)
1336{
1337 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
1338 struct snd_pcm_substream *substream =
1339 vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1340 struct msm_audio *prtd;
1341
1342 pr_debug("%s\n", __func__);
1343 if (!substream) {
1344 pr_err("%s substream not found\n", __func__);
1345 return -ENODEV;
1346 }
1347 if (!substream->runtime) {
1348 pr_err("%s substream runtime not found\n", __func__);
1349 return 0;
1350 }
1351 prtd = substream->runtime->private_data;
1352 if (prtd)
1353 ucontrol->value.integer.value[0] = prtd->volume;
1354 return 0;
1355}
1356
1357static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
1358 struct snd_ctl_elem_value *ucontrol)
1359{
1360 int rc = 0;
1361 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
1362 struct snd_pcm_substream *substream =
1363 vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1364 struct msm_audio *prtd;
1365 int volume = ucontrol->value.integer.value[0];
1366
1367 pr_debug("%s: volume : 0x%x\n", __func__, volume);
1368 if (!substream) {
1369 pr_err("%s substream not found\n", __func__);
1370 return -ENODEV;
1371 }
1372 if (!substream->runtime) {
1373 pr_err("%s substream runtime not found\n", __func__);
1374 return 0;
1375 }
1376 prtd = substream->runtime->private_data;
1377 if (prtd) {
1378 rc = msm_pcm_set_volume(prtd, volume);
1379 prtd->volume = volume;
1380 }
1381 return rc;
1382}
1383
1384static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
1385{
1386 int ret = 0;
1387 struct snd_pcm *pcm = rtd->pcm;
1388 struct snd_pcm_volume *volume_info;
1389 struct snd_kcontrol *kctl;
1390
1391 dev_dbg(rtd->dev, "%s, Volume control add\n", __func__);
1392 ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1393 NULL, 1, rtd->dai_link->id,
1394 &volume_info);
1395 if (ret < 0) {
1396 pr_err("%s volume control failed ret %d\n", __func__, ret);
1397 return ret;
1398 }
1399 kctl = volume_info->kctl;
1400 kctl->put = msm_pcm_volume_ctl_put;
1401 kctl->get = msm_pcm_volume_ctl_get;
1402 kctl->tlv.p = msm_pcm_vol_gain;
1403 return 0;
1404}
1405
1406static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
1407 struct snd_ctl_elem_info *uinfo)
1408{
1409 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1410 uinfo->count = 1;
1411 uinfo->value.integer.min = 0;
1412 uinfo->value.integer.max = 0x2000;
1413 return 0;
1414}
1415
1416static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
1417 struct snd_ctl_elem_value *ucontrol)
1418{
1419 struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
1420 struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
1421 struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
1422 struct snd_pcm_substream *substream;
1423 struct msm_audio *prtd;
1424
1425 if (!pdata) {
1426 pr_err("%s pdata is NULL\n", __func__);
1427 return -ENODEV;
1428 }
1429 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1430 if (!substream) {
1431 pr_err("%s substream not found\n", __func__);
1432 return -EINVAL;
1433 }
1434 if (!substream->runtime) {
1435 pr_err("%s substream runtime not found\n", __func__);
1436 return 0;
1437 }
1438 prtd = substream->runtime->private_data;
1439 if (prtd)
1440 ucontrol->value.integer.value[0] = prtd->compress_enable;
1441 return 0;
1442}
1443
1444static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
1445 struct snd_ctl_elem_value *ucontrol)
1446{
1447 int rc = 0;
1448 struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
1449 struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
1450 struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
1451 struct snd_pcm_substream *substream;
1452 struct msm_audio *prtd;
1453 int compress = ucontrol->value.integer.value[0];
1454
1455 if (!pdata) {
1456 pr_err("%s pdata is NULL\n", __func__);
1457 return -ENODEV;
1458 }
1459 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1460 pr_debug("%s: compress : 0x%x\n", __func__, compress);
1461 if (!substream) {
1462 pr_err("%s substream not found\n", __func__);
1463 return -EINVAL;
1464 }
1465 if (!substream->runtime) {
1466 pr_err("%s substream runtime not found\n", __func__);
1467 return 0;
1468 }
1469 prtd = substream->runtime->private_data;
1470 if (prtd) {
1471 pr_debug("%s: setting compress flag to 0x%x\n",
1472 __func__, compress);
1473 prtd->compress_enable = compress;
1474 }
1475 return rc;
1476}
1477
1478static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
1479{
1480 const char *mixer_ctl_name = "Playback ";
1481 const char *mixer_ctl_end_name = " Compress";
1482 const char *deviceNo = "NN";
1483 char *mixer_str = NULL;
1484 int ctl_len;
1485 int ret = 0;
1486 struct msm_plat_data *pdata;
1487 struct snd_kcontrol_new pcm_compress_control[1] = {
1488 {
1489 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1490 .name = "?",
1491 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1492 .info = msm_pcm_compress_ctl_info,
1493 .get = msm_pcm_compress_ctl_get,
1494 .put = msm_pcm_compress_ctl_put,
1495 .private_value = 0,
1496 }
1497 };
1498
1499 if (!rtd) {
1500 pr_err("%s: NULL rtd\n", __func__);
1501 return -EINVAL;
1502 }
1503
1504 ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
1505 strlen(mixer_ctl_end_name) + 1;
1506 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1507
1508 if (!mixer_str)
1509 return -ENOMEM;
1510
1511 snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
1512 rtd->pcm->device, mixer_ctl_end_name);
1513
1514 pcm_compress_control[0].name = mixer_str;
1515 pcm_compress_control[0].private_value = rtd->dai_link->id;
1516 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1517 pdata = dev_get_drvdata(rtd->platform->dev);
1518 if (pdata) {
1519 if (!pdata->pcm) {
1520 pdata->pcm = rtd->pcm;
1521 snd_soc_add_platform_controls(rtd->platform,
1522 pcm_compress_control,
1523 ARRAY_SIZE
1524 (pcm_compress_control));
1525 pr_debug("%s: add control success plt = %pK\n",
1526 __func__, rtd->platform);
1527 }
1528 } else {
1529 pr_err("%s: NULL pdata\n", __func__);
1530 ret = -EINVAL;
1531 }
1532 kfree(mixer_str);
1533 return ret;
1534}
1535
1536static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1537 struct snd_ctl_elem_value *ucontrol)
1538{
1539 int i;
1540 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1541 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1542 struct snd_pcm_substream *substream;
1543 struct msm_audio *prtd;
1544
1545 pr_debug("%s", __func__);
1546 substream = snd_pcm_chmap_substream(info, idx);
1547 if (!substream)
1548 return -ENODEV;
1549 if (!substream->runtime)
1550 return 0;
1551
1552 prtd = substream->runtime->private_data;
1553 if (prtd) {
1554 prtd->set_channel_map = true;
Dieter Luecking70668fc2018-09-28 15:03:01 +02001555 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301556 prtd->channel_map[i] =
1557 (char)(ucontrol->value.integer.value[i]);
1558 }
1559 return 0;
1560}
1561
1562static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
1563 struct snd_ctl_elem_value *ucontrol)
1564{
1565 int i;
1566 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1567 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1568 struct snd_pcm_substream *substream;
1569 struct msm_audio *prtd;
1570
1571 pr_debug("%s", __func__);
1572 substream = snd_pcm_chmap_substream(info, idx);
1573 if (!substream)
1574 return -ENODEV;
1575 memset(ucontrol->value.integer.value, 0,
1576 sizeof(ucontrol->value.integer.value));
1577 if (!substream->runtime)
1578 return 0; /* no channels set */
1579
1580 prtd = substream->runtime->private_data;
1581
1582 if (prtd && prtd->set_channel_map == true) {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001583 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301584 ucontrol->value.integer.value[i] =
1585 (int)prtd->channel_map[i];
1586 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001587 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301588 ucontrol->value.integer.value[i] = 0;
1589 }
1590
1591 return 0;
1592}
1593
1594static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
1595{
1596 struct snd_pcm *pcm = rtd->pcm;
1597 struct snd_pcm_chmap *chmap_info;
1598 struct snd_kcontrol *kctl;
1599 char device_num[12];
1600 int i, ret = 0;
1601
1602 pr_debug("%s, Channel map cntrl add\n", __func__);
1603 ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1604 snd_pcm_std_chmaps,
Dieter Luecking70668fc2018-09-28 15:03:01 +02001605 PCM_FORMAT_MAX_NUM_CHANNEL_V8, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301606 &chmap_info);
1607 if (ret < 0) {
1608 pr_err("%s, channel map cntrl add failed\n", __func__);
1609 return ret;
1610 }
1611 kctl = chmap_info->kctl;
1612 for (i = 0; i < kctl->count; i++)
1613 kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
1614 snprintf(device_num, sizeof(device_num), "%d", pcm->device);
1615 strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
1616 pr_debug("%s, Overwriting channel map control name to: %s\n",
1617 __func__, kctl->id.name);
1618 kctl->put = msm_pcm_chmap_ctl_put;
1619 kctl->get = msm_pcm_chmap_ctl_get;
1620 return 0;
1621}
1622
1623static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1624 struct snd_ctl_elem_value *ucontrol)
1625{
1626 u64 fe_id = kcontrol->private_value;
1627 int session_type = SESSION_TYPE_RX;
1628 int be_id = ucontrol->value.integer.value[3];
1629 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1630 int ret = 0;
1631
1632 cfg_data.app_type = ucontrol->value.integer.value[0];
1633 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1634 if (ucontrol->value.integer.value[2] != 0)
1635 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1636 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1637 __func__, fe_id, session_type, be_id,
1638 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1639 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1640 be_id, &cfg_data);
1641 if (ret < 0)
1642 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1643 __func__, ret);
1644
1645 return ret;
1646}
1647
1648static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1649 struct snd_ctl_elem_value *ucontrol)
1650{
1651 u64 fe_id = kcontrol->private_value;
1652 int session_type = SESSION_TYPE_RX;
1653 int be_id = 0;
1654 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1655 int ret = 0;
1656
1657 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1658 &be_id, &cfg_data);
1659 if (ret < 0) {
1660 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1661 __func__, ret);
1662 goto done;
1663 }
1664
1665 ucontrol->value.integer.value[0] = cfg_data.app_type;
1666 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1667 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1668 ucontrol->value.integer.value[3] = be_id;
1669 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1670 __func__, fe_id, session_type, be_id,
1671 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1672done:
1673 return ret;
1674}
1675
1676static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1677 struct snd_ctl_elem_value *ucontrol)
1678{
1679 u64 fe_id = kcontrol->private_value;
1680 int session_type = SESSION_TYPE_TX;
1681 int be_id = ucontrol->value.integer.value[3];
1682 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1683 int ret = 0;
1684
1685 cfg_data.app_type = ucontrol->value.integer.value[0];
1686 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1687 if (ucontrol->value.integer.value[2] != 0)
1688 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1689 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1690 __func__, fe_id, session_type, be_id,
1691 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1692 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1693 be_id, &cfg_data);
1694 if (ret < 0)
1695 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1696 __func__, ret);
1697
1698 return ret;
1699}
1700
1701static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1702 struct snd_ctl_elem_value *ucontrol)
1703{
1704 u64 fe_id = kcontrol->private_value;
1705 int session_type = SESSION_TYPE_TX;
1706 int be_id = 0;
1707 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1708 int ret = 0;
1709
1710 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1711 &be_id, &cfg_data);
1712 if (ret < 0) {
1713 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1714 __func__, ret);
1715 goto done;
1716 }
1717
1718 ucontrol->value.integer.value[0] = cfg_data.app_type;
1719 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1720 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1721 ucontrol->value.integer.value[3] = be_id;
1722 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1723 __func__, fe_id, session_type, be_id,
1724 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1725done:
1726 return ret;
1727}
1728
1729static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
1730{
1731 struct snd_pcm *pcm = rtd->pcm;
1732 struct snd_pcm_usr *app_type_info;
1733 struct snd_kcontrol *kctl;
1734 const char *playback_mixer_ctl_name = "Audio Stream";
1735 const char *capture_mixer_ctl_name = "Audio Stream Capture";
1736 const char *deviceNo = "NN";
1737 const char *suffix = "App Type Cfg";
1738 int ctl_len, ret = 0;
1739
1740 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
1741 ctl_len = strlen(playback_mixer_ctl_name) + 1 +
1742 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1743 pr_debug("%s: Playback app type cntrl add\n", __func__);
1744 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1745 NULL, 1, ctl_len, rtd->dai_link->id,
1746 &app_type_info);
1747 if (ret < 0) {
1748 pr_err("%s: playback app type cntrl add failed: %d\n",
1749 __func__, ret);
1750 return ret;
1751 }
1752 kctl = app_type_info->kctl;
1753 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1754 playback_mixer_ctl_name, rtd->pcm->device, suffix);
1755 kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
1756 kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
1757 }
1758
1759 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
1760 ctl_len = strlen(capture_mixer_ctl_name) + 1 +
1761 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1762 pr_debug("%s: Capture app type cntrl add\n", __func__);
1763 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
1764 NULL, 1, ctl_len, rtd->dai_link->id,
1765 &app_type_info);
1766 if (ret < 0) {
1767 pr_err("%s: capture app type cntrl add failed: %d\n",
1768 __func__, ret);
1769 return ret;
1770 }
1771 kctl = app_type_info->kctl;
1772 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1773 capture_mixer_ctl_name, rtd->pcm->device, suffix);
1774 kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
1775 kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
1776 }
1777
1778 return 0;
1779}
1780
1781static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
1782{
1783 int ret = 0;
1784
1785 pr_debug("%s\n", __func__);
1786 ret = msm_pcm_add_chmap_controls(rtd);
1787 if (ret)
1788 pr_err("%s: pcm add controls failed:%d\n", __func__, ret);
1789 ret = msm_pcm_add_app_type_controls(rtd);
1790 if (ret)
1791 pr_err("%s: pcm add app type controls failed:%d\n",
1792 __func__, ret);
1793 return ret;
1794}
1795
1796static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
1797{
1798 struct snd_card *card = rtd->card->snd_card;
1799 int ret = 0;
1800
1801 if (!card->dev->coherent_dma_mask)
1802 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
1803
1804 ret = msm_pcm_add_controls(rtd);
1805 if (ret) {
1806 pr_err("%s, kctl add failed:%d\n", __func__, ret);
1807 return ret;
1808 }
1809
1810 ret = msm_pcm_add_volume_control(rtd);
1811 if (ret)
1812 pr_err("%s: Could not add pcm Volume Control %d\n",
1813 __func__, ret);
1814
1815 ret = msm_pcm_add_compress_control(rtd);
1816 if (ret)
1817 pr_err("%s: Could not add pcm Compress Control %d\n",
1818 __func__, ret);
1819
1820 ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
1821 if (ret)
1822 pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
1823 __func__);
1824
1825 ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
1826 if (ret)
1827 pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
1828 __func__);
1829
1830 return ret;
1831}
1832
1833static snd_pcm_sframes_t msm_pcm_delay_blk(struct snd_pcm_substream *substream,
1834 struct snd_soc_dai *dai)
1835{
1836 struct snd_pcm_runtime *runtime = substream->runtime;
1837 struct msm_audio *prtd = runtime->private_data;
1838 struct audio_client *ac = prtd->audio_client;
1839 snd_pcm_sframes_t frames;
1840 int ret;
1841
1842 ret = q6asm_get_path_delay(prtd->audio_client);
1843 if (ret) {
1844 pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
1845 return 0;
1846 }
1847
1848 /* convert microseconds to frames */
1849 frames = ac->path_delay / 1000 * runtime->rate / 1000;
1850
1851 /* also convert the remainder from the initial division */
1852 frames += ac->path_delay % 1000 * runtime->rate / 1000000;
1853
1854 /* overcompensate for the loss of precision (empirical) */
1855 frames += 2;
1856
1857 return frames;
1858}
1859
1860static struct snd_soc_platform_driver msm_soc_platform = {
1861 .ops = &msm_pcm_ops,
1862 .pcm_new = msm_asoc_pcm_new,
1863 .delay_blk = msm_pcm_delay_blk,
1864};
1865
1866static int msm_pcm_probe(struct platform_device *pdev)
1867{
1868 int rc;
1869 int id;
1870 struct msm_plat_data *pdata;
1871 const char *latency_level;
1872
1873 rc = of_property_read_u32(pdev->dev.of_node,
1874 "qcom,msm-pcm-dsp-id", &id);
1875 if (rc) {
1876 dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
1877 __func__);
1878 return rc;
1879 }
1880
1881 pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
1882 if (!pdata)
1883 return -ENOMEM;
1884
1885 if (of_property_read_bool(pdev->dev.of_node,
1886 "qcom,msm-pcm-low-latency")) {
1887
1888 pdata->perf_mode = LOW_LATENCY_PCM_MODE;
1889 rc = of_property_read_string(pdev->dev.of_node,
1890 "qcom,latency-level", &latency_level);
1891 if (!rc) {
1892 if (!strcmp(latency_level, "ultra"))
1893 pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
1894 else if (!strcmp(latency_level, "ull-pp"))
1895 pdata->perf_mode =
1896 ULL_POST_PROCESSING_PCM_MODE;
1897 }
1898 } else {
1899 pdata->perf_mode = LEGACY_PCM_MODE;
1900 }
1901
1902 dev_set_drvdata(&pdev->dev, pdata);
1903
1904
1905 dev_dbg(&pdev->dev, "%s: dev name %s\n",
1906 __func__, dev_name(&pdev->dev));
1907 return snd_soc_register_platform(&pdev->dev,
1908 &msm_soc_platform);
1909}
1910
1911static int msm_pcm_remove(struct platform_device *pdev)
1912{
1913 struct msm_plat_data *pdata;
1914
1915 pdata = dev_get_drvdata(&pdev->dev);
1916 kfree(pdata);
1917 snd_soc_unregister_platform(&pdev->dev);
1918 return 0;
1919}
1920static const struct of_device_id msm_pcm_dt_match[] = {
1921 {.compatible = "qcom,msm-pcm-dsp"},
1922 {}
1923};
1924MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
1925
1926static struct platform_driver msm_pcm_driver = {
1927 .driver = {
1928 .name = "msm-pcm-dsp",
1929 .owner = THIS_MODULE,
1930 .of_match_table = msm_pcm_dt_match,
1931 },
1932 .probe = msm_pcm_probe,
1933 .remove = msm_pcm_remove,
1934};
1935
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301936int __init msm_pcm_dsp_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301937{
1938 init_waitqueue_head(&the_locks.enable_wait);
1939 init_waitqueue_head(&the_locks.eos_wait);
1940 init_waitqueue_head(&the_locks.write_wait);
1941 init_waitqueue_head(&the_locks.read_wait);
1942
1943 return platform_driver_register(&msm_pcm_driver);
1944}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301945
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05301946void msm_pcm_dsp_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301947{
1948 platform_driver_unregister(&msm_pcm_driver);
1949}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301950
1951MODULE_DESCRIPTION("PCM module platform driver");
1952MODULE_LICENSE("GPL v2");