blob: 2fc5c84592634dc82b63e8d7716c7cd04c450760 [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Laxminath Kasamd08ab1f2020-01-30 19:07:58 +05302/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303 */
4
5
6#include <linux/init.h>
7#include <linux/err.h>
8#include <linux/module.h>
9#include <linux/moduleparam.h>
10#include <linux/time.h>
Ajit Pandeya557d962019-09-05 16:26:01 +053011#include <linux/mutex.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053012#include <linux/wait.h>
13#include <linux/platform_device.h>
14#include <linux/slab.h>
15#include <sound/core.h>
16#include <sound/soc.h>
17#include <sound/soc-dapm.h>
18#include <sound/pcm.h>
19#include <sound/initval.h>
20#include <sound/control.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053021#include <sound/timer.h>
22#include <asm/dma.h>
23#include <linux/dma-mapping.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053024#include <linux/msm_audio.h>
25
26#include <linux/of_device.h>
27#include <sound/tlv.h>
28#include <sound/pcm_params.h>
Surendar Karka38d66472019-03-29 18:08:07 +053029#include <sound/devdep_params.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053030#include <dsp/msm_audio_ion.h>
31#include <dsp/q6audio-v2.h>
Dieter Luecking70668fc2018-09-28 15:03:01 +020032#include <dsp/q6core.h>
33#include <dsp/q6asm-v2.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053034
35#include "msm-pcm-q6-v2.h"
36#include "msm-pcm-routing-v2.h"
37#include "msm-qti-pp-config.h"
38
Meng Wangee084a02018-09-04 16:11:58 +080039#define DRV_NAME "msm-pcm-q6-v2"
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -070040#define TIMEOUT_MS 1000
Meng Wangee084a02018-09-04 16:11:58 +080041
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053042enum stream_state {
43 IDLE = 0,
44 STOPPED,
45 RUNNING,
46};
47
48static struct audio_locks the_locks;
49
50#define PCM_MASTER_VOL_MAX_STEPS 0x2000
51static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
52 PCM_MASTER_VOL_MAX_STEPS);
53
54struct snd_msm {
55 struct snd_card *card;
56 struct snd_pcm *pcm;
57};
58
59#define CMD_EOS_MIN_TIMEOUT_LENGTH 50
60#define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50)
61#define MAX_PB_COPY_RETRIES 3
62
63static struct snd_pcm_hardware msm_pcm_hardware_capture = {
64 .info = (SNDRV_PCM_INFO_MMAP |
65 SNDRV_PCM_INFO_BLOCK_TRANSFER |
66 SNDRV_PCM_INFO_MMAP_VALID |
67 SNDRV_PCM_INFO_INTERLEAVED |
68 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
69 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
70 SNDRV_PCM_FMTBIT_S24_LE |
71 SNDRV_PCM_FMTBIT_S24_3LE |
72 SNDRV_PCM_FMTBIT_S32_LE),
73 .rates = SNDRV_PCM_RATE_8000_384000,
74 .rate_min = 8000,
75 .rate_max = 384000,
76 .channels_min = 1,
77 .channels_max = 4,
78 .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
79 CAPTURE_MAX_PERIOD_SIZE,
80 .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
81 .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
82 .periods_min = CAPTURE_MIN_NUM_PERIODS,
83 .periods_max = CAPTURE_MAX_NUM_PERIODS,
84 .fifo_size = 0,
85};
86
87static struct snd_pcm_hardware msm_pcm_hardware_playback = {
88 .info = (SNDRV_PCM_INFO_MMAP |
89 SNDRV_PCM_INFO_BLOCK_TRANSFER |
90 SNDRV_PCM_INFO_MMAP_VALID |
91 SNDRV_PCM_INFO_INTERLEAVED |
92 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
93 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
94 SNDRV_PCM_FMTBIT_S24_LE |
95 SNDRV_PCM_FMTBIT_S24_3LE |
96 SNDRV_PCM_FMTBIT_S32_LE),
97 .rates = SNDRV_PCM_RATE_8000_384000,
98 .rate_min = 8000,
99 .rate_max = 384000,
100 .channels_min = 1,
101 .channels_max = 8,
102 .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS *
103 PLAYBACK_MAX_PERIOD_SIZE,
104 .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
105 .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
106 .periods_min = PLAYBACK_MIN_NUM_PERIODS,
107 .periods_max = PLAYBACK_MAX_NUM_PERIODS,
108 .fifo_size = 0,
109};
110
111/* Conventional and unconventional sample rate supported */
112static unsigned int supported_sample_rates[] = {
113 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
114 88200, 96000, 176400, 192000, 352800, 384000
115};
116
117static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
118 .count = ARRAY_SIZE(supported_sample_rates),
119 .list = supported_sample_rates,
120 .mask = 0,
121};
122
123static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
124 void *priv_data)
125{
126 struct msm_audio *prtd = priv_data;
127
128 WARN_ON(!prtd);
129
130 pr_debug("%s: event %x\n", __func__, event);
131
132 switch (event) {
133 case MSM_PCM_RT_EVT_BUF_RECFG:
134 q6asm_cmd(prtd->audio_client, CMD_PAUSE);
135 q6asm_cmd(prtd->audio_client, CMD_FLUSH);
136 q6asm_run(prtd->audio_client, 0, 0, 0);
137 /* fallthrough */
138 default:
139 break;
140 }
141}
142
143static void event_handler(uint32_t opcode,
144 uint32_t token, uint32_t *payload, void *priv)
145{
146 struct msm_audio *prtd = priv;
147 struct snd_pcm_substream *substream = prtd->substream;
148 uint32_t *ptrmem = (uint32_t *)payload;
149 uint32_t idx = 0;
150 uint32_t size = 0;
151 uint8_t buf_index;
152 struct snd_soc_pcm_runtime *rtd;
153 int ret = 0;
154
155 switch (opcode) {
156 case ASM_DATA_EVENT_WRITE_DONE_V2: {
157 pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
158 pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
159 prtd->pcm_irq_pos += prtd->pcm_count;
160 if (atomic_read(&prtd->start))
161 snd_pcm_period_elapsed(substream);
162 atomic_inc(&prtd->out_count);
163 wake_up(&the_locks.write_wait);
164 if (!atomic_read(&prtd->start))
165 break;
166 if (!prtd->mmap_flag || prtd->reset_event)
167 break;
168 if (q6asm_is_cpu_buf_avail_nolock(IN,
169 prtd->audio_client,
170 &size, &idx)) {
171 pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
172 __func__, prtd->pcm_count);
173 q6asm_write_nolock(prtd->audio_client,
174 prtd->pcm_count, 0, 0, NO_TIMESTAMP);
175 }
176 break;
177 }
178 case ASM_DATA_EVENT_RENDERED_EOS:
179 pr_debug("ASM_DATA_EVENT_RENDERED_EOS\n");
180 clear_bit(CMD_EOS, &prtd->cmd_pending);
181 wake_up(&the_locks.eos_wait);
182 break;
183 case ASM_DATA_EVENT_READ_DONE_V2: {
184 pr_debug("ASM_DATA_EVENT_READ_DONE_V2\n");
185 buf_index = q6asm_get_buf_index_from_token(token);
Vignesh Kulothungan3817b182017-12-04 15:56:05 -0800186 if (buf_index >= CAPTURE_MAX_NUM_PERIODS) {
187 pr_err("%s: buffer index %u is out of range.\n",
188 __func__, buf_index);
189 return;
190 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530191 pr_debug("%s: token=0x%08x buf_index=0x%08x\n",
192 __func__, token, buf_index);
193 prtd->in_frame_info[buf_index].size = payload[4];
194 prtd->in_frame_info[buf_index].offset = payload[5];
195 /* assume data size = 0 during flushing */
196 if (prtd->in_frame_info[buf_index].size) {
197 prtd->pcm_irq_pos +=
198 prtd->in_frame_info[buf_index].size;
199 pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
200 if (atomic_read(&prtd->start))
201 snd_pcm_period_elapsed(substream);
202 if (atomic_read(&prtd->in_count) <= prtd->periods)
203 atomic_inc(&prtd->in_count);
204 wake_up(&the_locks.read_wait);
205 if (prtd->mmap_flag &&
206 q6asm_is_cpu_buf_avail_nolock(OUT,
207 prtd->audio_client,
208 &size, &idx) &&
209 (substream->runtime->status->state ==
210 SNDRV_PCM_STATE_RUNNING))
211 q6asm_read_nolock(prtd->audio_client);
212 } else {
213 pr_debug("%s: reclaim flushed buf in_count %x\n",
214 __func__, atomic_read(&prtd->in_count));
215 prtd->pcm_irq_pos += prtd->pcm_count;
216 if (prtd->mmap_flag) {
217 if (q6asm_is_cpu_buf_avail_nolock(OUT,
218 prtd->audio_client,
219 &size, &idx) &&
220 (substream->runtime->status->state ==
221 SNDRV_PCM_STATE_RUNNING))
222 q6asm_read_nolock(prtd->audio_client);
223 } else {
224 atomic_inc(&prtd->in_count);
225 }
226 if (atomic_read(&prtd->in_count) == prtd->periods) {
227 pr_info("%s: reclaimed all bufs\n", __func__);
228 if (atomic_read(&prtd->start))
229 snd_pcm_period_elapsed(substream);
230 wake_up(&the_locks.read_wait);
231 }
232 }
233 break;
234 }
235 case ASM_STREAM_PP_EVENT:
236 case ASM_STREAM_CMD_ENCDEC_EVENTS: {
237 pr_debug("%s: ASM_STREAM_EVENT (0x%x)\n", __func__, opcode);
238 if (!substream) {
239 pr_err("%s: substream is NULL.\n", __func__);
240 return;
241 }
242
243 rtd = substream->private_data;
244 if (!rtd) {
245 pr_err("%s: rtd is NULL\n", __func__);
246 return;
247 }
248
249 ret = msm_adsp_inform_mixer_ctl(rtd, payload);
250 if (ret) {
251 pr_err("%s: failed to inform mixer ctl. err = %d\n",
252 __func__, ret);
253 return;
254 }
255
256 break;
257 }
258 case APR_BASIC_RSP_RESULT: {
259 switch (payload[0]) {
260 case ASM_SESSION_CMD_RUN_V2:
261 if (substream->stream
262 != SNDRV_PCM_STREAM_PLAYBACK) {
263 atomic_set(&prtd->start, 1);
264 break;
265 }
266 if (prtd->mmap_flag) {
267 pr_debug("%s:writing %d bytes of buffer to dsp\n",
268 __func__,
269 prtd->pcm_count);
270 q6asm_write_nolock(prtd->audio_client,
271 prtd->pcm_count,
272 0, 0, NO_TIMESTAMP);
273 } else {
274 while (atomic_read(&prtd->out_needed)) {
275 pr_debug("%s:writing %d bytes of buffer to dsp\n",
276 __func__,
277 prtd->pcm_count);
278 q6asm_write_nolock(prtd->audio_client,
279 prtd->pcm_count,
280 0, 0, NO_TIMESTAMP);
281 atomic_dec(&prtd->out_needed);
282 wake_up(&the_locks.write_wait);
283 };
284 }
285 atomic_set(&prtd->start, 1);
286 break;
287 case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
288 pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
289 __func__);
290 break;
291 default:
292 pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
293 __func__, payload[0], payload[1]);
294 break;
295 }
296 }
297 break;
298 case RESET_EVENTS:
299 pr_debug("%s RESET_EVENTS\n", __func__);
300 prtd->pcm_irq_pos += prtd->pcm_count;
301 atomic_inc(&prtd->out_count);
302 atomic_inc(&prtd->in_count);
303 prtd->reset_event = true;
304 if (atomic_read(&prtd->start))
305 snd_pcm_period_elapsed(substream);
306 wake_up(&the_locks.eos_wait);
307 wake_up(&the_locks.write_wait);
308 wake_up(&the_locks.read_wait);
309 break;
310 default:
311 pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
312 break;
313 }
314}
315
316static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
317{
318 struct snd_pcm_runtime *runtime = substream->runtime;
319 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800320 struct snd_soc_component *component =
321 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530322 struct msm_audio *prtd = runtime->private_data;
323 struct msm_plat_data *pdata;
324 struct snd_pcm_hw_params *params;
325 int ret;
326 uint32_t fmt_type = FORMAT_LINEAR_PCM;
327 uint16_t bits_per_sample;
328 uint16_t sample_word_size;
329
Meng Wangee084a02018-09-04 16:11:58 +0800330 if (!component) {
331 pr_err("%s: component is NULL\n", __func__);
332 return -EINVAL;
333 }
334
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530335 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800336 dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530337 if (!pdata) {
338 pr_err("%s: platform data not populated\n", __func__);
339 return -EINVAL;
340 }
341 if (!prtd || !prtd->audio_client) {
342 pr_err("%s: private data null or audio client freed\n",
343 __func__);
344 return -EINVAL;
345 }
346 params = &soc_prtd->dpcm[substream->stream].hw_params;
347
348 pr_debug("%s\n", __func__);
349 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
350 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
351 prtd->pcm_irq_pos = 0;
352 /* rate and channels are sent to audio driver */
353 prtd->samp_rate = runtime->rate;
354 prtd->channel_mode = runtime->channels;
355 if (prtd->enabled)
356 return 0;
357
358 prtd->audio_client->perf_mode = pdata->perf_mode;
359 pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode);
360
361 switch (params_format(params)) {
362 case SNDRV_PCM_FORMAT_S32_LE:
363 bits_per_sample = 32;
364 sample_word_size = 32;
365 break;
366 case SNDRV_PCM_FORMAT_S24_LE:
367 bits_per_sample = 24;
368 sample_word_size = 32;
369 break;
370 case SNDRV_PCM_FORMAT_S24_3LE:
371 bits_per_sample = 24;
372 sample_word_size = 24;
373 break;
374 case SNDRV_PCM_FORMAT_S16_LE:
375 default:
376 bits_per_sample = 16;
377 sample_word_size = 16;
378 break;
379 }
380 if (prtd->compress_enable) {
381 fmt_type = FORMAT_GEN_COMPR;
382 pr_debug("%s: Compressed enabled!\n", __func__);
383 ret = q6asm_open_write_compressed(prtd->audio_client, fmt_type,
384 COMPRESSED_PASSTHROUGH_GEN);
385 if (ret < 0) {
386 pr_err("%s: q6asm_open_write_compressed failed (%d)\n",
387 __func__, ret);
388 q6asm_audio_client_free(prtd->audio_client);
389 prtd->audio_client = NULL;
390 return -ENOMEM;
391 }
392 } else {
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530393 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200394 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Dieter Luecking9fb7c8c2019-03-06 13:31:09 +0100395 ADSP_ASM_API_VERSION_V2))
Dieter Luecking70668fc2018-09-28 15:03:01 +0200396 ret = q6asm_open_write_v5(prtd->audio_client,
397 fmt_type, bits_per_sample);
398 else
399 ret = q6asm_open_write_v4(prtd->audio_client,
400 fmt_type, bits_per_sample);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530401
402 if (ret < 0) {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200403 pr_err("%s: q6asm_open_write failed (%d)\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530404 __func__, ret);
405 q6asm_audio_client_free(prtd->audio_client);
406 prtd->audio_client = NULL;
407 return -ENOMEM;
408 }
409
410 ret = q6asm_send_cal(prtd->audio_client);
411 if (ret < 0)
412 pr_debug("%s : Send cal failed : %d", __func__, ret);
413 }
414 pr_debug("%s: session ID %d\n", __func__,
415 prtd->audio_client->session);
416 prtd->session_id = prtd->audio_client->session;
417
418 if (prtd->compress_enable) {
419 ret = msm_pcm_routing_reg_phy_compr_stream(
420 soc_prtd->dai_link->id,
421 prtd->audio_client->perf_mode,
422 prtd->session_id,
423 SNDRV_PCM_STREAM_PLAYBACK,
424 COMPRESSED_PASSTHROUGH_GEN);
425 } else {
426 ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id,
427 prtd->audio_client->perf_mode,
428 prtd->session_id, substream->stream);
429 }
430 if (ret) {
431 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
432 return ret;
433 }
434 if (prtd->compress_enable) {
435 ret = q6asm_media_format_block_gen_compr(
436 prtd->audio_client, runtime->rate,
437 runtime->channels, !prtd->set_channel_map,
438 prtd->channel_map, bits_per_sample);
439 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200440
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530441 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200442 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Dieter Luecking9fb7c8c2019-03-06 13:31:09 +0100443 ADSP_ASM_API_VERSION_V2)) {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200444
445 ret = q6asm_media_format_block_multi_ch_pcm_v5(
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530446 prtd->audio_client, runtime->rate,
447 runtime->channels, !prtd->set_channel_map,
448 prtd->channel_map, bits_per_sample,
449 sample_word_size, ASM_LITTLE_ENDIAN,
450 DEFAULT_QF);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200451 } else {
452 ret = q6asm_media_format_block_multi_ch_pcm_v4(
453 prtd->audio_client, runtime->rate,
454 runtime->channels, !prtd->set_channel_map,
455 prtd->channel_map, bits_per_sample,
456 sample_word_size, ASM_LITTLE_ENDIAN,
457 DEFAULT_QF);
458 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530459 }
460 if (ret < 0)
461 pr_info("%s: CMD Format block failed\n", __func__);
462
463 atomic_set(&prtd->out_count, runtime->periods);
464
465 prtd->enabled = 1;
466 prtd->cmd_pending = 0;
467 prtd->cmd_interrupt = 0;
468
469 return 0;
470}
471
472static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
473{
474 struct snd_pcm_runtime *runtime = substream->runtime;
475 struct msm_audio *prtd = runtime->private_data;
476 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800477 struct snd_soc_component *component =
478 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530479 struct msm_plat_data *pdata;
480 struct snd_pcm_hw_params *params;
481 struct msm_pcm_routing_evt event;
482 int ret = 0;
483 int i = 0;
484 uint16_t bits_per_sample = 16;
485 uint16_t sample_word_size;
486
Meng Wangee084a02018-09-04 16:11:58 +0800487 if (!component) {
488 pr_err("%s: component is NULL\n", __func__);
489 return -EINVAL;
490 }
491
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530492 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800493 dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530494 if (!pdata) {
495 pr_err("%s: platform data not populated\n", __func__);
496 return -EINVAL;
497 }
498 if (!prtd || !prtd->audio_client) {
499 pr_err("%s: private data null or audio client freed\n",
500 __func__);
501 return -EINVAL;
502 }
503
504 if (prtd->enabled == IDLE) {
505 pr_debug("%s:perf_mode=%d periods=%d\n", __func__,
506 pdata->perf_mode, runtime->periods);
507 params = &soc_prtd->dpcm[substream->stream].hw_params;
508 if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) ||
509 (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE))
510 bits_per_sample = 24;
511 else if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
512 bits_per_sample = 32;
513
514 /* ULL mode is not supported in capture path */
515 if (pdata->perf_mode == LEGACY_PCM_MODE)
516 prtd->audio_client->perf_mode = LEGACY_PCM_MODE;
517 else
518 prtd->audio_client->perf_mode = LOW_LATENCY_PCM_MODE;
519
520 pr_debug("%s Opening %d-ch PCM read stream, perf_mode %d\n",
521 __func__, params_channels(params),
522 prtd->audio_client->perf_mode);
523
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530524 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200525 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Dieter Luecking9fb7c8c2019-03-06 13:31:09 +0100526 ADSP_ASM_API_VERSION_V2))
Dieter Luecking70668fc2018-09-28 15:03:01 +0200527 ret = q6asm_open_read_v5(prtd->audio_client,
528 FORMAT_LINEAR_PCM,
529 bits_per_sample, false, ENC_CFG_ID_NONE);
530 else
531 ret = q6asm_open_read_v4(prtd->audio_client,
532 FORMAT_LINEAR_PCM,
Vikram Pandurangac712c172017-11-17 17:36:49 -0800533 bits_per_sample, false, ENC_CFG_ID_NONE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530534 if (ret < 0) {
535 pr_err("%s: q6asm_open_read failed\n", __func__);
536 q6asm_audio_client_free(prtd->audio_client);
537 prtd->audio_client = NULL;
538 return -ENOMEM;
539 }
540
541 ret = q6asm_send_cal(prtd->audio_client);
542 if (ret < 0)
543 pr_debug("%s : Send cal failed : %d", __func__, ret);
544
545 pr_debug("%s: session ID %d\n",
546 __func__, prtd->audio_client->session);
547 prtd->session_id = prtd->audio_client->session;
548 event.event_func = msm_pcm_route_event_handler;
549 event.priv_data = (void *) prtd;
550 ret = msm_pcm_routing_reg_phy_stream_v2(
551 soc_prtd->dai_link->id,
552 prtd->audio_client->perf_mode,
553 prtd->session_id, substream->stream,
554 event);
555 if (ret) {
556 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
557 return ret;
558 }
559 }
560
561 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
562 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
563 prtd->pcm_irq_pos = 0;
564 /* rate and channels are sent to audio driver */
565 prtd->samp_rate = runtime->rate;
566 prtd->channel_mode = runtime->channels;
567
568 if (prtd->enabled == IDLE || prtd->enabled == STOPPED) {
569 for (i = 0; i < runtime->periods; i++)
570 q6asm_read(prtd->audio_client);
571 prtd->periods = runtime->periods;
572 }
573
574 if (prtd->enabled != IDLE)
575 return 0;
576
577 switch (runtime->format) {
578 case SNDRV_PCM_FORMAT_S32_LE:
579 bits_per_sample = 32;
580 sample_word_size = 32;
581 break;
582 case SNDRV_PCM_FORMAT_S24_LE:
583 bits_per_sample = 24;
584 sample_word_size = 32;
585 break;
586 case SNDRV_PCM_FORMAT_S24_3LE:
587 bits_per_sample = 24;
588 sample_word_size = 24;
589 break;
590 case SNDRV_PCM_FORMAT_S16_LE:
591 default:
592 bits_per_sample = 16;
593 sample_word_size = 16;
594 break;
595 }
596
597 pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n",
598 __func__, prtd->samp_rate, prtd->channel_mode,
599 bits_per_sample, sample_word_size);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200600
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530601 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200602 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Dieter Luecking9fb7c8c2019-03-06 13:31:09 +0100603 ADSP_ASM_API_VERSION_V2))
Dieter Luecking70668fc2018-09-28 15:03:01 +0200604 ret = q6asm_enc_cfg_blk_pcm_format_support_v5(
605 prtd->audio_client,
606 prtd->samp_rate,
607 prtd->channel_mode,
608 bits_per_sample,
609 sample_word_size,
610 ASM_LITTLE_ENDIAN,
611 DEFAULT_QF);
612 else
613 ret = q6asm_enc_cfg_blk_pcm_format_support_v4(
614 prtd->audio_client,
615 prtd->samp_rate,
616 prtd->channel_mode,
617 bits_per_sample,
618 sample_word_size,
619 ASM_LITTLE_ENDIAN,
620 DEFAULT_QF);
621
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530622 if (ret < 0)
623 pr_debug("%s: cmd cfg pcm was block failed", __func__);
624
625 prtd->enabled = RUNNING;
626
627 return ret;
628}
629
630static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
631{
632 int ret = 0;
633 struct snd_pcm_runtime *runtime = substream->runtime;
634 struct msm_audio *prtd = runtime->private_data;
635
636 switch (cmd) {
637 case SNDRV_PCM_TRIGGER_START:
638 case SNDRV_PCM_TRIGGER_RESUME:
639 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
640 pr_debug("%s: Trigger start\n", __func__);
641 ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
642 break;
643 case SNDRV_PCM_TRIGGER_STOP:
644 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
645 atomic_set(&prtd->start, 0);
646 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
647 prtd->enabled = STOPPED;
648 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
649 break;
650 }
651 /* pending CMD_EOS isn't expected */
652 WARN_ON_ONCE(test_bit(CMD_EOS, &prtd->cmd_pending));
653 set_bit(CMD_EOS, &prtd->cmd_pending);
654 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
655 if (ret)
656 clear_bit(CMD_EOS, &prtd->cmd_pending);
657 break;
658 case SNDRV_PCM_TRIGGER_SUSPEND:
659 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
660 pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
661 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
662 atomic_set(&prtd->start, 0);
663 break;
664 default:
665 ret = -EINVAL;
666 break;
667 }
668
669 return ret;
670}
671
672static int msm_pcm_open(struct snd_pcm_substream *substream)
673{
674 struct snd_pcm_runtime *runtime = substream->runtime;
675 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800676 struct snd_soc_component *component =
677 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530678 struct msm_audio *prtd;
Banajit Goswami616e68c2017-10-27 01:31:19 -0700679 struct msm_plat_data *pdata;
Ramprasad Katkam17f05162019-04-15 18:37:10 +0530680 enum apr_subsys_state subsys_state;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530681 int ret = 0;
682
Meng Wangee084a02018-09-04 16:11:58 +0800683 if (!component) {
684 pr_err("%s: component is NULL\n", __func__);
685 return -EINVAL;
686 }
687
Banajit Goswami616e68c2017-10-27 01:31:19 -0700688 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800689 dev_get_drvdata(component->dev);
Banajit Goswami616e68c2017-10-27 01:31:19 -0700690 if (!pdata) {
691 pr_err("%s: platform data not populated\n", __func__);
692 return -EINVAL;
693 }
Ramprasad Katkam17f05162019-04-15 18:37:10 +0530694
695 subsys_state = apr_get_subsys_state();
696 if (subsys_state == APR_SUBSYS_DOWN) {
697 pr_debug("%s: adsp is down\n", __func__);
698 return -ENETRESET;
699 }
700
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530701 prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
702 if (prtd == NULL)
703 return -ENOMEM;
704
705 prtd->substream = substream;
706 prtd->audio_client = q6asm_audio_client_alloc(
707 (app_cb)event_handler, prtd);
708 if (!prtd->audio_client) {
709 pr_info("%s: Could not allocate memory\n", __func__);
710 kfree(prtd);
Vatsal Bucha2eb2e612018-06-01 12:05:25 +0530711 prtd = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530712 return -ENOMEM;
713 }
714
Meng Wangee084a02018-09-04 16:11:58 +0800715 prtd->audio_client->dev = component->dev;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530716
717 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
718 runtime->hw = msm_pcm_hardware_playback;
719
720 /* Capture path */
721 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
722 runtime->hw = msm_pcm_hardware_capture;
723 else {
724 pr_err("Invalid Stream type %d\n", substream->stream);
725 return -EINVAL;
726 }
727
728 ret = snd_pcm_hw_constraint_list(runtime, 0,
729 SNDRV_PCM_HW_PARAM_RATE,
730 &constraints_sample_rates);
731 if (ret < 0)
732 pr_info("snd_pcm_hw_constraint_list failed\n");
733 /* Ensure that buffer size is a multiple of period size */
734 ret = snd_pcm_hw_constraint_integer(runtime,
735 SNDRV_PCM_HW_PARAM_PERIODS);
736 if (ret < 0)
737 pr_info("snd_pcm_hw_constraint_integer failed\n");
738
739 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
740 ret = snd_pcm_hw_constraint_minmax(runtime,
741 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
742 PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
743 PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
744 if (ret < 0) {
745 pr_err("constraint for buffer bytes min max ret = %d\n",
746 ret);
747 }
748 }
749
750 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
751 ret = snd_pcm_hw_constraint_minmax(runtime,
752 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
753 CAPTURE_MIN_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
754 CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
755 if (ret < 0) {
756 pr_err("constraint for buffer bytes min max ret = %d\n",
757 ret);
758 }
759 }
760 ret = snd_pcm_hw_constraint_step(runtime, 0,
761 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
762 if (ret < 0) {
763 pr_err("constraint for period bytes step ret = %d\n",
764 ret);
765 }
766 ret = snd_pcm_hw_constraint_step(runtime, 0,
767 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
768 if (ret < 0) {
769 pr_err("constraint for buffer bytes step ret = %d\n",
770 ret);
771 }
772
773 prtd->enabled = IDLE;
774 prtd->dsp_cnt = 0;
775 prtd->set_channel_map = false;
776 prtd->reset_event = false;
777 runtime->private_data = prtd;
Xiaojun Sangf27e3512018-05-23 17:14:31 +0800778
779 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
780 msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
781
Banajit Goswami616e68c2017-10-27 01:31:19 -0700782 /* Vote to update the Rx thread priority to RT Thread for playback */
783 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
784 (pdata->perf_mode == LOW_LATENCY_PCM_MODE))
785 apr_start_rx_rt(prtd->audio_client->apr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530786
787 return 0;
788}
789
790static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +0800791 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530792{
793 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530794 int xfer = 0;
795 char *bufptr = NULL;
796 void *data = NULL;
797 uint32_t idx = 0;
798 uint32_t size = 0;
799 uint32_t retries = 0;
800
801 struct snd_pcm_runtime *runtime = substream->runtime;
802 struct msm_audio *prtd = runtime->private_data;
803
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530804 pr_debug("%s: prtd->out_count = %d\n",
805 __func__, atomic_read(&prtd->out_count));
806
807 while ((fbytes > 0) && (retries < MAX_PB_COPY_RETRIES)) {
808 if (prtd->reset_event) {
809 pr_err("%s: In SSR return ENETRESET before wait\n",
810 __func__);
811 return -ENETRESET;
812 }
813
814 ret = wait_event_timeout(the_locks.write_wait,
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -0700815 (atomic_read(&prtd->out_count)),
816 msecs_to_jiffies(TIMEOUT_MS));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530817 if (!ret) {
818 pr_err("%s: wait_event_timeout failed\n", __func__);
819 ret = -ETIMEDOUT;
820 goto fail;
821 }
822 ret = 0;
823
824 if (prtd->reset_event) {
825 pr_err("%s: In SSR return ENETRESET after wait\n",
826 __func__);
827 return -ENETRESET;
828 }
829
830 if (!atomic_read(&prtd->out_count)) {
831 pr_err("%s: pcm stopped out_count 0\n", __func__);
832 return 0;
833 }
834
835 data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size,
836 &idx);
837 if (data == NULL) {
838 retries++;
839 continue;
840 } else {
841 retries = 0;
842 }
843
844 if (fbytes > size)
845 xfer = size;
846 else
847 xfer = fbytes;
848
849 bufptr = data;
850 if (bufptr) {
Meng Wangac147b72017-10-30 16:46:16 +0800851 pr_debug("%s:fbytes =%lu: xfer=%d size=%d\n",
852 __func__, fbytes, xfer, size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530853 if (copy_from_user(bufptr, buf, xfer)) {
854 ret = -EFAULT;
855 pr_err("%s: copy_from_user failed\n",
856 __func__);
857 q6asm_cpu_buf_release(IN, prtd->audio_client);
858 goto fail;
859 }
860 buf += xfer;
861 fbytes -= xfer;
Meng Wangac147b72017-10-30 16:46:16 +0800862 pr_debug("%s:fbytes = %lu: xfer=%d\n", __func__,
863 fbytes, xfer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530864 if (atomic_read(&prtd->start)) {
865 pr_debug("%s:writing %d bytes of buffer to dsp\n",
866 __func__, xfer);
867 ret = q6asm_write(prtd->audio_client, xfer,
868 0, 0, NO_TIMESTAMP);
869 if (ret < 0) {
870 ret = -EFAULT;
871 q6asm_cpu_buf_release(IN,
872 prtd->audio_client);
873 goto fail;
874 }
875 } else
876 atomic_inc(&prtd->out_needed);
877 atomic_dec(&prtd->out_count);
878 }
879 }
880fail:
881 if (retries >= MAX_PB_COPY_RETRIES)
882 ret = -ENOMEM;
883
884 return ret;
885}
886
887static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
888{
889 struct snd_pcm_runtime *runtime = substream->runtime;
890 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
891 struct msm_audio *prtd = runtime->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800892 struct snd_soc_component *component =
893 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Banajit Goswami616e68c2017-10-27 01:31:19 -0700894 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530895 uint32_t timeout;
896 int dir = 0;
897 int ret = 0;
898
899 pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
900
Ajit Pandeya557d962019-09-05 16:26:01 +0530901 if (!component) {
902 pr_err("%s: component is NULL\n", __func__);
903 return -EINVAL;
904 }
905
906 pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
907 if (!pdata) {
908 pr_err("%s: platform data is NULL\n", __func__);
909 return -EINVAL;
910 }
911
912 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530913 if (prtd->audio_client) {
914 dir = IN;
915
Banajit Goswami616e68c2017-10-27 01:31:19 -0700916 /*
917 * Unvote to downgrade the Rx thread priority from
918 * RT Thread for Low-Latency use case.
919 */
Banajit Goswami616e68c2017-10-27 01:31:19 -0700920 if (pdata) {
921 if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
922 apr_end_rx_rt(prtd->audio_client->apr);
923 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530924 /* determine timeout length */
925 if (runtime->frame_bits == 0 || runtime->rate == 0) {
926 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
927 } else {
928 timeout = (runtime->period_size *
929 CMD_EOS_TIMEOUT_MULTIPLIER) /
930 ((runtime->frame_bits / 8) *
931 runtime->rate);
932 if (timeout < CMD_EOS_MIN_TIMEOUT_LENGTH)
933 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
934 }
935 pr_debug("%s: CMD_EOS timeout is %d\n", __func__, timeout);
936
937 ret = wait_event_timeout(the_locks.eos_wait,
938 !test_bit(CMD_EOS, &prtd->cmd_pending),
939 timeout);
940 if (!ret)
941 pr_err("%s: CMD_EOS failed, cmd_pending 0x%lx\n",
942 __func__, prtd->cmd_pending);
943 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
944 q6asm_audio_client_buf_free_contiguous(dir,
945 prtd->audio_client);
946 q6asm_audio_client_free(prtd->audio_client);
947 }
948 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
949 SNDRV_PCM_STREAM_PLAYBACK);
950 msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
951 kfree(prtd);
952 runtime->private_data = NULL;
Ajit Pandeya557d962019-09-05 16:26:01 +0530953 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530954 return 0;
955}
956
957static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
Meng Wangac147b72017-10-30 16:46:16 +0800958 int channel, unsigned long hwoff, void __user *buf,
959 unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530960{
961 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530962 int xfer;
963 char *bufptr;
964 void *data = NULL;
Vignesh Kulothungan0c5f3462019-05-22 11:53:08 -0700965 uint32_t idx = 0;
966 uint32_t size = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530967 uint32_t offset = 0;
968 struct snd_pcm_runtime *runtime = substream->runtime;
969 struct msm_audio *prtd = substream->runtime->private_data;
970
971
972 pr_debug("%s\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530973
974 pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
975 pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
976 pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
977
978 if (prtd->reset_event) {
979 pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
980 return -ENETRESET;
981 }
982 ret = wait_event_timeout(the_locks.read_wait,
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -0700983 (atomic_read(&prtd->in_count)),
984 msecs_to_jiffies(TIMEOUT_MS));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530985 if (!ret) {
986 pr_debug("%s: wait_event_timeout failed\n", __func__);
987 goto fail;
988 }
989 if (prtd->reset_event) {
990 pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
991 return -ENETRESET;
992 }
993 if (!atomic_read(&prtd->in_count)) {
994 pr_debug("%s: pcm stopped in_count 0\n", __func__);
995 return 0;
996 }
997 pr_debug("Checking if valid buffer is available...%pK\n",
998 data);
999 data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
1000 bufptr = data;
1001 pr_debug("Size = %d\n", size);
Meng Wangac147b72017-10-30 16:46:16 +08001002 pr_debug("fbytes = %lu\n", fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301003 pr_debug("idx = %d\n", idx);
1004 if (bufptr) {
1005 xfer = fbytes;
1006 if (xfer > size)
1007 xfer = size;
1008 offset = prtd->in_frame_info[idx].offset;
1009 pr_debug("Offset value = %d\n", offset);
1010 if (copy_to_user(buf, bufptr+offset, xfer)) {
1011 pr_err("Failed to copy buf to user\n");
1012 ret = -EFAULT;
1013 q6asm_cpu_buf_release(OUT, prtd->audio_client);
1014 goto fail;
1015 }
1016 fbytes -= xfer;
1017 size -= xfer;
1018 prtd->in_frame_info[idx].offset += xfer;
Meng Wangac147b72017-10-30 16:46:16 +08001019 pr_debug("%s:fbytes = %lu: size=%d: xfer=%d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301020 __func__, fbytes, size, xfer);
1021 pr_debug(" Sending next buffer to dsp\n");
1022 memset(&prtd->in_frame_info[idx], 0,
1023 sizeof(struct msm_audio_in_frame_info));
1024 atomic_dec(&prtd->in_count);
1025 ret = q6asm_read(prtd->audio_client);
1026 if (ret < 0) {
1027 pr_err("q6asm read failed\n");
1028 ret = -EFAULT;
1029 q6asm_cpu_buf_release(OUT, prtd->audio_client);
1030 goto fail;
1031 }
1032 } else
1033 pr_err("No valid buffer\n");
1034
1035 pr_debug("Returning from capture_copy... %d\n", ret);
1036fail:
1037 return ret;
1038}
1039
1040static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
1041{
1042 struct snd_pcm_runtime *runtime = substream->runtime;
1043 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
1044 struct msm_audio *prtd = runtime->private_data;
Ajit Pandeya557d962019-09-05 16:26:01 +05301045 struct snd_soc_component *component =
1046 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
1047 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301048 int dir = OUT;
1049
1050 pr_debug("%s\n", __func__);
Ajit Pandeya557d962019-09-05 16:26:01 +05301051
1052 if (!component) {
1053 pr_err("%s: component is NULL\n", __func__);
1054 return -EINVAL;
1055 }
1056
1057 pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
1058 if (!pdata) {
1059 pr_err("%s: platform data is NULL\n", __func__);
1060 return -EINVAL;
1061 }
1062
1063 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301064 if (prtd->audio_client) {
1065 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
1066 q6asm_audio_client_buf_free_contiguous(dir,
1067 prtd->audio_client);
1068 q6asm_audio_client_free(prtd->audio_client);
1069 }
1070
1071 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
1072 SNDRV_PCM_STREAM_CAPTURE);
1073 kfree(prtd);
1074 runtime->private_data = NULL;
Ajit Pandeya557d962019-09-05 16:26:01 +05301075 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301076 return 0;
1077}
1078
1079static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +08001080 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301081{
1082 int ret = 0;
1083
1084 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Meng Wangac147b72017-10-30 16:46:16 +08001085 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301086 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
Meng Wangac147b72017-10-30 16:46:16 +08001087 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301088 return ret;
1089}
1090
1091static int msm_pcm_close(struct snd_pcm_substream *substream)
1092{
1093 int ret = 0;
1094
1095 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1096 ret = msm_pcm_playback_close(substream);
1097 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1098 ret = msm_pcm_capture_close(substream);
1099 return ret;
1100}
1101
1102static int msm_pcm_prepare(struct snd_pcm_substream *substream)
1103{
1104 int ret = 0;
1105
1106 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1107 ret = msm_pcm_playback_prepare(substream);
1108 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1109 ret = msm_pcm_capture_prepare(substream);
1110 return ret;
1111}
1112
1113static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
1114{
1115
1116 struct snd_pcm_runtime *runtime = substream->runtime;
1117 struct msm_audio *prtd = runtime->private_data;
1118
1119 if (prtd->pcm_irq_pos >= prtd->pcm_size)
1120 prtd->pcm_irq_pos = 0;
1121
1122 pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
1123 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
1124}
1125
1126static int msm_pcm_mmap(struct snd_pcm_substream *substream,
1127 struct vm_area_struct *vma)
1128{
1129 struct snd_pcm_runtime *runtime = substream->runtime;
1130 struct msm_audio *prtd = runtime->private_data;
1131 struct audio_client *ac = prtd->audio_client;
1132 struct audio_port_data *apd = ac->port;
1133 struct audio_buffer *ab;
1134 int dir = -1;
1135
1136 prtd->mmap_flag = 1;
1137
1138 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1139 dir = IN;
1140 else
1141 dir = OUT;
1142 ab = &(apd[dir].buf[0]);
1143
1144 return msm_audio_ion_mmap(ab, vma);
1145}
1146
1147static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
1148 struct snd_pcm_hw_params *params)
1149{
1150 struct snd_pcm_runtime *runtime = substream->runtime;
1151 struct msm_audio *prtd = runtime->private_data;
1152 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
1153 struct audio_buffer *buf;
1154 int dir, ret;
1155
1156 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1157 dir = IN;
1158 else
1159 dir = OUT;
1160 ret = q6asm_audio_client_buf_alloc_contiguous(dir,
1161 prtd->audio_client,
1162 (params_buffer_bytes(params) / params_periods(params)),
1163 params_periods(params));
1164 if (ret < 0) {
1165 pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
1166 ret);
1167 return -ENOMEM;
1168 }
1169 buf = prtd->audio_client->port[dir].buf;
1170 if (buf == NULL || buf[0].data == NULL)
1171 return -ENOMEM;
1172
1173 pr_debug("%s:buf = %pK\n", __func__, buf);
1174 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
1175 dma_buf->dev.dev = substream->pcm->card->dev;
1176 dma_buf->private_data = NULL;
1177 dma_buf->area = buf[0].data;
1178 dma_buf->addr = buf[0].phys;
1179 dma_buf->bytes = params_buffer_bytes(params);
1180 if (!dma_buf->area)
1181 return -ENOMEM;
1182
1183 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
1184 return 0;
1185}
1186
Surendar Karka38d66472019-03-29 18:08:07 +05301187static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
1188 unsigned int cmd, void __user *arg)
1189{
1190 struct msm_audio *prtd = NULL;
1191 struct snd_soc_pcm_runtime *rtd = NULL;
1192 uint64_t ses_time = 0, abs_time = 0;
1193 int64_t av_offset = 0;
1194 int32_t clock_id = -EINVAL;
1195 int rc = 0;
1196 struct snd_pcm_prsnt_position userarg;
1197
1198 if (!substream || !substream->private_data) {
1199 pr_err("%s: Invalid %s\n", __func__,
1200 (!substream) ? "substream" : "private_data");
1201 return -EINVAL;
1202 }
1203
1204 if (!substream->runtime) {
1205 pr_err("%s substream runtime not found\n", __func__);
1206 return -EINVAL;
1207 }
1208
1209 prtd = substream->runtime->private_data;
1210 if (!prtd) {
1211 pr_err("%s prtd is null.\n", __func__);
1212 return -EINVAL;
1213 }
1214
1215 rtd = substream->private_data;
1216
1217 switch (cmd) {
1218 case SNDRV_PCM_IOCTL_DSP_POSITION:
1219 dev_dbg(rtd->dev, "%s: SNDRV_PCM_DSP_POSITION", __func__);
1220 if (!arg) {
1221 dev_err(rtd->dev, "%s: Invalid params DSP_POSITION\n",
1222 __func__);
1223 rc = -EINVAL;
1224 goto done;
1225 }
1226 memset(&userarg, 0, sizeof(userarg));
1227 if (copy_from_user(&userarg, arg, sizeof(userarg))) {
1228 dev_err(rtd->dev, "%s: err copyuser DSP_POSITION\n",
1229 __func__);
1230 rc = -EFAULT;
1231 goto done;
1232 }
1233 clock_id = userarg.clock_id;
1234 rc = q6asm_get_session_time_v2(prtd->audio_client, &ses_time,
1235 &abs_time);
1236 if (rc) {
1237 pr_err("%s: q6asm_get_session_time_v2 failed, rc=%d\n",
1238 __func__, rc);
1239 goto done;
1240 }
1241 userarg.frames = div64_u64((ses_time * prtd->samp_rate),
1242 1000000);
1243
1244 rc = avcs_core_query_timer_offset(&av_offset, clock_id);
1245 if (rc) {
1246 pr_err("%s: avcs offset query failed, rc=%d\n",
1247 __func__, rc);
1248 goto done;
1249 }
1250
1251 userarg.timestamp = abs_time + av_offset;
1252 if (copy_to_user(arg, &userarg, sizeof(userarg))) {
1253 dev_err(rtd->dev, "%s: err copy to user DSP_POSITION\n",
1254 __func__);
1255 rc = -EFAULT;
1256 goto done;
1257 }
1258 pr_debug("%s, vals f %lld, t %lld, avoff %lld, abst %lld, sess_time %llu sr %d\n",
1259 __func__, userarg.frames, userarg.timestamp,
1260 av_offset, abs_time, ses_time, prtd->samp_rate);
1261 break;
1262 default:
1263 rc = snd_pcm_lib_ioctl(substream, cmd, arg);
1264 break;
1265 }
1266done:
1267 return rc;
1268}
1269
1270#ifdef CONFIG_COMPAT
1271static int msm_pcm_compat_ioctl(struct snd_pcm_substream *substream,
1272 unsigned int cmd, void __user *arg)
1273{
1274 return msm_pcm_ioctl(substream, cmd, arg);
1275}
1276#else
1277#define msm_pcm_compat_ioctl NULL
1278#endif
1279
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301280static const struct snd_pcm_ops msm_pcm_ops = {
1281 .open = msm_pcm_open,
Meng Wangac147b72017-10-30 16:46:16 +08001282 .copy_user = msm_pcm_copy,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301283 .hw_params = msm_pcm_hw_params,
1284 .close = msm_pcm_close,
Surendar Karka38d66472019-03-29 18:08:07 +05301285 .ioctl = msm_pcm_ioctl,
1286 .compat_ioctl = msm_pcm_compat_ioctl,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301287 .prepare = msm_pcm_prepare,
1288 .trigger = msm_pcm_trigger,
1289 .pointer = msm_pcm_pointer,
1290 .mmap = msm_pcm_mmap,
1291};
1292
1293static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
1294 struct snd_ctl_elem_value *ucontrol)
1295{
Meng Wangee084a02018-09-04 16:11:58 +08001296 struct snd_soc_component *component =
1297 snd_soc_kcontrol_component(kcontrol);
1298 struct msm_plat_data *pdata = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301299 struct snd_pcm_substream *substream;
1300 struct msm_audio *prtd;
1301 int ret = 0;
1302 struct msm_adsp_event_data *event_data = NULL;
1303
Meng Wangee084a02018-09-04 16:11:58 +08001304 if (!component) {
1305 pr_err("%s: component is NULL\n", __func__);
1306 return -EINVAL;
1307 }
1308
1309 pdata = dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301310 if (!pdata) {
1311 pr_err("%s pdata is NULL\n", __func__);
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301312 return -ENODEV;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301313 }
1314
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301315 mutex_lock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301316 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1317 if (!substream) {
1318 pr_err("%s substream not found\n", __func__);
1319 ret = -EINVAL;
1320 goto done;
1321 }
1322
1323 if (!substream->runtime) {
1324 pr_err("%s substream runtime not found\n", __func__);
1325 ret = -EINVAL;
1326 goto done;
1327 }
Prasad Kumpatlad4e34682020-06-25 19:38:34 +05301328 if (substream->ref_count <= 0) {
1329 pr_err_ratelimited("%s substream ref_count:%d invalid\n",
1330 __func__, substream->ref_count);
1331 ret = -EINVAL;
1332 goto done;
1333 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301334 prtd = substream->runtime->private_data;
Vatsal Bucha2eb2e612018-06-01 12:05:25 +05301335 if (prtd == NULL) {
1336 pr_err("%s prtd is null.\n", __func__);
1337 ret = -EINVAL;
1338 goto done;
1339 }
1340
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301341 if (prtd->audio_client == NULL) {
1342 pr_err("%s prtd is null.\n", __func__);
1343 ret = -EINVAL;
1344 goto done;
1345 }
1346
1347 event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
1348 if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
1349 (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
1350 pr_err("%s: invalid event_type=%d",
1351 __func__, event_data->event_type);
1352 ret = -EINVAL;
1353 goto done;
1354 }
1355
Xiaojun Sang75642c32018-03-23 08:57:33 +08001356 if (event_data->payload_len > sizeof(ucontrol->value.bytes.data)
1357 - sizeof(struct msm_adsp_event_data)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301358 pr_err("%s param length=%d exceeds limit",
1359 __func__, event_data->payload_len);
1360 ret = -EINVAL;
1361 goto done;
1362 }
1363
1364 ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
1365 if (ret < 0)
1366 pr_err("%s: failed to send stream event cmd, err = %d\n",
1367 __func__, ret);
1368done:
Ajit Pandeya557d962019-09-05 16:26:01 +05301369 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301370 return ret;
1371}
1372
1373static int msm_pcm_add_audio_adsp_stream_cmd_control(
1374 struct snd_soc_pcm_runtime *rtd)
1375{
Meng Wangee084a02018-09-04 16:11:58 +08001376 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301377 const char *mixer_ctl_name = DSP_STREAM_CMD;
1378 const char *deviceNo = "NN";
1379 char *mixer_str = NULL;
1380 int ctl_len = 0, ret = 0;
1381 struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
1382 {
1383 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1384 .name = "?",
1385 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1386 .info = msm_adsp_stream_cmd_info,
1387 .put = msm_pcm_adsp_stream_cmd_put,
1388 .private_value = 0,
1389 }
1390 };
1391
1392 if (!rtd) {
1393 pr_err("%s rtd is NULL\n", __func__);
1394 ret = -EINVAL;
1395 goto done;
1396 }
1397
Meng Wangee084a02018-09-04 16:11:58 +08001398 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1399 if (!component) {
1400 pr_err("%s: component is NULL\n", __func__);
1401 return -EINVAL;
1402 }
1403
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301404 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1405 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1406 if (!mixer_str) {
1407 ret = -ENOMEM;
1408 goto done;
1409 }
1410
1411 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1412 fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
1413 fe_audio_adsp_stream_cmd_config_control[0].private_value =
1414 rtd->dai_link->id;
1415 pr_debug("Registering new mixer ctl %s\n", mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001416 ret = snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301417 fe_audio_adsp_stream_cmd_config_control,
1418 ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
1419 if (ret < 0)
1420 pr_err("%s: failed add ctl %s. err = %d\n",
1421 __func__, mixer_str, ret);
1422
1423 kfree(mixer_str);
1424done:
1425 return ret;
1426}
1427
1428static int msm_pcm_add_audio_adsp_stream_callback_control(
1429 struct snd_soc_pcm_runtime *rtd)
1430{
Meng Wangee084a02018-09-04 16:11:58 +08001431 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301432 const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
1433 const char *deviceNo = "NN";
1434 char *mixer_str = NULL;
1435 int ctl_len = 0, ret = 0;
1436 struct snd_kcontrol *kctl;
1437
1438 struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
1439 {
1440 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1441 .name = "?",
1442 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1443 .info = msm_adsp_stream_callback_info,
1444 .get = msm_adsp_stream_callback_get,
1445 .private_value = 0,
1446 }
1447 };
1448
1449 if (!rtd) {
1450 pr_err("%s NULL rtd\n", __func__);
1451 ret = -EINVAL;
1452 goto done;
1453 }
1454
Meng Wangee084a02018-09-04 16:11:58 +08001455 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1456 if (!component) {
1457 pr_err("%s: component is NULL\n", __func__);
1458 return -EINVAL;
1459 }
1460
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301461 pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
1462 __func__, rtd->dai_link->name, rtd->dai_link->id,
1463 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
1464 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1465 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1466 if (!mixer_str) {
1467 ret = -ENOMEM;
1468 goto done;
1469 }
1470
1471 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1472 fe_audio_adsp_callback_config_control[0].name = mixer_str;
1473 fe_audio_adsp_callback_config_control[0].private_value =
1474 rtd->dai_link->id;
1475 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001476 ret = snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301477 fe_audio_adsp_callback_config_control,
1478 ARRAY_SIZE(fe_audio_adsp_callback_config_control));
1479 if (ret < 0) {
1480 pr_err("%s: failed to add ctl %s. err = %d\n",
1481 __func__, mixer_str, ret);
1482 ret = -EINVAL;
1483 goto free_mixer_str;
1484 }
1485
1486 kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
1487 if (!kctl) {
1488 pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
1489 ret = -EINVAL;
1490 goto free_mixer_str;
1491 }
1492
1493 kctl->private_data = NULL;
1494
1495free_mixer_str:
1496 kfree(mixer_str);
1497done:
1498 return ret;
1499}
1500
1501static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
1502{
1503 int rc = 0;
1504
1505 if (prtd && prtd->audio_client) {
1506 pr_debug("%s: channels %d volume 0x%x\n", __func__,
1507 prtd->channel_mode, volume);
1508 rc = q6asm_set_volume(prtd->audio_client, volume);
1509 if (rc < 0) {
1510 pr_err("%s: Send Volume command failed rc=%d\n",
1511 __func__, rc);
1512 }
1513 }
1514 return rc;
1515}
1516
1517static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
1518 struct snd_ctl_elem_value *ucontrol)
1519{
1520 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301521 struct msm_plat_data *pdata = NULL;
Laxminath Kasamd08ab1f2020-01-30 19:07:58 +05301522 struct snd_pcm_substream *substream = NULL;
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301523 struct snd_soc_pcm_runtime *soc_prtd = NULL;
1524 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301525 struct msm_audio *prtd;
1526
1527 pr_debug("%s\n", __func__);
Laxminath Kasamd08ab1f2020-01-30 19:07:58 +05301528 if (!vol) {
1529 pr_err("%s: vol is NULL\n", __func__);
1530 return -ENODEV;
1531 }
1532 substream = vol->pcm->streams[vol->stream].substream;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301533 if (!substream) {
1534 pr_err("%s substream not found\n", __func__);
1535 return -ENODEV;
1536 }
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301537 soc_prtd = substream->private_data;
1538 if (!substream->runtime || !soc_prtd) {
1539 pr_debug("%s substream runtime or private_data not found\n",
1540 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301541 return 0;
1542 }
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301543
1544 component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
1545 if (!component) {
1546 pr_err("%s: component is NULL\n", __func__);
1547 return -EINVAL;
1548 }
1549
1550 pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
1551 if (!pdata) {
1552 pr_err("%s: pdata not found\n", __func__);
1553 return -ENODEV;
1554 }
1555
1556 mutex_lock(&pdata->lock);
Prasad Kumpatlad4e34682020-06-25 19:38:34 +05301557 if (substream->ref_count > 0) {
1558 prtd = substream->runtime->private_data;
1559 if (prtd)
1560 ucontrol->value.integer.value[0] = prtd->volume;
1561 }
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301562 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301563 return 0;
1564}
1565
1566static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
1567 struct snd_ctl_elem_value *ucontrol)
1568{
1569 int rc = 0;
1570 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
Ajit Pandeya557d962019-09-05 16:26:01 +05301571 struct msm_plat_data *pdata = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301572 struct snd_pcm_substream *substream =
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001573 vol->pcm->streams[vol->stream].substream;
Ajit Pandeya557d962019-09-05 16:26:01 +05301574 struct snd_soc_pcm_runtime *soc_prtd = NULL;
1575 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301576 struct msm_audio *prtd;
1577 int volume = ucontrol->value.integer.value[0];
1578
1579 pr_debug("%s: volume : 0x%x\n", __func__, volume);
1580 if (!substream) {
Ajit Pandeya557d962019-09-05 16:26:01 +05301581 pr_err("%s: substream not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301582 return -ENODEV;
1583 }
Ajit Pandeya557d962019-09-05 16:26:01 +05301584
1585 soc_prtd = substream->private_data;
1586 if (!substream->runtime || !soc_prtd) {
1587 pr_err("%s: substream runtime or private_data not found\n",
1588 __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301589 return 0;
1590 }
Ajit Pandeya557d962019-09-05 16:26:01 +05301591
1592 component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
1593 if (!component) {
1594 pr_err("%s: component is NULL\n", __func__);
1595 return -EINVAL;
1596 }
1597
1598 pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
1599 if (!pdata) {
1600 pr_err("%s: pdata not found\n", __func__);
1601 return -ENODEV;
1602 }
1603
1604 mutex_lock(&pdata->lock);
Prasad Kumpatlad4e34682020-06-25 19:38:34 +05301605 if (substream->ref_count > 0) {
1606 prtd = substream->runtime->private_data;
1607 if (prtd) {
1608 rc = msm_pcm_set_volume(prtd, volume);
1609 prtd->volume = volume;
1610 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301611 }
Ajit Pandeya557d962019-09-05 16:26:01 +05301612 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301613 return rc;
1614}
1615
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001616static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd,
1617 int stream)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301618{
1619 int ret = 0;
1620 struct snd_pcm *pcm = rtd->pcm;
1621 struct snd_pcm_volume *volume_info;
1622 struct snd_kcontrol *kctl;
1623
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001624 dev_dbg(rtd->dev, "%s, volume control add\n", __func__);
1625 ret = snd_pcm_add_volume_ctls(pcm, stream,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301626 NULL, 1, rtd->dai_link->id,
1627 &volume_info);
1628 if (ret < 0) {
1629 pr_err("%s volume control failed ret %d\n", __func__, ret);
1630 return ret;
1631 }
1632 kctl = volume_info->kctl;
1633 kctl->put = msm_pcm_volume_ctl_put;
1634 kctl->get = msm_pcm_volume_ctl_get;
1635 kctl->tlv.p = msm_pcm_vol_gain;
1636 return 0;
1637}
1638
1639static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
1640 struct snd_ctl_elem_info *uinfo)
1641{
1642 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1643 uinfo->count = 1;
1644 uinfo->value.integer.min = 0;
1645 uinfo->value.integer.max = 0x2000;
1646 return 0;
1647}
1648
1649static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
1650 struct snd_ctl_elem_value *ucontrol)
1651{
Meng Wangee084a02018-09-04 16:11:58 +08001652 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
1653 struct msm_plat_data *pdata = dev_get_drvdata(comp->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301654 struct snd_pcm_substream *substream;
1655 struct msm_audio *prtd;
1656
1657 if (!pdata) {
1658 pr_err("%s pdata is NULL\n", __func__);
1659 return -ENODEV;
1660 }
1661 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1662 if (!substream) {
1663 pr_err("%s substream not found\n", __func__);
1664 return -EINVAL;
1665 }
1666 if (!substream->runtime) {
Vignesh Kulothungan2ce67842018-09-25 16:40:29 -07001667 pr_debug("%s substream runtime not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301668 return 0;
1669 }
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301670 mutex_lock(&pdata->lock);
Prasad Kumpatlad4e34682020-06-25 19:38:34 +05301671 if (substream->ref_count > 0) {
1672 prtd = substream->runtime->private_data;
1673 if (prtd)
1674 ucontrol->value.integer.value[0] = prtd->compress_enable;
1675 }
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301676 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301677 return 0;
1678}
1679
1680static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
1681 struct snd_ctl_elem_value *ucontrol)
1682{
1683 int rc = 0;
Meng Wangee084a02018-09-04 16:11:58 +08001684 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
1685 struct msm_plat_data *pdata = dev_get_drvdata(comp->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301686 struct snd_pcm_substream *substream;
1687 struct msm_audio *prtd;
1688 int compress = ucontrol->value.integer.value[0];
1689
1690 if (!pdata) {
1691 pr_err("%s pdata is NULL\n", __func__);
1692 return -ENODEV;
1693 }
1694 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1695 pr_debug("%s: compress : 0x%x\n", __func__, compress);
1696 if (!substream) {
1697 pr_err("%s substream not found\n", __func__);
1698 return -EINVAL;
1699 }
1700 if (!substream->runtime) {
1701 pr_err("%s substream runtime not found\n", __func__);
1702 return 0;
1703 }
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301704 mutex_lock(&pdata->lock);
Prasad Kumpatlad4e34682020-06-25 19:38:34 +05301705 if (substream->ref_count > 0) {
1706 prtd = substream->runtime->private_data;
1707 if (prtd) {
1708 pr_debug("%s: setting compress flag to 0x%x\n",
1709 __func__, compress);
1710 prtd->compress_enable = compress;
1711 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301712 }
Prasad Kumpatla2ef0c882019-10-04 15:11:10 +05301713 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301714 return rc;
1715}
1716
1717static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
1718{
Meng Wangee084a02018-09-04 16:11:58 +08001719 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301720 const char *mixer_ctl_name = "Playback ";
1721 const char *mixer_ctl_end_name = " Compress";
1722 const char *deviceNo = "NN";
1723 char *mixer_str = NULL;
1724 int ctl_len;
1725 int ret = 0;
1726 struct msm_plat_data *pdata;
1727 struct snd_kcontrol_new pcm_compress_control[1] = {
1728 {
1729 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1730 .name = "?",
1731 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1732 .info = msm_pcm_compress_ctl_info,
1733 .get = msm_pcm_compress_ctl_get,
1734 .put = msm_pcm_compress_ctl_put,
1735 .private_value = 0,
1736 }
1737 };
1738
1739 if (!rtd) {
1740 pr_err("%s: NULL rtd\n", __func__);
1741 return -EINVAL;
1742 }
1743
Meng Wangee084a02018-09-04 16:11:58 +08001744 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1745 if (!component) {
1746 pr_err("%s: component is NULL\n", __func__);
1747 return -EINVAL;
1748 }
1749
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301750 ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
1751 strlen(mixer_ctl_end_name) + 1;
1752 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1753
1754 if (!mixer_str)
1755 return -ENOMEM;
1756
1757 snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
1758 rtd->pcm->device, mixer_ctl_end_name);
1759
1760 pcm_compress_control[0].name = mixer_str;
1761 pcm_compress_control[0].private_value = rtd->dai_link->id;
1762 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001763 pdata = dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301764 if (pdata) {
1765 if (!pdata->pcm) {
1766 pdata->pcm = rtd->pcm;
Meng Wangee084a02018-09-04 16:11:58 +08001767 snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301768 pcm_compress_control,
1769 ARRAY_SIZE
1770 (pcm_compress_control));
1771 pr_debug("%s: add control success plt = %pK\n",
Meng Wangee084a02018-09-04 16:11:58 +08001772 __func__, component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301773 }
1774 } else {
1775 pr_err("%s: NULL pdata\n", __func__);
1776 ret = -EINVAL;
1777 }
1778 kfree(mixer_str);
1779 return ret;
1780}
1781
1782static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1783 struct snd_ctl_elem_value *ucontrol)
1784{
1785 int i;
1786 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1787 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1788 struct snd_pcm_substream *substream;
1789 struct msm_audio *prtd;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301790 struct snd_soc_pcm_runtime *rtd = NULL;
1791 struct msm_plat_data *pdata = NULL;
1792 struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001793 struct snd_soc_component *component = NULL;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301794 u64 fe_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301795
1796 pr_debug("%s", __func__);
1797 substream = snd_pcm_chmap_substream(info, idx);
1798 if (!substream)
1799 return -ENODEV;
Ajit Pandeya557d962019-09-05 16:26:01 +05301800
1801 rtd = substream->private_data;
1802 if (rtd) {
1803 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1804 if (component) {
1805 pdata = (struct msm_plat_data *)
1806 dev_get_drvdata(component->dev);
1807 if (!pdata) {
1808 pr_err("%s: pdata not found\n", __func__);
1809 return -ENODEV;
1810 }
1811 } else {
1812 pr_err("%s: component is NULL\n", __func__);
1813 return -EINVAL;
1814 }
1815 }
1816
Vikram Panduranga2b0c9952019-10-14 12:44:25 -07001817 if (!rtd)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301818 return 0;
1819
Ajit Pandeya557d962019-09-05 16:26:01 +05301820 mutex_lock(&pdata->lock);
Prasad Kumpatlad4e34682020-06-25 19:38:34 +05301821 if (substream->ref_count <= 0) {
1822 pr_err_ratelimited("%s: substream ref_count:%d invalid\n",
1823 __func__, substream->ref_count);
1824 mutex_unlock(&pdata->lock);
1825 return -EINVAL;
1826 }
Vikram Panduranga2b0c9952019-10-14 12:44:25 -07001827 prtd = substream->runtime ? substream->runtime->private_data : NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301828 if (prtd) {
1829 prtd->set_channel_map = true;
Dieter Luecking70668fc2018-09-28 15:03:01 +02001830 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301831 prtd->channel_map[i] =
1832 (char)(ucontrol->value.integer.value[i]);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301833
1834 /* update chmixer_pspd chmap cached with routing driver as well */
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301835 if (rtd) {
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001836 if (component) {
1837 fe_id = rtd->dai_link->id;
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001838 chmixer_pspd = pdata ?
1839 pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301840
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001841 if (chmixer_pspd && chmixer_pspd->enable) {
1842 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1843 chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
1844 chmixer_pspd->override_in_ch_map = true;
1845 msm_pcm_routing_set_channel_mixer_cfg(fe_id,
1846 SESSION_TYPE_RX, chmixer_pspd);
1847 }
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301848 }
1849 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301850 }
Ajit Pandeya557d962019-09-05 16:26:01 +05301851 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301852 return 0;
1853}
1854
1855static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
1856 struct snd_ctl_elem_value *ucontrol)
1857{
1858 int i;
1859 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1860 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1861 struct snd_pcm_substream *substream;
1862 struct msm_audio *prtd;
Ajit Pandeya557d962019-09-05 16:26:01 +05301863 struct snd_soc_pcm_runtime *rtd = NULL;
1864 struct msm_plat_data *pdata = NULL;
1865 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301866
1867 pr_debug("%s", __func__);
1868 substream = snd_pcm_chmap_substream(info, idx);
1869 if (!substream)
1870 return -ENODEV;
Ajit Pandeya557d962019-09-05 16:26:01 +05301871
1872 rtd = substream->private_data;
1873 if (rtd) {
1874 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1875 if (component) {
1876 pdata = (struct msm_plat_data *)
1877 dev_get_drvdata(component->dev);
1878 if (!pdata) {
1879 pr_err("%s: pdata not found\n", __func__);
1880 return -ENODEV;
1881 }
1882 } else {
1883 pr_err("%s: component is NULL\n", __func__);
1884 return -EINVAL;
1885 }
1886 }
1887
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301888 memset(ucontrol->value.integer.value, 0,
1889 sizeof(ucontrol->value.integer.value));
Vikram Panduranga2b0c9952019-10-14 12:44:25 -07001890 if (!rtd)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301891 return 0; /* no channels set */
1892
Ajit Pandeya557d962019-09-05 16:26:01 +05301893 mutex_lock(&pdata->lock);
Prasad Kumpatlad4e34682020-06-25 19:38:34 +05301894 if (substream->ref_count <= 0) {
1895 pr_err_ratelimited("%s: substream ref_count:%d invalid\n",
1896 __func__, substream->ref_count);
1897 mutex_unlock(&pdata->lock);
1898 return -EINVAL;
1899 }
Vikram Panduranga2b0c9952019-10-14 12:44:25 -07001900 prtd = substream->runtime ? substream->runtime->private_data : NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301901
1902 if (prtd && prtd->set_channel_map == true) {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001903 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301904 ucontrol->value.integer.value[i] =
1905 (int)prtd->channel_map[i];
1906 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001907 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301908 ucontrol->value.integer.value[i] = 0;
1909 }
1910
Ajit Pandeya557d962019-09-05 16:26:01 +05301911 mutex_unlock(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301912 return 0;
1913}
1914
1915static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
1916{
1917 struct snd_pcm *pcm = rtd->pcm;
1918 struct snd_pcm_chmap *chmap_info;
1919 struct snd_kcontrol *kctl;
1920 char device_num[12];
1921 int i, ret = 0;
1922
1923 pr_debug("%s, Channel map cntrl add\n", __func__);
1924 ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1925 snd_pcm_std_chmaps,
Dieter Luecking70668fc2018-09-28 15:03:01 +02001926 PCM_FORMAT_MAX_NUM_CHANNEL_V8, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301927 &chmap_info);
1928 if (ret < 0) {
1929 pr_err("%s, channel map cntrl add failed\n", __func__);
1930 return ret;
1931 }
1932 kctl = chmap_info->kctl;
1933 for (i = 0; i < kctl->count; i++)
1934 kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
1935 snprintf(device_num, sizeof(device_num), "%d", pcm->device);
1936 strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
1937 pr_debug("%s, Overwriting channel map control name to: %s\n",
1938 __func__, kctl->id.name);
1939 kctl->put = msm_pcm_chmap_ctl_put;
1940 kctl->get = msm_pcm_chmap_ctl_get;
1941 return 0;
1942}
1943
1944static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1945 struct snd_ctl_elem_value *ucontrol)
1946{
1947 u64 fe_id = kcontrol->private_value;
1948 int session_type = SESSION_TYPE_RX;
1949 int be_id = ucontrol->value.integer.value[3];
1950 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1951 int ret = 0;
1952
1953 cfg_data.app_type = ucontrol->value.integer.value[0];
1954 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1955 if (ucontrol->value.integer.value[2] != 0)
1956 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1957 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1958 __func__, fe_id, session_type, be_id,
1959 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1960 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1961 be_id, &cfg_data);
1962 if (ret < 0)
1963 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1964 __func__, ret);
1965
1966 return ret;
1967}
1968
1969static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1970 struct snd_ctl_elem_value *ucontrol)
1971{
1972 u64 fe_id = kcontrol->private_value;
1973 int session_type = SESSION_TYPE_RX;
1974 int be_id = 0;
1975 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1976 int ret = 0;
1977
1978 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1979 &be_id, &cfg_data);
1980 if (ret < 0) {
1981 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1982 __func__, ret);
1983 goto done;
1984 }
1985
1986 ucontrol->value.integer.value[0] = cfg_data.app_type;
1987 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1988 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1989 ucontrol->value.integer.value[3] = be_id;
1990 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1991 __func__, fe_id, session_type, be_id,
1992 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1993done:
1994 return ret;
1995}
1996
1997static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1998 struct snd_ctl_elem_value *ucontrol)
1999{
2000 u64 fe_id = kcontrol->private_value;
2001 int session_type = SESSION_TYPE_TX;
2002 int be_id = ucontrol->value.integer.value[3];
2003 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
2004 int ret = 0;
2005
2006 cfg_data.app_type = ucontrol->value.integer.value[0];
2007 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
2008 if (ucontrol->value.integer.value[2] != 0)
2009 cfg_data.sample_rate = ucontrol->value.integer.value[2];
2010 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
2011 __func__, fe_id, session_type, be_id,
2012 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
2013 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
2014 be_id, &cfg_data);
2015 if (ret < 0)
2016 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
2017 __func__, ret);
2018
2019 return ret;
2020}
2021
2022static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
2023 struct snd_ctl_elem_value *ucontrol)
2024{
2025 u64 fe_id = kcontrol->private_value;
2026 int session_type = SESSION_TYPE_TX;
2027 int be_id = 0;
2028 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
2029 int ret = 0;
2030
2031 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
2032 &be_id, &cfg_data);
2033 if (ret < 0) {
2034 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
2035 __func__, ret);
2036 goto done;
2037 }
2038
2039 ucontrol->value.integer.value[0] = cfg_data.app_type;
2040 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
2041 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
2042 ucontrol->value.integer.value[3] = be_id;
2043 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
2044 __func__, fe_id, session_type, be_id,
2045 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
2046done:
2047 return ret;
2048}
2049
2050static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
2051{
2052 struct snd_pcm *pcm = rtd->pcm;
2053 struct snd_pcm_usr *app_type_info;
2054 struct snd_kcontrol *kctl;
2055 const char *playback_mixer_ctl_name = "Audio Stream";
2056 const char *capture_mixer_ctl_name = "Audio Stream Capture";
2057 const char *deviceNo = "NN";
2058 const char *suffix = "App Type Cfg";
2059 int ctl_len, ret = 0;
2060
2061 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
2062 ctl_len = strlen(playback_mixer_ctl_name) + 1 +
2063 strlen(deviceNo) + 1 + strlen(suffix) + 1;
2064 pr_debug("%s: Playback app type cntrl add\n", __func__);
2065 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
2066 NULL, 1, ctl_len, rtd->dai_link->id,
2067 &app_type_info);
2068 if (ret < 0) {
2069 pr_err("%s: playback app type cntrl add failed: %d\n",
2070 __func__, ret);
2071 return ret;
2072 }
2073 kctl = app_type_info->kctl;
2074 snprintf(kctl->id.name, ctl_len, "%s %d %s",
2075 playback_mixer_ctl_name, rtd->pcm->device, suffix);
2076 kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
2077 kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
2078 }
2079
2080 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
2081 ctl_len = strlen(capture_mixer_ctl_name) + 1 +
2082 strlen(deviceNo) + 1 + strlen(suffix) + 1;
2083 pr_debug("%s: Capture app type cntrl add\n", __func__);
2084 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
2085 NULL, 1, ctl_len, rtd->dai_link->id,
2086 &app_type_info);
2087 if (ret < 0) {
2088 pr_err("%s: capture app type cntrl add failed: %d\n",
2089 __func__, ret);
2090 return ret;
2091 }
2092 kctl = app_type_info->kctl;
2093 snprintf(kctl->id.name, ctl_len, "%s %d %s",
2094 capture_mixer_ctl_name, rtd->pcm->device, suffix);
2095 kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
2096 kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
2097 }
2098
2099 return 0;
2100}
2101
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302102static struct msm_pcm_channel_mixer *msm_pcm_get_chmixer(
2103 struct msm_plat_data *pdata,
2104 u64 fe_id, int session_type)
2105{
2106 if (!pdata) {
2107 pr_err("%s: missing pdata\n", __func__);
2108 return NULL;
2109 }
2110
2111 if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
2112 pr_err("%s: invalid FE %llu\n", __func__, fe_id);
2113 return NULL;
2114 }
2115
2116 if ((session_type != SESSION_TYPE_TX) &&
2117 (session_type != SESSION_TYPE_RX)) {
2118 pr_err("%s: invalid session type %d\n", __func__, session_type);
2119 return NULL;
2120 }
2121
2122 return pdata->chmixer_pspd[fe_id][session_type];
2123}
2124
2125static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
2126 struct snd_ctl_elem_value *ucontrol)
2127{
2128 u64 fe_id = kcontrol->private_value & 0xFF;
2129 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2130 int ret = 0;
2131 int stream_id = 0;
2132 int be_id = 0, i = 0;
2133 struct msm_audio *prtd = NULL;
2134 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2135 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2136 struct snd_pcm *pcm = NULL;
2137 struct snd_pcm_substream *substream = NULL;
2138 struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
2139 u8 asm_ch_map[PCM_FORMAT_MAX_NUM_CHANNEL_V8] = {0};
2140 bool reset_override_out_ch_map = false;
2141 bool reset_override_in_ch_map = false;
2142
2143 pcm = pdata->pcm_device[fe_id];
2144 if (!pcm) {
2145 pr_err("%s invalid pcm handle for fe_id %llu\n",
2146 __func__, fe_id);
2147 return -EINVAL;
2148 }
2149
2150 if (session_type == SESSION_TYPE_RX)
2151 substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
2152 else
2153 substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
2154 if (!substream) {
2155 pr_err("%s substream not found\n", __func__);
2156 return -EINVAL;
2157 }
2158
2159 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2160 if (!chmixer_pspd) {
2161 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2162 return -EINVAL;
2163 }
2164
2165 chmixer_pspd->enable = ucontrol->value.integer.value[0];
2166 chmixer_pspd->rule = ucontrol->value.integer.value[1];
2167 chmixer_pspd->input_channel = ucontrol->value.integer.value[2];
2168 chmixer_pspd->output_channel = ucontrol->value.integer.value[3];
2169 chmixer_pspd->port_idx = ucontrol->value.integer.value[4];
2170
Erin Yan2f81be22019-04-29 13:42:57 +08002171 if (chmixer_pspd->input_channel < 0 ||
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302172 chmixer_pspd->input_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8 ||
Erin Yan2f81be22019-04-29 13:42:57 +08002173 chmixer_pspd->output_channel < 0 ||
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302174 chmixer_pspd->output_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2175 pr_err("%s: Invalid channels, in %d, out %d\n",
2176 __func__, chmixer_pspd->input_channel,
2177 chmixer_pspd->output_channel);
2178 return -EINVAL;
2179 }
2180
Ajit Pandeya557d962019-09-05 16:26:01 +05302181 mutex_lock(&pdata->lock);
Prasad Kumpatlad4e34682020-06-25 19:38:34 +05302182 if (substream->ref_count <= 0) {
2183 pr_err_ratelimited("%s: substream ref_count:%d invalid\n",
2184 __func__, substream->ref_count);
2185 mutex_unlock(&pdata->lock);
2186 return -EINVAL;
2187 }
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302188 prtd = substream->runtime ? substream->runtime->private_data : NULL;
2189 if (chmixer_pspd->enable && prtd) {
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302190 if (session_type == SESSION_TYPE_RX &&
2191 !chmixer_pspd->override_in_ch_map) {
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302192 if (prtd->set_channel_map) {
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302193 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302194 chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302195 } else {
2196 q6asm_map_channels(asm_ch_map,
2197 chmixer_pspd->input_channel, false);
2198 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2199 chmixer_pspd->in_ch_map[i] = asm_ch_map[i];
2200 }
2201 chmixer_pspd->override_in_ch_map = true;
2202 reset_override_in_ch_map = true;
2203 } else if (session_type == SESSION_TYPE_TX &&
2204 !chmixer_pspd->override_out_ch_map) {
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302205 /*
2206 * Channel map set in prtd is for plyback only,
2207 * hence always use default for capture path.
2208 */
2209 q6asm_map_channels(asm_ch_map,
2210 chmixer_pspd->output_channel, false);
2211 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2212 chmixer_pspd->out_ch_map[i] = asm_ch_map[i];
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302213 chmixer_pspd->override_out_ch_map = true;
2214 reset_override_out_ch_map = true;
2215 }
2216 } else {
2217 chmixer_pspd->override_out_ch_map = false;
2218 chmixer_pspd->override_in_ch_map = false;
2219 }
2220
2221 /* cache value and take effect during adm_open stage */
2222 msm_pcm_routing_set_channel_mixer_cfg(fe_id,
2223 session_type,
2224 chmixer_pspd);
2225
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302226 if (chmixer_pspd->enable && prtd && prtd->audio_client) {
2227 stream_id = prtd->audio_client->session;
2228 be_id = chmixer_pspd->port_idx;
2229 msm_pcm_routing_set_channel_mixer_runtime(be_id,
2230 stream_id,
2231 session_type,
2232 chmixer_pspd);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302233 }
2234
2235 if (reset_override_out_ch_map)
2236 chmixer_pspd->override_out_ch_map = false;
2237 if (reset_override_in_ch_map)
2238 chmixer_pspd->override_in_ch_map = false;
2239
Ajit Pandeya557d962019-09-05 16:26:01 +05302240 mutex_unlock(&pdata->lock);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302241 return ret;
2242}
2243
2244static int msm_pcm_channel_mixer_cfg_ctl_get(struct snd_kcontrol *kcontrol,
2245 struct snd_ctl_elem_value *ucontrol)
2246{
2247 u64 fe_id = kcontrol->private_value & 0xFF;
2248 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2249 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2250 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2251 struct msm_pcm_channel_mixer *chmixer_pspd;
2252
2253 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2254 if (!chmixer_pspd) {
2255 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2256 return -EINVAL;
2257 }
2258
2259 ucontrol->value.integer.value[0] = chmixer_pspd->enable;
2260 ucontrol->value.integer.value[1] = chmixer_pspd->rule;
2261 ucontrol->value.integer.value[2] = chmixer_pspd->input_channel;
2262 ucontrol->value.integer.value[3] = chmixer_pspd->output_channel;
2263 ucontrol->value.integer.value[4] = chmixer_pspd->port_idx;
2264 return 0;
2265}
2266
2267static int msm_pcm_channel_mixer_output_map_ctl_put(
2268 struct snd_kcontrol *kcontrol,
2269 struct snd_ctl_elem_value *ucontrol)
2270{
2271 u64 fe_id = kcontrol->private_value & 0xFF;
2272 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2273 int i = 0;
2274 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2275 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2276 struct msm_pcm_channel_mixer *chmixer_pspd;
2277
2278 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2279 if (!chmixer_pspd) {
2280 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2281 return -EINVAL;
2282 }
2283
2284 chmixer_pspd->override_out_ch_map = true;
2285 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2286 chmixer_pspd->out_ch_map[i] =
2287 ucontrol->value.integer.value[i];
2288
2289 return 0;
2290}
2291
2292static int msm_pcm_channel_mixer_output_map_ctl_get(
2293 struct snd_kcontrol *kcontrol,
2294 struct snd_ctl_elem_value *ucontrol)
2295{
2296 u64 fe_id = kcontrol->private_value & 0xFF;
2297 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2298 int i = 0;
2299 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2300 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2301 struct msm_pcm_channel_mixer *chmixer_pspd;
2302
2303 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2304 if (!chmixer_pspd) {
2305 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2306 return -EINVAL;
2307 }
2308
2309 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2310 ucontrol->value.integer.value[i] =
2311 chmixer_pspd->out_ch_map[i];
2312 return 0;
2313}
2314
2315static int msm_pcm_channel_mixer_input_map_ctl_put(
2316 struct snd_kcontrol *kcontrol,
2317 struct snd_ctl_elem_value *ucontrol)
2318{
2319 u64 fe_id = kcontrol->private_value & 0xFF;
2320 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2321 int i = 0;
2322 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2323 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2324 struct msm_pcm_channel_mixer *chmixer_pspd;
2325
2326 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2327 if (!chmixer_pspd) {
2328 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2329 return -EINVAL;
2330 }
2331
2332 chmixer_pspd->override_in_ch_map = true;
2333 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2334 chmixer_pspd->in_ch_map[i] = ucontrol->value.integer.value[i];
2335
2336 return 0;
2337}
2338
2339static int msm_pcm_channel_mixer_input_map_ctl_get(
2340 struct snd_kcontrol *kcontrol,
2341 struct snd_ctl_elem_value *ucontrol)
2342{
2343 u64 fe_id = kcontrol->private_value & 0xFF;
2344 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2345 int i = 0;
2346 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2347 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2348 struct msm_pcm_channel_mixer *chmixer_pspd;
2349
2350 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2351 if (!chmixer_pspd) {
2352 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2353 return -EINVAL;
2354 }
2355
2356 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2357 ucontrol->value.integer.value[i] =
2358 chmixer_pspd->in_ch_map[i];
2359 return 0;
2360}
2361
2362static int msm_pcm_channel_mixer_weight_ctl_put(
2363 struct snd_kcontrol *kcontrol,
2364 struct snd_ctl_elem_value *ucontrol)
2365{
2366 u64 fe_id = kcontrol->private_value & 0xFF;
2367 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2368 int channel = (kcontrol->private_value >> 16) & 0xFF;
2369 int i = 0;
2370 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2371 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2372 struct msm_pcm_channel_mixer *chmixer_pspd;
2373
2374 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2375 if (!chmixer_pspd) {
2376 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2377 return -EINVAL;
2378 }
2379
2380 if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2381 pr_err("%s: invalid channel number %d\n", __func__, channel);
2382 return -EINVAL;
2383 }
2384 channel--;
2385
2386 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2387 chmixer_pspd->channel_weight[channel][i] =
2388 ucontrol->value.integer.value[i];
2389 return 0;
2390}
2391
2392static int msm_pcm_channel_mixer_weight_ctl_get(
2393 struct snd_kcontrol *kcontrol,
2394 struct snd_ctl_elem_value *ucontrol)
2395{
2396 u64 fe_id = kcontrol->private_value & 0xFF;
2397 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2398 int channel = (kcontrol->private_value >> 16) & 0xFF;
2399 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2400 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2401 int i = 0;
2402 struct msm_pcm_channel_mixer *chmixer_pspd;
2403
2404 if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2405 pr_err("%s: invalid channel number %d\n", __func__, channel);
2406 return -EINVAL;
2407 }
2408 channel--;
2409
2410 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2411 if (!chmixer_pspd) {
2412 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2413 return -EINVAL;
2414 }
2415
2416 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2417 ucontrol->value.integer.value[i] =
2418 chmixer_pspd->channel_weight[channel][i];
2419 return 0;
2420}
2421
2422static int msm_pcm_add_platform_controls(struct snd_kcontrol_new *kctl,
2423 struct snd_soc_pcm_runtime *rtd, const char *name_prefix,
2424 const char *name_suffix, int session_type, int channels)
2425{
2426 int ret = -EINVAL;
2427 char *mixer_name = NULL;
2428 struct snd_pcm *pcm = rtd->pcm;
2429 const char *deviceNo = "NN";
2430 const char *channelNo = "NN";
2431 int ctl_len = 0;
2432 struct snd_soc_component *component = NULL;
2433
2434 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2435 if (!component) {
2436 pr_err("%s: component is NULL\n", __func__);
2437 return -EINVAL;
2438 }
2439
2440 ctl_len = strlen(name_prefix) + 1 + strlen(deviceNo) + 1 +
2441 strlen(channelNo) + 1 + strlen(name_suffix) + 1;
2442
2443 mixer_name = kzalloc(ctl_len, GFP_KERNEL);
2444 if (mixer_name == NULL)
2445 return -ENOMEM;
2446
2447 if (channels >= 0) {
2448 snprintf(mixer_name, ctl_len, "%s %d %s %d",
2449 name_prefix, pcm->device, name_suffix, channels);
2450 kctl->private_value = (rtd->dai_link->id) | (session_type << 8) |
2451 (channels << 16);
2452 } else {
2453 snprintf(mixer_name, ctl_len, "%s %d %s",
2454 name_prefix, pcm->device, name_suffix);
2455 kctl->private_value = (rtd->dai_link->id) | (session_type << 8);
2456 }
2457
2458 kctl->name = mixer_name;
2459 ret = snd_soc_add_component_controls(component, kctl, 1);
2460 kfree(mixer_name);
2461 return ret;
2462}
2463
2464static int msm_pcm_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
2465 struct snd_ctl_elem_info *uinfo)
2466{
2467 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2468 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2469 /* Valid channel map value ranges from 1 to 64 */
2470 uinfo->value.integer.min = 1;
2471 uinfo->value.integer.max = 64;
2472 return 0;
2473}
2474
2475static int msm_pcm_add_channel_mixer_output_map_controls(
2476 struct snd_soc_pcm_runtime *rtd)
2477{
2478 struct snd_pcm *pcm = rtd->pcm;
2479 const char *playback_mixer_ctl_name = "AudStr";
2480 const char *capture_mixer_ctl_name = "AudStr Capture";
2481 const char *suffix = "ChMixer Output Map";
2482 int session_type = 0, ret = 0, channel = -1;
2483 struct snd_kcontrol_new channel_mixer_output_map_control = {
2484 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2485 .name = "?",
2486 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2487 .info = msm_pcm_channel_mixer_output_map_info,
2488 .put = msm_pcm_channel_mixer_output_map_ctl_put,
2489 .get = msm_pcm_channel_mixer_output_map_ctl_get,
2490 .private_value = 0,
2491 };
2492
2493 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2494 session_type = SESSION_TYPE_RX;
2495 ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
2496 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2497 if (ret < 0)
2498 goto fail;
2499 }
2500
2501 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2502 session_type = SESSION_TYPE_TX;
2503 ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
2504 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2505 if (ret < 0)
2506 goto fail;
2507 }
2508 return 0;
2509
2510fail:
2511 pr_err("%s: failed add platform ctl, err = %d\n",
2512 __func__, ret);
2513 return ret;
2514}
2515
2516static int msm_pcm_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
2517 struct snd_ctl_elem_info *uinfo)
2518{
2519 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2520 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2521 /* Valid channel map value ranges from 1 to 64 */
2522 uinfo->value.integer.min = 1;
2523 uinfo->value.integer.max = 64;
2524 return 0;
2525}
2526
2527static int msm_pcm_add_channel_mixer_input_map_controls(
2528 struct snd_soc_pcm_runtime *rtd)
2529{
2530 struct snd_pcm *pcm = rtd->pcm;
2531 const char *playback_mixer_ctl_name = "AudStr";
2532 const char *capture_mixer_ctl_name = "AudStr Capture";
2533 const char *suffix = "ChMixer Input Map";
2534 int session_type = 0, ret = 0, channel = -1;
2535 struct snd_kcontrol_new channel_mixer_input_map_control = {
2536 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2537 .name = "?",
2538 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2539 .info = msm_pcm_channel_mixer_input_map_info,
2540 .put = msm_pcm_channel_mixer_input_map_ctl_put,
2541 .get = msm_pcm_channel_mixer_input_map_ctl_get,
2542 .private_value = 0,
2543 };
2544
2545 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2546 session_type = SESSION_TYPE_RX;
2547 ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
2548 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2549 if (ret < 0)
2550 goto fail;
2551 }
2552
2553 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2554 session_type = SESSION_TYPE_TX;
2555 ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
2556 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2557 if (ret < 0)
2558 goto fail;
2559 }
2560 return 0;
2561
2562fail:
2563 pr_err("%s: failed add platform ctl, err = %d\n",
2564 __func__, ret);
2565
2566 return ret;
2567}
2568
2569static int msm_pcm_channel_mixer_cfg_info(struct snd_kcontrol *kcontrol,
2570 struct snd_ctl_elem_info *uinfo)
2571{
2572 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2573 /* five int values: enable, rule, in_channels, out_channels and port_id */
2574 uinfo->count = 5;
2575 /* Valid range is all positive values to support above controls */
2576 uinfo->value.integer.min = 0;
2577 uinfo->value.integer.max = INT_MAX;
2578 return 0;
2579}
2580
2581static int msm_pcm_add_channel_mixer_cfg_controls(
2582 struct snd_soc_pcm_runtime *rtd)
2583{
2584 struct snd_pcm *pcm = rtd->pcm;
2585 const char *playback_mixer_ctl_name = "AudStr";
2586 const char *capture_mixer_ctl_name = "AudStr Capture";
2587 const char *suffix = "ChMixer Cfg";
2588 int session_type = 0, ret = 0, channel = -1;
2589 struct msm_plat_data *pdata = NULL;
2590 struct snd_soc_component *component = NULL;
2591 struct snd_kcontrol_new channel_mixer_cfg_control = {
2592 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2593 .name = "?",
2594 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2595 .info = msm_pcm_channel_mixer_cfg_info,
2596 .put = msm_pcm_channel_mixer_cfg_ctl_put,
2597 .get = msm_pcm_channel_mixer_cfg_ctl_get,
2598 .private_value = 0,
2599 };
2600
2601 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2602 if (!component) {
2603 pr_err("%s: component is NULL\n", __func__);
2604 return -EINVAL;
2605 }
2606
2607 pdata = (struct msm_plat_data *)
2608 dev_get_drvdata(component->dev);
2609
2610 pdata->pcm_device[rtd->dai_link->id] = rtd->pcm;
2611
2612 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2613 session_type = SESSION_TYPE_RX;
2614 ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
2615 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2616 if (ret < 0)
2617 goto fail;
2618 }
2619
2620 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2621 session_type = SESSION_TYPE_TX;
2622 ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
2623 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2624 if (ret < 0)
2625 goto fail;
2626 }
2627 return 0;
2628
2629fail:
2630 pr_err("%s: failed add platform ctl, err = %d\n",
2631 __func__, ret);
2632
2633 return ret;
2634}
2635
2636static int msm_pcm_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
2637 struct snd_ctl_elem_info *uinfo)
2638{
2639 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2640 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2641 /* Valid range: 0 to 0x4000(Unity) gain weightage */
2642 uinfo->value.integer.min = 0;
2643 uinfo->value.integer.max = 0x4000;
2644 return 0;
2645}
2646
2647static int msm_pcm_add_channel_mixer_weight_controls(
2648 struct snd_soc_pcm_runtime *rtd,
2649 int channel)
2650{
2651 struct snd_pcm *pcm = rtd->pcm;
2652 const char *playback_mixer_ctl_name = "AudStr";
2653 const char *capture_mixer_ctl_name = "AudStr Capture";
2654 const char *suffix = "ChMixer Weight Ch";
2655 int session_type = 0, ret = 0;
2656 struct snd_kcontrol_new channel_mixer_weight_control = {
2657 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2658 .name = "?",
2659 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2660 .info = msm_pcm_channel_mixer_weight_info,
2661 .put = msm_pcm_channel_mixer_weight_ctl_put,
2662 .get = msm_pcm_channel_mixer_weight_ctl_get,
2663 .private_value = 0,
2664 };
2665
2666 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2667 session_type = SESSION_TYPE_RX;
2668 ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
2669 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2670 if (ret < 0)
2671 goto fail;
2672 }
2673
2674 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2675 session_type = SESSION_TYPE_TX;
2676 ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
2677 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2678 if (ret < 0)
2679 goto fail;
2680 }
2681 return 0;
2682
2683fail:
2684 pr_err("%s: failed add platform ctl, err = %d\n",
2685 __func__, ret);
2686
2687 return ret;
2688}
2689
2690static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
2691{
2692 int i, ret = 0;
2693 struct snd_pcm *pcm = NULL;
2694 struct msm_plat_data *pdata = NULL;
2695 struct snd_soc_component *component = NULL;
2696
2697 if (!rtd || !rtd->pcm) {
2698 pr_err("%s invalid rtd or pcm\n", __func__);
2699 return -EINVAL;
2700 }
2701 pcm = rtd->pcm;
2702
2703 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2704 if (!component) {
2705 pr_err("%s: component is NULL\n", __func__);
2706 return -EINVAL;
2707 }
2708
2709 pdata = (struct msm_plat_data *)
2710 dev_get_drvdata(component->dev);
2711 if (!pdata) {
2712 pr_err("%s: platform data not populated\n", __func__);
2713 return -EINVAL;
2714 }
2715
2716 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream &&
2717 !pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
2718 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] =
2719 kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
2720 if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
2721 ret = -ENOMEM;
2722 goto fail;
2723 }
2724 }
2725
2726 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream &&
2727 !pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
2728 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] =
2729 kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
2730 if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
2731 ret = -ENOMEM;
2732 goto fail;
2733 }
2734 }
2735
2736 ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
2737 if (ret) {
2738 pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
2739 __func__, ret);
2740 goto fail;
2741 }
2742 ret = msm_pcm_add_channel_mixer_input_map_controls(rtd);
2743 if (ret) {
2744 pr_err("%s: pcm add channel mixer input map controls failed:%d\n",
2745 __func__, ret);
2746 goto fail;
2747 }
2748 ret = msm_pcm_add_channel_mixer_output_map_controls(rtd);
2749 if (ret) {
2750 pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
2751 __func__, ret);
2752 goto fail;
2753 }
2754
2755 for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
2756 ret = msm_pcm_add_channel_mixer_weight_controls(rtd, i);
2757 if (ret) {
2758 pr_err("%s: pcm add channel mixer weight controls failed:%d\n",
2759 __func__, ret);
2760 goto fail;
2761 }
2762 }
2763 return 0;
2764
2765fail:
2766 kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]);
2767 kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]);
2768 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] = NULL;
2769 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] = NULL;
2770
2771 return ret;
2772}
2773
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302774static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
2775{
2776 int ret = 0;
2777
2778 pr_debug("%s\n", __func__);
2779 ret = msm_pcm_add_chmap_controls(rtd);
2780 if (ret)
2781 pr_err("%s: pcm add controls failed:%d\n", __func__, ret);
2782 ret = msm_pcm_add_app_type_controls(rtd);
2783 if (ret)
2784 pr_err("%s: pcm add app type controls failed:%d\n",
2785 __func__, ret);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302786 ret = msm_pcm_add_channel_mixer_controls(rtd);
2787 if (ret)
2788 pr_err("%s: pcm add channel mixer controls failed:%d\n",
2789 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302790 return ret;
2791}
2792
2793static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
2794{
2795 struct snd_card *card = rtd->card->snd_card;
2796 int ret = 0;
2797
2798 if (!card->dev->coherent_dma_mask)
2799 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
2800
2801 ret = msm_pcm_add_controls(rtd);
2802 if (ret) {
2803 pr_err("%s, kctl add failed:%d\n", __func__, ret);
2804 return ret;
2805 }
2806
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07002807 ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_PLAYBACK);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302808 if (ret)
2809 pr_err("%s: Could not add pcm Volume Control %d\n",
2810 __func__, ret);
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07002811 ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_CAPTURE);
2812 if (ret)
2813 pr_err("%s: Could not add pcm Volume Control %d\n",
2814 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302815 ret = msm_pcm_add_compress_control(rtd);
2816 if (ret)
2817 pr_err("%s: Could not add pcm Compress Control %d\n",
2818 __func__, ret);
2819
2820 ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
2821 if (ret)
2822 pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
2823 __func__);
2824
2825 ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
2826 if (ret)
2827 pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
2828 __func__);
2829
2830 return ret;
2831}
2832
2833static snd_pcm_sframes_t msm_pcm_delay_blk(struct snd_pcm_substream *substream,
2834 struct snd_soc_dai *dai)
2835{
2836 struct snd_pcm_runtime *runtime = substream->runtime;
2837 struct msm_audio *prtd = runtime->private_data;
2838 struct audio_client *ac = prtd->audio_client;
2839 snd_pcm_sframes_t frames;
2840 int ret;
2841
2842 ret = q6asm_get_path_delay(prtd->audio_client);
2843 if (ret) {
2844 pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
2845 return 0;
2846 }
2847
2848 /* convert microseconds to frames */
2849 frames = ac->path_delay / 1000 * runtime->rate / 1000;
2850
2851 /* also convert the remainder from the initial division */
2852 frames += ac->path_delay % 1000 * runtime->rate / 1000000;
2853
2854 /* overcompensate for the loss of precision (empirical) */
2855 frames += 2;
2856
2857 return frames;
2858}
2859
Meng Wangee084a02018-09-04 16:11:58 +08002860static struct snd_soc_component_driver msm_soc_component = {
2861 .name = DRV_NAME,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302862 .ops = &msm_pcm_ops,
2863 .pcm_new = msm_asoc_pcm_new,
2864 .delay_blk = msm_pcm_delay_blk,
2865};
2866
2867static int msm_pcm_probe(struct platform_device *pdev)
2868{
2869 int rc;
2870 int id;
2871 struct msm_plat_data *pdata;
2872 const char *latency_level;
2873
2874 rc = of_property_read_u32(pdev->dev.of_node,
2875 "qcom,msm-pcm-dsp-id", &id);
2876 if (rc) {
2877 dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
2878 __func__);
2879 return rc;
2880 }
2881
2882 pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
2883 if (!pdata)
2884 return -ENOMEM;
2885
2886 if (of_property_read_bool(pdev->dev.of_node,
2887 "qcom,msm-pcm-low-latency")) {
2888
2889 pdata->perf_mode = LOW_LATENCY_PCM_MODE;
2890 rc = of_property_read_string(pdev->dev.of_node,
2891 "qcom,latency-level", &latency_level);
2892 if (!rc) {
2893 if (!strcmp(latency_level, "ultra"))
2894 pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
2895 else if (!strcmp(latency_level, "ull-pp"))
2896 pdata->perf_mode =
2897 ULL_POST_PROCESSING_PCM_MODE;
2898 }
2899 } else {
2900 pdata->perf_mode = LEGACY_PCM_MODE;
2901 }
Ajit Pandeya557d962019-09-05 16:26:01 +05302902 mutex_init(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302903 dev_set_drvdata(&pdev->dev, pdata);
2904
2905
2906 dev_dbg(&pdev->dev, "%s: dev name %s\n",
2907 __func__, dev_name(&pdev->dev));
Meng Wangee084a02018-09-04 16:11:58 +08002908 return snd_soc_register_component(&pdev->dev,
2909 &msm_soc_component,
2910 NULL, 0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302911}
2912
2913static int msm_pcm_remove(struct platform_device *pdev)
2914{
2915 struct msm_plat_data *pdata;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302916 int i = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302917
2918 pdata = dev_get_drvdata(&pdev->dev);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302919 if (pdata) {
2920 for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++) {
2921 kfree(pdata->chmixer_pspd[i][SESSION_TYPE_RX]);
2922 kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
2923 }
2924 }
Ajit Pandeya557d962019-09-05 16:26:01 +05302925 mutex_destroy(&pdata->lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302926 kfree(pdata);
Meng Wangee084a02018-09-04 16:11:58 +08002927 snd_soc_unregister_component(&pdev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302928 return 0;
2929}
2930static const struct of_device_id msm_pcm_dt_match[] = {
2931 {.compatible = "qcom,msm-pcm-dsp"},
2932 {}
2933};
2934MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
2935
2936static struct platform_driver msm_pcm_driver = {
2937 .driver = {
2938 .name = "msm-pcm-dsp",
2939 .owner = THIS_MODULE,
2940 .of_match_table = msm_pcm_dt_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +08002941 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302942 },
2943 .probe = msm_pcm_probe,
2944 .remove = msm_pcm_remove,
2945};
2946
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302947int __init msm_pcm_dsp_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302948{
2949 init_waitqueue_head(&the_locks.enable_wait);
2950 init_waitqueue_head(&the_locks.eos_wait);
2951 init_waitqueue_head(&the_locks.write_wait);
2952 init_waitqueue_head(&the_locks.read_wait);
2953
2954 return platform_driver_register(&msm_pcm_driver);
2955}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302956
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05302957void msm_pcm_dsp_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302958{
2959 platform_driver_unregister(&msm_pcm_driver);
2960}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302961
2962MODULE_DESCRIPTION("PCM module platform driver");
2963MODULE_LICENSE("GPL v2");