blob: 0f98192a083e740e14e7d7e0db86b069918abda6 [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302/*
Soumya Managolid11d6f02020-05-27 17:25:12 +05303 * Copyright (c) 2013-2019, 2020, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304 */
5
6#include <linux/init.h>
7#include <linux/module.h>
8#include <linux/device.h>
9#include <linux/slab.h>
10#include <linux/vmalloc.h>
11#include <linux/kthread.h>
12#include <linux/platform_device.h>
13#include <linux/of.h>
14#include <linux/delay.h>
15#include <linux/sched.h>
16#include <linux/freezer.h>
17#include <sound/soc.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053018#include <sound/lsm_params.h>
19#include <sound/pcm_params.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053020#include "msm-slim-dma.h"
Soumya Managolid11d6f02020-05-27 17:25:12 +053021#include <asoc/cpe_core.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053022
Meng Wangee084a02018-09-04 16:11:58 +080023#define DRV_NAME "msm-cpe-lsm"
24
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053025#define SAMPLE_RATE_48KHZ 48000
26#define SAMPLE_RATE_16KHZ 16000
27#define LSM_VOICE_WAKEUP_APP_V2 2
28#define AFE_PORT_ID_1 1
29#define AFE_PORT_ID_3 3
30#define AFE_OUT_PORT_2 2
31#define LISTEN_MIN_NUM_PERIODS 2
32#define LISTEN_MAX_NUM_PERIODS 12
33#define LISTEN_MAX_PERIOD_SIZE 61440
34#define LISTEN_MIN_PERIOD_SIZE 320
35#define LISTEN_MAX_STATUS_PAYLOAD_SIZE 256
36#define MSM_CPE_MAX_CUSTOM_PARAM_SIZE 2048
37
38#define MSM_CPE_LAB_THREAD_TIMEOUT (3 * (HZ/10))
39
40#define MSM_CPE_LSM_GRAB_LOCK(lock, name) \
41{ \
42 pr_debug("%s: %s lock acquire\n", \
43 __func__, name); \
44 mutex_lock(lock); \
45}
46
47#define MSM_CPE_LSM_REL_LOCK(lock, name) \
48{ \
49 pr_debug("%s: %s lock release\n", \
50 __func__, name); \
51 mutex_unlock(lock); \
52}
53
54/* Conventional and unconventional sample rate supported */
55static unsigned int supported_sample_rates[] = {
56 8000, 16000, 48000, 192000, 384000
57};
58
59static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
60 .count = ARRAY_SIZE(supported_sample_rates),
61 .list = supported_sample_rates,
62 .mask = 0,
63};
64
65
66static struct snd_pcm_hardware msm_pcm_hardware_listen = {
67 .info = (SNDRV_PCM_INFO_BLOCK_TRANSFER |
68 SNDRV_PCM_INFO_MMAP_VALID |
69 SNDRV_PCM_INFO_INTERLEAVED |
70 SNDRV_PCM_INFO_PAUSE |
71 SNDRV_PCM_INFO_RESUME),
72 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
73 SNDRV_PCM_FMTBIT_S24_LE |
74 SNDRV_PCM_FMTBIT_S32_LE),
75 .rates = (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 |
76 SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000),
77 .rate_min = 16000,
78 .rate_max = 384000,
79 .channels_min = 1,
80 .channels_max = 1,
81 .buffer_bytes_max = LISTEN_MAX_NUM_PERIODS *
82 LISTEN_MAX_PERIOD_SIZE,
83 .period_bytes_min = LISTEN_MIN_PERIOD_SIZE,
84 .period_bytes_max = LISTEN_MAX_PERIOD_SIZE,
85 .periods_min = LISTEN_MIN_NUM_PERIODS,
86 .periods_max = LISTEN_MAX_NUM_PERIODS,
87 .fifo_size = 0,
88};
89
90enum {
91 AFE_CMD_INVALID = 0,
92 AFE_CMD_PORT_START,
93 AFE_CMD_PORT_SUSPEND,
94 AFE_CMD_PORT_RESUME,
95 AFE_CMD_PORT_STOP,
96};
97
98enum cpe_lab_thread_status {
99 MSM_LSM_LAB_THREAD_STOP,
100 MSM_LSM_LAB_THREAD_RUNNING,
101 MSM_LSM_LAB_THREAD_ERROR,
102};
103
104struct cpe_hw_params {
105 u32 sample_rate;
106 u16 sample_size;
107 u32 buf_sz;
108 u32 period_count;
109 u16 channels;
110};
111
112struct cpe_data_pcm_buf {
113 u8 *mem;
114 phys_addr_t phys;
115};
116
117struct cpe_lsm_lab {
118 atomic_t in_count;
119 atomic_t abort_read;
120 u32 dma_write;
121 u32 buf_idx;
122 u32 pcm_size;
123 enum cpe_lab_thread_status thread_status;
124 struct cpe_data_pcm_buf *pcm_buf;
125 wait_queue_head_t period_wait;
126 struct completion comp;
127 struct completion thread_complete;
128};
129
130struct cpe_priv {
131 void *core_handle;
132 struct snd_soc_codec *codec;
133 struct wcd_cpe_lsm_ops lsm_ops;
134 struct wcd_cpe_afe_ops afe_ops;
135 bool afe_mad_ctl;
136 u32 input_port_id;
137};
138
139struct cpe_lsm_data {
140 struct device *dev;
141 struct cpe_lsm_session *lsm_session;
142 struct mutex lsm_api_lock;
143 struct cpe_lsm_lab lab;
144 struct cpe_hw_params hw_params;
145 struct snd_pcm_substream *substream;
146
147 wait_queue_head_t event_wait;
148 atomic_t event_avail;
149 atomic_t event_stop;
150
151 u8 ev_det_status;
152 u8 ev_det_pld_size;
153 u8 *ev_det_payload;
154
155 bool cpe_prepared;
156};
157
158static int msm_cpe_afe_mad_ctl_get(struct snd_kcontrol *kcontrol,
159 struct snd_ctl_elem_value *ucontrol)
160{
161 struct cpe_priv *cpe = kcontrol->private_data;
162
163 ucontrol->value.integer.value[0] = cpe->afe_mad_ctl;
164 return 0;
165}
166
167static int msm_cpe_afe_mad_ctl_put(struct snd_kcontrol *kcontrol,
168 struct snd_ctl_elem_value *ucontrol)
169{
170 struct cpe_priv *cpe = kcontrol->private_data;
171
172 cpe->afe_mad_ctl = ucontrol->value.integer.value[0];
173 return 0;
174}
175
176static struct snd_kcontrol_new msm_cpe_kcontrols[] = {
177 SOC_SINGLE_EXT("CPE AFE MAD Enable", SND_SOC_NOPM, 0, 1, 0,
178 msm_cpe_afe_mad_ctl_get, msm_cpe_afe_mad_ctl_put),
179};
180
181/*
182 * cpe_get_private_data: obtain ASoC platform driver private data
183 * @substream: ASoC substream for which private data to be obtained
184 */
185static struct cpe_priv *cpe_get_private_data(
186 struct snd_pcm_substream *substream)
187{
188 struct snd_soc_pcm_runtime *rtd;
189
190 if (!substream || !substream->private_data) {
191 pr_err("%s: %s is invalid\n",
192 __func__,
193 (!substream) ? "substream" : "private_data");
194 goto err_ret;
195 }
196
197 rtd = substream->private_data;
198
199 if (!rtd || !rtd->platform) {
200 pr_err("%s: %s is invalid\n",
201 __func__,
202 (!rtd) ? "runtime" : "platform");
203 goto err_ret;
204 }
205
206 return snd_soc_platform_get_drvdata(rtd->platform);
207
208err_ret:
209 return NULL;
210}
211
212/*
213 * cpe_get_lsm_data: obtain the lsm session data given the substream
214 * @substream: ASoC substream for which lsm session data to be obtained
215 */
216static struct cpe_lsm_data *cpe_get_lsm_data(
217 struct snd_pcm_substream *substream)
218{
219 struct snd_pcm_runtime *runtime = substream->runtime;
220
221 return runtime->private_data;
222}
223
224static void msm_cpe_process_event_status(void *data,
225 u8 detect_status, u8 size, u8 *payload)
226{
227 struct cpe_lsm_data *lsm_d = data;
228
229 lsm_d->ev_det_status = detect_status;
230 lsm_d->ev_det_pld_size = size;
231
232 lsm_d->ev_det_payload = kzalloc(size, GFP_KERNEL);
233 if (!lsm_d->ev_det_payload)
234 return;
235
236 memcpy(lsm_d->ev_det_payload, payload, size);
237
238 atomic_set(&lsm_d->event_avail, 1);
239 wake_up(&lsm_d->event_wait);
240}
241
242static void msm_cpe_process_event_status_done(struct cpe_lsm_data *lsm_data)
243{
244 kfree(lsm_data->ev_det_payload);
245 lsm_data->ev_det_payload = NULL;
246
247 lsm_data->ev_det_status = 0;
248 lsm_data->ev_det_pld_size = 0;
249}
250
251/*
252 * msm_cpe_afe_port_cntl: Perform the afe port control
253 * @substream: substream for which afe port command to be performed
254 * @core_handle: handle to core
255 * @afe_ops: handle to the afe operations
256 * @afe_cfg: afe port configuration data
257 * @cmd: command to be sent to AFE
258 *
259 */
260static int msm_cpe_afe_port_cntl(
261 struct snd_pcm_substream *substream,
262 void *core_handle,
263 struct wcd_cpe_afe_ops *afe_ops,
264 struct wcd_cpe_afe_port_cfg *afe_cfg,
265 int cmd)
266{
267 struct snd_soc_pcm_runtime *rtd = substream->private_data;
268 int rc = 0;
269
270 if (!afe_cfg->port_id) {
271 /*
272 * It is possible driver can get closed without prepare,
273 * in which case afe ports will not be initialized.
274 */
275 dev_dbg(rtd->dev,
276 "%s: Invalid afe port id\n",
277 __func__);
278 return 0;
279 }
280
281 switch (cmd) {
282 case AFE_CMD_PORT_START:
283 rc = afe_ops->afe_port_start(core_handle, afe_cfg);
284 if (rc != 0)
285 dev_err(rtd->dev,
286 "%s: AFE port start failed\n",
287 __func__);
288 break;
289 case AFE_CMD_PORT_SUSPEND:
290 rc = afe_ops->afe_port_suspend(core_handle, afe_cfg);
291 if (rc != 0)
292 dev_err(rtd->dev,
293 "%s: afe_suspend failed, err = %d\n",
294 __func__, rc);
295 break;
296 case AFE_CMD_PORT_RESUME:
297 rc = afe_ops->afe_port_resume(core_handle, afe_cfg);
298 if (rc != 0)
299 dev_err(rtd->dev,
300 "%s: afe_resume failed, err = %d\n",
301 __func__, rc);
302 break;
303 case AFE_CMD_PORT_STOP:
304 rc = afe_ops->afe_port_stop(core_handle, afe_cfg);
305 if (rc != 0)
306 dev_err(rtd->dev,
307 "%s: afe_stopfailed, err = %d\n",
308 __func__, rc);
309 break;
310 }
311
312 return rc;
313}
314
315static int msm_cpe_lsm_lab_stop(struct snd_pcm_substream *substream)
316{
317 struct snd_soc_pcm_runtime *rtd = substream->private_data;
318 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
319 struct cpe_priv *cpe = cpe_get_private_data(substream);
320 struct wcd_cpe_lsm_ops *lsm_ops;
321 struct wcd_cpe_afe_ops *afe_ops;
322 struct cpe_lsm_session *session;
323 struct cpe_lsm_lab *lab_d = &lsm_d->lab;
324 struct msm_slim_dma_data *dma_data = NULL;
325 int rc;
326
327 /*
328 * the caller is not aware of LAB status and will
329 * try to stop lab even if it is already stopped.
330 * return success right away is LAB is already stopped
331 */
332 if (lab_d->thread_status == MSM_LSM_LAB_THREAD_STOP) {
333 dev_dbg(rtd->dev,
334 "%s: lab already stopped\n",
335 __func__);
336 return 0;
337 }
338
339 if (!cpe || !cpe->core_handle) {
340 dev_err(rtd->dev,
341 "%s: Invalid private data\n",
342 __func__);
343 return -EINVAL;
344 }
345
346 if (!lsm_d->lsm_session) {
347 dev_err(rtd->dev,
348 "%s: Invalid session data\n",
349 __func__);
350 return -EINVAL;
351 }
352
353 lsm_ops = &cpe->lsm_ops;
354 afe_ops = &cpe->afe_ops;
355 session = lsm_d->lsm_session;
356 if (rtd->cpu_dai)
357 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
358 substream);
359 if (!dma_data || !dma_data->dai_channel_ctl) {
360 dev_err(rtd->dev,
361 "%s: dma_data is not set\n",
362 __func__);
363 return -EINVAL;
364 }
365
366 if (lab_d->thread_status == MSM_LSM_LAB_THREAD_RUNNING) {
367 dev_dbg(rtd->dev, "%s: stopping lab thread\n",
368 __func__);
369 rc = kthread_stop(session->lsm_lab_thread);
370
371 /*
372 * kthread_stop returns EINTR if the thread_fn
373 * was not scheduled before calling kthread_stop.
374 * In this case, we dont need to wait for lab
375 * thread to complete as lab thread will not be
376 * scheduled at all.
377 */
378 if (rc == -EINTR)
379 goto done;
380
381 /* Wait for the lab thread to exit */
382 rc = wait_for_completion_timeout(
383 &lab_d->thread_complete,
384 MSM_CPE_LAB_THREAD_TIMEOUT);
385 if (!rc) {
386 dev_err(rtd->dev,
387 "%s: Wait for lab thread timedout\n",
388 __func__);
389 return -ETIMEDOUT;
390 }
391 }
392
393 rc = lsm_ops->lab_ch_setup(cpe->core_handle,
394 session,
395 WCD_CPE_PRE_DISABLE);
396 if (rc)
397 dev_err(rtd->dev,
398 "%s: PRE ch teardown failed, err = %d\n",
399 __func__, rc);
400 /* continue with teardown even if any intermediate step fails */
401 rc = dma_data->dai_channel_ctl(dma_data, rtd->cpu_dai, false);
402 if (rc)
403 dev_err(rtd->dev,
404 "%s: open data failed %d\n", __func__, rc);
405 dma_data->ph = 0;
406
407 /*
408 * Even though LAB stop failed,
409 * output AFE port needs to be stopped
410 */
411 rc = afe_ops->afe_port_stop(cpe->core_handle,
412 &session->afe_out_port_cfg);
413 if (rc)
414 dev_err(rtd->dev,
415 "%s: AFE out port stop failed, err = %d\n",
416 __func__, rc);
417
418 rc = lsm_ops->lab_ch_setup(cpe->core_handle,
419 session,
420 WCD_CPE_POST_DISABLE);
421 if (rc)
422 dev_err(rtd->dev,
423 "%s: POST ch teardown failed, err = %d\n",
424 __func__, rc);
425
426done:
427 lab_d->thread_status = MSM_LSM_LAB_THREAD_STOP;
428 lab_d->buf_idx = 0;
429 atomic_set(&lab_d->in_count, 0);
430 lab_d->dma_write = 0;
431
432 return 0;
433}
434
435static int msm_cpe_lab_buf_alloc(struct snd_pcm_substream *substream,
436 struct cpe_lsm_session *session,
437 struct msm_slim_dma_data *dma_data)
438{
439 struct snd_soc_pcm_runtime *rtd = substream->private_data;
440 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
441 struct cpe_lsm_lab *lab_d = &lsm_d->lab;
442 struct cpe_hw_params *hw_params = &lsm_d->hw_params;
443 struct cpe_data_pcm_buf *pcm_buf = NULL;
444 int rc = 0;
445 int dma_alloc = 0;
446 u32 count = 0;
447 u32 bufsz, bufcnt;
448
449 if (lab_d->pcm_buf &&
450 lab_d->pcm_buf->mem) {
451 dev_dbg(rtd->dev,
452 "%s: LAB buf already allocated\n",
453 __func__);
454 goto exit;
455 }
456
457 bufsz = hw_params->buf_sz;
458 bufcnt = hw_params->period_count;
459
460 dev_dbg(rtd->dev,
461 "%s:Buf Size %d Buf count %d\n",
462 __func__,
463 bufsz, bufcnt);
464
465 pcm_buf = kzalloc(((sizeof(struct cpe_data_pcm_buf)) * bufcnt),
466 GFP_KERNEL);
467 if (!pcm_buf) {
468 rc = -ENOMEM;
469 goto exit;
470 }
471
472 lab_d->pcm_buf = pcm_buf;
473 dma_alloc = bufsz * bufcnt;
474 pcm_buf->mem = NULL;
Rohit kumar42121f72018-01-02 18:17:22 +0530475 pcm_buf->mem = kzalloc(dma_alloc, GFP_DMA);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530476 if (!pcm_buf->mem) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530477 rc = -ENOMEM;
478 goto fail;
479 }
480
Rohit kumar42121f72018-01-02 18:17:22 +0530481 pcm_buf->phys = dma_map_single(dma_data->sdev->dev.parent,
482 pcm_buf->mem, dma_alloc, DMA_BIDIRECTIONAL);
483 if (dma_mapping_error(dma_data->sdev->dev.parent, pcm_buf->phys)) {
484 dev_err(rtd->dev, "%s Error mapping DMA buffers\n", __func__);
485 pcm_buf->phys = (phys_addr_t)NULL;
486 rc = -EFAULT;
487 goto fail;
488 }
489
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530490 count = 0;
491 while (count < bufcnt) {
492 pcm_buf[count].mem = pcm_buf[0].mem + (count * bufsz);
493 pcm_buf[count].phys = pcm_buf[0].phys + (count * bufsz);
494 dev_dbg(rtd->dev,
495 "%s: pcm_buf[%d].mem %pK pcm_buf[%d].phys %pK\n",
496 __func__, count,
497 (void *)pcm_buf[count].mem,
498 count, &(pcm_buf[count].phys));
499 count++;
500 }
501
502 return 0;
503fail:
Rohit kumar42121f72018-01-02 18:17:22 +0530504 if (pcm_buf && pcm_buf->mem)
505 kfree(pcm_buf->mem);
506 kfree(pcm_buf);
507 lab_d->pcm_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530508exit:
509 return rc;
510}
511
512static int msm_cpe_lab_buf_dealloc(struct snd_pcm_substream *substream,
513 struct cpe_lsm_session *session, struct msm_slim_dma_data *dma_data)
514{
515 struct snd_soc_pcm_runtime *rtd = substream->private_data;
516 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
517 struct cpe_lsm_lab *lab_d = &lsm_d->lab;
518 struct cpe_hw_params *hw_params = &lsm_d->hw_params;
519 int rc = 0;
520 int dma_alloc = 0;
521 struct cpe_data_pcm_buf *pcm_buf = NULL;
522 int bufsz, bufcnt;
523
524 bufsz = hw_params->buf_sz;
525 bufcnt = hw_params->period_count;
526
527 dev_dbg(rtd->dev,
528 "%s:Buf Size %d Buf count %d\n", __func__,
529 bufsz, bufcnt);
530
531 if (bufcnt <= 0 || bufsz <= 0) {
532 dev_err(rtd->dev,
533 "%s: Invalid params, bufsz = %u, bufcnt = %u\n",
534 __func__, bufsz, bufcnt);
535 return -EINVAL;
536 }
537
538 pcm_buf = lab_d->pcm_buf;
539 dma_alloc = bufsz * bufcnt;
540 if (dma_data && pcm_buf)
Rohit kumar42121f72018-01-02 18:17:22 +0530541 if (pcm_buf->phys)
542 dma_unmap_single(dma_data->sdev->dev.parent,
543 pcm_buf->phys, dma_alloc, DMA_BIDIRECTIONAL);
544 if (pcm_buf)
545 kfree(pcm_buf->mem);
546
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530547 kfree(pcm_buf);
548 lab_d->pcm_buf = NULL;
549 return rc;
550}
551
552/*
553 * msm_cpe_lab_thread: Initiated on KW detection
554 * @data: lab data
555 *
556 * Start lab thread and call CPE core API for SLIM
557 * read operations.
558 */
559static int msm_cpe_lab_thread(void *data)
560{
561 struct cpe_lsm_data *lsm_d = data;
562 struct cpe_lsm_session *session = lsm_d->lsm_session;
563 struct snd_pcm_substream *substream = lsm_d->substream;
564 struct cpe_lsm_lab *lab_d = &lsm_d->lab;
565 struct cpe_hw_params *hw_params = &lsm_d->hw_params;
566 struct cpe_priv *cpe = cpe_get_private_data(substream);
567 struct wcd_cpe_lsm_ops *lsm_ops;
568 struct wcd_cpe_afe_ops *afe_ops;
569 struct cpe_data_pcm_buf *cur_buf, *next_buf;
570 struct msm_slim_dma_data *dma_data = NULL;
571 struct snd_soc_pcm_runtime *rtd = NULL;
572 bool wait_timedout = false;
573 int rc = 0;
574 u32 done_len = 0;
575 u32 buf_count = 0;
576 u32 prd_cnt;
577
578 allow_signal(SIGKILL);
579 set_current_state(TASK_INTERRUPTIBLE);
580
581 pr_debug("%s: Lab thread start\n", __func__);
582 init_completion(&lab_d->comp);
583
584 if (PCM_RUNTIME_CHECK(substream)) {
585 rc = -EINVAL;
586 goto done;
587 }
588
589 if (!cpe || !cpe->core_handle) {
590 pr_err("%s: Handle to %s is invalid\n",
591 __func__,
592 (!cpe) ? "cpe" : "core");
593 rc = -EINVAL;
594 goto done;
595 }
596
597 rtd = substream->private_data;
598 if (rtd->cpu_dai)
599 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
600 substream);
601 if (!dma_data || !dma_data->dai_channel_ctl) {
602 pr_err("%s: dma_data is not set\n", __func__);
603 rc = -EINVAL;
604 goto done;
605 }
606
607 lsm_ops = &cpe->lsm_ops;
608 afe_ops = &cpe->afe_ops;
609
610 rc = lsm_ops->lab_ch_setup(cpe->core_handle,
611 session,
612 WCD_CPE_PRE_ENABLE);
613 if (rc) {
614 dev_err(rtd->dev,
615 "%s: PRE ch setup failed, err = %d\n",
616 __func__, rc);
617 goto done;
618 }
619
620 rc = dma_data->dai_channel_ctl(dma_data, rtd->cpu_dai, true);
621 if (rc) {
622 dev_err(rtd->dev,
623 "%s: open data failed %d\n", __func__, rc);
624 goto done;
625 }
626
627 dev_dbg(rtd->dev, "%s: Established data channel\n",
628 __func__);
629
630 init_waitqueue_head(&lab_d->period_wait);
631 memset(lab_d->pcm_buf[0].mem, 0, lab_d->pcm_size);
632
633 rc = slim_port_xfer(dma_data->sdev, dma_data->ph,
Rohit kumar42121f72018-01-02 18:17:22 +0530634 lab_d->pcm_buf[0].mem,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530635 hw_params->buf_sz, &lab_d->comp);
636 if (rc) {
637 dev_err(rtd->dev,
638 "%s: buf[0] slim_port_xfer failed, err = %d\n",
639 __func__, rc);
640 goto done;
641 }
642
643 rc = slim_port_xfer(dma_data->sdev, dma_data->ph,
Rohit kumar42121f72018-01-02 18:17:22 +0530644 lab_d->pcm_buf[1].mem,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530645 hw_params->buf_sz, &lab_d->comp);
646 if (rc) {
647 dev_err(rtd->dev,
648 "%s: buf[0] slim_port_xfer failed, err = %d\n",
649 __func__, rc);
650 goto done;
651 }
652
653 cur_buf = &lab_d->pcm_buf[0];
654 next_buf = &lab_d->pcm_buf[2];
655 prd_cnt = hw_params->period_count;
656 rc = lsm_ops->lab_ch_setup(cpe->core_handle,
657 session,
658 WCD_CPE_POST_ENABLE);
659 if (rc) {
660 dev_err(rtd->dev,
661 "%s: POST ch setup failed, err = %d\n",
662 __func__, rc);
663 goto done;
664 }
665
666 rc = afe_ops->afe_port_start(cpe->core_handle,
667 &session->afe_out_port_cfg);
668 if (rc) {
669 dev_err(rtd->dev,
670 "%s: AFE out port start failed, err = %d\n",
671 __func__, rc);
672 goto done;
673 }
674
675 while (!kthread_should_stop() &&
676 lab_d->thread_status != MSM_LSM_LAB_THREAD_ERROR) {
677
678 rc = slim_port_xfer(dma_data->sdev, dma_data->ph,
Rohit kumar42121f72018-01-02 18:17:22 +0530679 next_buf->mem,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530680 hw_params->buf_sz, &lab_d->comp);
681 if (rc) {
682 dev_err(rtd->dev,
683 "%s: slim_port_xfer failed, err = %d\n",
684 __func__, rc);
685 lab_d->thread_status = MSM_LSM_LAB_THREAD_ERROR;
686 }
687
688 rc = wait_for_completion_timeout(&lab_d->comp, (2 * HZ/10));
689 if (!rc) {
690 dev_err(rtd->dev,
691 "%s: wait timedout for slim buffer\n",
692 __func__);
693 wait_timedout = true;
694 } else {
695 wait_timedout = false;
696 }
697
698 rc = slim_port_get_xfer_status(dma_data->sdev,
699 dma_data->ph,
700 &cur_buf->phys, &done_len);
701 if (rc ||
702 (!rc && wait_timedout)) {
703 dev_err(rtd->dev,
704 "%s: xfer_status failure, rc = %d, wait_timedout = %s\n",
705 __func__, rc,
706 (wait_timedout ? "true" : "false"));
707 lab_d->thread_status = MSM_LSM_LAB_THREAD_ERROR;
708 }
709
710 if (done_len ||
711 ((!done_len) &&
712 lab_d->thread_status == MSM_LSM_LAB_THREAD_ERROR)) {
713 atomic_inc(&lab_d->in_count);
714 lab_d->dma_write += snd_pcm_lib_period_bytes(substream);
715 snd_pcm_period_elapsed(substream);
716 wake_up(&lab_d->period_wait);
717 buf_count++;
718
719 cur_buf = &lab_d->pcm_buf[buf_count % prd_cnt];
720 next_buf = &lab_d->pcm_buf[(buf_count + 2) % prd_cnt];
721 dev_dbg(rtd->dev,
722 "%s: Cur buf.mem = %pK Next Buf.mem = %pK\n"
723 " buf count = 0x%x\n", __func__,
724 cur_buf->mem, next_buf->mem, buf_count);
725 } else {
726 dev_err(rtd->dev,
727 "%s: SB get status, invalid len = 0x%x\n",
728 __func__, done_len);
729 }
730 done_len = 0;
731 }
732
733done:
734 if (rc)
735 lab_d->thread_status = MSM_LSM_LAB_THREAD_ERROR;
736 pr_debug("%s: Exit lab_thread, exit_status=%d, thread_status=%d\n",
737 __func__, rc, lab_d->thread_status);
738 complete(&lab_d->thread_complete);
739
740 return 0;
741}
742
743/*
744 * msm_cpe_lsm_open: ASoC call to open the stream
745 * @substream: substream that is to be opened
746 *
747 * Create session data for lsm session and open the lsm session
748 * on CPE.
749 */
750static int msm_cpe_lsm_open(struct snd_pcm_substream *substream)
751{
752 struct cpe_lsm_data *lsm_d;
753 struct snd_pcm_runtime *runtime = substream->runtime;
754 struct snd_soc_pcm_runtime *rtd = substream->private_data;
755 struct cpe_priv *cpe = cpe_get_private_data(substream);
756 struct wcd_cpe_lsm_ops *lsm_ops;
757 int rc = 0;
758
759 if (!cpe || !cpe->codec) {
760 dev_err(rtd->dev,
761 "%s: Invalid private data\n",
762 __func__);
763 return -EINVAL;
764 }
765
766 runtime->hw = msm_pcm_hardware_listen;
767
768 rc = snd_pcm_hw_constraint_list(runtime, 0,
769 SNDRV_PCM_HW_PARAM_RATE,
770 &constraints_sample_rates);
771 if (rc < 0) {
772 pr_err("snd_pcm_hw_constraint_list failed rc %d\n", rc);
773 return -EINVAL;
774 }
775
776 /* Ensure that buffer size is a multiple of period size */
777 rc = snd_pcm_hw_constraint_integer(runtime,
778 SNDRV_PCM_HW_PARAM_PERIODS);
779 if (rc < 0) {
780 pr_err("%s: Unable to set pcm_param_periods, rc %d\n",
781 __func__, rc);
782 return -EINVAL;
783 }
784
785 rc = snd_pcm_hw_constraint_minmax(runtime,
786 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
787 LISTEN_MIN_NUM_PERIODS * LISTEN_MIN_PERIOD_SIZE,
788 LISTEN_MAX_NUM_PERIODS * LISTEN_MAX_PERIOD_SIZE);
789 if (rc < 0) {
790 pr_err("%s: Unable to set pcm constraints, rc %d\n",
791 __func__, rc);
792 return -EINVAL;
793 }
794
795 cpe->core_handle = wcd_cpe_get_core_handle(cpe->codec);
796
797 if (!cpe->core_handle) {
798 dev_err(rtd->dev,
799 "%s: Invalid handle to codec core\n",
800 __func__);
801 return -EINVAL;
802 }
803
804 lsm_ops = &cpe->lsm_ops;
805 lsm_d = kzalloc(sizeof(struct cpe_lsm_data), GFP_KERNEL);
806 if (!lsm_d) {
807 dev_err(rtd->dev,
808 "%s: ENOMEM for lsm session, size = %zd\n",
809 __func__, sizeof(struct cpe_lsm_data));
810 rc = -ENOMEM;
811 goto fail_return;
812 }
813 mutex_init(&lsm_d->lsm_api_lock);
814
815 lsm_d->lsm_session = lsm_ops->lsm_alloc_session(cpe->core_handle,
816 lsm_d, msm_cpe_process_event_status);
817 if (!lsm_d->lsm_session) {
818 dev_err(rtd->dev,
819 "%s: session allocation failed",
820 __func__);
821 rc = -EINVAL;
822 goto fail_session_alloc;
823 }
824 /* Explicitly Assign the LAB thread to STOP state */
825 lsm_d->lab.thread_status = MSM_LSM_LAB_THREAD_STOP;
826 lsm_d->lsm_session->started = false;
827 lsm_d->substream = substream;
828 init_waitqueue_head(&lsm_d->lab.period_wait);
829 lsm_d->cpe_prepared = false;
830
831 dev_dbg(rtd->dev, "%s: allocated session with id = %d\n",
832 __func__, lsm_d->lsm_session->id);
833
834
835 rc = lsm_ops->lsm_open_tx(cpe->core_handle, lsm_d->lsm_session,
836 LSM_VOICE_WAKEUP_APP_V2, 16000);
837 if (rc < 0) {
838 dev_err(rtd->dev,
839 "%s: OPEN_TX cmd failed, err = %d\n",
840 __func__, rc);
841 goto fail_open_tx;
842 }
843
844 init_waitqueue_head(&lsm_d->event_wait);
845 atomic_set(&lsm_d->event_avail, 0);
846 atomic_set(&lsm_d->event_stop, 0);
847 runtime->private_data = lsm_d;
848
849 return 0;
850
851fail_open_tx:
852 lsm_ops->lsm_dealloc_session(cpe->core_handle, lsm_d->lsm_session);
853
854fail_session_alloc:
855 mutex_destroy(&lsm_d->lsm_api_lock);
856 kfree(lsm_d);
857fail_return:
858 return rc;
859}
860
861/*
862 * msm_cpe_lsm_close: ASoC call to close/cleanup the stream
863 * @substream: substream that is to be closed
864 *
865 * Deallocate the session and release the AFE port. It is not
866 * required to deregister the sound model as long as we close
867 * the lsm session on CPE.
868 */
869static int msm_cpe_lsm_close(struct snd_pcm_substream *substream)
870{
871 struct snd_pcm_runtime *runtime = substream->runtime;
872 struct snd_soc_pcm_runtime *rtd = substream->private_data;
873 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
874 struct cpe_priv *cpe = cpe_get_private_data(substream);
875 struct wcd_cpe_lsm_ops *lsm_ops;
876 struct cpe_lsm_session *session;
877 struct wcd_cpe_afe_ops *afe_ops;
878 struct wcd_cpe_afe_port_cfg *afe_cfg;
879 int rc = 0;
880
881 if (!cpe || !cpe->core_handle) {
882 dev_err(rtd->dev,
883 "%s: Invalid private data\n",
884 __func__);
885 return -EINVAL;
886 }
887
888 if (!lsm_d || !lsm_d->lsm_session) {
889 dev_err(rtd->dev,
890 "%s: Invalid session data\n",
891 __func__);
892 return -EINVAL;
893 }
894
895 lsm_ops = &cpe->lsm_ops;
896 session = lsm_d->lsm_session;
897 afe_ops = &cpe->afe_ops;
898 afe_cfg = &(lsm_d->lsm_session->afe_port_cfg);
899
900 /*
901 * If driver is closed without stopping LAB,
902 * explicitly stop LAB before cleaning up the
903 * driver resources.
904 */
905 rc = msm_cpe_lsm_lab_stop(substream);
906 if (rc) {
907 dev_err(rtd->dev,
908 "%s: Failed to stop lab, error = %d\n",
909 __func__, rc);
910 return rc;
911 }
912
913 rc = msm_cpe_afe_port_cntl(substream,
914 cpe->core_handle,
915 afe_ops, afe_cfg,
916 AFE_CMD_PORT_STOP);
917
918 lsm_d->cpe_prepared = false;
919
920 rc = lsm_ops->lsm_close_tx(cpe->core_handle, session);
921 if (rc != 0) {
922 dev_err(rtd->dev,
923 "%s: lsm_close fail, err = %d\n",
924 __func__, rc);
925 return rc;
926 }
927
928 lsm_ops->lsm_dealloc_session(cpe->core_handle, session);
929 runtime->private_data = NULL;
930 mutex_destroy(&lsm_d->lsm_api_lock);
931 kfree(lsm_d);
932
933 return rc;
934}
935
936static int msm_cpe_lsm_get_conf_levels(
937 struct cpe_lsm_session *session,
938 u8 *conf_levels_ptr)
939{
940 int rc = 0;
941
942 if (session->num_confidence_levels <= 0) {
943 pr_debug("%s: conf_levels (%u), skip set params\n",
944 __func__,
945 session->num_confidence_levels);
946 goto done;
947 }
948
949 session->conf_levels = kzalloc(session->num_confidence_levels,
950 GFP_KERNEL);
951 if (!session->conf_levels) {
952 rc = -ENOMEM;
953 goto done;
954 }
955
956 if (copy_from_user(session->conf_levels,
957 conf_levels_ptr,
958 session->num_confidence_levels)) {
959 pr_err("%s: copy_from_user failed for confidence levels %u\n",
960 __func__, session->num_confidence_levels);
961 kfree(session->conf_levels);
962 session->conf_levels = NULL;
963 rc = -EFAULT;
964 goto done;
965 }
966
967done:
968 return rc;
969}
970
971static int msm_cpe_lsm_validate_out_format(
972 struct snd_pcm_substream *substream,
973 struct snd_lsm_output_format_cfg *cfg)
974{
975 struct snd_soc_pcm_runtime *rtd = substream->private_data;
976 int rc = 0;
977
978 if (!cfg) {
979 dev_err(rtd->dev,
980 "%s: Invalid lsm out cfg\n", __func__);
981 rc = -EINVAL;
982 goto done;
983 }
984
985 if (cfg->format != LSM_OUT_FORMAT_PCM &&
986 cfg->format != LSM_OUT_FORMAT_ADPCM) {
987 dev_err(rtd->dev,
988 "%s: Invalid format %u\n",
989 __func__, cfg->format);
990 rc = -EINVAL;
991 goto done;
992 }
993
994 if (cfg->packing != LSM_OUT_DATA_RAW &&
995 cfg->packing != LSM_OUT_DATA_PACKED) {
996 dev_err(rtd->dev,
997 "%s: Invalid packing method %u\n",
998 __func__, cfg->packing);
999 rc = -EINVAL;
1000 goto done;
1001 }
1002
1003 if (cfg->events != LSM_OUT_DATA_EVENTS_DISABLED &&
1004 cfg->events != LSM_OUT_DATA_EVENTS_ENABLED) {
1005 dev_err(rtd->dev,
1006 "%s: Invalid events provided %u\n",
1007 __func__, cfg->events);
1008 rc = -EINVAL;
1009 goto done;
1010 }
1011
1012 if (cfg->mode != LSM_OUT_TRANSFER_MODE_RT &&
1013 cfg->mode != LSM_OUT_TRANSFER_MODE_FTRT) {
1014 dev_err(rtd->dev,
1015 "%s: Invalid transfer mode %u\n",
1016 __func__, cfg->mode);
1017 rc = -EINVAL;
1018 goto done;
1019 }
1020
1021done:
1022 return rc;
1023}
1024
1025/*
1026 * msm_cpe_lsm_ioctl_shared: Shared IOCTL for this platform driver
1027 * @substream: ASoC substream for which the operation is invoked
1028 * @cmd: command for the ioctl
1029 * @arg: argument for the ioctl
1030 *
1031 * Perform dedicated listen functions like register sound model,
1032 * deregister sound model, etc
1033 * Called with lsm_api_lock acquired.
1034 */
1035static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream,
1036 unsigned int cmd, void *arg)
1037{
1038 struct snd_lsm_sound_model_v2 snd_model;
1039 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1040 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
1041 struct cpe_priv *cpe = cpe_get_private_data(substream);
1042 struct cpe_lsm_session *session;
1043 struct wcd_cpe_lsm_ops *lsm_ops;
1044 struct cpe_lsm_lab *lab_d = &lsm_d->lab;
1045 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
1046 struct msm_slim_dma_data *dma_data = NULL;
1047 struct snd_lsm_detection_params det_params;
1048 int rc = 0;
1049
1050 if (!cpe || !cpe->core_handle) {
1051 dev_err(rtd->dev,
1052 "%s: Invalid private data\n",
1053 __func__);
1054 return -EINVAL;
1055 }
1056
1057 if (!lsm_d || !lsm_d->lsm_session) {
1058 dev_err(rtd->dev,
1059 "%s: Invalid session data\n",
1060 __func__);
1061 return -EINVAL;
1062 }
1063
1064 session = lsm_d->lsm_session;
1065 lsm_ops = &cpe->lsm_ops;
1066
1067 switch (cmd) {
1068 case SNDRV_LSM_STOP_LAB:
1069 dev_dbg(rtd->dev,
1070 "%s: %s, lab_enable = %d, lab_thread_ststus = %d\n",
1071 __func__, "SNDRV_LSM_STOP_LAB",
1072 session->lab_enable,
1073 lab_d->thread_status);
1074
1075 if (session->lab_enable &&
1076 lab_d->thread_status != MSM_LSM_LAB_THREAD_STOP) {
1077 atomic_inc(&lab_d->abort_read);
1078 wake_up(&lab_d->period_wait);
1079 rc = msm_cpe_lsm_lab_stop(substream);
1080 if (rc) {
1081 dev_err(rtd->dev,
1082 "%s: stop LAB failed, error = %d\n",
1083 __func__, rc);
1084 return rc;
1085 }
1086 } else if (!session->lab_enable) {
1087 dev_dbg(rtd->dev,
1088 "%s: LAB already stopped\n",
1089 __func__);
1090 }
1091
1092 break;
1093
1094 case SNDRV_LSM_LAB_CONTROL:
1095 if (copy_from_user(&session->lab_enable, (void *)arg,
1096 sizeof(u32))) {
1097 dev_err(rtd->dev,
1098 "%s: copy_from_user failed, size %zd\n",
1099 __func__, sizeof(u32));
1100 return -EFAULT;
1101 }
1102
1103 dev_dbg(rtd->dev,
1104 "%s: %s, lab_enable = %d\n",
1105 __func__, "SNDRV_LSM_LAB_CONTROL",
1106 session->lab_enable);
1107 if (rtd->cpu_dai)
1108 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
1109 substream);
1110 if (!dma_data || !dma_data->dai_channel_ctl) {
1111 dev_err(rtd->dev,
1112 "%s: dma_data is not set\n", __func__);
1113 return -EINVAL;
1114 }
1115
1116 if (session->lab_enable) {
1117 rc = msm_cpe_lab_buf_alloc(substream,
1118 session, dma_data);
1119 if (rc < 0) {
1120 dev_err(rtd->dev,
1121 "%s: lab buffer alloc failed, err = %d\n",
1122 __func__, rc);
1123 return rc;
1124 }
1125
1126 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
1127 dma_buf->dev.dev = substream->pcm->card->dev;
1128 dma_buf->private_data = NULL;
1129 dma_buf->area = lab_d->pcm_buf[0].mem;
1130 dma_buf->addr = lab_d->pcm_buf[0].phys;
1131 dma_buf->bytes = (lsm_d->hw_params.buf_sz *
1132 lsm_d->hw_params.period_count);
1133 init_completion(&lab_d->thread_complete);
1134 snd_pcm_set_runtime_buffer(substream,
1135 &substream->dma_buffer);
1136 rc = lsm_ops->lsm_lab_control(cpe->core_handle,
1137 session, true);
1138 if (rc < 0) {
1139 dev_err(rtd->dev,
1140 "%s: Lab Enable Failed rc %d\n",
1141 __func__, rc);
1142 return rc;
1143 }
1144 } else {
1145 /*
1146 * It is possible that lab is still enabled
1147 * when trying to de-allocate the lab buffer.
1148 * Make sure to disable lab before de-allocating
1149 * the lab buffer.
1150 */
1151 rc = msm_cpe_lsm_lab_stop(substream);
1152 if (rc < 0) {
1153 dev_err(rtd->dev,
1154 "%s: LAB stop failed, error = %d\n",
1155 __func__, rc);
1156 return rc;
1157 }
1158 /*
1159 * Buffer has to be de-allocated even if
1160 * lab_control failed.
1161 */
1162 rc = msm_cpe_lab_buf_dealloc(substream,
1163 session, dma_data);
1164 if (rc < 0) {
1165 dev_err(rtd->dev,
1166 "%s: lab buffer free failed, err = %d\n",
1167 __func__, rc);
1168 return rc;
1169 }
1170 }
1171 break;
1172 case SNDRV_LSM_REG_SND_MODEL_V2:
1173 dev_dbg(rtd->dev,
1174 "%s: %s\n",
1175 __func__, "SNDRV_LSM_REG_SND_MODEL_V2");
1176
1177 memcpy(&snd_model, arg,
1178 sizeof(struct snd_lsm_sound_model_v2));
1179
1180 session->num_confidence_levels =
1181 snd_model.num_confidence_levels;
1182 rc = msm_cpe_lsm_get_conf_levels(session,
1183 snd_model.confidence_level);
1184 if (rc) {
1185 dev_err(rtd->dev,
1186 "%s: %s get_conf_levels fail, err = %d\n",
1187 __func__, "SNDRV_LSM_REG_SND_MODEL_V2",
1188 rc);
1189 break;
1190 }
1191
1192 session->snd_model_data = kzalloc(snd_model.data_size,
1193 GFP_KERNEL);
1194 if (!session->snd_model_data) {
1195 kfree(session->conf_levels);
1196 session->conf_levels = NULL;
1197 return -ENOMEM;
1198 }
1199 session->snd_model_size = snd_model.data_size;
1200
1201 if (copy_from_user(session->snd_model_data,
1202 snd_model.data, snd_model.data_size)) {
1203 dev_err(rtd->dev,
1204 "%s: copy_from_user failed for snd_model\n",
1205 __func__);
1206 kfree(session->conf_levels);
1207 kfree(session->snd_model_data);
1208 session->conf_levels = NULL;
1209 session->snd_model_data = NULL;
1210 return -EFAULT;
1211 }
1212
1213 rc = lsm_ops->lsm_shmem_alloc(cpe->core_handle, session,
1214 session->snd_model_size);
1215 if (rc != 0) {
1216 dev_err(rtd->dev,
1217 "%s: shared memory allocation failed, err = %d\n",
1218 __func__, rc);
1219 kfree(session->snd_model_data);
1220 kfree(session->conf_levels);
1221 session->snd_model_data = NULL;
1222 session->conf_levels = NULL;
1223 return rc;
1224 }
1225
1226 rc = lsm_ops->lsm_register_snd_model(cpe->core_handle, session,
1227 snd_model.detection_mode,
1228 snd_model.detect_failure);
1229 if (rc != 0) {
1230 dev_err(rtd->dev,
1231 "%s: snd_model_reg failed, err = %d\n",
1232 __func__, rc);
1233 lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
1234 kfree(session->snd_model_data);
1235 kfree(session->conf_levels);
1236 session->snd_model_data = NULL;
1237 session->conf_levels = NULL;
1238 return rc;
1239 }
1240
1241 break;
1242
1243 case SNDRV_LSM_DEREG_SND_MODEL:
1244 dev_dbg(rtd->dev,
1245 "%s: %s\n",
1246 __func__, "SNDRV_LSM_DEREG_SND_MODEL");
1247
1248 if (session->lab_enable) {
1249 /*
1250 * It is possible that lab is still enabled
1251 * when trying to deregister sound model.
1252 * Make sure to disable lab before de-allocating
1253 * the lab buffer.
1254 */
1255 rc = msm_cpe_lsm_lab_stop(substream);
1256 if (rc) {
1257 dev_err(rtd->dev,
1258 "%s: LAB stop failed, error = %d\n",
1259 __func__, rc);
1260 return rc;
1261 }
1262
1263 rc = lsm_ops->lsm_lab_control(cpe->core_handle,
1264 session, false);
1265 if (rc)
1266 dev_err(rtd->dev,
1267 "%s: Lab Disable Failed rc %d\n",
1268 __func__, rc);
1269
1270 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai,
1271 substream);
1272 if (!dma_data || !dma_data->dai_channel_ctl)
1273 dev_err(rtd->dev,
1274 "%s: dma_data is not set\n", __func__);
1275
1276 /*
1277 * Buffer has to be de-allocated even if
1278 * lab_control failed and/or dma data is invalid.
1279 */
1280 rc = msm_cpe_lab_buf_dealloc(substream,
1281 session, dma_data);
1282 if (rc < 0)
1283 dev_err(rtd->dev,
1284 "%s: lab buffer free failed, err = %d\n",
1285 __func__, rc);
1286 }
1287
1288 rc = lsm_ops->lsm_deregister_snd_model(
1289 cpe->core_handle, session);
1290 if (rc != 0) {
1291 dev_err(rtd->dev,
1292 "%s: snd_model de-reg failed, err = %d\n",
1293 __func__, rc);
1294 return rc;
1295 }
1296
1297 kfree(session->snd_model_data);
1298 kfree(session->conf_levels);
1299 session->snd_model_data = NULL;
1300 session->conf_levels = NULL;
1301
1302 rc = lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
1303 if (rc != 0) {
1304 dev_err(rtd->dev,
1305 "%s: LSM shared memory dealloc failed, err = %d\n",
1306 __func__, rc);
1307 return rc;
1308 }
1309
1310 break;
1311
1312 case SNDRV_LSM_EVENT_STATUS:
1313 case SNDRV_LSM_EVENT_STATUS_V3: {
1314 struct snd_lsm_event_status *user;
1315 struct snd_lsm_event_status_v3 *user_v3;
1316
1317 dev_dbg(rtd->dev,
1318 "%s: %s\n",
1319 __func__, "SNDRV_LSM_EVENT_STATUS(_V3)");
1320 if (!arg) {
1321 dev_err(rtd->dev,
1322 "%s: Invalid argument to ioctl %s\n",
1323 __func__,
1324 "SNDRV_LSM_EVENT_STATUS(_V3)");
1325 return -EINVAL;
1326 }
1327
1328 /*
1329 * Release the api lock before wait to allow
1330 * other IOCTLs to be invoked while waiting
1331 * for event
1332 */
1333 MSM_CPE_LSM_REL_LOCK(&lsm_d->lsm_api_lock,
1334 "lsm_api_lock");
1335
1336 rc = wait_event_freezable(lsm_d->event_wait,
1337 (atomic_read(&lsm_d->event_avail) == 1) ||
1338 (atomic_read(&lsm_d->event_stop) == 1));
1339
1340 MSM_CPE_LSM_GRAB_LOCK(&lsm_d->lsm_api_lock,
1341 "lsm_api_lock");
1342
1343 if (!rc) {
1344 if (atomic_read(&lsm_d->event_avail) == 1) {
1345 rc = 0;
1346 atomic_set(&lsm_d->event_avail, 0);
1347
1348 if (cmd == SNDRV_LSM_EVENT_STATUS) {
1349 user = arg;
1350 if (lsm_d->ev_det_pld_size >
1351 user->payload_size) {
1352 dev_err(rtd->dev,
1353 "%s: avail pld_bytes = %u, needed = %u\n",
1354 __func__,
1355 user->payload_size,
1356 lsm_d->ev_det_pld_size);
1357 return -EINVAL;
1358 }
1359
1360 user->status = lsm_d->ev_det_status;
1361 user->payload_size =
1362 lsm_d->ev_det_pld_size;
1363 memcpy(user->payload,
1364 lsm_d->ev_det_payload,
1365 lsm_d->ev_det_pld_size);
1366 } else {
1367 user_v3 = arg;
1368 if (lsm_d->ev_det_pld_size >
1369 user_v3->payload_size) {
1370 dev_err(rtd->dev,
1371 "%s: avail pld_bytes = %u, needed = %u\n",
1372 __func__,
1373 user_v3->payload_size,
1374 lsm_d->ev_det_pld_size);
1375 return -EINVAL;
1376 }
1377 /* event status timestamp not supported
1378 * on CPE mode. Set msw and lsw to 0.
1379 */
1380 user_v3->timestamp_lsw = 0;
1381 user_v3->timestamp_msw = 0;
1382 user_v3->status = lsm_d->ev_det_status;
1383 user_v3->payload_size =
1384 lsm_d->ev_det_pld_size;
1385 memcpy(user_v3->payload,
1386 lsm_d->ev_det_payload,
1387 lsm_d->ev_det_pld_size);
1388 }
1389 } else if (atomic_read(&lsm_d->event_stop) == 1) {
1390 dev_dbg(rtd->dev,
1391 "%s: wait_aborted\n", __func__);
1392 if (cmd == SNDRV_LSM_EVENT_STATUS) {
1393 user = arg;
1394 user->payload_size = 0;
1395 } else {
1396 user_v3 = arg;
1397 user_v3->payload_size = 0;
1398 }
1399 rc = 0;
1400 }
1401 }
1402 }
1403 break;
1404
1405 case SNDRV_LSM_ABORT_EVENT:
1406 dev_dbg(rtd->dev,
1407 "%s: %s\n",
1408 __func__, "SNDRV_LSM_ABORT_EVENT");
1409 atomic_set(&lsm_d->event_stop, 1);
1410 wake_up(&lsm_d->event_wait);
1411 break;
1412
1413 case SNDRV_LSM_START:
1414 dev_dbg(rtd->dev,
1415 "%s: %s\n",
1416 __func__, "SNDRV_LSM_START");
1417 rc = lsm_ops->lsm_start(cpe->core_handle, session);
1418 if (rc != 0) {
1419 dev_err(rtd->dev,
1420 "%s: lsm_start fail, err = %d\n",
1421 __func__, rc);
1422 return rc;
1423 }
1424 session->started = true;
1425 break;
1426
1427 case SNDRV_LSM_STOP:
1428 dev_dbg(rtd->dev,
1429 "%s: %s, lab_enable = %d, lab_thread_status = %d\n",
1430 __func__, "SNDRV_LSM_STOP",
1431 session->lab_enable,
1432 lab_d->thread_status);
1433 if ((session->lab_enable &&
1434 lab_d->thread_status ==
1435 MSM_LSM_LAB_THREAD_RUNNING)) {
1436 /* Explicitly stop LAB */
1437 rc = msm_cpe_lsm_lab_stop(substream);
1438 if (rc) {
1439 dev_err(rtd->dev,
1440 "%s: lab_stop failed, err = %d\n",
1441 __func__, rc);
1442 return rc;
1443 }
1444 }
1445
1446 rc = lsm_ops->lsm_stop(cpe->core_handle, session);
1447 if (rc != 0) {
1448 dev_err(rtd->dev,
1449 "%s: lsm_stop fail err = %d\n",
1450 __func__, rc);
1451
1452 return rc;
1453 }
1454 session->started = false;
1455 break;
1456
1457 case SNDRV_LSM_SET_PARAMS:
1458 memcpy(&det_params, arg,
1459 sizeof(det_params));
1460 if (det_params.num_confidence_levels <= 0) {
1461 dev_err(rtd->dev,
1462 "%s: %s: Invalid confidence levels %u\n",
1463 __func__, "SNDRV_LSM_SET_PARAMS",
1464 det_params.num_confidence_levels);
1465 return -EINVAL;
1466 }
1467
1468 session->num_confidence_levels =
1469 det_params.num_confidence_levels;
1470 rc = msm_cpe_lsm_get_conf_levels(session,
1471 det_params.conf_level);
1472 if (rc) {
1473 dev_err(rtd->dev,
1474 "%s: %s get_conf_levels fail, err = %d\n",
1475 __func__, "SNDRV_LSM_SET_PARAMS",
1476 rc);
1477 break;
1478 }
1479
1480 rc = lsm_ops->lsm_set_data(cpe->core_handle, session,
1481 det_params.detect_mode,
1482 det_params.detect_failure);
1483 if (rc) {
1484 dev_err(rtd->dev,
1485 "%s: lsm_set_data failed, err = %d\n",
1486 __func__, rc);
1487 return rc;
1488 }
1489
1490 kfree(session->conf_levels);
1491 session->conf_levels = NULL;
1492
1493 break;
1494
1495 case SNDRV_LSM_OUT_FORMAT_CFG: {
1496 struct snd_lsm_output_format_cfg u_fmt_cfg;
1497
1498 if (!arg) {
1499 dev_err(rtd->dev,
1500 "%s: Invalid argument to ioctl %s\n",
1501 __func__, "SNDRV_LSM_OUT_FORMAT_CFG");
1502 return -EINVAL;
1503 }
1504
1505 if (copy_from_user(&u_fmt_cfg, arg,
1506 sizeof(u_fmt_cfg))) {
1507 dev_err(rtd->dev,
1508 "%s: copy_from_user failed for out_fmt_cfg\n",
1509 __func__);
1510 return -EFAULT;
1511 }
1512
1513 if (msm_cpe_lsm_validate_out_format(substream,
1514 &u_fmt_cfg))
1515 return -EINVAL;
1516
1517 session->out_fmt_cfg.format = u_fmt_cfg.format;
1518 session->out_fmt_cfg.pack_mode = u_fmt_cfg.packing;
1519 session->out_fmt_cfg.data_path_events =
1520 u_fmt_cfg.events;
1521 session->out_fmt_cfg.transfer_mode = u_fmt_cfg.mode;
1522
1523 rc = lsm_ops->lsm_set_fmt_cfg(cpe->core_handle,
1524 session);
1525 if (rc) {
1526 dev_err(rtd->dev,
1527 "%s: lsm_set_fmt_cfg failed, err = %d\n",
1528 __func__, rc);
1529 return rc;
1530 }
1531 }
1532 break;
1533
1534 case SNDRV_LSM_SET_PORT: {
1535 u32 port_id = cpe->input_port_id;
1536
1537 dev_dbg(rtd->dev, "%s: %s\n", __func__, "SNDRV_LSM_SET_PORT");
1538 rc = lsm_ops->lsm_set_port(cpe->core_handle, session, &port_id);
1539 if (rc) {
1540 dev_err(rtd->dev,
1541 "%s: lsm_set_port failed, err = %d\n",
1542 __func__, rc);
1543 return rc;
1544 }
1545 }
1546 break;
1547
1548 default:
1549 dev_dbg(rtd->dev,
1550 "%s: Default snd_lib_ioctl cmd 0x%x\n",
1551 __func__, cmd);
1552 rc = snd_pcm_lib_ioctl(substream, cmd, arg);
1553 }
1554
1555 return rc;
1556}
1557
1558static int msm_cpe_lsm_lab_start(struct snd_pcm_substream *substream,
1559 u16 event_det_status)
1560{
1561 struct snd_soc_pcm_runtime *rtd;
1562 struct cpe_lsm_data *lsm_d = NULL;
1563 struct cpe_priv *cpe = NULL;
1564 struct cpe_lsm_session *session = NULL;
1565 struct cpe_lsm_lab *lab_d = NULL;
1566 struct cpe_hw_params *hw_params;
1567 struct wcd_cpe_lsm_ops *lsm_ops;
1568 struct wcd_cpe_afe_ops *afe_ops;
1569 struct wcd_cpe_afe_port_cfg *out_port;
1570 int rc;
1571
1572 if (!substream || !substream->private_data) {
1573 pr_err("%s: invalid substream (%pK)\n",
1574 __func__, substream);
1575 return -EINVAL;
1576 }
1577
1578 rtd = substream->private_data;
1579 lsm_d = cpe_get_lsm_data(substream);
1580 cpe = cpe_get_private_data(substream);
1581
1582 if (!cpe || !cpe->core_handle) {
1583 dev_err(rtd->dev,
1584 "%s: Invalid private data\n",
1585 __func__);
1586 return -EINVAL;
1587 }
1588
1589 if (!lsm_d || !lsm_d->lsm_session) {
1590 dev_err(rtd->dev,
1591 "%s: Invalid session data\n",
1592 __func__);
1593 return -EINVAL;
1594 }
1595
1596 session = lsm_d->lsm_session;
1597 lsm_ops = &cpe->lsm_ops;
1598 lab_d = &lsm_d->lab;
1599 afe_ops = &cpe->afe_ops;
1600 hw_params = &lsm_d->hw_params;
1601
1602 if (!session->started) {
1603 dev_dbg(rtd->dev,
1604 "%s: Session is stopped, cannot start LAB\n",
1605 __func__);
1606 return 0;
1607 }
1608
1609 reinit_completion(&lab_d->thread_complete);
1610
1611 if (session->lab_enable &&
1612 event_det_status ==
1613 LSM_VOICE_WAKEUP_STATUS_DETECTED) {
1614 out_port = &session->afe_out_port_cfg;
1615 out_port->port_id = session->afe_out_port_id;
1616 out_port->bit_width = hw_params->sample_size;
1617 out_port->num_channels = hw_params->channels;
1618 out_port->sample_rate = hw_params->sample_rate;
1619 dev_dbg(rtd->dev, "%s: port_id= %u, bit_width= %u, rate= %u\n",
1620 __func__, out_port->port_id, out_port->bit_width,
1621 out_port->sample_rate);
1622
1623 rc = afe_ops->afe_port_cmd_cfg(cpe->core_handle,
1624 out_port);
1625 if (rc) {
1626 dev_err(rtd->dev,
1627 "%s: Failed afe generic config v2, err = %d\n",
1628 __func__, rc);
1629 return rc;
1630 }
1631
1632 atomic_set(&lab_d->abort_read, 0);
1633 dev_dbg(rtd->dev,
1634 "%s: KW detected, scheduling LAB thread\n",
1635 __func__);
1636
1637 /*
1638 * Even though thread might be only scheduled and
1639 * not currently running, mark the internal driver
1640 * status to running so driver can cancel this thread
1641 * if it needs to before the thread gets chance to run.
1642 */
1643 lab_d->thread_status = MSM_LSM_LAB_THREAD_RUNNING;
1644 session->lsm_lab_thread = kthread_run(
1645 msm_cpe_lab_thread,
1646 lsm_d,
1647 "lab_thread");
1648 }
1649
1650 return 0;
1651}
1652
1653static bool msm_cpe_lsm_is_valid_stream(struct snd_pcm_substream *substream,
1654 const char *func)
1655{
1656 struct snd_soc_pcm_runtime *rtd;
1657 struct cpe_lsm_data *lsm_d = NULL;
1658 struct cpe_priv *cpe = NULL;
1659 struct cpe_lsm_session *session = NULL;
1660 struct wcd_cpe_lsm_ops *lsm_ops;
1661
1662 if (!substream || !substream->private_data) {
1663 pr_err("%s: invalid substream (%pK)\n",
1664 func, substream);
1665 return false;
1666 }
1667
1668 rtd = substream->private_data;
1669 lsm_d = cpe_get_lsm_data(substream);
1670 cpe = cpe_get_private_data(substream);
1671
1672 if (!cpe || !cpe->core_handle) {
1673 dev_err(rtd->dev,
1674 "%s: Invalid private data\n",
1675 func);
1676 return false;
1677 }
1678
1679 if (!lsm_d || !lsm_d->lsm_session) {
1680 dev_err(rtd->dev,
1681 "%s: Invalid session data\n",
1682 func);
1683 return false;
1684 }
1685
1686 session = lsm_d->lsm_session;
1687 lsm_ops = &cpe->lsm_ops;
1688
1689 if (!lsm_ops) {
1690 dev_err(rtd->dev,
1691 "%s: Invalid lsm_ops\n", func);
1692 return false;
1693 }
1694
1695 return true;
1696}
1697
1698static int msm_cpe_lsm_set_epd(struct snd_pcm_substream *substream,
1699 struct lsm_params_info *p_info)
1700{
1701 struct snd_soc_pcm_runtime *rtd;
1702 struct cpe_lsm_data *lsm_d = NULL;
1703 struct cpe_priv *cpe = NULL;
1704 struct cpe_lsm_session *session = NULL;
1705 struct wcd_cpe_lsm_ops *lsm_ops;
1706 struct snd_lsm_ep_det_thres epd_thres;
1707 int rc;
1708
1709 if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
1710 return -EINVAL;
1711
1712 rtd = substream->private_data;
1713 lsm_d = cpe_get_lsm_data(substream);
1714 cpe = cpe_get_private_data(substream);
1715 session = lsm_d->lsm_session;
1716 lsm_ops = &cpe->lsm_ops;
1717
1718 if (p_info->param_size != sizeof(epd_thres)) {
1719 dev_err(rtd->dev,
1720 "%s: Invalid param_size %d\n",
1721 __func__, p_info->param_size);
1722 rc = -EINVAL;
1723 goto done;
1724 }
1725
1726 if (copy_from_user(&epd_thres, p_info->param_data,
1727 p_info->param_size)) {
1728 dev_err(rtd->dev,
1729 "%s: copy_from_user failed, size = %d\n",
1730 __func__, p_info->param_size);
1731 rc = -EFAULT;
1732 goto done;
1733 }
1734
1735 rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
1736 session, p_info, &epd_thres,
1737 LSM_ENDPOINT_DETECT_THRESHOLD);
1738 if (unlikely(rc))
1739 dev_err(rtd->dev,
1740 "%s: set_one_param(epd_threshold) failed, rc %d\n",
1741 __func__, rc);
1742done:
1743 return rc;
1744}
1745
1746static int msm_cpe_lsm_set_mode(struct snd_pcm_substream *substream,
1747 struct lsm_params_info *p_info)
1748{
1749 struct snd_soc_pcm_runtime *rtd;
1750 struct cpe_lsm_data *lsm_d = NULL;
1751 struct cpe_priv *cpe = NULL;
1752 struct cpe_lsm_session *session = NULL;
1753 struct wcd_cpe_lsm_ops *lsm_ops;
1754 struct snd_lsm_detect_mode det_mode;
1755 int rc;
1756
1757 if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
1758 return -EINVAL;
1759
1760 rtd = substream->private_data;
1761 lsm_d = cpe_get_lsm_data(substream);
1762 cpe = cpe_get_private_data(substream);
1763 session = lsm_d->lsm_session;
1764 lsm_ops = &cpe->lsm_ops;
1765
1766 if (p_info->param_size != sizeof(det_mode)) {
1767 dev_err(rtd->dev,
1768 "%s: Invalid param_size %d\n",
1769 __func__, p_info->param_size);
1770 rc = -EINVAL;
1771 goto done;
1772 }
1773
1774 if (copy_from_user(&det_mode, p_info->param_data,
1775 p_info->param_size)) {
1776 dev_err(rtd->dev,
1777 "%s: copy_from_user failed, size = %d\n",
1778 __func__, p_info->param_size);
1779 rc = -EFAULT;
1780 goto done;
1781 }
1782
1783 rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
1784 session, p_info, &det_mode,
1785 LSM_OPERATION_MODE);
1786 if (unlikely(rc))
1787 dev_err(rtd->dev,
1788 "%s: set_one_param(epd_threshold) failed, rc %d\n",
1789 __func__, rc);
1790done:
1791 return rc;
1792}
1793
1794static int msm_cpe_lsm_set_gain(struct snd_pcm_substream *substream,
1795 struct lsm_params_info *p_info)
1796{
1797 struct snd_soc_pcm_runtime *rtd;
1798 struct cpe_lsm_data *lsm_d = NULL;
1799 struct cpe_priv *cpe = NULL;
1800 struct cpe_lsm_session *session = NULL;
1801 struct wcd_cpe_lsm_ops *lsm_ops;
1802 struct snd_lsm_gain gain;
1803 int rc;
1804
1805 if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
1806 return -EINVAL;
1807
1808 rtd = substream->private_data;
1809 lsm_d = cpe_get_lsm_data(substream);
1810 cpe = cpe_get_private_data(substream);
1811 session = lsm_d->lsm_session;
1812 lsm_ops = &cpe->lsm_ops;
1813
1814 if (p_info->param_size != sizeof(gain)) {
1815 dev_err(rtd->dev,
1816 "%s: Invalid param_size %d\n",
1817 __func__, p_info->param_size);
1818 rc = -EINVAL;
1819 goto done;
1820 }
1821
1822 if (copy_from_user(&gain, p_info->param_data,
1823 p_info->param_size)) {
1824 dev_err(rtd->dev,
1825 "%s: copy_from_user failed, size = %d\n",
1826 __func__, p_info->param_size);
1827 rc = -EFAULT;
1828 goto done;
1829 }
1830
1831 rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
1832 session, p_info, &gain,
1833 LSM_GAIN);
1834 if (unlikely(rc))
1835 dev_err(rtd->dev,
1836 "%s: set_one_param(epd_threshold) failed, rc %d\n",
1837 __func__, rc);
1838done:
1839 return rc;
1840
1841}
1842
1843static int msm_cpe_lsm_set_conf(struct snd_pcm_substream *substream,
1844 struct lsm_params_info *p_info)
1845{
1846 struct snd_soc_pcm_runtime *rtd;
1847 struct cpe_lsm_data *lsm_d = NULL;
1848 struct cpe_priv *cpe = NULL;
1849 struct cpe_lsm_session *session = NULL;
1850 struct wcd_cpe_lsm_ops *lsm_ops;
1851 int rc;
1852
1853 if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
1854 return -EINVAL;
1855
1856 rtd = substream->private_data;
1857 lsm_d = cpe_get_lsm_data(substream);
1858 cpe = cpe_get_private_data(substream);
1859 session = lsm_d->lsm_session;
1860 lsm_ops = &cpe->lsm_ops;
1861
1862 session->num_confidence_levels =
1863 p_info->param_size;
1864 rc = msm_cpe_lsm_get_conf_levels(session,
1865 p_info->param_data);
1866 if (rc) {
1867 dev_err(rtd->dev,
1868 "%s: get_conf_levels failed, err = %d\n",
1869 __func__, rc);
1870 goto done;
1871 }
1872
1873 rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
1874 session, p_info, NULL,
1875 LSM_MIN_CONFIDENCE_LEVELS);
1876 if (unlikely(rc))
1877 dev_err(rtd->dev,
1878 "%s: set_one_param(conf_levels) failed, rc %d\n",
1879 __func__, rc);
1880done:
1881 return rc;
1882}
1883
1884static int msm_cpe_lsm_reg_model(struct snd_pcm_substream *substream,
1885 struct lsm_params_info *p_info)
1886{
1887 struct snd_soc_pcm_runtime *rtd;
1888 struct cpe_lsm_data *lsm_d = NULL;
1889 struct cpe_priv *cpe = NULL;
1890 struct cpe_lsm_session *session = NULL;
1891 struct wcd_cpe_lsm_ops *lsm_ops;
1892 int rc;
1893 size_t offset;
1894 u8 *snd_model_ptr;
1895
1896 if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
1897 return -EINVAL;
1898
1899 rtd = substream->private_data;
1900 lsm_d = cpe_get_lsm_data(substream);
1901 cpe = cpe_get_private_data(substream);
1902 session = lsm_d->lsm_session;
1903 lsm_ops = &cpe->lsm_ops;
1904
1905 lsm_ops->lsm_get_snd_model_offset(cpe->core_handle,
1906 session, &offset);
1907 /* Check if 'p_info->param_size + offset' crosses U32_MAX. */
1908 if (p_info->param_size > U32_MAX - offset) {
1909 dev_err(rtd->dev,
1910 "%s: Invalid param_size %d\n",
1911 __func__, p_info->param_size);
1912 return -EINVAL;
1913 }
1914 session->snd_model_size = p_info->param_size + offset;
1915
1916 session->snd_model_data = vzalloc(session->snd_model_size);
1917 if (!session->snd_model_data)
1918 return -ENOMEM;
1919
1920 snd_model_ptr = ((u8 *) session->snd_model_data) + offset;
1921
1922 if (copy_from_user(snd_model_ptr,
1923 p_info->param_data, p_info->param_size)) {
1924 dev_err(rtd->dev,
1925 "%s: copy_from_user for snd_model failed\n",
1926 __func__);
1927 rc = -EFAULT;
1928 goto free_snd_model_data;
1929 }
1930
1931 rc = lsm_ops->lsm_shmem_alloc(cpe->core_handle, session,
1932 session->snd_model_size);
1933 if (rc != 0) {
1934 dev_err(rtd->dev,
1935 "%s: shared memory allocation failed, err = %d\n",
1936 __func__, rc);
1937 rc = -EINVAL;
1938 goto free_snd_model_data;
1939 }
1940
1941 rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
1942 session, p_info, NULL,
1943 LSM_REG_SND_MODEL);
1944 if (unlikely(rc)) {
1945 dev_err(rtd->dev,
1946 "%s: set_one_param(snd_model) failed, rc %d\n",
1947 __func__, rc);
1948 goto dealloc_shmem;
1949 }
1950 return 0;
1951
1952dealloc_shmem:
1953 lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
1954
1955free_snd_model_data:
1956 vfree(session->snd_model_data);
1957 return rc;
1958}
1959
1960static int msm_cpe_lsm_dereg_model(struct snd_pcm_substream *substream,
1961 struct lsm_params_info *p_info)
1962{
1963 struct snd_soc_pcm_runtime *rtd;
1964 struct cpe_lsm_data *lsm_d = NULL;
1965 struct cpe_priv *cpe = NULL;
1966 struct cpe_lsm_session *session = NULL;
1967 struct wcd_cpe_lsm_ops *lsm_ops;
1968 int rc;
1969
1970 if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
1971 return -EINVAL;
1972
1973 rtd = substream->private_data;
1974 lsm_d = cpe_get_lsm_data(substream);
1975 cpe = cpe_get_private_data(substream);
1976 session = lsm_d->lsm_session;
1977 lsm_ops = &cpe->lsm_ops;
1978
1979 rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
1980 session, p_info, NULL,
1981 LSM_DEREG_SND_MODEL);
1982 if (rc)
1983 dev_err(rtd->dev,
1984 "%s: dereg_snd_model failed\n",
1985 __func__);
1986 return lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
1987}
1988
1989static int msm_cpe_lsm_set_custom(struct snd_pcm_substream *substream,
1990 struct lsm_params_info *p_info)
1991{
1992 struct snd_soc_pcm_runtime *rtd;
1993 struct cpe_lsm_data *lsm_d = NULL;
1994 struct cpe_priv *cpe = NULL;
1995 struct cpe_lsm_session *session = NULL;
1996 struct wcd_cpe_lsm_ops *lsm_ops;
1997 u8 *data;
1998 int rc;
1999
2000 if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
2001 return -EINVAL;
2002
2003 rtd = substream->private_data;
2004 lsm_d = cpe_get_lsm_data(substream);
2005 cpe = cpe_get_private_data(substream);
2006 session = lsm_d->lsm_session;
2007 lsm_ops = &cpe->lsm_ops;
2008
2009 if (p_info->param_size > MSM_CPE_MAX_CUSTOM_PARAM_SIZE) {
2010 dev_err(rtd->dev,
2011 "%s: invalid size %d, max allowed %d\n",
2012 __func__, p_info->param_size,
2013 MSM_CPE_MAX_CUSTOM_PARAM_SIZE);
2014 return -EINVAL;
2015 }
2016
2017 data = kzalloc(p_info->param_size, GFP_KERNEL);
2018 if (!data)
2019 return -ENOMEM;
2020
2021 if (copy_from_user(data, p_info->param_data,
2022 p_info->param_size)) {
2023 dev_err(rtd->dev,
2024 "%s: copy_from_user failed for custom params, size = %d\n",
2025 __func__, p_info->param_size);
2026 rc = -EFAULT;
2027 goto err_ret;
2028 }
2029
2030 rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
2031 session, p_info, data,
2032 LSM_CUSTOM_PARAMS);
2033 if (rc)
2034 dev_err(rtd->dev,
2035 "%s: custom_params failed, err = %d\n",
2036 __func__, rc);
2037err_ret:
2038 kfree(data);
2039 return rc;
2040}
2041
2042static int msm_cpe_lsm_process_params(struct snd_pcm_substream *substream,
2043 struct snd_lsm_module_params *p_data,
2044 void *params)
2045{
2046 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2047 struct lsm_params_info *p_info;
2048 int i;
2049 int rc = 0;
2050
2051 p_info = (struct lsm_params_info *) params;
2052
2053 for (i = 0; i < p_data->num_params; i++) {
2054 dev_dbg(rtd->dev,
2055 "%s: param (%d), module_id = 0x%x, param_id = 0x%x, param_size = 0x%x, param_type = 0x%x\n",
2056 __func__, i, p_info->module_id,
2057 p_info->param_id, p_info->param_size,
2058 p_info->param_type);
2059
2060 switch (p_info->param_type) {
2061 case LSM_ENDPOINT_DETECT_THRESHOLD:
2062 rc = msm_cpe_lsm_set_epd(substream, p_info);
2063 break;
2064 case LSM_OPERATION_MODE:
2065 rc = msm_cpe_lsm_set_mode(substream, p_info);
2066 break;
2067 case LSM_GAIN:
2068 rc = msm_cpe_lsm_set_gain(substream, p_info);
2069 break;
2070 case LSM_MIN_CONFIDENCE_LEVELS:
2071 rc = msm_cpe_lsm_set_conf(substream, p_info);
2072 break;
2073 case LSM_REG_SND_MODEL:
2074 rc = msm_cpe_lsm_reg_model(substream, p_info);
2075 break;
2076 case LSM_DEREG_SND_MODEL:
2077 rc = msm_cpe_lsm_dereg_model(substream, p_info);
2078 break;
2079 case LSM_CUSTOM_PARAMS:
2080 rc = msm_cpe_lsm_set_custom(substream, p_info);
2081 break;
2082 default:
2083 dev_err(rtd->dev,
2084 "%s: Invalid param_type %d\n",
2085 __func__, p_info->param_type);
2086 rc = -EINVAL;
2087 break;
2088 }
2089 if (rc) {
2090 pr_err("%s: set_param fail for param_type %d\n",
2091 __func__, p_info->param_type);
2092 return rc;
2093 }
2094
2095 p_info++;
2096 }
2097
2098 return rc;
2099}
2100
2101static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
2102 unsigned int cmd, void *arg)
2103{
2104 int err = 0;
2105 struct snd_soc_pcm_runtime *rtd;
2106 struct cpe_priv *cpe = NULL;
2107 struct cpe_lsm_data *lsm_d = NULL;
2108 struct cpe_lsm_session *session = NULL;
2109 struct wcd_cpe_lsm_ops *lsm_ops;
2110
2111 if (!substream || !substream->private_data) {
2112 pr_err("%s: invalid substream (%pK)\n",
2113 __func__, substream);
2114 return -EINVAL;
2115 }
2116
2117 rtd = substream->private_data;
2118 lsm_d = cpe_get_lsm_data(substream);
2119 cpe = cpe_get_private_data(substream);
2120
2121 if (!cpe || !cpe->core_handle) {
2122 dev_err(rtd->dev,
2123 "%s: Invalid private data\n",
2124 __func__);
2125 return -EINVAL;
2126 }
2127
2128 if (!lsm_d || !lsm_d->lsm_session) {
2129 dev_err(rtd->dev,
2130 "%s: Invalid session data\n",
2131 __func__);
2132 return -EINVAL;
2133 }
2134
2135 MSM_CPE_LSM_GRAB_LOCK(&lsm_d->lsm_api_lock,
2136 "lsm_api_lock");
2137
2138 session = lsm_d->lsm_session;
2139 lsm_ops = &cpe->lsm_ops;
2140
2141 switch (cmd) {
2142 case SNDRV_LSM_REG_SND_MODEL_V2: {
2143 struct snd_lsm_sound_model_v2 snd_model;
2144
2145 if (session->is_topology_used) {
2146 dev_err(rtd->dev,
2147 "%s: %s: not supported if using topology\n",
2148 __func__, "LSM_REG_SND_MODEL_V2");
2149 err = -EINVAL;
2150 goto done;
2151 }
2152
2153 if (copy_from_user(&snd_model, (void *)arg,
2154 sizeof(struct snd_lsm_sound_model_v2))) {
2155 dev_err(rtd->dev,
2156 "%s: copy from user failed, size %zd\n",
2157 __func__,
2158 sizeof(struct snd_lsm_sound_model_v2));
2159 err = -EFAULT;
2160 goto done;
2161 }
2162
2163 err = msm_cpe_lsm_ioctl_shared(substream, cmd,
2164 &snd_model);
2165 }
2166 break;
2167 case SNDRV_LSM_EVENT_STATUS: {
2168 struct snd_lsm_event_status u_event_status;
2169 struct snd_lsm_event_status *event_status = NULL;
2170 int u_pld_size = 0;
2171
2172 if (copy_from_user(&u_event_status, (void *)arg,
2173 sizeof(struct snd_lsm_event_status))) {
2174 dev_err(rtd->dev,
2175 "%s: event status copy from user failed, size %zd\n",
2176 __func__,
2177 sizeof(struct snd_lsm_event_status));
2178 err = -EFAULT;
2179 goto done;
2180 }
2181
2182 if (u_event_status.payload_size >
2183 LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
2184 dev_err(rtd->dev,
2185 "%s: payload_size %d is invalid, max allowed = %d\n",
2186 __func__, u_event_status.payload_size,
2187 LISTEN_MAX_STATUS_PAYLOAD_SIZE);
2188 err = -EINVAL;
2189 goto done;
2190 }
2191
2192 u_pld_size = sizeof(struct snd_lsm_event_status) +
2193 u_event_status.payload_size;
2194
2195 event_status = kzalloc(u_pld_size, GFP_KERNEL);
2196 if (!event_status) {
2197 err = -ENOMEM;
2198 goto done;
2199 } else {
2200 event_status->payload_size =
2201 u_event_status.payload_size;
2202 err = msm_cpe_lsm_ioctl_shared(substream,
2203 cmd, event_status);
2204 }
2205
2206 if (!err && copy_to_user(arg, event_status, u_pld_size)) {
2207 dev_err(rtd->dev,
2208 "%s: copy to user failed\n",
2209 __func__);
2210 kfree(event_status);
2211 err = -EFAULT;
2212 goto done;
2213 }
2214
2215 msm_cpe_lsm_lab_start(substream, event_status->status);
2216 msm_cpe_process_event_status_done(lsm_d);
2217 kfree(event_status);
2218 }
2219 break;
2220 case SNDRV_LSM_EVENT_STATUS_V3: {
2221 struct snd_lsm_event_status_v3 u_event_status;
2222 struct snd_lsm_event_status_v3 *event_status = NULL;
2223 int u_pld_size = 0;
2224
2225 if (copy_from_user(&u_event_status, (void *)arg,
2226 sizeof(struct snd_lsm_event_status_v3))) {
2227 dev_err(rtd->dev,
2228 "%s: event status copy from user failed, size %zd\n",
2229 __func__,
2230 sizeof(struct snd_lsm_event_status_v3));
2231 err = -EFAULT;
2232 goto done;
2233 }
2234
2235 if (u_event_status.payload_size >
2236 LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
2237 dev_err(rtd->dev,
2238 "%s: payload_size %d is invalid, max allowed = %d\n",
2239 __func__, u_event_status.payload_size,
2240 LISTEN_MAX_STATUS_PAYLOAD_SIZE);
2241 err = -EINVAL;
2242 goto done;
2243 }
2244
2245 u_pld_size = sizeof(struct snd_lsm_event_status_v3) +
2246 u_event_status.payload_size;
2247
2248 event_status = kzalloc(u_pld_size, GFP_KERNEL);
2249 if (!event_status) {
2250 err = -ENOMEM;
2251 goto done;
2252 } else {
2253 event_status->payload_size =
2254 u_event_status.payload_size;
2255 err = msm_cpe_lsm_ioctl_shared(substream,
2256 cmd, event_status);
2257 }
2258
2259 if (!err && copy_to_user(arg, event_status, u_pld_size)) {
2260 dev_err(rtd->dev,
2261 "%s: copy to user failed\n",
2262 __func__);
2263 kfree(event_status);
2264 err = -EFAULT;
2265 goto done;
2266 }
2267
2268 msm_cpe_lsm_lab_start(substream, event_status->status);
2269 msm_cpe_process_event_status_done(lsm_d);
2270 kfree(event_status);
2271 }
2272 break;
2273 case SNDRV_LSM_SET_PARAMS: {
2274 struct snd_lsm_detection_params det_params;
2275
2276 if (session->is_topology_used) {
2277 dev_err(rtd->dev,
2278 "%s: %s: not supported if using topology\n",
2279 __func__, "SNDRV_LSM_SET_PARAMS");
2280 err = -EINVAL;
2281 goto done;
2282 }
2283
2284 if (copy_from_user(&det_params, (void *) arg,
2285 sizeof(det_params))) {
2286 dev_err(rtd->dev,
2287 "%s: %s: copy_from_user failed, size = %zd\n",
2288 __func__, "SNDRV_LSM_SET_PARAMS",
2289 sizeof(det_params));
2290 err = -EFAULT;
2291 goto done;
2292 }
2293
2294 err = msm_cpe_lsm_ioctl_shared(substream, cmd,
2295 &det_params);
2296 }
2297 break;
2298
2299 case SNDRV_LSM_SET_MODULE_PARAMS: {
2300 struct snd_lsm_module_params p_data;
2301 size_t p_size;
2302 u8 *params;
2303
2304 if (!session->is_topology_used) {
2305 dev_err(rtd->dev,
2306 "%s: %s: not supported if not using topology\n",
2307 __func__, "SET_MODULE_PARAMS");
2308 err = -EINVAL;
2309 goto done;
2310 }
2311
2312 if (!arg) {
2313 dev_err(rtd->dev,
2314 "%s: %s: No Param data to set\n",
2315 __func__, "SET_MODULE_PARAMS");
2316 err = -EINVAL;
2317 goto done;
2318 }
2319
2320 if (copy_from_user(&p_data, arg,
2321 sizeof(p_data))) {
2322 dev_err(rtd->dev,
2323 "%s: %s: copy_from_user failed, size = %zd\n",
2324 __func__, "p_data", sizeof(p_data));
2325 err = -EFAULT;
2326 goto done;
2327 }
2328
2329 if (p_data.num_params > LSM_PARAMS_MAX) {
2330 dev_err(rtd->dev,
2331 "%s: %s: Invalid num_params %d\n",
2332 __func__, "SET_MODULE_PARAMS",
2333 p_data.num_params);
2334 err = -EINVAL;
2335 goto done;
2336 }
2337
2338 p_size = p_data.num_params *
2339 sizeof(struct lsm_params_info);
2340
2341 if (p_data.data_size != p_size) {
2342 dev_err(rtd->dev,
2343 "%s: %s: Invalid size %zd\n",
2344 __func__, "SET_MODULE_PARAMS", p_size);
2345
2346 err = -EFAULT;
2347 goto done;
2348 }
2349
2350 params = kzalloc(p_size, GFP_KERNEL);
2351 if (!params) {
2352 err = -ENOMEM;
2353 goto done;
2354 }
2355
2356 if (copy_from_user(params, p_data.params,
2357 p_data.data_size)) {
2358 dev_err(rtd->dev,
2359 "%s: %s: copy_from_user failed, size = %d\n",
2360 __func__, "params", p_data.data_size);
2361 kfree(params);
2362 err = -EFAULT;
2363 goto done;
2364 }
2365
2366 err = msm_cpe_lsm_process_params(substream, &p_data, params);
2367 if (err)
2368 dev_err(rtd->dev,
2369 "%s: %s: Failed to set params, err = %d\n",
2370 __func__, "SET_MODULE_PARAMS", err);
2371 kfree(params);
2372 break;
2373 }
2374 default:
2375 err = msm_cpe_lsm_ioctl_shared(substream, cmd, arg);
2376 break;
2377 }
2378
2379done:
2380 MSM_CPE_LSM_REL_LOCK(&lsm_d->lsm_api_lock,
2381 "lsm_api_lock");
2382 return err;
2383}
2384
2385#ifdef CONFIG_COMPAT
2386struct snd_lsm_sound_model_v2_32 {
2387 compat_uptr_t data;
2388 compat_uptr_t confidence_level;
2389 u32 data_size;
2390 enum lsm_detection_mode detection_mode;
2391 u8 num_confidence_levels;
2392 bool detect_failure;
2393};
2394
2395struct snd_lsm_detection_params_32 {
2396 compat_uptr_t conf_level;
2397 enum lsm_detection_mode detect_mode;
2398 u8 num_confidence_levels;
2399 bool detect_failure;
2400};
2401
2402struct lsm_params_info_32 {
2403 u32 module_id;
2404 u32 param_id;
2405 u32 param_size;
2406 compat_uptr_t param_data;
2407 uint32_t param_type;
2408};
2409
2410struct snd_lsm_module_params_32 {
2411 compat_uptr_t params;
2412 u32 num_params;
2413 u32 data_size;
2414};
2415
2416enum {
2417 SNDRV_LSM_REG_SND_MODEL_V2_32 =
2418 _IOW('U', 0x07, struct snd_lsm_sound_model_v2_32),
2419 SNDRV_LSM_SET_PARAMS32 =
2420 _IOW('U', 0x0A, struct snd_lsm_detection_params_32),
2421 SNDRV_LSM_SET_MODULE_PARAMS_32 =
2422 _IOW('U', 0x0B, struct snd_lsm_module_params_32),
2423};
2424
2425static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
2426 unsigned int cmd, void *arg)
2427{
2428 int err = 0;
2429 struct snd_soc_pcm_runtime *rtd;
2430 struct cpe_priv *cpe = NULL;
2431 struct cpe_lsm_data *lsm_d = NULL;
2432 struct cpe_lsm_session *session = NULL;
2433 struct wcd_cpe_lsm_ops *lsm_ops;
2434
2435 if (!substream || !substream->private_data) {
2436 pr_err("%s: invalid substream (%pK)\n",
2437 __func__, substream);
2438 return -EINVAL;
2439 }
2440
2441 rtd = substream->private_data;
2442 lsm_d = cpe_get_lsm_data(substream);
2443 cpe = cpe_get_private_data(substream);
2444
2445 if (!cpe || !cpe->core_handle) {
2446 dev_err(rtd->dev,
2447 "%s: Invalid private data\n",
2448 __func__);
2449 return -EINVAL;
2450 }
2451
2452 if (!lsm_d || !lsm_d->lsm_session) {
2453 dev_err(rtd->dev,
2454 "%s: Invalid session data\n",
2455 __func__);
2456 return -EINVAL;
2457 }
2458
2459 MSM_CPE_LSM_GRAB_LOCK(&lsm_d->lsm_api_lock,
2460 "lsm_api_lock");
2461
2462 session = lsm_d->lsm_session;
2463 lsm_ops = &cpe->lsm_ops;
2464
2465 switch (cmd) {
2466 case SNDRV_LSM_REG_SND_MODEL_V2_32: {
2467 struct snd_lsm_sound_model_v2 snd_model;
2468 struct snd_lsm_sound_model_v2_32 snd_model32;
2469
2470 if (session->is_topology_used) {
2471 dev_err(rtd->dev,
2472 "%s: %s: not supported if using topology\n",
2473 __func__, "LSM_REG_SND_MODEL_V2_32");
2474 err = -EINVAL;
2475 goto done;
2476 }
2477
2478 dev_dbg(rtd->dev,
2479 "%s: ioctl %s\n", __func__,
2480 "SNDRV_LSM_REG_SND_MODEL_V2_32");
2481
2482 if (copy_from_user(&snd_model32, (void *)arg,
2483 sizeof(snd_model32))) {
2484 dev_err(rtd->dev,
2485 "%s: copy from user failed, size %zd\n",
2486 __func__,
2487 sizeof(snd_model32));
2488 err = -EFAULT;
2489 goto done;
2490 }
2491
2492 snd_model.data = compat_ptr(snd_model32.data);
2493 snd_model.confidence_level =
2494 compat_ptr(snd_model32.confidence_level);
2495 snd_model.data_size = snd_model32.data_size;
2496 snd_model.detect_failure = snd_model32.detect_failure;
2497 snd_model.num_confidence_levels =
2498 snd_model32.num_confidence_levels;
2499 snd_model.detection_mode = snd_model32.detection_mode;
2500
2501 cmd = SNDRV_LSM_REG_SND_MODEL_V2;
2502 err = msm_cpe_lsm_ioctl_shared(substream, cmd, &snd_model);
2503 if (err)
2504 dev_err(rtd->dev,
2505 "%s: %s failed, error = %d\n",
2506 __func__,
2507 "SNDRV_LSM_REG_SND_MODEL_V2_32",
2508 err);
2509 }
2510 break;
2511 case SNDRV_LSM_EVENT_STATUS: {
2512 struct snd_lsm_event_status *event_status = NULL;
2513 struct snd_lsm_event_status u_event_status32;
2514 struct snd_lsm_event_status *udata_32 = NULL;
2515 int u_pld_size = 0;
2516
2517 dev_dbg(rtd->dev,
2518 "%s: ioctl %s\n", __func__,
2519 "SNDRV_LSM_EVENT_STATUS32");
2520
2521 if (copy_from_user(&u_event_status32, (void *)arg,
2522 sizeof(struct snd_lsm_event_status))) {
2523 dev_err(rtd->dev,
2524 "%s: event status copy from user failed, size %zd\n",
2525 __func__,
2526 sizeof(struct snd_lsm_event_status));
2527 err = -EFAULT;
2528 goto done;
2529 }
2530
2531 if (u_event_status32.payload_size >
2532 LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
2533 dev_err(rtd->dev,
2534 "%s: payload_size %d is invalid, max allowed = %d\n",
2535 __func__, u_event_status32.payload_size,
2536 LISTEN_MAX_STATUS_PAYLOAD_SIZE);
2537 err = -EINVAL;
2538 goto done;
2539 }
2540
2541 u_pld_size = sizeof(struct snd_lsm_event_status) +
2542 u_event_status32.payload_size;
2543 event_status = kzalloc(u_pld_size, GFP_KERNEL);
2544 if (!event_status) {
2545 dev_err(rtd->dev,
2546 "%s: No memory for event status\n",
2547 __func__);
2548 err = -ENOMEM;
2549 goto done;
2550 } else {
2551 event_status->payload_size =
2552 u_event_status32.payload_size;
2553 err = msm_cpe_lsm_ioctl_shared(substream,
2554 cmd, event_status);
2555 if (err)
2556 dev_err(rtd->dev,
2557 "%s: %s failed, error = %d\n",
2558 __func__,
2559 "SNDRV_LSM_EVENT_STATUS32",
2560 err);
2561 }
2562
2563 if (!err) {
2564 udata_32 = kzalloc(u_pld_size, GFP_KERNEL);
2565 if (!udata_32) {
2566 dev_err(rtd->dev,
2567 "%s: nomem for udata\n",
2568 __func__);
2569 err = -EFAULT;
2570 } else {
2571 udata_32->status = event_status->status;
2572 udata_32->payload_size =
2573 event_status->payload_size;
2574 memcpy(udata_32->payload,
2575 event_status->payload,
2576 u_pld_size);
2577 }
2578 }
2579
2580 if (!err && copy_to_user(arg, udata_32,
2581 u_pld_size)) {
2582 dev_err(rtd->dev,
2583 "%s: copy to user failed\n",
2584 __func__);
2585 kfree(event_status);
2586 kfree(udata_32);
2587 err = -EFAULT;
2588 goto done;
2589 }
2590
2591 msm_cpe_lsm_lab_start(substream, event_status->status);
2592 msm_cpe_process_event_status_done(lsm_d);
2593 kfree(event_status);
2594 kfree(udata_32);
2595 }
2596 break;
2597 case SNDRV_LSM_EVENT_STATUS_V3: {
2598 struct snd_lsm_event_status_v3 *event_status = NULL;
2599 struct snd_lsm_event_status_v3 u_event_status32;
2600 struct snd_lsm_event_status_v3 *udata_32 = NULL;
2601 int u_pld_size = 0;
2602
2603 dev_dbg(rtd->dev,
2604 "%s: ioctl %s\n", __func__,
2605 "SNDRV_LSM_EVENT_STATUS_V3_32");
2606
2607 if (copy_from_user(&u_event_status32, (void *)arg,
2608 sizeof(struct snd_lsm_event_status_v3))) {
2609 dev_err(rtd->dev,
2610 "%s: event status copy from user failed, size %zd\n",
2611 __func__,
2612 sizeof(struct snd_lsm_event_status_v3));
2613 err = -EFAULT;
2614 goto done;
2615 }
2616
2617 if (u_event_status32.payload_size >
2618 LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
2619 dev_err(rtd->dev,
2620 "%s: payload_size %d is invalid, max allowed = %d\n",
2621 __func__, u_event_status32.payload_size,
2622 LISTEN_MAX_STATUS_PAYLOAD_SIZE);
2623 err = -EINVAL;
2624 goto done;
2625 }
2626
2627 u_pld_size = sizeof(struct snd_lsm_event_status_v3) +
2628 u_event_status32.payload_size;
2629 event_status = kzalloc(u_pld_size, GFP_KERNEL);
2630 if (!event_status) {
2631 dev_err(rtd->dev,
2632 "%s: No memory for event status\n",
2633 __func__);
2634 err = -ENOMEM;
2635 goto done;
2636 } else {
2637 event_status->payload_size =
2638 u_event_status32.payload_size;
2639 err = msm_cpe_lsm_ioctl_shared(substream,
2640 cmd, event_status);
2641 if (err)
2642 dev_err(rtd->dev,
2643 "%s: %s failed, error = %d\n",
2644 __func__,
2645 "SNDRV_LSM_EVENT_STATUS_V3_32",
2646 err);
2647 }
2648
2649 if (!err) {
2650 udata_32 = kzalloc(u_pld_size, GFP_KERNEL);
2651 if (!udata_32) {
2652 dev_err(rtd->dev,
2653 "%s: nomem for udata\n",
2654 __func__);
2655 err = -EFAULT;
2656 } else {
2657 udata_32->timestamp_lsw =
2658 event_status->timestamp_lsw;
2659 udata_32->timestamp_msw =
2660 event_status->timestamp_msw;
2661 udata_32->status = event_status->status;
2662 udata_32->payload_size =
2663 event_status->payload_size;
2664 memcpy(udata_32->payload,
2665 event_status->payload,
2666 u_pld_size);
2667 }
2668 }
2669
2670 if (!err && copy_to_user(arg, udata_32,
2671 u_pld_size)) {
2672 dev_err(rtd->dev,
2673 "%s: copy to user failed\n",
2674 __func__);
2675 kfree(event_status);
2676 kfree(udata_32);
2677 err = -EFAULT;
2678 goto done;
2679 }
2680
2681 msm_cpe_lsm_lab_start(substream, event_status->status);
2682 msm_cpe_process_event_status_done(lsm_d);
2683 kfree(event_status);
2684 kfree(udata_32);
2685 }
2686 break;
2687 case SNDRV_LSM_SET_PARAMS32: {
2688 struct snd_lsm_detection_params_32 det_params32;
2689 struct snd_lsm_detection_params det_params;
2690
2691 if (session->is_topology_used) {
2692 dev_err(rtd->dev,
2693 "%s: %s: not supported if using topology\n",
2694 __func__, "SNDRV_LSM_SET_PARAMS32");
2695
2696 err = -EINVAL;
2697 goto done;
2698 }
2699
2700 if (copy_from_user(&det_params32, arg,
2701 sizeof(det_params32))) {
2702 err = -EFAULT;
2703 dev_err(rtd->dev,
2704 "%s: %s: copy_from_user failed, size = %zd\n",
2705 __func__, "SNDRV_LSM_SET_PARAMS_32",
2706 sizeof(det_params32));
2707 } else {
2708 det_params.conf_level =
2709 compat_ptr(det_params32.conf_level);
2710 det_params.detect_mode =
2711 det_params32.detect_mode;
2712 det_params.num_confidence_levels =
2713 det_params32.num_confidence_levels;
2714 det_params.detect_failure =
2715 det_params32.detect_failure;
2716 cmd = SNDRV_LSM_SET_PARAMS;
2717 err = msm_cpe_lsm_ioctl_shared(substream, cmd,
2718 &det_params);
2719 if (err)
2720 dev_err(rtd->dev,
2721 "%s: ioctl %s failed\n", __func__,
2722 "SNDRV_LSM_SET_PARAMS");
2723 }
2724
2725 break;
2726 }
2727
2728 case SNDRV_LSM_SET_MODULE_PARAMS_32: {
2729 struct snd_lsm_module_params_32 p_data_32;
2730 struct snd_lsm_module_params p_data;
2731 u8 *params, *params32;
2732 size_t p_size;
2733 struct lsm_params_info_32 *p_info_32;
2734 struct lsm_params_info *p_info;
2735 int i;
2736
2737 if (!session->is_topology_used) {
2738 dev_err(rtd->dev,
2739 "%s: %s: not supported if not using topology\n",
2740 __func__, "SET_MODULE_PARAMS_32");
2741 err = -EINVAL;
2742 goto done;
2743 }
2744
2745 if (copy_from_user(&p_data_32, arg,
2746 sizeof(p_data_32))) {
2747 dev_err(rtd->dev,
2748 "%s: %s: copy_from_user failed, size = %zd\n",
2749 __func__, "SET_MODULE_PARAMS_32",
2750 sizeof(p_data_32));
2751 err = -EFAULT;
2752 goto done;
2753 }
2754
2755 p_data.params = compat_ptr(p_data_32.params);
2756 p_data.num_params = p_data_32.num_params;
2757 p_data.data_size = p_data_32.data_size;
2758
2759 if (p_data.num_params > LSM_PARAMS_MAX) {
2760 dev_err(rtd->dev,
2761 "%s: %s: Invalid num_params %d\n",
2762 __func__, "SET_MODULE_PARAMS_32",
2763 p_data.num_params);
2764 err = -EINVAL;
2765 goto done;
2766 }
2767
2768 if (p_data.data_size !=
2769 (p_data.num_params * sizeof(struct lsm_params_info_32))) {
2770 dev_err(rtd->dev,
2771 "%s: %s: Invalid size %d\n",
2772 __func__, "SET_MODULE_PARAMS_32",
2773 p_data.data_size);
2774 err = -EINVAL;
2775 goto done;
2776 }
2777
2778 p_size = sizeof(struct lsm_params_info_32) *
2779 p_data.num_params;
2780
2781 params32 = kzalloc(p_size, GFP_KERNEL);
2782 if (!params32) {
2783 err = -ENOMEM;
2784 goto done;
2785 }
2786
2787 p_size = sizeof(struct lsm_params_info) * p_data.num_params;
2788 params = kzalloc(p_size, GFP_KERNEL);
2789 if (!params) {
2790 kfree(params32);
2791 err = -ENOMEM;
2792 goto done;
2793 }
2794
2795 if (copy_from_user(params32, p_data.params,
2796 p_data.data_size)) {
2797 dev_err(rtd->dev,
2798 "%s: %s: copy_from_user failed, size = %d\n",
2799 __func__, "params32", p_data.data_size);
2800 kfree(params32);
2801 kfree(params);
2802 err = -EFAULT;
2803 goto done;
2804 }
2805
2806 p_info_32 = (struct lsm_params_info_32 *) params32;
2807 p_info = (struct lsm_params_info *) params;
2808 for (i = 0; i < p_data.num_params; i++) {
2809 p_info->module_id = p_info_32->module_id;
2810 p_info->param_id = p_info_32->param_id;
2811 p_info->param_size = p_info_32->param_size;
2812 p_info->param_data = compat_ptr(p_info_32->param_data);
2813 p_info->param_type = p_info_32->param_type;
2814
2815 p_info_32++;
2816 p_info++;
2817 }
2818
2819 err = msm_cpe_lsm_process_params(substream,
2820 &p_data, params);
2821 if (err)
2822 dev_err(rtd->dev,
2823 "%s: Failed to process params, err = %d\n",
2824 __func__, err);
2825 kfree(params);
2826 kfree(params32);
2827 break;
2828 }
2829 case SNDRV_LSM_REG_SND_MODEL_V2:
2830 case SNDRV_LSM_SET_PARAMS:
2831 case SNDRV_LSM_SET_MODULE_PARAMS:
2832 /*
2833 * In ideal cases, the compat_ioctl should never be called
2834 * with the above unlocked ioctl commands. Print error
2835 * and return error if it does.
2836 */
2837 dev_err(rtd->dev,
2838 "%s: Invalid cmd for compat_ioctl\n",
2839 __func__);
2840 err = -EINVAL;
2841 break;
2842 default:
2843 err = msm_cpe_lsm_ioctl_shared(substream, cmd, arg);
2844 break;
2845 }
2846done:
2847 MSM_CPE_LSM_REL_LOCK(&lsm_d->lsm_api_lock,
2848 "lsm_api_lock");
2849 return err;
2850}
2851
2852#else
2853#define msm_cpe_lsm_ioctl_compat NULL
2854#endif
2855
2856/*
2857 * msm_cpe_lsm_prepare: prepare call from ASoC core for this platform
2858 * @substream: ASoC substream for which the operation is invoked
2859 *
2860 * start the AFE port on CPE associated for this listen session
2861 */
2862static int msm_cpe_lsm_prepare(struct snd_pcm_substream *substream)
2863{
2864 int rc = 0;
2865 struct cpe_priv *cpe = cpe_get_private_data(substream);
2866 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
2867 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2868 struct wcd_cpe_afe_ops *afe_ops;
2869 struct wcd_cpe_afe_port_cfg *afe_cfg;
2870 struct cpe_lsm_session *lsm_session;
2871 struct cpe_lsm_lab *lab_d = &lsm_d->lab;
2872 struct snd_pcm_runtime *runtime = substream->runtime;
2873 struct lsm_hw_params lsm_param;
2874 struct wcd_cpe_lsm_ops *lsm_ops;
2875
2876 if (!cpe || !cpe->core_handle) {
2877 dev_err(rtd->dev,
2878 "%s: Invalid private data\n",
2879 __func__);
2880 return -EINVAL;
2881 }
2882
2883 if (!lsm_d || !lsm_d->lsm_session) {
2884 dev_err(rtd->dev,
2885 "%s: Invalid session data\n",
2886 __func__);
2887 return -EINVAL;
2888 }
2889 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
2890 runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
2891 pr_err("%s: XRUN ignore for now\n", __func__);
2892 return 0;
2893 }
2894
2895 lsm_session = lsm_d->lsm_session;
2896 lab_d->pcm_size = snd_pcm_lib_buffer_bytes(substream);
2897
2898 dev_dbg(rtd->dev,
2899 "%s: pcm_size 0x%x", __func__, lab_d->pcm_size);
2900
2901 if (lsm_d->cpe_prepared) {
2902 dev_dbg(rtd->dev, "%s: CPE is alredy prepared\n",
2903 __func__);
2904 return 0;
2905 }
2906
2907 lsm_ops = &cpe->lsm_ops;
2908 afe_ops = &cpe->afe_ops;
2909 afe_cfg = &(lsm_d->lsm_session->afe_port_cfg);
2910
2911 switch (cpe->input_port_id) {
2912 case AFE_PORT_ID_3:
2913 afe_cfg->port_id = AFE_PORT_ID_3;
2914 afe_cfg->bit_width = 16;
2915 afe_cfg->num_channels = 1;
2916 afe_cfg->sample_rate = SAMPLE_RATE_48KHZ;
2917 rc = afe_ops->afe_port_cmd_cfg(cpe->core_handle, afe_cfg);
2918 break;
2919 case AFE_PORT_ID_1:
2920 default:
2921 afe_cfg->port_id = AFE_PORT_ID_1;
2922 afe_cfg->bit_width = 16;
2923 afe_cfg->num_channels = 1;
2924 afe_cfg->sample_rate = SAMPLE_RATE_16KHZ;
2925 rc = afe_ops->afe_set_params(cpe->core_handle,
2926 afe_cfg, cpe->afe_mad_ctl);
2927 break;
2928 }
2929
2930 if (rc != 0) {
2931 dev_err(rtd->dev,
2932 "%s: cpe afe params failed for port = %d, err = %d\n",
2933 __func__, afe_cfg->port_id, rc);
2934 return rc;
2935 }
2936 lsm_param.sample_rate = afe_cfg->sample_rate;
2937 lsm_param.num_chs = afe_cfg->num_channels;
2938 lsm_param.bit_width = afe_cfg->bit_width;
2939 rc = lsm_ops->lsm_set_media_fmt_params(cpe->core_handle, lsm_session,
2940 &lsm_param);
2941 if (rc)
2942 dev_dbg(rtd->dev,
2943 "%s: failed to set lsm media fmt params, err = %d\n",
2944 __func__, rc);
2945
2946 /* Send connect to port (input) */
2947 rc = lsm_ops->lsm_set_port(cpe->core_handle, lsm_session,
2948 &cpe->input_port_id);
2949 if (rc) {
2950 dev_err(rtd->dev,
2951 "%s: Failed to set connect input port, err=%d\n",
2952 __func__, rc);
2953 return rc;
2954 }
2955
2956 if (cpe->input_port_id != 3) {
2957 rc = lsm_ops->lsm_get_afe_out_port_id(cpe->core_handle,
2958 lsm_session);
2959 if (rc != 0) {
2960 dev_err(rtd->dev,
2961 "%s: failed to get port id, err = %d\n",
2962 __func__, rc);
2963 return rc;
2964 }
2965 /* Send connect to port (output) */
2966 rc = lsm_ops->lsm_set_port(cpe->core_handle, lsm_session,
2967 &lsm_session->afe_out_port_id);
2968 if (rc) {
2969 dev_err(rtd->dev,
2970 "%s: Failed to set connect output port, err=%d\n",
2971 __func__, rc);
2972 return rc;
2973 }
2974 }
2975 rc = msm_cpe_afe_port_cntl(substream,
2976 cpe->core_handle,
2977 afe_ops, afe_cfg,
2978 AFE_CMD_PORT_START);
2979 if (rc)
2980 dev_err(rtd->dev,
2981 "%s: cpe_afe_port start failed, err = %d\n",
2982 __func__, rc);
2983 else
2984 lsm_d->cpe_prepared = true;
2985
2986 return rc;
2987}
2988
2989/*
2990 * msm_cpe_lsm_trigger: trigger call from ASoC core for this platform
2991 * @substream: ASoC substream for which the operation is invoked
2992 * @cmd: the trigger command from framework
2993 *
2994 * suspend/resume the AFE port on CPE associated with listen session
2995 */
2996static int msm_cpe_lsm_trigger(struct snd_pcm_substream *substream,
2997 int cmd)
2998{
2999 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3000 struct cpe_priv *cpe = cpe_get_private_data(substream);
3001 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
3002 struct wcd_cpe_afe_ops *afe_ops;
3003 struct wcd_cpe_afe_port_cfg *afe_cfg;
3004 int afe_cmd = AFE_CMD_INVALID;
3005 int rc = 0;
3006
3007 if (!cpe || !cpe->core_handle) {
3008 dev_err(rtd->dev,
3009 "%s: Invalid private data\n",
3010 __func__);
3011 return -EINVAL;
3012 }
3013
3014 if (!lsm_d || !lsm_d->lsm_session) {
3015 dev_err(rtd->dev,
3016 "%s: Invalid session data\n",
3017 __func__);
3018 return -EINVAL;
3019 }
3020
3021 afe_ops = &cpe->afe_ops;
3022 afe_cfg = &(lsm_d->lsm_session->afe_port_cfg);
3023
3024 switch (cmd) {
3025 case SNDRV_PCM_TRIGGER_SUSPEND:
3026 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
3027 afe_cmd = AFE_CMD_PORT_SUSPEND;
3028 break;
3029
3030 case SNDRV_PCM_TRIGGER_RESUME:
3031 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
3032 afe_cmd = AFE_CMD_PORT_RESUME;
3033 break;
3034
3035 default:
3036 afe_cmd = AFE_CMD_INVALID;
3037 dev_dbg(rtd->dev,
3038 "%s: unhandled trigger cmd %d\n",
3039 __func__, cmd);
3040 break;
3041 }
3042
3043 if (afe_cmd != AFE_CMD_INVALID)
3044 rc = msm_cpe_afe_port_cntl(substream,
3045 cpe->core_handle,
3046 afe_ops, afe_cfg,
3047 afe_cmd);
3048
3049 return rc;
3050}
3051
3052static int msm_cpe_lsm_hwparams(struct snd_pcm_substream *substream,
3053 struct snd_pcm_hw_params *params)
3054{
3055
3056 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3057 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
3058 struct cpe_priv *cpe = cpe_get_private_data(substream);
3059 struct cpe_lsm_session *session = NULL;
3060 struct cpe_hw_params *hw_params = NULL;
3061
3062 if (!cpe || !cpe->core_handle) {
3063 dev_err(rtd->dev,
3064 "%s: Invalid %s\n",
3065 __func__,
3066 (!cpe) ? "cpe" : "core");
3067 return -EINVAL;
3068 }
3069
3070 if (!lsm_d || !lsm_d->lsm_session) {
3071 dev_err(rtd->dev,
3072 "%s: Invalid %s\n",
3073 __func__,
3074 (!lsm_d) ? "priv_data" : "session");
3075 return -EINVAL;
3076 }
3077
3078 session = lsm_d->lsm_session;
3079 hw_params = &lsm_d->hw_params;
3080 hw_params->buf_sz = (params_buffer_bytes(params)
3081 / params_periods(params));
3082 hw_params->period_count = params_periods(params);
3083 hw_params->channels = params_channels(params);
3084 hw_params->sample_rate = params_rate(params);
3085
3086 if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
3087 hw_params->sample_size = 16;
3088 else if (params_format(params) ==
3089 SNDRV_PCM_FORMAT_S24_LE)
3090 hw_params->sample_size = 24;
3091 else if (params_format(params) ==
3092 SNDRV_PCM_FORMAT_S32_LE)
3093 hw_params->sample_size = 32;
3094 else {
3095 dev_err(rtd->dev,
3096 "%s: Invalid Format 0x%x\n",
3097 __func__, params_format(params));
3098 return -EINVAL;
3099 }
3100
3101 dev_dbg(rtd->dev,
3102 "%s: Format %d buffer size(bytes) %d period count %d\n"
3103 " Channel %d period in bytes 0x%x Period Size 0x%x rate = %d\n",
3104 __func__, params_format(params), params_buffer_bytes(params),
3105 params_periods(params), params_channels(params),
3106 params_period_bytes(params), params_period_size(params),
3107 params_rate(params));
3108
3109 return 0;
3110}
3111
3112static snd_pcm_uframes_t msm_cpe_lsm_pointer(
3113 struct snd_pcm_substream *substream)
3114{
3115
3116 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
3117 struct snd_pcm_runtime *runtime = substream->runtime;
3118 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3119 struct cpe_lsm_session *session;
3120 struct cpe_lsm_lab *lab_d = &lsm_d->lab;
3121
3122 session = lsm_d->lsm_session;
3123 if (lab_d->dma_write >= lab_d->pcm_size)
3124 lab_d->dma_write = 0;
3125 dev_dbg(rtd->dev,
3126 "%s:pcm_dma_pos = %d\n",
3127 __func__, lab_d->dma_write);
3128
3129 return bytes_to_frames(runtime, (lab_d->dma_write));
3130}
3131
3132static int msm_cpe_lsm_copy(struct snd_pcm_substream *substream, int a,
Meng Wangac147b72017-10-30 16:46:16 +08003133 unsigned long hwoff, void __user *buf, unsigned long fbytes)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303134{
3135 struct cpe_lsm_data *lsm_d = cpe_get_lsm_data(substream);
3136 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3137 struct snd_pcm_runtime *runtime = substream->runtime;
3138 struct cpe_lsm_session *session;
3139 struct cpe_lsm_lab *lab_d = &lsm_d->lab;
3140 char *pcm_buf;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303141 int rc = 0;
3142
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303143 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
3144 runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
3145 pr_err("%s: XRUN ignore for now\n", __func__);
3146 return 0;
3147 }
3148 session = lsm_d->lsm_session;
3149
3150 /* Check if buffer reading is already in error state */
3151 if (lab_d->thread_status == MSM_LSM_LAB_THREAD_ERROR) {
3152 dev_err(rtd->dev,
3153 "%s: Bufferring is in error state\n",
3154 __func__);
3155 /*
3156 * Advance the period so there is no wait in case
3157 * read is invoked even after error is propogated
3158 */
3159 atomic_inc(&lab_d->in_count);
3160 lab_d->dma_write += snd_pcm_lib_period_bytes(substream);
3161 snd_pcm_period_elapsed(substream);
3162 return -ENETRESET;
3163 } else if (lab_d->thread_status == MSM_LSM_LAB_THREAD_STOP) {
3164 dev_err(rtd->dev,
3165 "%s: Buferring is in stopped\n",
3166 __func__);
3167 return -EIO;
3168 }
3169
3170 rc = wait_event_timeout(lab_d->period_wait,
3171 (atomic_read(&lab_d->in_count) ||
3172 atomic_read(&lab_d->abort_read)),
3173 (2 * HZ));
3174 if (atomic_read(&lab_d->abort_read)) {
3175 pr_debug("%s: LSM LAB Abort read\n", __func__);
3176 return -EIO;
3177 }
3178 if (lab_d->thread_status != MSM_LSM_LAB_THREAD_RUNNING) {
3179 pr_err("%s: Lab stopped\n", __func__);
3180 return -EIO;
3181 }
3182 if (!rc) {
3183 pr_err("%s:LAB err wait_event_timeout\n", __func__);
3184 rc = -EAGAIN;
3185 goto fail;
3186 }
3187 if (lab_d->buf_idx >= (lsm_d->hw_params.period_count))
3188 lab_d->buf_idx = 0;
3189 pcm_buf = (lab_d->pcm_buf[lab_d->buf_idx].mem);
3190 pr_debug("%s: Buf IDX = 0x%x pcm_buf %pK\n",
3191 __func__, lab_d->buf_idx, pcm_buf);
3192 if (pcm_buf) {
3193 if (copy_to_user(buf, pcm_buf, fbytes)) {
3194 pr_err("Failed to copy buf to user\n");
3195 rc = -EFAULT;
3196 goto fail;
3197 }
3198 }
3199 lab_d->buf_idx++;
3200 atomic_dec(&lab_d->in_count);
3201 return 0;
3202fail:
3203 return rc;
3204}
3205
3206/*
Meng Wangee084a02018-09-04 16:11:58 +08003207 * msm_asoc_cpe_lsm_probe: ASoC framework for lsm component driver
3208 * @component: component registered with ASoC core
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303209 *
Meng Wangee084a02018-09-04 16:11:58 +08003210 * Allocate the private data for this component and obtain the ops for
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303211 * lsm and afe modules from underlying driver. Also find the codec
Meng Wangee084a02018-09-04 16:11:58 +08003212 * for this component as specified by machine driver for ASoC framework.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303213 */
Meng Wangee084a02018-09-04 16:11:58 +08003214static int msm_asoc_cpe_lsm_probe(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303215{
3216 struct snd_soc_card *card;
3217 struct snd_soc_pcm_runtime *rtd;
3218 struct snd_soc_codec *codec;
3219 struct cpe_priv *cpe_priv;
Meng Wangee084a02018-09-04 16:11:58 +08003220 struct snd_soc_component *component_rtd = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303221 const struct snd_kcontrol_new *kcontrol;
3222 bool found_runtime = false;
3223 const char *cpe_dev_id = "qcom,msm-cpe-lsm-id";
3224 u32 port_id = 0;
3225 int ret = 0;
3226
Meng Wangee084a02018-09-04 16:11:58 +08003227 if (!component || !component->card) {
3228 pr_err("%s: Invalid component or card\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303229 __func__);
3230 return -EINVAL;
3231 }
3232
Meng Wangee084a02018-09-04 16:11:58 +08003233 card = component->card;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303234
Meng Wangee084a02018-09-04 16:11:58 +08003235 /* Match component to codec */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303236 list_for_each_entry(rtd, &card->rtd_list, list) {
Meng Wangee084a02018-09-04 16:11:58 +08003237 component_rtd = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
3238 if (!component_rtd)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303239 continue;
Meng Wangee084a02018-09-04 16:11:58 +08003240 if (!strcmp(component_rtd->name,
3241 component->name)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303242 found_runtime = true;
3243 break;
3244 }
3245 }
3246
3247 if (!found_runtime) {
Meng Wangee084a02018-09-04 16:11:58 +08003248 dev_err(component->dev,
3249 "%s: Failed to find runtime for component\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303250 __func__);
3251 return -EINVAL;
3252 }
3253
Meng Wangee084a02018-09-04 16:11:58 +08003254 ret = of_property_read_u32(component->dev->of_node, cpe_dev_id,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303255 &port_id);
3256 if (ret) {
Meng Wangee084a02018-09-04 16:11:58 +08003257 dev_dbg(component->dev,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303258 "%s: missing 0x%x in dt node\n", __func__, port_id);
3259 port_id = 1;
3260 }
3261
3262 codec = rtd->codec;
3263
3264 cpe_priv = kzalloc(sizeof(struct cpe_priv),
3265 GFP_KERNEL);
3266 if (!cpe_priv)
3267 return -ENOMEM;
3268
3269 cpe_priv->codec = codec;
3270 cpe_priv->input_port_id = port_id;
3271 wcd_cpe_get_lsm_ops(&cpe_priv->lsm_ops);
3272 wcd_cpe_get_afe_ops(&cpe_priv->afe_ops);
3273
Meng Wangee084a02018-09-04 16:11:58 +08003274 snd_soc_component_set_drvdata(component, cpe_priv);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303275 kcontrol = &msm_cpe_kcontrols[0];
3276 snd_ctl_add(card->snd_card, snd_ctl_new1(kcontrol, cpe_priv));
3277 return 0;
3278}
3279
3280static const struct snd_pcm_ops msm_cpe_lsm_ops = {
3281 .open = msm_cpe_lsm_open,
3282 .close = msm_cpe_lsm_close,
3283 .ioctl = msm_cpe_lsm_ioctl,
3284 .prepare = msm_cpe_lsm_prepare,
3285 .trigger = msm_cpe_lsm_trigger,
3286 .pointer = msm_cpe_lsm_pointer,
Meng Wangac147b72017-10-30 16:46:16 +08003287 .copy_user = msm_cpe_lsm_copy,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303288 .hw_params = msm_cpe_lsm_hwparams,
3289 .compat_ioctl = msm_cpe_lsm_ioctl_compat,
3290};
3291
Meng Wangee084a02018-09-04 16:11:58 +08003292static struct snd_soc_component_driver msm_soc_cpe_component = {
3293 .name = DRV_NAME,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303294 .ops = &msm_cpe_lsm_ops,
3295 .probe = msm_asoc_cpe_lsm_probe,
3296};
3297
3298/*
3299 * msm_cpe_lsm_probe: platform driver probe
3300 * @pdev: platform device
3301 *
3302 * Register the ASoC platform driver with ASoC core
3303 */
3304static int msm_cpe_lsm_probe(struct platform_device *pdev)
3305{
3306
Meng Wangee084a02018-09-04 16:11:58 +08003307 return snd_soc_register_component(&pdev->dev,
3308 &msm_soc_cpe_component,
3309 NULL, 0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303310}
3311
3312/*
3313 * msm_cpe_lsm_remove: platform driver remove
3314 * @pdev: platform device
3315 *
3316 * Deregister the ASoC platform driver
3317 */
3318static int msm_cpe_lsm_remove(struct platform_device *pdev)
3319{
Meng Wangee084a02018-09-04 16:11:58 +08003320 snd_soc_unregister_commponent(&pdev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303321 return 0;
3322}
3323
3324static const struct of_device_id msm_cpe_lsm_dt_match[] = {
3325 {.compatible = "qcom,msm-cpe-lsm" },
3326 { }
3327};
3328
3329static struct platform_driver msm_cpe_lsm_driver = {
3330 .driver = {
3331 .name = "msm-cpe-lsm",
3332 .owner = THIS_MODULE,
3333 .of_match_table = of_match_ptr(msm_cpe_lsm_dt_match),
Xiaojun Sang53cd13a2018-06-29 15:14:37 +08003334 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303335 },
3336 .probe = msm_cpe_lsm_probe,
3337 .remove = msm_cpe_lsm_remove,
3338};
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303339
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303340int __init msm_cpe_lsm_init(void)
3341{
3342 return platform_driver_register(&msm_cpe_lsm_driver);
3343}
3344
3345void __exit msm_cpe_lsm_exit(void)
3346{
3347 platform_driver_unregister(&msm_cpe_lsm_driver);
3348}
3349
3350module_init(msm_cpe_lsm_init);
3351module_exit(msm_cpe_lsm_exit);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303352MODULE_DESCRIPTION("CPE LSM platform driver");
3353MODULE_DEVICE_TABLE(of, msm_cpe_lsm_dt_match);
3354MODULE_LICENSE("GPL v2");