blob: 554e866e08bc21f559a3e5707a45630ac543efa3 [file] [log] [blame]
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301/*
kunleiz5574e742019-04-12 11:28:19 +08002 * Copyright (c) 2013-2019, Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13#include <linux/fs.h>
14#include <linux/mutex.h>
15#include <linux/wait.h>
16#include <linux/miscdevice.h>
17#include <linux/uaccess.h>
18#include <linux/sched.h>
19#include <linux/miscdevice.h>
20#include <linux/delay.h>
21#include <linux/spinlock.h>
22#include <linux/slab.h>
23#include <linux/debugfs.h>
24#include <linux/time.h>
25#include <linux/atomic.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053026#include <sound/lsm_params.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053027#include <asm/ioctls.h>
28#include <linux/memory.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053029#include <dsp/msm_audio_ion.h>
30#include <dsp/apr_audio-v2.h>
31#include <dsp/q6core.h>
32#include <dsp/q6lsm.h>
33#include <dsp/q6afe-v2.h>
34#include <dsp/audio_cal_utils.h>
35#include "adsp_err.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053036
37#define APR_TIMEOUT (5 * HZ)
38#define LSM_ALIGN_BOUNDARY 512
39#define LSM_SAMPLE_RATE 16000
40#define QLSM_PARAM_ID_MINOR_VERSION 1
41#define QLSM_PARAM_ID_MINOR_VERSION_2 2
42
43static int lsm_afe_port;
44
45enum {
46 LSM_CUSTOM_TOP_IDX,
47 LSM_TOP_IDX,
48 LSM_CAL_IDX,
49 LSM_MAX_CAL_IDX
50};
51
52enum {
53 CMD_STATE_CLEARED = 0,
54 CMD_STATE_WAIT_RESP = 1,
55};
56
57enum {
58 LSM_INVALID_SESSION_ID = 0,
59 LSM_MIN_SESSION_ID = 1,
60 LSM_MAX_SESSION_ID = 8,
61 LSM_CONTROL_SESSION = 0x0F,
62};
63
64#define CHECK_SESSION(x) (x < LSM_MIN_SESSION_ID || x > LSM_MAX_SESSION_ID)
65struct lsm_common {
66 void *apr;
67 atomic_t apr_users;
68 struct lsm_client common_client[LSM_MAX_SESSION_ID + 1];
69
70 int set_custom_topology;
71 struct cal_type_data *cal_data[LSM_MAX_CAL_IDX];
72
73 struct mutex apr_lock;
74};
75
76struct lsm_module_param_ids {
77 uint32_t module_id;
78 uint32_t param_id;
79};
80
Laxminath Kasamf8cc0e02018-06-30 19:57:10 +053081static DEFINE_MUTEX(session_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053082static struct lsm_common lsm_common;
83/*
84 * mmap_handle_p can point either client->sound_model.mem_map_handle or
85 * lsm_common.mmap_handle_for_cal.
86 * mmap_lock must be held while accessing this.
87 */
88static spinlock_t mmap_lock;
89static uint32_t *mmap_handle_p;
90
91static spinlock_t lsm_session_lock;
92static struct lsm_client *lsm_session[LSM_MAX_SESSION_ID + 1];
93
94static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
95static int q6lsm_send_cal(struct lsm_client *client, u32 set_params_opcode);
96static int q6lsm_memory_map_regions(struct lsm_client *client,
97 dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
98 uint32_t *mmap_p);
99static int q6lsm_memory_unmap_regions(struct lsm_client *client,
100 uint32_t handle);
101
102static void q6lsm_set_param_hdr_info(
103 struct lsm_set_params_hdr *param_hdr,
104 u32 payload_size, u32 addr_lsw, u32 addr_msw,
105 u32 mmap_handle)
106{
107 param_hdr->data_payload_size = payload_size;
108 param_hdr->data_payload_addr_lsw = addr_lsw;
109 param_hdr->data_payload_addr_msw = addr_msw;
110 param_hdr->mem_map_handle = mmap_handle;
111}
112
113static void q6lsm_set_param_common(
114 struct lsm_param_payload_common *common,
115 struct lsm_module_param_ids *ids,
116 u32 param_size, u32 set_param_version)
117{
118 common->module_id = ids->module_id;
119 common->param_id = ids->param_id;
120
121 switch (set_param_version) {
122 case LSM_SESSION_CMD_SET_PARAMS_V2:
123 common->p_size.param_size = param_size;
124 break;
125 case LSM_SESSION_CMD_SET_PARAMS:
126 default:
127 common->p_size.sr.param_size =
128 (u16) param_size;
129 common->p_size.sr.reserved = 0;
130 break;
131 }
132}
133
Laxminath Kasamf8cc0e02018-06-30 19:57:10 +0530134static int q6lsm_get_session_id_from_lsm_client(struct lsm_client *client)
135{
136 int n;
137
138 for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
139 if (lsm_session[n] == client)
140 return n;
141 }
142 pr_err("%s: cannot find matching lsm client. client = %pa\n",
143 __func__, client);
144 return LSM_INVALID_SESSION_ID;
145}
146
147static bool q6lsm_is_valid_lsm_client(struct lsm_client *client)
148{
149 return q6lsm_get_session_id_from_lsm_client(client) ? 1 : 0;
150}
151
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530152static int q6lsm_callback(struct apr_client_data *data, void *priv)
153{
154 struct lsm_client *client = (struct lsm_client *)priv;
155 uint32_t token;
156 uint32_t *payload;
157
158 if (!client || !data) {
159 pr_err("%s: client %pK data %pK\n",
160 __func__, client, data);
161 WARN_ON(1);
162 return -EINVAL;
163 }
164
165 if (data->opcode == RESET_EVENTS) {
166 pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
167 __func__, data->opcode, data->reset_event,
168 data->reset_proc);
169
Laxminath Kasamf8cc0e02018-06-30 19:57:10 +0530170 mutex_lock(&session_lock);
171 if (!client || !q6lsm_is_valid_lsm_client(client)) {
172 pr_err("%s: client already freed/invalid, return\n",
173 __func__);
174 mutex_unlock(&session_lock);
175 return 0;
176 }
Xiaoyu Yefb90eb62017-10-10 12:26:08 -0700177 apr_reset(client->apr);
178 client->apr = NULL;
179 atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
180 wake_up(&client->cmd_wait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530181 cal_utils_clear_cal_block_q6maps(LSM_MAX_CAL_IDX,
182 lsm_common.cal_data);
183 mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
184 lsm_common.set_custom_topology = 1;
185 mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
Laxminath Kasamf8cc0e02018-06-30 19:57:10 +0530186 mutex_unlock(&session_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530187 return 0;
188 }
189
190 payload = data->payload;
191 pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n"
192 "payload [0] = 0x%x\n", __func__, client->session,
193 data->opcode, data->token, data->payload_size, payload[0]);
194 if (data->opcode == LSM_DATA_EVENT_READ_DONE) {
195 struct lsm_cmd_read_done read_done;
196
197 token = data->token;
kunleiz5574e742019-04-12 11:28:19 +0800198 if (data->payload_size > sizeof(read_done) ||
199 data->payload_size < 6 * sizeof(payload[0])) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530200 pr_err("%s: read done error payload size %d expected size %zd\n",
201 __func__, data->payload_size,
202 sizeof(read_done));
203 return -EINVAL;
204 }
205 pr_debug("%s: opcode %x status %x lsw %x msw %x mem_map handle %x\n",
206 __func__, data->opcode, payload[0], payload[1],
207 payload[2], payload[3]);
208 read_done.status = payload[0];
209 read_done.buf_addr_lsw = payload[1];
210 read_done.buf_addr_msw = payload[2];
211 read_done.mem_map_handle = payload[3];
212 read_done.total_size = payload[4];
213 read_done.offset = payload[5];
214 if (client->cb)
215 client->cb(data->opcode, data->token,
216 (void *)&read_done,
kunleiz5574e742019-04-12 11:28:19 +0800217 sizeof(read_done),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530218 client->priv);
219 return 0;
220 } else if (data->opcode == APR_BASIC_RSP_RESULT) {
221 token = data->token;
222 switch (payload[0]) {
223 case LSM_SESSION_CMD_START:
224 case LSM_SESSION_CMD_STOP:
225 case LSM_SESSION_CMD_SET_PARAMS:
226 case LSM_SESSION_CMD_OPEN_TX:
227 case LSM_SESSION_CMD_CLOSE_TX:
228 case LSM_SESSION_CMD_REGISTER_SOUND_MODEL:
229 case LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL:
230 case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
231 case LSM_SESSION_CMD_EOB:
232 case LSM_SESSION_CMD_READ:
233 case LSM_SESSION_CMD_OPEN_TX_V2:
234 case LSM_CMD_ADD_TOPOLOGIES:
235 case LSM_SESSION_CMD_SET_PARAMS_V2:
236 if (token != client->session &&
237 payload[0] !=
238 LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL) {
239 pr_err("%s: Invalid session %d receivced expected %d\n",
240 __func__, token, client->session);
241 return -EINVAL;
242 }
kunleiz5574e742019-04-12 11:28:19 +0800243 if (data->payload_size < 2 * sizeof(payload[0])) {
244 pr_err("%s: payload has invalid size[%d]\n",
245 __func__, data->payload_size);
246 return -EINVAL;
247 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530248 client->cmd_err_code = payload[1];
249 if (client->cmd_err_code)
250 pr_err("%s: cmd 0x%x failed status %d\n",
251 __func__, payload[0], client->cmd_err_code);
252 if (atomic_cmpxchg(&client->cmd_state,
253 CMD_STATE_WAIT_RESP,
254 CMD_STATE_CLEARED) ==
255 CMD_STATE_WAIT_RESP)
256 wake_up(&client->cmd_wait);
257 break;
258 default:
259 pr_debug("%s: Unknown command 0x%x\n",
260 __func__, payload[0]);
261 break;
262 }
263 return 0;
264 }
265
266 if (client->cb)
267 client->cb(data->opcode, data->token, data->payload,
kunleiz5574e742019-04-12 11:28:19 +0800268 data->payload_size, client->priv);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530269
270 return 0;
271}
272
273static int q6lsm_session_alloc(struct lsm_client *client)
274{
275 unsigned long flags;
276 int n, ret = -ENOMEM;
277
278 spin_lock_irqsave(&lsm_session_lock, flags);
279 for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
280 if (!lsm_session[n]) {
281 lsm_session[n] = client;
282 ret = n;
283 break;
284 }
285 }
286 spin_unlock_irqrestore(&lsm_session_lock, flags);
287 pr_debug("%s: Alloc Session %d", __func__, n);
288 return ret;
289}
290
291static void q6lsm_session_free(struct lsm_client *client)
292{
293 unsigned long flags;
294
295 pr_debug("%s: Freeing session ID %d\n", __func__, client->session);
296 spin_lock_irqsave(&lsm_session_lock, flags);
Soumya Managolia8eda112019-11-11 18:44:59 +0530297 lsm_session[client->session] = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530298 spin_unlock_irqrestore(&lsm_session_lock, flags);
299 client->session = LSM_INVALID_SESSION_ID;
300}
301
302static void *q6lsm_mmap_apr_reg(void)
303{
304 if (atomic_inc_return(&lsm_common.apr_users) == 1) {
305 lsm_common.apr =
306 apr_register("ADSP", "LSM", q6lsm_mmapcallback,
307 0x0FFFFFFFF, &lsm_common);
308 if (!lsm_common.apr) {
309 pr_debug("%s: Unable to register APR LSM common port\n",
310 __func__);
311 atomic_dec(&lsm_common.apr_users);
312 }
313 }
314 return lsm_common.apr;
315}
316
317static int q6lsm_mmap_apr_dereg(void)
318{
319 if (atomic_read(&lsm_common.apr_users) <= 0) {
320 WARN("%s: APR common port already closed\n", __func__);
321 } else {
322 if (atomic_dec_return(&lsm_common.apr_users) == 0) {
323 apr_deregister(lsm_common.apr);
324 pr_debug("%s: APR De-Register common port\n", __func__);
325 }
326 }
327 return 0;
328}
329
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530330/**
331 * q6lsm_client_alloc -
332 * Allocate session for LSM client
333 *
334 * @cb: callback fn
335 * @priv: private data
336 *
337 * Returns LSM client handle on success or NULL on failure
338 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530339struct lsm_client *q6lsm_client_alloc(lsm_app_cb cb, void *priv)
340{
341 struct lsm_client *client;
342 int n;
343
344 client = kzalloc(sizeof(struct lsm_client), GFP_KERNEL);
345 if (!client)
346 return NULL;
347 n = q6lsm_session_alloc(client);
348 if (n <= 0) {
349 kfree(client);
350 return NULL;
351 }
352 client->session = n;
353 client->cb = cb;
354 client->priv = priv;
355 if (CHECK_SESSION(client->session)) {
356 pr_err("%s: Client session %d\n",
357 __func__, client->session);
358 kfree(client);
359 return NULL;
360 }
pavanc34c1d6d2018-06-06 12:13:17 +0530361
362 init_waitqueue_head(&client->cmd_wait);
363 mutex_init(&client->cmd_lock);
364 atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
365
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530366 pr_debug("%s: Client Session %d\n", __func__, client->session);
367 client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
368 ((client->session) << 8 | client->session),
369 client);
370
371 if (client->apr == NULL) {
372 pr_err("%s: Registration with APR failed\n", __func__);
373 goto fail;
374 }
375
376 pr_debug("%s: Registering the common port with APR\n", __func__);
377 client->mmap_apr = q6lsm_mmap_apr_reg();
378 if (!client->mmap_apr) {
379 pr_err("%s: APR registration failed\n", __func__);
380 goto fail;
381 }
382
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530383 pr_debug("%s: New client allocated\n", __func__);
384 return client;
385fail:
386 q6lsm_client_free(client);
387 return NULL;
388}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530389EXPORT_SYMBOL(q6lsm_client_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530390
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530391/**
392 * q6lsm_client_free -
393 * Performs LSM client free
394 *
395 * @client: LSM client handle
396 *
397 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530398void q6lsm_client_free(struct lsm_client *client)
399{
400 if (!client)
401 return;
402 if (CHECK_SESSION(client->session)) {
403 pr_err("%s: Invalid Session %d\n", __func__, client->session);
404 return;
405 }
Laxminath Kasamf8cc0e02018-06-30 19:57:10 +0530406 mutex_lock(&session_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530407 apr_deregister(client->apr);
408 client->mmap_apr = NULL;
409 q6lsm_session_free(client);
410 q6lsm_mmap_apr_dereg();
411 mutex_destroy(&client->cmd_lock);
412 kfree(client);
413 client = NULL;
Laxminath Kasamf8cc0e02018-06-30 19:57:10 +0530414 mutex_unlock(&session_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530415}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530416EXPORT_SYMBOL(q6lsm_client_free);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530417
418/*
419 * q6lsm_apr_send_pkt : If wait == true, hold mutex to prevent from preempting
420 * other thread's wait.
421 * If mmap_handle_p != NULL, disable irq and spin lock to
422 * protect mmap_handle_p
423 */
424static int q6lsm_apr_send_pkt(struct lsm_client *client, void *handle,
425 void *data, bool wait, uint32_t *mmap_p)
426{
427 int ret;
428 unsigned long flags = 0;
429 struct apr_hdr *msg_hdr = (struct apr_hdr *) data;
430
Xiaoyu Yefb90eb62017-10-10 12:26:08 -0700431 if (!handle) {
432 pr_err("%s: handle is NULL\n", __func__);
433 return -EINVAL;
434 }
435
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530436 pr_debug("%s: enter wait %d\n", __func__, wait);
437 if (wait)
438 mutex_lock(&lsm_common.apr_lock);
439 if (mmap_p) {
440 WARN_ON(!wait);
441 spin_lock_irqsave(&mmap_lock, flags);
442 mmap_handle_p = mmap_p;
443 }
444 atomic_set(&client->cmd_state, CMD_STATE_WAIT_RESP);
445 client->cmd_err_code = 0;
446 ret = apr_send_pkt(handle, data);
447 if (mmap_p)
448 spin_unlock_irqrestore(&mmap_lock, flags);
449
450 if (ret < 0) {
451 pr_err("%s: apr_send_pkt failed %d\n", __func__, ret);
452 } else if (wait) {
453 ret = wait_event_timeout(client->cmd_wait,
454 (atomic_read(&client->cmd_state) ==
455 CMD_STATE_CLEARED),
456 APR_TIMEOUT);
457 if (likely(ret)) {
458 /* q6 returned error */
459 if (client->cmd_err_code) {
460 pr_err("%s: DSP returned error[%s]\n",
461 __func__, adsp_err_get_err_str(
462 client->cmd_err_code));
463 ret = adsp_err_get_lnx_err_code(
464 client->cmd_err_code);
465 } else {
466 ret = 0;
467 }
468 } else {
469 pr_err("%s: wait timedout, apr_opcode = 0x%x, size = %d\n",
470 __func__, msg_hdr->opcode, msg_hdr->pkt_size);
471 /* ret = 0 means wait timed out */
472 ret = -ETIMEDOUT;
473 }
474 } else {
475 ret = 0;
476 }
477 if (wait)
478 mutex_unlock(&lsm_common.apr_lock);
479
480 pr_debug("%s: leave ret %d\n", __func__, ret);
481 return ret;
482}
483
484static void q6lsm_add_hdr(struct lsm_client *client, struct apr_hdr *hdr,
485 uint32_t pkt_size, bool cmd_flg)
486{
487 pr_debug("%s: pkt_size %d cmd_flg %d session %d\n", __func__,
488 pkt_size, cmd_flg, client->session);
489 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
490 APR_HDR_LEN(sizeof(struct apr_hdr)),
491 APR_PKT_VER);
492 hdr->src_svc = APR_SVC_LSM;
493 hdr->src_domain = APR_DOMAIN_APPS;
494 hdr->dest_svc = APR_SVC_LSM;
495 hdr->dest_domain = APR_DOMAIN_ADSP;
496 hdr->src_port = ((client->session << 8) & 0xFF00) | client->session;
497 hdr->dest_port = ((client->session << 8) & 0xFF00) | client->session;
498 hdr->pkt_size = pkt_size;
499 if (cmd_flg)
500 hdr->token = client->session;
501}
502
503
504static int q6lsm_send_custom_topologies(struct lsm_client *client)
505{
506 int rc;
507 struct cal_block_data *cal_block = NULL;
508 struct lsm_custom_topologies cstm_top;
509
510 if (lsm_common.cal_data[LSM_CUSTOM_TOP_IDX] == NULL) {
511 pr_err("%s: LSM_CUSTOM_TOP_IDX invalid\n", __func__);
512 rc = -EINVAL;
513 goto done;
514 }
515
516 lsm_common.set_custom_topology = 0;
517
518 mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
519 cal_block = cal_utils_get_only_cal_block(
520 lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]);
521 if (!cal_block) {
522 pr_err("%s: Cal block for LSM_CUSTOM_TOP_IDX not found\n",
523 __func__);
524 rc = -EINVAL;
525 goto unlock;
526 }
527
528 if (cal_block->cal_data.size <= 0) {
529 pr_err("%s: Invalid size for LSM_CUSTOM_TOP %zd\n",
530 __func__, cal_block->cal_data.size);
531 rc = -EINVAL;
532 goto unlock;
533 }
534
535 memset(&cstm_top, 0, sizeof(cstm_top));
536 /* Map the memory for out-of-band data */
537 rc = q6lsm_memory_map_regions(client, cal_block->cal_data.paddr,
538 cal_block->map_data.map_size,
539 &cal_block->map_data.q6map_handle);
540 if (rc < 0) {
541 pr_err("%s: Failed to map custom topologied, err = %d\n",
542 __func__, rc);
543 goto unlock;
544 }
545
546 q6lsm_add_hdr(client, &cstm_top.hdr,
547 sizeof(cstm_top), true);
548 cstm_top.hdr.opcode = LSM_CMD_ADD_TOPOLOGIES;
549
550 /*
551 * For ADD_TOPOLOGIES, the dest_port should be 0
552 * Note that source port cannot be zero as it is used
553 * to route the response to a specific client registered
554 * on APR
555 */
556 cstm_top.hdr.dest_port = 0;
557
558 cstm_top.data_payload_addr_lsw =
559 lower_32_bits(cal_block->cal_data.paddr);
560 cstm_top.data_payload_addr_msw =
561 msm_audio_populate_upper_32_bits(
562 cal_block->cal_data.paddr);
563 cstm_top.mem_map_handle = cal_block->map_data.q6map_handle;
564 cstm_top.buffer_size = cal_block->cal_data.size;
565
566 rc = q6lsm_apr_send_pkt(client, client->apr,
567 &cstm_top, true, NULL);
568 if (rc)
569 pr_err("%s: Failed to add custom top, err = %d\n",
570 __func__, rc);
571 /* go ahead and unmap even if custom top failed */
572 rc = q6lsm_memory_unmap_regions(client,
573 cal_block->map_data.q6map_handle);
574 if (rc) {
575 pr_err("%s: Failed to unmap, err = %d\n",
576 __func__, rc);
577 /* Even if mem unmap failed, treat the cmd as success */
578 rc = 0;
579 }
580
581unlock:
582 mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
583done:
584 return rc;
585}
586
587static int q6lsm_do_open_v2(struct lsm_client *client,
588 uint16_t app_id)
589{
590 int rc;
591 struct cal_block_data *cal_block = NULL;
592 struct audio_cal_info_lsm_top *lsm_top;
593 struct lsm_stream_cmd_open_tx_v2 open_v2;
594
595 if (lsm_common.cal_data[LSM_TOP_IDX] == NULL) {
596 pr_err("%s: LSM_TOP_IDX invalid\n", __func__);
597 rc = -EINVAL;
598 goto done;
599 }
600
601 mutex_lock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
602 cal_block = cal_utils_get_only_cal_block(
603 lsm_common.cal_data[LSM_TOP_IDX]);
604 if (!cal_block) {
605 pr_err("%s: Cal block for LSM_TOP_IDX not found\n",
606 __func__);
607 rc = -EINVAL;
608 goto unlock;
609 }
610
611 lsm_top = (struct audio_cal_info_lsm_top *)
612 cal_block->cal_info;
613 if (!lsm_top) {
614 pr_err("%s: cal_info for LSM_TOP_IDX not found\n",
615 __func__);
616 rc = -EINVAL;
617 goto unlock;
618 }
619
620 pr_debug("%s: topology_id = 0x%x, acdb_id = 0x%x, app_type = 0x%x\n",
621 __func__, lsm_top->topology, lsm_top->acdb_id,
622 lsm_top->app_type);
623
624 if (lsm_top->topology == 0) {
625 pr_err("%s: toplogy id not sent for app_type 0x%x\n",
626 __func__, lsm_top->app_type);
627 rc = -EINVAL;
628 goto unlock;
629 }
630
631 client->app_id = lsm_top->app_type;
632 memset(&open_v2, 0, sizeof(open_v2));
633 q6lsm_add_hdr(client, &open_v2.hdr,
634 sizeof(open_v2), true);
635 open_v2.topology_id = lsm_top->topology;
636 open_v2.hdr.opcode = LSM_SESSION_CMD_OPEN_TX_V2;
637
638 rc = q6lsm_apr_send_pkt(client, client->apr,
639 &open_v2, true, NULL);
640 if (rc)
641 pr_err("%s: open_v2 failed, err = %d\n",
642 __func__, rc);
643 else
644 client->use_topology = true;
645unlock:
646 mutex_unlock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
647done:
648 return rc;
649
650}
651
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530652/**
653 * q6lsm_sm_set_param_data -
654 * Update sound model param data
655 *
656 * @client: LSM client handle
657 * @p_info: param info
658 * @offset: pointer to retrieve size
659 *
660 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530661void q6lsm_sm_set_param_data(struct lsm_client *client,
662 struct lsm_params_info *p_info,
663 size_t *offset)
664{
665 struct lsm_param_payload_common *param;
666
667 param = (struct lsm_param_payload_common *)
668 client->sound_model.data;
669 param->module_id = p_info->module_id;
670 param->param_id = p_info->param_id;
671 param->p_size.param_size = client->sound_model.size;
672 *offset = sizeof(*param);
673}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530674EXPORT_SYMBOL(q6lsm_sm_set_param_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530675
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530676/**
677 * q6lsm_open -
678 * command to open LSM session
679 *
680 * @client: LSM client handle
681 * @app_id: App ID for LSM
682 *
683 * Returns 0 on success or error on failure
684 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530685int q6lsm_open(struct lsm_client *client, uint16_t app_id)
686{
687 int rc = 0;
688 struct lsm_stream_cmd_open_tx open;
689
690 /* Add Custom topologies if needed */
691 if (lsm_common.set_custom_topology) {
692 rc = q6lsm_send_custom_topologies(client);
693 if (rc)
694 pr_err("%s: Failed to send cust_top, err = %d\n",
695 __func__, rc);
696 }
697
698 /* Try to open with topology first */
699 rc = q6lsm_do_open_v2(client, app_id);
700 if (!rc)
701 /* open_v2 was successful */
702 goto done;
703
704 pr_debug("%s: try without topology\n",
705 __func__);
706
707 memset(&open, 0, sizeof(open));
708 q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
709 switch (client->app_id) {
710 case LSM_VOICE_WAKEUP_APP_ID_V2:
711 open.app_id = client->app_id;
712 break;
713 default:
714 pr_err("%s: default err 0x%x\n", __func__, client->app_id);
715 rc = -EINVAL;
716 break;
717 }
718
719 open.sampling_rate = LSM_SAMPLE_RATE;
720 open.hdr.opcode = LSM_SESSION_CMD_OPEN_TX;
721 rc = q6lsm_apr_send_pkt(client, client->apr,
722 &open, true, NULL);
723 if (rc)
724 pr_err("%s: Open failed opcode 0x%x, rc %d\n",
725 __func__, open.hdr.opcode, rc);
726 else
727 client->use_topology = false;
728done:
729 pr_debug("%s: leave %d\n", __func__, rc);
730 return rc;
731}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530732EXPORT_SYMBOL(q6lsm_open);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530733
734static int q6lsm_send_confidence_levels(
735 struct lsm_client *client,
736 struct lsm_module_param_ids *ids,
737 u32 set_param_opcode)
738{
739 u8 *packet;
740 size_t pkt_size;
741 struct lsm_cmd_set_params_conf *conf_params;
742 struct apr_hdr *msg_hdr;
743 struct lsm_param_min_confidence_levels *cfl;
744 uint8_t i = 0;
745 uint8_t padd_size = 0;
746 u8 *conf_levels;
747 int rc;
748 u32 payload_size, param_size;
749
750 padd_size = (4 - (client->num_confidence_levels % 4)) - 1;
751 pkt_size = sizeof(*conf_params) + padd_size +
752 client->num_confidence_levels;
753
754 packet = kzalloc(pkt_size, GFP_KERNEL);
755 if (!packet)
756 return -ENOMEM;
757
758 conf_params = (struct lsm_cmd_set_params_conf *) packet;
759 conf_levels = (u8 *) (packet + sizeof(*conf_params));
760 msg_hdr = &conf_params->msg_hdr;
761 q6lsm_add_hdr(client, msg_hdr,
762 pkt_size, true);
763 msg_hdr->opcode = set_param_opcode;
764 payload_size = pkt_size - sizeof(*msg_hdr) -
765 sizeof(conf_params->params_hdr);
766 q6lsm_set_param_hdr_info(&conf_params->params_hdr,
767 payload_size, 0, 0, 0);
768 cfl = &conf_params->conf_payload;
769 param_size = ((sizeof(uint8_t) + padd_size +
770 client->num_confidence_levels)) *
771 sizeof(uint8_t);
772 q6lsm_set_param_common(&cfl->common, ids,
773 param_size, set_param_opcode);
774 cfl->num_confidence_levels = client->num_confidence_levels;
775
776 pr_debug("%s: CMD PARAM SIZE = %d\n",
777 __func__, param_size);
778 pr_debug("%s: Num conf_level = %d\n",
779 __func__, client->num_confidence_levels);
780
781 memcpy(conf_levels, client->confidence_levels,
782 client->num_confidence_levels);
783 for (i = 0; i < client->num_confidence_levels; i++)
784 pr_debug("%s: Confidence_level[%d] = %d\n",
785 __func__, i, conf_levels[i]);
786
787 rc = q6lsm_apr_send_pkt(client, client->apr,
788 packet, true, NULL);
789 if (rc)
790 pr_err("%s: confidence_levels cmd failed, err = %d\n",
791 __func__, rc);
792 kfree(packet);
793 return rc;
794}
795
796static int q6lsm_send_param_opmode(struct lsm_client *client,
797 struct lsm_module_param_ids *opmode_ids,
798 u32 set_param_opcode)
799{
800 int rc;
801 struct lsm_cmd_set_params_opmode opmode_params;
802 struct apr_hdr *msg_hdr;
803
804 struct lsm_param_op_mode *op_mode;
805 u32 data_payload_size, param_size;
806
807 msg_hdr = &opmode_params.msg_hdr;
808 q6lsm_add_hdr(client, msg_hdr,
809 sizeof(opmode_params), true);
810 msg_hdr->opcode = set_param_opcode;
811 data_payload_size = sizeof(opmode_params) -
812 sizeof(*msg_hdr) -
813 sizeof(opmode_params.params_hdr);
814 q6lsm_set_param_hdr_info(&opmode_params.params_hdr,
815 data_payload_size, 0, 0, 0);
816 op_mode = &opmode_params.op_mode;
817
818
819 param_size = sizeof(struct lsm_param_op_mode) -
820 sizeof(op_mode->common);
821 q6lsm_set_param_common(&op_mode->common,
822 opmode_ids, param_size,
823 set_param_opcode);
824 op_mode->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
825 op_mode->mode = client->mode;
826 op_mode->reserved = 0;
827 pr_debug("%s: mode = 0x%x", __func__, op_mode->mode);
828
829 rc = q6lsm_apr_send_pkt(client, client->apr,
830 &opmode_params, true, NULL);
831 if (rc)
832 pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
833 __func__, msg_hdr->opcode, rc);
834
835 pr_debug("%s: leave %d\n", __func__, rc);
836 return rc;
837}
838
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530839/**
840 * set_lsm_port -
841 * Update LSM AFE port
842 *
843 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530844void set_lsm_port(int lsm_port)
845{
846 lsm_afe_port = lsm_port;
847}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530848EXPORT_SYMBOL(set_lsm_port);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530849
850int get_lsm_port(void)
851{
852 return lsm_afe_port;
853}
854
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530855/**
856 * q6lsm_set_port_connected -
857 * command to set LSM port connected
858 *
859 * @client: LSM client handle
860 *
861 * Returns 0 on success or error on failure
862 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530863int q6lsm_set_port_connected(struct lsm_client *client)
864{
865 int rc;
866 struct lsm_cmd_set_connectport connectport;
867 struct lsm_module_param_ids connectport_ids;
868 struct apr_hdr *msg_hdr;
869 struct lsm_param_connect_to_port *connect_to_port;
870 u32 data_payload_size, param_size, set_param_opcode;
871
872 if (client->use_topology) {
873 set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
874 connectport_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
875 connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
876 } else {
877 set_param_opcode = LSM_SESSION_CMD_SET_PARAMS;
878 connectport_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
879 connectport_ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
880 }
881 client->connect_to_port = get_lsm_port();
882
883 msg_hdr = &connectport.msg_hdr;
884 q6lsm_add_hdr(client, msg_hdr,
885 sizeof(connectport), true);
886 msg_hdr->opcode = set_param_opcode;
887 data_payload_size = sizeof(connectport) -
888 sizeof(*msg_hdr) -
889 sizeof(connectport.params_hdr);
890 q6lsm_set_param_hdr_info(&connectport.params_hdr,
891 data_payload_size, 0, 0, 0);
892 connect_to_port = &connectport.connect_to_port;
893
894 param_size = (sizeof(struct lsm_param_connect_to_port) -
895 sizeof(connect_to_port->common));
896 q6lsm_set_param_common(&connect_to_port->common,
897 &connectport_ids, param_size,
898 set_param_opcode);
899 connect_to_port->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
900 connect_to_port->port_id = client->connect_to_port;
901 connect_to_port->reserved = 0;
902 pr_debug("%s: port= %d", __func__, connect_to_port->port_id);
903
904 rc = q6lsm_apr_send_pkt(client, client->apr,
905 &connectport, true, NULL);
906 if (rc)
907 pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
908 __func__, msg_hdr->opcode, rc);
909
910 return rc;
911}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530912EXPORT_SYMBOL(q6lsm_set_port_connected);
913
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530914static int q6lsm_send_param_polling_enable(struct lsm_client *client,
915 bool poll_en,
916 struct lsm_module_param_ids *poll_enable_ids,
917 u32 set_param_opcode)
918{
919 int rc = 0;
920 struct lsm_cmd_poll_enable cmd;
921 struct apr_hdr *msg_hdr;
922 struct lsm_param_poll_enable *poll_enable;
923 u32 data_payload_size, param_size;
924
925 msg_hdr = &cmd.msg_hdr;
926 q6lsm_add_hdr(client, msg_hdr,
927 sizeof(struct lsm_cmd_poll_enable), true);
928 msg_hdr->opcode = set_param_opcode;
929 data_payload_size = sizeof(struct lsm_cmd_poll_enable) -
930 sizeof(struct apr_hdr) -
931 sizeof(struct lsm_set_params_hdr);
932 q6lsm_set_param_hdr_info(&cmd.params_hdr,
933 data_payload_size, 0, 0, 0);
934 poll_enable = &cmd.poll_enable;
935
936 param_size = (sizeof(struct lsm_param_poll_enable) -
937 sizeof(poll_enable->common));
938 q6lsm_set_param_common(&poll_enable->common,
939 poll_enable_ids, param_size,
940 set_param_opcode);
941 poll_enable->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
942 poll_enable->polling_enable = (poll_en) ? 1 : 0;
943 pr_debug("%s: poll enable= %d", __func__, poll_enable->polling_enable);
944
945 rc = q6lsm_apr_send_pkt(client, client->apr,
946 &cmd, true, NULL);
947 if (rc)
948 pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
949 __func__, msg_hdr->opcode, rc);
950
951 return rc;
952}
953
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530954/**
955 * q6lsm_set_fwk_mode_cfg -
956 * command to set LSM fwk mode cfg
957 *
958 * @client: LSM client handle
959 * @event_mode: mode for fwk cfg
960 *
961 * Returns 0 on success or error on failure
962 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530963int q6lsm_set_fwk_mode_cfg(struct lsm_client *client,
964 uint32_t event_mode)
965{
966 int rc = 0;
967 struct lsm_cmd_set_fwk_mode_cfg cmd;
968 struct lsm_module_param_ids fwk_mode_cfg_ids;
969 struct apr_hdr *msg_hdr;
970 struct lsm_param_fwk_mode_cfg *fwk_mode_cfg;
971 u32 data_payload_size, param_size, set_param_opcode;
972
973 if (client->use_topology) {
974 set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
975 fwk_mode_cfg_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
976 fwk_mode_cfg_ids.param_id = LSM_PARAM_ID_FWK_MODE_CONFIG;
977 } else {
978 pr_debug("%s: Ignore sending event mode\n", __func__);
979 return rc;
980 }
981
982 msg_hdr = &cmd.msg_hdr;
983 q6lsm_add_hdr(client, msg_hdr,
984 sizeof(struct lsm_cmd_set_fwk_mode_cfg), true);
985 msg_hdr->opcode = set_param_opcode;
986 data_payload_size = sizeof(struct lsm_cmd_set_fwk_mode_cfg) -
987 sizeof(struct apr_hdr) -
988 sizeof(struct lsm_set_params_hdr);
989 q6lsm_set_param_hdr_info(&cmd.params_hdr,
990 data_payload_size, 0, 0, 0);
991 fwk_mode_cfg = &cmd.fwk_mode_cfg;
992
993 param_size = (sizeof(struct lsm_param_fwk_mode_cfg) -
994 sizeof(fwk_mode_cfg->common));
995 q6lsm_set_param_common(&fwk_mode_cfg->common,
996 &fwk_mode_cfg_ids, param_size,
997 set_param_opcode);
998
999 fwk_mode_cfg->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
1000 fwk_mode_cfg->mode = event_mode;
1001 pr_debug("%s: mode = %d\n", __func__, fwk_mode_cfg->mode);
1002
1003 rc = q6lsm_apr_send_pkt(client, client->apr,
1004 &cmd, true, NULL);
1005 if (rc)
1006 pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
1007 __func__, msg_hdr->opcode, rc);
1008 return rc;
1009}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301010EXPORT_SYMBOL(q6lsm_set_fwk_mode_cfg);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301011
1012static int q6lsm_arrange_mch_map(struct lsm_param_media_fmt *media_fmt,
1013 int channel_count)
1014{
1015 int rc = 0;
1016
1017 memset(media_fmt->channel_mapping, 0, LSM_MAX_NUM_CHANNELS);
1018
1019 switch (channel_count) {
1020 case 1:
1021 media_fmt->channel_mapping[0] = PCM_CHANNEL_FC;
1022 break;
1023 case 2:
1024 media_fmt->channel_mapping[0] = PCM_CHANNEL_FL;
1025 media_fmt->channel_mapping[1] = PCM_CHANNEL_FR;
1026 break;
1027 case 3:
1028 media_fmt->channel_mapping[0] = PCM_CHANNEL_FL;
1029 media_fmt->channel_mapping[1] = PCM_CHANNEL_FR;
1030 media_fmt->channel_mapping[2] = PCM_CHANNEL_FC;
1031 break;
1032 case 4:
1033 media_fmt->channel_mapping[0] = PCM_CHANNEL_FL;
1034 media_fmt->channel_mapping[1] = PCM_CHANNEL_FR;
1035 media_fmt->channel_mapping[2] = PCM_CHANNEL_LS;
1036 media_fmt->channel_mapping[3] = PCM_CHANNEL_RS;
1037 break;
1038 default:
1039 pr_err("%s: invalid num_chan %d\n", __func__, channel_count);
1040 rc = -EINVAL;
1041 break;
1042 }
1043 return rc;
1044}
1045
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301046/**
1047 * q6lsm_set_media_fmt_params -
1048 * command to set LSM media fmt params
1049 *
1050 * @client: LSM client handle
1051 *
1052 * Returns 0 on success or error on failure
1053 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301054int q6lsm_set_media_fmt_params(struct lsm_client *client)
1055{
1056 int rc = 0;
1057 struct lsm_cmd_set_media_fmt cmd;
1058 struct lsm_module_param_ids media_fmt_ids;
1059 struct apr_hdr *msg_hdr;
1060 struct lsm_param_media_fmt *media_fmt;
1061 u32 data_payload_size, param_size, set_param_opcode;
1062 struct lsm_hw_params param = client->hw_params;
1063
1064 if (client->use_topology) {
1065 set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
1066 media_fmt_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
1067 media_fmt_ids.param_id = LSM_PARAM_ID_MEDIA_FMT;
1068 } else {
1069 pr_debug("%s: Ignore sending media format\n", __func__);
1070 goto err_ret;
1071 }
1072
1073 msg_hdr = &cmd.msg_hdr;
1074 q6lsm_add_hdr(client, msg_hdr,
1075 sizeof(struct lsm_cmd_set_media_fmt), true);
1076 msg_hdr->opcode = set_param_opcode;
1077 data_payload_size = sizeof(struct lsm_cmd_set_media_fmt) -
1078 sizeof(struct apr_hdr) -
1079 sizeof(struct lsm_set_params_hdr);
1080 q6lsm_set_param_hdr_info(&cmd.params_hdr,
1081 data_payload_size, 0, 0, 0);
1082 media_fmt = &cmd.media_fmt;
1083
1084 param_size = (sizeof(struct lsm_param_media_fmt) -
1085 sizeof(media_fmt->common));
1086 q6lsm_set_param_common(&media_fmt->common,
1087 &media_fmt_ids, param_size,
1088 set_param_opcode);
1089
1090 media_fmt->minor_version = QLSM_PARAM_ID_MINOR_VERSION_2;
1091 media_fmt->sample_rate = param.sample_rate;
1092 media_fmt->num_channels = param.num_chs;
1093 media_fmt->bit_width = param.sample_size;
1094
1095 rc = q6lsm_arrange_mch_map(media_fmt, media_fmt->num_channels);
1096 if (rc)
1097 goto err_ret;
1098
1099 pr_debug("%s: sample rate= %d, channels %d bit width %d\n",
1100 __func__, media_fmt->sample_rate, media_fmt->num_channels,
1101 media_fmt->bit_width);
1102
1103 rc = q6lsm_apr_send_pkt(client, client->apr,
1104 &cmd, true, NULL);
1105 if (rc)
1106 pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
1107 __func__, msg_hdr->opcode, rc);
1108err_ret:
1109 return rc;
1110}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301111EXPORT_SYMBOL(q6lsm_set_media_fmt_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301112
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301113/**
1114 * q6lsm_set_data -
1115 * Command to set LSM data
1116 *
1117 * @client: LSM client handle
1118 * @mode: LSM detection mode value
1119 * @detectfailure: flag for detect failure
1120 *
1121 * Returns 0 on success or error on failure
1122 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301123int q6lsm_set_data(struct lsm_client *client,
1124 enum lsm_detection_mode mode,
1125 bool detectfailure)
1126{
1127 int rc = 0;
1128 struct lsm_module_param_ids opmode_ids;
1129 struct lsm_module_param_ids conf_levels_ids;
1130
1131 if (!client->confidence_levels) {
1132 /*
1133 * It is possible that confidence levels are
1134 * not provided. This is not a error condition.
1135 * Return gracefully without any error
1136 */
1137 pr_debug("%s: no conf levels to set\n",
1138 __func__);
1139 return rc;
1140 }
1141
1142 if (mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
1143 client->mode = 0x01;
1144 } else if (mode == LSM_MODE_USER_KEYWORD_DETECTION) {
1145 client->mode = 0x03;
1146 } else {
1147 pr_err("%s: Incorrect detection mode %d\n", __func__, mode);
1148 rc = -EINVAL;
1149 goto err_ret;
1150 }
1151 client->mode |= detectfailure << 2;
1152
1153 opmode_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
1154 opmode_ids.param_id = LSM_PARAM_ID_OPERATION_MODE;
1155
1156 rc = q6lsm_send_param_opmode(client, &opmode_ids,
1157 LSM_SESSION_CMD_SET_PARAMS);
1158 if (rc) {
1159 pr_err("%s: Failed to set lsm config params %d\n",
1160 __func__, rc);
1161 goto err_ret;
1162 }
1163
1164 conf_levels_ids.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
1165 conf_levels_ids.param_id = LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS;
1166
1167 rc = q6lsm_send_confidence_levels(client, &conf_levels_ids,
1168 LSM_SESSION_CMD_SET_PARAMS);
1169 if (rc) {
1170 pr_err("%s: Failed to send conf_levels, err = %d\n",
1171 __func__, rc);
1172 goto err_ret;
1173 }
1174
1175 rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS);
1176 if (rc) {
1177 pr_err("%s: Failed to send calibration data %d\n",
1178 __func__, rc);
1179 goto err_ret;
1180 }
1181
1182err_ret:
1183 return rc;
1184}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301185EXPORT_SYMBOL(q6lsm_set_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301186
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301187/**
1188 * q6lsm_register_sound_model -
1189 * Register LSM snd model
1190 *
1191 * @client: LSM client handle
1192 *
1193 * Returns 0 on success or error on failure
1194 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301195int q6lsm_register_sound_model(struct lsm_client *client,
1196 enum lsm_detection_mode mode,
1197 bool detectfailure)
1198{
1199 int rc;
1200 struct lsm_cmd_reg_snd_model cmd;
1201
1202 memset(&cmd, 0, sizeof(cmd));
1203 rc = q6lsm_set_data(client, mode, detectfailure);
1204 if (rc) {
1205 pr_err("%s: Failed to set lsm data, err = %d\n",
1206 __func__, rc);
1207 return rc;
1208 }
1209
1210 q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
1211 cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
1212 cmd.model_addr_lsw = lower_32_bits(client->sound_model.phys);
1213 cmd.model_addr_msw = msm_audio_populate_upper_32_bits(
1214 client->sound_model.phys);
1215 cmd.model_size = client->sound_model.size;
1216 /* read updated mem_map_handle by q6lsm_mmapcallback */
1217 rmb();
1218 cmd.mem_map_handle = client->sound_model.mem_map_handle;
1219
1220 pr_debug("%s: addr %pK, size %d, handle 0x%x\n", __func__,
1221 &client->sound_model.phys, cmd.model_size, cmd.mem_map_handle);
1222 rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
1223 if (rc)
1224 pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
1225 cmd.hdr.opcode, rc);
1226 else
1227 pr_debug("%s: Register sound model succeeded\n", __func__);
1228
1229 return rc;
1230}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301231EXPORT_SYMBOL(q6lsm_register_sound_model);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301232
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301233/**
1234 * q6lsm_deregister_sound_model -
1235 * De-register LSM snd model
1236 *
1237 * @client: LSM client handle
1238 *
1239 * Returns 0 on success or error on failure
1240 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301241int q6lsm_deregister_sound_model(struct lsm_client *client)
1242{
1243 int rc;
1244 struct lsm_cmd_reg_snd_model cmd;
1245
1246 if (!client) {
1247 pr_err("APR handle NULL\n");
1248 return -EINVAL;
1249 }
1250 if (!client->apr) {
1251 pr_err("APR client handle NULL\n");
1252 return -EINVAL;
1253 }
1254
1255 if (CHECK_SESSION(client->session)) {
1256 pr_err("%s: session[%d]", __func__, client->session);
1257 return -EINVAL;
1258 }
1259
1260 memset(&cmd, 0, sizeof(cmd));
1261 q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
1262 cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
1263
1264 rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
1265 if (rc) {
1266 pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
1267 cmd.hdr.opcode, rc);
1268 } else {
1269 pr_debug("%s: Deregister sound model succeeded\n", __func__);
1270 }
1271
1272 q6lsm_snd_model_buf_free(client);
1273
1274 return rc;
1275}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301276EXPORT_SYMBOL(q6lsm_deregister_sound_model);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301277
1278static void q6lsm_add_mmaphdr(struct lsm_client *client, struct apr_hdr *hdr,
1279 u32 pkt_size, u32 cmd_flg, u32 token)
1280{
1281 pr_debug("%s: pkt size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
1282 cmd_flg, client->session);
1283 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1284 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1285 hdr->src_port = 0x00;
1286 hdr->dest_port = client->session;
1287 if (cmd_flg)
1288 hdr->token = token;
1289 hdr->pkt_size = pkt_size;
1290}
1291
1292static int q6lsm_memory_map_regions(struct lsm_client *client,
1293 dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
1294 uint32_t *mmap_p)
1295{
1296 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
1297 struct avs_shared_map_region_payload *mregions = NULL;
1298 void *mmap_region_cmd = NULL;
1299 void *payload = NULL;
1300 int rc;
1301 int cmd_size = 0;
1302
1303 pr_debug("%s: dma_addr_p 0x%pK, dma_buf_sz %d, mmap_p 0x%pK, session %d\n",
1304 __func__, &dma_addr_p, dma_buf_sz, mmap_p,
1305 client->session);
1306 if (CHECK_SESSION(client->session)) {
1307 pr_err("%s: session[%d]", __func__, client->session);
1308 return -EINVAL;
1309 }
1310 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
1311 sizeof(struct avs_shared_map_region_payload);
1312
1313 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
1314 if (!mmap_region_cmd)
1315 return -ENOMEM;
1316
1317 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
1318 q6lsm_add_mmaphdr(client, &mmap_regions->hdr, cmd_size, true,
1319 (client->session << 8));
1320
1321 mmap_regions->hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS;
1322 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
1323 mmap_regions->num_regions = 1;
1324 mmap_regions->property_flag = 0x00;
1325 payload = ((u8 *)mmap_region_cmd +
1326 sizeof(struct avs_cmd_shared_mem_map_regions));
1327 mregions = (struct avs_shared_map_region_payload *)payload;
1328
1329 mregions->shm_addr_lsw = lower_32_bits(dma_addr_p);
1330 mregions->shm_addr_msw = msm_audio_populate_upper_32_bits(dma_addr_p);
1331 mregions->mem_size_bytes = dma_buf_sz;
1332
1333 rc = q6lsm_apr_send_pkt(client, client->mmap_apr, mmap_region_cmd,
1334 true, mmap_p);
1335 if (rc)
1336 pr_err("%s: Failed mmap_regions opcode 0x%x, rc %d\n",
1337 __func__, mmap_regions->hdr.opcode, rc);
1338
1339 pr_debug("%s: leave %d\n", __func__, rc);
1340 kfree(mmap_region_cmd);
1341 return rc;
1342}
1343
1344static int q6lsm_memory_unmap_regions(struct lsm_client *client,
1345 uint32_t handle)
1346{
1347 struct avs_cmd_shared_mem_unmap_regions unmap;
1348 int rc = 0;
1349 int cmd_size = 0;
1350
1351 if (CHECK_SESSION(client->session)) {
1352 pr_err("%s: session[%d]", __func__, client->session);
1353 return -EINVAL;
1354 }
1355 cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
1356 q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
1357 true, (client->session << 8));
1358 unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
1359 unmap.mem_map_handle = handle;
1360
1361 pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
1362 rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
1363 NULL);
1364 if (rc)
1365 pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
1366 __func__, unmap.hdr.opcode, rc);
1367
1368 return rc;
1369}
1370
1371static int q6lsm_send_cal(struct lsm_client *client,
1372 u32 set_params_opcode)
1373{
1374 int rc = 0;
1375 struct lsm_cmd_set_params params;
1376 struct lsm_set_params_hdr *params_hdr = &params.param_hdr;
1377 struct apr_hdr *msg_hdr = &params.msg_hdr;
1378 struct cal_block_data *cal_block = NULL;
1379
1380 pr_debug("%s: Session id %d\n", __func__, client->session);
1381 if (CHECK_SESSION(client->session)) {
1382 pr_err("%s: session[%d]", __func__, client->session);
1383 return -EINVAL;
1384 }
1385
1386 if (lsm_common.cal_data[LSM_CAL_IDX] == NULL)
1387 goto done;
1388
1389 mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
1390 cal_block = cal_utils_get_only_cal_block(
1391 lsm_common.cal_data[LSM_CAL_IDX]);
1392
1393 if (!cal_block || cal_block->cal_data.size <= 0) {
1394 pr_debug("%s: No cal to send!\n", __func__);
1395 goto unlock;
1396 }
1397
1398 if (cal_block->cal_data.size != client->lsm_cal_size) {
1399 pr_err("%s: Cal size %zd doesn't match lsm cal size %d\n",
1400 __func__, cal_block->cal_data.size,
1401 client->lsm_cal_size);
1402 rc = -EINVAL;
1403 goto unlock;
1404 }
1405 /* Cache mmap address, only map once or if new addr */
1406 lsm_common.common_client[client->session].session = client->session;
1407 q6lsm_add_hdr(client, msg_hdr, sizeof(params), true);
1408 msg_hdr->opcode = set_params_opcode;
1409 q6lsm_set_param_hdr_info(params_hdr,
1410 cal_block->cal_data.size,
1411 lower_32_bits(client->lsm_cal_phy_addr),
1412 msm_audio_populate_upper_32_bits(
1413 client->lsm_cal_phy_addr),
1414 client->sound_model.mem_map_handle);
1415
1416 pr_debug("%s: Cal Size = %zd", __func__,
1417 cal_block->cal_data.size);
1418 rc = q6lsm_apr_send_pkt(client, client->apr, &params, true, NULL);
1419 if (rc)
1420 pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
1421 __func__, msg_hdr->opcode, rc);
1422unlock:
1423 mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
1424done:
1425 return rc;
1426}
1427
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301428/**
1429 * q6lsm_snd_model_buf_free -
1430 * Free memory for LSM snd model
1431 *
1432 * @client: LSM client handle
1433 *
1434 * Returns 0 on success or error on failure
1435 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301436int q6lsm_snd_model_buf_free(struct lsm_client *client)
1437{
1438 int rc;
1439
1440 pr_debug("%s: Session id %d\n", __func__, client->session);
1441 if (CHECK_SESSION(client->session)) {
1442 pr_err("%s: session[%d]", __func__, client->session);
1443 return -EINVAL;
1444 }
1445
1446 mutex_lock(&client->cmd_lock);
1447 rc = q6lsm_memory_unmap_regions(client,
1448 client->sound_model.mem_map_handle);
1449 if (rc)
1450 pr_err("%s: CMD Memory_unmap_regions failed %d\n",
1451 __func__, rc);
1452
1453 if (client->sound_model.data) {
1454 msm_audio_ion_free(client->sound_model.client,
1455 client->sound_model.handle);
1456 client->sound_model.client = NULL;
1457 client->sound_model.handle = NULL;
1458 client->sound_model.data = NULL;
1459 client->sound_model.phys = 0;
1460 client->lsm_cal_phy_addr = 0;
1461 client->lsm_cal_size = 0;
1462 }
1463 mutex_unlock(&client->cmd_lock);
1464 return rc;
1465}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301466EXPORT_SYMBOL(q6lsm_snd_model_buf_free);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301467
1468static struct lsm_client *q6lsm_get_lsm_client(int session_id)
1469{
1470 unsigned long flags;
1471 struct lsm_client *client = NULL;
1472
1473 spin_lock_irqsave(&lsm_session_lock, flags);
1474 if (session_id < LSM_MIN_SESSION_ID || session_id > LSM_MAX_SESSION_ID)
1475 pr_err("%s: Invalid session %d\n", __func__, session_id);
1476 else if (!lsm_session[session_id])
1477 pr_err("%s: Not an active session %d\n", __func__, session_id);
1478 else
1479 client = lsm_session[session_id];
1480 spin_unlock_irqrestore(&lsm_session_lock, flags);
1481 return client;
1482}
1483
1484/*
1485 * q6lsm_mmapcallback : atomic context
1486 */
1487static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
1488{
1489 unsigned long flags;
1490 uint32_t command;
1491 uint32_t retcode;
1492 uint32_t sid;
1493 const uint32_t *payload = data->payload;
1494 struct lsm_client *client = NULL;
1495
1496 if (data->opcode == RESET_EVENTS) {
1497 sid = (data->token >> 8) & 0x0F;
1498 pr_debug("%s: SSR event received 0x%x, event 0x%x,\n"
1499 "proc 0x%x SID 0x%x\n", __func__, data->opcode,
1500 data->reset_event, data->reset_proc, sid);
Xiaoyu Yefb90eb62017-10-10 12:26:08 -07001501
kunleiz5574e742019-04-12 11:28:19 +08001502 if (sid < LSM_MIN_SESSION_ID || sid > LSM_MAX_SESSION_ID)
1503 pr_err("%s: Invalid session %d\n", __func__, sid);
Xiaoyu Yefb90eb62017-10-10 12:26:08 -07001504 apr_reset(lsm_common.apr);
1505 lsm_common.apr = NULL;
1506 atomic_set(&lsm_common.apr_users, 0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301507 lsm_common.common_client[sid].lsm_cal_phy_addr = 0;
1508 cal_utils_clear_cal_block_q6maps(LSM_MAX_CAL_IDX,
1509 lsm_common.cal_data);
1510 lsm_common.set_custom_topology = 1;
1511 return 0;
1512 }
1513
1514 command = payload[0];
1515 retcode = payload[1];
1516 sid = (data->token >> 8) & 0x0F;
1517 pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x SID 0x%x\n",
1518 __func__, data->opcode, command, retcode, sid);
1519 client = q6lsm_get_lsm_client(sid);
1520 if (!client) {
1521 pr_debug("%s: Session %d already freed\n", __func__, sid);
1522 return 0;
1523 }
1524
1525 switch (data->opcode) {
1526 case LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS:
1527 if (atomic_read(&client->cmd_state) == CMD_STATE_WAIT_RESP) {
1528 spin_lock_irqsave(&mmap_lock, flags);
1529 *mmap_handle_p = command;
1530 /* spin_unlock_irqrestore implies barrier */
1531 spin_unlock_irqrestore(&mmap_lock, flags);
1532 atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
1533 wake_up(&client->cmd_wait);
1534 }
1535 break;
1536 case APR_BASIC_RSP_RESULT:
1537 switch (command) {
1538 case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
1539 atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
1540 wake_up(&client->cmd_wait);
1541 break;
1542 case LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS:
1543 if (retcode != 0) {
1544 /* error state, signal to stop waiting */
1545 if (atomic_read(&client->cmd_state) ==
1546 CMD_STATE_WAIT_RESP) {
1547 spin_lock_irqsave(&mmap_lock, flags);
1548 /* implies barrier */
1549 spin_unlock_irqrestore(&mmap_lock,
1550 flags);
1551 atomic_set(&client->cmd_state,
1552 CMD_STATE_CLEARED);
1553 wake_up(&client->cmd_wait);
1554 }
1555 }
1556 break;
1557 default:
1558 pr_warn("%s: Unexpected command 0x%x\n", __func__,
1559 command);
1560 }
1561 /* fallthrough */
1562 default:
1563 pr_debug("%s: command 0x%x return code 0x%x opcode 0x%x\n",
1564 __func__, command, retcode, data->opcode);
1565 break;
1566 }
1567 if (client->cb)
1568 client->cb(data->opcode, data->token,
kunleiz5574e742019-04-12 11:28:19 +08001569 data->payload, data->payload_size,
1570 client->priv);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301571 return 0;
1572}
1573
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301574/**
1575 * q6lsm_snd_model_buf_alloc -
1576 * Allocate memory for LSM snd model
1577 *
1578 * @client: LSM client handle
1579 * @len: size of sound model
1580 * @allocate_module_data: flag to allocate for set_param payload
1581 *
1582 * Returns 0 on success or error on failure
1583 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301584int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
1585 bool allocate_module_data)
1586{
1587 int rc = -EINVAL;
1588 struct cal_block_data *cal_block = NULL;
1589
1590 size_t pad_zero = 0, total_mem = 0;
1591
1592 if (!client || len <= LSM_ALIGN_BOUNDARY)
1593 return rc;
1594
1595 mutex_lock(&client->cmd_lock);
1596
1597 mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
1598 cal_block = cal_utils_get_only_cal_block(
1599 lsm_common.cal_data[LSM_CAL_IDX]);
1600 if (cal_block == NULL)
1601 goto fail;
1602
1603 pr_debug("%s:Snd Model len = %zd cal size %zd phys addr %pK", __func__,
1604 len, cal_block->cal_data.size,
1605 &cal_block->cal_data.paddr);
1606 if (!cal_block->cal_data.paddr) {
1607 pr_err("%s: No LSM calibration set for session", __func__);
1608 rc = -EINVAL;
1609 goto fail;
1610 }
1611 if (!client->sound_model.data) {
1612
1613 /*
1614 * if sound module is sent as set_param
1615 * Then memory needs to be allocated for
1616 * set_param payload as well.
1617 */
1618 if (allocate_module_data)
1619 len += sizeof(struct lsm_param_payload_common);
1620
1621 client->sound_model.size = len;
1622 pad_zero = (LSM_ALIGN_BOUNDARY -
1623 (len % LSM_ALIGN_BOUNDARY));
1624 if ((len > SIZE_MAX - pad_zero) ||
1625 (len + pad_zero >
1626 SIZE_MAX - cal_block->cal_data.size)) {
1627 pr_err("%s: invalid allocation size, len = %zd, pad_zero =%zd, cal_size = %zd\n",
1628 __func__, len, pad_zero,
1629 cal_block->cal_data.size);
1630 rc = -EINVAL;
1631 goto fail;
1632 }
1633
1634 total_mem = PAGE_ALIGN(pad_zero + len +
1635 cal_block->cal_data.size);
1636 pr_debug("%s: Pad zeros sound model %zd Total mem %zd\n",
1637 __func__, pad_zero, total_mem);
1638 rc = msm_audio_ion_alloc("lsm_client",
1639 &client->sound_model.client,
1640 &client->sound_model.handle,
1641 total_mem,
1642 &client->sound_model.phys,
1643 &len,
1644 &client->sound_model.data);
1645 if (rc) {
1646 pr_err("%s: Audio ION alloc is failed, rc = %d\n",
1647 __func__, rc);
1648 goto fail;
1649 }
1650 pr_debug("%s: Length = %zd\n", __func__, len);
1651 client->lsm_cal_phy_addr = (pad_zero +
1652 client->sound_model.phys +
1653 client->sound_model.size);
1654 client->lsm_cal_size = cal_block->cal_data.size;
1655 memcpy((client->sound_model.data + pad_zero +
1656 client->sound_model.size),
1657 (uint32_t *)cal_block->cal_data.kvaddr, client->lsm_cal_size);
1658 pr_debug("%s: Copy cal start virt_addr %pK phy_addr %pK\n"
1659 "Offset cal virtual Addr %pK\n", __func__,
1660 client->sound_model.data, &client->sound_model.phys,
1661 (pad_zero + client->sound_model.data +
1662 client->sound_model.size));
1663 } else {
1664 pr_err("%s: sound model busy\n", __func__);
1665 rc = -EBUSY;
1666 goto fail;
1667 }
1668 mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
1669 mutex_unlock(&client->cmd_lock);
1670
1671 rc = q6lsm_memory_map_regions(client, client->sound_model.phys,
1672 len,
1673 &client->sound_model.mem_map_handle);
1674 if (rc) {
1675 pr_err("%s: CMD Memory_map_regions failed %d\n", __func__, rc);
1676 goto exit;
1677 }
1678
1679 return 0;
1680fail:
1681 mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
1682 mutex_unlock(&client->cmd_lock);
1683exit:
1684 q6lsm_snd_model_buf_free(client);
1685 return rc;
1686}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301687EXPORT_SYMBOL(q6lsm_snd_model_buf_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301688
1689static int q6lsm_cmd(struct lsm_client *client, int opcode, bool wait)
1690{
1691 struct apr_hdr hdr;
1692 int rc;
1693
1694 pr_debug("%s: enter opcode %x wait %d\n", __func__, opcode, wait);
1695 q6lsm_add_hdr(client, &hdr, sizeof(hdr), true);
1696 switch (opcode) {
1697 case LSM_SESSION_CMD_START:
1698 case LSM_SESSION_CMD_STOP:
1699 case LSM_SESSION_CMD_CLOSE_TX:
1700 case LSM_SESSION_CMD_EOB:
1701 hdr.opcode = opcode;
1702 break;
1703 default:
1704 pr_err("%s: Invalid opcode 0x%x\n", __func__, opcode);
1705 return -EINVAL;
1706 }
1707 rc = q6lsm_apr_send_pkt(client, client->apr, &hdr, wait, NULL);
1708 if (rc)
1709 pr_err("%s: Failed commmand 0x%x\n", __func__, hdr.opcode);
1710
1711 pr_debug("%s: leave %d\n", __func__, rc);
1712 return rc;
1713}
1714
1715static int q6lsm_send_param_epd_thres(
1716 struct lsm_client *client,
1717 void *data, struct lsm_module_param_ids *ids)
1718{
1719 struct snd_lsm_ep_det_thres *ep_det_data;
1720 struct lsm_cmd_set_epd_threshold epd_cmd;
1721 struct apr_hdr *msg_hdr = &epd_cmd.msg_hdr;
1722 struct lsm_set_params_hdr *param_hdr =
1723 &epd_cmd.param_hdr;
1724 struct lsm_param_epd_thres *epd_thres =
1725 &epd_cmd.epd_thres;
1726 int rc;
1727
1728 ep_det_data = (struct snd_lsm_ep_det_thres *) data;
1729 q6lsm_add_hdr(client, msg_hdr,
1730 sizeof(epd_cmd), true);
1731 msg_hdr->opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
1732 q6lsm_set_param_hdr_info(param_hdr,
1733 sizeof(*epd_thres), 0, 0, 0);
1734 q6lsm_set_param_common(&epd_thres->common, ids,
1735 sizeof(*epd_thres) - sizeof(epd_thres->common),
1736 LSM_SESSION_CMD_SET_PARAMS_V2);
1737 epd_thres->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
1738 epd_thres->epd_begin = ep_det_data->epd_begin;
1739 epd_thres->epd_end = ep_det_data->epd_end;
1740
1741 rc = q6lsm_apr_send_pkt(client, client->apr,
1742 &epd_cmd, true, NULL);
1743 if (unlikely(rc))
1744 pr_err("%s: EPD_THRESHOLD failed, rc %d\n",
1745 __func__, rc);
1746 return rc;
1747}
1748
1749static int q6lsm_send_param_gain(
1750 struct lsm_client *client,
1751 u16 gain, struct lsm_module_param_ids *ids)
1752{
1753 struct lsm_cmd_set_gain lsm_cmd_gain;
1754 struct apr_hdr *msg_hdr = &lsm_cmd_gain.msg_hdr;
1755 struct lsm_param_gain *lsm_gain = &lsm_cmd_gain.lsm_gain;
1756 int rc;
1757
1758 q6lsm_add_hdr(client, msg_hdr,
1759 sizeof(lsm_cmd_gain), true);
1760 msg_hdr->opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
1761 q6lsm_set_param_hdr_info(&lsm_cmd_gain.param_hdr,
1762 sizeof(*lsm_gain), 0, 0, 0);
1763 q6lsm_set_param_common(&lsm_gain->common, ids,
1764 sizeof(*lsm_gain) - sizeof(lsm_gain->common),
1765 LSM_SESSION_CMD_SET_PARAMS_V2);
1766 lsm_gain->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
1767 lsm_gain->gain = gain;
1768 lsm_gain->reserved = 0;
1769
1770 rc = q6lsm_apr_send_pkt(client, client->apr,
1771 &lsm_cmd_gain, true, NULL);
1772 if (unlikely(rc))
1773 pr_err("%s: LSM_GAIN CMD send failed, rc %d\n",
1774 __func__, rc);
1775 return rc;
1776}
1777
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301778/**
1779 * q6lsm_set_one_param -
1780 * command for LSM set params
1781 *
1782 * @client: LSM client handle
1783 * p_info: Params info
1784 * data: payload based on param type
1785 * param_type: LSM param type
1786 *
1787 * Returns 0 on success or error on failure
1788 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301789int q6lsm_set_one_param(struct lsm_client *client,
1790 struct lsm_params_info *p_info, void *data,
1791 uint32_t param_type)
1792{
1793 int rc = 0, pkt_sz;
1794 struct lsm_module_param_ids ids;
1795 u8 *packet;
1796
1797 memset(&ids, 0, sizeof(ids));
1798 switch (param_type) {
1799 case LSM_ENDPOINT_DETECT_THRESHOLD: {
1800 ids.module_id = p_info->module_id;
1801 ids.param_id = p_info->param_id;
1802 rc = q6lsm_send_param_epd_thres(client, data,
1803 &ids);
1804 break;
1805 }
1806
1807 case LSM_OPERATION_MODE: {
1808 struct snd_lsm_detect_mode *det_mode = data;
1809 struct lsm_module_param_ids opmode_ids;
1810
1811 if (det_mode->mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
1812 client->mode = 0x01;
1813 } else if (det_mode->mode == LSM_MODE_USER_KEYWORD_DETECTION) {
1814 client->mode = 0x03;
1815 } else {
1816 pr_err("%s: Incorrect detection mode %d\n",
1817 __func__, det_mode->mode);
1818 return -EINVAL;
1819 }
1820
1821 client->mode |= det_mode->detect_failure << 2;
1822
1823 opmode_ids.module_id = p_info->module_id;
1824 opmode_ids.param_id = p_info->param_id;
1825
1826 rc = q6lsm_send_param_opmode(client, &opmode_ids,
1827 LSM_SESSION_CMD_SET_PARAMS_V2);
1828 if (rc)
1829 pr_err("%s: OPERATION_MODE failed, rc %d\n",
1830 __func__, rc);
1831 break;
1832 }
1833
1834 case LSM_GAIN: {
1835 struct snd_lsm_gain *lsm_gain = (struct snd_lsm_gain *) data;
1836
1837 ids.module_id = p_info->module_id;
1838 ids.param_id = p_info->param_id;
1839 rc = q6lsm_send_param_gain(client, lsm_gain->gain, &ids);
1840 if (rc)
1841 pr_err("%s: LSM_GAIN command failed, rc %d\n",
1842 __func__, rc);
1843 break;
1844 }
1845
1846 case LSM_MIN_CONFIDENCE_LEVELS:
1847 ids.module_id = p_info->module_id;
1848 ids.param_id = p_info->param_id;
1849 rc = q6lsm_send_confidence_levels(client, &ids,
1850 LSM_SESSION_CMD_SET_PARAMS_V2);
1851 if (rc)
1852 pr_err("%s: CONFIDENCE_LEVELS cmd failed, rc %d\n",
1853 __func__, rc);
1854 break;
1855 case LSM_POLLING_ENABLE: {
1856 struct snd_lsm_poll_enable *lsm_poll_enable =
1857 (struct snd_lsm_poll_enable *) data;
1858 ids.module_id = p_info->module_id;
1859 ids.param_id = p_info->param_id;
1860 rc = q6lsm_send_param_polling_enable(client,
1861 lsm_poll_enable->poll_en, &ids,
1862 LSM_SESSION_CMD_SET_PARAMS_V2);
1863 if (rc)
1864 pr_err("%s: POLLING ENABLE cmd failed, rc %d\n",
1865 __func__, rc);
1866 break;
1867 }
1868
1869 case LSM_REG_SND_MODEL: {
1870 struct lsm_cmd_set_params model_param;
1871 u32 payload_size;
1872
1873 memset(&model_param, 0, sizeof(model_param));
1874 q6lsm_add_hdr(client, &model_param.msg_hdr,
1875 sizeof(model_param), true);
1876 model_param.msg_hdr.opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
1877 payload_size = p_info->param_size +
1878 sizeof(struct lsm_param_payload_common);
1879 q6lsm_set_param_hdr_info(&model_param.param_hdr,
1880 payload_size,
1881 lower_32_bits(client->sound_model.phys),
1882 msm_audio_populate_upper_32_bits(
1883 client->sound_model.phys),
1884 client->sound_model.mem_map_handle);
1885
1886 rc = q6lsm_apr_send_pkt(client, client->apr,
1887 &model_param, true, NULL);
1888 if (rc) {
1889 pr_err("%s: REG_SND_MODEL failed, rc %d\n",
1890 __func__, rc);
1891 return rc;
1892 }
1893
1894 rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS);
1895 if (rc)
1896 pr_err("%s: Failed to send lsm cal, err = %d\n",
1897 __func__, rc);
1898 break;
1899 }
1900
1901 case LSM_DEREG_SND_MODEL: {
1902 struct lsm_param_payload_common *common;
1903 struct lsm_cmd_set_params *param;
1904
1905 pkt_sz = sizeof(*param) + sizeof(*common);
1906 packet = kzalloc(pkt_sz, GFP_KERNEL);
1907 if (!packet) {
1908 pr_err("%s: No memory for DEREG_SND_MODEL pkt, size = %d\n",
1909 __func__, pkt_sz);
1910 return -ENOMEM;
1911 }
1912
1913 param = (struct lsm_cmd_set_params *) packet;
1914 common = (struct lsm_param_payload_common *)
1915 (packet + sizeof(*param));
1916 q6lsm_add_hdr(client, &param->msg_hdr, pkt_sz, true);
1917 param->msg_hdr.opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
1918 q6lsm_set_param_hdr_info(&param->param_hdr,
1919 sizeof(*common),
1920 0, 0, 0);
1921 ids.module_id = p_info->module_id;
1922 ids.param_id = p_info->param_id;
1923 q6lsm_set_param_common(common, &ids, 0,
1924 LSM_SESSION_CMD_SET_PARAMS_V2);
1925 rc = q6lsm_apr_send_pkt(client, client->apr,
1926 packet, true, NULL);
1927 if (rc)
1928 pr_err("%s: DEREG_SND_MODEL failed, rc %d\n",
1929 __func__, rc);
1930 kfree(packet);
1931 break;
1932 }
1933
1934 case LSM_CUSTOM_PARAMS: {
1935 struct apr_hdr *hdr;
1936 u8 *custom_data;
1937
1938 if (p_info->param_size <
1939 sizeof(struct lsm_param_payload_common)) {
1940 pr_err("%s: Invalid param_size %d\n",
1941 __func__, p_info->param_size);
1942 return -EINVAL;
1943 }
1944
1945 pkt_sz = p_info->param_size + sizeof(*hdr);
1946 packet = kzalloc(pkt_sz, GFP_KERNEL);
1947 if (!packet) {
1948 pr_err("%s: no memory for CUSTOM_PARAMS, size = %d\n",
1949 __func__, pkt_sz);
1950 return -ENOMEM;
1951 }
1952
1953 hdr = (struct apr_hdr *) packet;
1954 custom_data = (u8 *) (packet + sizeof(*hdr));
1955 q6lsm_add_hdr(client, hdr, pkt_sz, true);
1956 hdr->opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
1957 memcpy(custom_data, data, p_info->param_size);
1958
1959 rc = q6lsm_apr_send_pkt(client, client->apr,
1960 packet, true, NULL);
1961 if (rc)
1962 pr_err("%s: CUSTOM_PARAMS failed, rc %d\n",
1963 __func__, rc);
1964 kfree(packet);
1965 break;
1966 }
1967 default:
1968 pr_err("%s: wrong param_type 0x%x\n",
1969 __func__, p_info->param_type);
1970 }
1971
1972 return rc;
1973}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301974EXPORT_SYMBOL(q6lsm_set_one_param);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301975
1976
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301977/**
1978 * q6lsm_start -
1979 * command for LSM start
1980 *
1981 * @client: LSM client handle
1982 *
1983 * Returns 0 on success or error on failure
1984 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301985int q6lsm_start(struct lsm_client *client, bool wait)
1986{
1987 return q6lsm_cmd(client, LSM_SESSION_CMD_START, wait);
1988}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301989EXPORT_SYMBOL(q6lsm_start);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301990
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301991/**
1992 * q6lsm_stop -
1993 * command for LSM stop
1994 *
1995 * @client: LSM client handle
1996 *
1997 * Returns 0 on success or error on failure
1998 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301999int q6lsm_stop(struct lsm_client *client, bool wait)
2000{
2001 return q6lsm_cmd(client, LSM_SESSION_CMD_STOP, wait);
2002}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302003EXPORT_SYMBOL(q6lsm_stop);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302004
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302005/**
2006 * q6lsm_close -
2007 * command for LSM close
2008 *
2009 * @client: LSM client handle
2010 *
2011 * Returns 0 on success or error on failure
2012 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302013int q6lsm_close(struct lsm_client *client)
2014{
2015 return q6lsm_cmd(client, LSM_SESSION_CMD_CLOSE_TX, true);
2016}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302017EXPORT_SYMBOL(q6lsm_close);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302018
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302019/**
2020 * q6lsm_lab_control -
2021 * command to set LSM LAB control params
2022 *
2023 * @client: LSM client handle
2024 * @enable: bool flag to enable or disable LAB on DSP
2025 *
2026 * Returns 0 on success or error on failure
2027 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302028int q6lsm_lab_control(struct lsm_client *client, u32 enable)
2029{
2030 int rc = 0;
2031 struct lsm_params_lab_enable lab_enable;
2032 struct lsm_params_lab_config lab_config;
2033 struct lsm_module_param_ids lab_ids;
2034 u32 param_size;
2035
2036 if (!client) {
2037 pr_err("%s: invalid param client %pK\n", __func__, client);
2038 return -EINVAL;
2039 }
2040 /* enable/disable lab on dsp */
2041 q6lsm_add_hdr(client, &lab_enable.msg_hdr, sizeof(lab_enable), true);
2042 lab_enable.msg_hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
2043 q6lsm_set_param_hdr_info(&lab_enable.params_hdr,
2044 sizeof(struct lsm_lab_enable),
2045 0, 0, 0);
2046 param_size = (sizeof(struct lsm_lab_enable) -
2047 sizeof(struct lsm_param_payload_common));
2048 lab_ids.module_id = LSM_MODULE_ID_LAB;
2049 lab_ids.param_id = LSM_PARAM_ID_LAB_ENABLE;
2050 q6lsm_set_param_common(&lab_enable.lab_enable.common,
2051 &lab_ids, param_size,
2052 LSM_SESSION_CMD_SET_PARAMS);
2053 lab_enable.lab_enable.enable = (enable) ? 1 : 0;
2054 rc = q6lsm_apr_send_pkt(client, client->apr, &lab_enable, true, NULL);
2055 if (rc) {
2056 pr_err("%s: Lab enable failed rc %d\n", __func__, rc);
2057 return rc;
2058 }
2059 if (!enable)
2060 goto exit;
2061 /* lab session is being enabled set the config values */
2062 q6lsm_add_hdr(client, &lab_config.msg_hdr, sizeof(lab_config), true);
2063 lab_config.msg_hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
2064 q6lsm_set_param_hdr_info(&lab_config.params_hdr,
2065 sizeof(struct lsm_lab_config),
2066 0, 0, 0);
2067 lab_ids.module_id = LSM_MODULE_ID_LAB;
2068 lab_ids.param_id = LSM_PARAM_ID_LAB_CONFIG;
2069 param_size = (sizeof(struct lsm_lab_config) -
2070 sizeof(struct lsm_param_payload_common));
2071 q6lsm_set_param_common(&lab_config.lab_config.common,
2072 &lab_ids, param_size,
2073 LSM_SESSION_CMD_SET_PARAMS);
2074 lab_config.lab_config.minor_version = 1;
2075 lab_config.lab_config.wake_up_latency_ms = 250;
2076 rc = q6lsm_apr_send_pkt(client, client->apr, &lab_config, true, NULL);
2077 if (rc) {
2078 pr_err("%s: Lab config failed rc %d disable lab\n",
2079 __func__, rc);
2080 /* Lab config failed disable lab */
2081 lab_enable.lab_enable.enable = 0;
2082 if (q6lsm_apr_send_pkt(client, client->apr,
2083 &lab_enable, true, NULL))
2084 pr_err("%s: Lab disable failed\n", __func__);
2085 }
2086exit:
2087 return rc;
2088}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302089EXPORT_SYMBOL(q6lsm_lab_control);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302090
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302091/**
2092 * q6lsm_stop_lab -
2093 * command to stop LSM LAB
2094 *
2095 * @client: LSM client handle
2096 *
2097 * Returns 0 on success or error on failure
2098 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302099int q6lsm_stop_lab(struct lsm_client *client)
2100{
2101 int rc = 0;
2102
2103 if (!client) {
2104 pr_err("%s: invalid param client %pK\n", __func__, client);
2105 return -EINVAL;
2106 }
2107 rc = q6lsm_cmd(client, LSM_SESSION_CMD_EOB, true);
2108 if (rc)
2109 pr_err("%s: Lab stop failed %d\n", __func__, rc);
2110 return rc;
2111}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302112EXPORT_SYMBOL(q6lsm_stop_lab);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302113
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302114/**
2115 * q6lsm_read -
2116 * command for LSM read
2117 *
2118 * @client: LSM client handle
2119 * @lsm_cmd_read: LSM read command
2120 *
2121 * Returns 0 on success or error on failure
2122 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302123int q6lsm_read(struct lsm_client *client, struct lsm_cmd_read *read)
2124{
2125 int rc = 0;
2126
2127 if (!client || !read) {
2128 pr_err("%s: Invalid params client %pK read %pK\n", __func__,
2129 client, read);
2130 return -EINVAL;
2131 }
2132 pr_debug("%s: read call memmap handle %x address %x%x size %d\n",
2133 __func__, read->mem_map_handle, read->buf_addr_msw,
2134 read->buf_addr_lsw, read->buf_size);
2135 q6lsm_add_hdr(client, &read->hdr, sizeof(struct lsm_cmd_read), true);
2136 read->hdr.opcode = LSM_SESSION_CMD_READ;
2137 rc = q6lsm_apr_send_pkt(client, client->apr, read, false, NULL);
2138 if (rc)
2139 pr_err("%s: read buffer call failed rc %d\n", __func__, rc);
2140 return rc;
2141}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302142EXPORT_SYMBOL(q6lsm_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302143
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302144/**
2145 * q6lsm_lab_buffer_alloc -
2146 * Lab buffer allocation or de-alloc
2147 *
2148 * @client: LSM client handle
2149 * @alloc: Allocate or free ion memory
2150 *
2151 * Returns 0 on success or error on failure
2152 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302153int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc)
2154{
2155 int ret = 0, i = 0;
2156 size_t allocate_size = 0, len = 0;
2157
2158 if (!client) {
2159 pr_err("%s: invalid client\n", __func__);
2160 return -EINVAL;
2161 }
2162 if (alloc) {
2163 if (client->lab_buffer) {
2164 pr_err("%s: buffers are allocated period count %d period size %d\n",
2165 __func__,
2166 client->hw_params.period_count,
2167 client->hw_params.buf_sz);
2168 return -EINVAL;
2169 }
2170 allocate_size = client->hw_params.period_count *
2171 client->hw_params.buf_sz;
2172 allocate_size = PAGE_ALIGN(allocate_size);
2173 client->lab_buffer =
2174 kzalloc(sizeof(struct lsm_lab_buffer) *
2175 client->hw_params.period_count, GFP_KERNEL);
2176 if (!client->lab_buffer) {
2177 pr_err("%s: memory allocation for lab buffer failed count %d\n"
2178 , __func__,
2179 client->hw_params.period_count);
2180 return -ENOMEM;
2181 }
2182 ret = msm_audio_ion_alloc("lsm_lab",
2183 &client->lab_buffer[0].client,
2184 &client->lab_buffer[0].handle,
2185 allocate_size, &client->lab_buffer[0].phys,
2186 &len,
2187 &client->lab_buffer[0].data);
2188 if (ret)
2189 pr_err("%s: ion alloc failed ret %d size %zd\n",
2190 __func__, ret, allocate_size);
2191 else {
2192 ret = q6lsm_memory_map_regions(client,
2193 client->lab_buffer[0].phys, len,
2194 &client->lab_buffer[0].mem_map_handle);
2195 if (ret) {
2196 pr_err("%s: memory map filed ret %d size %zd\n",
2197 __func__, ret, len);
2198 msm_audio_ion_free(
2199 client->lab_buffer[0].client,
2200 client->lab_buffer[0].handle);
2201 }
2202 }
2203 if (ret) {
2204 pr_err("%s: alloc lab buffer failed ret %d\n",
2205 __func__, ret);
2206 kfree(client->lab_buffer);
2207 client->lab_buffer = NULL;
2208 } else {
2209 pr_debug("%s: Memory map handle %x phys %pK size %d\n",
2210 __func__,
2211 client->lab_buffer[0].mem_map_handle,
2212 &client->lab_buffer[0].phys,
2213 client->hw_params.buf_sz);
2214 for (i = 0; i < client->hw_params.period_count; i++) {
2215 client->lab_buffer[i].phys =
2216 client->lab_buffer[0].phys +
2217 (i * client->hw_params.buf_sz);
2218 client->lab_buffer[i].size =
2219 client->hw_params.buf_sz;
2220 client->lab_buffer[i].data =
2221 (u8 *)(client->lab_buffer[0].data) +
2222 (i * client->hw_params.buf_sz);
2223 client->lab_buffer[i].mem_map_handle =
2224 client->lab_buffer[0].mem_map_handle;
2225 }
2226 }
2227 } else {
2228 ret = q6lsm_memory_unmap_regions(client,
2229 client->lab_buffer[0].mem_map_handle);
2230 if (!ret)
2231 msm_audio_ion_free(
2232 client->lab_buffer[0].client,
2233 client->lab_buffer[0].handle);
2234 else
2235 pr_err("%s: unmap failed not freeing memory\n",
2236 __func__);
2237 kfree(client->lab_buffer);
2238 client->lab_buffer = NULL;
2239 }
2240 return ret;
2241}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302242EXPORT_SYMBOL(q6lsm_lab_buffer_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302243
2244static int get_cal_type_index(int32_t cal_type)
2245{
2246 int ret = -EINVAL;
2247
2248 switch (cal_type) {
2249 case LSM_CUST_TOPOLOGY_CAL_TYPE:
2250 ret = LSM_CUSTOM_TOP_IDX;
2251 break;
2252 case LSM_TOPOLOGY_CAL_TYPE:
2253 ret = LSM_TOP_IDX;
2254 break;
2255 case LSM_CAL_TYPE:
2256 ret = LSM_CAL_IDX;
2257 break;
2258 default:
2259 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
2260 }
2261 return ret;
2262}
2263
2264static int q6lsm_alloc_cal(int32_t cal_type,
2265 size_t data_size, void *data)
2266{
2267 int ret = 0;
2268 int cal_index;
2269
2270 pr_debug("%s:\n", __func__);
2271
2272 cal_index = get_cal_type_index(cal_type);
2273 if (cal_index < 0) {
2274 pr_err("%s: could not get cal index %d!\n",
2275 __func__, cal_index);
2276 ret = -EINVAL;
2277 goto done;
2278 }
2279
2280 ret = cal_utils_alloc_cal(data_size, data,
2281 lsm_common.cal_data[cal_index], 0, NULL);
2282 if (ret < 0) {
2283 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
2284 __func__, ret, cal_type);
2285 ret = -EINVAL;
2286 goto done;
2287 }
2288done:
2289 return ret;
2290}
2291
2292static int q6lsm_dealloc_cal(int32_t cal_type,
2293 size_t data_size, void *data)
2294{
2295 int ret = 0;
2296 int cal_index;
2297
2298 pr_debug("%s:\n", __func__);
2299
2300 cal_index = get_cal_type_index(cal_type);
2301 if (cal_index < 0) {
2302 pr_err("%s: could not get cal index %d!\n",
2303 __func__, cal_index);
2304 ret = -EINVAL;
2305 goto done;
2306 }
2307
2308 ret = cal_utils_dealloc_cal(data_size, data,
2309 lsm_common.cal_data[cal_index]);
2310 if (ret < 0) {
2311 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
2312 __func__, ret, cal_type);
2313 ret = -EINVAL;
2314 goto done;
2315 }
2316done:
2317 return ret;
2318}
2319
2320static int q6lsm_set_cal(int32_t cal_type,
2321 size_t data_size, void *data)
2322{
2323 int ret = 0;
2324 int cal_index;
2325
2326 pr_debug("%s:\n", __func__);
2327
2328 cal_index = get_cal_type_index(cal_type);
2329 if (cal_index < 0) {
2330 pr_err("%s: could not get cal index %d!\n",
2331 __func__, cal_index);
2332 ret = -EINVAL;
2333 goto done;
2334 }
2335
2336 ret = cal_utils_set_cal(data_size, data,
2337 lsm_common.cal_data[cal_index], 0, NULL);
2338 if (ret < 0) {
2339 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
2340 __func__, ret, cal_type);
2341 ret = -EINVAL;
2342 goto done;
2343 }
2344
2345 if (cal_index == LSM_CUSTOM_TOP_IDX) {
2346 mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
2347 lsm_common.set_custom_topology = 1;
2348 mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
2349 }
2350
2351done:
2352 return ret;
2353}
2354
2355static void lsm_delete_cal_data(void)
2356{
2357 pr_debug("%s:\n", __func__);
2358
2359 cal_utils_destroy_cal_types(LSM_MAX_CAL_IDX, lsm_common.cal_data);
2360}
2361
2362static int q6lsm_init_cal_data(void)
2363{
2364 int ret = 0;
2365 struct cal_type_info cal_type_info[] = {
2366 {{LSM_CUST_TOPOLOGY_CAL_TYPE,
2367 {q6lsm_alloc_cal, q6lsm_dealloc_cal, NULL,
2368 q6lsm_set_cal, NULL, NULL} },
2369 {NULL, NULL, cal_utils_match_buf_num} },
2370
2371 {{LSM_TOPOLOGY_CAL_TYPE,
2372 {NULL, NULL, NULL,
2373 q6lsm_set_cal, NULL, NULL} },
2374 {NULL, NULL, cal_utils_match_buf_num} },
2375
2376 {{LSM_CAL_TYPE,
2377 {q6lsm_alloc_cal, q6lsm_dealloc_cal, NULL,
2378 q6lsm_set_cal, NULL, NULL} },
2379 {NULL, NULL, cal_utils_match_buf_num} }
2380 };
2381 pr_debug("%s:\n", __func__);
2382
2383 ret = cal_utils_create_cal_types(LSM_MAX_CAL_IDX,
2384 lsm_common.cal_data, cal_type_info);
2385 if (ret < 0) {
2386 pr_err("%s: could not create cal type!\n",
2387 __func__);
2388 ret = -EINVAL;
2389 goto err;
2390 }
2391
2392 return ret;
2393err:
2394 lsm_delete_cal_data();
2395 return ret;
2396}
2397
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302398int __init q6lsm_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302399{
2400 int i = 0;
2401
2402 pr_debug("%s:\n", __func__);
2403 spin_lock_init(&lsm_session_lock);
2404 spin_lock_init(&mmap_lock);
2405 mutex_init(&lsm_common.apr_lock);
2406 for (; i <= LSM_MAX_SESSION_ID; i++) {
2407 lsm_common.common_client[i].session = LSM_CONTROL_SESSION;
2408 init_waitqueue_head(&lsm_common.common_client[i].cmd_wait);
2409 mutex_init(&lsm_common.common_client[i].cmd_lock);
2410 atomic_set(&lsm_common.common_client[i].cmd_state,
2411 CMD_STATE_CLEARED);
2412 }
2413
2414 if (q6lsm_init_cal_data())
2415 pr_err("%s: could not init cal data!\n", __func__);
2416
2417 return 0;
2418}
2419
Asish Bhattacharya5faacb32017-12-04 17:23:15 +05302420void q6lsm_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302421{
2422 lsm_delete_cal_data();
2423}