blob: 0ea2694540356e85e3967d54d9dadeb487e61180 [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Meng Wang61af6842018-09-10 17:47:55 +08002/*
Laxminath Kasamc910c022018-04-04 10:59:57 +05303 * Copyright (c) 2010-2014, 2016-2019 The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304 */
5
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <linux/types.h>
9#include <linux/uaccess.h>
10#include <linux/spinlock.h>
11#include <linux/list.h>
12#include <linux/sched.h>
13#include <linux/wait.h>
14#include <linux/errno.h>
15#include <linux/fs.h>
16#include <linux/delay.h>
17#include <linux/debugfs.h>
18#include <linux/platform_device.h>
19#include <linux/sysfs.h>
20#include <linux/device.h>
Banajit Goswami3d99f7a2018-03-03 02:09:05 -080021#include <linux/of.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053022#include <linux/slab.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053023#include <linux/ipc_logging.h>
Meng Wangeab9a2b2018-05-02 14:55:53 +080024#include <linux/of_platform.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053025#include <soc/qcom/subsystem_restart.h>
26#include <soc/qcom/scm.h>
Banajit Goswami40bdd6b2018-07-20 19:24:54 -070027#include <soc/snd_event.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053028#include <dsp/apr_audio-v2.h>
29#include <dsp/audio_notifier.h>
30#include <ipc/apr.h>
31#include <ipc/apr_tal.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053032
33#define APR_PKT_IPC_LOG_PAGE_CNT 2
34
35static struct apr_q6 q6;
36static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
37static void *apr_pkt_ctx;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053038static wait_queue_head_t modem_wait;
39static bool is_modem_up;
Meng Wangf71f3502018-05-07 16:59:30 +080040static char *subsys_name = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053041/* Subsystem restart: QDSP6 data, functions */
42static struct workqueue_struct *apr_reset_workqueue;
43static void apr_reset_deregister(struct work_struct *work);
44static void dispatch_event(unsigned long code, uint16_t proc);
45struct apr_reset_work {
46 void *handle;
47 struct work_struct work;
48};
49
Banajit Goswami3d99f7a2018-03-03 02:09:05 -080050struct apr_chld_device {
51 struct platform_device *pdev;
52 struct list_head node;
53};
54
55struct apr_private {
56 struct device *dev;
57 spinlock_t apr_lock;
58 bool is_initial_boot;
59 struct work_struct add_chld_dev_work;
Banajit Goswami3d99f7a2018-03-03 02:09:05 -080060};
61
62static struct apr_private *apr_priv;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053063static bool apr_cf_debug;
64
65#ifdef CONFIG_DEBUG_FS
66static struct dentry *debugfs_apr_debug;
67static ssize_t apr_debug_write(struct file *filp, const char __user *ubuf,
68 size_t cnt, loff_t *ppos)
69{
70 char cmd;
71
72 if (copy_from_user(&cmd, ubuf, 1))
73 return -EFAULT;
74
75 apr_cf_debug = (cmd == '1') ? true : false;
76
77 return cnt;
78}
79
80static const struct file_operations apr_debug_ops = {
81 .write = apr_debug_write,
82};
83#endif
84
85#define APR_PKT_INFO(x...) \
86do { \
87 if (apr_pkt_ctx) \
88 ipc_log_string(apr_pkt_ctx, "<APR>: "x); \
89} while (0)
90
91
92struct apr_svc_table {
93 char name[64];
94 int idx;
95 int id;
96 int client_id;
97};
98
99static const struct apr_svc_table svc_tbl_qdsp6[] = {
100 {
101 .name = "AFE",
102 .idx = 0,
103 .id = APR_SVC_AFE,
104 .client_id = APR_CLIENT_AUDIO,
105 },
106 {
107 .name = "ASM",
108 .idx = 1,
109 .id = APR_SVC_ASM,
110 .client_id = APR_CLIENT_AUDIO,
111 },
112 {
113 .name = "ADM",
114 .idx = 2,
115 .id = APR_SVC_ADM,
116 .client_id = APR_CLIENT_AUDIO,
117 },
118 {
119 .name = "CORE",
120 .idx = 3,
121 .id = APR_SVC_ADSP_CORE,
122 .client_id = APR_CLIENT_AUDIO,
123 },
124 {
125 .name = "TEST",
126 .idx = 4,
127 .id = APR_SVC_TEST_CLIENT,
128 .client_id = APR_CLIENT_AUDIO,
129 },
130 {
131 .name = "MVM",
132 .idx = 5,
133 .id = APR_SVC_ADSP_MVM,
134 .client_id = APR_CLIENT_AUDIO,
135 },
136 {
137 .name = "CVS",
138 .idx = 6,
139 .id = APR_SVC_ADSP_CVS,
140 .client_id = APR_CLIENT_AUDIO,
141 },
142 {
143 .name = "CVP",
144 .idx = 7,
145 .id = APR_SVC_ADSP_CVP,
146 .client_id = APR_CLIENT_AUDIO,
147 },
148 {
149 .name = "USM",
150 .idx = 8,
151 .id = APR_SVC_USM,
152 .client_id = APR_CLIENT_AUDIO,
153 },
154 {
155 .name = "VIDC",
156 .idx = 9,
157 .id = APR_SVC_VIDC,
158 },
159 {
160 .name = "LSM",
161 .idx = 10,
162 .id = APR_SVC_LSM,
163 .client_id = APR_CLIENT_AUDIO,
164 },
165};
166
167static struct apr_svc_table svc_tbl_voice[] = {
168 {
169 .name = "VSM",
170 .idx = 0,
171 .id = APR_SVC_VSM,
172 .client_id = APR_CLIENT_VOICE,
173 },
174 {
175 .name = "VPM",
176 .idx = 1,
177 .id = APR_SVC_VPM,
178 .client_id = APR_CLIENT_VOICE,
179 },
180 {
181 .name = "MVS",
182 .idx = 2,
183 .id = APR_SVC_MVS,
184 .client_id = APR_CLIENT_VOICE,
185 },
186 {
187 .name = "MVM",
188 .idx = 3,
189 .id = APR_SVC_MVM,
190 .client_id = APR_CLIENT_VOICE,
191 },
192 {
193 .name = "CVS",
194 .idx = 4,
195 .id = APR_SVC_CVS,
196 .client_id = APR_CLIENT_VOICE,
197 },
198 {
199 .name = "CVP",
200 .idx = 5,
201 .id = APR_SVC_CVP,
202 .client_id = APR_CLIENT_VOICE,
203 },
204 {
205 .name = "SRD",
206 .idx = 6,
207 .id = APR_SVC_SRD,
208 .client_id = APR_CLIENT_VOICE,
209 },
210 {
211 .name = "TEST",
212 .idx = 7,
213 .id = APR_SVC_TEST_CLIENT,
214 .client_id = APR_CLIENT_VOICE,
215 },
216};
217
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530218/**
219 * apr_get_modem_state:
220 *
221 * Returns current modem load status
222 *
223 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530224enum apr_subsys_state apr_get_modem_state(void)
225{
226 return atomic_read(&q6.modem_state);
227}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530228EXPORT_SYMBOL(apr_get_modem_state);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530229
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530230/**
231 * apr_set_modem_state - Update modem load status.
232 *
233 * @state: State to update modem load status
234 *
235 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530236void apr_set_modem_state(enum apr_subsys_state state)
237{
238 atomic_set(&q6.modem_state, state);
239}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530240EXPORT_SYMBOL(apr_set_modem_state);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530241
242enum apr_subsys_state apr_cmpxchg_modem_state(enum apr_subsys_state prev,
243 enum apr_subsys_state new)
244{
245 return atomic_cmpxchg(&q6.modem_state, prev, new);
246}
247
248static void apr_modem_down(unsigned long opcode)
249{
250 apr_set_modem_state(APR_SUBSYS_DOWN);
251 dispatch_event(opcode, APR_DEST_MODEM);
252}
253
254static void apr_modem_up(void)
255{
256 if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
257 APR_SUBSYS_DOWN)
258 wake_up(&modem_wait);
259 is_modem_up = 1;
260}
261
262enum apr_subsys_state apr_get_q6_state(void)
263{
264 return atomic_read(&q6.q6_state);
265}
266EXPORT_SYMBOL(apr_get_q6_state);
267
268int apr_set_q6_state(enum apr_subsys_state state)
269{
270 pr_debug("%s: setting adsp state %d\n", __func__, state);
271 if (state < APR_SUBSYS_DOWN || state > APR_SUBSYS_LOADED)
272 return -EINVAL;
273 atomic_set(&q6.q6_state, state);
274 return 0;
275}
276EXPORT_SYMBOL(apr_set_q6_state);
277
Banajit Goswami40bdd6b2018-07-20 19:24:54 -0700278static void apr_ssr_disable(struct device *dev, void *data)
279{
280 apr_set_q6_state(APR_SUBSYS_DOWN);
281}
282
283static const struct snd_event_ops apr_ssr_ops = {
284 .disable = apr_ssr_disable,
285};
286
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530287static void apr_adsp_down(unsigned long opcode)
288{
Meng Wangeab9a2b2018-05-02 14:55:53 +0800289 pr_info("%s: Q6 is Down\n", __func__);
Banajit Goswami40bdd6b2018-07-20 19:24:54 -0700290 snd_event_notify(apr_priv->dev, SND_EVENT_DOWN);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530291 apr_set_q6_state(APR_SUBSYS_DOWN);
292 dispatch_event(opcode, APR_DEST_QDSP6);
293}
294
Banajit Goswami3d99f7a2018-03-03 02:09:05 -0800295static void apr_add_child_devices(struct work_struct *work)
296{
297 int ret;
Banajit Goswami3d99f7a2018-03-03 02:09:05 -0800298
Meng Wangeab9a2b2018-05-02 14:55:53 +0800299 ret = of_platform_populate(apr_priv->dev->of_node,
300 NULL, NULL, apr_priv->dev);
301 if (ret)
302 dev_err(apr_priv->dev, "%s: failed to add child nodes, ret=%d\n",
303 __func__, ret);
Banajit Goswami3d99f7a2018-03-03 02:09:05 -0800304}
305
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530306static void apr_adsp_up(void)
307{
Meng Wangeab9a2b2018-05-02 14:55:53 +0800308 pr_info("%s: Q6 is Up\n", __func__);
Meng Wanga6092af2018-05-07 15:08:26 +0800309 apr_set_q6_state(APR_SUBSYS_LOADED);
Banajit Goswami3d99f7a2018-03-03 02:09:05 -0800310
311 spin_lock(&apr_priv->apr_lock);
312 if (apr_priv->is_initial_boot)
313 schedule_work(&apr_priv->add_chld_dev_work);
314 spin_unlock(&apr_priv->apr_lock);
Banajit Goswami40bdd6b2018-07-20 19:24:54 -0700315 snd_event_notify(apr_priv->dev, SND_EVENT_UP);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530316}
317
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530318int apr_load_adsp_image(void)
319{
320 int rc = 0;
321
322 mutex_lock(&q6.lock);
323 if (apr_get_q6_state() == APR_SUBSYS_UP) {
324 q6.pil = subsystem_get("adsp");
325 if (IS_ERR(q6.pil)) {
326 rc = PTR_ERR(q6.pil);
327 pr_err("APR: Unable to load q6 image, error:%d\n", rc);
328 } else {
329 apr_set_q6_state(APR_SUBSYS_LOADED);
330 pr_debug("APR: Image is loaded, stated\n");
331 }
332 } else if (apr_get_q6_state() == APR_SUBSYS_LOADED) {
333 pr_debug("APR: q6 image already loaded\n");
334 } else {
335 pr_debug("APR: cannot load state %d\n", apr_get_q6_state());
336 }
337 mutex_unlock(&q6.lock);
338 return rc;
339}
340
341struct apr_client *apr_get_client(int dest_id, int client_id)
342{
343 return &client[dest_id][client_id];
344}
345
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530346/**
347 * apr_send_pkt - Clients call to send packet
348 * to destination processor.
349 *
350 * @handle: APR service handle
351 * @buf: payload to send to destination processor.
352 *
353 * Returns Bytes(>0)pkt_size on success or error on failure.
354 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530355int apr_send_pkt(void *handle, uint32_t *buf)
356{
357 struct apr_svc *svc = handle;
358 struct apr_client *clnt;
359 struct apr_hdr *hdr;
360 uint16_t dest_id;
361 uint16_t client_id;
362 uint16_t w_len;
363 int rc;
364 unsigned long flags;
365
366 if (!handle || !buf) {
Karthikeyan Mani5670cbd2019-03-21 18:00:51 -0700367 pr_err("APR: Wrong parameters for %s\n",
368 !handle ? "handle" : "buf");
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530369 return -EINVAL;
370 }
371 if (svc->need_reset) {
Laxminath Kasamc910c022018-04-04 10:59:57 +0530372 pr_err_ratelimited("apr: send_pkt service need reset\n");
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530373 return -ENETRESET;
374 }
375
376 if ((svc->dest_id == APR_DEST_QDSP6) &&
377 (apr_get_q6_state() != APR_SUBSYS_LOADED)) {
Laxminath Kasamc910c022018-04-04 10:59:57 +0530378 pr_err_ratelimited("%s: Still dsp is not Up\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530379 return -ENETRESET;
380 } else if ((svc->dest_id == APR_DEST_MODEM) &&
381 (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
382 pr_err("apr: Still Modem is not Up\n");
383 return -ENETRESET;
384 }
385
386 spin_lock_irqsave(&svc->w_lock, flags);
387 dest_id = svc->dest_id;
388 client_id = svc->client_id;
389 clnt = &client[dest_id][client_id];
390
391 if (!client[dest_id][client_id].handle) {
Laxminath Kasamc910c022018-04-04 10:59:57 +0530392 pr_err_ratelimited("APR: Still service is not yet opened\n");
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530393 spin_unlock_irqrestore(&svc->w_lock, flags);
394 return -EINVAL;
395 }
396 hdr = (struct apr_hdr *)buf;
397
398 hdr->src_domain = APR_DOMAIN_APPS;
399 hdr->src_svc = svc->id;
400 hdr->dest_domain = svc->dest_domain;
401 hdr->dest_svc = svc->id;
402
403 if (unlikely(apr_cf_debug)) {
404 APR_PKT_INFO(
405 "Tx: src_addr[0x%X] dest_addr[0x%X] opcode[0x%X] token[0x%X]",
406 (hdr->src_domain << 8) | hdr->src_svc,
407 (hdr->dest_domain << 8) | hdr->dest_svc, hdr->opcode,
408 hdr->token);
409 }
410
411 rc = apr_tal_write(clnt->handle, buf,
412 (struct apr_pkt_priv *)&svc->pkt_owner,
413 hdr->pkt_size);
414 if (rc >= 0) {
415 w_len = rc;
416 if (w_len != hdr->pkt_size) {
417 pr_err("%s: Unable to write whole APR pkt successfully: %d\n",
418 __func__, rc);
419 rc = -EINVAL;
420 }
421 } else {
Ramprasad Katkamb91472b2019-02-19 19:35:55 +0530422 pr_err_ratelimited("%s: Write APR pkt failed with error %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530423 __func__, rc);
Ramprasad Katkamb91472b2019-02-19 19:35:55 +0530424 if (rc == -ECONNRESET) {
425 pr_err_ratelimited("%s: Received reset error from tal\n",
426 __func__);
427 rc = -ENETRESET;
428 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530429 }
430 spin_unlock_irqrestore(&svc->w_lock, flags);
431
432 return rc;
433}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530434EXPORT_SYMBOL(apr_send_pkt);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530435
436int apr_pkt_config(void *handle, struct apr_pkt_cfg *cfg)
437{
438 struct apr_svc *svc = (struct apr_svc *)handle;
439 uint16_t dest_id;
440 uint16_t client_id;
441 struct apr_client *clnt;
442
443 if (!handle) {
444 pr_err("%s: Invalid handle\n", __func__);
445 return -EINVAL;
446 }
447
448 if (svc->need_reset) {
449 pr_err("%s: service need reset\n", __func__);
450 return -ENETRESET;
451 }
452
453 svc->pkt_owner = cfg->pkt_owner;
454 dest_id = svc->dest_id;
455 client_id = svc->client_id;
456 clnt = &client[dest_id][client_id];
457
458 return apr_tal_rx_intents_config(clnt->handle,
459 cfg->intents.num_of_intents, cfg->intents.size);
460}
461
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530462/**
463 * apr_register - Clients call to register
464 * to APR.
465 *
466 * @dest: destination processor
467 * @svc_name: name of service to register as
468 * @svc_fn: callback function to trigger when response
469 * ack or packets received from destination processor.
470 * @src_port: Port number within a service
471 * @priv: private data of client, passed back in cb fn.
472 *
473 * Returns apr_svc handle on success or NULL on failure.
474 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530475struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
476 uint32_t src_port, void *priv)
477{
478 struct apr_client *clnt;
479 int client_id = 0;
480 int svc_idx = 0;
481 int svc_id = 0;
482 int dest_id = 0;
483 int domain_id = 0;
484 int temp_port = 0;
485 struct apr_svc *svc = NULL;
486 int rc = 0;
487 bool can_open_channel = true;
488
489 if (!dest || !svc_name || !svc_fn)
490 return NULL;
491
492 if (!strcmp(dest, "ADSP"))
493 domain_id = APR_DOMAIN_ADSP;
494 else if (!strcmp(dest, "MODEM")) {
495 /* Don't request for SMD channels if destination is MODEM,
496 * as these channels are no longer used and these clients
497 * are to listen only for MODEM SSR events
498 */
499 can_open_channel = false;
500 domain_id = APR_DOMAIN_MODEM;
501 } else {
502 pr_err("APR: wrong destination\n");
503 goto done;
504 }
505
506 dest_id = apr_get_dest_id(dest);
507
508 if (dest_id == APR_DEST_QDSP6) {
509 if (apr_get_q6_state() != APR_SUBSYS_LOADED) {
Laxminath Kasamc910c022018-04-04 10:59:57 +0530510 pr_err_ratelimited("%s: adsp not up\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530511 return NULL;
512 }
513 pr_debug("%s: adsp Up\n", __func__);
514 } else if (dest_id == APR_DEST_MODEM) {
515 if (apr_get_modem_state() == APR_SUBSYS_DOWN) {
516 if (is_modem_up) {
517 pr_err("%s: modem shutdown due to SSR, ret",
518 __func__);
519 return NULL;
520 }
521 pr_debug("%s: Wait for modem to bootup\n", __func__);
Meng Wanga6092af2018-05-07 15:08:26 +0800522 rc = wait_event_interruptible_timeout(modem_wait,
523 (apr_get_modem_state() == APR_SUBSYS_UP),
524 (1 * HZ));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530525 if (rc == 0) {
526 pr_err("%s: Modem is not Up\n", __func__);
527 return NULL;
528 }
529 }
530 pr_debug("%s: modem Up\n", __func__);
531 }
532
533 if (apr_get_svc(svc_name, domain_id, &client_id, &svc_idx, &svc_id)) {
Laxminath Kasamc910c022018-04-04 10:59:57 +0530534 pr_err_ratelimited("%s: apr_get_svc failed\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530535 goto done;
536 }
537
538 clnt = &client[dest_id][client_id];
539 mutex_lock(&clnt->m_lock);
540 if (!clnt->handle && can_open_channel) {
541 clnt->handle = apr_tal_open(client_id, dest_id,
542 APR_DL_SMD, apr_cb_func, NULL);
543 if (!clnt->handle) {
544 svc = NULL;
Laxminath Kasamc910c022018-04-04 10:59:57 +0530545 pr_err_ratelimited("APR: Unable to open handle\n");
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530546 mutex_unlock(&clnt->m_lock);
547 goto done;
548 }
549 }
550 mutex_unlock(&clnt->m_lock);
551 svc = &clnt->svc[svc_idx];
552 mutex_lock(&svc->m_lock);
553 clnt->id = client_id;
554 if (svc->need_reset) {
555 mutex_unlock(&svc->m_lock);
Laxminath Kasamc910c022018-04-04 10:59:57 +0530556 pr_err_ratelimited("APR: Service needs reset\n");
Vidyakumar Athota0b9c8c12018-08-14 10:57:27 -0700557 svc = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530558 goto done;
559 }
560 svc->id = svc_id;
561 svc->dest_id = dest_id;
562 svc->client_id = client_id;
563 svc->dest_domain = domain_id;
564 svc->pkt_owner = APR_PKT_OWNER_DRIVER;
565
566 if (src_port != 0xFFFFFFFF) {
567 temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
568 pr_debug("port = %d t_port = %d\n", src_port, temp_port);
569 if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
570 pr_err("APR: temp_port out of bounds\n");
571 mutex_unlock(&svc->m_lock);
572 return NULL;
573 }
574 if (!svc->svc_cnt)
575 clnt->svc_cnt++;
576 svc->port_cnt++;
577 svc->port_fn[temp_port] = svc_fn;
578 svc->port_priv[temp_port] = priv;
579 svc->svc_cnt++;
580 } else {
581 if (!svc->fn) {
582 if (!svc->svc_cnt)
583 clnt->svc_cnt++;
584 svc->fn = svc_fn;
585 svc->priv = priv;
586 svc->svc_cnt++;
587 }
588 }
589
590 mutex_unlock(&svc->m_lock);
591done:
592 return svc;
593}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530594EXPORT_SYMBOL(apr_register);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530595
596
597void apr_cb_func(void *buf, int len, void *priv)
598{
599 struct apr_client_data data;
600 struct apr_client *apr_client;
601 struct apr_svc *c_svc;
602 struct apr_hdr *hdr;
603 uint16_t hdr_size;
604 uint16_t msg_type;
605 uint16_t ver;
606 uint16_t src;
607 uint16_t svc;
608 uint16_t clnt;
609 int i;
610 int temp_port = 0;
611 uint32_t *ptr;
612
613 pr_debug("APR2: len = %d\n", len);
614 ptr = buf;
615 pr_debug("\n*****************\n");
616 for (i = 0; i < len/4; i++)
617 pr_debug("%x ", ptr[i]);
618 pr_debug("\n");
619 pr_debug("\n*****************\n");
620
621 if (!buf || len <= APR_HDR_SIZE) {
622 pr_err("APR: Improper apr pkt received:%pK %d\n", buf, len);
623 return;
624 }
625 hdr = buf;
626
627 ver = hdr->hdr_field;
628 ver = (ver & 0x000F);
629 if (ver > APR_PKT_VER + 1) {
630 pr_err("APR: Wrong version: %d\n", ver);
631 return;
632 }
633
634 hdr_size = hdr->hdr_field;
635 hdr_size = ((hdr_size & 0x00F0) >> 0x4) * 4;
636 if (hdr_size < APR_HDR_SIZE) {
637 pr_err("APR: Wrong hdr size:%d\n", hdr_size);
638 return;
639 }
640
641 if (hdr->pkt_size < APR_HDR_SIZE) {
642 pr_err("APR: Wrong paket size\n");
643 return;
644 }
Karthikeyan Manieca1a392019-01-15 16:36:08 -0800645
646 if (hdr->pkt_size < hdr_size) {
647 pr_err("APR: Packet size less than header size\n");
648 return;
649 }
650
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530651 msg_type = hdr->hdr_field;
652 msg_type = (msg_type >> 0x08) & 0x0003;
653 if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) {
654 pr_err("APR: Wrong message type: %d\n", msg_type);
655 return;
656 }
657
658 if (hdr->src_domain >= APR_DOMAIN_MAX ||
659 hdr->dest_domain >= APR_DOMAIN_MAX ||
660 hdr->src_svc >= APR_SVC_MAX ||
661 hdr->dest_svc >= APR_SVC_MAX) {
662 pr_err("APR: Wrong APR header\n");
663 return;
664 }
665
666 svc = hdr->dest_svc;
667 if (hdr->src_domain == APR_DOMAIN_MODEM) {
668 if (svc == APR_SVC_MVS || svc == APR_SVC_MVM ||
669 svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
670 svc == APR_SVC_TEST_CLIENT)
671 clnt = APR_CLIENT_VOICE;
672 else {
673 pr_err("APR: Wrong svc :%d\n", svc);
674 return;
675 }
676 } else if (hdr->src_domain == APR_DOMAIN_ADSP) {
677 if (svc == APR_SVC_AFE || svc == APR_SVC_ASM ||
678 svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
679 svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
680 svc == APR_SVC_USM ||
681 svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
682 svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP ||
683 svc == APR_SVC_LSM)
684 clnt = APR_CLIENT_AUDIO;
685 else if (svc == APR_SVC_VIDC)
686 clnt = APR_CLIENT_AUDIO;
687 else {
688 pr_err("APR: Wrong svc :%d\n", svc);
689 return;
690 }
691 } else {
692 pr_err("APR: Pkt from wrong source: %d\n", hdr->src_domain);
693 return;
694 }
695
696 src = apr_get_data_src(hdr);
697 if (src == APR_DEST_MAX)
698 return;
699
700 pr_debug("src =%d clnt = %d\n", src, clnt);
701 apr_client = &client[src][clnt];
702 for (i = 0; i < APR_SVC_MAX; i++)
703 if (apr_client->svc[i].id == svc) {
704 pr_debug("%d\n", apr_client->svc[i].id);
705 c_svc = &apr_client->svc[i];
706 break;
707 }
708
709 if (i == APR_SVC_MAX) {
710 pr_err("APR: service is not registered\n");
711 return;
712 }
713 pr_debug("svc_idx = %d\n", i);
714 pr_debug("%x %x %x %pK %pK\n", c_svc->id, c_svc->dest_id,
715 c_svc->client_id, c_svc->fn, c_svc->priv);
716 data.payload_size = hdr->pkt_size - hdr_size;
717 data.opcode = hdr->opcode;
718 data.src = src;
719 data.src_port = hdr->src_port;
720 data.dest_port = hdr->dest_port;
721 data.token = hdr->token;
722 data.msg_type = msg_type;
723 data.payload = NULL;
724 if (data.payload_size > 0)
725 data.payload = (char *)hdr + hdr_size;
726
727 if (unlikely(apr_cf_debug)) {
728 if (hdr->opcode == APR_BASIC_RSP_RESULT && data.payload) {
729 uint32_t *ptr = data.payload;
730
731 APR_PKT_INFO(
732 "Rx: src_addr[0x%X] dest_addr[0x%X] opcode[0x%X] token[0x%X] rc[0x%X]",
733 (hdr->src_domain << 8) | hdr->src_svc,
734 (hdr->dest_domain << 8) | hdr->dest_svc,
735 hdr->opcode, hdr->token, ptr[1]);
736 } else {
737 APR_PKT_INFO(
738 "Rx: src_addr[0x%X] dest_addr[0x%X] opcode[0x%X] token[0x%X]",
739 (hdr->src_domain << 8) | hdr->src_svc,
740 (hdr->dest_domain << 8) | hdr->dest_svc, hdr->opcode,
741 hdr->token);
742 }
743 }
744
745 temp_port = ((data.dest_port >> 8) * 8) + (data.dest_port & 0xFF);
Aditya Bavanarid3047b22017-11-22 15:29:52 +0530746 if (((temp_port >= 0) && (temp_port < APR_MAX_PORTS))
747 && (c_svc->port_cnt && c_svc->port_fn[temp_port]))
748 c_svc->port_fn[temp_port](&data,
749 c_svc->port_priv[temp_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530750 else if (c_svc->fn)
751 c_svc->fn(&data, c_svc->priv);
752 else
753 pr_err("APR: Rxed a packet for NULL callback\n");
754}
755
756int apr_get_svc(const char *svc_name, int domain_id, int *client_id,
757 int *svc_idx, int *svc_id)
758{
759 int i;
760 int size;
761 struct apr_svc_table *tbl;
762 int ret = 0;
763
764 if (domain_id == APR_DOMAIN_ADSP) {
765 tbl = (struct apr_svc_table *)&svc_tbl_qdsp6;
766 size = ARRAY_SIZE(svc_tbl_qdsp6);
767 } else {
768 tbl = (struct apr_svc_table *)&svc_tbl_voice;
769 size = ARRAY_SIZE(svc_tbl_voice);
770 }
771
772 for (i = 0; i < size; i++) {
773 if (!strcmp(svc_name, tbl[i].name)) {
774 *client_id = tbl[i].client_id;
775 *svc_idx = tbl[i].idx;
776 *svc_id = tbl[i].id;
777 break;
778 }
779 }
780
781 pr_debug("%s: svc_name = %s c_id = %d domain_id = %d\n",
782 __func__, svc_name, *client_id, domain_id);
783 if (i == size) {
784 pr_err("%s: APR: Wrong svc name %s\n", __func__, svc_name);
785 ret = -EINVAL;
786 }
787
788 return ret;
789}
790
791static void apr_reset_deregister(struct work_struct *work)
792{
793 struct apr_svc *handle = NULL;
794 struct apr_reset_work *apr_reset =
795 container_of(work, struct apr_reset_work, work);
796
797 handle = apr_reset->handle;
798 pr_debug("%s:handle[%pK]\n", __func__, handle);
799 apr_deregister(handle);
800 kfree(apr_reset);
801}
802
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530803/**
Banajit Goswami88327322017-12-08 10:51:58 -0800804 * apr_start_rx_rt - Clients call to vote for thread
805 * priority upgrade whenever needed.
806 *
807 * @handle: APR service handle
808 *
809 * Returns 0 on success or error otherwise.
810 */
811int apr_start_rx_rt(void *handle)
812{
813 int rc = 0;
814 struct apr_svc *svc = handle;
815 uint16_t dest_id = 0;
816 uint16_t client_id = 0;
817
818 if (!svc) {
819 pr_err("%s: Invalid APR handle\n", __func__);
820 return -EINVAL;
821 }
822
823 mutex_lock(&svc->m_lock);
824 dest_id = svc->dest_id;
825 client_id = svc->client_id;
826
827 if ((client_id >= APR_CLIENT_MAX) || (dest_id >= APR_DEST_MAX)) {
828 pr_err("%s: %s invalid. client_id = %u, dest_id = %u\n",
829 __func__,
830 client_id >= APR_CLIENT_MAX ? "Client ID" : "Dest ID",
831 client_id, dest_id);
832 rc = -EINVAL;
833 goto exit;
834 }
835
836 if (!client[dest_id][client_id].handle) {
837 pr_err("%s: Client handle is NULL\n", __func__);
838 rc = -EINVAL;
839 goto exit;
840 }
841
842 rc = apr_tal_start_rx_rt(client[dest_id][client_id].handle);
843 if (rc)
844 pr_err("%s: failed to set RT thread priority for APR RX. rc = %d\n",
845 __func__, rc);
846
847exit:
848 mutex_unlock(&svc->m_lock);
849 return rc;
850}
851EXPORT_SYMBOL(apr_start_rx_rt);
852
853/**
854 * apr_end_rx_rt - Clients call to unvote for thread
855 * priority upgrade (perviously voted with
856 * apr_start_rx_rt()).
857 *
858 * @handle: APR service handle
859 *
860 * Returns 0 on success or error otherwise.
861 */
862int apr_end_rx_rt(void *handle)
863{
864 int rc = 0;
865 struct apr_svc *svc = handle;
866 uint16_t dest_id = 0;
867 uint16_t client_id = 0;
868
869 if (!svc) {
870 pr_err("%s: Invalid APR handle\n", __func__);
871 return -EINVAL;
872 }
873
874 mutex_lock(&svc->m_lock);
875 dest_id = svc->dest_id;
876 client_id = svc->client_id;
877
878 if ((client_id >= APR_CLIENT_MAX) || (dest_id >= APR_DEST_MAX)) {
879 pr_err("%s: %s invalid. client_id = %u, dest_id = %u\n",
880 __func__,
881 client_id >= APR_CLIENT_MAX ? "Client ID" : "Dest ID",
882 client_id, dest_id);
883 rc = -EINVAL;
884 goto exit;
885 }
886
887 if (!client[dest_id][client_id].handle) {
888 pr_err("%s: Client handle is NULL\n", __func__);
889 rc = -EINVAL;
890 goto exit;
891 }
892
893 rc = apr_tal_end_rx_rt(client[dest_id][client_id].handle);
894 if (rc)
895 pr_err("%s: failed to reset RT thread priority for APR RX. rc = %d\n",
896 __func__, rc);
897
898exit:
899 mutex_unlock(&svc->m_lock);
900 return rc;
901}
902EXPORT_SYMBOL(apr_end_rx_rt);
903
904/**
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530905 * apr_deregister - Clients call to de-register
906 * from APR.
907 *
908 * @handle: APR service handle to de-register
909 *
910 * Returns 0 on success or -EINVAL on error.
911 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530912int apr_deregister(void *handle)
913{
914 struct apr_svc *svc = handle;
915 struct apr_client *clnt;
916 uint16_t dest_id;
917 uint16_t client_id;
918
919 if (!handle)
920 return -EINVAL;
921
922 mutex_lock(&svc->m_lock);
923 if (!svc->svc_cnt) {
924 pr_err("%s: svc already deregistered. svc = %pK\n",
925 __func__, svc);
926 mutex_unlock(&svc->m_lock);
927 return -EINVAL;
928 }
929
930 dest_id = svc->dest_id;
931 client_id = svc->client_id;
932 clnt = &client[dest_id][client_id];
933
934 if (svc->svc_cnt > 0) {
935 if (svc->port_cnt)
936 svc->port_cnt--;
937 svc->svc_cnt--;
938 if (!svc->svc_cnt) {
939 client[dest_id][client_id].svc_cnt--;
940 pr_debug("%s: service is reset %pK\n", __func__, svc);
941 }
942 }
943
944 if (!svc->svc_cnt) {
945 svc->priv = NULL;
946 svc->id = 0;
947 svc->fn = NULL;
948 svc->dest_id = 0;
949 svc->client_id = 0;
950 svc->need_reset = 0x0;
951 }
952 if (client[dest_id][client_id].handle &&
953 !client[dest_id][client_id].svc_cnt) {
954 apr_tal_close(client[dest_id][client_id].handle);
955 client[dest_id][client_id].handle = NULL;
956 }
957 mutex_unlock(&svc->m_lock);
958
959 return 0;
960}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530961EXPORT_SYMBOL(apr_deregister);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530962
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530963/**
964 * apr_reset - sets up workqueue to de-register
965 * the given APR service handle.
966 *
967 * @handle: APR service handle
968 *
969 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530970void apr_reset(void *handle)
971{
972 struct apr_reset_work *apr_reset_worker = NULL;
973
974 if (!handle)
975 return;
976 pr_debug("%s: handle[%pK]\n", __func__, handle);
977
978 if (apr_reset_workqueue == NULL) {
979 pr_err("%s: apr_reset_workqueue is NULL\n", __func__);
980 return;
981 }
982
983 apr_reset_worker = kzalloc(sizeof(struct apr_reset_work),
984 GFP_ATOMIC);
985
986 if (apr_reset_worker == NULL) {
987 pr_err("%s: mem failure\n", __func__);
988 return;
989 }
990
991 apr_reset_worker->handle = handle;
992 INIT_WORK(&apr_reset_worker->work, apr_reset_deregister);
993 queue_work(apr_reset_workqueue, &apr_reset_worker->work);
994}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530995EXPORT_SYMBOL(apr_reset);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530996
997/* Dispatch the Reset events to Modem and audio clients */
998static void dispatch_event(unsigned long code, uint16_t proc)
999{
1000 struct apr_client *apr_client;
1001 struct apr_client_data data;
1002 struct apr_svc *svc;
1003 uint16_t clnt;
1004 int i, j;
1005
Laxminath Kasam8f7ccc22017-08-28 17:35:04 +05301006 memset(&data, 0, sizeof(data));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301007 data.opcode = RESET_EVENTS;
1008 data.reset_event = code;
1009
1010 /* Service domain can be different from the processor */
1011 data.reset_proc = apr_get_reset_domain(proc);
1012
1013 clnt = APR_CLIENT_AUDIO;
1014 apr_client = &client[proc][clnt];
1015 for (i = 0; i < APR_SVC_MAX; i++) {
1016 mutex_lock(&apr_client->svc[i].m_lock);
1017 if (apr_client->svc[i].fn) {
1018 apr_client->svc[i].need_reset = 0x1;
1019 apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
1020 }
1021 if (apr_client->svc[i].port_cnt) {
1022 svc = &(apr_client->svc[i]);
1023 svc->need_reset = 0x1;
1024 for (j = 0; j < APR_MAX_PORTS; j++)
1025 if (svc->port_fn[j])
1026 svc->port_fn[j](&data,
1027 svc->port_priv[j]);
1028 }
1029 mutex_unlock(&apr_client->svc[i].m_lock);
1030 }
1031
1032 clnt = APR_CLIENT_VOICE;
1033 apr_client = &client[proc][clnt];
1034 for (i = 0; i < APR_SVC_MAX; i++) {
1035 mutex_lock(&apr_client->svc[i].m_lock);
1036 if (apr_client->svc[i].fn) {
1037 apr_client->svc[i].need_reset = 0x1;
1038 apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
1039 }
1040 if (apr_client->svc[i].port_cnt) {
1041 svc = &(apr_client->svc[i]);
1042 svc->need_reset = 0x1;
1043 for (j = 0; j < APR_MAX_PORTS; j++)
1044 if (svc->port_fn[j])
1045 svc->port_fn[j](&data,
1046 svc->port_priv[j]);
1047 }
1048 mutex_unlock(&apr_client->svc[i].m_lock);
1049 }
1050}
1051
1052static int apr_notifier_service_cb(struct notifier_block *this,
1053 unsigned long opcode, void *data)
1054{
1055 struct audio_notifier_cb_data *cb_data = data;
1056
1057 if (cb_data == NULL) {
1058 pr_err("%s: Callback data is NULL!\n", __func__);
1059 goto done;
1060 }
1061
1062 pr_debug("%s: Service opcode 0x%lx, domain %d\n",
1063 __func__, opcode, cb_data->domain);
1064
1065 switch (opcode) {
1066 case AUDIO_NOTIFIER_SERVICE_DOWN:
1067 /*
1068 * Use flag to ignore down notifications during
1069 * initial boot. There is no benefit from error
1070 * recovery notifications during initial boot
1071 * up since everything is expected to be down.
1072 */
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001073 spin_lock(&apr_priv->apr_lock);
1074 if (apr_priv->is_initial_boot) {
1075 spin_unlock(&apr_priv->apr_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301076 break;
1077 }
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001078 spin_unlock(&apr_priv->apr_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301079 if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN)
1080 apr_modem_down(opcode);
1081 else
1082 apr_adsp_down(opcode);
1083 break;
1084 case AUDIO_NOTIFIER_SERVICE_UP:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301085 if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN)
1086 apr_modem_up();
1087 else
1088 apr_adsp_up();
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001089 spin_lock(&apr_priv->apr_lock);
1090 apr_priv->is_initial_boot = false;
1091 spin_unlock(&apr_priv->apr_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301092 break;
1093 default:
1094 break;
1095 }
1096done:
1097 return NOTIFY_OK;
1098}
1099
1100static struct notifier_block adsp_service_nb = {
1101 .notifier_call = apr_notifier_service_cb,
1102 .priority = 0,
1103};
1104
1105static struct notifier_block modem_service_nb = {
1106 .notifier_call = apr_notifier_service_cb,
1107 .priority = 0,
1108};
1109
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301110#ifdef CONFIG_DEBUG_FS
1111static int __init apr_debug_init(void)
1112{
1113 debugfs_apr_debug = debugfs_create_file("msm_apr_debug",
1114 S_IFREG | 0444, NULL, NULL,
1115 &apr_debug_ops);
1116 return 0;
1117}
1118#else
1119static int __init apr_debug_init(void)
1120(
1121 return 0;
1122)
1123#endif
1124
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001125static void apr_cleanup(void)
1126{
1127 int i, j, k;
1128
Meng Wangeab9a2b2018-05-02 14:55:53 +08001129 of_platform_depopulate(apr_priv->dev);
Meng Wangf71f3502018-05-07 16:59:30 +08001130 subsys_notif_deregister(subsys_name);
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001131 if (apr_reset_workqueue) {
1132 flush_workqueue(apr_reset_workqueue);
1133 destroy_workqueue(apr_reset_workqueue);
1134 }
1135 mutex_destroy(&q6.lock);
1136 for (i = 0; i < APR_DEST_MAX; i++) {
1137 for (j = 0; j < APR_CLIENT_MAX; j++) {
1138 mutex_destroy(&client[i][j].m_lock);
1139 for (k = 0; k < APR_SVC_MAX; k++)
1140 mutex_destroy(&client[i][j].svc[k].m_lock);
1141 }
1142 }
Meng Wangeab9a2b2018-05-02 14:55:53 +08001143 debugfs_remove(debugfs_apr_debug);
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001144}
1145
1146static int apr_probe(struct platform_device *pdev)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301147{
Meng Wangf71f3502018-05-07 16:59:30 +08001148 int i, j, k, ret = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301149
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301150 init_waitqueue_head(&modem_wait);
1151
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001152 apr_priv = devm_kzalloc(&pdev->dev, sizeof(*apr_priv), GFP_KERNEL);
1153 if (!apr_priv)
1154 return -ENOMEM;
1155
1156 apr_priv->dev = &pdev->dev;
1157 spin_lock_init(&apr_priv->apr_lock);
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001158 INIT_WORK(&apr_priv->add_chld_dev_work, apr_add_child_devices);
1159
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301160 for (i = 0; i < APR_DEST_MAX; i++)
1161 for (j = 0; j < APR_CLIENT_MAX; j++) {
1162 mutex_init(&client[i][j].m_lock);
1163 for (k = 0; k < APR_SVC_MAX; k++) {
1164 mutex_init(&client[i][j].svc[k].m_lock);
1165 spin_lock_init(&client[i][j].svc[k].w_lock);
1166 }
1167 }
1168 apr_set_subsys_state();
1169 mutex_init(&q6.lock);
1170 apr_reset_workqueue = create_singlethread_workqueue("apr_driver");
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001171 if (!apr_reset_workqueue) {
1172 apr_priv = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301173 return -ENOMEM;
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001174 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301175
1176 apr_pkt_ctx = ipc_log_context_create(APR_PKT_IPC_LOG_PAGE_CNT,
1177 "apr", 0);
1178 if (!apr_pkt_ctx)
1179 pr_err("%s: Unable to create ipc log context\n", __func__);
1180
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001181 spin_lock(&apr_priv->apr_lock);
1182 apr_priv->is_initial_boot = true;
1183 spin_unlock(&apr_priv->apr_lock);
Meng Wangf71f3502018-05-07 16:59:30 +08001184 ret = of_property_read_string(pdev->dev.of_node,
1185 "qcom,subsys-name",
1186 (const char **)(&subsys_name));
1187 if (ret) {
1188 pr_err("%s: missing subsys-name entry in dt node\n", __func__);
1189 return -EINVAL;
1190 }
1191
1192 if (!strcmp(subsys_name, "apr_adsp")) {
1193 subsys_notif_register("apr_adsp",
1194 AUDIO_NOTIFIER_ADSP_DOMAIN,
1195 &adsp_service_nb);
1196 } else if (!strcmp(subsys_name, "apr_modem")) {
1197 subsys_notif_register("apr_modem",
1198 AUDIO_NOTIFIER_MODEM_DOMAIN,
1199 &modem_service_nb);
1200 } else {
1201 pr_err("%s: invalid subsys-name %s\n", __func__, subsys_name);
1202 return -EINVAL;
1203 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301204
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301205 apr_tal_init();
Banajit Goswami40bdd6b2018-07-20 19:24:54 -07001206
1207 ret = snd_event_client_register(&pdev->dev, &apr_ssr_ops, NULL);
1208 if (ret) {
Banajit Goswamic366b452018-08-22 17:53:25 -07001209 pr_err("%s: Registration with SND event fwk failed ret = %d\n",
Banajit Goswami40bdd6b2018-07-20 19:24:54 -07001210 __func__, ret);
1211 ret = 0;
1212 }
1213
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301214 return apr_debug_init();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301215}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301216
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001217static int apr_remove(struct platform_device *pdev)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301218{
Banajit Goswami40bdd6b2018-07-20 19:24:54 -07001219 snd_event_client_deregister(&pdev->dev);
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001220 apr_cleanup();
Shiv Maliyappanahalli72354822017-11-17 16:07:27 -08001221 apr_tal_exit();
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001222 apr_priv = NULL;
1223 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301224}
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001225
1226static const struct of_device_id apr_machine_of_match[] = {
1227 { .compatible = "qcom,msm-audio-apr", },
1228 {},
1229};
1230
1231static struct platform_driver apr_driver = {
1232 .probe = apr_probe,
1233 .remove = apr_remove,
1234 .driver = {
1235 .name = "audio_apr",
1236 .owner = THIS_MODULE,
1237 .of_match_table = apr_machine_of_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +08001238 .suppress_bind_attrs = true,
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001239 }
1240};
1241
1242module_platform_driver(apr_driver);
1243
1244MODULE_DESCRIPTION("APR DRIVER");
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301245MODULE_LICENSE("GPL v2");
Banajit Goswami3d99f7a2018-03-03 02:09:05 -08001246MODULE_DEVICE_TABLE(of, apr_machine_of_match);