blob: a087dd822c04a9a55e8c4aa1ef234e4140657d61 [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 =
1394 vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1395 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 =
1418 vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1419 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
1439static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
1440{
1441 int ret = 0;
1442 struct snd_pcm *pcm = rtd->pcm;
1443 struct snd_pcm_volume *volume_info;
1444 struct snd_kcontrol *kctl;
1445
1446 dev_dbg(rtd->dev, "%s, Volume control add\n", __func__);
1447 ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1448 NULL, 1, rtd->dai_link->id,
1449 &volume_info);
1450 if (ret < 0) {
1451 pr_err("%s volume control failed ret %d\n", __func__, ret);
1452 return ret;
1453 }
1454 kctl = volume_info->kctl;
1455 kctl->put = msm_pcm_volume_ctl_put;
1456 kctl->get = msm_pcm_volume_ctl_get;
1457 kctl->tlv.p = msm_pcm_vol_gain;
1458 return 0;
1459}
1460
1461static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
1462 struct snd_ctl_elem_info *uinfo)
1463{
1464 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1465 uinfo->count = 1;
1466 uinfo->value.integer.min = 0;
1467 uinfo->value.integer.max = 0x2000;
1468 return 0;
1469}
1470
1471static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
1472 struct snd_ctl_elem_value *ucontrol)
1473{
Meng Wangee084a02018-09-04 16:11:58 +08001474 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
1475 struct msm_plat_data *pdata = dev_get_drvdata(comp->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301476 struct snd_pcm_substream *substream;
1477 struct msm_audio *prtd;
1478
1479 if (!pdata) {
1480 pr_err("%s pdata is NULL\n", __func__);
1481 return -ENODEV;
1482 }
1483 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1484 if (!substream) {
1485 pr_err("%s substream not found\n", __func__);
1486 return -EINVAL;
1487 }
1488 if (!substream->runtime) {
Vignesh Kulothungan2ce67842018-09-25 16:40:29 -07001489 pr_debug("%s substream runtime not found\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301490 return 0;
1491 }
1492 prtd = substream->runtime->private_data;
1493 if (prtd)
1494 ucontrol->value.integer.value[0] = prtd->compress_enable;
1495 return 0;
1496}
1497
1498static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
1499 struct snd_ctl_elem_value *ucontrol)
1500{
1501 int rc = 0;
Meng Wangee084a02018-09-04 16:11:58 +08001502 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
1503 struct msm_plat_data *pdata = dev_get_drvdata(comp->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301504 struct snd_pcm_substream *substream;
1505 struct msm_audio *prtd;
1506 int compress = ucontrol->value.integer.value[0];
1507
1508 if (!pdata) {
1509 pr_err("%s pdata is NULL\n", __func__);
1510 return -ENODEV;
1511 }
1512 substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1513 pr_debug("%s: compress : 0x%x\n", __func__, compress);
1514 if (!substream) {
1515 pr_err("%s substream not found\n", __func__);
1516 return -EINVAL;
1517 }
1518 if (!substream->runtime) {
1519 pr_err("%s substream runtime not found\n", __func__);
1520 return 0;
1521 }
1522 prtd = substream->runtime->private_data;
1523 if (prtd) {
1524 pr_debug("%s: setting compress flag to 0x%x\n",
1525 __func__, compress);
1526 prtd->compress_enable = compress;
1527 }
1528 return rc;
1529}
1530
1531static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
1532{
Meng Wangee084a02018-09-04 16:11:58 +08001533 struct snd_soc_component *component = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301534 const char *mixer_ctl_name = "Playback ";
1535 const char *mixer_ctl_end_name = " Compress";
1536 const char *deviceNo = "NN";
1537 char *mixer_str = NULL;
1538 int ctl_len;
1539 int ret = 0;
1540 struct msm_plat_data *pdata;
1541 struct snd_kcontrol_new pcm_compress_control[1] = {
1542 {
1543 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1544 .name = "?",
1545 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1546 .info = msm_pcm_compress_ctl_info,
1547 .get = msm_pcm_compress_ctl_get,
1548 .put = msm_pcm_compress_ctl_put,
1549 .private_value = 0,
1550 }
1551 };
1552
1553 if (!rtd) {
1554 pr_err("%s: NULL rtd\n", __func__);
1555 return -EINVAL;
1556 }
1557
Meng Wangee084a02018-09-04 16:11:58 +08001558 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1559 if (!component) {
1560 pr_err("%s: component is NULL\n", __func__);
1561 return -EINVAL;
1562 }
1563
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301564 ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
1565 strlen(mixer_ctl_end_name) + 1;
1566 mixer_str = kzalloc(ctl_len, GFP_KERNEL);
1567
1568 if (!mixer_str)
1569 return -ENOMEM;
1570
1571 snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
1572 rtd->pcm->device, mixer_ctl_end_name);
1573
1574 pcm_compress_control[0].name = mixer_str;
1575 pcm_compress_control[0].private_value = rtd->dai_link->id;
1576 pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
Meng Wangee084a02018-09-04 16:11:58 +08001577 pdata = dev_get_drvdata(component->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301578 if (pdata) {
1579 if (!pdata->pcm) {
1580 pdata->pcm = rtd->pcm;
Meng Wangee084a02018-09-04 16:11:58 +08001581 snd_soc_add_component_controls(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301582 pcm_compress_control,
1583 ARRAY_SIZE
1584 (pcm_compress_control));
1585 pr_debug("%s: add control success plt = %pK\n",
Meng Wangee084a02018-09-04 16:11:58 +08001586 __func__, component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301587 }
1588 } else {
1589 pr_err("%s: NULL pdata\n", __func__);
1590 ret = -EINVAL;
1591 }
1592 kfree(mixer_str);
1593 return ret;
1594}
1595
1596static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1597 struct snd_ctl_elem_value *ucontrol)
1598{
1599 int i;
1600 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1601 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1602 struct snd_pcm_substream *substream;
1603 struct msm_audio *prtd;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301604 struct snd_soc_pcm_runtime *rtd = NULL;
1605 struct msm_plat_data *pdata = NULL;
1606 struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001607 struct snd_soc_component *component = NULL;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301608 u64 fe_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301609
1610 pr_debug("%s", __func__);
1611 substream = snd_pcm_chmap_substream(info, idx);
1612 if (!substream)
1613 return -ENODEV;
1614 if (!substream->runtime)
1615 return 0;
1616
1617 prtd = substream->runtime->private_data;
1618 if (prtd) {
1619 prtd->set_channel_map = true;
Dieter Luecking70668fc2018-09-28 15:03:01 +02001620 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301621 prtd->channel_map[i] =
1622 (char)(ucontrol->value.integer.value[i]);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301623
1624 /* update chmixer_pspd chmap cached with routing driver as well */
1625 rtd = substream->private_data;
1626 if (rtd) {
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001627 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
1628 if (component) {
1629 fe_id = rtd->dai_link->id;
1630 pdata = (struct msm_plat_data *)
1631 dev_get_drvdata(component->dev);
1632 chmixer_pspd = pdata ?
1633 pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301634
Vignesh Kulothungan764b2d22019-03-21 10:54:09 -07001635 if (chmixer_pspd && chmixer_pspd->enable) {
1636 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1637 chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
1638 chmixer_pspd->override_in_ch_map = true;
1639 msm_pcm_routing_set_channel_mixer_cfg(fe_id,
1640 SESSION_TYPE_RX, chmixer_pspd);
1641 }
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301642 }
1643 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301644 }
1645 return 0;
1646}
1647
1648static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
1649 struct snd_ctl_elem_value *ucontrol)
1650{
1651 int i;
1652 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1653 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1654 struct snd_pcm_substream *substream;
1655 struct msm_audio *prtd;
1656
1657 pr_debug("%s", __func__);
1658 substream = snd_pcm_chmap_substream(info, idx);
1659 if (!substream)
1660 return -ENODEV;
1661 memset(ucontrol->value.integer.value, 0,
1662 sizeof(ucontrol->value.integer.value));
1663 if (!substream->runtime)
1664 return 0; /* no channels set */
1665
1666 prtd = substream->runtime->private_data;
1667
1668 if (prtd && prtd->set_channel_map == true) {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001669 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301670 ucontrol->value.integer.value[i] =
1671 (int)prtd->channel_map[i];
1672 } else {
Dieter Luecking70668fc2018-09-28 15:03:01 +02001673 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301674 ucontrol->value.integer.value[i] = 0;
1675 }
1676
1677 return 0;
1678}
1679
1680static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
1681{
1682 struct snd_pcm *pcm = rtd->pcm;
1683 struct snd_pcm_chmap *chmap_info;
1684 struct snd_kcontrol *kctl;
1685 char device_num[12];
1686 int i, ret = 0;
1687
1688 pr_debug("%s, Channel map cntrl add\n", __func__);
1689 ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1690 snd_pcm_std_chmaps,
Dieter Luecking70668fc2018-09-28 15:03:01 +02001691 PCM_FORMAT_MAX_NUM_CHANNEL_V8, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301692 &chmap_info);
1693 if (ret < 0) {
1694 pr_err("%s, channel map cntrl add failed\n", __func__);
1695 return ret;
1696 }
1697 kctl = chmap_info->kctl;
1698 for (i = 0; i < kctl->count; i++)
1699 kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
1700 snprintf(device_num, sizeof(device_num), "%d", pcm->device);
1701 strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
1702 pr_debug("%s, Overwriting channel map control name to: %s\n",
1703 __func__, kctl->id.name);
1704 kctl->put = msm_pcm_chmap_ctl_put;
1705 kctl->get = msm_pcm_chmap_ctl_get;
1706 return 0;
1707}
1708
1709static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1710 struct snd_ctl_elem_value *ucontrol)
1711{
1712 u64 fe_id = kcontrol->private_value;
1713 int session_type = SESSION_TYPE_RX;
1714 int be_id = ucontrol->value.integer.value[3];
1715 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1716 int ret = 0;
1717
1718 cfg_data.app_type = ucontrol->value.integer.value[0];
1719 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1720 if (ucontrol->value.integer.value[2] != 0)
1721 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1722 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1723 __func__, fe_id, session_type, be_id,
1724 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1725 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1726 be_id, &cfg_data);
1727 if (ret < 0)
1728 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1729 __func__, ret);
1730
1731 return ret;
1732}
1733
1734static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1735 struct snd_ctl_elem_value *ucontrol)
1736{
1737 u64 fe_id = kcontrol->private_value;
1738 int session_type = SESSION_TYPE_RX;
1739 int be_id = 0;
1740 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1741 int ret = 0;
1742
1743 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1744 &be_id, &cfg_data);
1745 if (ret < 0) {
1746 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1747 __func__, ret);
1748 goto done;
1749 }
1750
1751 ucontrol->value.integer.value[0] = cfg_data.app_type;
1752 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1753 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1754 ucontrol->value.integer.value[3] = be_id;
1755 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1756 __func__, fe_id, session_type, be_id,
1757 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1758done:
1759 return ret;
1760}
1761
1762static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1763 struct snd_ctl_elem_value *ucontrol)
1764{
1765 u64 fe_id = kcontrol->private_value;
1766 int session_type = SESSION_TYPE_TX;
1767 int be_id = ucontrol->value.integer.value[3];
1768 struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
1769 int ret = 0;
1770
1771 cfg_data.app_type = ucontrol->value.integer.value[0];
1772 cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
1773 if (ucontrol->value.integer.value[2] != 0)
1774 cfg_data.sample_rate = ucontrol->value.integer.value[2];
1775 pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
1776 __func__, fe_id, session_type, be_id,
1777 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1778 ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
1779 be_id, &cfg_data);
1780 if (ret < 0)
1781 pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
1782 __func__, ret);
1783
1784 return ret;
1785}
1786
1787static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
1788 struct snd_ctl_elem_value *ucontrol)
1789{
1790 u64 fe_id = kcontrol->private_value;
1791 int session_type = SESSION_TYPE_TX;
1792 int be_id = 0;
1793 struct msm_pcm_stream_app_type_cfg cfg_data = {0};
1794 int ret = 0;
1795
1796 ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
1797 &be_id, &cfg_data);
1798 if (ret < 0) {
1799 pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
1800 __func__, ret);
1801 goto done;
1802 }
1803
1804 ucontrol->value.integer.value[0] = cfg_data.app_type;
1805 ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
1806 ucontrol->value.integer.value[2] = cfg_data.sample_rate;
1807 ucontrol->value.integer.value[3] = be_id;
1808 pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
1809 __func__, fe_id, session_type, be_id,
1810 cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
1811done:
1812 return ret;
1813}
1814
1815static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
1816{
1817 struct snd_pcm *pcm = rtd->pcm;
1818 struct snd_pcm_usr *app_type_info;
1819 struct snd_kcontrol *kctl;
1820 const char *playback_mixer_ctl_name = "Audio Stream";
1821 const char *capture_mixer_ctl_name = "Audio Stream Capture";
1822 const char *deviceNo = "NN";
1823 const char *suffix = "App Type Cfg";
1824 int ctl_len, ret = 0;
1825
1826 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
1827 ctl_len = strlen(playback_mixer_ctl_name) + 1 +
1828 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1829 pr_debug("%s: Playback app type cntrl add\n", __func__);
1830 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1831 NULL, 1, ctl_len, rtd->dai_link->id,
1832 &app_type_info);
1833 if (ret < 0) {
1834 pr_err("%s: playback app type cntrl add failed: %d\n",
1835 __func__, ret);
1836 return ret;
1837 }
1838 kctl = app_type_info->kctl;
1839 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1840 playback_mixer_ctl_name, rtd->pcm->device, suffix);
1841 kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
1842 kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
1843 }
1844
1845 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
1846 ctl_len = strlen(capture_mixer_ctl_name) + 1 +
1847 strlen(deviceNo) + 1 + strlen(suffix) + 1;
1848 pr_debug("%s: Capture app type cntrl add\n", __func__);
1849 ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
1850 NULL, 1, ctl_len, rtd->dai_link->id,
1851 &app_type_info);
1852 if (ret < 0) {
1853 pr_err("%s: capture app type cntrl add failed: %d\n",
1854 __func__, ret);
1855 return ret;
1856 }
1857 kctl = app_type_info->kctl;
1858 snprintf(kctl->id.name, ctl_len, "%s %d %s",
1859 capture_mixer_ctl_name, rtd->pcm->device, suffix);
1860 kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
1861 kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
1862 }
1863
1864 return 0;
1865}
1866
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301867static struct msm_pcm_channel_mixer *msm_pcm_get_chmixer(
1868 struct msm_plat_data *pdata,
1869 u64 fe_id, int session_type)
1870{
1871 if (!pdata) {
1872 pr_err("%s: missing pdata\n", __func__);
1873 return NULL;
1874 }
1875
1876 if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
1877 pr_err("%s: invalid FE %llu\n", __func__, fe_id);
1878 return NULL;
1879 }
1880
1881 if ((session_type != SESSION_TYPE_TX) &&
1882 (session_type != SESSION_TYPE_RX)) {
1883 pr_err("%s: invalid session type %d\n", __func__, session_type);
1884 return NULL;
1885 }
1886
1887 return pdata->chmixer_pspd[fe_id][session_type];
1888}
1889
1890static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
1891 struct snd_ctl_elem_value *ucontrol)
1892{
1893 u64 fe_id = kcontrol->private_value & 0xFF;
1894 int session_type = (kcontrol->private_value >> 8) & 0xFF;
1895 int ret = 0;
1896 int stream_id = 0;
1897 int be_id = 0, i = 0;
1898 struct msm_audio *prtd = NULL;
1899 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
1900 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
1901 struct snd_pcm *pcm = NULL;
1902 struct snd_pcm_substream *substream = NULL;
1903 struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
1904 u8 asm_ch_map[PCM_FORMAT_MAX_NUM_CHANNEL_V8] = {0};
1905 bool reset_override_out_ch_map = false;
1906 bool reset_override_in_ch_map = false;
1907
1908 pcm = pdata->pcm_device[fe_id];
1909 if (!pcm) {
1910 pr_err("%s invalid pcm handle for fe_id %llu\n",
1911 __func__, fe_id);
1912 return -EINVAL;
1913 }
1914
1915 if (session_type == SESSION_TYPE_RX)
1916 substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1917 else
1918 substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
1919 if (!substream) {
1920 pr_err("%s substream not found\n", __func__);
1921 return -EINVAL;
1922 }
1923
1924 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
1925 if (!chmixer_pspd) {
1926 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
1927 return -EINVAL;
1928 }
1929
1930 chmixer_pspd->enable = ucontrol->value.integer.value[0];
1931 chmixer_pspd->rule = ucontrol->value.integer.value[1];
1932 chmixer_pspd->input_channel = ucontrol->value.integer.value[2];
1933 chmixer_pspd->output_channel = ucontrol->value.integer.value[3];
1934 chmixer_pspd->port_idx = ucontrol->value.integer.value[4];
1935
1936 if (chmixer_pspd->enable) {
1937 if (session_type == SESSION_TYPE_RX &&
1938 !chmixer_pspd->override_in_ch_map) {
1939 if (pdata->ch_map[fe_id] &&
1940 pdata->ch_map[fe_id]->set_ch_map) {
1941 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1942 chmixer_pspd->in_ch_map[i] =
1943 pdata->ch_map[fe_id]->channel_map[i];
1944 } else {
Rohit kumar2a64e522019-02-04 11:22:49 +05301945 if (chmixer_pspd->input_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
1946 pr_err("%s: Invalid channel count %d\n",
1947 __func__, chmixer_pspd->input_channel);
1948 return -EINVAL;
1949 }
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301950 q6asm_map_channels(asm_ch_map,
1951 chmixer_pspd->input_channel, false);
1952 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1953 chmixer_pspd->in_ch_map[i] = asm_ch_map[i];
1954 }
1955 chmixer_pspd->override_in_ch_map = true;
1956 reset_override_in_ch_map = true;
1957 } else if (session_type == SESSION_TYPE_TX &&
1958 !chmixer_pspd->override_out_ch_map) {
1959 if (pdata->ch_map[fe_id] &&
1960 pdata->ch_map[fe_id]->set_ch_map) {
1961 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1962 chmixer_pspd->out_ch_map[i] =
1963 pdata->ch_map[fe_id]->channel_map[i];
1964 } else {
Rohit kumar2a64e522019-02-04 11:22:49 +05301965 if (chmixer_pspd->output_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
1966 pr_err("%s: Invalid channel count %d\n",
1967 __func__, chmixer_pspd->output_channel);
1968 return -EINVAL;
1969 }
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05301970 q6asm_map_channels(asm_ch_map,
1971 chmixer_pspd->output_channel, false);
1972 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
1973 chmixer_pspd->out_ch_map[i] = asm_ch_map[i];
1974 }
1975 chmixer_pspd->override_out_ch_map = true;
1976 reset_override_out_ch_map = true;
1977 }
1978 } else {
1979 chmixer_pspd->override_out_ch_map = false;
1980 chmixer_pspd->override_in_ch_map = false;
1981 }
1982
1983 /* cache value and take effect during adm_open stage */
1984 msm_pcm_routing_set_channel_mixer_cfg(fe_id,
1985 session_type,
1986 chmixer_pspd);
1987
1988 if (chmixer_pspd->enable && substream->runtime) {
1989 prtd = substream->runtime->private_data;
1990 if (!prtd) {
1991 pr_err("%s find invalid prtd fail\n", __func__);
1992 ret = -EINVAL;
1993 goto done;
1994 }
1995
1996 if (prtd->audio_client) {
1997 stream_id = prtd->audio_client->session;
1998 be_id = chmixer_pspd->port_idx;
1999 msm_pcm_routing_set_channel_mixer_runtime(be_id,
2000 stream_id,
2001 session_type,
2002 chmixer_pspd);
2003 }
2004 }
2005
2006 if (reset_override_out_ch_map)
2007 chmixer_pspd->override_out_ch_map = false;
2008 if (reset_override_in_ch_map)
2009 chmixer_pspd->override_in_ch_map = false;
2010
2011done:
2012 return ret;
2013}
2014
2015static int msm_pcm_channel_mixer_cfg_ctl_get(struct snd_kcontrol *kcontrol,
2016 struct snd_ctl_elem_value *ucontrol)
2017{
2018 u64 fe_id = kcontrol->private_value & 0xFF;
2019 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2020 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2021 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2022 struct msm_pcm_channel_mixer *chmixer_pspd;
2023
2024 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2025 if (!chmixer_pspd) {
2026 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2027 return -EINVAL;
2028 }
2029
2030 ucontrol->value.integer.value[0] = chmixer_pspd->enable;
2031 ucontrol->value.integer.value[1] = chmixer_pspd->rule;
2032 ucontrol->value.integer.value[2] = chmixer_pspd->input_channel;
2033 ucontrol->value.integer.value[3] = chmixer_pspd->output_channel;
2034 ucontrol->value.integer.value[4] = chmixer_pspd->port_idx;
2035 return 0;
2036}
2037
2038static int msm_pcm_channel_mixer_output_map_ctl_put(
2039 struct snd_kcontrol *kcontrol,
2040 struct snd_ctl_elem_value *ucontrol)
2041{
2042 u64 fe_id = kcontrol->private_value & 0xFF;
2043 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2044 int i = 0;
2045 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2046 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2047 struct msm_pcm_channel_mixer *chmixer_pspd;
2048
2049 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2050 if (!chmixer_pspd) {
2051 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2052 return -EINVAL;
2053 }
2054
2055 chmixer_pspd->override_out_ch_map = true;
2056 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2057 chmixer_pspd->out_ch_map[i] =
2058 ucontrol->value.integer.value[i];
2059
2060 return 0;
2061}
2062
2063static int msm_pcm_channel_mixer_output_map_ctl_get(
2064 struct snd_kcontrol *kcontrol,
2065 struct snd_ctl_elem_value *ucontrol)
2066{
2067 u64 fe_id = kcontrol->private_value & 0xFF;
2068 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2069 int i = 0;
2070 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2071 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2072 struct msm_pcm_channel_mixer *chmixer_pspd;
2073
2074 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2075 if (!chmixer_pspd) {
2076 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2077 return -EINVAL;
2078 }
2079
2080 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2081 ucontrol->value.integer.value[i] =
2082 chmixer_pspd->out_ch_map[i];
2083 return 0;
2084}
2085
2086static int msm_pcm_channel_mixer_input_map_ctl_put(
2087 struct snd_kcontrol *kcontrol,
2088 struct snd_ctl_elem_value *ucontrol)
2089{
2090 u64 fe_id = kcontrol->private_value & 0xFF;
2091 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2092 int i = 0;
2093 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2094 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2095 struct msm_pcm_channel_mixer *chmixer_pspd;
2096
2097 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2098 if (!chmixer_pspd) {
2099 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2100 return -EINVAL;
2101 }
2102
2103 chmixer_pspd->override_in_ch_map = true;
2104 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2105 chmixer_pspd->in_ch_map[i] = ucontrol->value.integer.value[i];
2106
2107 return 0;
2108}
2109
2110static int msm_pcm_channel_mixer_input_map_ctl_get(
2111 struct snd_kcontrol *kcontrol,
2112 struct snd_ctl_elem_value *ucontrol)
2113{
2114 u64 fe_id = kcontrol->private_value & 0xFF;
2115 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2116 int i = 0;
2117 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2118 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2119 struct msm_pcm_channel_mixer *chmixer_pspd;
2120
2121 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2122 if (!chmixer_pspd) {
2123 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2124 return -EINVAL;
2125 }
2126
2127 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2128 ucontrol->value.integer.value[i] =
2129 chmixer_pspd->in_ch_map[i];
2130 return 0;
2131}
2132
2133static int msm_pcm_channel_mixer_weight_ctl_put(
2134 struct snd_kcontrol *kcontrol,
2135 struct snd_ctl_elem_value *ucontrol)
2136{
2137 u64 fe_id = kcontrol->private_value & 0xFF;
2138 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2139 int channel = (kcontrol->private_value >> 16) & 0xFF;
2140 int i = 0;
2141 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2142 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2143 struct msm_pcm_channel_mixer *chmixer_pspd;
2144
2145 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2146 if (!chmixer_pspd) {
2147 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2148 return -EINVAL;
2149 }
2150
2151 if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2152 pr_err("%s: invalid channel number %d\n", __func__, channel);
2153 return -EINVAL;
2154 }
2155 channel--;
2156
2157 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2158 chmixer_pspd->channel_weight[channel][i] =
2159 ucontrol->value.integer.value[i];
2160 return 0;
2161}
2162
2163static int msm_pcm_channel_mixer_weight_ctl_get(
2164 struct snd_kcontrol *kcontrol,
2165 struct snd_ctl_elem_value *ucontrol)
2166{
2167 u64 fe_id = kcontrol->private_value & 0xFF;
2168 int session_type = (kcontrol->private_value >> 8) & 0xFF;
2169 int channel = (kcontrol->private_value >> 16) & 0xFF;
2170 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
2171 struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
2172 int i = 0;
2173 struct msm_pcm_channel_mixer *chmixer_pspd;
2174
2175 if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
2176 pr_err("%s: invalid channel number %d\n", __func__, channel);
2177 return -EINVAL;
2178 }
2179 channel--;
2180
2181 chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
2182 if (!chmixer_pspd) {
2183 pr_err("%s: invalid chmixer_pspd in pdata", __func__);
2184 return -EINVAL;
2185 }
2186
2187 for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
2188 ucontrol->value.integer.value[i] =
2189 chmixer_pspd->channel_weight[channel][i];
2190 return 0;
2191}
2192
2193static int msm_pcm_add_platform_controls(struct snd_kcontrol_new *kctl,
2194 struct snd_soc_pcm_runtime *rtd, const char *name_prefix,
2195 const char *name_suffix, int session_type, int channels)
2196{
2197 int ret = -EINVAL;
2198 char *mixer_name = NULL;
2199 struct snd_pcm *pcm = rtd->pcm;
2200 const char *deviceNo = "NN";
2201 const char *channelNo = "NN";
2202 int ctl_len = 0;
2203 struct snd_soc_component *component = NULL;
2204
2205 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2206 if (!component) {
2207 pr_err("%s: component is NULL\n", __func__);
2208 return -EINVAL;
2209 }
2210
2211 ctl_len = strlen(name_prefix) + 1 + strlen(deviceNo) + 1 +
2212 strlen(channelNo) + 1 + strlen(name_suffix) + 1;
2213
2214 mixer_name = kzalloc(ctl_len, GFP_KERNEL);
2215 if (mixer_name == NULL)
2216 return -ENOMEM;
2217
2218 if (channels >= 0) {
2219 snprintf(mixer_name, ctl_len, "%s %d %s %d",
2220 name_prefix, pcm->device, name_suffix, channels);
2221 kctl->private_value = (rtd->dai_link->id) | (session_type << 8) |
2222 (channels << 16);
2223 } else {
2224 snprintf(mixer_name, ctl_len, "%s %d %s",
2225 name_prefix, pcm->device, name_suffix);
2226 kctl->private_value = (rtd->dai_link->id) | (session_type << 8);
2227 }
2228
2229 kctl->name = mixer_name;
2230 ret = snd_soc_add_component_controls(component, kctl, 1);
2231 kfree(mixer_name);
2232 return ret;
2233}
2234
2235static int msm_pcm_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
2236 struct snd_ctl_elem_info *uinfo)
2237{
2238 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2239 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2240 /* Valid channel map value ranges from 1 to 64 */
2241 uinfo->value.integer.min = 1;
2242 uinfo->value.integer.max = 64;
2243 return 0;
2244}
2245
2246static int msm_pcm_add_channel_mixer_output_map_controls(
2247 struct snd_soc_pcm_runtime *rtd)
2248{
2249 struct snd_pcm *pcm = rtd->pcm;
2250 const char *playback_mixer_ctl_name = "AudStr";
2251 const char *capture_mixer_ctl_name = "AudStr Capture";
2252 const char *suffix = "ChMixer Output Map";
2253 int session_type = 0, ret = 0, channel = -1;
2254 struct snd_kcontrol_new channel_mixer_output_map_control = {
2255 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2256 .name = "?",
2257 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2258 .info = msm_pcm_channel_mixer_output_map_info,
2259 .put = msm_pcm_channel_mixer_output_map_ctl_put,
2260 .get = msm_pcm_channel_mixer_output_map_ctl_get,
2261 .private_value = 0,
2262 };
2263
2264 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2265 session_type = SESSION_TYPE_RX;
2266 ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
2267 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2268 if (ret < 0)
2269 goto fail;
2270 }
2271
2272 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2273 session_type = SESSION_TYPE_TX;
2274 ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
2275 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2276 if (ret < 0)
2277 goto fail;
2278 }
2279 return 0;
2280
2281fail:
2282 pr_err("%s: failed add platform ctl, err = %d\n",
2283 __func__, ret);
2284 return ret;
2285}
2286
2287static int msm_pcm_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
2288 struct snd_ctl_elem_info *uinfo)
2289{
2290 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2291 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2292 /* Valid channel map value ranges from 1 to 64 */
2293 uinfo->value.integer.min = 1;
2294 uinfo->value.integer.max = 64;
2295 return 0;
2296}
2297
2298static int msm_pcm_add_channel_mixer_input_map_controls(
2299 struct snd_soc_pcm_runtime *rtd)
2300{
2301 struct snd_pcm *pcm = rtd->pcm;
2302 const char *playback_mixer_ctl_name = "AudStr";
2303 const char *capture_mixer_ctl_name = "AudStr Capture";
2304 const char *suffix = "ChMixer Input Map";
2305 int session_type = 0, ret = 0, channel = -1;
2306 struct snd_kcontrol_new channel_mixer_input_map_control = {
2307 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2308 .name = "?",
2309 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2310 .info = msm_pcm_channel_mixer_input_map_info,
2311 .put = msm_pcm_channel_mixer_input_map_ctl_put,
2312 .get = msm_pcm_channel_mixer_input_map_ctl_get,
2313 .private_value = 0,
2314 };
2315
2316 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2317 session_type = SESSION_TYPE_RX;
2318 ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
2319 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2320 if (ret < 0)
2321 goto fail;
2322 }
2323
2324 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2325 session_type = SESSION_TYPE_TX;
2326 ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
2327 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2328 if (ret < 0)
2329 goto fail;
2330 }
2331 return 0;
2332
2333fail:
2334 pr_err("%s: failed add platform ctl, err = %d\n",
2335 __func__, ret);
2336
2337 return ret;
2338}
2339
2340static int msm_pcm_channel_mixer_cfg_info(struct snd_kcontrol *kcontrol,
2341 struct snd_ctl_elem_info *uinfo)
2342{
2343 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2344 /* five int values: enable, rule, in_channels, out_channels and port_id */
2345 uinfo->count = 5;
2346 /* Valid range is all positive values to support above controls */
2347 uinfo->value.integer.min = 0;
2348 uinfo->value.integer.max = INT_MAX;
2349 return 0;
2350}
2351
2352static int msm_pcm_add_channel_mixer_cfg_controls(
2353 struct snd_soc_pcm_runtime *rtd)
2354{
2355 struct snd_pcm *pcm = rtd->pcm;
2356 const char *playback_mixer_ctl_name = "AudStr";
2357 const char *capture_mixer_ctl_name = "AudStr Capture";
2358 const char *suffix = "ChMixer Cfg";
2359 int session_type = 0, ret = 0, channel = -1;
2360 struct msm_plat_data *pdata = NULL;
2361 struct snd_soc_component *component = NULL;
2362 struct snd_kcontrol_new channel_mixer_cfg_control = {
2363 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2364 .name = "?",
2365 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2366 .info = msm_pcm_channel_mixer_cfg_info,
2367 .put = msm_pcm_channel_mixer_cfg_ctl_put,
2368 .get = msm_pcm_channel_mixer_cfg_ctl_get,
2369 .private_value = 0,
2370 };
2371
2372 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2373 if (!component) {
2374 pr_err("%s: component is NULL\n", __func__);
2375 return -EINVAL;
2376 }
2377
2378 pdata = (struct msm_plat_data *)
2379 dev_get_drvdata(component->dev);
2380
2381 pdata->pcm_device[rtd->dai_link->id] = rtd->pcm;
2382
2383 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2384 session_type = SESSION_TYPE_RX;
2385 ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
2386 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2387 if (ret < 0)
2388 goto fail;
2389 }
2390
2391 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2392 session_type = SESSION_TYPE_TX;
2393 ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
2394 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2395 if (ret < 0)
2396 goto fail;
2397 }
2398 return 0;
2399
2400fail:
2401 pr_err("%s: failed add platform ctl, err = %d\n",
2402 __func__, ret);
2403
2404 return ret;
2405}
2406
2407static int msm_pcm_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
2408 struct snd_ctl_elem_info *uinfo)
2409{
2410 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2411 uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
2412 /* Valid range: 0 to 0x4000(Unity) gain weightage */
2413 uinfo->value.integer.min = 0;
2414 uinfo->value.integer.max = 0x4000;
2415 return 0;
2416}
2417
2418static int msm_pcm_add_channel_mixer_weight_controls(
2419 struct snd_soc_pcm_runtime *rtd,
2420 int channel)
2421{
2422 struct snd_pcm *pcm = rtd->pcm;
2423 const char *playback_mixer_ctl_name = "AudStr";
2424 const char *capture_mixer_ctl_name = "AudStr Capture";
2425 const char *suffix = "ChMixer Weight Ch";
2426 int session_type = 0, ret = 0;
2427 struct snd_kcontrol_new channel_mixer_weight_control = {
2428 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2429 .name = "?",
2430 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2431 .info = msm_pcm_channel_mixer_weight_info,
2432 .put = msm_pcm_channel_mixer_weight_ctl_put,
2433 .get = msm_pcm_channel_mixer_weight_ctl_get,
2434 .private_value = 0,
2435 };
2436
2437 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
2438 session_type = SESSION_TYPE_RX;
2439 ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
2440 rtd, playback_mixer_ctl_name, suffix, session_type, channel);
2441 if (ret < 0)
2442 goto fail;
2443 }
2444
2445 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
2446 session_type = SESSION_TYPE_TX;
2447 ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
2448 rtd, capture_mixer_ctl_name, suffix, session_type, channel);
2449 if (ret < 0)
2450 goto fail;
2451 }
2452 return 0;
2453
2454fail:
2455 pr_err("%s: failed add platform ctl, err = %d\n",
2456 __func__, ret);
2457
2458 return ret;
2459}
2460
2461static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
2462{
2463 int i, ret = 0;
2464 struct snd_pcm *pcm = NULL;
2465 struct msm_plat_data *pdata = NULL;
2466 struct snd_soc_component *component = NULL;
2467
2468 if (!rtd || !rtd->pcm) {
2469 pr_err("%s invalid rtd or pcm\n", __func__);
2470 return -EINVAL;
2471 }
2472 pcm = rtd->pcm;
2473
2474 component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
2475 if (!component) {
2476 pr_err("%s: component is NULL\n", __func__);
2477 return -EINVAL;
2478 }
2479
2480 pdata = (struct msm_plat_data *)
2481 dev_get_drvdata(component->dev);
2482 if (!pdata) {
2483 pr_err("%s: platform data not populated\n", __func__);
2484 return -EINVAL;
2485 }
2486
2487 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream &&
2488 !pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
2489 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] =
2490 kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
2491 if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
2492 ret = -ENOMEM;
2493 goto fail;
2494 }
2495 }
2496
2497 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream &&
2498 !pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
2499 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] =
2500 kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
2501 if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
2502 ret = -ENOMEM;
2503 goto fail;
2504 }
2505 }
2506
2507 ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
2508 if (ret) {
2509 pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
2510 __func__, ret);
2511 goto fail;
2512 }
2513 ret = msm_pcm_add_channel_mixer_input_map_controls(rtd);
2514 if (ret) {
2515 pr_err("%s: pcm add channel mixer input map controls failed:%d\n",
2516 __func__, ret);
2517 goto fail;
2518 }
2519 ret = msm_pcm_add_channel_mixer_output_map_controls(rtd);
2520 if (ret) {
2521 pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
2522 __func__, ret);
2523 goto fail;
2524 }
2525
2526 for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
2527 ret = msm_pcm_add_channel_mixer_weight_controls(rtd, i);
2528 if (ret) {
2529 pr_err("%s: pcm add channel mixer weight controls failed:%d\n",
2530 __func__, ret);
2531 goto fail;
2532 }
2533 }
2534 return 0;
2535
2536fail:
2537 kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]);
2538 kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]);
2539 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] = NULL;
2540 pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] = NULL;
2541
2542 return ret;
2543}
2544
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302545static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
2546{
2547 int ret = 0;
2548
2549 pr_debug("%s\n", __func__);
2550 ret = msm_pcm_add_chmap_controls(rtd);
2551 if (ret)
2552 pr_err("%s: pcm add controls failed:%d\n", __func__, ret);
2553 ret = msm_pcm_add_app_type_controls(rtd);
2554 if (ret)
2555 pr_err("%s: pcm add app type controls failed:%d\n",
2556 __func__, ret);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302557 ret = msm_pcm_add_channel_mixer_controls(rtd);
2558 if (ret)
2559 pr_err("%s: pcm add channel mixer controls failed:%d\n",
2560 __func__, ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302561 return ret;
2562}
2563
2564static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
2565{
2566 struct snd_card *card = rtd->card->snd_card;
2567 int ret = 0;
2568
2569 if (!card->dev->coherent_dma_mask)
2570 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
2571
2572 ret = msm_pcm_add_controls(rtd);
2573 if (ret) {
2574 pr_err("%s, kctl add failed:%d\n", __func__, ret);
2575 return ret;
2576 }
2577
2578 ret = msm_pcm_add_volume_control(rtd);
2579 if (ret)
2580 pr_err("%s: Could not add pcm Volume Control %d\n",
2581 __func__, ret);
2582
2583 ret = msm_pcm_add_compress_control(rtd);
2584 if (ret)
2585 pr_err("%s: Could not add pcm Compress Control %d\n",
2586 __func__, ret);
2587
2588 ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
2589 if (ret)
2590 pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
2591 __func__);
2592
2593 ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
2594 if (ret)
2595 pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
2596 __func__);
2597
2598 return ret;
2599}
2600
2601static snd_pcm_sframes_t msm_pcm_delay_blk(struct snd_pcm_substream *substream,
2602 struct snd_soc_dai *dai)
2603{
2604 struct snd_pcm_runtime *runtime = substream->runtime;
2605 struct msm_audio *prtd = runtime->private_data;
2606 struct audio_client *ac = prtd->audio_client;
2607 snd_pcm_sframes_t frames;
2608 int ret;
2609
2610 ret = q6asm_get_path_delay(prtd->audio_client);
2611 if (ret) {
2612 pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
2613 return 0;
2614 }
2615
2616 /* convert microseconds to frames */
2617 frames = ac->path_delay / 1000 * runtime->rate / 1000;
2618
2619 /* also convert the remainder from the initial division */
2620 frames += ac->path_delay % 1000 * runtime->rate / 1000000;
2621
2622 /* overcompensate for the loss of precision (empirical) */
2623 frames += 2;
2624
2625 return frames;
2626}
2627
Meng Wangee084a02018-09-04 16:11:58 +08002628static struct snd_soc_component_driver msm_soc_component = {
2629 .name = DRV_NAME,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302630 .ops = &msm_pcm_ops,
2631 .pcm_new = msm_asoc_pcm_new,
2632 .delay_blk = msm_pcm_delay_blk,
2633};
2634
2635static int msm_pcm_probe(struct platform_device *pdev)
2636{
2637 int rc;
2638 int id;
2639 struct msm_plat_data *pdata;
2640 const char *latency_level;
2641
2642 rc = of_property_read_u32(pdev->dev.of_node,
2643 "qcom,msm-pcm-dsp-id", &id);
2644 if (rc) {
2645 dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
2646 __func__);
2647 return rc;
2648 }
2649
2650 pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
2651 if (!pdata)
2652 return -ENOMEM;
2653
2654 if (of_property_read_bool(pdev->dev.of_node,
2655 "qcom,msm-pcm-low-latency")) {
2656
2657 pdata->perf_mode = LOW_LATENCY_PCM_MODE;
2658 rc = of_property_read_string(pdev->dev.of_node,
2659 "qcom,latency-level", &latency_level);
2660 if (!rc) {
2661 if (!strcmp(latency_level, "ultra"))
2662 pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
2663 else if (!strcmp(latency_level, "ull-pp"))
2664 pdata->perf_mode =
2665 ULL_POST_PROCESSING_PCM_MODE;
2666 }
2667 } else {
2668 pdata->perf_mode = LEGACY_PCM_MODE;
2669 }
2670
2671 dev_set_drvdata(&pdev->dev, pdata);
2672
2673
2674 dev_dbg(&pdev->dev, "%s: dev name %s\n",
2675 __func__, dev_name(&pdev->dev));
Meng Wangee084a02018-09-04 16:11:58 +08002676 return snd_soc_register_component(&pdev->dev,
2677 &msm_soc_component,
2678 NULL, 0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302679}
2680
2681static int msm_pcm_remove(struct platform_device *pdev)
2682{
2683 struct msm_plat_data *pdata;
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302684 int i = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302685
2686 pdata = dev_get_drvdata(&pdev->dev);
Dhananjay Kumar807f7e92018-12-11 18:10:08 +05302687 if (pdata) {
2688 for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++) {
2689 kfree(pdata->chmixer_pspd[i][SESSION_TYPE_RX]);
2690 kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
2691 }
2692 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302693 kfree(pdata);
Meng Wangee084a02018-09-04 16:11:58 +08002694 snd_soc_unregister_component(&pdev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302695 return 0;
2696}
2697static const struct of_device_id msm_pcm_dt_match[] = {
2698 {.compatible = "qcom,msm-pcm-dsp"},
2699 {}
2700};
2701MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
2702
2703static struct platform_driver msm_pcm_driver = {
2704 .driver = {
2705 .name = "msm-pcm-dsp",
2706 .owner = THIS_MODULE,
2707 .of_match_table = msm_pcm_dt_match,
2708 },
2709 .probe = msm_pcm_probe,
2710 .remove = msm_pcm_remove,
2711};
2712
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302713int __init msm_pcm_dsp_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302714{
2715 init_waitqueue_head(&the_locks.enable_wait);
2716 init_waitqueue_head(&the_locks.eos_wait);
2717 init_waitqueue_head(&the_locks.write_wait);
2718 init_waitqueue_head(&the_locks.read_wait);
2719
2720 return platform_driver_register(&msm_pcm_driver);
2721}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302722
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05302723void msm_pcm_dsp_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302724{
2725 platform_driver_unregister(&msm_pcm_driver);
2726}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302727
2728MODULE_DESCRIPTION("PCM module platform driver");
2729MODULE_LICENSE("GPL v2");