blob: 5da97952c8f503661a871aace60c9216ad35648b [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 {
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530389 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200390 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530391 ADSP_ASM_API_VERSION_V2) &&
392 q6core_use_Q6_32ch_support())
Dieter Luecking70668fc2018-09-28 15:03:01 +0200393 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 Luecking70668fc2018-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 Luecking70668fc2018-09-28 15:03:01 +0200437
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530438 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200439 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530440 ADSP_ASM_API_VERSION_V2) &&
441 q6core_use_Q6_32ch_support()) {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200442
443 ret = q6asm_media_format_block_multi_ch_pcm_v5(
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530444 prtd->audio_client, runtime->rate,
445 runtime->channels, !prtd->set_channel_map,
446 prtd->channel_map, bits_per_sample,
447 sample_word_size, ASM_LITTLE_ENDIAN,
448 DEFAULT_QF);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200449 } else {
450 ret = q6asm_media_format_block_multi_ch_pcm_v4(
451 prtd->audio_client, runtime->rate,
452 runtime->channels, !prtd->set_channel_map,
453 prtd->channel_map, bits_per_sample,
454 sample_word_size, ASM_LITTLE_ENDIAN,
455 DEFAULT_QF);
456 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530457 }
458 if (ret < 0)
459 pr_info("%s: CMD Format block failed\n", __func__);
460
461 atomic_set(&prtd->out_count, runtime->periods);
462
463 prtd->enabled = 1;
464 prtd->cmd_pending = 0;
465 prtd->cmd_interrupt = 0;
466
467 return 0;
468}
469
470static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
471{
472 struct snd_pcm_runtime *runtime = substream->runtime;
473 struct msm_audio *prtd = runtime->private_data;
474 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
475 struct msm_plat_data *pdata;
476 struct snd_pcm_hw_params *params;
477 struct msm_pcm_routing_evt event;
478 int ret = 0;
479 int i = 0;
480 uint16_t bits_per_sample = 16;
481 uint16_t sample_word_size;
482
483 pdata = (struct msm_plat_data *)
484 dev_get_drvdata(soc_prtd->platform->dev);
485 if (!pdata) {
486 pr_err("%s: platform data not populated\n", __func__);
487 return -EINVAL;
488 }
489 if (!prtd || !prtd->audio_client) {
490 pr_err("%s: private data null or audio client freed\n",
491 __func__);
492 return -EINVAL;
493 }
494
495 if (prtd->enabled == IDLE) {
496 pr_debug("%s:perf_mode=%d periods=%d\n", __func__,
497 pdata->perf_mode, runtime->periods);
498 params = &soc_prtd->dpcm[substream->stream].hw_params;
499 if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) ||
500 (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE))
501 bits_per_sample = 24;
502 else if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
503 bits_per_sample = 32;
504
505 /* ULL mode is not supported in capture path */
506 if (pdata->perf_mode == LEGACY_PCM_MODE)
507 prtd->audio_client->perf_mode = LEGACY_PCM_MODE;
508 else
509 prtd->audio_client->perf_mode = LOW_LATENCY_PCM_MODE;
510
511 pr_debug("%s Opening %d-ch PCM read stream, perf_mode %d\n",
512 __func__, params_channels(params),
513 prtd->audio_client->perf_mode);
514
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530515 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200516 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530517 ADSP_ASM_API_VERSION_V2) &&
518 q6core_use_Q6_32ch_support())
Dieter Luecking70668fc2018-09-28 15:03:01 +0200519 ret = q6asm_open_read_v5(prtd->audio_client,
520 FORMAT_LINEAR_PCM,
521 bits_per_sample, false, ENC_CFG_ID_NONE);
522 else
523 ret = q6asm_open_read_v4(prtd->audio_client,
524 FORMAT_LINEAR_PCM,
Vikram Pandurangac712c172017-11-17 17:36:49 -0800525 bits_per_sample, false, ENC_CFG_ID_NONE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530526 if (ret < 0) {
527 pr_err("%s: q6asm_open_read failed\n", __func__);
528 q6asm_audio_client_free(prtd->audio_client);
529 prtd->audio_client = NULL;
530 return -ENOMEM;
531 }
532
533 ret = q6asm_send_cal(prtd->audio_client);
534 if (ret < 0)
535 pr_debug("%s : Send cal failed : %d", __func__, ret);
536
537 pr_debug("%s: session ID %d\n",
538 __func__, prtd->audio_client->session);
539 prtd->session_id = prtd->audio_client->session;
540 event.event_func = msm_pcm_route_event_handler;
541 event.priv_data = (void *) prtd;
542 ret = msm_pcm_routing_reg_phy_stream_v2(
543 soc_prtd->dai_link->id,
544 prtd->audio_client->perf_mode,
545 prtd->session_id, substream->stream,
546 event);
547 if (ret) {
548 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
549 return ret;
550 }
551 }
552
553 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
554 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
555 prtd->pcm_irq_pos = 0;
556 /* rate and channels are sent to audio driver */
557 prtd->samp_rate = runtime->rate;
558 prtd->channel_mode = runtime->channels;
559
560 if (prtd->enabled == IDLE || prtd->enabled == STOPPED) {
561 for (i = 0; i < runtime->periods; i++)
562 q6asm_read(prtd->audio_client);
563 prtd->periods = runtime->periods;
564 }
565
566 if (prtd->enabled != IDLE)
567 return 0;
568
569 switch (runtime->format) {
570 case SNDRV_PCM_FORMAT_S32_LE:
571 bits_per_sample = 32;
572 sample_word_size = 32;
573 break;
574 case SNDRV_PCM_FORMAT_S24_LE:
575 bits_per_sample = 24;
576 sample_word_size = 32;
577 break;
578 case SNDRV_PCM_FORMAT_S24_3LE:
579 bits_per_sample = 24;
580 sample_word_size = 24;
581 break;
582 case SNDRV_PCM_FORMAT_S16_LE:
583 default:
584 bits_per_sample = 16;
585 sample_word_size = 16;
586 break;
587 }
588
589 pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n",
590 __func__, prtd->samp_rate, prtd->channel_mode,
591 bits_per_sample, sample_word_size);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200592
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530593 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200594 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530595 ADSP_ASM_API_VERSION_V2) &&
596 q6core_use_Q6_32ch_support())
Dieter Luecking70668fc2018-09-28 15:03:01 +0200597 ret = q6asm_enc_cfg_blk_pcm_format_support_v5(
598 prtd->audio_client,
599 prtd->samp_rate,
600 prtd->channel_mode,
601 bits_per_sample,
602 sample_word_size,
603 ASM_LITTLE_ENDIAN,
604 DEFAULT_QF);
605 else
606 ret = q6asm_enc_cfg_blk_pcm_format_support_v4(
607 prtd->audio_client,
608 prtd->samp_rate,
609 prtd->channel_mode,
610 bits_per_sample,
611 sample_word_size,
612 ASM_LITTLE_ENDIAN,
613 DEFAULT_QF);
614
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530615 if (ret < 0)
616 pr_debug("%s: cmd cfg pcm was block failed", __func__);
617
618 prtd->enabled = RUNNING;
619
620 return ret;
621}
622
623static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
624{
625 int ret = 0;
626 struct snd_pcm_runtime *runtime = substream->runtime;
627 struct msm_audio *prtd = runtime->private_data;
628
629 switch (cmd) {
630 case SNDRV_PCM_TRIGGER_START:
631 case SNDRV_PCM_TRIGGER_RESUME:
632 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
633 pr_debug("%s: Trigger start\n", __func__);
634 ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
635 break;
636 case SNDRV_PCM_TRIGGER_STOP:
637 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
638 atomic_set(&prtd->start, 0);
639 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
640 prtd->enabled = STOPPED;
641 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
642 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 Bucha2eb2e612018-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;
Xiaojun Sangf27e3512018-05-23 17:14:31 +0800756
757 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
758 msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
759
Banajit Goswami616e68c2017-10-27 01:31:19 -0700760 /* Vote to update the Rx thread priority to RT Thread for playback */
761 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
762 (pdata->perf_mode == LOW_LATENCY_PCM_MODE))
763 apr_start_rx_rt(prtd->audio_client->apr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530764
765 return 0;
766}
767
768static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +0800769 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530770{
771 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530772 int xfer = 0;
773 char *bufptr = NULL;
774 void *data = NULL;
775 uint32_t idx = 0;
776 uint32_t size = 0;
777 uint32_t retries = 0;
778
779 struct snd_pcm_runtime *runtime = substream->runtime;
780 struct msm_audio *prtd = runtime->private_data;
781
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530782 pr_debug("%s: prtd->out_count = %d\n",
783 __func__, atomic_read(&prtd->out_count));
784
785 while ((fbytes > 0) && (retries < MAX_PB_COPY_RETRIES)) {
786 if (prtd->reset_event) {
787 pr_err("%s: In SSR return ENETRESET before wait\n",
788 __func__);
789 return -ENETRESET;
790 }
791
792 ret = wait_event_timeout(the_locks.write_wait,
793 (atomic_read(&prtd->out_count)), 5 * HZ);
794 if (!ret) {
795 pr_err("%s: wait_event_timeout failed\n", __func__);
796 ret = -ETIMEDOUT;
797 goto fail;
798 }
799 ret = 0;
800
801 if (prtd->reset_event) {
802 pr_err("%s: In SSR return ENETRESET after wait\n",
803 __func__);
804 return -ENETRESET;
805 }
806
807 if (!atomic_read(&prtd->out_count)) {
808 pr_err("%s: pcm stopped out_count 0\n", __func__);
809 return 0;
810 }
811
812 data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size,
813 &idx);
814 if (data == NULL) {
815 retries++;
816 continue;
817 } else {
818 retries = 0;
819 }
820
821 if (fbytes > size)
822 xfer = size;
823 else
824 xfer = fbytes;
825
826 bufptr = data;
827 if (bufptr) {
Meng Wangac147b72017-10-30 16:46:16 +0800828 pr_debug("%s:fbytes =%lu: xfer=%d size=%d\n",
829 __func__, fbytes, xfer, size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530830 if (copy_from_user(bufptr, buf, xfer)) {
831 ret = -EFAULT;
832 pr_err("%s: copy_from_user failed\n",
833 __func__);
834 q6asm_cpu_buf_release(IN, prtd->audio_client);
835 goto fail;
836 }
837 buf += xfer;
838 fbytes -= xfer;
Meng Wangac147b72017-10-30 16:46:16 +0800839 pr_debug("%s:fbytes = %lu: xfer=%d\n", __func__,
840 fbytes, xfer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530841 if (atomic_read(&prtd->start)) {
842 pr_debug("%s:writing %d bytes of buffer to dsp\n",
843 __func__, xfer);
844 ret = q6asm_write(prtd->audio_client, xfer,
845 0, 0, NO_TIMESTAMP);
846 if (ret < 0) {
847 ret = -EFAULT;
848 q6asm_cpu_buf_release(IN,
849 prtd->audio_client);
850 goto fail;
851 }
852 } else
853 atomic_inc(&prtd->out_needed);
854 atomic_dec(&prtd->out_count);
855 }
856 }
857fail:
858 if (retries >= MAX_PB_COPY_RETRIES)
859 ret = -ENOMEM;
860
861 return ret;
862}
863
864static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
865{
866 struct snd_pcm_runtime *runtime = substream->runtime;
867 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
868 struct msm_audio *prtd = runtime->private_data;
Banajit Goswami616e68c2017-10-27 01:31:19 -0700869 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530870 uint32_t timeout;
871 int dir = 0;
872 int ret = 0;
873
874 pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
875
876 if (prtd->audio_client) {
877 dir = IN;
878
Banajit Goswami616e68c2017-10-27 01:31:19 -0700879 /*
880 * Unvote to downgrade the Rx thread priority from
881 * RT Thread for Low-Latency use case.
882 */
883 pdata = (struct msm_plat_data *)
884 dev_get_drvdata(soc_prtd->platform->dev);
885 if (pdata) {
886 if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
887 apr_end_rx_rt(prtd->audio_client->apr);
888 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530889 /* determine timeout length */
890 if (runtime->frame_bits == 0 || runtime->rate == 0) {
891 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
892 } else {
893 timeout = (runtime->period_size *
894 CMD_EOS_TIMEOUT_MULTIPLIER) /
895 ((runtime->frame_bits / 8) *
896 runtime->rate);
897 if (timeout < CMD_EOS_MIN_TIMEOUT_LENGTH)
898 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
899 }
900 pr_debug("%s: CMD_EOS timeout is %d\n", __func__, timeout);
901
902 ret = wait_event_timeout(the_locks.eos_wait,
903 !test_bit(CMD_EOS, &prtd->cmd_pending),
904 timeout);
905 if (!ret)
906 pr_err("%s: CMD_EOS failed, cmd_pending 0x%lx\n",
907 __func__, prtd->cmd_pending);
908 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
909 q6asm_audio_client_buf_free_contiguous(dir,
910 prtd->audio_client);
911 q6asm_audio_client_free(prtd->audio_client);
912 }
913 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
914 SNDRV_PCM_STREAM_PLAYBACK);
915 msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
916 kfree(prtd);
917 runtime->private_data = NULL;
918
919 return 0;
920}
921
922static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
Meng Wangac147b72017-10-30 16:46:16 +0800923 int channel, unsigned long hwoff, void __user *buf,
924 unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530925{
926 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530927 int xfer;
928 char *bufptr;
929 void *data = NULL;
930 static uint32_t idx;
931 static uint32_t size;
932 uint32_t offset = 0;
933 struct snd_pcm_runtime *runtime = substream->runtime;
934 struct msm_audio *prtd = substream->runtime->private_data;
935
936
937 pr_debug("%s\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530938
939 pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
940 pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
941 pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
942
943 if (prtd->reset_event) {
944 pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
945 return -ENETRESET;
946 }
947 ret = wait_event_timeout(the_locks.read_wait,
948 (atomic_read(&prtd->in_count)), 5 * HZ);
949 if (!ret) {
950 pr_debug("%s: wait_event_timeout failed\n", __func__);
951 goto fail;
952 }
953 if (prtd->reset_event) {
954 pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
955 return -ENETRESET;
956 }
957 if (!atomic_read(&prtd->in_count)) {
958 pr_debug("%s: pcm stopped in_count 0\n", __func__);
959 return 0;
960 }
961 pr_debug("Checking if valid buffer is available...%pK\n",
962 data);
963 data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
964 bufptr = data;
965 pr_debug("Size = %d\n", size);
Meng Wangac147b72017-10-30 16:46:16 +0800966 pr_debug("fbytes = %lu\n", fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530967 pr_debug("idx = %d\n", idx);
968 if (bufptr) {
969 xfer = fbytes;
970 if (xfer > size)
971 xfer = size;
972 offset = prtd->in_frame_info[idx].offset;
973 pr_debug("Offset value = %d\n", offset);
974 if (copy_to_user(buf, bufptr+offset, xfer)) {
975 pr_err("Failed to copy buf to user\n");
976 ret = -EFAULT;
977 q6asm_cpu_buf_release(OUT, prtd->audio_client);
978 goto fail;
979 }
980 fbytes -= xfer;
981 size -= xfer;
982 prtd->in_frame_info[idx].offset += xfer;
Meng Wangac147b72017-10-30 16:46:16 +0800983 pr_debug("%s:fbytes = %lu: size=%d: xfer=%d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530984 __func__, fbytes, size, xfer);
985 pr_debug(" Sending next buffer to dsp\n");
986 memset(&prtd->in_frame_info[idx], 0,
987 sizeof(struct msm_audio_in_frame_info));
988 atomic_dec(&prtd->in_count);
989 ret = q6asm_read(prtd->audio_client);
990 if (ret < 0) {
991 pr_err("q6asm read failed\n");
992 ret = -EFAULT;
993 q6asm_cpu_buf_release(OUT, prtd->audio_client);
994 goto fail;
995 }
996 } else
997 pr_err("No valid buffer\n");
998
999 pr_debug("Returning from capture_copy... %d\n", ret);
1000fail:
1001 return ret;
1002}
1003
1004static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
1005{
1006 struct snd_pcm_runtime *runtime = substream->runtime;
1007 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
1008 struct msm_audio *prtd = runtime->private_data;
1009 int dir = OUT;
1010
1011 pr_debug("%s\n", __func__);
1012 if (prtd->audio_client) {
1013 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
1014 q6asm_audio_client_buf_free_contiguous(dir,
1015 prtd->audio_client);
1016 q6asm_audio_client_free(prtd->audio_client);
1017 }
1018
1019 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
1020 SNDRV_PCM_STREAM_CAPTURE);
1021 kfree(prtd);
1022 runtime->private_data = NULL;
1023
1024 return 0;
1025}
1026
1027static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +08001028 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301029{
1030 int ret = 0;
1031
1032 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Meng Wangac147b72017-10-30 16:46:16 +08001033 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301034 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
Meng Wangac147b72017-10-30 16:46:16 +08001035 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301036 return ret;
1037}
1038
1039static int msm_pcm_close(struct snd_pcm_substream *substream)
1040{
1041 int ret = 0;
1042
1043 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1044 ret = msm_pcm_playback_close(substream);
1045 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1046 ret = msm_pcm_capture_close(substream);
1047 return ret;
1048}
1049
1050static int msm_pcm_prepare(struct snd_pcm_substream *substream)
1051{
1052 int ret = 0;
1053
1054 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1055 ret = msm_pcm_playback_prepare(substream);
1056 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1057 ret = msm_pcm_capture_prepare(substream);
1058 return ret;
1059}
1060
1061static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
1062{
1063
1064 struct snd_pcm_runtime *runtime = substream->runtime;
1065 struct msm_audio *prtd = runtime->private_data;
1066
1067 if (prtd->pcm_irq_pos >= prtd->pcm_size)
1068 prtd->pcm_irq_pos = 0;
1069
1070 pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
1071 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
1072}
1073
1074static int msm_pcm_mmap(struct snd_pcm_substream *substream,
1075 struct vm_area_struct *vma)
1076{
1077 struct snd_pcm_runtime *runtime = substream->runtime;
1078 struct msm_audio *prtd = runtime->private_data;
1079 struct audio_client *ac = prtd->audio_client;
1080 struct audio_port_data *apd = ac->port;
1081 struct audio_buffer *ab;
1082 int dir = -1;
1083
1084 prtd->mmap_flag = 1;
1085
1086 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1087 dir = IN;
1088 else
1089 dir = OUT;
1090 ab = &(apd[dir].buf[0]);
1091
1092 return msm_audio_ion_mmap(ab, vma);
1093}
1094
1095static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
1096 struct snd_pcm_hw_params *params)
1097{
1098 struct snd_pcm_runtime *runtime = substream->runtime;
1099 struct msm_audio *prtd = runtime->private_data;
1100 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
1101 struct audio_buffer *buf;
1102 int dir, ret;
1103
1104 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1105 dir = IN;
1106 else
1107 dir = OUT;
1108 ret = q6asm_audio_client_buf_alloc_contiguous(dir,
1109 prtd->audio_client,
1110 (params_buffer_bytes(params) / params_periods(params)),
1111 params_periods(params));
1112 if (ret < 0) {
1113 pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
1114 ret);
1115 return -ENOMEM;
1116 }
1117 buf = prtd->audio_client->port[dir].buf;
1118 if (buf == NULL || buf[0].data == NULL)
1119 return -ENOMEM;
1120
1121 pr_debug("%s:buf = %pK\n", __func__, buf);
1122 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
1123 dma_buf->dev.dev = substream->pcm->card->dev;
1124 dma_buf->private_data = NULL;
1125 dma_buf->area = buf[0].data;
1126 dma_buf->addr = buf[0].phys;
1127 dma_buf->bytes = params_buffer_bytes(params);
1128 if (!dma_buf->area)
1129 return -ENOMEM;
1130
1131 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
1132 return 0;
1133}
1134
1135static const struct snd_pcm_ops msm_pcm_ops = {
1136 .open = msm_pcm_open,
Meng Wangac147b72017-10-30 16:46:16 +08001137 .copy_user = msm_pcm_copy,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301138 .hw_params = msm_pcm_hw_params,
1139 .close = msm_pcm_close,
1140 .ioctl = snd_pcm_lib_ioctl,
1141 .prepare = msm_pcm_prepare,
1142 .trigger = msm_pcm_trigger,
1143 .pointer = msm_pcm_pointer,
1144 .mmap = msm_pcm_mmap,
1145};
1146
1147static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
1148 struct snd_ctl_elem_value *ucontrol)
1149{
1150 struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
1151 struct snd_soc_platform *platform = snd_soc_component_to_platform(pcm);
1152 struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
1153 struct snd_pcm_substream *substream;
1154 struct msm_audio *prtd;
1155 int ret = 0;
1156 struct msm_adsp_event_data *event_data = NULL;
1157
1158 if (!pdata) {
1159 pr_err("%s pdata is NULL\n", __func__);
1160 ret = -ENODEV;
1161 goto done;
1162 }
1163
1164 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1165 if (!substream) {
1166 pr_err("%s substream not found\n", __func__);
1167 ret = -EINVAL;
1168 goto done;
1169 }
1170
1171 if (!substream->runtime) {
1172 pr_err("%s substream runtime not found\n", __func__);
1173 ret = -EINVAL;
1174 goto done;
1175 }
1176
1177 prtd = substream->runtime->private_data;
Vatsal Bucha2eb2e612018-06-01 12:05:25 +05301178 if (prtd == NULL) {
1179 pr_err("%s prtd is null.\n", __func__);
1180 ret = -EINVAL;
1181 goto done;
1182 }
1183
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301184 if (prtd->audio_client == NULL) {
1185 pr_err("%s prtd is null.\n", __func__);
1186 ret = -EINVAL;
1187 goto done;
1188 }
1189
1190 event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
1191 if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
1192 (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
1193 pr_err("%s: invalid event_type=%d",
1194 __func__, event_data->event_type);
1195 ret = -EINVAL;
1196 goto done;
1197 }
1198
Xiaojun Sang75642c32018-03-23 08:57:33 +08001199 if (event_data->payload_len > sizeof(ucontrol->value.bytes.data)
1200 - sizeof(struct msm_adsp_event_data)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301201 pr_err("%s param length=%d exceeds limit",
1202 __func__, event_data->payload_len);
1203 ret = -EINVAL;
1204 goto done;
1205 }
1206
1207 ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
1208 if (ret < 0)
1209 pr_err("%s: failed to send stream event cmd, err = %d\n",
1210 __func__, ret);
1211done:
1212 return ret;
1213}
1214
1215static int msm_pcm_add_audio_adsp_stream_cmd_control(
1216 struct snd_soc_pcm_runtime *rtd)
1217{
1218 const char *mixer_ctl_name = DSP_STREAM_CMD;
1219 const char *deviceNo = "NN";
1220 char *mixer_str = NULL;
1221 int ctl_len = 0, ret = 0;
1222 struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
1223 {
1224 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1225 .name = "?",
1226 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1227 .info = msm_adsp_stream_cmd_info,
1228 .put = msm_pcm_adsp_stream_cmd_put,
1229 .private_value = 0,
1230 }
1231 };
1232
1233 if (!rtd) {
1234 pr_err("%s rtd is NULL\n", __func__);
1235 ret = -EINVAL;
1236 goto done;
1237 }
1238
1239 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1240 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1241 if (!mixer_str) {
1242 ret = -ENOMEM;
1243 goto done;
1244 }
1245
1246 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1247 fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
1248 fe_audio_adsp_stream_cmd_config_control[0].private_value =
1249 rtd->dai_link->id;
1250 pr_debug("Registering new mixer ctl %s\n", mixer_str);
1251 ret = snd_soc_add_platform_controls(rtd->platform,
1252 fe_audio_adsp_stream_cmd_config_control,
1253 ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
1254 if (ret < 0)
1255 pr_err("%s: failed add ctl %s. err = %d\n",
1256 __func__, mixer_str, ret);
1257
1258 kfree(mixer_str);
1259done:
1260 return ret;
1261}
1262
1263static int msm_pcm_add_audio_adsp_stream_callback_control(
1264 struct snd_soc_pcm_runtime *rtd)
1265{
1266 const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
1267 const char *deviceNo = "NN";
1268 char *mixer_str = NULL;
1269 int ctl_len = 0, ret = 0;
1270 struct snd_kcontrol *kctl;
1271
1272 struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
1273 {
1274 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1275 .name = "?",
1276 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1277 .info = msm_adsp_stream_callback_info,
1278 .get = msm_adsp_stream_callback_get,
1279 .private_value = 0,
1280 }
1281 };
1282
1283 if (!rtd) {
1284 pr_err("%s NULL rtd\n", __func__);
1285 ret = -EINVAL;
1286 goto done;
1287 }
1288
1289 pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
1290 __func__, rtd->dai_link->name, rtd->dai_link->id,
1291 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
1292 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1293 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1294 if (!mixer_str) {
1295 ret = -ENOMEM;
1296 goto done;
1297 }
1298
1299 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1300 fe_audio_adsp_callback_config_control[0].name = mixer_str;
1301 fe_audio_adsp_callback_config_control[0].private_value =
1302 rtd->dai_link->id;
1303 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1304 ret = snd_soc_add_platform_controls(rtd->platform,
1305 fe_audio_adsp_callback_config_control,
1306 ARRAY_SIZE(fe_audio_adsp_callback_config_control));
1307 if (ret < 0) {
1308 pr_err("%s: failed to add ctl %s. err = %d\n",
1309 __func__, mixer_str, ret);
1310 ret = -EINVAL;
1311 goto free_mixer_str;
1312 }
1313
1314 kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
1315 if (!kctl) {
1316 pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
1317 ret = -EINVAL;
1318 goto free_mixer_str;
1319 }
1320
1321 kctl->private_data = NULL;
1322
1323free_mixer_str:
1324 kfree(mixer_str);
1325done:
1326 return ret;
1327}
1328
1329static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
1330{
1331 int rc = 0;
1332
1333 if (prtd && prtd->audio_client) {
1334 pr_debug("%s: channels %d volume 0x%x\n", __func__,
1335 prtd->channel_mode, volume);
1336 rc = q6asm_set_volume(prtd->audio_client, volume);
1337 if (rc < 0) {
1338 pr_err("%s: Send Volume command failed rc=%d\n",
1339 __func__, rc);
1340 }
1341 }
1342 return rc;
1343}
1344
1345static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
1346 struct snd_ctl_elem_value *ucontrol)
1347{
1348 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
1349 struct snd_pcm_substream *substream =
1350 vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1351 struct msm_audio *prtd;
1352
1353 pr_debug("%s\n", __func__);
1354 if (!substream) {
1355 pr_err("%s substream not found\n", __func__);
1356 return -ENODEV;
1357 }
1358 if (!substream->runtime) {
Vignesh Kulothungan2ce67842018-09-25 16:40:29 -07001359 pr_debug("%s substream runtime not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301360 return 0;
1361 }
1362 prtd = substream->runtime->private_data;
1363 if (prtd)
1364 ucontrol->value.integer.value[0] = prtd->volume;
1365 return 0;
1366}
1367
1368static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
1369 struct snd_ctl_elem_value *ucontrol)
1370{
1371 int rc = 0;
1372 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
1373 struct snd_pcm_substream *substream =
1374 vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1375 struct msm_audio *prtd;
1376 int volume = ucontrol->value.integer.value[0];
1377
1378 pr_debug("%s: volume : 0x%x\n", __func__, volume);
1379 if (!substream) {
1380 pr_err("%s substream not found\n", __func__);
1381 return -ENODEV;
1382 }
1383 if (!substream->runtime) {
1384 pr_err("%s substream runtime not found\n", __func__);
1385 return 0;
1386 }
1387 prtd = substream->runtime->private_data;
1388 if (prtd) {
1389 rc = msm_pcm_set_volume(prtd, volume);
1390 prtd->volume = volume;
1391 }
1392 return rc;
1393}
1394
1395static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
1396{
1397 int ret = 0;
1398 struct snd_pcm *pcm = rtd->pcm;
1399 struct snd_pcm_volume *volume_info;
1400 struct snd_kcontrol *kctl;
1401
1402 dev_dbg(rtd->dev, "%s, Volume control add\n", __func__);
1403 ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1404 NULL, 1, rtd->dai_link->id,
1405 &volume_info);
1406 if (ret < 0) {
1407 pr_err("%s volume control failed ret %d\n", __func__, ret);
1408 return ret;
1409 }
1410 kctl = volume_info->kctl;
1411 kctl->put = msm_pcm_volume_ctl_put;
1412 kctl->get = msm_pcm_volume_ctl_get;
1413 kctl->tlv.p = msm_pcm_vol_gain;
1414 return 0;
1415}
1416
1417static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
1418 struct snd_ctl_elem_info *uinfo)
1419{
1420 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1421 uinfo->count = 1;
1422 uinfo->value.integer.min = 0;
1423 uinfo->value.integer.max = 0x2000;
1424 return 0;
1425}
1426
1427static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
1428 struct snd_ctl_elem_value *ucontrol)
1429{
1430 struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
1431 struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
1432 struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
1433 struct snd_pcm_substream *substream;
1434 struct msm_audio *prtd;
1435
1436 if (!pdata) {
1437 pr_err("%s pdata is NULL\n", __func__);
1438 return -ENODEV;
1439 }
1440 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1441 if (!substream) {
1442 pr_err("%s substream not found\n", __func__);
1443 return -EINVAL;
1444 }
1445 if (!substream->runtime) {
Vignesh Kulothungan2ce67842018-09-25 16:40:29 -07001446 pr_debug("%s substream runtime not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301447 return 0;
1448 }
1449 prtd = substream->runtime->private_data;
1450 if (prtd)
1451 ucontrol->value.integer.value[0] = prtd->compress_enable;
1452 return 0;
1453}
1454
1455static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
1456 struct snd_ctl_elem_value *ucontrol)
1457{
1458 int rc = 0;
1459 struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
1460 struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
1461 struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
1462 struct snd_pcm_substream *substream;
1463 struct msm_audio *prtd;
1464 int compress = ucontrol->value.integer.value[0];
1465
1466 if (!pdata) {
1467 pr_err("%s pdata is NULL\n", __func__);
1468 return -ENODEV;
1469 }
1470 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1471 pr_debug("%s: compress : 0x%x\n", __func__, compress);
1472 if (!substream) {
1473 pr_err("%s substream not found\n", __func__);
1474 return -EINVAL;
1475 }
1476 if (!substream->runtime) {
1477 pr_err("%s substream runtime not found\n", __func__);
1478 return 0;
1479 }
1480 prtd = substream->runtime->private_data;
1481 if (prtd) {
1482 pr_debug("%s: setting compress flag to 0x%x\n",
1483 __func__, compress);
1484 prtd->compress_enable = compress;
1485 }
1486 return rc;
1487}
1488
1489static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
1490{
1491 const char *mixer_ctl_name = "Playback ";
1492 const char *mixer_ctl_end_name = " Compress";
1493 const char *deviceNo = "NN";
1494 char *mixer_str = NULL;
1495 int ctl_len;
1496 int ret = 0;
1497 struct msm_plat_data *pdata;
1498 struct snd_kcontrol_new pcm_compress_control[1] = {
1499 {
1500 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1501 .name = "?",
1502 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1503 .info = msm_pcm_compress_ctl_info,
1504 .get = msm_pcm_compress_ctl_get,
1505 .put = msm_pcm_compress_ctl_put,
1506 .private_value = 0,
1507 }
1508 };
1509
1510 if (!rtd) {
1511 pr_err("%s: NULL rtd\n", __func__);
1512 return -EINVAL;
1513 }
1514
1515 ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
1516 strlen(mixer_ctl_end_name) + 1;
1517 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1518
1519 if (!mixer_str)
1520 return -ENOMEM;
1521
1522 snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
1523 rtd->pcm->device, mixer_ctl_end_name);
1524
1525 pcm_compress_control[0].name = mixer_str;
1526 pcm_compress_control[0].private_value = rtd->dai_link->id;
1527 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
1528 pdata = dev_get_drvdata(rtd->platform->dev);
1529 if (pdata) {
1530 if (!pdata->pcm) {
1531 pdata->pcm = rtd->pcm;
1532 snd_soc_add_platform_controls(rtd->platform,
1533 pcm_compress_control,
1534 ARRAY_SIZE
1535 (pcm_compress_control));
1536 pr_debug("%s: add control success plt = %pK\n",
1537 __func__, rtd->platform);
1538 }
1539 } else {
1540 pr_err("%s: NULL pdata\n", __func__);
1541 ret = -EINVAL;
1542 }
1543 kfree(mixer_str);
1544 return ret;
1545}
1546
1547static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1548 struct snd_ctl_elem_value *ucontrol)
1549{
1550 int i;
1551 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1552 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1553 struct snd_pcm_substream *substream;
1554 struct msm_audio *prtd;
1555
1556 pr_debug("%s", __func__);
1557 substream = snd_pcm_chmap_substream(info, idx);
1558 if (!substream)
1559 return -ENODEV;
1560 if (!substream->runtime)
1561 return 0;
1562
1563 prtd = substream->runtime->private_data;
1564 if (prtd) {
1565 prtd->set_channel_map = true;
Dieter Luecking70668fc2018-09-28 15:03:01 +02001566 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301567 prtd->channel_map[i] =
1568 (char)(ucontrol->value.integer.value[i]);
1569 }
1570 return 0;
1571}
1572
1573static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
1574 struct snd_ctl_elem_value *ucontrol)
1575{
1576 int i;
1577 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1578 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1579 struct snd_pcm_substream *substream;
1580 struct msm_audio *prtd;
1581
1582 pr_debug("%s", __func__);
1583 substream = snd_pcm_chmap_substream(info, idx);
1584 if (!substream)
1585 return -ENODEV;
1586 memset(ucontrol->value.integer.value, 0,
1587 sizeof(ucontrol->value.integer.value));
1588 if (!substream->runtime)
1589 return 0; /* no channels set */
1590
1591 prtd = substream->runtime->private_data;
1592
1593 if (prtd && prtd->set_channel_map == true) {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001594 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301595 ucontrol->value.integer.value[i] =
1596 (int)prtd->channel_map[i];
1597 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001598 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301599 ucontrol->value.integer.value[i] = 0;
1600 }
1601
1602 return 0;
1603}
1604
1605static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
1606{
1607 struct snd_pcm *pcm = rtd->pcm;
1608 struct snd_pcm_chmap *chmap_info;
1609 struct snd_kcontrol *kctl;
1610 char device_num[12];
1611 int i, ret = 0;
1612
1613 pr_debug("%s, Channel map cntrl add\n", __func__);
1614 ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1615 snd_pcm_std_chmaps,
Dieter Luecking70668fc2018-09-28 15:03:01 +02001616 PCM_FORMAT_MAX_NUM_CHANNEL_V8, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301617 &chmap_info);
1618 if (ret < 0) {
1619 pr_err("%s, channel map cntrl add failed\n", __func__);
1620 return ret;
1621 }
1622 kctl = chmap_info->kctl;
1623 for (i = 0; i < kctl->count; i++)
1624 kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
1625 snprintf(device_num, sizeof(device_num), "%d", pcm->device);
1626 strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
1627 pr_debug("%s, Overwriting channel map control name to: %s\n",
1628 __func__, kctl->id.name);
1629 kctl->put = msm_pcm_chmap_ctl_put;
1630 kctl->get = msm_pcm_chmap_ctl_get;
1631 return 0;
1632}
1633
1634static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1635 struct snd_ctl_elem_value *ucontrol)
1636{
1637 u64 fe_id = kcontrol->private_value;
1638 int session_type = SESSION_TYPE_RX;
1639 int be_id = ucontrol->value.integer.value[3];
1640 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1641 int ret = 0;
1642
1643 cfg_data.app_type = ucontrol->value.integer.value[0];
1644 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1645 if (ucontrol->value.integer.value[2] != 0)
1646 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1647 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1648 __func__, fe_id, session_type, be_id,
1649 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1650 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1651 be_id, &cfg_data);
1652 if (ret < 0)
1653 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1654 __func__, ret);
1655
1656 return ret;
1657}
1658
1659static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1660 struct snd_ctl_elem_value *ucontrol)
1661{
1662 u64 fe_id = kcontrol->private_value;
1663 int session_type = SESSION_TYPE_RX;
1664 int be_id = 0;
1665 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1666 int ret = 0;
1667
1668 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1669 &be_id, &cfg_data);
1670 if (ret < 0) {
1671 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1672 __func__, ret);
1673 goto done;
1674 }
1675
1676 ucontrol->value.integer.value[0] = cfg_data.app_type;
1677 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1678 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1679 ucontrol->value.integer.value[3] = be_id;
1680 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1681 __func__, fe_id, session_type, be_id,
1682 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1683done:
1684 return ret;
1685}
1686
1687static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1688 struct snd_ctl_elem_value *ucontrol)
1689{
1690 u64 fe_id = kcontrol->private_value;
1691 int session_type = SESSION_TYPE_TX;
1692 int be_id = ucontrol->value.integer.value[3];
1693 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1694 int ret = 0;
1695
1696 cfg_data.app_type = ucontrol->value.integer.value[0];
1697 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1698 if (ucontrol->value.integer.value[2] != 0)
1699 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1700 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1701 __func__, fe_id, session_type, be_id,
1702 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1703 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1704 be_id, &cfg_data);
1705 if (ret < 0)
1706 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1707 __func__, ret);
1708
1709 return ret;
1710}
1711
1712static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1713 struct snd_ctl_elem_value *ucontrol)
1714{
1715 u64 fe_id = kcontrol->private_value;
1716 int session_type = SESSION_TYPE_TX;
1717 int be_id = 0;
1718 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1719 int ret = 0;
1720
1721 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1722 &be_id, &cfg_data);
1723 if (ret < 0) {
1724 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1725 __func__, ret);
1726 goto done;
1727 }
1728
1729 ucontrol->value.integer.value[0] = cfg_data.app_type;
1730 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1731 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1732 ucontrol->value.integer.value[3] = be_id;
1733 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1734 __func__, fe_id, session_type, be_id,
1735 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1736done:
1737 return ret;
1738}
1739
1740static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
1741{
1742 struct snd_pcm *pcm = rtd->pcm;
1743 struct snd_pcm_usr *app_type_info;
1744 struct snd_kcontrol *kctl;
1745 const char *playback_mixer_ctl_name = "Audio Stream";
1746 const char *capture_mixer_ctl_name = "Audio Stream Capture";
1747 const char *deviceNo = "NN";
1748 const char *suffix = "App Type Cfg";
1749 int ctl_len, ret = 0;
1750
1751 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
1752 ctl_len = strlen(playback_mixer_ctl_name) + 1 +
1753 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1754 pr_debug("%s: Playback app type cntrl add\n", __func__);
1755 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1756 NULL, 1, ctl_len, rtd->dai_link->id,
1757 &app_type_info);
1758 if (ret < 0) {
1759 pr_err("%s: playback app type cntrl add failed: %d\n",
1760 __func__, ret);
1761 return ret;
1762 }
1763 kctl = app_type_info->kctl;
1764 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1765 playback_mixer_ctl_name, rtd->pcm->device, suffix);
1766 kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
1767 kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
1768 }
1769
1770 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
1771 ctl_len = strlen(capture_mixer_ctl_name) + 1 +
1772 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1773 pr_debug("%s: Capture app type cntrl add\n", __func__);
1774 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
1775 NULL, 1, ctl_len, rtd->dai_link->id,
1776 &app_type_info);
1777 if (ret < 0) {
1778 pr_err("%s: capture app type cntrl add failed: %d\n",
1779 __func__, ret);
1780 return ret;
1781 }
1782 kctl = app_type_info->kctl;
1783 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1784 capture_mixer_ctl_name, rtd->pcm->device, suffix);
1785 kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
1786 kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
1787 }
1788
1789 return 0;
1790}
1791
1792static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
1793{
1794 int ret = 0;
1795
1796 pr_debug("%s\n", __func__);
1797 ret = msm_pcm_add_chmap_controls(rtd);
1798 if (ret)
1799 pr_err("%s: pcm add controls failed:%d\n", __func__, ret);
1800 ret = msm_pcm_add_app_type_controls(rtd);
1801 if (ret)
1802 pr_err("%s: pcm add app type controls failed:%d\n",
1803 __func__, ret);
1804 return ret;
1805}
1806
1807static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
1808{
1809 struct snd_card *card = rtd->card->snd_card;
1810 int ret = 0;
1811
1812 if (!card->dev->coherent_dma_mask)
1813 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
1814
1815 ret = msm_pcm_add_controls(rtd);
1816 if (ret) {
1817 pr_err("%s, kctl add failed:%d\n", __func__, ret);
1818 return ret;
1819 }
1820
1821 ret = msm_pcm_add_volume_control(rtd);
1822 if (ret)
1823 pr_err("%s: Could not add pcm Volume Control %d\n",
1824 __func__, ret);
1825
1826 ret = msm_pcm_add_compress_control(rtd);
1827 if (ret)
1828 pr_err("%s: Could not add pcm Compress Control %d\n",
1829 __func__, ret);
1830
1831 ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
1832 if (ret)
1833 pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
1834 __func__);
1835
1836 ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
1837 if (ret)
1838 pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
1839 __func__);
1840
1841 return ret;
1842}
1843
1844static snd_pcm_sframes_t msm_pcm_delay_blk(struct snd_pcm_substream *substream,
1845 struct snd_soc_dai *dai)
1846{
1847 struct snd_pcm_runtime *runtime = substream->runtime;
1848 struct msm_audio *prtd = runtime->private_data;
1849 struct audio_client *ac = prtd->audio_client;
1850 snd_pcm_sframes_t frames;
1851 int ret;
1852
1853 ret = q6asm_get_path_delay(prtd->audio_client);
1854 if (ret) {
1855 pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
1856 return 0;
1857 }
1858
1859 /* convert microseconds to frames */
1860 frames = ac->path_delay / 1000 * runtime->rate / 1000;
1861
1862 /* also convert the remainder from the initial division */
1863 frames += ac->path_delay % 1000 * runtime->rate / 1000000;
1864
1865 /* overcompensate for the loss of precision (empirical) */
1866 frames += 2;
1867
1868 return frames;
1869}
1870
1871static struct snd_soc_platform_driver msm_soc_platform = {
1872 .ops = &msm_pcm_ops,
1873 .pcm_new = msm_asoc_pcm_new,
1874 .delay_blk = msm_pcm_delay_blk,
1875};
1876
1877static int msm_pcm_probe(struct platform_device *pdev)
1878{
1879 int rc;
1880 int id;
1881 struct msm_plat_data *pdata;
1882 const char *latency_level;
1883
1884 rc = of_property_read_u32(pdev->dev.of_node,
1885 "qcom,msm-pcm-dsp-id", &id);
1886 if (rc) {
1887 dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
1888 __func__);
1889 return rc;
1890 }
1891
1892 pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
1893 if (!pdata)
1894 return -ENOMEM;
1895
1896 if (of_property_read_bool(pdev->dev.of_node,
1897 "qcom,msm-pcm-low-latency")) {
1898
1899 pdata->perf_mode = LOW_LATENCY_PCM_MODE;
1900 rc = of_property_read_string(pdev->dev.of_node,
1901 "qcom,latency-level", &latency_level);
1902 if (!rc) {
1903 if (!strcmp(latency_level, "ultra"))
1904 pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
1905 else if (!strcmp(latency_level, "ull-pp"))
1906 pdata->perf_mode =
1907 ULL_POST_PROCESSING_PCM_MODE;
1908 }
1909 } else {
1910 pdata->perf_mode = LEGACY_PCM_MODE;
1911 }
1912
1913 dev_set_drvdata(&pdev->dev, pdata);
1914
1915
1916 dev_dbg(&pdev->dev, "%s: dev name %s\n",
1917 __func__, dev_name(&pdev->dev));
1918 return snd_soc_register_platform(&pdev->dev,
1919 &msm_soc_platform);
1920}
1921
1922static int msm_pcm_remove(struct platform_device *pdev)
1923{
1924 struct msm_plat_data *pdata;
1925
1926 pdata = dev_get_drvdata(&pdev->dev);
1927 kfree(pdata);
1928 snd_soc_unregister_platform(&pdev->dev);
1929 return 0;
1930}
1931static const struct of_device_id msm_pcm_dt_match[] = {
1932 {.compatible = "qcom,msm-pcm-dsp"},
1933 {}
1934};
1935MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
1936
1937static struct platform_driver msm_pcm_driver = {
1938 .driver = {
1939 .name = "msm-pcm-dsp",
1940 .owner = THIS_MODULE,
1941 .of_match_table = msm_pcm_dt_match,
1942 },
1943 .probe = msm_pcm_probe,
1944 .remove = msm_pcm_remove,
1945};
1946
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301947int __init msm_pcm_dsp_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301948{
1949 init_waitqueue_head(&the_locks.enable_wait);
1950 init_waitqueue_head(&the_locks.eos_wait);
1951 init_waitqueue_head(&the_locks.write_wait);
1952 init_waitqueue_head(&the_locks.read_wait);
1953
1954 return platform_driver_register(&msm_pcm_driver);
1955}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301956
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05301957void msm_pcm_dsp_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301958{
1959 platform_driver_unregister(&msm_pcm_driver);
1960}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301961
1962MODULE_DESCRIPTION("PCM module platform driver");
1963MODULE_LICENSE("GPL v2");