blob: 54e45b457f1a1a4984474ab3290366d434bab9dd [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001
2/* arch/arm/mach-msm/qdsp5/audpp.c
3 *
4 * common code to deal with the AUDPP dsp task (audio postproc)
5 *
6 * Copyright (C) 2008 Google, Inc.
Manish Dewangan8e87bc12012-02-09 20:25:15 +05307 * Copyright (c) 2009-2010, 2012 Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/wait.h>
23#include <linux/delay.h>
24#include <linux/sched.h>
25#include <linux/platform_device.h>
26#include <linux/dma-mapping.h>
27
28#include <asm/atomic.h>
29#include <asm/ioctls.h>
30#include <mach/board.h>
31#include <mach/msm_adsp.h>
32
33#include "audmgr.h"
34
35#include <mach/qdsp5/qdsp5audppcmdi.h>
36#include <mach/qdsp5/qdsp5audppmsg.h>
37#include <mach/debug_mm.h>
38
39#include "evlog.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);
69
70#define CH_COUNT 5
71#define AUDPP_CLNT_MAX_COUNT 6
72#define AUDPP_AVSYNC_INFO_SIZE 7
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
80#define AUDPP_CMD_VOLUME_PAN 0
81#define AUDPP_CMD_IIR_TUNING_FILTER 1
82#define AUDPP_CMD_EQUALIZER 2
83#define AUDPP_CMD_ADRC 3
84#define AUDPP_CMD_SPECTROGRAM 4
85#define AUDPP_CMD_QCONCERT 5
86#define AUDPP_CMD_SIDECHAIN_TUNING_FILTER 6
87#define AUDPP_CMD_SAMPLING_FREQUENCY 7
88#define AUDPP_CMD_QAFX 8
89#define AUDPP_CMD_QRUMBLE 9
90#define AUDPP_CMD_MBADRC 10
91
92#define MAX_EVENT_CALLBACK_CLIENTS 1
93
94#define AUDPP_CONCURRENCY_DEFAULT 6 /* All non tunnel mode */
95#define AUDPP_MAX_DECODER_CNT 5
96#define AUDPP_CODEC_MASK 0x000000FF
97#define AUDPP_MODE_MASK 0x00000F00
98#define AUDPP_OP_MASK 0xF0000000
99
100struct audpp_decoder_info {
101 unsigned int codec;
102 pid_t pid;
103};
104
105struct audpp_state {
106 struct msm_adsp_module *mod;
107 audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
108 void *private[AUDPP_CLNT_MAX_COUNT];
109 struct mutex *lock;
110 unsigned open_count;
111 unsigned enabled;
112
113 /* Related to decoder allocation */
114 struct mutex *lock_dec;
115 struct msm_adspdec_database *dec_database;
116 struct audpp_decoder_info dec_info_table[AUDPP_MAX_DECODER_CNT];
117 unsigned dec_inuse;
118 unsigned long concurrency;
119
120 /* which channels are actually enabled */
121 unsigned avsync_mask;
122
123 /* flags, 48 bits sample/bytes counter per channel */
124 uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
125 struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
126
127 wait_queue_head_t event_wait;
128};
129
130struct audpp_state the_audpp_state = {
131 .lock = &audpp_lock,
132 .lock_dec = &audpp_dec_lock,
133};
134
135int audpp_send_queue1(void *cmd, unsigned len)
136{
137 return msm_adsp_write(the_audpp_state.mod,
138 QDSP_uPAudPPCmd1Queue, cmd, len);
139}
140EXPORT_SYMBOL(audpp_send_queue1);
141
142int audpp_send_queue2(void *cmd, unsigned len)
143{
144 return msm_adsp_write(the_audpp_state.mod,
145 QDSP_uPAudPPCmd2Queue, cmd, len);
146}
147EXPORT_SYMBOL(audpp_send_queue2);
148
149int audpp_send_queue3(void *cmd, unsigned len)
150{
151 return msm_adsp_write(the_audpp_state.mod,
152 QDSP_uPAudPPCmd3Queue, cmd, len);
153}
154EXPORT_SYMBOL(audpp_send_queue3);
155
156static int audpp_dsp_config(int enable)
157{
158 audpp_cmd_cfg cmd;
159
160 cmd.cmd_id = AUDPP_CMD_CFG;
161 cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
162
163 return audpp_send_queue1(&cmd, sizeof(cmd));
164}
165
166int is_audpp_enable(void)
167{
168 struct audpp_state *audpp = &the_audpp_state;
169
170 return audpp->enabled;
171}
172EXPORT_SYMBOL(is_audpp_enable);
173
174int audpp_register_event_callback(struct audpp_event_callback *ecb)
175{
176 struct audpp_state *audpp = &the_audpp_state;
177 int i;
178
179 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
180 if (NULL == audpp->cb_tbl[i]) {
181 audpp->cb_tbl[i] = ecb;
182 return 0;
183 }
184 }
185 return -1;
186}
187EXPORT_SYMBOL(audpp_register_event_callback);
188
189int audpp_unregister_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 (ecb == audpp->cb_tbl[i]) {
196 audpp->cb_tbl[i] = NULL;
197 return 0;
198 }
199 }
200 return -1;
201}
202EXPORT_SYMBOL(audpp_unregister_event_callback);
203
204static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
205 uint16_t *msg)
206{
207 unsigned n;
208 for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
209 if (audpp->func[n])
210 audpp->func[n] (audpp->private[n], id, msg);
211 }
212
213 for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
214 if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
215 audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private, id,
216 msg);
217}
218
219static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
220 unsigned id, uint16_t *msg)
221{
222 if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
223 audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
224}
225
226static void audpp_handle_pcmdmamiss(struct audpp_state *audpp,
227 uint16_t bit_mask)
228{
229 uint8_t b_index;
230
231 for (b_index = 0; b_index < AUDPP_CLNT_MAX_COUNT; b_index++) {
232 if (bit_mask & (0x1 << b_index))
233 if (audpp->func[b_index])
234 audpp->func[b_index] (audpp->private[b_index],
235 AUDPP_MSG_PCMDMAMISSED,
236 &bit_mask);
237 }
238}
239
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530240static void audpp_fake_event(struct audpp_state *audpp, int id,
241 unsigned event, unsigned arg)
242{
243 uint16_t msg[1];
244 msg[0] = arg;
245 audpp->func[id] (audpp->private[id], event, msg);
246}
247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248static void audpp_dsp_event(void *data, unsigned id, size_t len,
249 void (*getevent) (void *ptr, size_t len))
250{
251 struct audpp_state *audpp = data;
252 uint16_t msg[8];
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530253 int cid = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254
255 if (id == AUDPP_MSG_AVSYNC_MSG) {
256 getevent(audpp->avsync, sizeof(audpp->avsync));
257
258 /* mask off any channels we're not watching to avoid
259 * cases where we might get one last update after
260 * disabling avsync and end up in an odd state when
261 * we next read...
262 */
263 audpp->avsync[0] &= audpp->avsync_mask;
264 return;
265 }
266
267 getevent(msg, sizeof(msg));
268
269 LOG(EV_EVENT, (id << 16) | msg[0]);
270 LOG(EV_DATA, (msg[1] << 16) | msg[2]);
271
272 switch (id) {
273 case AUDPP_MSG_STATUS_MSG:{
274 unsigned cid = msg[0];
275 MM_DBG("status %d %d %d\n", cid, msg[1], msg[2]);
276 if ((cid < 5) && audpp->func[cid])
277 audpp->func[cid] (audpp->private[cid], id, msg);
278 break;
279 }
280 case AUDPP_MSG_HOST_PCM_INTF_MSG:
281 if (audpp->func[5])
282 audpp->func[5] (audpp->private[5], id, msg);
283 break;
284 case AUDPP_MSG_PCMDMAMISSED:
285 audpp_handle_pcmdmamiss(audpp, msg[0]);
286 break;
287 case AUDPP_MSG_CFG_MSG:
288 if (msg[0] == AUDPP_MSG_ENA_ENA) {
289 MM_INFO("ENABLE\n");
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530290 if (!audpp->enabled) {
291 audpp->enabled = 1;
292 audpp_broadcast(audpp, id, msg);
293 } else {
294 cid = msg[1];
295 audpp_fake_event(audpp, cid,
296 id, AUDPP_MSG_ENA_ENA);
297 }
298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530300 if (audpp->open_count == 0) {
301 MM_INFO("DISABLE\n");
302 audpp->enabled = 0;
303 wake_up(&audpp->event_wait);
304 audpp_broadcast(audpp, id, msg);
305 } else {
306 cid = msg[1];
307 audpp_fake_event(audpp, cid,
308 id, AUDPP_MSG_ENA_DIS);
309 audpp->func[cid] = NULL;
310 audpp->private[cid] = NULL;
311 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 } else {
313 MM_ERR("invalid config msg %d\n", msg[0]);
314 }
315 break;
316 case AUDPP_MSG_ROUTING_ACK:
317 audpp_notify_clnt(audpp, msg[0], id, msg);
318 break;
319 case AUDPP_MSG_FLUSH_ACK:
320 audpp_notify_clnt(audpp, msg[0], id, msg);
321 break;
322 case ADSP_MESSAGE_ID:
323 MM_DBG("Received ADSP event: module enable/disable(audpptask)");
324 break;
325 default:
326 MM_ERR("unhandled msg id %x\n", id);
327 }
328}
329
330static struct msm_adsp_ops adsp_ops = {
331 .event = audpp_dsp_event,
332};
333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334int audpp_enable(int id, audpp_event_func func, void *private)
335{
336 struct audpp_state *audpp = &the_audpp_state;
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530337 uint16_t msg[8];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338 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("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 msm_adsp_enable(audpp->mod);
368 audpp_dsp_config(1);
369 } else {
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530370 if (audpp->enabled) {
371 msg[0] = AUDPP_MSG_ENA_ENA;
372 msg[1] = id;
373 res = msm_adsp_generate_event(audpp, audpp->mod,
374 AUDPP_MSG_CFG_MSG, sizeof(msg),
375 sizeof(uint16_t), (void *)msg);
376 if (res < 0)
377 goto out;
378 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379 }
380
381 res = 0;
382out:
383 mutex_unlock(audpp->lock);
384 return res;
385}
386EXPORT_SYMBOL(audpp_enable);
387
388void audpp_disable(int id, void *private)
389{
390 struct audpp_state *audpp = &the_audpp_state;
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530391 uint16_t msg[8];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 int rc;
393
394 if (id < -1 || id > 4)
395 return;
396
397 if (id == -1)
398 id = 5;
399
400 mutex_lock(audpp->lock);
401 LOG(EV_DISABLE, 1);
402 if (!audpp->func[id])
403 goto out;
404 if (audpp->private[id] != private)
405 goto out;
406
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530407 msg[0] = AUDPP_MSG_ENA_DIS;
408 msg[1] = id;
409 rc = msm_adsp_generate_event(audpp, audpp->mod,
410 AUDPP_MSG_CFG_MSG, sizeof(msg),
411 sizeof(uint16_t), (void *)msg);
412 if (rc < 0)
413 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700414
415 if (--audpp->open_count == 0) {
416 MM_DBG("disable\n");
417 LOG(EV_DISABLE, 2);
418 audpp_dsp_config(0);
419 rc = wait_event_interruptible(audpp->event_wait,
420 (audpp->enabled == 0));
421 if (audpp->enabled == 0)
422 MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
423 else
424 MM_ERR("Didn't receive CFG_MSG DISABLE \
425 message from ADSP\n");
426 msm_adsp_disable(audpp->mod);
427 msm_adsp_put(audpp->mod);
428 audpp->mod = NULL;
429 }
430out:
431 mutex_unlock(audpp->lock);
432}
433EXPORT_SYMBOL(audpp_disable);
434
435#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
436
437void audpp_avsync(int id, unsigned rate)
438{
439 unsigned long flags;
440 audpp_cmd_avsync cmd;
441
442 if (BAD_ID(id))
443 return;
444
445 local_irq_save(flags);
446 if (rate)
447 the_audpp_state.avsync_mask |= (1 << id);
448 else
449 the_audpp_state.avsync_mask &= (~(1 << id));
450 the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
451 local_irq_restore(flags);
452
453 cmd.cmd_id = AUDPP_CMD_AVSYNC;
454 cmd.object_number = id;
455 cmd.interrupt_interval_lsw = rate;
456 cmd.interrupt_interval_msw = rate >> 16;
457 audpp_send_queue1(&cmd, sizeof(cmd));
458}
459EXPORT_SYMBOL(audpp_avsync);
460
461unsigned audpp_avsync_sample_count(int id)
462{
463 uint16_t *avsync = the_audpp_state.avsync;
464 unsigned val;
465 unsigned long flags;
466 unsigned mask;
467
468 if (BAD_ID(id))
469 return 0;
470
471 mask = 1 << id;
472 id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
473 local_irq_save(flags);
474 if (avsync[0] & mask)
475 val = (avsync[id] << 16) | avsync[id + 1];
476 else
477 val = 0;
478 local_irq_restore(flags);
479
480 return val;
481}
482EXPORT_SYMBOL(audpp_avsync_sample_count);
483
484unsigned audpp_avsync_byte_count(int id)
485{
486 uint16_t *avsync = the_audpp_state.avsync;
487 unsigned val;
488 unsigned long flags;
489 unsigned mask;
490
491 if (BAD_ID(id))
492 return 0;
493
494 mask = 1 << id;
495 id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
496 local_irq_save(flags);
497 if (avsync[0] & mask)
498 val = (avsync[id] << 16) | avsync[id + 1];
499 else
500 val = 0;
501 local_irq_restore(flags);
502
503 return val;
504}
505EXPORT_SYMBOL(audpp_avsync_byte_count);
506
507int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan)
508{
509 /* cmd, obj_cfg[7], cmd_type, volume, pan */
510 uint16_t cmd[11];
511
512 if (id > 6)
513 return -EINVAL;
514
515 memset(cmd, 0, sizeof(cmd));
516 cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
517 cmd[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
518 cmd[8] = AUDPP_CMD_VOLUME_PAN;
519 cmd[9] = volume;
520 cmd[10] = pan;
521
522 return audpp_send_queue3(cmd, sizeof(cmd));
523}
524EXPORT_SYMBOL(audpp_set_volume_and_pan);
525
526/* Implementation of COPP features */
527int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
528 audpp_cmd_cfg_object_params_mbadrc *mbadrc)
529{
530 audpp_cmd_cfg_object_params_mbadrc cmd;
531
532 if (id != 6)
533 return -EINVAL;
534
535 memset(&cmd, 0, sizeof(cmd));
536 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
537 cmd.common.command_type = AUDPP_CMD_MBADRC;
538
539 if (enable) {
540 memcpy(&cmd.num_bands, &mbadrc->num_bands,
541 sizeof(*mbadrc) -
542 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
543 cmd.enable = AUDPP_CMD_ADRC_FLAG_ENA;
544 } else
545 cmd.enable = AUDPP_CMD_ADRC_FLAG_DIS;
546
547 /*order the writes to mbadrc */
548 dma_coherent_pre_ops();
549 return audpp_send_queue3(&cmd, sizeof(cmd));
550}
551EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
552
553int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
554 audpp_cmd_cfg_object_params_qconcert *
555 qconcert_plus)
556{
557 audpp_cmd_cfg_object_params_qconcert cmd;
558 if (id != 6)
559 return -EINVAL;
560
561 memset(&cmd, 0, sizeof(cmd));
562 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
563 cmd.common.command_type = AUDPP_CMD_QCONCERT;
564
565 if (enable) {
566 memcpy(&cmd.op_mode, &qconcert_plus->op_mode,
567 sizeof(audpp_cmd_cfg_object_params_qconcert) -
568 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
569 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
570 } else
571 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
572
573 return audpp_send_queue3(&cmd, sizeof(cmd));
574}
575
576int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
577 audpp_cmd_cfg_object_params_pcm *iir)
578{
579 audpp_cmd_cfg_object_params_pcm cmd;
580
581 if (id != 6)
582 return -EINVAL;
583
584 memset(&cmd, 0, sizeof(cmd));
585 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
586 cmd.common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
587
588 if (enable) {
589 cmd.active_flag = AUDPP_CMD_IIR_FLAG_ENA;
590 cmd.num_bands = iir->num_bands;
591 memcpy(&cmd.params_filter, &iir->params_filter,
592 sizeof(iir->params_filter));
593 } else
594 cmd.active_flag = AUDPP_CMD_IIR_FLAG_DIS;
595
596 return audpp_send_queue3(&cmd, sizeof(cmd));
597}
598EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
599
600/* Implementation Of COPP + POPP */
601int audpp_dsp_set_eq(unsigned id, unsigned enable,
602 audpp_cmd_cfg_object_params_eqalizer *eq)
603{
604 audpp_cmd_cfg_object_params_eqalizer cmd;
605 unsigned short *id_ptr = (unsigned short *)&cmd;
606
607 if (id > 6 || id == 5)
608 return -EINVAL;
609
610 memset(&cmd, 0, sizeof(cmd));
611 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
612 cmd.common.command_type = AUDPP_CMD_EQUALIZER;
613
614 if (enable) {
615 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
616 cmd.num_bands = eq->num_bands;
617 memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
618 } else
619 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
620
621 return audpp_send_queue3(&cmd, sizeof(cmd));
622}
623EXPORT_SYMBOL(audpp_dsp_set_eq);
624
625int audpp_dsp_set_vol_pan(unsigned id,
626 audpp_cmd_cfg_object_params_volume *vol_pan)
627{
628 audpp_cmd_cfg_object_params_volume cmd;
629 unsigned short *id_ptr = (unsigned short *)&cmd;
630
631 if (id > 6)
632 return -EINVAL;
633
634 memset(&cmd, 0, sizeof(cmd));
635 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
636 cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
637
638 cmd.volume = vol_pan->volume;
639 cmd.pan = vol_pan->pan;
640
641 return audpp_send_queue3(&cmd, sizeof(cmd));
642}
643EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
644
645int audpp_pause(unsigned id, int pause)
646{
647 /* pause 1 = pause 0 = resume */
648 u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
649
650 if (id >= CH_COUNT)
651 return -EINVAL;
652
653 memset(pause_cmd, 0, sizeof(pause_cmd));
654
655 pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
656 if (pause == 1)
657 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
658 else if (pause == 0)
659 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
660 else
661 return -EINVAL;
662
663 return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
664}
665EXPORT_SYMBOL(audpp_pause);
666
667int audpp_flush(unsigned id)
668{
669 u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
670
671 if (id >= CH_COUNT)
672 return -EINVAL;
673
674 memset(flush_cmd, 0, sizeof(flush_cmd));
675
676 flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
677 flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
678
679 return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
680}
681EXPORT_SYMBOL(audpp_flush);
682
683/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
684 * like mp3, aac, wma etc ... *
685 * = 15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
686 * = 31:16, reserved */
687int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
688 unsigned *queueid)
689{
690 struct audpp_state *audpp = &the_audpp_state;
691 int decid = -1, idx, lidx, mode, codec;
692 int codecs_supported, min_codecs_supported;
693 unsigned int *concurrency_entry;
694 mutex_lock(audpp->lock_dec);
695 /* Represents in bit mask */
696 mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
697 codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
698 /* Point to Last entry of the row */
699 concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
700 ((audpp->concurrency + 1) *
701 (audpp->dec_database->num_dec))) - 1);
702
703 lidx = audpp->dec_database->num_dec;
704 min_codecs_supported = sizeof(unsigned int) * 8;
705
706 MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
707
708 for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
709 if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
710 if ((mode & *concurrency_entry) &&
711 (codec & *concurrency_entry)) {
712 /* Check supports minimum number codecs */
713 codecs_supported =
714 audpp->dec_database->dec_info_list[idx -
715 1].
716 nr_codec_support;
717 if (codecs_supported < min_codecs_supported) {
718 lidx = idx - 1;
719 min_codecs_supported = codecs_supported;
720 }
721 }
722 }
723 }
724
725 if (lidx < audpp->dec_database->num_dec) {
726 audpp->dec_inuse |= (1 << lidx);
727 *module_name =
728 audpp->dec_database->dec_info_list[lidx].module_name;
729 *queueid =
730 audpp->dec_database->dec_info_list[lidx].module_queueid;
731 decid = audpp->dec_database->dec_info_list[lidx].module_decid;
732 audpp->dec_info_table[lidx].codec =
733 (dec_attrb & AUDPP_CODEC_MASK);
734 audpp->dec_info_table[lidx].pid = current->pid;
735 /* point to row to get supported operation */
736 concurrency_entry =
737 ((audpp->dec_database->dec_concurrency_table +
738 ((audpp->concurrency) * (audpp->dec_database->num_dec))) +
739 lidx);
740 decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
741 MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n",
742 decid, *module_name, *queueid);
743 }
744 mutex_unlock(audpp->lock_dec);
745 return decid;
746
747}
748EXPORT_SYMBOL(audpp_adec_alloc);
749
750void audpp_adec_free(int decid)
751{
752 struct audpp_state *audpp = &the_audpp_state;
753 int idx;
754 mutex_lock(audpp->lock_dec);
755 for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
756 if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
757 decid) {
758 audpp->dec_inuse &= ~(1 << (idx - 1));
759 audpp->dec_info_table[idx - 1].codec = -1;
760 audpp->dec_info_table[idx - 1].pid = 0;
761 MM_INFO("free decid =%d \n", decid);
762 break;
763 }
764 }
765 mutex_unlock(audpp->lock_dec);
766 return;
767
768}
769EXPORT_SYMBOL(audpp_adec_free);
770
771static ssize_t concurrency_show(struct device *dev,
772 struct device_attribute *attr, char *buf)
773{
774 struct audpp_state *audpp = &the_audpp_state;
775 int rc;
776 mutex_lock(audpp->lock_dec);
777 rc = sprintf(buf, "%ld\n", audpp->concurrency);
778 mutex_unlock(audpp->lock_dec);
779 return rc;
780}
781
782static ssize_t concurrency_store(struct device *dev,
783 struct device_attribute *attr,
784 const char *buf, size_t count)
785{
786 struct audpp_state *audpp = &the_audpp_state;
787 unsigned long concurrency;
788 int rc = -1;
789 mutex_lock(audpp->lock_dec);
790 if (audpp->dec_inuse) {
791 MM_ERR("Can not change profile, while playback in progress\n");
792 goto done;
793 }
794 rc = strict_strtoul(buf, 10, &concurrency);
795 if (!rc &&
796 (concurrency < audpp->dec_database->num_concurrency_support)) {
797 audpp->concurrency = concurrency;
798 MM_DBG("Concurrency case %ld\n", audpp->concurrency);
799 rc = count;
800 } else {
801 MM_ERR("Not a valid Concurrency case\n");
802 rc = -EINVAL;
803 }
804done:
805 mutex_unlock(audpp->lock_dec);
806 return rc;
807}
808
809static ssize_t decoder_info_show(struct device *dev,
810 struct device_attribute *attr, char *buf);
811static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
812 __ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
813 __ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
814 __ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
815 __ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
816 __ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
817};
818
819static ssize_t decoder_info_show(struct device *dev,
820 struct device_attribute *attr, char *buf)
821{
822 int cpy_sz = 0;
823 struct audpp_state *audpp = &the_audpp_state;
824 const ptrdiff_t off = attr - dev_attr_decoder; /* decoder number */
825 mutex_lock(audpp->lock_dec);
826 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
827 audpp->dec_info_table[off].codec);
828 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
829 audpp->dec_info_table[off].pid);
830 mutex_unlock(audpp->lock_dec);
831 return cpy_sz;
832}
833
834static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
835 concurrency_store);
836static int audpp_probe(struct platform_device *pdev)
837{
838 int rc, idx;
839 struct audpp_state *audpp = &the_audpp_state;
840 audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
841 audpp->dec_database =
842 (struct msm_adspdec_database *)pdev->dev.platform_data;
843
844 MM_INFO("Number of decoder supported %d\n",
845 audpp->dec_database->num_dec);
846 MM_INFO("Number of concurrency supported %d\n",
847 audpp->dec_database->num_concurrency_support);
848
849 init_waitqueue_head(&audpp->event_wait);
850
851 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
852 audpp->dec_info_table[idx].codec = -1;
853 audpp->dec_info_table[idx].pid = 0;
854 MM_INFO("module_name:%s\n",
855 audpp->dec_database->dec_info_list[idx].module_name);
856 MM_INFO("queueid:%d\n",
857 audpp->dec_database->dec_info_list[idx].module_queueid);
858 MM_INFO("decid:%d\n",
859 audpp->dec_database->dec_info_list[idx].module_decid);
860 MM_INFO("nr_codec_support:%d\n",
861 audpp->dec_database->dec_info_list[idx].
862 nr_codec_support);
863 }
864
865 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
866 rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
867 if (rc)
868 goto err;
869 }
870 rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
871 if (rc)
872 goto err;
873 else
874 goto done;
875err:
876 while (idx--)
877 device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
878done:
879 return rc;
880}
881
882static struct platform_driver audpp_plat_driver = {
883 .probe = audpp_probe,
884 .driver = {
885 .name = "msm_adspdec",
886 .owner = THIS_MODULE,
887 },
888};
889
890static int __init audpp_init(void)
891{
892 return platform_driver_register(&audpp_plat_driver);
893}
894
895device_initcall(audpp_init);