blob: 678badc363efc35ea9933d748d546e35536abb55 [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -07002/* Copyright (c) 2012-2019, 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>
11#include <linux/wait.h>
12#include <linux/platform_device.h>
13#include <linux/slab.h>
14#include <sound/core.h>
15#include <sound/soc.h>
16#include <sound/soc-dapm.h>
17#include <sound/pcm.h>
18#include <sound/initval.h>
19#include <sound/control.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053020#include <sound/timer.h>
21#include <asm/dma.h>
22#include <linux/dma-mapping.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053023#include <linux/msm_audio.h>
24
25#include <linux/of_device.h>
26#include <sound/tlv.h>
27#include <sound/pcm_params.h>
Surendar Karka38d66472019-03-29 18:08:07 +053028#include <sound/devdep_params.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053029#include <dsp/msm_audio_ion.h>
30#include <dsp/q6audio-v2.h>
Dieter Luecking70668fc2018-09-28 15:03:01 +020031#include <dsp/q6core.h>
32#include <dsp/q6asm-v2.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053033
34#include "msm-pcm-q6-v2.h"
35#include "msm-pcm-routing-v2.h"
36#include "msm-qti-pp-config.h"
37
Meng Wangee084a02018-09-04 16:11:58 +080038#define DRV_NAME "msm-pcm-q6-v2"
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -070039#define TIMEOUT_MS 1000
Meng Wangee084a02018-09-04 16:11:58 +080040
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053041enum stream_state {
42 IDLE = 0,
43 STOPPED,
44 RUNNING,
45};
46
47static struct audio_locks the_locks;
48
49#define PCM_MASTER_VOL_MAX_STEPS 0x2000
50static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
51 PCM_MASTER_VOL_MAX_STEPS);
52
53struct snd_msm {
54 struct snd_card *card;
55 struct snd_pcm *pcm;
56};
57
58#define CMD_EOS_MIN_TIMEOUT_LENGTH 50
59#define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50)
60#define MAX_PB_COPY_RETRIES 3
61
62static struct snd_pcm_hardware msm_pcm_hardware_capture = {
63 .info = (SNDRV_PCM_INFO_MMAP |
64 SNDRV_PCM_INFO_BLOCK_TRANSFER |
65 SNDRV_PCM_INFO_MMAP_VALID |
66 SNDRV_PCM_INFO_INTERLEAVED |
67 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
68 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
69 SNDRV_PCM_FMTBIT_S24_LE |
70 SNDRV_PCM_FMTBIT_S24_3LE |
71 SNDRV_PCM_FMTBIT_S32_LE),
72 .rates = SNDRV_PCM_RATE_8000_384000,
73 .rate_min = 8000,
74 .rate_max = 384000,
75 .channels_min = 1,
76 .channels_max = 4,
77 .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
78 CAPTURE_MAX_PERIOD_SIZE,
79 .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
80 .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
81 .periods_min = CAPTURE_MIN_NUM_PERIODS,
82 .periods_max = CAPTURE_MAX_NUM_PERIODS,
83 .fifo_size = 0,
84};
85
86static struct snd_pcm_hardware msm_pcm_hardware_playback = {
87 .info = (SNDRV_PCM_INFO_MMAP |
88 SNDRV_PCM_INFO_BLOCK_TRANSFER |
89 SNDRV_PCM_INFO_MMAP_VALID |
90 SNDRV_PCM_INFO_INTERLEAVED |
91 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
92 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
93 SNDRV_PCM_FMTBIT_S24_LE |
94 SNDRV_PCM_FMTBIT_S24_3LE |
95 SNDRV_PCM_FMTBIT_S32_LE),
96 .rates = SNDRV_PCM_RATE_8000_384000,
97 .rate_min = 8000,
98 .rate_max = 384000,
99 .channels_min = 1,
100 .channels_max = 8,
101 .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS *
102 PLAYBACK_MAX_PERIOD_SIZE,
103 .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
104 .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
105 .periods_min = PLAYBACK_MIN_NUM_PERIODS,
106 .periods_max = PLAYBACK_MAX_NUM_PERIODS,
107 .fifo_size = 0,
108};
109
110/* Conventional and unconventional sample rate supported */
111static unsigned int supported_sample_rates[] = {
112 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
113 88200, 96000, 176400, 192000, 352800, 384000
114};
115
116static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
117 .count = ARRAY_SIZE(supported_sample_rates),
118 .list = supported_sample_rates,
119 .mask = 0,
120};
121
122static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
123 void *priv_data)
124{
125 struct msm_audio *prtd = priv_data;
126
127 WARN_ON(!prtd);
128
129 pr_debug("%s: event %x\n", __func__, event);
130
131 switch (event) {
132 case MSM_PCM_RT_EVT_BUF_RECFG:
133 q6asm_cmd(prtd->audio_client, CMD_PAUSE);
134 q6asm_cmd(prtd->audio_client, CMD_FLUSH);
135 q6asm_run(prtd->audio_client, 0, 0, 0);
136 /* fallthrough */
137 default:
138 break;
139 }
140}
141
142static void event_handler(uint32_t opcode,
143 uint32_t token, uint32_t *payload, void *priv)
144{
145 struct msm_audio *prtd = priv;
146 struct snd_pcm_substream *substream = prtd->substream;
147 uint32_t *ptrmem = (uint32_t *)payload;
148 uint32_t idx = 0;
149 uint32_t size = 0;
150 uint8_t buf_index;
151 struct snd_soc_pcm_runtime *rtd;
152 int ret = 0;
153
154 switch (opcode) {
155 case ASM_DATA_EVENT_WRITE_DONE_V2: {
156 pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
157 pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
158 prtd->pcm_irq_pos += prtd->pcm_count;
159 if (atomic_read(&prtd->start))
160 snd_pcm_period_elapsed(substream);
161 atomic_inc(&prtd->out_count);
162 wake_up(&the_locks.write_wait);
163 if (!atomic_read(&prtd->start))
164 break;
165 if (!prtd->mmap_flag || prtd->reset_event)
166 break;
167 if (q6asm_is_cpu_buf_avail_nolock(IN,
168 prtd->audio_client,
169 &size, &idx)) {
170 pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
171 __func__, prtd->pcm_count);
172 q6asm_write_nolock(prtd->audio_client,
173 prtd->pcm_count, 0, 0, NO_TIMESTAMP);
174 }
175 break;
176 }
177 case ASM_DATA_EVENT_RENDERED_EOS:
178 pr_debug("ASM_DATA_EVENT_RENDERED_EOS\n");
179 clear_bit(CMD_EOS, &prtd->cmd_pending);
180 wake_up(&the_locks.eos_wait);
181 break;
182 case ASM_DATA_EVENT_READ_DONE_V2: {
183 pr_debug("ASM_DATA_EVENT_READ_DONE_V2\n");
184 buf_index = q6asm_get_buf_index_from_token(token);
Vignesh Kulothungan3817b182017-12-04 15:56:05 -0800185 if (buf_index >= CAPTURE_MAX_NUM_PERIODS) {
186 pr_err("%s: buffer index %u is out of range.\n",
187 __func__, buf_index);
188 return;
189 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530190 pr_debug("%s: token=0x%08x buf_index=0x%08x\n",
191 __func__, token, buf_index);
192 prtd->in_frame_info[buf_index].size = payload[4];
193 prtd->in_frame_info[buf_index].offset = payload[5];
194 /* assume data size = 0 during flushing */
195 if (prtd->in_frame_info[buf_index].size) {
196 prtd->pcm_irq_pos +=
197 prtd->in_frame_info[buf_index].size;
198 pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
199 if (atomic_read(&prtd->start))
200 snd_pcm_period_elapsed(substream);
201 if (atomic_read(&prtd->in_count) <= prtd->periods)
202 atomic_inc(&prtd->in_count);
203 wake_up(&the_locks.read_wait);
204 if (prtd->mmap_flag &&
205 q6asm_is_cpu_buf_avail_nolock(OUT,
206 prtd->audio_client,
207 &size, &idx) &&
208 (substream->runtime->status->state ==
209 SNDRV_PCM_STATE_RUNNING))
210 q6asm_read_nolock(prtd->audio_client);
211 } else {
212 pr_debug("%s: reclaim flushed buf in_count %x\n",
213 __func__, atomic_read(&prtd->in_count));
214 prtd->pcm_irq_pos += prtd->pcm_count;
215 if (prtd->mmap_flag) {
216 if (q6asm_is_cpu_buf_avail_nolock(OUT,
217 prtd->audio_client,
218 &size, &idx) &&
219 (substream->runtime->status->state ==
220 SNDRV_PCM_STATE_RUNNING))
221 q6asm_read_nolock(prtd->audio_client);
222 } else {
223 atomic_inc(&prtd->in_count);
224 }
225 if (atomic_read(&prtd->in_count) == prtd->periods) {
226 pr_info("%s: reclaimed all bufs\n", __func__);
227 if (atomic_read(&prtd->start))
228 snd_pcm_period_elapsed(substream);
229 wake_up(&the_locks.read_wait);
230 }
231 }
232 break;
233 }
234 case ASM_STREAM_PP_EVENT:
235 case ASM_STREAM_CMD_ENCDEC_EVENTS: {
236 pr_debug("%s: ASM_STREAM_EVENT (0x%x)\n", __func__, opcode);
237 if (!substream) {
238 pr_err("%s: substream is NULL.\n", __func__);
239 return;
240 }
241
242 rtd = substream->private_data;
243 if (!rtd) {
244 pr_err("%s: rtd is NULL\n", __func__);
245 return;
246 }
247
248 ret = msm_adsp_inform_mixer_ctl(rtd, payload);
249 if (ret) {
250 pr_err("%s: failed to inform mixer ctl. err = %d\n",
251 __func__, ret);
252 return;
253 }
254
255 break;
256 }
257 case APR_BASIC_RSP_RESULT: {
258 switch (payload[0]) {
259 case ASM_SESSION_CMD_RUN_V2:
260 if (substream->stream
261 != SNDRV_PCM_STREAM_PLAYBACK) {
262 atomic_set(&prtd->start, 1);
263 break;
264 }
265 if (prtd->mmap_flag) {
266 pr_debug("%s:writing %d bytes of buffer to dsp\n",
267 __func__,
268 prtd->pcm_count);
269 q6asm_write_nolock(prtd->audio_client,
270 prtd->pcm_count,
271 0, 0, NO_TIMESTAMP);
272 } else {
273 while (atomic_read(&prtd->out_needed)) {
274 pr_debug("%s:writing %d bytes of buffer to dsp\n",
275 __func__,
276 prtd->pcm_count);
277 q6asm_write_nolock(prtd->audio_client,
278 prtd->pcm_count,
279 0, 0, NO_TIMESTAMP);
280 atomic_dec(&prtd->out_needed);
281 wake_up(&the_locks.write_wait);
282 };
283 }
284 atomic_set(&prtd->start, 1);
285 break;
286 case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
287 pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
288 __func__);
289 break;
290 default:
291 pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
292 __func__, payload[0], payload[1]);
293 break;
294 }
295 }
296 break;
297 case RESET_EVENTS:
298 pr_debug("%s RESET_EVENTS\n", __func__);
299 prtd->pcm_irq_pos += prtd->pcm_count;
300 atomic_inc(&prtd->out_count);
301 atomic_inc(&prtd->in_count);
302 prtd->reset_event = true;
303 if (atomic_read(&prtd->start))
304 snd_pcm_period_elapsed(substream);
305 wake_up(&the_locks.eos_wait);
306 wake_up(&the_locks.write_wait);
307 wake_up(&the_locks.read_wait);
308 break;
309 default:
310 pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
311 break;
312 }
313}
314
315static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
316{
317 struct snd_pcm_runtime *runtime = substream->runtime;
318 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800319 struct snd_soc_component *component =
320 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530321 struct msm_audio *prtd = runtime->private_data;
322 struct msm_plat_data *pdata;
323 struct snd_pcm_hw_params *params;
324 int ret;
325 uint32_t fmt_type = FORMAT_LINEAR_PCM;
326 uint16_t bits_per_sample;
327 uint16_t sample_word_size;
328
Meng Wangee084a02018-09-04 16:11:58 +0800329 if (!component) {
330 pr_err("%s: component is NULL\n", __func__);
331 return -EINVAL;
332 }
333
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530334 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800335 dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530336 if (!pdata) {
337 pr_err("%s: platform data not populated\n", __func__);
338 return -EINVAL;
339 }
340 if (!prtd || !prtd->audio_client) {
341 pr_err("%s: private data null or audio client freed\n",
342 __func__);
343 return -EINVAL;
344 }
345 params = &soc_prtd->dpcm[substream->stream].hw_params;
346
347 pr_debug("%s\n", __func__);
348 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
349 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
350 prtd->pcm_irq_pos = 0;
351 /* rate and channels are sent to audio driver */
352 prtd->samp_rate = runtime->rate;
353 prtd->channel_mode = runtime->channels;
354 if (prtd->enabled)
355 return 0;
356
357 prtd->audio_client->perf_mode = pdata->perf_mode;
358 pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode);
359
360 switch (params_format(params)) {
361 case SNDRV_PCM_FORMAT_S32_LE:
362 bits_per_sample = 32;
363 sample_word_size = 32;
364 break;
365 case SNDRV_PCM_FORMAT_S24_LE:
366 bits_per_sample = 24;
367 sample_word_size = 32;
368 break;
369 case SNDRV_PCM_FORMAT_S24_3LE:
370 bits_per_sample = 24;
371 sample_word_size = 24;
372 break;
373 case SNDRV_PCM_FORMAT_S16_LE:
374 default:
375 bits_per_sample = 16;
376 sample_word_size = 16;
377 break;
378 }
379 if (prtd->compress_enable) {
380 fmt_type = FORMAT_GEN_COMPR;
381 pr_debug("%s: Compressed enabled!\n", __func__);
382 ret = q6asm_open_write_compressed(prtd->audio_client, fmt_type,
383 COMPRESSED_PASSTHROUGH_GEN);
384 if (ret < 0) {
385 pr_err("%s: q6asm_open_write_compressed failed (%d)\n",
386 __func__, ret);
387 q6asm_audio_client_free(prtd->audio_client);
388 prtd->audio_client = NULL;
389 return -ENOMEM;
390 }
391 } else {
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530392 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200393 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530394 ADSP_ASM_API_VERSION_V2) &&
395 q6core_use_Q6_32ch_support())
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) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530443 ADSP_ASM_API_VERSION_V2) &&
444 q6core_use_Q6_32ch_support()) {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200445
446 ret = q6asm_media_format_block_multi_ch_pcm_v5(
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530447 prtd->audio_client, runtime->rate,
448 runtime->channels, !prtd->set_channel_map,
449 prtd->channel_map, bits_per_sample,
450 sample_word_size, ASM_LITTLE_ENDIAN,
451 DEFAULT_QF);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200452 } else {
453 ret = q6asm_media_format_block_multi_ch_pcm_v4(
454 prtd->audio_client, runtime->rate,
455 runtime->channels, !prtd->set_channel_map,
456 prtd->channel_map, bits_per_sample,
457 sample_word_size, ASM_LITTLE_ENDIAN,
458 DEFAULT_QF);
459 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530460 }
461 if (ret < 0)
462 pr_info("%s: CMD Format block failed\n", __func__);
463
464 atomic_set(&prtd->out_count, runtime->periods);
465
466 prtd->enabled = 1;
467 prtd->cmd_pending = 0;
468 prtd->cmd_interrupt = 0;
469
470 return 0;
471}
472
473static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
474{
475 struct snd_pcm_runtime *runtime = substream->runtime;
476 struct msm_audio *prtd = runtime->private_data;
477 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800478 struct snd_soc_component *component =
479 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530480 struct msm_plat_data *pdata;
481 struct snd_pcm_hw_params *params;
482 struct msm_pcm_routing_evt event;
483 int ret = 0;
484 int i = 0;
485 uint16_t bits_per_sample = 16;
486 uint16_t sample_word_size;
487
Meng Wangee084a02018-09-04 16:11:58 +0800488 if (!component) {
489 pr_err("%s: component is NULL\n", __func__);
490 return -EINVAL;
491 }
492
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530493 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800494 dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530495 if (!pdata) {
496 pr_err("%s: platform data not populated\n", __func__);
497 return -EINVAL;
498 }
499 if (!prtd || !prtd->audio_client) {
500 pr_err("%s: private data null or audio client freed\n",
501 __func__);
502 return -EINVAL;
503 }
504
505 if (prtd->enabled == IDLE) {
506 pr_debug("%s:perf_mode=%d periods=%d\n", __func__,
507 pdata->perf_mode, runtime->periods);
508 params = &soc_prtd->dpcm[substream->stream].hw_params;
509 if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) ||
510 (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE))
511 bits_per_sample = 24;
512 else if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
513 bits_per_sample = 32;
514
515 /* ULL mode is not supported in capture path */
516 if (pdata->perf_mode == LEGACY_PCM_MODE)
517 prtd->audio_client->perf_mode = LEGACY_PCM_MODE;
518 else
519 prtd->audio_client->perf_mode = LOW_LATENCY_PCM_MODE;
520
521 pr_debug("%s Opening %d-ch PCM read stream, perf_mode %d\n",
522 __func__, params_channels(params),
523 prtd->audio_client->perf_mode);
524
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530525 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200526 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530527 ADSP_ASM_API_VERSION_V2) &&
528 q6core_use_Q6_32ch_support())
Dieter Luecking70668fc2018-09-28 15:03:01 +0200529 ret = q6asm_open_read_v5(prtd->audio_client,
530 FORMAT_LINEAR_PCM,
531 bits_per_sample, false, ENC_CFG_ID_NONE);
532 else
533 ret = q6asm_open_read_v4(prtd->audio_client,
534 FORMAT_LINEAR_PCM,
Vikram Pandurangac712c172017-11-17 17:36:49 -0800535 bits_per_sample, false, ENC_CFG_ID_NONE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530536 if (ret < 0) {
537 pr_err("%s: q6asm_open_read failed\n", __func__);
538 q6asm_audio_client_free(prtd->audio_client);
539 prtd->audio_client = NULL;
540 return -ENOMEM;
541 }
542
543 ret = q6asm_send_cal(prtd->audio_client);
544 if (ret < 0)
545 pr_debug("%s : Send cal failed : %d", __func__, ret);
546
547 pr_debug("%s: session ID %d\n",
548 __func__, prtd->audio_client->session);
549 prtd->session_id = prtd->audio_client->session;
550 event.event_func = msm_pcm_route_event_handler;
551 event.priv_data = (void *) prtd;
552 ret = msm_pcm_routing_reg_phy_stream_v2(
553 soc_prtd->dai_link->id,
554 prtd->audio_client->perf_mode,
555 prtd->session_id, substream->stream,
556 event);
557 if (ret) {
558 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
559 return ret;
560 }
561 }
562
563 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
564 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
565 prtd->pcm_irq_pos = 0;
566 /* rate and channels are sent to audio driver */
567 prtd->samp_rate = runtime->rate;
568 prtd->channel_mode = runtime->channels;
569
570 if (prtd->enabled == IDLE || prtd->enabled == STOPPED) {
571 for (i = 0; i < runtime->periods; i++)
572 q6asm_read(prtd->audio_client);
573 prtd->periods = runtime->periods;
574 }
575
576 if (prtd->enabled != IDLE)
577 return 0;
578
579 switch (runtime->format) {
580 case SNDRV_PCM_FORMAT_S32_LE:
581 bits_per_sample = 32;
582 sample_word_size = 32;
583 break;
584 case SNDRV_PCM_FORMAT_S24_LE:
585 bits_per_sample = 24;
586 sample_word_size = 32;
587 break;
588 case SNDRV_PCM_FORMAT_S24_3LE:
589 bits_per_sample = 24;
590 sample_word_size = 24;
591 break;
592 case SNDRV_PCM_FORMAT_S16_LE:
593 default:
594 bits_per_sample = 16;
595 sample_word_size = 16;
596 break;
597 }
598
599 pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n",
600 __func__, prtd->samp_rate, prtd->channel_mode,
601 bits_per_sample, sample_word_size);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200602
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530603 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200604 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530605 ADSP_ASM_API_VERSION_V2) &&
606 q6core_use_Q6_32ch_support())
Dieter Luecking70668fc2018-09-28 15:03:01 +0200607 ret = q6asm_enc_cfg_blk_pcm_format_support_v5(
608 prtd->audio_client,
609 prtd->samp_rate,
610 prtd->channel_mode,
611 bits_per_sample,
612 sample_word_size,
613 ASM_LITTLE_ENDIAN,
614 DEFAULT_QF);
615 else
616 ret = q6asm_enc_cfg_blk_pcm_format_support_v4(
617 prtd->audio_client,
618 prtd->samp_rate,
619 prtd->channel_mode,
620 bits_per_sample,
621 sample_word_size,
622 ASM_LITTLE_ENDIAN,
623 DEFAULT_QF);
624
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530625 if (ret < 0)
626 pr_debug("%s: cmd cfg pcm was block failed", __func__);
627
628 prtd->enabled = RUNNING;
629
630 return ret;
631}
632
633static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
634{
635 int ret = 0;
636 struct snd_pcm_runtime *runtime = substream->runtime;
637 struct msm_audio *prtd = runtime->private_data;
638
639 switch (cmd) {
640 case SNDRV_PCM_TRIGGER_START:
641 case SNDRV_PCM_TRIGGER_RESUME:
642 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
643 pr_debug("%s: Trigger start\n", __func__);
644 ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
645 break;
646 case SNDRV_PCM_TRIGGER_STOP:
647 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
648 atomic_set(&prtd->start, 0);
649 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
650 prtd->enabled = STOPPED;
651 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
652 break;
653 }
654 /* pending CMD_EOS isn't expected */
655 WARN_ON_ONCE(test_bit(CMD_EOS, &prtd->cmd_pending));
656 set_bit(CMD_EOS, &prtd->cmd_pending);
657 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
658 if (ret)
659 clear_bit(CMD_EOS, &prtd->cmd_pending);
660 break;
661 case SNDRV_PCM_TRIGGER_SUSPEND:
662 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
663 pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
664 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
665 atomic_set(&prtd->start, 0);
666 break;
667 default:
668 ret = -EINVAL;
669 break;
670 }
671
672 return ret;
673}
674
675static int msm_pcm_open(struct snd_pcm_substream *substream)
676{
677 struct snd_pcm_runtime *runtime = substream->runtime;
678 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800679 struct snd_soc_component *component =
680 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530681 struct msm_audio *prtd;
Banajit Goswami616e68c2017-10-27 01:31:19 -0700682 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530683 int ret = 0;
684
Meng Wangee084a02018-09-04 16:11:58 +0800685 if (!component) {
686 pr_err("%s: component is NULL\n", __func__);
687 return -EINVAL;
688 }
689
Banajit Goswami616e68c2017-10-27 01:31:19 -0700690 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800691 dev_get_drvdata(component->dev);
Banajit Goswami616e68c2017-10-27 01:31:19 -0700692 if (!pdata) {
693 pr_err("%s: platform data not populated\n", __func__);
694 return -EINVAL;
695 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530696 prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
697 if (prtd == NULL)
698 return -ENOMEM;
699
700 prtd->substream = substream;
701 prtd->audio_client = q6asm_audio_client_alloc(
702 (app_cb)event_handler, prtd);
703 if (!prtd->audio_client) {
704 pr_info("%s: Could not allocate memory\n", __func__);
705 kfree(prtd);
Vatsal Bucha2eb2e612018-06-01 12:05:25 +0530706 prtd = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530707 return -ENOMEM;
708 }
709
Meng Wangee084a02018-09-04 16:11:58 +0800710 prtd->audio_client->dev = component->dev;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530711
712 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
713 runtime->hw = msm_pcm_hardware_playback;
714
715 /* Capture path */
716 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
717 runtime->hw = msm_pcm_hardware_capture;
718 else {
719 pr_err("Invalid Stream type %d\n", substream->stream);
720 return -EINVAL;
721 }
722
723 ret = snd_pcm_hw_constraint_list(runtime, 0,
724 SNDRV_PCM_HW_PARAM_RATE,
725 &constraints_sample_rates);
726 if (ret < 0)
727 pr_info("snd_pcm_hw_constraint_list failed\n");
728 /* Ensure that buffer size is a multiple of period size */
729 ret = snd_pcm_hw_constraint_integer(runtime,
730 SNDRV_PCM_HW_PARAM_PERIODS);
731 if (ret < 0)
732 pr_info("snd_pcm_hw_constraint_integer failed\n");
733
734 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
735 ret = snd_pcm_hw_constraint_minmax(runtime,
736 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
737 PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
738 PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
739 if (ret < 0) {
740 pr_err("constraint for buffer bytes min max ret = %d\n",
741 ret);
742 }
743 }
744
745 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
746 ret = snd_pcm_hw_constraint_minmax(runtime,
747 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
748 CAPTURE_MIN_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
749 CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
750 if (ret < 0) {
751 pr_err("constraint for buffer bytes min max ret = %d\n",
752 ret);
753 }
754 }
755 ret = snd_pcm_hw_constraint_step(runtime, 0,
756 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
757 if (ret < 0) {
758 pr_err("constraint for period bytes step ret = %d\n",
759 ret);
760 }
761 ret = snd_pcm_hw_constraint_step(runtime, 0,
762 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
763 if (ret < 0) {
764 pr_err("constraint for buffer bytes step ret = %d\n",
765 ret);
766 }
767
768 prtd->enabled = IDLE;
769 prtd->dsp_cnt = 0;
770 prtd->set_channel_map = false;
771 prtd->reset_event = false;
772 runtime->private_data = prtd;
Xiaojun Sangf27e3512018-05-23 17:14:31 +0800773
774 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
775 msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
776
Banajit Goswami616e68c2017-10-27 01:31:19 -0700777 /* Vote to update the Rx thread priority to RT Thread for playback */
778 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
779 (pdata->perf_mode == LOW_LATENCY_PCM_MODE))
780 apr_start_rx_rt(prtd->audio_client->apr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530781
782 return 0;
783}
784
785static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +0800786 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530787{
788 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530789 int xfer = 0;
790 char *bufptr = NULL;
791 void *data = NULL;
792 uint32_t idx = 0;
793 uint32_t size = 0;
794 uint32_t retries = 0;
795
796 struct snd_pcm_runtime *runtime = substream->runtime;
797 struct msm_audio *prtd = runtime->private_data;
798
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530799 pr_debug("%s: prtd->out_count = %d\n",
800 __func__, atomic_read(&prtd->out_count));
801
802 while ((fbytes > 0) && (retries < MAX_PB_COPY_RETRIES)) {
803 if (prtd->reset_event) {
804 pr_err("%s: In SSR return ENETRESET before wait\n",
805 __func__);
806 return -ENETRESET;
807 }
808
809 ret = wait_event_timeout(the_locks.write_wait,
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -0700810 (atomic_read(&prtd->out_count)),
811 msecs_to_jiffies(TIMEOUT_MS));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530812 if (!ret) {
813 pr_err("%s: wait_event_timeout failed\n", __func__);
814 ret = -ETIMEDOUT;
815 goto fail;
816 }
817 ret = 0;
818
819 if (prtd->reset_event) {
820 pr_err("%s: In SSR return ENETRESET after wait\n",
821 __func__);
822 return -ENETRESET;
823 }
824
825 if (!atomic_read(&prtd->out_count)) {
826 pr_err("%s: pcm stopped out_count 0\n", __func__);
827 return 0;
828 }
829
830 data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size,
831 &idx);
832 if (data == NULL) {
833 retries++;
834 continue;
835 } else {
836 retries = 0;
837 }
838
839 if (fbytes > size)
840 xfer = size;
841 else
842 xfer = fbytes;
843
844 bufptr = data;
845 if (bufptr) {
Meng Wangac147b72017-10-30 16:46:16 +0800846 pr_debug("%s:fbytes =%lu: xfer=%d size=%d\n",
847 __func__, fbytes, xfer, size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530848 if (copy_from_user(bufptr, buf, xfer)) {
849 ret = -EFAULT;
850 pr_err("%s: copy_from_user failed\n",
851 __func__);
852 q6asm_cpu_buf_release(IN, prtd->audio_client);
853 goto fail;
854 }
855 buf += xfer;
856 fbytes -= xfer;
Meng Wangac147b72017-10-30 16:46:16 +0800857 pr_debug("%s:fbytes = %lu: xfer=%d\n", __func__,
858 fbytes, xfer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530859 if (atomic_read(&prtd->start)) {
860 pr_debug("%s:writing %d bytes of buffer to dsp\n",
861 __func__, xfer);
862 ret = q6asm_write(prtd->audio_client, xfer,
863 0, 0, NO_TIMESTAMP);
864 if (ret < 0) {
865 ret = -EFAULT;
866 q6asm_cpu_buf_release(IN,
867 prtd->audio_client);
868 goto fail;
869 }
870 } else
871 atomic_inc(&prtd->out_needed);
872 atomic_dec(&prtd->out_count);
873 }
874 }
875fail:
876 if (retries >= MAX_PB_COPY_RETRIES)
877 ret = -ENOMEM;
878
879 return ret;
880}
881
882static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
883{
884 struct snd_pcm_runtime *runtime = substream->runtime;
885 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
886 struct msm_audio *prtd = runtime->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800887 struct snd_soc_component *component =
888 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Banajit Goswami616e68c2017-10-27 01:31:19 -0700889 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530890 uint32_t timeout;
891 int dir = 0;
892 int ret = 0;
893
894 pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
895
896 if (prtd->audio_client) {
897 dir = IN;
Meng Wangee084a02018-09-04 16:11:58 +0800898 if (!component) {
899 pr_err("%s: component is NULL\n", __func__);
900 return -EINVAL;
901 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530902
Banajit Goswami616e68c2017-10-27 01:31:19 -0700903 /*
904 * Unvote to downgrade the Rx thread priority from
905 * RT Thread for Low-Latency use case.
906 */
907 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800908 dev_get_drvdata(component->dev);
Banajit Goswami616e68c2017-10-27 01:31:19 -0700909 if (pdata) {
910 if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
911 apr_end_rx_rt(prtd->audio_client->apr);
912 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530913 /* determine timeout length */
914 if (runtime->frame_bits == 0 || runtime->rate == 0) {
915 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
916 } else {
917 timeout = (runtime->period_size *
918 CMD_EOS_TIMEOUT_MULTIPLIER) /
919 ((runtime->frame_bits / 8) *
920 runtime->rate);
921 if (timeout < CMD_EOS_MIN_TIMEOUT_LENGTH)
922 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
923 }
924 pr_debug("%s: CMD_EOS timeout is %d\n", __func__, timeout);
925
926 ret = wait_event_timeout(the_locks.eos_wait,
927 !test_bit(CMD_EOS, &prtd->cmd_pending),
928 timeout);
929 if (!ret)
930 pr_err("%s: CMD_EOS failed, cmd_pending 0x%lx\n",
931 __func__, prtd->cmd_pending);
932 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
933 q6asm_audio_client_buf_free_contiguous(dir,
934 prtd->audio_client);
935 q6asm_audio_client_free(prtd->audio_client);
936 }
937 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
938 SNDRV_PCM_STREAM_PLAYBACK);
939 msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
940 kfree(prtd);
941 runtime->private_data = NULL;
942
943 return 0;
944}
945
946static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
Meng Wangac147b72017-10-30 16:46:16 +0800947 int channel, unsigned long hwoff, void __user *buf,
948 unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530949{
950 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530951 int xfer;
952 char *bufptr;
953 void *data = NULL;
Vignesh Kulothungan0c5f3462019-05-22 11:53:08 -0700954 uint32_t idx = 0;
955 uint32_t size = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530956 uint32_t offset = 0;
957 struct snd_pcm_runtime *runtime = substream->runtime;
958 struct msm_audio *prtd = substream->runtime->private_data;
959
960
961 pr_debug("%s\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530962
963 pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
964 pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
965 pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
966
967 if (prtd->reset_event) {
968 pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
969 return -ENETRESET;
970 }
971 ret = wait_event_timeout(the_locks.read_wait,
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -0700972 (atomic_read(&prtd->in_count)),
973 msecs_to_jiffies(TIMEOUT_MS));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530974 if (!ret) {
975 pr_debug("%s: wait_event_timeout failed\n", __func__);
976 goto fail;
977 }
978 if (prtd->reset_event) {
979 pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
980 return -ENETRESET;
981 }
982 if (!atomic_read(&prtd->in_count)) {
983 pr_debug("%s: pcm stopped in_count 0\n", __func__);
984 return 0;
985 }
986 pr_debug("Checking if valid buffer is available...%pK\n",
987 data);
988 data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
989 bufptr = data;
990 pr_debug("Size = %d\n", size);
Meng Wangac147b72017-10-30 16:46:16 +0800991 pr_debug("fbytes = %lu\n", fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530992 pr_debug("idx = %d\n", idx);
993 if (bufptr) {
994 xfer = fbytes;
995 if (xfer > size)
996 xfer = size;
997 offset = prtd->in_frame_info[idx].offset;
998 pr_debug("Offset value = %d\n", offset);
999 if (copy_to_user(buf, bufptr+offset, xfer)) {
1000 pr_err("Failed to copy buf to user\n");
1001 ret = -EFAULT;
1002 q6asm_cpu_buf_release(OUT, prtd->audio_client);
1003 goto fail;
1004 }
1005 fbytes -= xfer;
1006 size -= xfer;
1007 prtd->in_frame_info[idx].offset += xfer;
Meng Wangac147b72017-10-30 16:46:16 +08001008 pr_debug("%s:fbytes = %lu: size=%d: xfer=%d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301009 __func__, fbytes, size, xfer);
1010 pr_debug(" Sending next buffer to dsp\n");
1011 memset(&prtd->in_frame_info[idx], 0,
1012 sizeof(struct msm_audio_in_frame_info));
1013 atomic_dec(&prtd->in_count);
1014 ret = q6asm_read(prtd->audio_client);
1015 if (ret < 0) {
1016 pr_err("q6asm read failed\n");
1017 ret = -EFAULT;
1018 q6asm_cpu_buf_release(OUT, prtd->audio_client);
1019 goto fail;
1020 }
1021 } else
1022 pr_err("No valid buffer\n");
1023
1024 pr_debug("Returning from capture_copy... %d\n", ret);
1025fail:
1026 return ret;
1027}
1028
1029static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
1030{
1031 struct snd_pcm_runtime *runtime = substream->runtime;
1032 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
1033 struct msm_audio *prtd = runtime->private_data;
1034 int dir = OUT;
1035
1036 pr_debug("%s\n", __func__);
1037 if (prtd->audio_client) {
1038 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
1039 q6asm_audio_client_buf_free_contiguous(dir,
1040 prtd->audio_client);
1041 q6asm_audio_client_free(prtd->audio_client);
1042 }
1043
1044 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
1045 SNDRV_PCM_STREAM_CAPTURE);
1046 kfree(prtd);
1047 runtime->private_data = NULL;
1048
1049 return 0;
1050}
1051
1052static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +08001053 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301054{
1055 int ret = 0;
1056
1057 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Meng Wangac147b72017-10-30 16:46:16 +08001058 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301059 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
Meng Wangac147b72017-10-30 16:46:16 +08001060 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301061 return ret;
1062}
1063
1064static int msm_pcm_close(struct snd_pcm_substream *substream)
1065{
1066 int ret = 0;
1067
1068 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1069 ret = msm_pcm_playback_close(substream);
1070 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1071 ret = msm_pcm_capture_close(substream);
1072 return ret;
1073}
1074
1075static int msm_pcm_prepare(struct snd_pcm_substream *substream)
1076{
1077 int ret = 0;
1078
1079 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1080 ret = msm_pcm_playback_prepare(substream);
1081 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1082 ret = msm_pcm_capture_prepare(substream);
1083 return ret;
1084}
1085
1086static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
1087{
1088
1089 struct snd_pcm_runtime *runtime = substream->runtime;
1090 struct msm_audio *prtd = runtime->private_data;
1091
1092 if (prtd->pcm_irq_pos >= prtd->pcm_size)
1093 prtd->pcm_irq_pos = 0;
1094
1095 pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
1096 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
1097}
1098
1099static int msm_pcm_mmap(struct snd_pcm_substream *substream,
1100 struct vm_area_struct *vma)
1101{
1102 struct snd_pcm_runtime *runtime = substream->runtime;
1103 struct msm_audio *prtd = runtime->private_data;
1104 struct audio_client *ac = prtd->audio_client;
1105 struct audio_port_data *apd = ac->port;
1106 struct audio_buffer *ab;
1107 int dir = -1;
1108
1109 prtd->mmap_flag = 1;
1110
1111 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1112 dir = IN;
1113 else
1114 dir = OUT;
1115 ab = &(apd[dir].buf[0]);
1116
1117 return msm_audio_ion_mmap(ab, vma);
1118}
1119
1120static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
1121 struct snd_pcm_hw_params *params)
1122{
1123 struct snd_pcm_runtime *runtime = substream->runtime;
1124 struct msm_audio *prtd = runtime->private_data;
1125 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
1126 struct audio_buffer *buf;
1127 int dir, ret;
1128
1129 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1130 dir = IN;
1131 else
1132 dir = OUT;
1133 ret = q6asm_audio_client_buf_alloc_contiguous(dir,
1134 prtd->audio_client,
1135 (params_buffer_bytes(params) / params_periods(params)),
1136 params_periods(params));
1137 if (ret < 0) {
1138 pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
1139 ret);
1140 return -ENOMEM;
1141 }
1142 buf = prtd->audio_client->port[dir].buf;
1143 if (buf == NULL || buf[0].data == NULL)
1144 return -ENOMEM;
1145
1146 pr_debug("%s:buf = %pK\n", __func__, buf);
1147 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
1148 dma_buf->dev.dev = substream->pcm->card->dev;
1149 dma_buf->private_data = NULL;
1150 dma_buf->area = buf[0].data;
1151 dma_buf->addr = buf[0].phys;
1152 dma_buf->bytes = params_buffer_bytes(params);
1153 if (!dma_buf->area)
1154 return -ENOMEM;
1155
1156 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
1157 return 0;
1158}
1159
Surendar Karka38d66472019-03-29 18:08:07 +05301160static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
1161 unsigned int cmd, void __user *arg)
1162{
1163 struct msm_audio *prtd = NULL;
1164 struct snd_soc_pcm_runtime *rtd = NULL;
1165 uint64_t ses_time = 0, abs_time = 0;
1166 int64_t av_offset = 0;
1167 int32_t clock_id = -EINVAL;
1168 int rc = 0;
1169 struct snd_pcm_prsnt_position userarg;
1170
1171 if (!substream || !substream->private_data) {
1172 pr_err("%s: Invalid %s\n", __func__,
1173 (!substream) ? "substream" : "private_data");
1174 return -EINVAL;
1175 }
1176
1177 if (!substream->runtime) {
1178 pr_err("%s substream runtime not found\n", __func__);
1179 return -EINVAL;
1180 }
1181
1182 prtd = substream->runtime->private_data;
1183 if (!prtd) {
1184 pr_err("%s prtd is null.\n", __func__);
1185 return -EINVAL;
1186 }
1187
1188 rtd = substream->private_data;
1189
1190 switch (cmd) {
1191 case SNDRV_PCM_IOCTL_DSP_POSITION:
1192 dev_dbg(rtd->dev, "%s: SNDRV_PCM_DSP_POSITION", __func__);
1193 if (!arg) {
1194 dev_err(rtd->dev, "%s: Invalid params DSP_POSITION\n",
1195 __func__);
1196 rc = -EINVAL;
1197 goto done;
1198 }
1199 memset(&userarg, 0, sizeof(userarg));
1200 if (copy_from_user(&userarg, arg, sizeof(userarg))) {
1201 dev_err(rtd->dev, "%s: err copyuser DSP_POSITION\n",
1202 __func__);
1203 rc = -EFAULT;
1204 goto done;
1205 }
1206 clock_id = userarg.clock_id;
1207 rc = q6asm_get_session_time_v2(prtd->audio_client, &ses_time,
1208 &abs_time);
1209 if (rc) {
1210 pr_err("%s: q6asm_get_session_time_v2 failed, rc=%d\n",
1211 __func__, rc);
1212 goto done;
1213 }
1214 userarg.frames = div64_u64((ses_time * prtd->samp_rate),
1215 1000000);
1216
1217 rc = avcs_core_query_timer_offset(&av_offset, clock_id);
1218 if (rc) {
1219 pr_err("%s: avcs offset query failed, rc=%d\n",
1220 __func__, rc);
1221 goto done;
1222 }
1223
1224 userarg.timestamp = abs_time + av_offset;
1225 if (copy_to_user(arg, &userarg, sizeof(userarg))) {
1226 dev_err(rtd->dev, "%s: err copy to user DSP_POSITION\n",
1227 __func__);
1228 rc = -EFAULT;
1229 goto done;
1230 }
1231 pr_debug("%s, vals f %lld, t %lld, avoff %lld, abst %lld, sess_time %llu sr %d\n",
1232 __func__, userarg.frames, userarg.timestamp,
1233 av_offset, abs_time, ses_time, prtd->samp_rate);
1234 break;
1235 default:
1236 rc = snd_pcm_lib_ioctl(substream, cmd, arg);
1237 break;
1238 }
1239done:
1240 return rc;
1241}
1242
1243#ifdef CONFIG_COMPAT
1244static int msm_pcm_compat_ioctl(struct snd_pcm_substream *substream,
1245 unsigned int cmd, void __user *arg)
1246{
1247 return msm_pcm_ioctl(substream, cmd, arg);
1248}
1249#else
1250#define msm_pcm_compat_ioctl NULL
1251#endif
1252
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301253static const struct snd_pcm_ops msm_pcm_ops = {
1254 .open = msm_pcm_open,
Meng Wangac147b72017-10-30 16:46:16 +08001255 .copy_user = msm_pcm_copy,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301256 .hw_params = msm_pcm_hw_params,
1257 .close = msm_pcm_close,
Surendar Karka38d66472019-03-29 18:08:07 +05301258 .ioctl = msm_pcm_ioctl,
1259 .compat_ioctl = msm_pcm_compat_ioctl,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301260 .prepare = msm_pcm_prepare,
1261 .trigger = msm_pcm_trigger,
1262 .pointer = msm_pcm_pointer,
1263 .mmap = msm_pcm_mmap,
1264};
1265
1266static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
1267 struct snd_ctl_elem_value *ucontrol)
1268{
Meng Wangee084a02018-09-04 16:11:58 +08001269 struct snd_soc_component *component =
1270 snd_soc_kcontrol_component(kcontrol);
1271 struct msm_plat_data *pdata = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301272 struct snd_pcm_substream *substream;
1273 struct msm_audio *prtd;
1274 int ret = 0;
1275 struct msm_adsp_event_data *event_data = NULL;
1276
Meng Wangee084a02018-09-04 16:11:58 +08001277 if (!component) {
1278 pr_err("%s: component is NULL\n", __func__);
1279 return -EINVAL;
1280 }
1281
1282 pdata = dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301283 if (!pdata) {
1284 pr_err("%s pdata is NULL\n", __func__);
1285 ret = -ENODEV;
1286 goto done;
1287 }
1288
1289 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1290 if (!substream) {
1291 pr_err("%s substream not found\n", __func__);
1292 ret = -EINVAL;
1293 goto done;
1294 }
1295
1296 if (!substream->runtime) {
1297 pr_err("%s substream runtime not found\n", __func__);
1298 ret = -EINVAL;
1299 goto done;
1300 }
1301
1302 prtd = substream->runtime->private_data;
Vatsal Bucha2eb2e612018-06-01 12:05:25 +05301303 if (prtd == NULL) {
1304 pr_err("%s prtd is null.\n", __func__);
1305 ret = -EINVAL;
1306 goto done;
1307 }
1308
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301309 if (prtd->audio_client == NULL) {
1310 pr_err("%s prtd is null.\n", __func__);
1311 ret = -EINVAL;
1312 goto done;
1313 }
1314
1315 event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
1316 if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
1317 (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
1318 pr_err("%s: invalid event_type=%d",
1319 __func__, event_data->event_type);
1320 ret = -EINVAL;
1321 goto done;
1322 }
1323
Xiaojun Sang75642c32018-03-23 08:57:33 +08001324 if (event_data->payload_len > sizeof(ucontrol->value.bytes.data)
1325 - sizeof(struct msm_adsp_event_data)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301326 pr_err("%s param length=%d exceeds limit",
1327 __func__, event_data->payload_len);
1328 ret = -EINVAL;
1329 goto done;
1330 }
1331
1332 ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
1333 if (ret < 0)
1334 pr_err("%s: failed to send stream event cmd, err = %d\n",
1335 __func__, ret);
1336done:
1337 return ret;
1338}
1339
1340static int msm_pcm_add_audio_adsp_stream_cmd_control(
1341 struct snd_soc_pcm_runtime *rtd)
1342{
Meng Wangee084a02018-09-04 16:11:58 +08001343 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301344 const char *mixer_ctl_name = DSP_STREAM_CMD;
1345 const char *deviceNo = "NN";
1346 char *mixer_str = NULL;
1347 int ctl_len = 0, ret = 0;
1348 struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
1349 {
1350 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1351 .name = "?",
1352 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1353 .info = msm_adsp_stream_cmd_info,
1354 .put = msm_pcm_adsp_stream_cmd_put,
1355 .private_value = 0,
1356 }
1357 };
1358
1359 if (!rtd) {
1360 pr_err("%s rtd is NULL\n", __func__);
1361 ret = -EINVAL;
1362 goto done;
1363 }
1364
Meng Wangee084a02018-09-04 16:11:58 +08001365 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1366 if (!component) {
1367 pr_err("%s: component is NULL\n", __func__);
1368 return -EINVAL;
1369 }
1370
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301371 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1372 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1373 if (!mixer_str) {
1374 ret = -ENOMEM;
1375 goto done;
1376 }
1377
1378 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1379 fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
1380 fe_audio_adsp_stream_cmd_config_control[0].private_value =
1381 rtd->dai_link->id;
1382 pr_debug("Registering new mixer ctl %s\n", mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001383 ret = snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301384 fe_audio_adsp_stream_cmd_config_control,
1385 ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
1386 if (ret < 0)
1387 pr_err("%s: failed add ctl %s. err = %d\n",
1388 __func__, mixer_str, ret);
1389
1390 kfree(mixer_str);
1391done:
1392 return ret;
1393}
1394
1395static int msm_pcm_add_audio_adsp_stream_callback_control(
1396 struct snd_soc_pcm_runtime *rtd)
1397{
Meng Wangee084a02018-09-04 16:11:58 +08001398 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301399 const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
1400 const char *deviceNo = "NN";
1401 char *mixer_str = NULL;
1402 int ctl_len = 0, ret = 0;
1403 struct snd_kcontrol *kctl;
1404
1405 struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
1406 {
1407 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1408 .name = "?",
1409 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1410 .info = msm_adsp_stream_callback_info,
1411 .get = msm_adsp_stream_callback_get,
1412 .private_value = 0,
1413 }
1414 };
1415
1416 if (!rtd) {
1417 pr_err("%s NULL rtd\n", __func__);
1418 ret = -EINVAL;
1419 goto done;
1420 }
1421
Meng Wangee084a02018-09-04 16:11:58 +08001422 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1423 if (!component) {
1424 pr_err("%s: component is NULL\n", __func__);
1425 return -EINVAL;
1426 }
1427
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301428 pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
1429 __func__, rtd->dai_link->name, rtd->dai_link->id,
1430 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
1431 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1432 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1433 if (!mixer_str) {
1434 ret = -ENOMEM;
1435 goto done;
1436 }
1437
1438 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1439 fe_audio_adsp_callback_config_control[0].name = mixer_str;
1440 fe_audio_adsp_callback_config_control[0].private_value =
1441 rtd->dai_link->id;
1442 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001443 ret = snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301444 fe_audio_adsp_callback_config_control,
1445 ARRAY_SIZE(fe_audio_adsp_callback_config_control));
1446 if (ret < 0) {
1447 pr_err("%s: failed to add ctl %s. err = %d\n",
1448 __func__, mixer_str, ret);
1449 ret = -EINVAL;
1450 goto free_mixer_str;
1451 }
1452
1453 kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
1454 if (!kctl) {
1455 pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
1456 ret = -EINVAL;
1457 goto free_mixer_str;
1458 }
1459
1460 kctl->private_data = NULL;
1461
1462free_mixer_str:
1463 kfree(mixer_str);
1464done:
1465 return ret;
1466}
1467
1468static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
1469{
1470 int rc = 0;
1471
1472 if (prtd && prtd->audio_client) {
1473 pr_debug("%s: channels %d volume 0x%x\n", __func__,
1474 prtd->channel_mode, volume);
1475 rc = q6asm_set_volume(prtd->audio_client, volume);
1476 if (rc < 0) {
1477 pr_err("%s: Send Volume command failed rc=%d\n",
1478 __func__, rc);
1479 }
1480 }
1481 return rc;
1482}
1483
1484static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
1485 struct snd_ctl_elem_value *ucontrol)
1486{
1487 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
1488 struct snd_pcm_substream *substream =
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001489 vol->pcm->streams[vol->stream].substream;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301490 struct msm_audio *prtd;
1491
1492 pr_debug("%s\n", __func__);
1493 if (!substream) {
1494 pr_err("%s substream not found\n", __func__);
1495 return -ENODEV;
1496 }
1497 if (!substream->runtime) {
Vignesh Kulothungan2ce67842018-09-25 16:40:29 -07001498 pr_debug("%s substream runtime not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301499 return 0;
1500 }
1501 prtd = substream->runtime->private_data;
1502 if (prtd)
1503 ucontrol->value.integer.value[0] = prtd->volume;
1504 return 0;
1505}
1506
1507static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
1508 struct snd_ctl_elem_value *ucontrol)
1509{
1510 int rc = 0;
1511 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
1512 struct snd_pcm_substream *substream =
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001513 vol->pcm->streams[vol->stream].substream;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301514 struct msm_audio *prtd;
1515 int volume = ucontrol->value.integer.value[0];
1516
1517 pr_debug("%s: volume : 0x%x\n", __func__, volume);
1518 if (!substream) {
1519 pr_err("%s substream not found\n", __func__);
1520 return -ENODEV;
1521 }
1522 if (!substream->runtime) {
1523 pr_err("%s substream runtime not found\n", __func__);
1524 return 0;
1525 }
1526 prtd = substream->runtime->private_data;
1527 if (prtd) {
1528 rc = msm_pcm_set_volume(prtd, volume);
1529 prtd->volume = volume;
1530 }
1531 return rc;
1532}
1533
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001534static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd,
1535 int stream)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301536{
1537 int ret = 0;
1538 struct snd_pcm *pcm = rtd->pcm;
1539 struct snd_pcm_volume *volume_info;
1540 struct snd_kcontrol *kctl;
1541
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001542 dev_dbg(rtd->dev, "%s, volume control add\n", __func__);
1543 ret = snd_pcm_add_volume_ctls(pcm, stream,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301544 NULL, 1, rtd->dai_link->id,
1545 &volume_info);
1546 if (ret < 0) {
1547 pr_err("%s volume control failed ret %d\n", __func__, ret);
1548 return ret;
1549 }
1550 kctl = volume_info->kctl;
1551 kctl->put = msm_pcm_volume_ctl_put;
1552 kctl->get = msm_pcm_volume_ctl_get;
1553 kctl->tlv.p = msm_pcm_vol_gain;
1554 return 0;
1555}
1556
1557static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
1558 struct snd_ctl_elem_info *uinfo)
1559{
1560 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1561 uinfo->count = 1;
1562 uinfo->value.integer.min = 0;
1563 uinfo->value.integer.max = 0x2000;
1564 return 0;
1565}
1566
1567static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
1568 struct snd_ctl_elem_value *ucontrol)
1569{
Meng Wangee084a02018-09-04 16:11:58 +08001570 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
1571 struct msm_plat_data *pdata = dev_get_drvdata(comp->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301572 struct snd_pcm_substream *substream;
1573 struct msm_audio *prtd;
1574
1575 if (!pdata) {
1576 pr_err("%s pdata is NULL\n", __func__);
1577 return -ENODEV;
1578 }
1579 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1580 if (!substream) {
1581 pr_err("%s substream not found\n", __func__);
1582 return -EINVAL;
1583 }
1584 if (!substream->runtime) {
Vignesh Kulothungan2ce67842018-09-25 16:40:29 -07001585 pr_debug("%s substream runtime not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301586 return 0;
1587 }
1588 prtd = substream->runtime->private_data;
1589 if (prtd)
1590 ucontrol->value.integer.value[0] = prtd->compress_enable;
1591 return 0;
1592}
1593
1594static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
1595 struct snd_ctl_elem_value *ucontrol)
1596{
1597 int rc = 0;
Meng Wangee084a02018-09-04 16:11:58 +08001598 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
1599 struct msm_plat_data *pdata = dev_get_drvdata(comp->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301600 struct snd_pcm_substream *substream;
1601 struct msm_audio *prtd;
1602 int compress = ucontrol->value.integer.value[0];
1603
1604 if (!pdata) {
1605 pr_err("%s pdata is NULL\n", __func__);
1606 return -ENODEV;
1607 }
1608 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1609 pr_debug("%s: compress : 0x%x\n", __func__, compress);
1610 if (!substream) {
1611 pr_err("%s substream not found\n", __func__);
1612 return -EINVAL;
1613 }
1614 if (!substream->runtime) {
1615 pr_err("%s substream runtime not found\n", __func__);
1616 return 0;
1617 }
1618 prtd = substream->runtime->private_data;
1619 if (prtd) {
1620 pr_debug("%s: setting compress flag to 0x%x\n",
1621 __func__, compress);
1622 prtd->compress_enable = compress;
1623 }
1624 return rc;
1625}
1626
1627static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
1628{
Meng Wangee084a02018-09-04 16:11:58 +08001629 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301630 const char *mixer_ctl_name = "Playback ";
1631 const char *mixer_ctl_end_name = " Compress";
1632 const char *deviceNo = "NN";
1633 char *mixer_str = NULL;
1634 int ctl_len;
1635 int ret = 0;
1636 struct msm_plat_data *pdata;
1637 struct snd_kcontrol_new pcm_compress_control[1] = {
1638 {
1639 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1640 .name = "?",
1641 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1642 .info = msm_pcm_compress_ctl_info,
1643 .get = msm_pcm_compress_ctl_get,
1644 .put = msm_pcm_compress_ctl_put,
1645 .private_value = 0,
1646 }
1647 };
1648
1649 if (!rtd) {
1650 pr_err("%s: NULL rtd\n", __func__);
1651 return -EINVAL;
1652 }
1653
Meng Wangee084a02018-09-04 16:11:58 +08001654 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1655 if (!component) {
1656 pr_err("%s: component is NULL\n", __func__);
1657 return -EINVAL;
1658 }
1659
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301660 ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
1661 strlen(mixer_ctl_end_name) + 1;
1662 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1663
1664 if (!mixer_str)
1665 return -ENOMEM;
1666
1667 snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
1668 rtd->pcm->device, mixer_ctl_end_name);
1669
1670 pcm_compress_control[0].name = mixer_str;
1671 pcm_compress_control[0].private_value = rtd->dai_link->id;
1672 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001673 pdata = dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301674 if (pdata) {
1675 if (!pdata->pcm) {
1676 pdata->pcm = rtd->pcm;
Meng Wangee084a02018-09-04 16:11:58 +08001677 snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301678 pcm_compress_control,
1679 ARRAY_SIZE
1680 (pcm_compress_control));
1681 pr_debug("%s: add control success plt = %pK\n",
Meng Wangee084a02018-09-04 16:11:58 +08001682 __func__, component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301683 }
1684 } else {
1685 pr_err("%s: NULL pdata\n", __func__);
1686 ret = -EINVAL;
1687 }
1688 kfree(mixer_str);
1689 return ret;
1690}
1691
1692static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1693 struct snd_ctl_elem_value *ucontrol)
1694{
1695 int i;
1696 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1697 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1698 struct snd_pcm_substream *substream;
1699 struct msm_audio *prtd;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301700 struct snd_soc_pcm_runtime *rtd = NULL;
1701 struct msm_plat_data *pdata = NULL;
1702 struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001703 struct snd_soc_component *component = NULL;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301704 u64 fe_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301705
1706 pr_debug("%s", __func__);
1707 substream = snd_pcm_chmap_substream(info, idx);
1708 if (!substream)
1709 return -ENODEV;
1710 if (!substream->runtime)
1711 return 0;
1712
1713 prtd = substream->runtime->private_data;
1714 if (prtd) {
1715 prtd->set_channel_map = true;
Dieter Luecking70668fc2018-09-28 15:03:01 +02001716 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301717 prtd->channel_map[i] =
1718 (char)(ucontrol->value.integer.value[i]);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301719
1720 /* update chmixer_pspd chmap cached with routing driver as well */
1721 rtd = substream->private_data;
1722 if (rtd) {
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001723 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1724 if (component) {
1725 fe_id = rtd->dai_link->id;
1726 pdata = (struct msm_plat_data *)
1727 dev_get_drvdata(component->dev);
1728 chmixer_pspd = pdata ?
1729 pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301730
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001731 if (chmixer_pspd && chmixer_pspd->enable) {
1732 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1733 chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
1734 chmixer_pspd->override_in_ch_map = true;
1735 msm_pcm_routing_set_channel_mixer_cfg(fe_id,
1736 SESSION_TYPE_RX, chmixer_pspd);
1737 }
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301738 }
1739 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301740 }
1741 return 0;
1742}
1743
1744static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
1745 struct snd_ctl_elem_value *ucontrol)
1746{
1747 int i;
1748 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1749 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1750 struct snd_pcm_substream *substream;
1751 struct msm_audio *prtd;
1752
1753 pr_debug("%s", __func__);
1754 substream = snd_pcm_chmap_substream(info, idx);
1755 if (!substream)
1756 return -ENODEV;
1757 memset(ucontrol->value.integer.value, 0,
1758 sizeof(ucontrol->value.integer.value));
1759 if (!substream->runtime)
1760 return 0; /* no channels set */
1761
1762 prtd = substream->runtime->private_data;
1763
1764 if (prtd && prtd->set_channel_map == true) {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001765 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301766 ucontrol->value.integer.value[i] =
1767 (int)prtd->channel_map[i];
1768 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001769 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301770 ucontrol->value.integer.value[i] = 0;
1771 }
1772
1773 return 0;
1774}
1775
1776static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
1777{
1778 struct snd_pcm *pcm = rtd->pcm;
1779 struct snd_pcm_chmap *chmap_info;
1780 struct snd_kcontrol *kctl;
1781 char device_num[12];
1782 int i, ret = 0;
1783
1784 pr_debug("%s, Channel map cntrl add\n", __func__);
1785 ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1786 snd_pcm_std_chmaps,
Dieter Luecking70668fc2018-09-28 15:03:01 +02001787 PCM_FORMAT_MAX_NUM_CHANNEL_V8, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301788 &chmap_info);
1789 if (ret < 0) {
1790 pr_err("%s, channel map cntrl add failed\n", __func__);
1791 return ret;
1792 }
1793 kctl = chmap_info->kctl;
1794 for (i = 0; i < kctl->count; i++)
1795 kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
1796 snprintf(device_num, sizeof(device_num), "%d", pcm->device);
1797 strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
1798 pr_debug("%s, Overwriting channel map control name to: %s\n",
1799 __func__, kctl->id.name);
1800 kctl->put = msm_pcm_chmap_ctl_put;
1801 kctl->get = msm_pcm_chmap_ctl_get;
1802 return 0;
1803}
1804
1805static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1806 struct snd_ctl_elem_value *ucontrol)
1807{
1808 u64 fe_id = kcontrol->private_value;
1809 int session_type = SESSION_TYPE_RX;
1810 int be_id = ucontrol->value.integer.value[3];
1811 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1812 int ret = 0;
1813
1814 cfg_data.app_type = ucontrol->value.integer.value[0];
1815 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1816 if (ucontrol->value.integer.value[2] != 0)
1817 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1818 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1819 __func__, fe_id, session_type, be_id,
1820 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1821 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1822 be_id, &cfg_data);
1823 if (ret < 0)
1824 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1825 __func__, ret);
1826
1827 return ret;
1828}
1829
1830static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1831 struct snd_ctl_elem_value *ucontrol)
1832{
1833 u64 fe_id = kcontrol->private_value;
1834 int session_type = SESSION_TYPE_RX;
1835 int be_id = 0;
1836 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1837 int ret = 0;
1838
1839 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1840 &be_id, &cfg_data);
1841 if (ret < 0) {
1842 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1843 __func__, ret);
1844 goto done;
1845 }
1846
1847 ucontrol->value.integer.value[0] = cfg_data.app_type;
1848 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1849 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1850 ucontrol->value.integer.value[3] = be_id;
1851 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1852 __func__, fe_id, session_type, be_id,
1853 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1854done:
1855 return ret;
1856}
1857
1858static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1859 struct snd_ctl_elem_value *ucontrol)
1860{
1861 u64 fe_id = kcontrol->private_value;
1862 int session_type = SESSION_TYPE_TX;
1863 int be_id = ucontrol->value.integer.value[3];
1864 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1865 int ret = 0;
1866
1867 cfg_data.app_type = ucontrol->value.integer.value[0];
1868 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1869 if (ucontrol->value.integer.value[2] != 0)
1870 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1871 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1872 __func__, fe_id, session_type, be_id,
1873 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1874 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1875 be_id, &cfg_data);
1876 if (ret < 0)
1877 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1878 __func__, ret);
1879
1880 return ret;
1881}
1882
1883static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1884 struct snd_ctl_elem_value *ucontrol)
1885{
1886 u64 fe_id = kcontrol->private_value;
1887 int session_type = SESSION_TYPE_TX;
1888 int be_id = 0;
1889 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1890 int ret = 0;
1891
1892 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1893 &be_id, &cfg_data);
1894 if (ret < 0) {
1895 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1896 __func__, ret);
1897 goto done;
1898 }
1899
1900 ucontrol->value.integer.value[0] = cfg_data.app_type;
1901 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1902 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1903 ucontrol->value.integer.value[3] = be_id;
1904 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1905 __func__, fe_id, session_type, be_id,
1906 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1907done:
1908 return ret;
1909}
1910
1911static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
1912{
1913 struct snd_pcm *pcm = rtd->pcm;
1914 struct snd_pcm_usr *app_type_info;
1915 struct snd_kcontrol *kctl;
1916 const char *playback_mixer_ctl_name = "Audio Stream";
1917 const char *capture_mixer_ctl_name = "Audio Stream Capture";
1918 const char *deviceNo = "NN";
1919 const char *suffix = "App Type Cfg";
1920 int ctl_len, ret = 0;
1921
1922 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
1923 ctl_len = strlen(playback_mixer_ctl_name) + 1 +
1924 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1925 pr_debug("%s: Playback app type cntrl add\n", __func__);
1926 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1927 NULL, 1, ctl_len, rtd->dai_link->id,
1928 &app_type_info);
1929 if (ret < 0) {
1930 pr_err("%s: playback app type cntrl add failed: %d\n",
1931 __func__, ret);
1932 return ret;
1933 }
1934 kctl = app_type_info->kctl;
1935 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1936 playback_mixer_ctl_name, rtd->pcm->device, suffix);
1937 kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
1938 kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
1939 }
1940
1941 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
1942 ctl_len = strlen(capture_mixer_ctl_name) + 1 +
1943 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1944 pr_debug("%s: Capture app type cntrl add\n", __func__);
1945 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
1946 NULL, 1, ctl_len, rtd->dai_link->id,
1947 &app_type_info);
1948 if (ret < 0) {
1949 pr_err("%s: capture app type cntrl add failed: %d\n",
1950 __func__, ret);
1951 return ret;
1952 }
1953 kctl = app_type_info->kctl;
1954 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1955 capture_mixer_ctl_name, rtd->pcm->device, suffix);
1956 kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
1957 kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
1958 }
1959
1960 return 0;
1961}
1962
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301963static struct msm_pcm_channel_mixer *msm_pcm_get_chmixer(
1964 struct msm_plat_data *pdata,
1965 u64 fe_id, int session_type)
1966{
1967 if (!pdata) {
1968 pr_err("%s: missing pdata\n", __func__);
1969 return NULL;
1970 }
1971
1972 if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
1973 pr_err("%s: invalid FE %llu\n", __func__, fe_id);
1974 return NULL;
1975 }
1976
1977 if ((session_type != SESSION_TYPE_TX) &&
1978 (session_type != SESSION_TYPE_RX)) {
1979 pr_err("%s: invalid session type %d\n", __func__, session_type);
1980 return NULL;
1981 }
1982
1983 return pdata->chmixer_pspd[fe_id][session_type];
1984}
1985
1986static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1987 struct snd_ctl_elem_value *ucontrol)
1988{
1989 u64 fe_id = kcontrol->private_value & 0xFF;
1990 int session_type = (kcontrol->private_value >> 8) & 0xFF;
1991 int ret = 0;
1992 int stream_id = 0;
1993 int be_id = 0, i = 0;
1994 struct msm_audio *prtd = NULL;
1995 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
1996 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
1997 struct snd_pcm *pcm = NULL;
1998 struct snd_pcm_substream *substream = NULL;
1999 struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
2000 u8 asm_ch_map[PCM_FORMAT_MAX_NUM_CHANNEL_V8] = {0};
2001 bool reset_override_out_ch_map = false;
2002 bool reset_override_in_ch_map = false;
2003
2004 pcm = pdata->pcm_device[fe_id];
2005 if (!pcm) {
2006 pr_err("%s invalid pcm handle for fe_id %llu\n",
2007 __func__, fe_id);
2008 return -EINVAL;
2009 }
2010
2011 if (session_type == SESSION_TYPE_RX)
2012 substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
2013 else
2014 substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
2015 if (!substream) {
2016 pr_err("%s substream not found\n", __func__);
2017 return -EINVAL;
2018 }
2019
2020 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2021 if (!chmixer_pspd) {
2022 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2023 return -EINVAL;
2024 }
2025
2026 chmixer_pspd->enable = ucontrol->value.integer.value[0];
2027 chmixer_pspd->rule = ucontrol->value.integer.value[1];
2028 chmixer_pspd->input_channel = ucontrol->value.integer.value[2];
2029 chmixer_pspd->output_channel = ucontrol->value.integer.value[3];
2030 chmixer_pspd->port_idx = ucontrol->value.integer.value[4];
2031
Erin Yan2f81be22019-04-29 13:42:57 +08002032 if (chmixer_pspd->input_channel < 0 ||
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302033 chmixer_pspd->input_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8 ||
Erin Yan2f81be22019-04-29 13:42:57 +08002034 chmixer_pspd->output_channel < 0 ||
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302035 chmixer_pspd->output_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2036 pr_err("%s: Invalid channels, in %d, out %d\n",
2037 __func__, chmixer_pspd->input_channel,
2038 chmixer_pspd->output_channel);
2039 return -EINVAL;
2040 }
2041
2042 prtd = substream->runtime ? substream->runtime->private_data : NULL;
2043 if (chmixer_pspd->enable && prtd) {
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302044 if (session_type == SESSION_TYPE_RX &&
2045 !chmixer_pspd->override_in_ch_map) {
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302046 if (prtd->set_channel_map) {
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302047 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302048 chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302049 } else {
2050 q6asm_map_channels(asm_ch_map,
2051 chmixer_pspd->input_channel, false);
2052 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2053 chmixer_pspd->in_ch_map[i] = asm_ch_map[i];
2054 }
2055 chmixer_pspd->override_in_ch_map = true;
2056 reset_override_in_ch_map = true;
2057 } else if (session_type == SESSION_TYPE_TX &&
2058 !chmixer_pspd->override_out_ch_map) {
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302059 /*
2060 * Channel map set in prtd is for plyback only,
2061 * hence always use default for capture path.
2062 */
2063 q6asm_map_channels(asm_ch_map,
2064 chmixer_pspd->output_channel, false);
2065 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2066 chmixer_pspd->out_ch_map[i] = asm_ch_map[i];
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302067 chmixer_pspd->override_out_ch_map = true;
2068 reset_override_out_ch_map = true;
2069 }
2070 } else {
2071 chmixer_pspd->override_out_ch_map = false;
2072 chmixer_pspd->override_in_ch_map = false;
2073 }
2074
2075 /* cache value and take effect during adm_open stage */
2076 msm_pcm_routing_set_channel_mixer_cfg(fe_id,
2077 session_type,
2078 chmixer_pspd);
2079
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05302080 if (chmixer_pspd->enable && prtd && prtd->audio_client) {
2081 stream_id = prtd->audio_client->session;
2082 be_id = chmixer_pspd->port_idx;
2083 msm_pcm_routing_set_channel_mixer_runtime(be_id,
2084 stream_id,
2085 session_type,
2086 chmixer_pspd);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302087 }
2088
2089 if (reset_override_out_ch_map)
2090 chmixer_pspd->override_out_ch_map = false;
2091 if (reset_override_in_ch_map)
2092 chmixer_pspd->override_in_ch_map = false;
2093
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302094 return ret;
2095}
2096
2097static int msm_pcm_channel_mixer_cfg_ctl_get(struct snd_kcontrol *kcontrol,
2098 struct snd_ctl_elem_value *ucontrol)
2099{
2100 u64 fe_id = kcontrol->private_value & 0xFF;
2101 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2102 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2103 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2104 struct msm_pcm_channel_mixer *chmixer_pspd;
2105
2106 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2107 if (!chmixer_pspd) {
2108 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2109 return -EINVAL;
2110 }
2111
2112 ucontrol->value.integer.value[0] = chmixer_pspd->enable;
2113 ucontrol->value.integer.value[1] = chmixer_pspd->rule;
2114 ucontrol->value.integer.value[2] = chmixer_pspd->input_channel;
2115 ucontrol->value.integer.value[3] = chmixer_pspd->output_channel;
2116 ucontrol->value.integer.value[4] = chmixer_pspd->port_idx;
2117 return 0;
2118}
2119
2120static int msm_pcm_channel_mixer_output_map_ctl_put(
2121 struct snd_kcontrol *kcontrol,
2122 struct snd_ctl_elem_value *ucontrol)
2123{
2124 u64 fe_id = kcontrol->private_value & 0xFF;
2125 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2126 int i = 0;
2127 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2128 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2129 struct msm_pcm_channel_mixer *chmixer_pspd;
2130
2131 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2132 if (!chmixer_pspd) {
2133 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2134 return -EINVAL;
2135 }
2136
2137 chmixer_pspd->override_out_ch_map = true;
2138 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2139 chmixer_pspd->out_ch_map[i] =
2140 ucontrol->value.integer.value[i];
2141
2142 return 0;
2143}
2144
2145static int msm_pcm_channel_mixer_output_map_ctl_get(
2146 struct snd_kcontrol *kcontrol,
2147 struct snd_ctl_elem_value *ucontrol)
2148{
2149 u64 fe_id = kcontrol->private_value & 0xFF;
2150 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2151 int i = 0;
2152 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2153 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2154 struct msm_pcm_channel_mixer *chmixer_pspd;
2155
2156 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2157 if (!chmixer_pspd) {
2158 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2159 return -EINVAL;
2160 }
2161
2162 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2163 ucontrol->value.integer.value[i] =
2164 chmixer_pspd->out_ch_map[i];
2165 return 0;
2166}
2167
2168static int msm_pcm_channel_mixer_input_map_ctl_put(
2169 struct snd_kcontrol *kcontrol,
2170 struct snd_ctl_elem_value *ucontrol)
2171{
2172 u64 fe_id = kcontrol->private_value & 0xFF;
2173 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2174 int i = 0;
2175 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2176 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2177 struct msm_pcm_channel_mixer *chmixer_pspd;
2178
2179 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2180 if (!chmixer_pspd) {
2181 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2182 return -EINVAL;
2183 }
2184
2185 chmixer_pspd->override_in_ch_map = true;
2186 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2187 chmixer_pspd->in_ch_map[i] = ucontrol->value.integer.value[i];
2188
2189 return 0;
2190}
2191
2192static int msm_pcm_channel_mixer_input_map_ctl_get(
2193 struct snd_kcontrol *kcontrol,
2194 struct snd_ctl_elem_value *ucontrol)
2195{
2196 u64 fe_id = kcontrol->private_value & 0xFF;
2197 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2198 int i = 0;
2199 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2200 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2201 struct msm_pcm_channel_mixer *chmixer_pspd;
2202
2203 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2204 if (!chmixer_pspd) {
2205 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2206 return -EINVAL;
2207 }
2208
2209 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2210 ucontrol->value.integer.value[i] =
2211 chmixer_pspd->in_ch_map[i];
2212 return 0;
2213}
2214
2215static int msm_pcm_channel_mixer_weight_ctl_put(
2216 struct snd_kcontrol *kcontrol,
2217 struct snd_ctl_elem_value *ucontrol)
2218{
2219 u64 fe_id = kcontrol->private_value & 0xFF;
2220 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2221 int channel = (kcontrol->private_value >> 16) & 0xFF;
2222 int i = 0;
2223 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2224 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2225 struct msm_pcm_channel_mixer *chmixer_pspd;
2226
2227 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2228 if (!chmixer_pspd) {
2229 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2230 return -EINVAL;
2231 }
2232
2233 if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2234 pr_err("%s: invalid channel number %d\n", __func__, channel);
2235 return -EINVAL;
2236 }
2237 channel--;
2238
2239 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2240 chmixer_pspd->channel_weight[channel][i] =
2241 ucontrol->value.integer.value[i];
2242 return 0;
2243}
2244
2245static int msm_pcm_channel_mixer_weight_ctl_get(
2246 struct snd_kcontrol *kcontrol,
2247 struct snd_ctl_elem_value *ucontrol)
2248{
2249 u64 fe_id = kcontrol->private_value & 0xFF;
2250 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2251 int channel = (kcontrol->private_value >> 16) & 0xFF;
2252 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2253 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2254 int i = 0;
2255 struct msm_pcm_channel_mixer *chmixer_pspd;
2256
2257 if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2258 pr_err("%s: invalid channel number %d\n", __func__, channel);
2259 return -EINVAL;
2260 }
2261 channel--;
2262
2263 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2264 if (!chmixer_pspd) {
2265 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2266 return -EINVAL;
2267 }
2268
2269 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2270 ucontrol->value.integer.value[i] =
2271 chmixer_pspd->channel_weight[channel][i];
2272 return 0;
2273}
2274
2275static int msm_pcm_add_platform_controls(struct snd_kcontrol_new *kctl,
2276 struct snd_soc_pcm_runtime *rtd, const char *name_prefix,
2277 const char *name_suffix, int session_type, int channels)
2278{
2279 int ret = -EINVAL;
2280 char *mixer_name = NULL;
2281 struct snd_pcm *pcm = rtd->pcm;
2282 const char *deviceNo = "NN";
2283 const char *channelNo = "NN";
2284 int ctl_len = 0;
2285 struct snd_soc_component *component = NULL;
2286
2287 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2288 if (!component) {
2289 pr_err("%s: component is NULL\n", __func__);
2290 return -EINVAL;
2291 }
2292
2293 ctl_len = strlen(name_prefix) + 1 + strlen(deviceNo) + 1 +
2294 strlen(channelNo) + 1 + strlen(name_suffix) + 1;
2295
2296 mixer_name = kzalloc(ctl_len, GFP_KERNEL);
2297 if (mixer_name == NULL)
2298 return -ENOMEM;
2299
2300 if (channels >= 0) {
2301 snprintf(mixer_name, ctl_len, "%s %d %s %d",
2302 name_prefix, pcm->device, name_suffix, channels);
2303 kctl->private_value = (rtd->dai_link->id) | (session_type << 8) |
2304 (channels << 16);
2305 } else {
2306 snprintf(mixer_name, ctl_len, "%s %d %s",
2307 name_prefix, pcm->device, name_suffix);
2308 kctl->private_value = (rtd->dai_link->id) | (session_type << 8);
2309 }
2310
2311 kctl->name = mixer_name;
2312 ret = snd_soc_add_component_controls(component, kctl, 1);
2313 kfree(mixer_name);
2314 return ret;
2315}
2316
2317static int msm_pcm_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
2318 struct snd_ctl_elem_info *uinfo)
2319{
2320 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2321 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2322 /* Valid channel map value ranges from 1 to 64 */
2323 uinfo->value.integer.min = 1;
2324 uinfo->value.integer.max = 64;
2325 return 0;
2326}
2327
2328static int msm_pcm_add_channel_mixer_output_map_controls(
2329 struct snd_soc_pcm_runtime *rtd)
2330{
2331 struct snd_pcm *pcm = rtd->pcm;
2332 const char *playback_mixer_ctl_name = "AudStr";
2333 const char *capture_mixer_ctl_name = "AudStr Capture";
2334 const char *suffix = "ChMixer Output Map";
2335 int session_type = 0, ret = 0, channel = -1;
2336 struct snd_kcontrol_new channel_mixer_output_map_control = {
2337 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2338 .name = "?",
2339 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2340 .info = msm_pcm_channel_mixer_output_map_info,
2341 .put = msm_pcm_channel_mixer_output_map_ctl_put,
2342 .get = msm_pcm_channel_mixer_output_map_ctl_get,
2343 .private_value = 0,
2344 };
2345
2346 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2347 session_type = SESSION_TYPE_RX;
2348 ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
2349 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2350 if (ret < 0)
2351 goto fail;
2352 }
2353
2354 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2355 session_type = SESSION_TYPE_TX;
2356 ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
2357 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2358 if (ret < 0)
2359 goto fail;
2360 }
2361 return 0;
2362
2363fail:
2364 pr_err("%s: failed add platform ctl, err = %d\n",
2365 __func__, ret);
2366 return ret;
2367}
2368
2369static int msm_pcm_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
2370 struct snd_ctl_elem_info *uinfo)
2371{
2372 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2373 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2374 /* Valid channel map value ranges from 1 to 64 */
2375 uinfo->value.integer.min = 1;
2376 uinfo->value.integer.max = 64;
2377 return 0;
2378}
2379
2380static int msm_pcm_add_channel_mixer_input_map_controls(
2381 struct snd_soc_pcm_runtime *rtd)
2382{
2383 struct snd_pcm *pcm = rtd->pcm;
2384 const char *playback_mixer_ctl_name = "AudStr";
2385 const char *capture_mixer_ctl_name = "AudStr Capture";
2386 const char *suffix = "ChMixer Input Map";
2387 int session_type = 0, ret = 0, channel = -1;
2388 struct snd_kcontrol_new channel_mixer_input_map_control = {
2389 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2390 .name = "?",
2391 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2392 .info = msm_pcm_channel_mixer_input_map_info,
2393 .put = msm_pcm_channel_mixer_input_map_ctl_put,
2394 .get = msm_pcm_channel_mixer_input_map_ctl_get,
2395 .private_value = 0,
2396 };
2397
2398 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2399 session_type = SESSION_TYPE_RX;
2400 ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
2401 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2402 if (ret < 0)
2403 goto fail;
2404 }
2405
2406 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2407 session_type = SESSION_TYPE_TX;
2408 ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
2409 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2410 if (ret < 0)
2411 goto fail;
2412 }
2413 return 0;
2414
2415fail:
2416 pr_err("%s: failed add platform ctl, err = %d\n",
2417 __func__, ret);
2418
2419 return ret;
2420}
2421
2422static int msm_pcm_channel_mixer_cfg_info(struct snd_kcontrol *kcontrol,
2423 struct snd_ctl_elem_info *uinfo)
2424{
2425 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2426 /* five int values: enable, rule, in_channels, out_channels and port_id */
2427 uinfo->count = 5;
2428 /* Valid range is all positive values to support above controls */
2429 uinfo->value.integer.min = 0;
2430 uinfo->value.integer.max = INT_MAX;
2431 return 0;
2432}
2433
2434static int msm_pcm_add_channel_mixer_cfg_controls(
2435 struct snd_soc_pcm_runtime *rtd)
2436{
2437 struct snd_pcm *pcm = rtd->pcm;
2438 const char *playback_mixer_ctl_name = "AudStr";
2439 const char *capture_mixer_ctl_name = "AudStr Capture";
2440 const char *suffix = "ChMixer Cfg";
2441 int session_type = 0, ret = 0, channel = -1;
2442 struct msm_plat_data *pdata = NULL;
2443 struct snd_soc_component *component = NULL;
2444 struct snd_kcontrol_new channel_mixer_cfg_control = {
2445 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2446 .name = "?",
2447 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2448 .info = msm_pcm_channel_mixer_cfg_info,
2449 .put = msm_pcm_channel_mixer_cfg_ctl_put,
2450 .get = msm_pcm_channel_mixer_cfg_ctl_get,
2451 .private_value = 0,
2452 };
2453
2454 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2455 if (!component) {
2456 pr_err("%s: component is NULL\n", __func__);
2457 return -EINVAL;
2458 }
2459
2460 pdata = (struct msm_plat_data *)
2461 dev_get_drvdata(component->dev);
2462
2463 pdata->pcm_device[rtd->dai_link->id] = rtd->pcm;
2464
2465 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2466 session_type = SESSION_TYPE_RX;
2467 ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
2468 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2469 if (ret < 0)
2470 goto fail;
2471 }
2472
2473 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2474 session_type = SESSION_TYPE_TX;
2475 ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
2476 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2477 if (ret < 0)
2478 goto fail;
2479 }
2480 return 0;
2481
2482fail:
2483 pr_err("%s: failed add platform ctl, err = %d\n",
2484 __func__, ret);
2485
2486 return ret;
2487}
2488
2489static int msm_pcm_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
2490 struct snd_ctl_elem_info *uinfo)
2491{
2492 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2493 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2494 /* Valid range: 0 to 0x4000(Unity) gain weightage */
2495 uinfo->value.integer.min = 0;
2496 uinfo->value.integer.max = 0x4000;
2497 return 0;
2498}
2499
2500static int msm_pcm_add_channel_mixer_weight_controls(
2501 struct snd_soc_pcm_runtime *rtd,
2502 int channel)
2503{
2504 struct snd_pcm *pcm = rtd->pcm;
2505 const char *playback_mixer_ctl_name = "AudStr";
2506 const char *capture_mixer_ctl_name = "AudStr Capture";
2507 const char *suffix = "ChMixer Weight Ch";
2508 int session_type = 0, ret = 0;
2509 struct snd_kcontrol_new channel_mixer_weight_control = {
2510 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2511 .name = "?",
2512 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2513 .info = msm_pcm_channel_mixer_weight_info,
2514 .put = msm_pcm_channel_mixer_weight_ctl_put,
2515 .get = msm_pcm_channel_mixer_weight_ctl_get,
2516 .private_value = 0,
2517 };
2518
2519 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2520 session_type = SESSION_TYPE_RX;
2521 ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
2522 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2523 if (ret < 0)
2524 goto fail;
2525 }
2526
2527 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2528 session_type = SESSION_TYPE_TX;
2529 ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
2530 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2531 if (ret < 0)
2532 goto fail;
2533 }
2534 return 0;
2535
2536fail:
2537 pr_err("%s: failed add platform ctl, err = %d\n",
2538 __func__, ret);
2539
2540 return ret;
2541}
2542
2543static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
2544{
2545 int i, ret = 0;
2546 struct snd_pcm *pcm = NULL;
2547 struct msm_plat_data *pdata = NULL;
2548 struct snd_soc_component *component = NULL;
2549
2550 if (!rtd || !rtd->pcm) {
2551 pr_err("%s invalid rtd or pcm\n", __func__);
2552 return -EINVAL;
2553 }
2554 pcm = rtd->pcm;
2555
2556 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2557 if (!component) {
2558 pr_err("%s: component is NULL\n", __func__);
2559 return -EINVAL;
2560 }
2561
2562 pdata = (struct msm_plat_data *)
2563 dev_get_drvdata(component->dev);
2564 if (!pdata) {
2565 pr_err("%s: platform data not populated\n", __func__);
2566 return -EINVAL;
2567 }
2568
2569 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream &&
2570 !pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
2571 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] =
2572 kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
2573 if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
2574 ret = -ENOMEM;
2575 goto fail;
2576 }
2577 }
2578
2579 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream &&
2580 !pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
2581 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] =
2582 kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
2583 if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
2584 ret = -ENOMEM;
2585 goto fail;
2586 }
2587 }
2588
2589 ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
2590 if (ret) {
2591 pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
2592 __func__, ret);
2593 goto fail;
2594 }
2595 ret = msm_pcm_add_channel_mixer_input_map_controls(rtd);
2596 if (ret) {
2597 pr_err("%s: pcm add channel mixer input map controls failed:%d\n",
2598 __func__, ret);
2599 goto fail;
2600 }
2601 ret = msm_pcm_add_channel_mixer_output_map_controls(rtd);
2602 if (ret) {
2603 pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
2604 __func__, ret);
2605 goto fail;
2606 }
2607
2608 for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
2609 ret = msm_pcm_add_channel_mixer_weight_controls(rtd, i);
2610 if (ret) {
2611 pr_err("%s: pcm add channel mixer weight controls failed:%d\n",
2612 __func__, ret);
2613 goto fail;
2614 }
2615 }
2616 return 0;
2617
2618fail:
2619 kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]);
2620 kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]);
2621 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] = NULL;
2622 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] = NULL;
2623
2624 return ret;
2625}
2626
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302627static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
2628{
2629 int ret = 0;
2630
2631 pr_debug("%s\n", __func__);
2632 ret = msm_pcm_add_chmap_controls(rtd);
2633 if (ret)
2634 pr_err("%s: pcm add controls failed:%d\n", __func__, ret);
2635 ret = msm_pcm_add_app_type_controls(rtd);
2636 if (ret)
2637 pr_err("%s: pcm add app type controls failed:%d\n",
2638 __func__, ret);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302639 ret = msm_pcm_add_channel_mixer_controls(rtd);
2640 if (ret)
2641 pr_err("%s: pcm add channel mixer controls failed:%d\n",
2642 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302643 return ret;
2644}
2645
2646static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
2647{
2648 struct snd_card *card = rtd->card->snd_card;
2649 int ret = 0;
2650
2651 if (!card->dev->coherent_dma_mask)
2652 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
2653
2654 ret = msm_pcm_add_controls(rtd);
2655 if (ret) {
2656 pr_err("%s, kctl add failed:%d\n", __func__, ret);
2657 return ret;
2658 }
2659
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07002660 ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_PLAYBACK);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302661 if (ret)
2662 pr_err("%s: Could not add pcm Volume Control %d\n",
2663 __func__, ret);
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07002664 ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_CAPTURE);
2665 if (ret)
2666 pr_err("%s: Could not add pcm Volume Control %d\n",
2667 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302668 ret = msm_pcm_add_compress_control(rtd);
2669 if (ret)
2670 pr_err("%s: Could not add pcm Compress Control %d\n",
2671 __func__, ret);
2672
2673 ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
2674 if (ret)
2675 pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
2676 __func__);
2677
2678 ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
2679 if (ret)
2680 pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
2681 __func__);
2682
2683 return ret;
2684}
2685
2686static snd_pcm_sframes_t msm_pcm_delay_blk(struct snd_pcm_substream *substream,
2687 struct snd_soc_dai *dai)
2688{
2689 struct snd_pcm_runtime *runtime = substream->runtime;
2690 struct msm_audio *prtd = runtime->private_data;
2691 struct audio_client *ac = prtd->audio_client;
2692 snd_pcm_sframes_t frames;
2693 int ret;
2694
2695 ret = q6asm_get_path_delay(prtd->audio_client);
2696 if (ret) {
2697 pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
2698 return 0;
2699 }
2700
2701 /* convert microseconds to frames */
2702 frames = ac->path_delay / 1000 * runtime->rate / 1000;
2703
2704 /* also convert the remainder from the initial division */
2705 frames += ac->path_delay % 1000 * runtime->rate / 1000000;
2706
2707 /* overcompensate for the loss of precision (empirical) */
2708 frames += 2;
2709
2710 return frames;
2711}
2712
Meng Wangee084a02018-09-04 16:11:58 +08002713static struct snd_soc_component_driver msm_soc_component = {
2714 .name = DRV_NAME,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302715 .ops = &msm_pcm_ops,
2716 .pcm_new = msm_asoc_pcm_new,
2717 .delay_blk = msm_pcm_delay_blk,
2718};
2719
2720static int msm_pcm_probe(struct platform_device *pdev)
2721{
2722 int rc;
2723 int id;
2724 struct msm_plat_data *pdata;
2725 const char *latency_level;
2726
2727 rc = of_property_read_u32(pdev->dev.of_node,
2728 "qcom,msm-pcm-dsp-id", &id);
2729 if (rc) {
2730 dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
2731 __func__);
2732 return rc;
2733 }
2734
2735 pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
2736 if (!pdata)
2737 return -ENOMEM;
2738
2739 if (of_property_read_bool(pdev->dev.of_node,
2740 "qcom,msm-pcm-low-latency")) {
2741
2742 pdata->perf_mode = LOW_LATENCY_PCM_MODE;
2743 rc = of_property_read_string(pdev->dev.of_node,
2744 "qcom,latency-level", &latency_level);
2745 if (!rc) {
2746 if (!strcmp(latency_level, "ultra"))
2747 pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
2748 else if (!strcmp(latency_level, "ull-pp"))
2749 pdata->perf_mode =
2750 ULL_POST_PROCESSING_PCM_MODE;
2751 }
2752 } else {
2753 pdata->perf_mode = LEGACY_PCM_MODE;
2754 }
2755
2756 dev_set_drvdata(&pdev->dev, pdata);
2757
2758
2759 dev_dbg(&pdev->dev, "%s: dev name %s\n",
2760 __func__, dev_name(&pdev->dev));
Meng Wangee084a02018-09-04 16:11:58 +08002761 return snd_soc_register_component(&pdev->dev,
2762 &msm_soc_component,
2763 NULL, 0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302764}
2765
2766static int msm_pcm_remove(struct platform_device *pdev)
2767{
2768 struct msm_plat_data *pdata;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302769 int i = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302770
2771 pdata = dev_get_drvdata(&pdev->dev);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302772 if (pdata) {
2773 for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++) {
2774 kfree(pdata->chmixer_pspd[i][SESSION_TYPE_RX]);
2775 kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
2776 }
2777 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302778 kfree(pdata);
Meng Wangee084a02018-09-04 16:11:58 +08002779 snd_soc_unregister_component(&pdev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302780 return 0;
2781}
2782static const struct of_device_id msm_pcm_dt_match[] = {
2783 {.compatible = "qcom,msm-pcm-dsp"},
2784 {}
2785};
2786MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
2787
2788static struct platform_driver msm_pcm_driver = {
2789 .driver = {
2790 .name = "msm-pcm-dsp",
2791 .owner = THIS_MODULE,
2792 .of_match_table = msm_pcm_dt_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +08002793 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302794 },
2795 .probe = msm_pcm_probe,
2796 .remove = msm_pcm_remove,
2797};
2798
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302799int __init msm_pcm_dsp_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302800{
2801 init_waitqueue_head(&the_locks.enable_wait);
2802 init_waitqueue_head(&the_locks.eos_wait);
2803 init_waitqueue_head(&the_locks.write_wait);
2804 init_waitqueue_head(&the_locks.read_wait);
2805
2806 return platform_driver_register(&msm_pcm_driver);
2807}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302808
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05302809void msm_pcm_dsp_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302810{
2811 platform_driver_unregister(&msm_pcm_driver);
2812}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302813
2814MODULE_DESCRIPTION("PCM module platform driver");
2815MODULE_LICENSE("GPL v2");