blob: 322bf661e171e73eb00fc560739a23574961a1ea [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>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053028#include <dsp/msm_audio_ion.h>
29#include <dsp/q6audio-v2.h>
Dieter Luecking70668fc2018-09-28 15:03:01 +020030#include <dsp/q6core.h>
31#include <dsp/q6asm-v2.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053032
33#include "msm-pcm-q6-v2.h"
34#include "msm-pcm-routing-v2.h"
35#include "msm-qti-pp-config.h"
36
Meng Wangee084a02018-09-04 16:11:58 +080037#define DRV_NAME "msm-pcm-q6-v2"
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -070038#define TIMEOUT_MS 1000
Meng Wangee084a02018-09-04 16:11:58 +080039
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053040enum stream_state {
41 IDLE = 0,
42 STOPPED,
43 RUNNING,
44};
45
46static struct audio_locks the_locks;
47
48#define PCM_MASTER_VOL_MAX_STEPS 0x2000
49static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
50 PCM_MASTER_VOL_MAX_STEPS);
51
52struct snd_msm {
53 struct snd_card *card;
54 struct snd_pcm *pcm;
55};
56
57#define CMD_EOS_MIN_TIMEOUT_LENGTH 50
58#define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50)
59#define MAX_PB_COPY_RETRIES 3
60
61static struct snd_pcm_hardware msm_pcm_hardware_capture = {
62 .info = (SNDRV_PCM_INFO_MMAP |
63 SNDRV_PCM_INFO_BLOCK_TRANSFER |
64 SNDRV_PCM_INFO_MMAP_VALID |
65 SNDRV_PCM_INFO_INTERLEAVED |
66 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
67 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
68 SNDRV_PCM_FMTBIT_S24_LE |
69 SNDRV_PCM_FMTBIT_S24_3LE |
70 SNDRV_PCM_FMTBIT_S32_LE),
71 .rates = SNDRV_PCM_RATE_8000_384000,
72 .rate_min = 8000,
73 .rate_max = 384000,
74 .channels_min = 1,
75 .channels_max = 4,
76 .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
77 CAPTURE_MAX_PERIOD_SIZE,
78 .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
79 .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
80 .periods_min = CAPTURE_MIN_NUM_PERIODS,
81 .periods_max = CAPTURE_MAX_NUM_PERIODS,
82 .fifo_size = 0,
83};
84
85static struct snd_pcm_hardware msm_pcm_hardware_playback = {
86 .info = (SNDRV_PCM_INFO_MMAP |
87 SNDRV_PCM_INFO_BLOCK_TRANSFER |
88 SNDRV_PCM_INFO_MMAP_VALID |
89 SNDRV_PCM_INFO_INTERLEAVED |
90 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
91 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
92 SNDRV_PCM_FMTBIT_S24_LE |
93 SNDRV_PCM_FMTBIT_S24_3LE |
94 SNDRV_PCM_FMTBIT_S32_LE),
95 .rates = SNDRV_PCM_RATE_8000_384000,
96 .rate_min = 8000,
97 .rate_max = 384000,
98 .channels_min = 1,
99 .channels_max = 8,
100 .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS *
101 PLAYBACK_MAX_PERIOD_SIZE,
102 .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
103 .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
104 .periods_min = PLAYBACK_MIN_NUM_PERIODS,
105 .periods_max = PLAYBACK_MAX_NUM_PERIODS,
106 .fifo_size = 0,
107};
108
109/* Conventional and unconventional sample rate supported */
110static unsigned int supported_sample_rates[] = {
111 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
112 88200, 96000, 176400, 192000, 352800, 384000
113};
114
115static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
116 .count = ARRAY_SIZE(supported_sample_rates),
117 .list = supported_sample_rates,
118 .mask = 0,
119};
120
121static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
122 void *priv_data)
123{
124 struct msm_audio *prtd = priv_data;
125
126 WARN_ON(!prtd);
127
128 pr_debug("%s: event %x\n", __func__, event);
129
130 switch (event) {
131 case MSM_PCM_RT_EVT_BUF_RECFG:
132 q6asm_cmd(prtd->audio_client, CMD_PAUSE);
133 q6asm_cmd(prtd->audio_client, CMD_FLUSH);
134 q6asm_run(prtd->audio_client, 0, 0, 0);
135 /* fallthrough */
136 default:
137 break;
138 }
139}
140
141static void event_handler(uint32_t opcode,
142 uint32_t token, uint32_t *payload, void *priv)
143{
144 struct msm_audio *prtd = priv;
145 struct snd_pcm_substream *substream = prtd->substream;
146 uint32_t *ptrmem = (uint32_t *)payload;
147 uint32_t idx = 0;
148 uint32_t size = 0;
149 uint8_t buf_index;
150 struct snd_soc_pcm_runtime *rtd;
151 int ret = 0;
152
153 switch (opcode) {
154 case ASM_DATA_EVENT_WRITE_DONE_V2: {
155 pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
156 pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
157 prtd->pcm_irq_pos += prtd->pcm_count;
158 if (atomic_read(&prtd->start))
159 snd_pcm_period_elapsed(substream);
160 atomic_inc(&prtd->out_count);
161 wake_up(&the_locks.write_wait);
162 if (!atomic_read(&prtd->start))
163 break;
164 if (!prtd->mmap_flag || prtd->reset_event)
165 break;
166 if (q6asm_is_cpu_buf_avail_nolock(IN,
167 prtd->audio_client,
168 &size, &idx)) {
169 pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
170 __func__, prtd->pcm_count);
171 q6asm_write_nolock(prtd->audio_client,
172 prtd->pcm_count, 0, 0, NO_TIMESTAMP);
173 }
174 break;
175 }
176 case ASM_DATA_EVENT_RENDERED_EOS:
177 pr_debug("ASM_DATA_EVENT_RENDERED_EOS\n");
178 clear_bit(CMD_EOS, &prtd->cmd_pending);
179 wake_up(&the_locks.eos_wait);
180 break;
181 case ASM_DATA_EVENT_READ_DONE_V2: {
182 pr_debug("ASM_DATA_EVENT_READ_DONE_V2\n");
183 buf_index = q6asm_get_buf_index_from_token(token);
Vignesh Kulothungan3817b182017-12-04 15:56:05 -0800184 if (buf_index >= CAPTURE_MAX_NUM_PERIODS) {
185 pr_err("%s: buffer index %u is out of range.\n",
186 __func__, buf_index);
187 return;
188 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530189 pr_debug("%s: token=0x%08x buf_index=0x%08x\n",
190 __func__, token, buf_index);
191 prtd->in_frame_info[buf_index].size = payload[4];
192 prtd->in_frame_info[buf_index].offset = payload[5];
193 /* assume data size = 0 during flushing */
194 if (prtd->in_frame_info[buf_index].size) {
195 prtd->pcm_irq_pos +=
196 prtd->in_frame_info[buf_index].size;
197 pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
198 if (atomic_read(&prtd->start))
199 snd_pcm_period_elapsed(substream);
200 if (atomic_read(&prtd->in_count) <= prtd->periods)
201 atomic_inc(&prtd->in_count);
202 wake_up(&the_locks.read_wait);
203 if (prtd->mmap_flag &&
204 q6asm_is_cpu_buf_avail_nolock(OUT,
205 prtd->audio_client,
206 &size, &idx) &&
207 (substream->runtime->status->state ==
208 SNDRV_PCM_STATE_RUNNING))
209 q6asm_read_nolock(prtd->audio_client);
210 } else {
211 pr_debug("%s: reclaim flushed buf in_count %x\n",
212 __func__, atomic_read(&prtd->in_count));
213 prtd->pcm_irq_pos += prtd->pcm_count;
214 if (prtd->mmap_flag) {
215 if (q6asm_is_cpu_buf_avail_nolock(OUT,
216 prtd->audio_client,
217 &size, &idx) &&
218 (substream->runtime->status->state ==
219 SNDRV_PCM_STATE_RUNNING))
220 q6asm_read_nolock(prtd->audio_client);
221 } else {
222 atomic_inc(&prtd->in_count);
223 }
224 if (atomic_read(&prtd->in_count) == prtd->periods) {
225 pr_info("%s: reclaimed all bufs\n", __func__);
226 if (atomic_read(&prtd->start))
227 snd_pcm_period_elapsed(substream);
228 wake_up(&the_locks.read_wait);
229 }
230 }
231 break;
232 }
233 case ASM_STREAM_PP_EVENT:
234 case ASM_STREAM_CMD_ENCDEC_EVENTS: {
235 pr_debug("%s: ASM_STREAM_EVENT (0x%x)\n", __func__, opcode);
236 if (!substream) {
237 pr_err("%s: substream is NULL.\n", __func__);
238 return;
239 }
240
241 rtd = substream->private_data;
242 if (!rtd) {
243 pr_err("%s: rtd is NULL\n", __func__);
244 return;
245 }
246
247 ret = msm_adsp_inform_mixer_ctl(rtd, payload);
248 if (ret) {
249 pr_err("%s: failed to inform mixer ctl. err = %d\n",
250 __func__, ret);
251 return;
252 }
253
254 break;
255 }
256 case APR_BASIC_RSP_RESULT: {
257 switch (payload[0]) {
258 case ASM_SESSION_CMD_RUN_V2:
259 if (substream->stream
260 != SNDRV_PCM_STREAM_PLAYBACK) {
261 atomic_set(&prtd->start, 1);
262 break;
263 }
264 if (prtd->mmap_flag) {
265 pr_debug("%s:writing %d bytes of buffer to dsp\n",
266 __func__,
267 prtd->pcm_count);
268 q6asm_write_nolock(prtd->audio_client,
269 prtd->pcm_count,
270 0, 0, NO_TIMESTAMP);
271 } else {
272 while (atomic_read(&prtd->out_needed)) {
273 pr_debug("%s:writing %d bytes of buffer to dsp\n",
274 __func__,
275 prtd->pcm_count);
276 q6asm_write_nolock(prtd->audio_client,
277 prtd->pcm_count,
278 0, 0, NO_TIMESTAMP);
279 atomic_dec(&prtd->out_needed);
280 wake_up(&the_locks.write_wait);
281 };
282 }
283 atomic_set(&prtd->start, 1);
284 break;
285 case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
286 pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
287 __func__);
288 break;
289 default:
290 pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
291 __func__, payload[0], payload[1]);
292 break;
293 }
294 }
295 break;
296 case RESET_EVENTS:
297 pr_debug("%s RESET_EVENTS\n", __func__);
298 prtd->pcm_irq_pos += prtd->pcm_count;
299 atomic_inc(&prtd->out_count);
300 atomic_inc(&prtd->in_count);
301 prtd->reset_event = true;
302 if (atomic_read(&prtd->start))
303 snd_pcm_period_elapsed(substream);
304 wake_up(&the_locks.eos_wait);
305 wake_up(&the_locks.write_wait);
306 wake_up(&the_locks.read_wait);
307 break;
308 default:
309 pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
310 break;
311 }
312}
313
314static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
315{
316 struct snd_pcm_runtime *runtime = substream->runtime;
317 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800318 struct snd_soc_component *component =
319 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530320 struct msm_audio *prtd = runtime->private_data;
321 struct msm_plat_data *pdata;
322 struct snd_pcm_hw_params *params;
323 int ret;
324 uint32_t fmt_type = FORMAT_LINEAR_PCM;
325 uint16_t bits_per_sample;
326 uint16_t sample_word_size;
327
Meng Wangee084a02018-09-04 16:11:58 +0800328 if (!component) {
329 pr_err("%s: component is NULL\n", __func__);
330 return -EINVAL;
331 }
332
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530333 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800334 dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530335 if (!pdata) {
336 pr_err("%s: platform data not populated\n", __func__);
337 return -EINVAL;
338 }
339 if (!prtd || !prtd->audio_client) {
340 pr_err("%s: private data null or audio client freed\n",
341 __func__);
342 return -EINVAL;
343 }
344 params = &soc_prtd->dpcm[substream->stream].hw_params;
345
346 pr_debug("%s\n", __func__);
347 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
348 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
349 prtd->pcm_irq_pos = 0;
350 /* rate and channels are sent to audio driver */
351 prtd->samp_rate = runtime->rate;
352 prtd->channel_mode = runtime->channels;
353 if (prtd->enabled)
354 return 0;
355
356 prtd->audio_client->perf_mode = pdata->perf_mode;
357 pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode);
358
359 switch (params_format(params)) {
360 case SNDRV_PCM_FORMAT_S32_LE:
361 bits_per_sample = 32;
362 sample_word_size = 32;
363 break;
364 case SNDRV_PCM_FORMAT_S24_LE:
365 bits_per_sample = 24;
366 sample_word_size = 32;
367 break;
368 case SNDRV_PCM_FORMAT_S24_3LE:
369 bits_per_sample = 24;
370 sample_word_size = 24;
371 break;
372 case SNDRV_PCM_FORMAT_S16_LE:
373 default:
374 bits_per_sample = 16;
375 sample_word_size = 16;
376 break;
377 }
378 if (prtd->compress_enable) {
379 fmt_type = FORMAT_GEN_COMPR;
380 pr_debug("%s: Compressed enabled!\n", __func__);
381 ret = q6asm_open_write_compressed(prtd->audio_client, fmt_type,
382 COMPRESSED_PASSTHROUGH_GEN);
383 if (ret < 0) {
384 pr_err("%s: q6asm_open_write_compressed failed (%d)\n",
385 __func__, ret);
386 q6asm_audio_client_free(prtd->audio_client);
387 prtd->audio_client = NULL;
388 return -ENOMEM;
389 }
390 } else {
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530391 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200392 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530393 ADSP_ASM_API_VERSION_V2) &&
394 q6core_use_Q6_32ch_support())
Dieter Luecking70668fc2018-09-28 15:03:01 +0200395 ret = q6asm_open_write_v5(prtd->audio_client,
396 fmt_type, bits_per_sample);
397 else
398 ret = q6asm_open_write_v4(prtd->audio_client,
399 fmt_type, bits_per_sample);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530400
401 if (ret < 0) {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200402 pr_err("%s: q6asm_open_write failed (%d)\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530403 __func__, ret);
404 q6asm_audio_client_free(prtd->audio_client);
405 prtd->audio_client = NULL;
406 return -ENOMEM;
407 }
408
409 ret = q6asm_send_cal(prtd->audio_client);
410 if (ret < 0)
411 pr_debug("%s : Send cal failed : %d", __func__, ret);
412 }
413 pr_debug("%s: session ID %d\n", __func__,
414 prtd->audio_client->session);
415 prtd->session_id = prtd->audio_client->session;
416
417 if (prtd->compress_enable) {
418 ret = msm_pcm_routing_reg_phy_compr_stream(
419 soc_prtd->dai_link->id,
420 prtd->audio_client->perf_mode,
421 prtd->session_id,
422 SNDRV_PCM_STREAM_PLAYBACK,
423 COMPRESSED_PASSTHROUGH_GEN);
424 } else {
425 ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id,
426 prtd->audio_client->perf_mode,
427 prtd->session_id, substream->stream);
428 }
429 if (ret) {
430 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
431 return ret;
432 }
433 if (prtd->compress_enable) {
434 ret = q6asm_media_format_block_gen_compr(
435 prtd->audio_client, runtime->rate,
436 runtime->channels, !prtd->set_channel_map,
437 prtd->channel_map, bits_per_sample);
438 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200439
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530440 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200441 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530442 ADSP_ASM_API_VERSION_V2) &&
443 q6core_use_Q6_32ch_support()) {
Dieter Luecking70668fc2018-09-28 15:03:01 +0200444
445 ret = q6asm_media_format_block_multi_ch_pcm_v5(
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530446 prtd->audio_client, runtime->rate,
447 runtime->channels, !prtd->set_channel_map,
448 prtd->channel_map, bits_per_sample,
449 sample_word_size, ASM_LITTLE_ENDIAN,
450 DEFAULT_QF);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200451 } else {
452 ret = q6asm_media_format_block_multi_ch_pcm_v4(
453 prtd->audio_client, runtime->rate,
454 runtime->channels, !prtd->set_channel_map,
455 prtd->channel_map, bits_per_sample,
456 sample_word_size, ASM_LITTLE_ENDIAN,
457 DEFAULT_QF);
458 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530459 }
460 if (ret < 0)
461 pr_info("%s: CMD Format block failed\n", __func__);
462
463 atomic_set(&prtd->out_count, runtime->periods);
464
465 prtd->enabled = 1;
466 prtd->cmd_pending = 0;
467 prtd->cmd_interrupt = 0;
468
469 return 0;
470}
471
472static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
473{
474 struct snd_pcm_runtime *runtime = substream->runtime;
475 struct msm_audio *prtd = runtime->private_data;
476 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800477 struct snd_soc_component *component =
478 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530479 struct msm_plat_data *pdata;
480 struct snd_pcm_hw_params *params;
481 struct msm_pcm_routing_evt event;
482 int ret = 0;
483 int i = 0;
484 uint16_t bits_per_sample = 16;
485 uint16_t sample_word_size;
486
Meng Wangee084a02018-09-04 16:11:58 +0800487 if (!component) {
488 pr_err("%s: component is NULL\n", __func__);
489 return -EINVAL;
490 }
491
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530492 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800493 dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530494 if (!pdata) {
495 pr_err("%s: platform data not populated\n", __func__);
496 return -EINVAL;
497 }
498 if (!prtd || !prtd->audio_client) {
499 pr_err("%s: private data null or audio client freed\n",
500 __func__);
501 return -EINVAL;
502 }
503
504 if (prtd->enabled == IDLE) {
505 pr_debug("%s:perf_mode=%d periods=%d\n", __func__,
506 pdata->perf_mode, runtime->periods);
507 params = &soc_prtd->dpcm[substream->stream].hw_params;
508 if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) ||
509 (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE))
510 bits_per_sample = 24;
511 else if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
512 bits_per_sample = 32;
513
514 /* ULL mode is not supported in capture path */
515 if (pdata->perf_mode == LEGACY_PCM_MODE)
516 prtd->audio_client->perf_mode = LEGACY_PCM_MODE;
517 else
518 prtd->audio_client->perf_mode = LOW_LATENCY_PCM_MODE;
519
520 pr_debug("%s Opening %d-ch PCM read stream, perf_mode %d\n",
521 __func__, params_channels(params),
522 prtd->audio_client->perf_mode);
523
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530524 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200525 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530526 ADSP_ASM_API_VERSION_V2) &&
527 q6core_use_Q6_32ch_support())
Dieter Luecking70668fc2018-09-28 15:03:01 +0200528 ret = q6asm_open_read_v5(prtd->audio_client,
529 FORMAT_LINEAR_PCM,
530 bits_per_sample, false, ENC_CFG_ID_NONE);
531 else
532 ret = q6asm_open_read_v4(prtd->audio_client,
533 FORMAT_LINEAR_PCM,
Vikram Pandurangac712c172017-11-17 17:36:49 -0800534 bits_per_sample, false, ENC_CFG_ID_NONE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530535 if (ret < 0) {
536 pr_err("%s: q6asm_open_read failed\n", __func__);
537 q6asm_audio_client_free(prtd->audio_client);
538 prtd->audio_client = NULL;
539 return -ENOMEM;
540 }
541
542 ret = q6asm_send_cal(prtd->audio_client);
543 if (ret < 0)
544 pr_debug("%s : Send cal failed : %d", __func__, ret);
545
546 pr_debug("%s: session ID %d\n",
547 __func__, prtd->audio_client->session);
548 prtd->session_id = prtd->audio_client->session;
549 event.event_func = msm_pcm_route_event_handler;
550 event.priv_data = (void *) prtd;
551 ret = msm_pcm_routing_reg_phy_stream_v2(
552 soc_prtd->dai_link->id,
553 prtd->audio_client->perf_mode,
554 prtd->session_id, substream->stream,
555 event);
556 if (ret) {
557 pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
558 return ret;
559 }
560 }
561
562 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
563 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
564 prtd->pcm_irq_pos = 0;
565 /* rate and channels are sent to audio driver */
566 prtd->samp_rate = runtime->rate;
567 prtd->channel_mode = runtime->channels;
568
569 if (prtd->enabled == IDLE || prtd->enabled == STOPPED) {
570 for (i = 0; i < runtime->periods; i++)
571 q6asm_read(prtd->audio_client);
572 prtd->periods = runtime->periods;
573 }
574
575 if (prtd->enabled != IDLE)
576 return 0;
577
578 switch (runtime->format) {
579 case SNDRV_PCM_FORMAT_S32_LE:
580 bits_per_sample = 32;
581 sample_word_size = 32;
582 break;
583 case SNDRV_PCM_FORMAT_S24_LE:
584 bits_per_sample = 24;
585 sample_word_size = 32;
586 break;
587 case SNDRV_PCM_FORMAT_S24_3LE:
588 bits_per_sample = 24;
589 sample_word_size = 24;
590 break;
591 case SNDRV_PCM_FORMAT_S16_LE:
592 default:
593 bits_per_sample = 16;
594 sample_word_size = 16;
595 break;
596 }
597
598 pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n",
599 __func__, prtd->samp_rate, prtd->channel_mode,
600 bits_per_sample, sample_word_size);
Dieter Luecking70668fc2018-09-28 15:03:01 +0200601
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530602 if ((q6core_get_avcs_api_version_per_service(
Dieter Luecking70668fc2018-09-28 15:03:01 +0200603 APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
Mangesh Kunchamwar9f295c72018-10-08 18:20:41 +0530604 ADSP_ASM_API_VERSION_V2) &&
605 q6core_use_Q6_32ch_support())
Dieter Luecking70668fc2018-09-28 15:03:01 +0200606 ret = q6asm_enc_cfg_blk_pcm_format_support_v5(
607 prtd->audio_client,
608 prtd->samp_rate,
609 prtd->channel_mode,
610 bits_per_sample,
611 sample_word_size,
612 ASM_LITTLE_ENDIAN,
613 DEFAULT_QF);
614 else
615 ret = q6asm_enc_cfg_blk_pcm_format_support_v4(
616 prtd->audio_client,
617 prtd->samp_rate,
618 prtd->channel_mode,
619 bits_per_sample,
620 sample_word_size,
621 ASM_LITTLE_ENDIAN,
622 DEFAULT_QF);
623
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530624 if (ret < 0)
625 pr_debug("%s: cmd cfg pcm was block failed", __func__);
626
627 prtd->enabled = RUNNING;
628
629 return ret;
630}
631
632static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
633{
634 int ret = 0;
635 struct snd_pcm_runtime *runtime = substream->runtime;
636 struct msm_audio *prtd = runtime->private_data;
637
638 switch (cmd) {
639 case SNDRV_PCM_TRIGGER_START:
640 case SNDRV_PCM_TRIGGER_RESUME:
641 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
642 pr_debug("%s: Trigger start\n", __func__);
643 ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
644 break;
645 case SNDRV_PCM_TRIGGER_STOP:
646 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
647 atomic_set(&prtd->start, 0);
648 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
649 prtd->enabled = STOPPED;
650 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
651 break;
652 }
653 /* pending CMD_EOS isn't expected */
654 WARN_ON_ONCE(test_bit(CMD_EOS, &prtd->cmd_pending));
655 set_bit(CMD_EOS, &prtd->cmd_pending);
656 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
657 if (ret)
658 clear_bit(CMD_EOS, &prtd->cmd_pending);
659 break;
660 case SNDRV_PCM_TRIGGER_SUSPEND:
661 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
662 pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
663 ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
664 atomic_set(&prtd->start, 0);
665 break;
666 default:
667 ret = -EINVAL;
668 break;
669 }
670
671 return ret;
672}
673
674static int msm_pcm_open(struct snd_pcm_substream *substream)
675{
676 struct snd_pcm_runtime *runtime = substream->runtime;
677 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800678 struct snd_soc_component *component =
679 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530680 struct msm_audio *prtd;
Banajit Goswami616e68c2017-10-27 01:31:19 -0700681 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530682 int ret = 0;
683
Meng Wangee084a02018-09-04 16:11:58 +0800684 if (!component) {
685 pr_err("%s: component is NULL\n", __func__);
686 return -EINVAL;
687 }
688
Banajit Goswami616e68c2017-10-27 01:31:19 -0700689 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800690 dev_get_drvdata(component->dev);
Banajit Goswami616e68c2017-10-27 01:31:19 -0700691 if (!pdata) {
692 pr_err("%s: platform data not populated\n", __func__);
693 return -EINVAL;
694 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530695 prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
696 if (prtd == NULL)
697 return -ENOMEM;
698
699 prtd->substream = substream;
700 prtd->audio_client = q6asm_audio_client_alloc(
701 (app_cb)event_handler, prtd);
702 if (!prtd->audio_client) {
703 pr_info("%s: Could not allocate memory\n", __func__);
704 kfree(prtd);
Vatsal Bucha2eb2e612018-06-01 12:05:25 +0530705 prtd = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530706 return -ENOMEM;
707 }
708
Meng Wangee084a02018-09-04 16:11:58 +0800709 prtd->audio_client->dev = component->dev;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530710
711 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
712 runtime->hw = msm_pcm_hardware_playback;
713
714 /* Capture path */
715 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
716 runtime->hw = msm_pcm_hardware_capture;
717 else {
718 pr_err("Invalid Stream type %d\n", substream->stream);
719 return -EINVAL;
720 }
721
722 ret = snd_pcm_hw_constraint_list(runtime, 0,
723 SNDRV_PCM_HW_PARAM_RATE,
724 &constraints_sample_rates);
725 if (ret < 0)
726 pr_info("snd_pcm_hw_constraint_list failed\n");
727 /* Ensure that buffer size is a multiple of period size */
728 ret = snd_pcm_hw_constraint_integer(runtime,
729 SNDRV_PCM_HW_PARAM_PERIODS);
730 if (ret < 0)
731 pr_info("snd_pcm_hw_constraint_integer failed\n");
732
733 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
734 ret = snd_pcm_hw_constraint_minmax(runtime,
735 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
736 PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
737 PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
738 if (ret < 0) {
739 pr_err("constraint for buffer bytes min max ret = %d\n",
740 ret);
741 }
742 }
743
744 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
745 ret = snd_pcm_hw_constraint_minmax(runtime,
746 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
747 CAPTURE_MIN_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
748 CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
749 if (ret < 0) {
750 pr_err("constraint for buffer bytes min max ret = %d\n",
751 ret);
752 }
753 }
754 ret = snd_pcm_hw_constraint_step(runtime, 0,
755 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
756 if (ret < 0) {
757 pr_err("constraint for period bytes step ret = %d\n",
758 ret);
759 }
760 ret = snd_pcm_hw_constraint_step(runtime, 0,
761 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
762 if (ret < 0) {
763 pr_err("constraint for buffer bytes step ret = %d\n",
764 ret);
765 }
766
767 prtd->enabled = IDLE;
768 prtd->dsp_cnt = 0;
769 prtd->set_channel_map = false;
770 prtd->reset_event = false;
771 runtime->private_data = prtd;
Xiaojun Sangf27e3512018-05-23 17:14:31 +0800772
773 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
774 msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
775
Banajit Goswami616e68c2017-10-27 01:31:19 -0700776 /* Vote to update the Rx thread priority to RT Thread for playback */
777 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
778 (pdata->perf_mode == LOW_LATENCY_PCM_MODE))
779 apr_start_rx_rt(prtd->audio_client->apr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530780
781 return 0;
782}
783
784static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +0800785 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530786{
787 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530788 int xfer = 0;
789 char *bufptr = NULL;
790 void *data = NULL;
791 uint32_t idx = 0;
792 uint32_t size = 0;
793 uint32_t retries = 0;
794
795 struct snd_pcm_runtime *runtime = substream->runtime;
796 struct msm_audio *prtd = runtime->private_data;
797
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530798 pr_debug("%s: prtd->out_count = %d\n",
799 __func__, atomic_read(&prtd->out_count));
800
801 while ((fbytes > 0) && (retries < MAX_PB_COPY_RETRIES)) {
802 if (prtd->reset_event) {
803 pr_err("%s: In SSR return ENETRESET before wait\n",
804 __func__);
805 return -ENETRESET;
806 }
807
808 ret = wait_event_timeout(the_locks.write_wait,
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -0700809 (atomic_read(&prtd->out_count)),
810 msecs_to_jiffies(TIMEOUT_MS));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530811 if (!ret) {
812 pr_err("%s: wait_event_timeout failed\n", __func__);
813 ret = -ETIMEDOUT;
814 goto fail;
815 }
816 ret = 0;
817
818 if (prtd->reset_event) {
819 pr_err("%s: In SSR return ENETRESET after wait\n",
820 __func__);
821 return -ENETRESET;
822 }
823
824 if (!atomic_read(&prtd->out_count)) {
825 pr_err("%s: pcm stopped out_count 0\n", __func__);
826 return 0;
827 }
828
829 data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size,
830 &idx);
831 if (data == NULL) {
832 retries++;
833 continue;
834 } else {
835 retries = 0;
836 }
837
838 if (fbytes > size)
839 xfer = size;
840 else
841 xfer = fbytes;
842
843 bufptr = data;
844 if (bufptr) {
Meng Wangac147b72017-10-30 16:46:16 +0800845 pr_debug("%s:fbytes =%lu: xfer=%d size=%d\n",
846 __func__, fbytes, xfer, size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530847 if (copy_from_user(bufptr, buf, xfer)) {
848 ret = -EFAULT;
849 pr_err("%s: copy_from_user failed\n",
850 __func__);
851 q6asm_cpu_buf_release(IN, prtd->audio_client);
852 goto fail;
853 }
854 buf += xfer;
855 fbytes -= xfer;
Meng Wangac147b72017-10-30 16:46:16 +0800856 pr_debug("%s:fbytes = %lu: xfer=%d\n", __func__,
857 fbytes, xfer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530858 if (atomic_read(&prtd->start)) {
859 pr_debug("%s:writing %d bytes of buffer to dsp\n",
860 __func__, xfer);
861 ret = q6asm_write(prtd->audio_client, xfer,
862 0, 0, NO_TIMESTAMP);
863 if (ret < 0) {
864 ret = -EFAULT;
865 q6asm_cpu_buf_release(IN,
866 prtd->audio_client);
867 goto fail;
868 }
869 } else
870 atomic_inc(&prtd->out_needed);
871 atomic_dec(&prtd->out_count);
872 }
873 }
874fail:
875 if (retries >= MAX_PB_COPY_RETRIES)
876 ret = -ENOMEM;
877
878 return ret;
879}
880
881static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
882{
883 struct snd_pcm_runtime *runtime = substream->runtime;
884 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
885 struct msm_audio *prtd = runtime->private_data;
Meng Wangee084a02018-09-04 16:11:58 +0800886 struct snd_soc_component *component =
887 snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
Banajit Goswami616e68c2017-10-27 01:31:19 -0700888 struct msm_plat_data *pdata;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530889 uint32_t timeout;
890 int dir = 0;
891 int ret = 0;
892
893 pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
894
895 if (prtd->audio_client) {
896 dir = IN;
Meng Wangee084a02018-09-04 16:11:58 +0800897 if (!component) {
898 pr_err("%s: component is NULL\n", __func__);
899 return -EINVAL;
900 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530901
Banajit Goswami616e68c2017-10-27 01:31:19 -0700902 /*
903 * Unvote to downgrade the Rx thread priority from
904 * RT Thread for Low-Latency use case.
905 */
906 pdata = (struct msm_plat_data *)
Meng Wangee084a02018-09-04 16:11:58 +0800907 dev_get_drvdata(component->dev);
Banajit Goswami616e68c2017-10-27 01:31:19 -0700908 if (pdata) {
909 if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
910 apr_end_rx_rt(prtd->audio_client->apr);
911 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530912 /* determine timeout length */
913 if (runtime->frame_bits == 0 || runtime->rate == 0) {
914 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
915 } else {
916 timeout = (runtime->period_size *
917 CMD_EOS_TIMEOUT_MULTIPLIER) /
918 ((runtime->frame_bits / 8) *
919 runtime->rate);
920 if (timeout < CMD_EOS_MIN_TIMEOUT_LENGTH)
921 timeout = CMD_EOS_MIN_TIMEOUT_LENGTH;
922 }
923 pr_debug("%s: CMD_EOS timeout is %d\n", __func__, timeout);
924
925 ret = wait_event_timeout(the_locks.eos_wait,
926 !test_bit(CMD_EOS, &prtd->cmd_pending),
927 timeout);
928 if (!ret)
929 pr_err("%s: CMD_EOS failed, cmd_pending 0x%lx\n",
930 __func__, prtd->cmd_pending);
931 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
932 q6asm_audio_client_buf_free_contiguous(dir,
933 prtd->audio_client);
934 q6asm_audio_client_free(prtd->audio_client);
935 }
936 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
937 SNDRV_PCM_STREAM_PLAYBACK);
938 msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
939 kfree(prtd);
940 runtime->private_data = NULL;
941
942 return 0;
943}
944
945static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
Meng Wangac147b72017-10-30 16:46:16 +0800946 int channel, unsigned long hwoff, void __user *buf,
947 unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530948{
949 int ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530950 int xfer;
951 char *bufptr;
952 void *data = NULL;
953 static uint32_t idx;
954 static uint32_t size;
955 uint32_t offset = 0;
956 struct snd_pcm_runtime *runtime = substream->runtime;
957 struct msm_audio *prtd = substream->runtime->private_data;
958
959
960 pr_debug("%s\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530961
962 pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
963 pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
964 pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
965
966 if (prtd->reset_event) {
967 pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
968 return -ENETRESET;
969 }
970 ret = wait_event_timeout(the_locks.read_wait,
Vignesh Kulothungan0fcf2af2018-09-20 17:43:49 -0700971 (atomic_read(&prtd->in_count)),
972 msecs_to_jiffies(TIMEOUT_MS));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530973 if (!ret) {
974 pr_debug("%s: wait_event_timeout failed\n", __func__);
975 goto fail;
976 }
977 if (prtd->reset_event) {
978 pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
979 return -ENETRESET;
980 }
981 if (!atomic_read(&prtd->in_count)) {
982 pr_debug("%s: pcm stopped in_count 0\n", __func__);
983 return 0;
984 }
985 pr_debug("Checking if valid buffer is available...%pK\n",
986 data);
987 data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
988 bufptr = data;
989 pr_debug("Size = %d\n", size);
Meng Wangac147b72017-10-30 16:46:16 +0800990 pr_debug("fbytes = %lu\n", fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530991 pr_debug("idx = %d\n", idx);
992 if (bufptr) {
993 xfer = fbytes;
994 if (xfer > size)
995 xfer = size;
996 offset = prtd->in_frame_info[idx].offset;
997 pr_debug("Offset value = %d\n", offset);
998 if (copy_to_user(buf, bufptr+offset, xfer)) {
999 pr_err("Failed to copy buf to user\n");
1000 ret = -EFAULT;
1001 q6asm_cpu_buf_release(OUT, prtd->audio_client);
1002 goto fail;
1003 }
1004 fbytes -= xfer;
1005 size -= xfer;
1006 prtd->in_frame_info[idx].offset += xfer;
Meng Wangac147b72017-10-30 16:46:16 +08001007 pr_debug("%s:fbytes = %lu: size=%d: xfer=%d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301008 __func__, fbytes, size, xfer);
1009 pr_debug(" Sending next buffer to dsp\n");
1010 memset(&prtd->in_frame_info[idx], 0,
1011 sizeof(struct msm_audio_in_frame_info));
1012 atomic_dec(&prtd->in_count);
1013 ret = q6asm_read(prtd->audio_client);
1014 if (ret < 0) {
1015 pr_err("q6asm read failed\n");
1016 ret = -EFAULT;
1017 q6asm_cpu_buf_release(OUT, prtd->audio_client);
1018 goto fail;
1019 }
1020 } else
1021 pr_err("No valid buffer\n");
1022
1023 pr_debug("Returning from capture_copy... %d\n", ret);
1024fail:
1025 return ret;
1026}
1027
1028static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
1029{
1030 struct snd_pcm_runtime *runtime = substream->runtime;
1031 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
1032 struct msm_audio *prtd = runtime->private_data;
1033 int dir = OUT;
1034
1035 pr_debug("%s\n", __func__);
1036 if (prtd->audio_client) {
1037 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
1038 q6asm_audio_client_buf_free_contiguous(dir,
1039 prtd->audio_client);
1040 q6asm_audio_client_free(prtd->audio_client);
1041 }
1042
1043 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
1044 SNDRV_PCM_STREAM_CAPTURE);
1045 kfree(prtd);
1046 runtime->private_data = NULL;
1047
1048 return 0;
1049}
1050
1051static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +08001052 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301053{
1054 int ret = 0;
1055
1056 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Meng Wangac147b72017-10-30 16:46:16 +08001057 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301058 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
Meng Wangac147b72017-10-30 16:46:16 +08001059 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, fbytes);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301060 return ret;
1061}
1062
1063static int msm_pcm_close(struct snd_pcm_substream *substream)
1064{
1065 int ret = 0;
1066
1067 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1068 ret = msm_pcm_playback_close(substream);
1069 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1070 ret = msm_pcm_capture_close(substream);
1071 return ret;
1072}
1073
1074static int msm_pcm_prepare(struct snd_pcm_substream *substream)
1075{
1076 int ret = 0;
1077
1078 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1079 ret = msm_pcm_playback_prepare(substream);
1080 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1081 ret = msm_pcm_capture_prepare(substream);
1082 return ret;
1083}
1084
1085static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
1086{
1087
1088 struct snd_pcm_runtime *runtime = substream->runtime;
1089 struct msm_audio *prtd = runtime->private_data;
1090
1091 if (prtd->pcm_irq_pos >= prtd->pcm_size)
1092 prtd->pcm_irq_pos = 0;
1093
1094 pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
1095 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
1096}
1097
1098static int msm_pcm_mmap(struct snd_pcm_substream *substream,
1099 struct vm_area_struct *vma)
1100{
1101 struct snd_pcm_runtime *runtime = substream->runtime;
1102 struct msm_audio *prtd = runtime->private_data;
1103 struct audio_client *ac = prtd->audio_client;
1104 struct audio_port_data *apd = ac->port;
1105 struct audio_buffer *ab;
1106 int dir = -1;
1107
1108 prtd->mmap_flag = 1;
1109
1110 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1111 dir = IN;
1112 else
1113 dir = OUT;
1114 ab = &(apd[dir].buf[0]);
1115
1116 return msm_audio_ion_mmap(ab, vma);
1117}
1118
1119static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
1120 struct snd_pcm_hw_params *params)
1121{
1122 struct snd_pcm_runtime *runtime = substream->runtime;
1123 struct msm_audio *prtd = runtime->private_data;
1124 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
1125 struct audio_buffer *buf;
1126 int dir, ret;
1127
1128 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1129 dir = IN;
1130 else
1131 dir = OUT;
1132 ret = q6asm_audio_client_buf_alloc_contiguous(dir,
1133 prtd->audio_client,
1134 (params_buffer_bytes(params) / params_periods(params)),
1135 params_periods(params));
1136 if (ret < 0) {
1137 pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
1138 ret);
1139 return -ENOMEM;
1140 }
1141 buf = prtd->audio_client->port[dir].buf;
1142 if (buf == NULL || buf[0].data == NULL)
1143 return -ENOMEM;
1144
1145 pr_debug("%s:buf = %pK\n", __func__, buf);
1146 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
1147 dma_buf->dev.dev = substream->pcm->card->dev;
1148 dma_buf->private_data = NULL;
1149 dma_buf->area = buf[0].data;
1150 dma_buf->addr = buf[0].phys;
1151 dma_buf->bytes = params_buffer_bytes(params);
1152 if (!dma_buf->area)
1153 return -ENOMEM;
1154
1155 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
1156 return 0;
1157}
1158
1159static const struct snd_pcm_ops msm_pcm_ops = {
1160 .open = msm_pcm_open,
Meng Wangac147b72017-10-30 16:46:16 +08001161 .copy_user = msm_pcm_copy,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301162 .hw_params = msm_pcm_hw_params,
1163 .close = msm_pcm_close,
1164 .ioctl = snd_pcm_lib_ioctl,
1165 .prepare = msm_pcm_prepare,
1166 .trigger = msm_pcm_trigger,
1167 .pointer = msm_pcm_pointer,
1168 .mmap = msm_pcm_mmap,
1169};
1170
1171static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
1172 struct snd_ctl_elem_value *ucontrol)
1173{
Meng Wangee084a02018-09-04 16:11:58 +08001174 struct snd_soc_component *component =
1175 snd_soc_kcontrol_component(kcontrol);
1176 struct msm_plat_data *pdata = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301177 struct snd_pcm_substream *substream;
1178 struct msm_audio *prtd;
1179 int ret = 0;
1180 struct msm_adsp_event_data *event_data = NULL;
1181
Meng Wangee084a02018-09-04 16:11:58 +08001182 if (!component) {
1183 pr_err("%s: component is NULL\n", __func__);
1184 return -EINVAL;
1185 }
1186
1187 pdata = dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301188 if (!pdata) {
1189 pr_err("%s pdata is NULL\n", __func__);
1190 ret = -ENODEV;
1191 goto done;
1192 }
1193
1194 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1195 if (!substream) {
1196 pr_err("%s substream not found\n", __func__);
1197 ret = -EINVAL;
1198 goto done;
1199 }
1200
1201 if (!substream->runtime) {
1202 pr_err("%s substream runtime not found\n", __func__);
1203 ret = -EINVAL;
1204 goto done;
1205 }
1206
1207 prtd = substream->runtime->private_data;
Vatsal Bucha2eb2e612018-06-01 12:05:25 +05301208 if (prtd == NULL) {
1209 pr_err("%s prtd is null.\n", __func__);
1210 ret = -EINVAL;
1211 goto done;
1212 }
1213
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301214 if (prtd->audio_client == NULL) {
1215 pr_err("%s prtd is null.\n", __func__);
1216 ret = -EINVAL;
1217 goto done;
1218 }
1219
1220 event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
1221 if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
1222 (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
1223 pr_err("%s: invalid event_type=%d",
1224 __func__, event_data->event_type);
1225 ret = -EINVAL;
1226 goto done;
1227 }
1228
Xiaojun Sang75642c32018-03-23 08:57:33 +08001229 if (event_data->payload_len > sizeof(ucontrol->value.bytes.data)
1230 - sizeof(struct msm_adsp_event_data)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301231 pr_err("%s param length=%d exceeds limit",
1232 __func__, event_data->payload_len);
1233 ret = -EINVAL;
1234 goto done;
1235 }
1236
1237 ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
1238 if (ret < 0)
1239 pr_err("%s: failed to send stream event cmd, err = %d\n",
1240 __func__, ret);
1241done:
1242 return ret;
1243}
1244
1245static int msm_pcm_add_audio_adsp_stream_cmd_control(
1246 struct snd_soc_pcm_runtime *rtd)
1247{
Meng Wangee084a02018-09-04 16:11:58 +08001248 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301249 const char *mixer_ctl_name = DSP_STREAM_CMD;
1250 const char *deviceNo = "NN";
1251 char *mixer_str = NULL;
1252 int ctl_len = 0, ret = 0;
1253 struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
1254 {
1255 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1256 .name = "?",
1257 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1258 .info = msm_adsp_stream_cmd_info,
1259 .put = msm_pcm_adsp_stream_cmd_put,
1260 .private_value = 0,
1261 }
1262 };
1263
1264 if (!rtd) {
1265 pr_err("%s rtd is NULL\n", __func__);
1266 ret = -EINVAL;
1267 goto done;
1268 }
1269
Meng Wangee084a02018-09-04 16:11:58 +08001270 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1271 if (!component) {
1272 pr_err("%s: component is NULL\n", __func__);
1273 return -EINVAL;
1274 }
1275
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301276 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1277 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1278 if (!mixer_str) {
1279 ret = -ENOMEM;
1280 goto done;
1281 }
1282
1283 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1284 fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
1285 fe_audio_adsp_stream_cmd_config_control[0].private_value =
1286 rtd->dai_link->id;
1287 pr_debug("Registering new mixer ctl %s\n", mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001288 ret = snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301289 fe_audio_adsp_stream_cmd_config_control,
1290 ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
1291 if (ret < 0)
1292 pr_err("%s: failed add ctl %s. err = %d\n",
1293 __func__, mixer_str, ret);
1294
1295 kfree(mixer_str);
1296done:
1297 return ret;
1298}
1299
1300static int msm_pcm_add_audio_adsp_stream_callback_control(
1301 struct snd_soc_pcm_runtime *rtd)
1302{
Meng Wangee084a02018-09-04 16:11:58 +08001303 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301304 const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
1305 const char *deviceNo = "NN";
1306 char *mixer_str = NULL;
1307 int ctl_len = 0, ret = 0;
1308 struct snd_kcontrol *kctl;
1309
1310 struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
1311 {
1312 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1313 .name = "?",
1314 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1315 .info = msm_adsp_stream_callback_info,
1316 .get = msm_adsp_stream_callback_get,
1317 .private_value = 0,
1318 }
1319 };
1320
1321 if (!rtd) {
1322 pr_err("%s NULL rtd\n", __func__);
1323 ret = -EINVAL;
1324 goto done;
1325 }
1326
Meng Wangee084a02018-09-04 16:11:58 +08001327 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1328 if (!component) {
1329 pr_err("%s: component is NULL\n", __func__);
1330 return -EINVAL;
1331 }
1332
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301333 pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
1334 __func__, rtd->dai_link->name, rtd->dai_link->id,
1335 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
1336 ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
1337 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1338 if (!mixer_str) {
1339 ret = -ENOMEM;
1340 goto done;
1341 }
1342
1343 snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
1344 fe_audio_adsp_callback_config_control[0].name = mixer_str;
1345 fe_audio_adsp_callback_config_control[0].private_value =
1346 rtd->dai_link->id;
1347 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001348 ret = snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301349 fe_audio_adsp_callback_config_control,
1350 ARRAY_SIZE(fe_audio_adsp_callback_config_control));
1351 if (ret < 0) {
1352 pr_err("%s: failed to add ctl %s. err = %d\n",
1353 __func__, mixer_str, ret);
1354 ret = -EINVAL;
1355 goto free_mixer_str;
1356 }
1357
1358 kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
1359 if (!kctl) {
1360 pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
1361 ret = -EINVAL;
1362 goto free_mixer_str;
1363 }
1364
1365 kctl->private_data = NULL;
1366
1367free_mixer_str:
1368 kfree(mixer_str);
1369done:
1370 return ret;
1371}
1372
1373static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
1374{
1375 int rc = 0;
1376
1377 if (prtd && prtd->audio_client) {
1378 pr_debug("%s: channels %d volume 0x%x\n", __func__,
1379 prtd->channel_mode, volume);
1380 rc = q6asm_set_volume(prtd->audio_client, volume);
1381 if (rc < 0) {
1382 pr_err("%s: Send Volume command failed rc=%d\n",
1383 __func__, rc);
1384 }
1385 }
1386 return rc;
1387}
1388
1389static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
1390 struct snd_ctl_elem_value *ucontrol)
1391{
1392 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
1393 struct snd_pcm_substream *substream =
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001394 vol->pcm->streams[vol->stream].substream;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301395 struct msm_audio *prtd;
1396
1397 pr_debug("%s\n", __func__);
1398 if (!substream) {
1399 pr_err("%s substream not found\n", __func__);
1400 return -ENODEV;
1401 }
1402 if (!substream->runtime) {
Vignesh Kulothungan2ce67842018-09-25 16:40:29 -07001403 pr_debug("%s substream runtime not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301404 return 0;
1405 }
1406 prtd = substream->runtime->private_data;
1407 if (prtd)
1408 ucontrol->value.integer.value[0] = prtd->volume;
1409 return 0;
1410}
1411
1412static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
1413 struct snd_ctl_elem_value *ucontrol)
1414{
1415 int rc = 0;
1416 struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
1417 struct snd_pcm_substream *substream =
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001418 vol->pcm->streams[vol->stream].substream;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301419 struct msm_audio *prtd;
1420 int volume = ucontrol->value.integer.value[0];
1421
1422 pr_debug("%s: volume : 0x%x\n", __func__, volume);
1423 if (!substream) {
1424 pr_err("%s substream not found\n", __func__);
1425 return -ENODEV;
1426 }
1427 if (!substream->runtime) {
1428 pr_err("%s substream runtime not found\n", __func__);
1429 return 0;
1430 }
1431 prtd = substream->runtime->private_data;
1432 if (prtd) {
1433 rc = msm_pcm_set_volume(prtd, volume);
1434 prtd->volume = volume;
1435 }
1436 return rc;
1437}
1438
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001439static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd,
1440 int stream)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301441{
1442 int ret = 0;
1443 struct snd_pcm *pcm = rtd->pcm;
1444 struct snd_pcm_volume *volume_info;
1445 struct snd_kcontrol *kctl;
1446
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07001447 dev_dbg(rtd->dev, "%s, volume control add\n", __func__);
1448 ret = snd_pcm_add_volume_ctls(pcm, stream,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301449 NULL, 1, rtd->dai_link->id,
1450 &volume_info);
1451 if (ret < 0) {
1452 pr_err("%s volume control failed ret %d\n", __func__, ret);
1453 return ret;
1454 }
1455 kctl = volume_info->kctl;
1456 kctl->put = msm_pcm_volume_ctl_put;
1457 kctl->get = msm_pcm_volume_ctl_get;
1458 kctl->tlv.p = msm_pcm_vol_gain;
1459 return 0;
1460}
1461
1462static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
1463 struct snd_ctl_elem_info *uinfo)
1464{
1465 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1466 uinfo->count = 1;
1467 uinfo->value.integer.min = 0;
1468 uinfo->value.integer.max = 0x2000;
1469 return 0;
1470}
1471
1472static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
1473 struct snd_ctl_elem_value *ucontrol)
1474{
Meng Wangee084a02018-09-04 16:11:58 +08001475 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
1476 struct msm_plat_data *pdata = dev_get_drvdata(comp->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301477 struct snd_pcm_substream *substream;
1478 struct msm_audio *prtd;
1479
1480 if (!pdata) {
1481 pr_err("%s pdata is NULL\n", __func__);
1482 return -ENODEV;
1483 }
1484 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1485 if (!substream) {
1486 pr_err("%s substream not found\n", __func__);
1487 return -EINVAL;
1488 }
1489 if (!substream->runtime) {
Vignesh Kulothungan2ce67842018-09-25 16:40:29 -07001490 pr_debug("%s substream runtime not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301491 return 0;
1492 }
1493 prtd = substream->runtime->private_data;
1494 if (prtd)
1495 ucontrol->value.integer.value[0] = prtd->compress_enable;
1496 return 0;
1497}
1498
1499static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
1500 struct snd_ctl_elem_value *ucontrol)
1501{
1502 int rc = 0;
Meng Wangee084a02018-09-04 16:11:58 +08001503 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
1504 struct msm_plat_data *pdata = dev_get_drvdata(comp->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301505 struct snd_pcm_substream *substream;
1506 struct msm_audio *prtd;
1507 int compress = ucontrol->value.integer.value[0];
1508
1509 if (!pdata) {
1510 pr_err("%s pdata is NULL\n", __func__);
1511 return -ENODEV;
1512 }
1513 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1514 pr_debug("%s: compress : 0x%x\n", __func__, compress);
1515 if (!substream) {
1516 pr_err("%s substream not found\n", __func__);
1517 return -EINVAL;
1518 }
1519 if (!substream->runtime) {
1520 pr_err("%s substream runtime not found\n", __func__);
1521 return 0;
1522 }
1523 prtd = substream->runtime->private_data;
1524 if (prtd) {
1525 pr_debug("%s: setting compress flag to 0x%x\n",
1526 __func__, compress);
1527 prtd->compress_enable = compress;
1528 }
1529 return rc;
1530}
1531
1532static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
1533{
Meng Wangee084a02018-09-04 16:11:58 +08001534 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301535 const char *mixer_ctl_name = "Playback ";
1536 const char *mixer_ctl_end_name = " Compress";
1537 const char *deviceNo = "NN";
1538 char *mixer_str = NULL;
1539 int ctl_len;
1540 int ret = 0;
1541 struct msm_plat_data *pdata;
1542 struct snd_kcontrol_new pcm_compress_control[1] = {
1543 {
1544 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1545 .name = "?",
1546 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1547 .info = msm_pcm_compress_ctl_info,
1548 .get = msm_pcm_compress_ctl_get,
1549 .put = msm_pcm_compress_ctl_put,
1550 .private_value = 0,
1551 }
1552 };
1553
1554 if (!rtd) {
1555 pr_err("%s: NULL rtd\n", __func__);
1556 return -EINVAL;
1557 }
1558
Meng Wangee084a02018-09-04 16:11:58 +08001559 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1560 if (!component) {
1561 pr_err("%s: component is NULL\n", __func__);
1562 return -EINVAL;
1563 }
1564
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301565 ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
1566 strlen(mixer_ctl_end_name) + 1;
1567 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1568
1569 if (!mixer_str)
1570 return -ENOMEM;
1571
1572 snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
1573 rtd->pcm->device, mixer_ctl_end_name);
1574
1575 pcm_compress_control[0].name = mixer_str;
1576 pcm_compress_control[0].private_value = rtd->dai_link->id;
1577 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001578 pdata = dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301579 if (pdata) {
1580 if (!pdata->pcm) {
1581 pdata->pcm = rtd->pcm;
Meng Wangee084a02018-09-04 16:11:58 +08001582 snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301583 pcm_compress_control,
1584 ARRAY_SIZE
1585 (pcm_compress_control));
1586 pr_debug("%s: add control success plt = %pK\n",
Meng Wangee084a02018-09-04 16:11:58 +08001587 __func__, component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301588 }
1589 } else {
1590 pr_err("%s: NULL pdata\n", __func__);
1591 ret = -EINVAL;
1592 }
1593 kfree(mixer_str);
1594 return ret;
1595}
1596
1597static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1598 struct snd_ctl_elem_value *ucontrol)
1599{
1600 int i;
1601 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1602 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1603 struct snd_pcm_substream *substream;
1604 struct msm_audio *prtd;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301605 struct snd_soc_pcm_runtime *rtd = NULL;
1606 struct msm_plat_data *pdata = NULL;
1607 struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001608 struct snd_soc_component *component = NULL;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301609 u64 fe_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301610
1611 pr_debug("%s", __func__);
1612 substream = snd_pcm_chmap_substream(info, idx);
1613 if (!substream)
1614 return -ENODEV;
1615 if (!substream->runtime)
1616 return 0;
1617
1618 prtd = substream->runtime->private_data;
1619 if (prtd) {
1620 prtd->set_channel_map = true;
Dieter Luecking70668fc2018-09-28 15:03:01 +02001621 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301622 prtd->channel_map[i] =
1623 (char)(ucontrol->value.integer.value[i]);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301624
1625 /* update chmixer_pspd chmap cached with routing driver as well */
1626 rtd = substream->private_data;
1627 if (rtd) {
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001628 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1629 if (component) {
1630 fe_id = rtd->dai_link->id;
1631 pdata = (struct msm_plat_data *)
1632 dev_get_drvdata(component->dev);
1633 chmixer_pspd = pdata ?
1634 pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301635
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001636 if (chmixer_pspd && chmixer_pspd->enable) {
1637 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1638 chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
1639 chmixer_pspd->override_in_ch_map = true;
1640 msm_pcm_routing_set_channel_mixer_cfg(fe_id,
1641 SESSION_TYPE_RX, chmixer_pspd);
1642 }
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301643 }
1644 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301645 }
1646 return 0;
1647}
1648
1649static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
1650 struct snd_ctl_elem_value *ucontrol)
1651{
1652 int i;
1653 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1654 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1655 struct snd_pcm_substream *substream;
1656 struct msm_audio *prtd;
1657
1658 pr_debug("%s", __func__);
1659 substream = snd_pcm_chmap_substream(info, idx);
1660 if (!substream)
1661 return -ENODEV;
1662 memset(ucontrol->value.integer.value, 0,
1663 sizeof(ucontrol->value.integer.value));
1664 if (!substream->runtime)
1665 return 0; /* no channels set */
1666
1667 prtd = substream->runtime->private_data;
1668
1669 if (prtd && prtd->set_channel_map == true) {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001670 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301671 ucontrol->value.integer.value[i] =
1672 (int)prtd->channel_map[i];
1673 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001674 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301675 ucontrol->value.integer.value[i] = 0;
1676 }
1677
1678 return 0;
1679}
1680
1681static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
1682{
1683 struct snd_pcm *pcm = rtd->pcm;
1684 struct snd_pcm_chmap *chmap_info;
1685 struct snd_kcontrol *kctl;
1686 char device_num[12];
1687 int i, ret = 0;
1688
1689 pr_debug("%s, Channel map cntrl add\n", __func__);
1690 ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1691 snd_pcm_std_chmaps,
Dieter Luecking70668fc2018-09-28 15:03:01 +02001692 PCM_FORMAT_MAX_NUM_CHANNEL_V8, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301693 &chmap_info);
1694 if (ret < 0) {
1695 pr_err("%s, channel map cntrl add failed\n", __func__);
1696 return ret;
1697 }
1698 kctl = chmap_info->kctl;
1699 for (i = 0; i < kctl->count; i++)
1700 kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
1701 snprintf(device_num, sizeof(device_num), "%d", pcm->device);
1702 strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
1703 pr_debug("%s, Overwriting channel map control name to: %s\n",
1704 __func__, kctl->id.name);
1705 kctl->put = msm_pcm_chmap_ctl_put;
1706 kctl->get = msm_pcm_chmap_ctl_get;
1707 return 0;
1708}
1709
1710static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1711 struct snd_ctl_elem_value *ucontrol)
1712{
1713 u64 fe_id = kcontrol->private_value;
1714 int session_type = SESSION_TYPE_RX;
1715 int be_id = ucontrol->value.integer.value[3];
1716 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1717 int ret = 0;
1718
1719 cfg_data.app_type = ucontrol->value.integer.value[0];
1720 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1721 if (ucontrol->value.integer.value[2] != 0)
1722 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1723 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1724 __func__, fe_id, session_type, be_id,
1725 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1726 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1727 be_id, &cfg_data);
1728 if (ret < 0)
1729 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1730 __func__, ret);
1731
1732 return ret;
1733}
1734
1735static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1736 struct snd_ctl_elem_value *ucontrol)
1737{
1738 u64 fe_id = kcontrol->private_value;
1739 int session_type = SESSION_TYPE_RX;
1740 int be_id = 0;
1741 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1742 int ret = 0;
1743
1744 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1745 &be_id, &cfg_data);
1746 if (ret < 0) {
1747 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1748 __func__, ret);
1749 goto done;
1750 }
1751
1752 ucontrol->value.integer.value[0] = cfg_data.app_type;
1753 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1754 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1755 ucontrol->value.integer.value[3] = be_id;
1756 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1757 __func__, fe_id, session_type, be_id,
1758 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1759done:
1760 return ret;
1761}
1762
1763static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1764 struct snd_ctl_elem_value *ucontrol)
1765{
1766 u64 fe_id = kcontrol->private_value;
1767 int session_type = SESSION_TYPE_TX;
1768 int be_id = ucontrol->value.integer.value[3];
1769 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1770 int ret = 0;
1771
1772 cfg_data.app_type = ucontrol->value.integer.value[0];
1773 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1774 if (ucontrol->value.integer.value[2] != 0)
1775 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1776 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1777 __func__, fe_id, session_type, be_id,
1778 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1779 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1780 be_id, &cfg_data);
1781 if (ret < 0)
1782 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1783 __func__, ret);
1784
1785 return ret;
1786}
1787
1788static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1789 struct snd_ctl_elem_value *ucontrol)
1790{
1791 u64 fe_id = kcontrol->private_value;
1792 int session_type = SESSION_TYPE_TX;
1793 int be_id = 0;
1794 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1795 int ret = 0;
1796
1797 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1798 &be_id, &cfg_data);
1799 if (ret < 0) {
1800 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1801 __func__, ret);
1802 goto done;
1803 }
1804
1805 ucontrol->value.integer.value[0] = cfg_data.app_type;
1806 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1807 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1808 ucontrol->value.integer.value[3] = be_id;
1809 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1810 __func__, fe_id, session_type, be_id,
1811 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1812done:
1813 return ret;
1814}
1815
1816static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
1817{
1818 struct snd_pcm *pcm = rtd->pcm;
1819 struct snd_pcm_usr *app_type_info;
1820 struct snd_kcontrol *kctl;
1821 const char *playback_mixer_ctl_name = "Audio Stream";
1822 const char *capture_mixer_ctl_name = "Audio Stream Capture";
1823 const char *deviceNo = "NN";
1824 const char *suffix = "App Type Cfg";
1825 int ctl_len, ret = 0;
1826
1827 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
1828 ctl_len = strlen(playback_mixer_ctl_name) + 1 +
1829 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1830 pr_debug("%s: Playback app type cntrl add\n", __func__);
1831 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1832 NULL, 1, ctl_len, rtd->dai_link->id,
1833 &app_type_info);
1834 if (ret < 0) {
1835 pr_err("%s: playback app type cntrl add failed: %d\n",
1836 __func__, ret);
1837 return ret;
1838 }
1839 kctl = app_type_info->kctl;
1840 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1841 playback_mixer_ctl_name, rtd->pcm->device, suffix);
1842 kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
1843 kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
1844 }
1845
1846 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
1847 ctl_len = strlen(capture_mixer_ctl_name) + 1 +
1848 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1849 pr_debug("%s: Capture app type cntrl add\n", __func__);
1850 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
1851 NULL, 1, ctl_len, rtd->dai_link->id,
1852 &app_type_info);
1853 if (ret < 0) {
1854 pr_err("%s: capture app type cntrl add failed: %d\n",
1855 __func__, ret);
1856 return ret;
1857 }
1858 kctl = app_type_info->kctl;
1859 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1860 capture_mixer_ctl_name, rtd->pcm->device, suffix);
1861 kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
1862 kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
1863 }
1864
1865 return 0;
1866}
1867
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301868static struct msm_pcm_channel_mixer *msm_pcm_get_chmixer(
1869 struct msm_plat_data *pdata,
1870 u64 fe_id, int session_type)
1871{
1872 if (!pdata) {
1873 pr_err("%s: missing pdata\n", __func__);
1874 return NULL;
1875 }
1876
1877 if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
1878 pr_err("%s: invalid FE %llu\n", __func__, fe_id);
1879 return NULL;
1880 }
1881
1882 if ((session_type != SESSION_TYPE_TX) &&
1883 (session_type != SESSION_TYPE_RX)) {
1884 pr_err("%s: invalid session type %d\n", __func__, session_type);
1885 return NULL;
1886 }
1887
1888 return pdata->chmixer_pspd[fe_id][session_type];
1889}
1890
1891static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1892 struct snd_ctl_elem_value *ucontrol)
1893{
1894 u64 fe_id = kcontrol->private_value & 0xFF;
1895 int session_type = (kcontrol->private_value >> 8) & 0xFF;
1896 int ret = 0;
1897 int stream_id = 0;
1898 int be_id = 0, i = 0;
1899 struct msm_audio *prtd = NULL;
1900 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
1901 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
1902 struct snd_pcm *pcm = NULL;
1903 struct snd_pcm_substream *substream = NULL;
1904 struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
1905 u8 asm_ch_map[PCM_FORMAT_MAX_NUM_CHANNEL_V8] = {0};
1906 bool reset_override_out_ch_map = false;
1907 bool reset_override_in_ch_map = false;
1908
1909 pcm = pdata->pcm_device[fe_id];
1910 if (!pcm) {
1911 pr_err("%s invalid pcm handle for fe_id %llu\n",
1912 __func__, fe_id);
1913 return -EINVAL;
1914 }
1915
1916 if (session_type == SESSION_TYPE_RX)
1917 substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1918 else
1919 substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
1920 if (!substream) {
1921 pr_err("%s substream not found\n", __func__);
1922 return -EINVAL;
1923 }
1924
1925 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
1926 if (!chmixer_pspd) {
1927 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
1928 return -EINVAL;
1929 }
1930
1931 chmixer_pspd->enable = ucontrol->value.integer.value[0];
1932 chmixer_pspd->rule = ucontrol->value.integer.value[1];
1933 chmixer_pspd->input_channel = ucontrol->value.integer.value[2];
1934 chmixer_pspd->output_channel = ucontrol->value.integer.value[3];
1935 chmixer_pspd->port_idx = ucontrol->value.integer.value[4];
1936
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05301937 if (chmixer_pspd->input_channel <= 0 ||
1938 chmixer_pspd->input_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8 ||
1939 chmixer_pspd->output_channel <= 0 ||
1940 chmixer_pspd->output_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
1941 pr_err("%s: Invalid channels, in %d, out %d\n",
1942 __func__, chmixer_pspd->input_channel,
1943 chmixer_pspd->output_channel);
1944 return -EINVAL;
1945 }
1946
1947 prtd = substream->runtime ? substream->runtime->private_data : NULL;
1948 if (chmixer_pspd->enable && prtd) {
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301949 if (session_type == SESSION_TYPE_RX &&
1950 !chmixer_pspd->override_in_ch_map) {
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05301951 if (prtd->set_channel_map) {
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301952 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05301953 chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301954 } else {
1955 q6asm_map_channels(asm_ch_map,
1956 chmixer_pspd->input_channel, false);
1957 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1958 chmixer_pspd->in_ch_map[i] = asm_ch_map[i];
1959 }
1960 chmixer_pspd->override_in_ch_map = true;
1961 reset_override_in_ch_map = true;
1962 } else if (session_type == SESSION_TYPE_TX &&
1963 !chmixer_pspd->override_out_ch_map) {
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05301964 /*
1965 * Channel map set in prtd is for plyback only,
1966 * hence always use default for capture path.
1967 */
1968 q6asm_map_channels(asm_ch_map,
1969 chmixer_pspd->output_channel, false);
1970 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1971 chmixer_pspd->out_ch_map[i] = asm_ch_map[i];
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301972 chmixer_pspd->override_out_ch_map = true;
1973 reset_override_out_ch_map = true;
1974 }
1975 } else {
1976 chmixer_pspd->override_out_ch_map = false;
1977 chmixer_pspd->override_in_ch_map = false;
1978 }
1979
1980 /* cache value and take effect during adm_open stage */
1981 msm_pcm_routing_set_channel_mixer_cfg(fe_id,
1982 session_type,
1983 chmixer_pspd);
1984
Dhananjay Kumarf682acd2019-03-01 17:07:10 +05301985 if (chmixer_pspd->enable && prtd && prtd->audio_client) {
1986 stream_id = prtd->audio_client->session;
1987 be_id = chmixer_pspd->port_idx;
1988 msm_pcm_routing_set_channel_mixer_runtime(be_id,
1989 stream_id,
1990 session_type,
1991 chmixer_pspd);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301992 }
1993
1994 if (reset_override_out_ch_map)
1995 chmixer_pspd->override_out_ch_map = false;
1996 if (reset_override_in_ch_map)
1997 chmixer_pspd->override_in_ch_map = false;
1998
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301999 return ret;
2000}
2001
2002static int msm_pcm_channel_mixer_cfg_ctl_get(struct snd_kcontrol *kcontrol,
2003 struct snd_ctl_elem_value *ucontrol)
2004{
2005 u64 fe_id = kcontrol->private_value & 0xFF;
2006 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2007 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2008 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2009 struct msm_pcm_channel_mixer *chmixer_pspd;
2010
2011 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2012 if (!chmixer_pspd) {
2013 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2014 return -EINVAL;
2015 }
2016
2017 ucontrol->value.integer.value[0] = chmixer_pspd->enable;
2018 ucontrol->value.integer.value[1] = chmixer_pspd->rule;
2019 ucontrol->value.integer.value[2] = chmixer_pspd->input_channel;
2020 ucontrol->value.integer.value[3] = chmixer_pspd->output_channel;
2021 ucontrol->value.integer.value[4] = chmixer_pspd->port_idx;
2022 return 0;
2023}
2024
2025static int msm_pcm_channel_mixer_output_map_ctl_put(
2026 struct snd_kcontrol *kcontrol,
2027 struct snd_ctl_elem_value *ucontrol)
2028{
2029 u64 fe_id = kcontrol->private_value & 0xFF;
2030 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2031 int i = 0;
2032 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2033 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2034 struct msm_pcm_channel_mixer *chmixer_pspd;
2035
2036 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2037 if (!chmixer_pspd) {
2038 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2039 return -EINVAL;
2040 }
2041
2042 chmixer_pspd->override_out_ch_map = true;
2043 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2044 chmixer_pspd->out_ch_map[i] =
2045 ucontrol->value.integer.value[i];
2046
2047 return 0;
2048}
2049
2050static int msm_pcm_channel_mixer_output_map_ctl_get(
2051 struct snd_kcontrol *kcontrol,
2052 struct snd_ctl_elem_value *ucontrol)
2053{
2054 u64 fe_id = kcontrol->private_value & 0xFF;
2055 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2056 int i = 0;
2057 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2058 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2059 struct msm_pcm_channel_mixer *chmixer_pspd;
2060
2061 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2062 if (!chmixer_pspd) {
2063 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2064 return -EINVAL;
2065 }
2066
2067 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2068 ucontrol->value.integer.value[i] =
2069 chmixer_pspd->out_ch_map[i];
2070 return 0;
2071}
2072
2073static int msm_pcm_channel_mixer_input_map_ctl_put(
2074 struct snd_kcontrol *kcontrol,
2075 struct snd_ctl_elem_value *ucontrol)
2076{
2077 u64 fe_id = kcontrol->private_value & 0xFF;
2078 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2079 int i = 0;
2080 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2081 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2082 struct msm_pcm_channel_mixer *chmixer_pspd;
2083
2084 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2085 if (!chmixer_pspd) {
2086 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2087 return -EINVAL;
2088 }
2089
2090 chmixer_pspd->override_in_ch_map = true;
2091 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2092 chmixer_pspd->in_ch_map[i] = ucontrol->value.integer.value[i];
2093
2094 return 0;
2095}
2096
2097static int msm_pcm_channel_mixer_input_map_ctl_get(
2098 struct snd_kcontrol *kcontrol,
2099 struct snd_ctl_elem_value *ucontrol)
2100{
2101 u64 fe_id = kcontrol->private_value & 0xFF;
2102 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2103 int i = 0;
2104 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2105 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2106 struct msm_pcm_channel_mixer *chmixer_pspd;
2107
2108 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2109 if (!chmixer_pspd) {
2110 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2111 return -EINVAL;
2112 }
2113
2114 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2115 ucontrol->value.integer.value[i] =
2116 chmixer_pspd->in_ch_map[i];
2117 return 0;
2118}
2119
2120static int msm_pcm_channel_mixer_weight_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 channel = (kcontrol->private_value >> 16) & 0xFF;
2127 int i = 0;
2128 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2129 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2130 struct msm_pcm_channel_mixer *chmixer_pspd;
2131
2132 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2133 if (!chmixer_pspd) {
2134 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2135 return -EINVAL;
2136 }
2137
2138 if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2139 pr_err("%s: invalid channel number %d\n", __func__, channel);
2140 return -EINVAL;
2141 }
2142 channel--;
2143
2144 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2145 chmixer_pspd->channel_weight[channel][i] =
2146 ucontrol->value.integer.value[i];
2147 return 0;
2148}
2149
2150static int msm_pcm_channel_mixer_weight_ctl_get(
2151 struct snd_kcontrol *kcontrol,
2152 struct snd_ctl_elem_value *ucontrol)
2153{
2154 u64 fe_id = kcontrol->private_value & 0xFF;
2155 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2156 int channel = (kcontrol->private_value >> 16) & 0xFF;
2157 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2158 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2159 int i = 0;
2160 struct msm_pcm_channel_mixer *chmixer_pspd;
2161
2162 if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2163 pr_err("%s: invalid channel number %d\n", __func__, channel);
2164 return -EINVAL;
2165 }
2166 channel--;
2167
2168 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2169 if (!chmixer_pspd) {
2170 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2171 return -EINVAL;
2172 }
2173
2174 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2175 ucontrol->value.integer.value[i] =
2176 chmixer_pspd->channel_weight[channel][i];
2177 return 0;
2178}
2179
2180static int msm_pcm_add_platform_controls(struct snd_kcontrol_new *kctl,
2181 struct snd_soc_pcm_runtime *rtd, const char *name_prefix,
2182 const char *name_suffix, int session_type, int channels)
2183{
2184 int ret = -EINVAL;
2185 char *mixer_name = NULL;
2186 struct snd_pcm *pcm = rtd->pcm;
2187 const char *deviceNo = "NN";
2188 const char *channelNo = "NN";
2189 int ctl_len = 0;
2190 struct snd_soc_component *component = NULL;
2191
2192 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2193 if (!component) {
2194 pr_err("%s: component is NULL\n", __func__);
2195 return -EINVAL;
2196 }
2197
2198 ctl_len = strlen(name_prefix) + 1 + strlen(deviceNo) + 1 +
2199 strlen(channelNo) + 1 + strlen(name_suffix) + 1;
2200
2201 mixer_name = kzalloc(ctl_len, GFP_KERNEL);
2202 if (mixer_name == NULL)
2203 return -ENOMEM;
2204
2205 if (channels >= 0) {
2206 snprintf(mixer_name, ctl_len, "%s %d %s %d",
2207 name_prefix, pcm->device, name_suffix, channels);
2208 kctl->private_value = (rtd->dai_link->id) | (session_type << 8) |
2209 (channels << 16);
2210 } else {
2211 snprintf(mixer_name, ctl_len, "%s %d %s",
2212 name_prefix, pcm->device, name_suffix);
2213 kctl->private_value = (rtd->dai_link->id) | (session_type << 8);
2214 }
2215
2216 kctl->name = mixer_name;
2217 ret = snd_soc_add_component_controls(component, kctl, 1);
2218 kfree(mixer_name);
2219 return ret;
2220}
2221
2222static int msm_pcm_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
2223 struct snd_ctl_elem_info *uinfo)
2224{
2225 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2226 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2227 /* Valid channel map value ranges from 1 to 64 */
2228 uinfo->value.integer.min = 1;
2229 uinfo->value.integer.max = 64;
2230 return 0;
2231}
2232
2233static int msm_pcm_add_channel_mixer_output_map_controls(
2234 struct snd_soc_pcm_runtime *rtd)
2235{
2236 struct snd_pcm *pcm = rtd->pcm;
2237 const char *playback_mixer_ctl_name = "AudStr";
2238 const char *capture_mixer_ctl_name = "AudStr Capture";
2239 const char *suffix = "ChMixer Output Map";
2240 int session_type = 0, ret = 0, channel = -1;
2241 struct snd_kcontrol_new channel_mixer_output_map_control = {
2242 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2243 .name = "?",
2244 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2245 .info = msm_pcm_channel_mixer_output_map_info,
2246 .put = msm_pcm_channel_mixer_output_map_ctl_put,
2247 .get = msm_pcm_channel_mixer_output_map_ctl_get,
2248 .private_value = 0,
2249 };
2250
2251 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2252 session_type = SESSION_TYPE_RX;
2253 ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
2254 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2255 if (ret < 0)
2256 goto fail;
2257 }
2258
2259 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2260 session_type = SESSION_TYPE_TX;
2261 ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
2262 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2263 if (ret < 0)
2264 goto fail;
2265 }
2266 return 0;
2267
2268fail:
2269 pr_err("%s: failed add platform ctl, err = %d\n",
2270 __func__, ret);
2271 return ret;
2272}
2273
2274static int msm_pcm_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
2275 struct snd_ctl_elem_info *uinfo)
2276{
2277 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2278 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2279 /* Valid channel map value ranges from 1 to 64 */
2280 uinfo->value.integer.min = 1;
2281 uinfo->value.integer.max = 64;
2282 return 0;
2283}
2284
2285static int msm_pcm_add_channel_mixer_input_map_controls(
2286 struct snd_soc_pcm_runtime *rtd)
2287{
2288 struct snd_pcm *pcm = rtd->pcm;
2289 const char *playback_mixer_ctl_name = "AudStr";
2290 const char *capture_mixer_ctl_name = "AudStr Capture";
2291 const char *suffix = "ChMixer Input Map";
2292 int session_type = 0, ret = 0, channel = -1;
2293 struct snd_kcontrol_new channel_mixer_input_map_control = {
2294 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2295 .name = "?",
2296 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2297 .info = msm_pcm_channel_mixer_input_map_info,
2298 .put = msm_pcm_channel_mixer_input_map_ctl_put,
2299 .get = msm_pcm_channel_mixer_input_map_ctl_get,
2300 .private_value = 0,
2301 };
2302
2303 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2304 session_type = SESSION_TYPE_RX;
2305 ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
2306 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2307 if (ret < 0)
2308 goto fail;
2309 }
2310
2311 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2312 session_type = SESSION_TYPE_TX;
2313 ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
2314 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2315 if (ret < 0)
2316 goto fail;
2317 }
2318 return 0;
2319
2320fail:
2321 pr_err("%s: failed add platform ctl, err = %d\n",
2322 __func__, ret);
2323
2324 return ret;
2325}
2326
2327static int msm_pcm_channel_mixer_cfg_info(struct snd_kcontrol *kcontrol,
2328 struct snd_ctl_elem_info *uinfo)
2329{
2330 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2331 /* five int values: enable, rule, in_channels, out_channels and port_id */
2332 uinfo->count = 5;
2333 /* Valid range is all positive values to support above controls */
2334 uinfo->value.integer.min = 0;
2335 uinfo->value.integer.max = INT_MAX;
2336 return 0;
2337}
2338
2339static int msm_pcm_add_channel_mixer_cfg_controls(
2340 struct snd_soc_pcm_runtime *rtd)
2341{
2342 struct snd_pcm *pcm = rtd->pcm;
2343 const char *playback_mixer_ctl_name = "AudStr";
2344 const char *capture_mixer_ctl_name = "AudStr Capture";
2345 const char *suffix = "ChMixer Cfg";
2346 int session_type = 0, ret = 0, channel = -1;
2347 struct msm_plat_data *pdata = NULL;
2348 struct snd_soc_component *component = NULL;
2349 struct snd_kcontrol_new channel_mixer_cfg_control = {
2350 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2351 .name = "?",
2352 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2353 .info = msm_pcm_channel_mixer_cfg_info,
2354 .put = msm_pcm_channel_mixer_cfg_ctl_put,
2355 .get = msm_pcm_channel_mixer_cfg_ctl_get,
2356 .private_value = 0,
2357 };
2358
2359 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2360 if (!component) {
2361 pr_err("%s: component is NULL\n", __func__);
2362 return -EINVAL;
2363 }
2364
2365 pdata = (struct msm_plat_data *)
2366 dev_get_drvdata(component->dev);
2367
2368 pdata->pcm_device[rtd->dai_link->id] = rtd->pcm;
2369
2370 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2371 session_type = SESSION_TYPE_RX;
2372 ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
2373 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2374 if (ret < 0)
2375 goto fail;
2376 }
2377
2378 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2379 session_type = SESSION_TYPE_TX;
2380 ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
2381 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2382 if (ret < 0)
2383 goto fail;
2384 }
2385 return 0;
2386
2387fail:
2388 pr_err("%s: failed add platform ctl, err = %d\n",
2389 __func__, ret);
2390
2391 return ret;
2392}
2393
2394static int msm_pcm_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
2395 struct snd_ctl_elem_info *uinfo)
2396{
2397 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2398 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2399 /* Valid range: 0 to 0x4000(Unity) gain weightage */
2400 uinfo->value.integer.min = 0;
2401 uinfo->value.integer.max = 0x4000;
2402 return 0;
2403}
2404
2405static int msm_pcm_add_channel_mixer_weight_controls(
2406 struct snd_soc_pcm_runtime *rtd,
2407 int channel)
2408{
2409 struct snd_pcm *pcm = rtd->pcm;
2410 const char *playback_mixer_ctl_name = "AudStr";
2411 const char *capture_mixer_ctl_name = "AudStr Capture";
2412 const char *suffix = "ChMixer Weight Ch";
2413 int session_type = 0, ret = 0;
2414 struct snd_kcontrol_new channel_mixer_weight_control = {
2415 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2416 .name = "?",
2417 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2418 .info = msm_pcm_channel_mixer_weight_info,
2419 .put = msm_pcm_channel_mixer_weight_ctl_put,
2420 .get = msm_pcm_channel_mixer_weight_ctl_get,
2421 .private_value = 0,
2422 };
2423
2424 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2425 session_type = SESSION_TYPE_RX;
2426 ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
2427 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2428 if (ret < 0)
2429 goto fail;
2430 }
2431
2432 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2433 session_type = SESSION_TYPE_TX;
2434 ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
2435 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2436 if (ret < 0)
2437 goto fail;
2438 }
2439 return 0;
2440
2441fail:
2442 pr_err("%s: failed add platform ctl, err = %d\n",
2443 __func__, ret);
2444
2445 return ret;
2446}
2447
2448static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
2449{
2450 int i, ret = 0;
2451 struct snd_pcm *pcm = NULL;
2452 struct msm_plat_data *pdata = NULL;
2453 struct snd_soc_component *component = NULL;
2454
2455 if (!rtd || !rtd->pcm) {
2456 pr_err("%s invalid rtd or pcm\n", __func__);
2457 return -EINVAL;
2458 }
2459 pcm = rtd->pcm;
2460
2461 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2462 if (!component) {
2463 pr_err("%s: component is NULL\n", __func__);
2464 return -EINVAL;
2465 }
2466
2467 pdata = (struct msm_plat_data *)
2468 dev_get_drvdata(component->dev);
2469 if (!pdata) {
2470 pr_err("%s: platform data not populated\n", __func__);
2471 return -EINVAL;
2472 }
2473
2474 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream &&
2475 !pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
2476 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] =
2477 kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
2478 if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
2479 ret = -ENOMEM;
2480 goto fail;
2481 }
2482 }
2483
2484 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream &&
2485 !pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
2486 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] =
2487 kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
2488 if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
2489 ret = -ENOMEM;
2490 goto fail;
2491 }
2492 }
2493
2494 ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
2495 if (ret) {
2496 pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
2497 __func__, ret);
2498 goto fail;
2499 }
2500 ret = msm_pcm_add_channel_mixer_input_map_controls(rtd);
2501 if (ret) {
2502 pr_err("%s: pcm add channel mixer input map controls failed:%d\n",
2503 __func__, ret);
2504 goto fail;
2505 }
2506 ret = msm_pcm_add_channel_mixer_output_map_controls(rtd);
2507 if (ret) {
2508 pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
2509 __func__, ret);
2510 goto fail;
2511 }
2512
2513 for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
2514 ret = msm_pcm_add_channel_mixer_weight_controls(rtd, i);
2515 if (ret) {
2516 pr_err("%s: pcm add channel mixer weight controls failed:%d\n",
2517 __func__, ret);
2518 goto fail;
2519 }
2520 }
2521 return 0;
2522
2523fail:
2524 kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]);
2525 kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]);
2526 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] = NULL;
2527 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] = NULL;
2528
2529 return ret;
2530}
2531
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302532static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
2533{
2534 int ret = 0;
2535
2536 pr_debug("%s\n", __func__);
2537 ret = msm_pcm_add_chmap_controls(rtd);
2538 if (ret)
2539 pr_err("%s: pcm add controls failed:%d\n", __func__, ret);
2540 ret = msm_pcm_add_app_type_controls(rtd);
2541 if (ret)
2542 pr_err("%s: pcm add app type controls failed:%d\n",
2543 __func__, ret);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302544 ret = msm_pcm_add_channel_mixer_controls(rtd);
2545 if (ret)
2546 pr_err("%s: pcm add channel mixer controls failed:%d\n",
2547 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302548 return ret;
2549}
2550
2551static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
2552{
2553 struct snd_card *card = rtd->card->snd_card;
2554 int ret = 0;
2555
2556 if (!card->dev->coherent_dma_mask)
2557 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
2558
2559 ret = msm_pcm_add_controls(rtd);
2560 if (ret) {
2561 pr_err("%s, kctl add failed:%d\n", __func__, ret);
2562 return ret;
2563 }
2564
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07002565 ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_PLAYBACK);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302566 if (ret)
2567 pr_err("%s: Could not add pcm Volume Control %d\n",
2568 __func__, ret);
Haynes Mathew George86eb0ce2018-04-06 18:18:51 -07002569 ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_CAPTURE);
2570 if (ret)
2571 pr_err("%s: Could not add pcm Volume Control %d\n",
2572 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302573 ret = msm_pcm_add_compress_control(rtd);
2574 if (ret)
2575 pr_err("%s: Could not add pcm Compress Control %d\n",
2576 __func__, ret);
2577
2578 ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
2579 if (ret)
2580 pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
2581 __func__);
2582
2583 ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
2584 if (ret)
2585 pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
2586 __func__);
2587
2588 return ret;
2589}
2590
2591static snd_pcm_sframes_t msm_pcm_delay_blk(struct snd_pcm_substream *substream,
2592 struct snd_soc_dai *dai)
2593{
2594 struct snd_pcm_runtime *runtime = substream->runtime;
2595 struct msm_audio *prtd = runtime->private_data;
2596 struct audio_client *ac = prtd->audio_client;
2597 snd_pcm_sframes_t frames;
2598 int ret;
2599
2600 ret = q6asm_get_path_delay(prtd->audio_client);
2601 if (ret) {
2602 pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
2603 return 0;
2604 }
2605
2606 /* convert microseconds to frames */
2607 frames = ac->path_delay / 1000 * runtime->rate / 1000;
2608
2609 /* also convert the remainder from the initial division */
2610 frames += ac->path_delay % 1000 * runtime->rate / 1000000;
2611
2612 /* overcompensate for the loss of precision (empirical) */
2613 frames += 2;
2614
2615 return frames;
2616}
2617
Meng Wangee084a02018-09-04 16:11:58 +08002618static struct snd_soc_component_driver msm_soc_component = {
2619 .name = DRV_NAME,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302620 .ops = &msm_pcm_ops,
2621 .pcm_new = msm_asoc_pcm_new,
2622 .delay_blk = msm_pcm_delay_blk,
2623};
2624
2625static int msm_pcm_probe(struct platform_device *pdev)
2626{
2627 int rc;
2628 int id;
2629 struct msm_plat_data *pdata;
2630 const char *latency_level;
2631
2632 rc = of_property_read_u32(pdev->dev.of_node,
2633 "qcom,msm-pcm-dsp-id", &id);
2634 if (rc) {
2635 dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
2636 __func__);
2637 return rc;
2638 }
2639
2640 pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
2641 if (!pdata)
2642 return -ENOMEM;
2643
2644 if (of_property_read_bool(pdev->dev.of_node,
2645 "qcom,msm-pcm-low-latency")) {
2646
2647 pdata->perf_mode = LOW_LATENCY_PCM_MODE;
2648 rc = of_property_read_string(pdev->dev.of_node,
2649 "qcom,latency-level", &latency_level);
2650 if (!rc) {
2651 if (!strcmp(latency_level, "ultra"))
2652 pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
2653 else if (!strcmp(latency_level, "ull-pp"))
2654 pdata->perf_mode =
2655 ULL_POST_PROCESSING_PCM_MODE;
2656 }
2657 } else {
2658 pdata->perf_mode = LEGACY_PCM_MODE;
2659 }
2660
2661 dev_set_drvdata(&pdev->dev, pdata);
2662
2663
2664 dev_dbg(&pdev->dev, "%s: dev name %s\n",
2665 __func__, dev_name(&pdev->dev));
Meng Wangee084a02018-09-04 16:11:58 +08002666 return snd_soc_register_component(&pdev->dev,
2667 &msm_soc_component,
2668 NULL, 0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302669}
2670
2671static int msm_pcm_remove(struct platform_device *pdev)
2672{
2673 struct msm_plat_data *pdata;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302674 int i = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302675
2676 pdata = dev_get_drvdata(&pdev->dev);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302677 if (pdata) {
2678 for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++) {
2679 kfree(pdata->chmixer_pspd[i][SESSION_TYPE_RX]);
2680 kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
2681 }
2682 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302683 kfree(pdata);
Meng Wangee084a02018-09-04 16:11:58 +08002684 snd_soc_unregister_component(&pdev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302685 return 0;
2686}
2687static const struct of_device_id msm_pcm_dt_match[] = {
2688 {.compatible = "qcom,msm-pcm-dsp"},
2689 {}
2690};
2691MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
2692
2693static struct platform_driver msm_pcm_driver = {
2694 .driver = {
2695 .name = "msm-pcm-dsp",
2696 .owner = THIS_MODULE,
2697 .of_match_table = msm_pcm_dt_match,
2698 },
2699 .probe = msm_pcm_probe,
2700 .remove = msm_pcm_remove,
2701};
2702
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302703int __init msm_pcm_dsp_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302704{
2705 init_waitqueue_head(&the_locks.enable_wait);
2706 init_waitqueue_head(&the_locks.eos_wait);
2707 init_waitqueue_head(&the_locks.write_wait);
2708 init_waitqueue_head(&the_locks.read_wait);
2709
2710 return platform_driver_register(&msm_pcm_driver);
2711}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302712
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05302713void msm_pcm_dsp_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302714{
2715 platform_driver_unregister(&msm_pcm_driver);
2716}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302717
2718MODULE_DESCRIPTION("PCM module platform driver");
2719MODULE_LICENSE("GPL v2");