blob: 7a40156d961f69d643c16e2e18a5485aa5afe9dd [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/qdsp5/audpp.c
2 *
3 * common code to deal with the AUDPP dsp task (audio postproc)
4 *
5 * Copyright (C) 2008 Google, Inc.
Duy Truong790f06d2013-02-13 16:38:12 -08006 * Copyright (c) 2009-2011, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/wait.h>
22#include <linux/delay.h>
23#include <linux/sched.h>
24#include <linux/platform_device.h>
25#include <linux/wakelock.h>
26
27
28#include <asm/atomic.h>
29#include <asm/ioctls.h>
30#include <mach/board.h>
31#include <mach/msm_adsp.h>
32#include <mach/qdsp5v2/audio_acdbi.h>
33#include <mach/qdsp5v2/qdsp5audppcmdi.h>
34#include <mach/qdsp5v2/qdsp5audppmsg.h>
35#include <mach/qdsp5v2/audpp.h>
36#include <mach/qdsp5v2/audio_dev_ctl.h>
37
38#include "../qdsp5/evlog.h"
39#include <mach/debug_mm.h>
40
41enum {
42 EV_NULL,
43 EV_ENABLE,
44 EV_DISABLE,
45 EV_EVENT,
46 EV_DATA,
47};
48
49static const char *dsp_log_strings[] = {
50 "NULL",
51 "ENABLE",
52 "DISABLE",
53 "EVENT",
54 "DATA",
55};
56
57DECLARE_LOG(dsp_log, 64, dsp_log_strings);
58
59static int __init _dsp_log_init(void)
60{
61 return ev_log_init(&dsp_log);
62}
63
64module_init(_dsp_log_init);
65#define LOG(id, arg) ev_log_write(&dsp_log, id, arg)
66
67static DEFINE_MUTEX(audpp_lock);
68static DEFINE_MUTEX(audpp_dec_lock);
69static struct wake_lock audpp_wake_lock;
70
71#define CH_COUNT 5
72#define AUDPP_CLNT_MAX_COUNT 6
73
74#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
75#define AUDPP_CMD_EQ_FLAG_DIS 0x0000
76#define AUDPP_CMD_EQ_FLAG_ENA -1
77#define AUDPP_CMD_IIR_FLAG_DIS 0x0000
78#define AUDPP_CMD_IIR_FLAG_ENA -1
79#define AUDPP_CMD_STF_FLAG_ENA -1
80#define AUDPP_CMD_STF_FLAG_DIS 0x0000
81
82#define MAX_EVENT_CALLBACK_CLIENTS 1
83
84#define AUDPP_CONCURRENCY_DEFAULT 0 /* Set default to LPA mode */
85#define AUDPP_MAX_DECODER_CNT 5
86#define AUDPP_CODEC_MASK 0x000000FF
87#define AUDPP_MODE_MASK 0x00000F00
88#define AUDPP_OP_MASK 0xF0000000
89
90struct audpp_decoder_info {
91 unsigned int codec;
92 pid_t pid;
93};
94
95struct audpp_state {
96 struct msm_adsp_module *mod;
97 audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
98 void *private[AUDPP_CLNT_MAX_COUNT];
99 struct mutex *lock;
100 unsigned open_count;
101 unsigned enabled;
102
103 /* Related to decoder allocation */
104 struct mutex *lock_dec;
105 struct msm_adspdec_database *dec_database;
106 struct audpp_decoder_info dec_info_table[AUDPP_MAX_DECODER_CNT];
107 unsigned dec_inuse;
108 unsigned long concurrency;
109
110 struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
111
112 /* Related to decoder instances */
113 uint8_t op_mode; /* Specifies Turbo/Non Turbo mode */
114 uint8_t decoder_count; /* No. of decoders active running */
115 uint8_t codec_max_instances; /* Max codecs allowed currently */
116 uint8_t codec_cnt[MSM_MAX_DEC_CNT]; /* Nr of each codec
117 type enabled */
118
119 wait_queue_head_t event_wait;
120};
121
122struct audpp_state the_audpp_state = {
123 .lock = &audpp_lock,
124 .lock_dec = &audpp_dec_lock,
125};
126
127static inline void prevent_suspend(void)
128{
129 wake_lock(&audpp_wake_lock);
130}
131static inline void allow_suspend(void)
132{
133 wake_unlock(&audpp_wake_lock);
134}
135
136int audpp_send_queue1(void *cmd, unsigned len)
137{
138 return msm_adsp_write(the_audpp_state.mod,
139 QDSP_uPAudPPCmd1Queue, cmd, len);
140}
141EXPORT_SYMBOL(audpp_send_queue1);
142
143int audpp_send_queue2(void *cmd, unsigned len)
144{
145 return msm_adsp_write(the_audpp_state.mod,
146 QDSP_uPAudPPCmd2Queue, cmd, len);
147}
148EXPORT_SYMBOL(audpp_send_queue2);
149
150int audpp_send_queue3(void *cmd, unsigned len)
151{
152 return msm_adsp_write(the_audpp_state.mod,
153 QDSP_uPAudPPCmd3Queue, cmd, len);
154}
155EXPORT_SYMBOL(audpp_send_queue3);
156
157static int audpp_dsp_config(int enable)
158{
159 struct audpp_cmd_cfg cmd;
160
161 cmd.cmd_id = AUDPP_CMD_CFG;
162 cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
163
164 return audpp_send_queue1(&cmd, sizeof(cmd));
165}
166
167void audpp_route_stream(unsigned short dec_id, unsigned short mixer_mask)
168{
169 struct audpp_cmd_cfg_dev_mixer_params mixer_params_cmd;
170
171 memset(&mixer_params_cmd, 0, sizeof(mixer_params_cmd));
172
173 mixer_params_cmd.cmd_id = AUDPP_CMD_CFG_DEV_MIXER;
174 mixer_params_cmd.stream_id = dec_id;
175 mixer_params_cmd.mixer_cmd = mixer_mask;
176 audpp_send_queue1(&mixer_params_cmd, sizeof(mixer_params_cmd));
177
178}
179EXPORT_SYMBOL(audpp_route_stream);
180
181int is_audpp_enable(void)
182{
183 struct audpp_state *audpp = &the_audpp_state;
184
185 return audpp->enabled;
186}
187EXPORT_SYMBOL(is_audpp_enable);
188
189int audpp_register_event_callback(struct audpp_event_callback *ecb)
190{
191 struct audpp_state *audpp = &the_audpp_state;
192 int i;
193
194 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
195 if (NULL == audpp->cb_tbl[i]) {
196 audpp->cb_tbl[i] = ecb;
197 return 0;
198 }
199 }
200 return -1;
201}
202EXPORT_SYMBOL(audpp_register_event_callback);
203
204
205int audpp_unregister_event_callback(struct audpp_event_callback *ecb)
206{
207 struct audpp_state *audpp = &the_audpp_state;
208 int i;
209
210 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
211 if (ecb == audpp->cb_tbl[i]) {
212 audpp->cb_tbl[i] = NULL;
213 return 0;
214 }
215 }
216 return -1;
217}
218EXPORT_SYMBOL(audpp_unregister_event_callback);
219
220static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
221 uint16_t *msg)
222{
223 unsigned n;
224 for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
225 if (audpp->func[n])
226 audpp->func[n] (audpp->private[n], id, msg);
227 }
228
229 for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
230 if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
231 audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private, id,
232 msg);
233}
234
235static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
236 unsigned id, uint16_t *msg)
237{
238 if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
239 audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
240}
241
242static void audpp_handle_pcmdmamiss(struct audpp_state *audpp,
243 uint16_t bit_mask)
244{
245 uint8_t b_index;
246
247 for (b_index = 0; b_index < AUDPP_CLNT_MAX_COUNT; b_index++) {
248 if (bit_mask & (0x1 << b_index))
249 if (audpp->func[b_index])
250 audpp->func[b_index] (audpp->private[b_index],
251 AUDPP_MSG_PCMDMAMISSED,
252 &bit_mask);
253 }
254}
255
256static void audpp_dsp_event(void *data, unsigned id, size_t len,
257 void (*getevent) (void *ptr, size_t len))
258{
259 struct audpp_state *audpp = data;
260 uint16_t msg[8];
261
262 getevent(msg, sizeof(msg));
263
264 LOG(EV_EVENT, (id << 16) | msg[0]);
265 LOG(EV_DATA, (msg[1] << 16) | msg[2]);
266
267 switch (id) {
268 case AUDPP_MSG_STATUS_MSG:{
269 unsigned cid = msg[0];
270 MM_DBG("status %d %d %d\n", cid, msg[1], msg[2]);
271
272 if ((cid < 5) && audpp->func[cid])
273 audpp->func[cid] (audpp->private[cid], id, msg);
274 break;
275 }
276 case AUDPP_MSG_HOST_PCM_INTF_MSG:
277 if (audpp->func[5])
278 audpp->func[5] (audpp->private[5], id, msg);
279 break;
280 case AUDPP_MSG_PCMDMAMISSED:
281 audpp_handle_pcmdmamiss(audpp, msg[0]);
282 break;
283 case AUDPP_MSG_CFG_MSG:
284 if (msg[0] == AUDPP_MSG_ENA_ENA) {
285 MM_INFO("ENABLE\n");
286 audpp->enabled = 1;
287 audpp_broadcast(audpp, id, msg);
288 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
289 MM_INFO("DISABLE\n");
290 audpp->enabled = 0;
291 wake_up(&audpp->event_wait);
292 audpp_broadcast(audpp, id, msg);
293 } else {
294 MM_ERR("invalid config msg %d\n", msg[0]);
295 }
296 break;
297 case AUDPP_MSG_ROUTING_ACK:
298 audpp_notify_clnt(audpp, msg[0], id, msg);
299 break;
300 case AUDPP_MSG_FLUSH_ACK:
301 audpp_notify_clnt(audpp, msg[0], id, msg);
302 break;
303 case ADSP_MESSAGE_ID:
304 MM_DBG("Received ADSP event: module enable/disable \
305 (audpptask)");
306 break;
307 case AUDPP_MSG_AVSYNC_MSG:
308 audpp_notify_clnt(audpp, msg[0], id, msg);
309 break;
310#ifdef CONFIG_DEBUG_FS
311 case AUDPP_MSG_FEAT_QUERY_DM_DONE:
312 MM_INFO(" RTC ACK --> %x %x %x %x %x %x %x %x\n", msg[0],\
313 msg[1], msg[2], msg[3], msg[4], \
314 msg[5], msg[6], msg[7]);
315 acdb_rtc_set_err(msg[3]);
316 break;
317#endif
318 default:
319 MM_INFO("unhandled msg id %x\n", id);
320 }
321}
322
323static struct msm_adsp_ops adsp_ops = {
324 .event = audpp_dsp_event,
325};
326
327static void audpp_fake_event(struct audpp_state *audpp, int id,
328 unsigned event, unsigned arg)
329{
330 uint16_t msg[1];
Santosh Mardie9185852011-09-08 10:38:31 +0530331 uint16_t n = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 msg[0] = arg;
333 audpp->func[id] (audpp->private[id], event, msg);
Santosh Mardie9185852011-09-08 10:38:31 +0530334 if (audpp->enabled == 1) {
335 for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
336 if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
337 audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private,
338 AUDPP_MSG_CFG_MSG, msg);
339 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340}
341
342int audpp_enable(int id, audpp_event_func func, void *private)
343{
344 struct audpp_state *audpp = &the_audpp_state;
345 int res = 0;
346
347 if (id < -1 || id > 4)
348 return -EINVAL;
349
350 if (id == -1)
351 id = 5;
352
353 mutex_lock(audpp->lock);
354 if (audpp->func[id]) {
355 res = -EBUSY;
356 goto out;
357 }
358
359 audpp->func[id] = func;
360 audpp->private[id] = private;
361
362 LOG(EV_ENABLE, 1);
363 if (audpp->open_count++ == 0) {
364 MM_DBG("enable\n");
365 res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
366 if (res < 0) {
367 MM_ERR("audpp: cannot open AUDPPTASK\n");
368 audpp->open_count = 0;
369 audpp->func[id] = NULL;
370 audpp->private[id] = NULL;
371 goto out;
372 }
373 LOG(EV_ENABLE, 2);
374 prevent_suspend();
375 msm_adsp_enable(audpp->mod);
376 audpp_dsp_config(1);
377 } else {
378 unsigned long flags;
379 local_irq_save(flags);
380 if (audpp->enabled)
381 audpp_fake_event(audpp, id,
382 AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
383 local_irq_restore(flags);
384 }
385
386 res = 0;
387out:
388 mutex_unlock(audpp->lock);
389 return res;
390}
391EXPORT_SYMBOL(audpp_enable);
392
393void audpp_disable(int id, void *private)
394{
395 struct audpp_state *audpp = &the_audpp_state;
396 unsigned long flags;
397 int rc;
398
399 if (id < -1 || id > 4)
400 return;
401
402 if (id == -1)
403 id = 5;
404
405 mutex_lock(audpp->lock);
406 LOG(EV_DISABLE, 1);
407 if (!audpp->func[id])
408 goto out;
409 if (audpp->private[id] != private)
410 goto out;
411
412 local_irq_save(flags);
413 audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS);
414 audpp->func[id] = NULL;
415 audpp->private[id] = NULL;
416 local_irq_restore(flags);
417
418 if (--audpp->open_count == 0) {
419 MM_DBG("disable\n");
420 LOG(EV_DISABLE, 2);
421 audpp_dsp_config(0);
422 rc = wait_event_interruptible(audpp->event_wait,
423 (audpp->enabled == 0));
424 if (audpp->enabled == 0)
425 MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
426 else
427 MM_ERR("Didn't receive CFG_MSG DISABLE \
428 message from ADSP\n");
429 msm_adsp_disable(audpp->mod);
430 msm_adsp_put(audpp->mod);
431 audpp->mod = NULL;
432 allow_suspend();
433 }
434out:
435 mutex_unlock(audpp->lock);
436}
437EXPORT_SYMBOL(audpp_disable);
438
439#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
440
441int audpp_restore_avsync(int id, uint16_t *avsync)
442{
443 struct audpp_cmd_avsync cmd;
444
445 if (BAD_ID(id))
446 return -1;
447
448 memset(&cmd, 0, sizeof(cmd));
449 cmd.cmd_id = AUDPP_CMD_AVSYNC;
450 cmd.stream_id = id;
451 cmd.interrupt_interval = 0; /* Setting it to Zero as there won't be
452 periodic update */
453 cmd.sample_counter_dlsw = avsync[3];
454 cmd.sample_counter_dmsw = avsync[2];
455 cmd.sample_counter_msw = avsync[1];
456 cmd.byte_counter_dlsw = avsync[6];
457 cmd.byte_counter_dmsw = avsync[5];
458 cmd.byte_counter_msw = avsync[4];
459
460 return audpp_send_queue1(&cmd, sizeof(cmd));
461}
462EXPORT_SYMBOL(audpp_restore_avsync);
463
464int audpp_query_avsync(int id)
465{
466 struct audpp_cmd_query_avsync cmd;
467
468 if (BAD_ID(id))
469 return -EINVAL;
470
471 memset(&cmd, 0, sizeof(cmd));
472 cmd.cmd_id = AUDPP_CMD_QUERY_AVSYNC;
473 cmd.stream_id = id;
474 return audpp_send_queue1(&cmd, sizeof(cmd));
475
476}
477EXPORT_SYMBOL(audpp_query_avsync);
478
479int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan,
480 enum obj_type objtype)
481{
482 /* cmd, obj_cfg[7], cmd_type, volume, pan */
483 uint16_t cmd[7];
484
485 if (objtype) {
486 if (id > 5) {
487 MM_ERR("Wrong POPP decoder id: %d\n", id);
488 return -EINVAL;
489 }
490 } else {
491 if (id > 3) {
492 MM_ERR("Wrong COPP decoder id: %d\n", id);
493 return -EINVAL;
494 }
495 }
496
497 memset(cmd, 0, sizeof(cmd));
498 cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
499 if (objtype)
500 cmd[1] = AUDPP_CMD_POPP_STREAM;
501 else
502 cmd[1] = AUDPP_CMD_COPP_STREAM;
503 cmd[2] = id;
504 cmd[3] = AUDPP_CMD_CFG_OBJ_UPDATE;
505 cmd[4] = AUDPP_CMD_VOLUME_PAN;
506 cmd[5] = volume;
507 cmd[6] = pan;
508
509 return audpp_send_queue3(cmd, sizeof(cmd));
510}
511EXPORT_SYMBOL(audpp_set_volume_and_pan);
512
513/* Implementation of COPP features */
514int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
515 struct audpp_cmd_cfg_object_params_mbadrc *mbadrc,
516 enum obj_type objtype)
517{
518 if (objtype) {
519 if (id > 5) {
520 MM_ERR("Wrong POPP decoder id: %d\n", id);
521 return -EINVAL;
522 }
523 } else {
524 if (id > 3) {
525 MM_ERR("Wrong COPP decoder id: %d\n", id);
526 return -EINVAL;
527 }
528 }
529
530 mbadrc->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
531 if (objtype)
532 mbadrc->common.stream = AUDPP_CMD_POPP_STREAM;
533 else
534 mbadrc->common.stream = AUDPP_CMD_COPP_STREAM;
535
536 mbadrc->common.stream_id = id;
537 mbadrc->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
538 mbadrc->common.command_type = AUDPP_CMD_MBADRC;
539
540 if (enable)
541 mbadrc->enable = AUDPP_CMD_ADRC_FLAG_ENA;
542 else
543 mbadrc->enable = AUDPP_CMD_ADRC_FLAG_DIS;
544
545 return audpp_send_queue3(mbadrc,
546 sizeof(struct audpp_cmd_cfg_object_params_mbadrc));
547}
548EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
549
550int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
551 struct audpp_cmd_cfg_object_params_qconcert *qconcert_plus,
552 enum obj_type objtype)
553{
554 if (objtype) {
555 if (id > 5) {
556 MM_ERR("Wrong POPP decoder id: %d\n", id);
557 return -EINVAL;
558 }
559 } else {
560 if (id > 3) {
561 MM_ERR("Wrong COPP decoder id: %d\n", id);
562 return -EINVAL;
563 }
564 }
565
566 qconcert_plus->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
567 if (objtype)
568 qconcert_plus->common.stream = AUDPP_CMD_POPP_STREAM;
569 else
570 qconcert_plus->common.stream = AUDPP_CMD_COPP_STREAM;
571
572 qconcert_plus->common.stream_id = id;
573 qconcert_plus->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
574 qconcert_plus->common.command_type = AUDPP_CMD_QCONCERT;
575
576 if (enable)
577 qconcert_plus->enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
578 else
579 qconcert_plus->enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
580
581 return audpp_send_queue3(qconcert_plus,
582 sizeof(struct audpp_cmd_cfg_object_params_qconcert));
583}
584EXPORT_SYMBOL(audpp_dsp_set_qconcert_plus);
585
586int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
587 struct audpp_cmd_cfg_object_params_pcm *iir,
588 enum obj_type objtype)
589{
590
591 if (objtype) {
592 if (id > 5) {
593 MM_ERR("Wrong POPP decoder id: %d\n", id);
594 return -EINVAL;
595 }
596 } else {
597 if (id > 3) {
598 MM_ERR("Wrong COPP decoder id: %d\n", id);
599 return -EINVAL;
600 }
601 }
602
603 iir->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
604 if (objtype)
605 iir->common.stream = AUDPP_CMD_POPP_STREAM;
606 else
607 iir->common.stream = AUDPP_CMD_COPP_STREAM;
608
609 iir->common.stream_id = id;
610 iir->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
611 iir->common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
612
613 if (enable)
614 iir->active_flag = AUDPP_CMD_IIR_FLAG_ENA;
615 else
616 iir->active_flag = AUDPP_CMD_IIR_FLAG_DIS;
617
618 return audpp_send_queue3(iir,
619 sizeof(struct audpp_cmd_cfg_object_params_pcm));
620}
621EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
622
623int audpp_dsp_set_gain_rx(unsigned id,
624 struct audpp_cmd_cfg_cal_gain *calib_gain_rx,
625 enum obj_type objtype)
626{
627 if (objtype) {
628 return -EINVAL;
629 } else {
630 if (id > 3) {
631 MM_ERR("Wrong COPP decoder id: %d\n", id);
632 return -EINVAL;
633 }
634 }
635 calib_gain_rx->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
636 calib_gain_rx->common.stream = AUDPP_CMD_COPP_STREAM;
637
638 calib_gain_rx->common.stream_id = id;
639 calib_gain_rx->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
640 calib_gain_rx->common.command_type = AUDPP_CMD_CALIB_GAIN_RX;
641
642 return audpp_send_queue3(calib_gain_rx,
643 sizeof(struct audpp_cmd_cfg_cal_gain));
644}
645EXPORT_SYMBOL(audpp_dsp_set_gain_rx);
646
647int audpp_dsp_set_pbe(unsigned id, unsigned enable,
648 struct audpp_cmd_cfg_pbe *pbe_block,
649 enum obj_type objtype)
650{
651 if (objtype) {
652 if (id > 5) {
653 MM_ERR("Wrong POPP decoder id: %d\n", id);
654 return -EINVAL;
655 }
656 } else {
657 if (id > 3) {
658 MM_ERR("Wrong COPP decoder id: %d\n", id);
659 return -EINVAL;
660 }
661 }
662
663 pbe_block->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
664 if (objtype)
665 pbe_block->common.stream = AUDPP_CMD_POPP_STREAM;
666 else
667 pbe_block->common.stream = AUDPP_CMD_COPP_STREAM;
668
669 pbe_block->common.stream_id = id;
670 pbe_block->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
671 pbe_block->common.command_type = AUDPP_CMD_PBE;
672
673 if (enable)
674 pbe_block->pbe_enable = AUDPP_CMD_PBE_FLAG_ENA;
675 else
676 pbe_block->pbe_enable = AUDPP_CMD_PBE_FLAG_DIS;
677
678 return audpp_send_queue3(pbe_block,
679 sizeof(struct audpp_cmd_cfg_pbe));
680}
681EXPORT_SYMBOL(audpp_dsp_set_pbe);
682
683int audpp_dsp_set_spa(unsigned id,
684 struct audpp_cmd_cfg_object_params_spectram *spa,
685 enum obj_type objtype){
686 struct audpp_cmd_cfg_object_params_spectram cmd;
687
688 if (objtype) {
689 if (id > 5) {
690 MM_ERR("Wrong POPP decoder id: %d\n", id);
691 return -EINVAL;
692 }
693 } else {
694 if (id > 3) {
695 MM_ERR("Wrong COPP decoder id: %d\n", id);
696 return -EINVAL;
697 }
698 }
699
700 memset(&cmd, 0, sizeof(cmd));
701 if (objtype)
702 cmd.common.stream = AUDPP_CMD_POPP_STREAM;
703 else
704 cmd.common.stream = AUDPP_CMD_COPP_STREAM;
705
706 cmd.common.stream_id = id;
707 cmd.common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
708 cmd.common.command_type = AUDPP_CMD_SPECTROGRAM;
709 cmd.sample_interval = spa->sample_interval;
710 cmd.num_coeff = spa->num_coeff;
711 return audpp_send_queue3(&cmd, sizeof(cmd));
712
713}
714EXPORT_SYMBOL(audpp_dsp_set_spa);
715
716int audpp_dsp_set_stf(unsigned id, unsigned enable,
717 struct audpp_cmd_cfg_object_params_sidechain *stf,
718 enum obj_type objtype){
719 if (objtype) {
720 if (id > 5) {
721 MM_ERR("Wrong POPP decoder id: %d\n", id);
722 return -EINVAL;
723 }
724 } else {
725 if (id > 3) {
726 MM_ERR("Wrong COPP decoder id: %d\n", id);
727 return -EINVAL;
728 }
729 }
730
731 stf->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
732 if (objtype)
733 stf->common.stream = AUDPP_CMD_POPP_STREAM;
734 else
735 stf->common.stream = AUDPP_CMD_COPP_STREAM;
736
737 stf->common.stream_id = id;
738 stf->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
739 stf->common.command_type = AUDPP_CMD_SIDECHAIN_TUNING_FILTER;
740
741 if (enable)
742 stf->active_flag = AUDPP_CMD_STF_FLAG_ENA;
743 else
744 stf->active_flag = AUDPP_CMD_STF_FLAG_DIS;
745 return audpp_send_queue3(stf,
746 sizeof(struct audpp_cmd_cfg_object_params_sidechain));
747}
748EXPORT_SYMBOL(audpp_dsp_set_stf);
749
750/* Implementation Of COPP + POPP */
751int audpp_dsp_set_eq(unsigned id, unsigned enable,
752 struct audpp_cmd_cfg_object_params_eqalizer *eq,
753 enum obj_type objtype)
754{
755 struct audpp_cmd_cfg_object_params_eqalizer cmd;
756
757 if (objtype) {
758 if (id > 5) {
759 MM_ERR("Wrong POPP decoder id: %d\n", id);
760 return -EINVAL;
761 }
762 } else {
763 if (id > 3) {
764 MM_ERR("Wrong COPP decoder id: %d\n", id);
765 return -EINVAL;
766 }
767 }
768
769 memset(&cmd, 0, sizeof(cmd));
770 if (objtype)
771 cmd.common.stream = AUDPP_CMD_POPP_STREAM;
772 else
773 cmd.common.stream = AUDPP_CMD_COPP_STREAM;
774
775 cmd.common.stream_id = id;
776 cmd.common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
777 cmd.common.command_type = AUDPP_CMD_EQUALIZER;
778 if (enable) {
779 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
780 cmd.num_bands = eq->num_bands;
781 memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
782 } else
783 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
784
785 return audpp_send_queue3(&cmd, sizeof(cmd));
786}
787EXPORT_SYMBOL(audpp_dsp_set_eq);
788
789int audpp_dsp_set_vol_pan(unsigned id,
790 struct audpp_cmd_cfg_object_params_volume *vol_pan,
791 enum obj_type objtype)
792{
793 struct audpp_cmd_cfg_object_params_volume cmd;
794
795 if (objtype) {
796 if (id > 5) {
797 MM_ERR("Wrong POPP decoder id: %d\n", id);
798 return -EINVAL;
799 }
800 } else {
801 if (id > AUDPP_MAX_COPP_DEVICES) {
802 MM_ERR("Wrong COPP decoder id: %d\n", id);
803 return -EINVAL;
804 }
805 }
806
807 memset(&cmd, 0, sizeof(cmd));
808 cmd.common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
809 if (objtype)
810 cmd.common.stream = AUDPP_CMD_POPP_STREAM;
811 else
812 cmd.common.stream = AUDPP_CMD_COPP_STREAM;
813
814 cmd.common.stream_id = id;
815 cmd.common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
816 cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
817
818 cmd.volume = vol_pan->volume;
819 cmd.pan = vol_pan->pan;
820
821 return audpp_send_queue3(&cmd, sizeof(cmd));
822}
823EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
824
825int audpp_pause(unsigned id, int pause)
826{
827 /* pause 1 = pause 0 = resume */
828 u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
829
830 if (id >= CH_COUNT)
831 return -EINVAL;
832
833 memset(pause_cmd, 0, sizeof(pause_cmd));
834
835 pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
836 pause_cmd[1] = id;
837 if (pause == 1)
838 pause_cmd[2] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
839 else if (pause == 0)
840 pause_cmd[2] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
841 else
842 return -EINVAL;
843
844 return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
845}
846EXPORT_SYMBOL(audpp_pause);
847
848int audpp_flush(unsigned id)
849{
850 u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
851
852 if (id >= CH_COUNT)
853 return -EINVAL;
854
855 memset(flush_cmd, 0, sizeof(flush_cmd));
856
857 flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
858 flush_cmd[1] = id;
859 flush_cmd[2] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
860
861 return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
862}
863EXPORT_SYMBOL(audpp_flush);
864
865/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
866 * like mp3, aac, wma etc ... *
867 * = 15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
868 * = 31:16, reserved */
869int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
870 unsigned *queueid)
871{
872 struct audpp_state *audpp = &the_audpp_state;
873 int decid = -1, idx, lidx, mode, codec;
874 int codecs_supported, min_codecs_supported;
875 unsigned int *concurrency_entry;
876 u8 max_instance, codec_type;
877
878 struct dec_instance_table *dec_instance_list;
879 dec_instance_list = (struct dec_instance_table *)
880 (audpp->dec_database->dec_instance_list);
881
882 mutex_lock(audpp->lock_dec);
883 /* Represents in bit mask */
884 mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
885 codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
886 codec_type = (dec_attrb & AUDPP_CODEC_MASK);
887
888 /* Find whether same/different codec instances are running */
889 audpp->decoder_count++;
890 audpp->codec_cnt[codec_type]++;
891 max_instance = 0;
892
893 /*if different instance of codec*/
894 if (audpp->codec_cnt[codec_type] < audpp->decoder_count) {
895 max_instance = audpp->codec_max_instances;
896 /* Get the maximum no. of instances that can be supported */
897 for (idx = 0; idx < MSM_MAX_DEC_CNT; idx++) {
898 if (audpp->codec_cnt[idx]) {
899 if ((dec_instance_list +
900 audpp->op_mode * MSM_MAX_DEC_CNT +
901 idx)->
902 max_instances_diff_dec <
903 max_instance) {
904 max_instance =
905 (dec_instance_list +
906 audpp->op_mode *
907 MSM_MAX_DEC_CNT
908 + idx)->
909 max_instances_diff_dec;
910 }
911 }
912 }
913 /* if different codec type, should not cross maximum other
914 supported */
915 if (audpp->decoder_count > (max_instance + 1)) {
916 MM_ERR("Can not support, already reached max\n");
917 audpp->decoder_count--;
918 audpp->codec_cnt[codec_type]--;
919 goto done;
920 }
921 audpp->codec_max_instances = max_instance;
922 MM_DBG("different codec running\n");
923 } else {
924 max_instance = (dec_instance_list + audpp->op_mode *
925 MSM_MAX_DEC_CNT +
926 codec_type)->
927 max_instances_same_dec;
928 /* if same codec type, should not cross maximum supported */
929 if (audpp->decoder_count > max_instance) {
930 MM_ERR("Can not support, already reached max\n");
931 audpp->decoder_count--;
932 audpp->codec_cnt[codec_type]--;
933 goto done;
934 }
935 audpp->codec_max_instances = max_instance;
936 MM_DBG("same codec running\n");
937 }
938
939 /* Point to Last entry of the row */
940 concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
941 ((audpp->concurrency + 1) *
942 (audpp->dec_database->num_dec))) - 1);
943
944 lidx = audpp->dec_database->num_dec;
945 min_codecs_supported = sizeof(unsigned int) * 8;
946
947 MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
948
949 for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
950 if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
951 if (((mode & *concurrency_entry) == mode) &&
952 (codec & *concurrency_entry)) {
953 /* Check supports minimum number codecs */
954 codecs_supported =
955 audpp->dec_database->dec_info_list[idx -
956 1].
957 nr_codec_support;
958 if (codecs_supported < min_codecs_supported) {
959 lidx = idx - 1;
960 min_codecs_supported = codecs_supported;
961 }
962 }
963 }
964 }
965
966 if (lidx < audpp->dec_database->num_dec) {
967 audpp->dec_inuse |= (1 << lidx);
968 *module_name =
969 audpp->dec_database->dec_info_list[lidx].module_name;
970 *queueid =
971 audpp->dec_database->dec_info_list[lidx].module_queueid;
972 decid = audpp->dec_database->dec_info_list[lidx].module_decid;
973 audpp->dec_info_table[lidx].codec =
974 (dec_attrb & AUDPP_CODEC_MASK);
975 audpp->dec_info_table[lidx].pid = current->pid;
976 /* point to row to get supported operation */
977 concurrency_entry =
978 ((audpp->dec_database->dec_concurrency_table +
979 ((audpp->concurrency) * (audpp->dec_database->num_dec))) +
980 lidx);
981 decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
982 MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n", decid,
983 *module_name, *queueid);
984 }
985done:
986 mutex_unlock(audpp->lock_dec);
987 return decid;
988
989}
990EXPORT_SYMBOL(audpp_adec_alloc);
991
992void audpp_adec_free(int decid)
993{
994 struct audpp_state *audpp = &the_audpp_state;
995 int idx;
996 mutex_lock(audpp->lock_dec);
997 for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
998 if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
999 decid) {
1000 audpp->decoder_count--;
1001 audpp->\
1002 codec_cnt[audpp->dec_info_table[idx - 1].codec]--;
1003 audpp->dec_inuse &= ~(1 << (idx - 1));
1004 audpp->dec_info_table[idx - 1].codec = -1;
1005 audpp->dec_info_table[idx - 1].pid = 0;
1006 MM_INFO("free decid =%d \n", decid);
1007 break;
1008 }
1009 }
1010 mutex_unlock(audpp->lock_dec);
1011 return;
1012
1013}
1014EXPORT_SYMBOL(audpp_adec_free);
1015
1016static ssize_t concurrency_show(struct device *dev,
1017 struct device_attribute *attr, char *buf)
1018{
1019 struct audpp_state *audpp = &the_audpp_state;
1020 int rc;
1021 mutex_lock(audpp->lock_dec);
1022 rc = sprintf(buf, "%ld\n", audpp->concurrency);
1023 mutex_unlock(audpp->lock_dec);
1024 return rc;
1025}
1026
1027static ssize_t concurrency_store(struct device *dev,
1028 struct device_attribute *attr,
1029 const char *buf, size_t count)
1030{
1031 struct audpp_state *audpp = &the_audpp_state;
1032 unsigned long concurrency;
1033 int rc = -1;
1034 mutex_lock(audpp->lock_dec);
1035 if (audpp->dec_inuse) {
1036 MM_ERR("Can not change profile, while playback in progress\n");
1037 goto done;
1038 }
1039 rc = strict_strtoul(buf, 10, &concurrency);
1040 if (!rc &&
1041 (concurrency < audpp->dec_database->num_concurrency_support)) {
1042 audpp->concurrency = concurrency;
1043 MM_DBG("Concurrency case %ld\n", audpp->concurrency);
1044 rc = count;
1045 } else {
1046 MM_ERR("Not a valid Concurrency case\n");
1047 rc = -EINVAL;
1048 }
1049done:
1050 mutex_unlock(audpp->lock_dec);
1051 return rc;
1052}
1053
1054static ssize_t decoder_info_show(struct device *dev,
1055 struct device_attribute *attr, char *buf);
1056static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
1057 __ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
1058 __ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
1059 __ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
1060 __ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
1061 __ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
1062};
1063
1064static ssize_t decoder_info_show(struct device *dev,
1065 struct device_attribute *attr, char *buf)
1066{
1067 int cpy_sz = 0;
1068 struct audpp_state *audpp = &the_audpp_state;
1069 const ptrdiff_t off = attr - dev_attr_decoder; /* decoder number */
1070 mutex_lock(audpp->lock_dec);
1071 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
1072 audpp->dec_info_table[off].codec);
1073 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
1074 audpp->dec_info_table[off].pid);
1075 mutex_unlock(audpp->lock_dec);
1076 return cpy_sz;
1077}
1078
1079static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
1080 concurrency_store);
1081static int audpp_probe(struct platform_device *pdev)
1082{
1083 int rc, idx;
1084 struct audpp_state *audpp = &the_audpp_state;
1085 audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
1086 audpp->dec_database =
1087 (struct msm_adspdec_database *)pdev->dev.platform_data;
1088
1089 MM_INFO("Number of decoder supported %d\n",
1090 audpp->dec_database->num_dec);
1091 MM_INFO("Number of concurrency supported %d\n",
1092 audpp->dec_database->num_concurrency_support);
1093 init_waitqueue_head(&audpp->event_wait);
1094 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
1095 audpp->dec_info_table[idx].codec = -1;
1096 audpp->dec_info_table[idx].pid = 0;
1097 MM_INFO("module_name:%s\n",
1098 audpp->dec_database->dec_info_list[idx].module_name);
1099 MM_INFO("queueid:%d\n",
1100 audpp->dec_database->dec_info_list[idx].module_queueid);
1101 MM_INFO("decid:%d\n",
1102 audpp->dec_database->dec_info_list[idx].module_decid);
1103 MM_INFO("nr_codec_support:%d\n",
1104 audpp->dec_database->dec_info_list[idx].
1105 nr_codec_support);
1106 }
1107
1108 wake_lock_init(&audpp_wake_lock, WAKE_LOCK_SUSPEND, "audpp");
1109 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
1110 rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
1111 if (rc)
1112 goto err;
1113 }
1114 rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
1115 audpp->op_mode = 0; /* Consider as non turbo mode */
1116 if (rc)
1117 goto err;
1118 else
1119 goto done;
1120err:
1121 while (idx--)
1122 device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
1123done:
1124 return rc;
1125}
1126
1127static struct platform_driver audpp_plat_driver = {
1128 .probe = audpp_probe,
1129 .driver = {
1130 .name = "msm_adspdec",
1131 .owner = THIS_MODULE,
1132 },
1133};
1134
1135static int __init audpp_init(void)
1136{
1137 return platform_driver_register(&audpp_plat_driver);
1138}
1139
1140device_initcall(audpp_init);