blob: be274c7fcb407bbddcb1af4461ae8e6150d3b97c [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.
6 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
7 *
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];
331 msg[0] = arg;
332 audpp->func[id] (audpp->private[id], event, msg);
333}
334
335int audpp_enable(int id, audpp_event_func func, void *private)
336{
337 struct audpp_state *audpp = &the_audpp_state;
338 int res = 0;
339
340 if (id < -1 || id > 4)
341 return -EINVAL;
342
343 if (id == -1)
344 id = 5;
345
346 mutex_lock(audpp->lock);
347 if (audpp->func[id]) {
348 res = -EBUSY;
349 goto out;
350 }
351
352 audpp->func[id] = func;
353 audpp->private[id] = private;
354
355 LOG(EV_ENABLE, 1);
356 if (audpp->open_count++ == 0) {
357 MM_DBG("enable\n");
358 res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
359 if (res < 0) {
360 MM_ERR("audpp: cannot open AUDPPTASK\n");
361 audpp->open_count = 0;
362 audpp->func[id] = NULL;
363 audpp->private[id] = NULL;
364 goto out;
365 }
366 LOG(EV_ENABLE, 2);
367 prevent_suspend();
368 msm_adsp_enable(audpp->mod);
369 audpp_dsp_config(1);
370 } else {
371 unsigned long flags;
372 local_irq_save(flags);
373 if (audpp->enabled)
374 audpp_fake_event(audpp, id,
375 AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
376 local_irq_restore(flags);
377 }
378
379 res = 0;
380out:
381 mutex_unlock(audpp->lock);
382 return res;
383}
384EXPORT_SYMBOL(audpp_enable);
385
386void audpp_disable(int id, void *private)
387{
388 struct audpp_state *audpp = &the_audpp_state;
389 unsigned long flags;
390 int rc;
391
392 if (id < -1 || id > 4)
393 return;
394
395 if (id == -1)
396 id = 5;
397
398 mutex_lock(audpp->lock);
399 LOG(EV_DISABLE, 1);
400 if (!audpp->func[id])
401 goto out;
402 if (audpp->private[id] != private)
403 goto out;
404
405 local_irq_save(flags);
406 audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS);
407 audpp->func[id] = NULL;
408 audpp->private[id] = NULL;
409 local_irq_restore(flags);
410
411 if (--audpp->open_count == 0) {
412 MM_DBG("disable\n");
413 LOG(EV_DISABLE, 2);
414 audpp_dsp_config(0);
415 rc = wait_event_interruptible(audpp->event_wait,
416 (audpp->enabled == 0));
417 if (audpp->enabled == 0)
418 MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
419 else
420 MM_ERR("Didn't receive CFG_MSG DISABLE \
421 message from ADSP\n");
422 msm_adsp_disable(audpp->mod);
423 msm_adsp_put(audpp->mod);
424 audpp->mod = NULL;
425 allow_suspend();
426 }
427out:
428 mutex_unlock(audpp->lock);
429}
430EXPORT_SYMBOL(audpp_disable);
431
432#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
433
434int audpp_restore_avsync(int id, uint16_t *avsync)
435{
436 struct audpp_cmd_avsync cmd;
437
438 if (BAD_ID(id))
439 return -1;
440
441 memset(&cmd, 0, sizeof(cmd));
442 cmd.cmd_id = AUDPP_CMD_AVSYNC;
443 cmd.stream_id = id;
444 cmd.interrupt_interval = 0; /* Setting it to Zero as there won't be
445 periodic update */
446 cmd.sample_counter_dlsw = avsync[3];
447 cmd.sample_counter_dmsw = avsync[2];
448 cmd.sample_counter_msw = avsync[1];
449 cmd.byte_counter_dlsw = avsync[6];
450 cmd.byte_counter_dmsw = avsync[5];
451 cmd.byte_counter_msw = avsync[4];
452
453 return audpp_send_queue1(&cmd, sizeof(cmd));
454}
455EXPORT_SYMBOL(audpp_restore_avsync);
456
457int audpp_query_avsync(int id)
458{
459 struct audpp_cmd_query_avsync cmd;
460
461 if (BAD_ID(id))
462 return -EINVAL;
463
464 memset(&cmd, 0, sizeof(cmd));
465 cmd.cmd_id = AUDPP_CMD_QUERY_AVSYNC;
466 cmd.stream_id = id;
467 return audpp_send_queue1(&cmd, sizeof(cmd));
468
469}
470EXPORT_SYMBOL(audpp_query_avsync);
471
472int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan,
473 enum obj_type objtype)
474{
475 /* cmd, obj_cfg[7], cmd_type, volume, pan */
476 uint16_t cmd[7];
477
478 if (objtype) {
479 if (id > 5) {
480 MM_ERR("Wrong POPP decoder id: %d\n", id);
481 return -EINVAL;
482 }
483 } else {
484 if (id > 3) {
485 MM_ERR("Wrong COPP decoder id: %d\n", id);
486 return -EINVAL;
487 }
488 }
489
490 memset(cmd, 0, sizeof(cmd));
491 cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
492 if (objtype)
493 cmd[1] = AUDPP_CMD_POPP_STREAM;
494 else
495 cmd[1] = AUDPP_CMD_COPP_STREAM;
496 cmd[2] = id;
497 cmd[3] = AUDPP_CMD_CFG_OBJ_UPDATE;
498 cmd[4] = AUDPP_CMD_VOLUME_PAN;
499 cmd[5] = volume;
500 cmd[6] = pan;
501
502 return audpp_send_queue3(cmd, sizeof(cmd));
503}
504EXPORT_SYMBOL(audpp_set_volume_and_pan);
505
506/* Implementation of COPP features */
507int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
508 struct audpp_cmd_cfg_object_params_mbadrc *mbadrc,
509 enum obj_type objtype)
510{
511 if (objtype) {
512 if (id > 5) {
513 MM_ERR("Wrong POPP decoder id: %d\n", id);
514 return -EINVAL;
515 }
516 } else {
517 if (id > 3) {
518 MM_ERR("Wrong COPP decoder id: %d\n", id);
519 return -EINVAL;
520 }
521 }
522
523 mbadrc->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
524 if (objtype)
525 mbadrc->common.stream = AUDPP_CMD_POPP_STREAM;
526 else
527 mbadrc->common.stream = AUDPP_CMD_COPP_STREAM;
528
529 mbadrc->common.stream_id = id;
530 mbadrc->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
531 mbadrc->common.command_type = AUDPP_CMD_MBADRC;
532
533 if (enable)
534 mbadrc->enable = AUDPP_CMD_ADRC_FLAG_ENA;
535 else
536 mbadrc->enable = AUDPP_CMD_ADRC_FLAG_DIS;
537
538 return audpp_send_queue3(mbadrc,
539 sizeof(struct audpp_cmd_cfg_object_params_mbadrc));
540}
541EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
542
543int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
544 struct audpp_cmd_cfg_object_params_qconcert *qconcert_plus,
545 enum obj_type objtype)
546{
547 if (objtype) {
548 if (id > 5) {
549 MM_ERR("Wrong POPP decoder id: %d\n", id);
550 return -EINVAL;
551 }
552 } else {
553 if (id > 3) {
554 MM_ERR("Wrong COPP decoder id: %d\n", id);
555 return -EINVAL;
556 }
557 }
558
559 qconcert_plus->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
560 if (objtype)
561 qconcert_plus->common.stream = AUDPP_CMD_POPP_STREAM;
562 else
563 qconcert_plus->common.stream = AUDPP_CMD_COPP_STREAM;
564
565 qconcert_plus->common.stream_id = id;
566 qconcert_plus->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
567 qconcert_plus->common.command_type = AUDPP_CMD_QCONCERT;
568
569 if (enable)
570 qconcert_plus->enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
571 else
572 qconcert_plus->enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
573
574 return audpp_send_queue3(qconcert_plus,
575 sizeof(struct audpp_cmd_cfg_object_params_qconcert));
576}
577EXPORT_SYMBOL(audpp_dsp_set_qconcert_plus);
578
579int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
580 struct audpp_cmd_cfg_object_params_pcm *iir,
581 enum obj_type objtype)
582{
583
584 if (objtype) {
585 if (id > 5) {
586 MM_ERR("Wrong POPP decoder id: %d\n", id);
587 return -EINVAL;
588 }
589 } else {
590 if (id > 3) {
591 MM_ERR("Wrong COPP decoder id: %d\n", id);
592 return -EINVAL;
593 }
594 }
595
596 iir->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
597 if (objtype)
598 iir->common.stream = AUDPP_CMD_POPP_STREAM;
599 else
600 iir->common.stream = AUDPP_CMD_COPP_STREAM;
601
602 iir->common.stream_id = id;
603 iir->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
604 iir->common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
605
606 if (enable)
607 iir->active_flag = AUDPP_CMD_IIR_FLAG_ENA;
608 else
609 iir->active_flag = AUDPP_CMD_IIR_FLAG_DIS;
610
611 return audpp_send_queue3(iir,
612 sizeof(struct audpp_cmd_cfg_object_params_pcm));
613}
614EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
615
616int audpp_dsp_set_gain_rx(unsigned id,
617 struct audpp_cmd_cfg_cal_gain *calib_gain_rx,
618 enum obj_type objtype)
619{
620 if (objtype) {
621 return -EINVAL;
622 } else {
623 if (id > 3) {
624 MM_ERR("Wrong COPP decoder id: %d\n", id);
625 return -EINVAL;
626 }
627 }
628 calib_gain_rx->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
629 calib_gain_rx->common.stream = AUDPP_CMD_COPP_STREAM;
630
631 calib_gain_rx->common.stream_id = id;
632 calib_gain_rx->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
633 calib_gain_rx->common.command_type = AUDPP_CMD_CALIB_GAIN_RX;
634
635 return audpp_send_queue3(calib_gain_rx,
636 sizeof(struct audpp_cmd_cfg_cal_gain));
637}
638EXPORT_SYMBOL(audpp_dsp_set_gain_rx);
639
640int audpp_dsp_set_pbe(unsigned id, unsigned enable,
641 struct audpp_cmd_cfg_pbe *pbe_block,
642 enum obj_type objtype)
643{
644 if (objtype) {
645 if (id > 5) {
646 MM_ERR("Wrong POPP decoder id: %d\n", id);
647 return -EINVAL;
648 }
649 } else {
650 if (id > 3) {
651 MM_ERR("Wrong COPP decoder id: %d\n", id);
652 return -EINVAL;
653 }
654 }
655
656 pbe_block->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
657 if (objtype)
658 pbe_block->common.stream = AUDPP_CMD_POPP_STREAM;
659 else
660 pbe_block->common.stream = AUDPP_CMD_COPP_STREAM;
661
662 pbe_block->common.stream_id = id;
663 pbe_block->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
664 pbe_block->common.command_type = AUDPP_CMD_PBE;
665
666 if (enable)
667 pbe_block->pbe_enable = AUDPP_CMD_PBE_FLAG_ENA;
668 else
669 pbe_block->pbe_enable = AUDPP_CMD_PBE_FLAG_DIS;
670
671 return audpp_send_queue3(pbe_block,
672 sizeof(struct audpp_cmd_cfg_pbe));
673}
674EXPORT_SYMBOL(audpp_dsp_set_pbe);
675
676int audpp_dsp_set_spa(unsigned id,
677 struct audpp_cmd_cfg_object_params_spectram *spa,
678 enum obj_type objtype){
679 struct audpp_cmd_cfg_object_params_spectram cmd;
680
681 if (objtype) {
682 if (id > 5) {
683 MM_ERR("Wrong POPP decoder id: %d\n", id);
684 return -EINVAL;
685 }
686 } else {
687 if (id > 3) {
688 MM_ERR("Wrong COPP decoder id: %d\n", id);
689 return -EINVAL;
690 }
691 }
692
693 memset(&cmd, 0, sizeof(cmd));
694 if (objtype)
695 cmd.common.stream = AUDPP_CMD_POPP_STREAM;
696 else
697 cmd.common.stream = AUDPP_CMD_COPP_STREAM;
698
699 cmd.common.stream_id = id;
700 cmd.common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
701 cmd.common.command_type = AUDPP_CMD_SPECTROGRAM;
702 cmd.sample_interval = spa->sample_interval;
703 cmd.num_coeff = spa->num_coeff;
704 return audpp_send_queue3(&cmd, sizeof(cmd));
705
706}
707EXPORT_SYMBOL(audpp_dsp_set_spa);
708
709int audpp_dsp_set_stf(unsigned id, unsigned enable,
710 struct audpp_cmd_cfg_object_params_sidechain *stf,
711 enum obj_type objtype){
712 if (objtype) {
713 if (id > 5) {
714 MM_ERR("Wrong POPP decoder id: %d\n", id);
715 return -EINVAL;
716 }
717 } else {
718 if (id > 3) {
719 MM_ERR("Wrong COPP decoder id: %d\n", id);
720 return -EINVAL;
721 }
722 }
723
724 stf->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
725 if (objtype)
726 stf->common.stream = AUDPP_CMD_POPP_STREAM;
727 else
728 stf->common.stream = AUDPP_CMD_COPP_STREAM;
729
730 stf->common.stream_id = id;
731 stf->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
732 stf->common.command_type = AUDPP_CMD_SIDECHAIN_TUNING_FILTER;
733
734 if (enable)
735 stf->active_flag = AUDPP_CMD_STF_FLAG_ENA;
736 else
737 stf->active_flag = AUDPP_CMD_STF_FLAG_DIS;
738 return audpp_send_queue3(stf,
739 sizeof(struct audpp_cmd_cfg_object_params_sidechain));
740}
741EXPORT_SYMBOL(audpp_dsp_set_stf);
742
743/* Implementation Of COPP + POPP */
744int audpp_dsp_set_eq(unsigned id, unsigned enable,
745 struct audpp_cmd_cfg_object_params_eqalizer *eq,
746 enum obj_type objtype)
747{
748 struct audpp_cmd_cfg_object_params_eqalizer cmd;
749
750 if (objtype) {
751 if (id > 5) {
752 MM_ERR("Wrong POPP decoder id: %d\n", id);
753 return -EINVAL;
754 }
755 } else {
756 if (id > 3) {
757 MM_ERR("Wrong COPP decoder id: %d\n", id);
758 return -EINVAL;
759 }
760 }
761
762 memset(&cmd, 0, sizeof(cmd));
763 if (objtype)
764 cmd.common.stream = AUDPP_CMD_POPP_STREAM;
765 else
766 cmd.common.stream = AUDPP_CMD_COPP_STREAM;
767
768 cmd.common.stream_id = id;
769 cmd.common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
770 cmd.common.command_type = AUDPP_CMD_EQUALIZER;
771 if (enable) {
772 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
773 cmd.num_bands = eq->num_bands;
774 memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
775 } else
776 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
777
778 return audpp_send_queue3(&cmd, sizeof(cmd));
779}
780EXPORT_SYMBOL(audpp_dsp_set_eq);
781
782int audpp_dsp_set_vol_pan(unsigned id,
783 struct audpp_cmd_cfg_object_params_volume *vol_pan,
784 enum obj_type objtype)
785{
786 struct audpp_cmd_cfg_object_params_volume cmd;
787
788 if (objtype) {
789 if (id > 5) {
790 MM_ERR("Wrong POPP decoder id: %d\n", id);
791 return -EINVAL;
792 }
793 } else {
794 if (id > AUDPP_MAX_COPP_DEVICES) {
795 MM_ERR("Wrong COPP decoder id: %d\n", id);
796 return -EINVAL;
797 }
798 }
799
800 memset(&cmd, 0, sizeof(cmd));
801 cmd.common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
802 if (objtype)
803 cmd.common.stream = AUDPP_CMD_POPP_STREAM;
804 else
805 cmd.common.stream = AUDPP_CMD_COPP_STREAM;
806
807 cmd.common.stream_id = id;
808 cmd.common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
809 cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
810
811 cmd.volume = vol_pan->volume;
812 cmd.pan = vol_pan->pan;
813
814 return audpp_send_queue3(&cmd, sizeof(cmd));
815}
816EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
817
818int audpp_pause(unsigned id, int pause)
819{
820 /* pause 1 = pause 0 = resume */
821 u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
822
823 if (id >= CH_COUNT)
824 return -EINVAL;
825
826 memset(pause_cmd, 0, sizeof(pause_cmd));
827
828 pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
829 pause_cmd[1] = id;
830 if (pause == 1)
831 pause_cmd[2] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
832 else if (pause == 0)
833 pause_cmd[2] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
834 else
835 return -EINVAL;
836
837 return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
838}
839EXPORT_SYMBOL(audpp_pause);
840
841int audpp_flush(unsigned id)
842{
843 u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
844
845 if (id >= CH_COUNT)
846 return -EINVAL;
847
848 memset(flush_cmd, 0, sizeof(flush_cmd));
849
850 flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
851 flush_cmd[1] = id;
852 flush_cmd[2] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
853
854 return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
855}
856EXPORT_SYMBOL(audpp_flush);
857
858/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
859 * like mp3, aac, wma etc ... *
860 * = 15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
861 * = 31:16, reserved */
862int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
863 unsigned *queueid)
864{
865 struct audpp_state *audpp = &the_audpp_state;
866 int decid = -1, idx, lidx, mode, codec;
867 int codecs_supported, min_codecs_supported;
868 unsigned int *concurrency_entry;
869 u8 max_instance, codec_type;
870
871 struct dec_instance_table *dec_instance_list;
872 dec_instance_list = (struct dec_instance_table *)
873 (audpp->dec_database->dec_instance_list);
874
875 mutex_lock(audpp->lock_dec);
876 /* Represents in bit mask */
877 mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
878 codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
879 codec_type = (dec_attrb & AUDPP_CODEC_MASK);
880
881 /* Find whether same/different codec instances are running */
882 audpp->decoder_count++;
883 audpp->codec_cnt[codec_type]++;
884 max_instance = 0;
885
886 /*if different instance of codec*/
887 if (audpp->codec_cnt[codec_type] < audpp->decoder_count) {
888 max_instance = audpp->codec_max_instances;
889 /* Get the maximum no. of instances that can be supported */
890 for (idx = 0; idx < MSM_MAX_DEC_CNT; idx++) {
891 if (audpp->codec_cnt[idx]) {
892 if ((dec_instance_list +
893 audpp->op_mode * MSM_MAX_DEC_CNT +
894 idx)->
895 max_instances_diff_dec <
896 max_instance) {
897 max_instance =
898 (dec_instance_list +
899 audpp->op_mode *
900 MSM_MAX_DEC_CNT
901 + idx)->
902 max_instances_diff_dec;
903 }
904 }
905 }
906 /* if different codec type, should not cross maximum other
907 supported */
908 if (audpp->decoder_count > (max_instance + 1)) {
909 MM_ERR("Can not support, already reached max\n");
910 audpp->decoder_count--;
911 audpp->codec_cnt[codec_type]--;
912 goto done;
913 }
914 audpp->codec_max_instances = max_instance;
915 MM_DBG("different codec running\n");
916 } else {
917 max_instance = (dec_instance_list + audpp->op_mode *
918 MSM_MAX_DEC_CNT +
919 codec_type)->
920 max_instances_same_dec;
921 /* if same codec type, should not cross maximum supported */
922 if (audpp->decoder_count > max_instance) {
923 MM_ERR("Can not support, already reached max\n");
924 audpp->decoder_count--;
925 audpp->codec_cnt[codec_type]--;
926 goto done;
927 }
928 audpp->codec_max_instances = max_instance;
929 MM_DBG("same codec running\n");
930 }
931
932 /* Point to Last entry of the row */
933 concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
934 ((audpp->concurrency + 1) *
935 (audpp->dec_database->num_dec))) - 1);
936
937 lidx = audpp->dec_database->num_dec;
938 min_codecs_supported = sizeof(unsigned int) * 8;
939
940 MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
941
942 for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
943 if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
944 if (((mode & *concurrency_entry) == mode) &&
945 (codec & *concurrency_entry)) {
946 /* Check supports minimum number codecs */
947 codecs_supported =
948 audpp->dec_database->dec_info_list[idx -
949 1].
950 nr_codec_support;
951 if (codecs_supported < min_codecs_supported) {
952 lidx = idx - 1;
953 min_codecs_supported = codecs_supported;
954 }
955 }
956 }
957 }
958
959 if (lidx < audpp->dec_database->num_dec) {
960 audpp->dec_inuse |= (1 << lidx);
961 *module_name =
962 audpp->dec_database->dec_info_list[lidx].module_name;
963 *queueid =
964 audpp->dec_database->dec_info_list[lidx].module_queueid;
965 decid = audpp->dec_database->dec_info_list[lidx].module_decid;
966 audpp->dec_info_table[lidx].codec =
967 (dec_attrb & AUDPP_CODEC_MASK);
968 audpp->dec_info_table[lidx].pid = current->pid;
969 /* point to row to get supported operation */
970 concurrency_entry =
971 ((audpp->dec_database->dec_concurrency_table +
972 ((audpp->concurrency) * (audpp->dec_database->num_dec))) +
973 lidx);
974 decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
975 MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n", decid,
976 *module_name, *queueid);
977 }
978done:
979 mutex_unlock(audpp->lock_dec);
980 return decid;
981
982}
983EXPORT_SYMBOL(audpp_adec_alloc);
984
985void audpp_adec_free(int decid)
986{
987 struct audpp_state *audpp = &the_audpp_state;
988 int idx;
989 mutex_lock(audpp->lock_dec);
990 for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
991 if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
992 decid) {
993 audpp->decoder_count--;
994 audpp->\
995 codec_cnt[audpp->dec_info_table[idx - 1].codec]--;
996 audpp->dec_inuse &= ~(1 << (idx - 1));
997 audpp->dec_info_table[idx - 1].codec = -1;
998 audpp->dec_info_table[idx - 1].pid = 0;
999 MM_INFO("free decid =%d \n", decid);
1000 break;
1001 }
1002 }
1003 mutex_unlock(audpp->lock_dec);
1004 return;
1005
1006}
1007EXPORT_SYMBOL(audpp_adec_free);
1008
1009static ssize_t concurrency_show(struct device *dev,
1010 struct device_attribute *attr, char *buf)
1011{
1012 struct audpp_state *audpp = &the_audpp_state;
1013 int rc;
1014 mutex_lock(audpp->lock_dec);
1015 rc = sprintf(buf, "%ld\n", audpp->concurrency);
1016 mutex_unlock(audpp->lock_dec);
1017 return rc;
1018}
1019
1020static ssize_t concurrency_store(struct device *dev,
1021 struct device_attribute *attr,
1022 const char *buf, size_t count)
1023{
1024 struct audpp_state *audpp = &the_audpp_state;
1025 unsigned long concurrency;
1026 int rc = -1;
1027 mutex_lock(audpp->lock_dec);
1028 if (audpp->dec_inuse) {
1029 MM_ERR("Can not change profile, while playback in progress\n");
1030 goto done;
1031 }
1032 rc = strict_strtoul(buf, 10, &concurrency);
1033 if (!rc &&
1034 (concurrency < audpp->dec_database->num_concurrency_support)) {
1035 audpp->concurrency = concurrency;
1036 MM_DBG("Concurrency case %ld\n", audpp->concurrency);
1037 rc = count;
1038 } else {
1039 MM_ERR("Not a valid Concurrency case\n");
1040 rc = -EINVAL;
1041 }
1042done:
1043 mutex_unlock(audpp->lock_dec);
1044 return rc;
1045}
1046
1047static ssize_t decoder_info_show(struct device *dev,
1048 struct device_attribute *attr, char *buf);
1049static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
1050 __ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
1051 __ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
1052 __ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
1053 __ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
1054 __ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
1055};
1056
1057static ssize_t decoder_info_show(struct device *dev,
1058 struct device_attribute *attr, char *buf)
1059{
1060 int cpy_sz = 0;
1061 struct audpp_state *audpp = &the_audpp_state;
1062 const ptrdiff_t off = attr - dev_attr_decoder; /* decoder number */
1063 mutex_lock(audpp->lock_dec);
1064 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
1065 audpp->dec_info_table[off].codec);
1066 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
1067 audpp->dec_info_table[off].pid);
1068 mutex_unlock(audpp->lock_dec);
1069 return cpy_sz;
1070}
1071
1072static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
1073 concurrency_store);
1074static int audpp_probe(struct platform_device *pdev)
1075{
1076 int rc, idx;
1077 struct audpp_state *audpp = &the_audpp_state;
1078 audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
1079 audpp->dec_database =
1080 (struct msm_adspdec_database *)pdev->dev.platform_data;
1081
1082 MM_INFO("Number of decoder supported %d\n",
1083 audpp->dec_database->num_dec);
1084 MM_INFO("Number of concurrency supported %d\n",
1085 audpp->dec_database->num_concurrency_support);
1086 init_waitqueue_head(&audpp->event_wait);
1087 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
1088 audpp->dec_info_table[idx].codec = -1;
1089 audpp->dec_info_table[idx].pid = 0;
1090 MM_INFO("module_name:%s\n",
1091 audpp->dec_database->dec_info_list[idx].module_name);
1092 MM_INFO("queueid:%d\n",
1093 audpp->dec_database->dec_info_list[idx].module_queueid);
1094 MM_INFO("decid:%d\n",
1095 audpp->dec_database->dec_info_list[idx].module_decid);
1096 MM_INFO("nr_codec_support:%d\n",
1097 audpp->dec_database->dec_info_list[idx].
1098 nr_codec_support);
1099 }
1100
1101 wake_lock_init(&audpp_wake_lock, WAKE_LOCK_SUSPEND, "audpp");
1102 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
1103 rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
1104 if (rc)
1105 goto err;
1106 }
1107 rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
1108 audpp->op_mode = 0; /* Consider as non turbo mode */
1109 if (rc)
1110 goto err;
1111 else
1112 goto done;
1113err:
1114 while (idx--)
1115 device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
1116done:
1117 return rc;
1118}
1119
1120static struct platform_driver audpp_plat_driver = {
1121 .probe = audpp_probe,
1122 .driver = {
1123 .name = "msm_adspdec",
1124 .owner = THIS_MODULE,
1125 },
1126};
1127
1128static int __init audpp_init(void)
1129{
1130 return platform_driver_register(&audpp_plat_driver);
1131}
1132
1133device_initcall(audpp_init);