blob: 1616ad0b5241f2b9a016a491d07d3d20e25b7f99 [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
Sidipotu Ashok3144aa22012-03-16 10:55:24 +053074#define AUDPP_SRS_PARAMS 2
75#define AUDPP_SRS_PARAMS_G 0
76#define AUDPP_SRS_PARAMS_W 1
77#define AUDPP_SRS_PARAMS_C 2
78#define AUDPP_SRS_PARAMS_H 3
79#define AUDPP_SRS_PARAMS_P 4
80#define AUDPP_SRS_PARAMS_L 5
81
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
83#define AUDPP_CMD_EQ_FLAG_DIS 0x0000
84#define AUDPP_CMD_EQ_FLAG_ENA -1
85#define AUDPP_CMD_IIR_FLAG_DIS 0x0000
86#define AUDPP_CMD_IIR_FLAG_ENA -1
87
88#define AUDPP_CMD_VOLUME_PAN 0
89#define AUDPP_CMD_IIR_TUNING_FILTER 1
90#define AUDPP_CMD_EQUALIZER 2
91#define AUDPP_CMD_ADRC 3
92#define AUDPP_CMD_SPECTROGRAM 4
93#define AUDPP_CMD_QCONCERT 5
94#define AUDPP_CMD_SIDECHAIN_TUNING_FILTER 6
95#define AUDPP_CMD_SAMPLING_FREQUENCY 7
96#define AUDPP_CMD_QAFX 8
97#define AUDPP_CMD_QRUMBLE 9
98#define AUDPP_CMD_MBADRC 10
99
100#define MAX_EVENT_CALLBACK_CLIENTS 1
101
102#define AUDPP_CONCURRENCY_DEFAULT 6 /* All non tunnel mode */
103#define AUDPP_MAX_DECODER_CNT 5
104#define AUDPP_CODEC_MASK 0x000000FF
105#define AUDPP_MODE_MASK 0x00000F00
106#define AUDPP_OP_MASK 0xF0000000
107
108struct audpp_decoder_info {
109 unsigned int codec;
110 pid_t pid;
111};
112
113struct audpp_state {
114 struct msm_adsp_module *mod;
115 audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
116 void *private[AUDPP_CLNT_MAX_COUNT];
117 struct mutex *lock;
118 unsigned open_count;
119 unsigned enabled;
120
121 /* Related to decoder allocation */
122 struct mutex *lock_dec;
123 struct msm_adspdec_database *dec_database;
124 struct audpp_decoder_info dec_info_table[AUDPP_MAX_DECODER_CNT];
125 unsigned dec_inuse;
126 unsigned long concurrency;
127
128 /* which channels are actually enabled */
129 unsigned avsync_mask;
130
131 /* flags, 48 bits sample/bytes counter per channel */
132 uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
133 struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
134
Manish Dewangan0f90d472012-02-25 14:09:23 +0530135 spinlock_t avsync_lock;
136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 wait_queue_head_t event_wait;
138};
139
140struct audpp_state the_audpp_state = {
141 .lock = &audpp_lock,
142 .lock_dec = &audpp_dec_lock,
143};
144
145int audpp_send_queue1(void *cmd, unsigned len)
146{
147 return msm_adsp_write(the_audpp_state.mod,
148 QDSP_uPAudPPCmd1Queue, cmd, len);
149}
150EXPORT_SYMBOL(audpp_send_queue1);
151
152int audpp_send_queue2(void *cmd, unsigned len)
153{
154 return msm_adsp_write(the_audpp_state.mod,
155 QDSP_uPAudPPCmd2Queue, cmd, len);
156}
157EXPORT_SYMBOL(audpp_send_queue2);
158
159int audpp_send_queue3(void *cmd, unsigned len)
160{
161 return msm_adsp_write(the_audpp_state.mod,
162 QDSP_uPAudPPCmd3Queue, cmd, len);
163}
164EXPORT_SYMBOL(audpp_send_queue3);
165
166static int audpp_dsp_config(int enable)
167{
168 audpp_cmd_cfg cmd;
169
170 cmd.cmd_id = AUDPP_CMD_CFG;
171 cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
172
173 return audpp_send_queue1(&cmd, sizeof(cmd));
174}
175
176int is_audpp_enable(void)
177{
178 struct audpp_state *audpp = &the_audpp_state;
179
180 return audpp->enabled;
181}
182EXPORT_SYMBOL(is_audpp_enable);
183
184int audpp_register_event_callback(struct audpp_event_callback *ecb)
185{
186 struct audpp_state *audpp = &the_audpp_state;
187 int i;
188
189 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
190 if (NULL == audpp->cb_tbl[i]) {
191 audpp->cb_tbl[i] = ecb;
192 return 0;
193 }
194 }
195 return -1;
196}
197EXPORT_SYMBOL(audpp_register_event_callback);
198
199int audpp_unregister_event_callback(struct audpp_event_callback *ecb)
200{
201 struct audpp_state *audpp = &the_audpp_state;
202 int i;
203
204 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
205 if (ecb == audpp->cb_tbl[i]) {
206 audpp->cb_tbl[i] = NULL;
207 return 0;
208 }
209 }
210 return -1;
211}
212EXPORT_SYMBOL(audpp_unregister_event_callback);
213
214static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
215 uint16_t *msg)
216{
217 unsigned n;
218 for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
219 if (audpp->func[n])
220 audpp->func[n] (audpp->private[n], id, msg);
221 }
222
223 for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
224 if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
225 audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private, id,
226 msg);
227}
228
229static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
230 unsigned id, uint16_t *msg)
231{
232 if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
233 audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
234}
235
236static void audpp_handle_pcmdmamiss(struct audpp_state *audpp,
237 uint16_t bit_mask)
238{
239 uint8_t b_index;
240
241 for (b_index = 0; b_index < AUDPP_CLNT_MAX_COUNT; b_index++) {
242 if (bit_mask & (0x1 << b_index))
243 if (audpp->func[b_index])
244 audpp->func[b_index] (audpp->private[b_index],
245 AUDPP_MSG_PCMDMAMISSED,
246 &bit_mask);
247 }
248}
249
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530250static void audpp_fake_event(struct audpp_state *audpp, int id,
251 unsigned event, unsigned arg)
252{
253 uint16_t msg[1];
254 msg[0] = arg;
255 audpp->func[id] (audpp->private[id], event, msg);
256}
257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258static void audpp_dsp_event(void *data, unsigned id, size_t len,
259 void (*getevent) (void *ptr, size_t len))
260{
261 struct audpp_state *audpp = data;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530262 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 uint16_t msg[8];
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530264 int cid = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265
266 if (id == AUDPP_MSG_AVSYNC_MSG) {
Manish Dewangan0f90d472012-02-25 14:09:23 +0530267 spin_lock_irqsave(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 getevent(audpp->avsync, sizeof(audpp->avsync));
269
270 /* mask off any channels we're not watching to avoid
271 * cases where we might get one last update after
272 * disabling avsync and end up in an odd state when
273 * we next read...
274 */
275 audpp->avsync[0] &= audpp->avsync_mask;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530276 spin_unlock_irqrestore(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 return;
278 }
279
280 getevent(msg, sizeof(msg));
281
282 LOG(EV_EVENT, (id << 16) | msg[0]);
283 LOG(EV_DATA, (msg[1] << 16) | msg[2]);
284
285 switch (id) {
286 case AUDPP_MSG_STATUS_MSG:{
287 unsigned cid = msg[0];
288 MM_DBG("status %d %d %d\n", cid, msg[1], msg[2]);
289 if ((cid < 5) && audpp->func[cid])
290 audpp->func[cid] (audpp->private[cid], id, msg);
291 break;
292 }
293 case AUDPP_MSG_HOST_PCM_INTF_MSG:
294 if (audpp->func[5])
295 audpp->func[5] (audpp->private[5], id, msg);
296 break;
297 case AUDPP_MSG_PCMDMAMISSED:
298 audpp_handle_pcmdmamiss(audpp, msg[0]);
299 break;
300 case AUDPP_MSG_CFG_MSG:
301 if (msg[0] == AUDPP_MSG_ENA_ENA) {
302 MM_INFO("ENABLE\n");
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530303 if (!audpp->enabled) {
304 audpp->enabled = 1;
305 audpp_broadcast(audpp, id, msg);
306 } else {
307 cid = msg[1];
308 audpp_fake_event(audpp, cid,
309 id, AUDPP_MSG_ENA_ENA);
310 }
311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530313 if (audpp->open_count == 0) {
314 MM_INFO("DISABLE\n");
315 audpp->enabled = 0;
316 wake_up(&audpp->event_wait);
317 audpp_broadcast(audpp, id, msg);
318 } else {
319 cid = msg[1];
320 audpp_fake_event(audpp, cid,
321 id, AUDPP_MSG_ENA_DIS);
322 audpp->func[cid] = NULL;
323 audpp->private[cid] = NULL;
324 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325 } else {
326 MM_ERR("invalid config msg %d\n", msg[0]);
327 }
328 break;
329 case AUDPP_MSG_ROUTING_ACK:
330 audpp_notify_clnt(audpp, msg[0], id, msg);
331 break;
332 case AUDPP_MSG_FLUSH_ACK:
333 audpp_notify_clnt(audpp, msg[0], id, msg);
334 break;
335 case ADSP_MESSAGE_ID:
336 MM_DBG("Received ADSP event: module enable/disable(audpptask)");
337 break;
338 default:
339 MM_ERR("unhandled msg id %x\n", id);
340 }
341}
342
343static struct msm_adsp_ops adsp_ops = {
344 .event = audpp_dsp_event,
345};
346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347int audpp_enable(int id, audpp_event_func func, void *private)
348{
349 struct audpp_state *audpp = &the_audpp_state;
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530350 uint16_t msg[8];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 int res = 0;
352
353 if (id < -1 || id > 4)
354 return -EINVAL;
355
356 if (id == -1)
357 id = 5;
358
359 mutex_lock(audpp->lock);
360 if (audpp->func[id]) {
361 res = -EBUSY;
362 goto out;
363 }
364
365 audpp->func[id] = func;
366 audpp->private[id] = private;
367
368 LOG(EV_ENABLE, 1);
369 if (audpp->open_count++ == 0) {
370 MM_DBG("enable\n");
371 res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
372 if (res < 0) {
373 MM_ERR("cannot open AUDPPTASK\n");
374 audpp->open_count = 0;
375 audpp->func[id] = NULL;
376 audpp->private[id] = NULL;
377 goto out;
378 }
379 LOG(EV_ENABLE, 2);
380 msm_adsp_enable(audpp->mod);
381 audpp_dsp_config(1);
382 } else {
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530383 if (audpp->enabled) {
384 msg[0] = AUDPP_MSG_ENA_ENA;
385 msg[1] = id;
386 res = msm_adsp_generate_event(audpp, audpp->mod,
387 AUDPP_MSG_CFG_MSG, sizeof(msg),
388 sizeof(uint16_t), (void *)msg);
389 if (res < 0)
390 goto out;
391 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 }
393
394 res = 0;
395out:
396 mutex_unlock(audpp->lock);
397 return res;
398}
399EXPORT_SYMBOL(audpp_enable);
400
401void audpp_disable(int id, void *private)
402{
403 struct audpp_state *audpp = &the_audpp_state;
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530404 uint16_t msg[8];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 int rc;
406
407 if (id < -1 || id > 4)
408 return;
409
410 if (id == -1)
411 id = 5;
412
413 mutex_lock(audpp->lock);
414 LOG(EV_DISABLE, 1);
415 if (!audpp->func[id])
416 goto out;
417 if (audpp->private[id] != private)
418 goto out;
419
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530420 msg[0] = AUDPP_MSG_ENA_DIS;
421 msg[1] = id;
422 rc = msm_adsp_generate_event(audpp, audpp->mod,
423 AUDPP_MSG_CFG_MSG, sizeof(msg),
424 sizeof(uint16_t), (void *)msg);
425 if (rc < 0)
426 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427
428 if (--audpp->open_count == 0) {
429 MM_DBG("disable\n");
430 LOG(EV_DISABLE, 2);
431 audpp_dsp_config(0);
432 rc = wait_event_interruptible(audpp->event_wait,
433 (audpp->enabled == 0));
434 if (audpp->enabled == 0)
435 MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
436 else
437 MM_ERR("Didn't receive CFG_MSG DISABLE \
438 message from ADSP\n");
439 msm_adsp_disable(audpp->mod);
440 msm_adsp_put(audpp->mod);
441 audpp->mod = NULL;
442 }
443out:
444 mutex_unlock(audpp->lock);
445}
446EXPORT_SYMBOL(audpp_disable);
447
448#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
449
450void audpp_avsync(int id, unsigned rate)
451{
452 unsigned long flags;
453 audpp_cmd_avsync cmd;
454
455 if (BAD_ID(id))
456 return;
457
Manish Dewangan0f90d472012-02-25 14:09:23 +0530458 spin_lock_irqsave(&the_audpp_state.avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459 if (rate)
460 the_audpp_state.avsync_mask |= (1 << id);
461 else
462 the_audpp_state.avsync_mask &= (~(1 << id));
463 the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530464 spin_unlock_irqrestore(&the_audpp_state.avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465
466 cmd.cmd_id = AUDPP_CMD_AVSYNC;
467 cmd.object_number = id;
468 cmd.interrupt_interval_lsw = rate;
469 cmd.interrupt_interval_msw = rate >> 16;
470 audpp_send_queue1(&cmd, sizeof(cmd));
471}
472EXPORT_SYMBOL(audpp_avsync);
473
474unsigned audpp_avsync_sample_count(int id)
475{
Manish Dewangan0f90d472012-02-25 14:09:23 +0530476 struct audpp_state *audpp = &the_audpp_state;
477 uint16_t *avsync = audpp->avsync;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478 unsigned val;
479 unsigned long flags;
480 unsigned mask;
481
482 if (BAD_ID(id))
483 return 0;
484
485 mask = 1 << id;
486 id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530487 spin_lock_irqsave(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 if (avsync[0] & mask)
489 val = (avsync[id] << 16) | avsync[id + 1];
490 else
491 val = 0;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530492 spin_unlock_irqrestore(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493
494 return val;
495}
496EXPORT_SYMBOL(audpp_avsync_sample_count);
497
498unsigned audpp_avsync_byte_count(int id)
499{
Manish Dewangan0f90d472012-02-25 14:09:23 +0530500 struct audpp_state *audpp = &the_audpp_state;
501 uint16_t *avsync = audpp->avsync;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 unsigned val;
503 unsigned long flags;
504 unsigned mask;
505
506 if (BAD_ID(id))
507 return 0;
508
509 mask = 1 << id;
510 id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530511 spin_lock_irqsave(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512 if (avsync[0] & mask)
513 val = (avsync[id] << 16) | avsync[id + 1];
514 else
515 val = 0;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530516 spin_unlock_irqrestore(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517
518 return val;
519}
520EXPORT_SYMBOL(audpp_avsync_byte_count);
521
522int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan)
523{
524 /* cmd, obj_cfg[7], cmd_type, volume, pan */
525 uint16_t cmd[11];
526
527 if (id > 6)
528 return -EINVAL;
529
530 memset(cmd, 0, sizeof(cmd));
531 cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
532 cmd[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
533 cmd[8] = AUDPP_CMD_VOLUME_PAN;
534 cmd[9] = volume;
535 cmd[10] = pan;
536
537 return audpp_send_queue3(cmd, sizeof(cmd));
538}
539EXPORT_SYMBOL(audpp_set_volume_and_pan);
540
541/* Implementation of COPP features */
542int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
543 audpp_cmd_cfg_object_params_mbadrc *mbadrc)
544{
545 audpp_cmd_cfg_object_params_mbadrc cmd;
546
547 if (id != 6)
548 return -EINVAL;
549
550 memset(&cmd, 0, sizeof(cmd));
551 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
552 cmd.common.command_type = AUDPP_CMD_MBADRC;
553
554 if (enable) {
555 memcpy(&cmd.num_bands, &mbadrc->num_bands,
556 sizeof(*mbadrc) -
557 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
558 cmd.enable = AUDPP_CMD_ADRC_FLAG_ENA;
559 } else
560 cmd.enable = AUDPP_CMD_ADRC_FLAG_DIS;
561
562 /*order the writes to mbadrc */
563 dma_coherent_pre_ops();
564 return audpp_send_queue3(&cmd, sizeof(cmd));
565}
566EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
567
568int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
569 audpp_cmd_cfg_object_params_qconcert *
570 qconcert_plus)
571{
572 audpp_cmd_cfg_object_params_qconcert cmd;
573 if (id != 6)
574 return -EINVAL;
575
576 memset(&cmd, 0, sizeof(cmd));
577 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
578 cmd.common.command_type = AUDPP_CMD_QCONCERT;
579
580 if (enable) {
581 memcpy(&cmd.op_mode, &qconcert_plus->op_mode,
582 sizeof(audpp_cmd_cfg_object_params_qconcert) -
583 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
584 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
585 } else
586 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
587
588 return audpp_send_queue3(&cmd, sizeof(cmd));
589}
590
591int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
592 audpp_cmd_cfg_object_params_pcm *iir)
593{
594 audpp_cmd_cfg_object_params_pcm cmd;
595
596 if (id != 6)
597 return -EINVAL;
598
599 memset(&cmd, 0, sizeof(cmd));
600 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
601 cmd.common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
602
603 if (enable) {
604 cmd.active_flag = AUDPP_CMD_IIR_FLAG_ENA;
605 cmd.num_bands = iir->num_bands;
606 memcpy(&cmd.params_filter, &iir->params_filter,
607 sizeof(iir->params_filter));
608 } else
609 cmd.active_flag = AUDPP_CMD_IIR_FLAG_DIS;
610
611 return audpp_send_queue3(&cmd, sizeof(cmd));
612}
613EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
614
Sidipotu Ashok3144aa22012-03-16 10:55:24 +0530615int audpp_dsp_set_rx_srs_trumedia_g(
616 struct audpp_cmd_cfg_object_params_srstm_g *srstm)
617{
618 struct audpp_cmd_cfg_object_params_srstm_g cmd;
619
620 MM_DBG("%s\n", __func__);
621 memset(&cmd, 0, sizeof(cmd));
622 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
623 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
624 cmd.common.command_type = AUDPP_SRS_PARAMS_G;
625
626 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
627
628 return audpp_send_queue3(&cmd, sizeof(cmd));
629}
630EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_g);
631
632int audpp_dsp_set_rx_srs_trumedia_w(
633 struct audpp_cmd_cfg_object_params_srstm_w *srstm)
634{
635 struct audpp_cmd_cfg_object_params_srstm_w cmd;
636
637 MM_DBG("%s\n", __func__);
638 memset(&cmd, 0, sizeof(cmd));
639 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
640 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
641 cmd.common.command_type = AUDPP_SRS_PARAMS_W;
642
643 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
644
645 return audpp_send_queue3(&cmd, sizeof(cmd));
646}
647EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_w);
648
649int audpp_dsp_set_rx_srs_trumedia_c(
650 struct audpp_cmd_cfg_object_params_srstm_c *srstm)
651{
652 struct audpp_cmd_cfg_object_params_srstm_c cmd;
653
654 MM_DBG("%s\n", __func__);
655 memset(&cmd, 0, sizeof(cmd));
656 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
657 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
658 cmd.common.command_type = AUDPP_SRS_PARAMS_C;
659
660 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
661
662 return audpp_send_queue3(&cmd, sizeof(cmd));
663}
664EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_c);
665
666int audpp_dsp_set_rx_srs_trumedia_h(
667 struct audpp_cmd_cfg_object_params_srstm_h *srstm)
668{
669 struct audpp_cmd_cfg_object_params_srstm_h cmd;
670
671 MM_DBG("%s\n", __func__);
672 memset(&cmd, 0, sizeof(cmd));
673 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
674 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
675 cmd.common.command_type = AUDPP_SRS_PARAMS_H;
676
677 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
678
679 return audpp_send_queue3(&cmd, sizeof(cmd));
680}
681EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_h);
682
683int audpp_dsp_set_rx_srs_trumedia_p(
684 struct audpp_cmd_cfg_object_params_srstm_p *srstm)
685{
686 struct audpp_cmd_cfg_object_params_srstm_p cmd;
687
688 MM_DBG("%s\n", __func__);
689 memset(&cmd, 0, sizeof(cmd));
690 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
691 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
692 cmd.common.command_type = AUDPP_SRS_PARAMS_P;
693
694 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
695
696 return audpp_send_queue3(&cmd, sizeof(cmd));
697}
698EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_p);
699
700int audpp_dsp_set_rx_srs_trumedia_l(
701 struct audpp_cmd_cfg_object_params_srstm_l *srstm)
702{
703 struct audpp_cmd_cfg_object_params_srstm_l cmd;
704
705 MM_DBG("%s\n", __func__);
706 memset(&cmd, 0, sizeof(cmd));
707 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
708 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
709 cmd.common.command_type = AUDPP_SRS_PARAMS_L;
710
711 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
712
713 return audpp_send_queue3(&cmd, sizeof(cmd));
714}
715EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_l);
716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700717/* Implementation Of COPP + POPP */
718int audpp_dsp_set_eq(unsigned id, unsigned enable,
719 audpp_cmd_cfg_object_params_eqalizer *eq)
720{
721 audpp_cmd_cfg_object_params_eqalizer cmd;
722 unsigned short *id_ptr = (unsigned short *)&cmd;
723
724 if (id > 6 || id == 5)
725 return -EINVAL;
726
727 memset(&cmd, 0, sizeof(cmd));
728 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
729 cmd.common.command_type = AUDPP_CMD_EQUALIZER;
730
731 if (enable) {
732 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
733 cmd.num_bands = eq->num_bands;
734 memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
735 } else
736 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
737
738 return audpp_send_queue3(&cmd, sizeof(cmd));
739}
740EXPORT_SYMBOL(audpp_dsp_set_eq);
741
742int audpp_dsp_set_vol_pan(unsigned id,
743 audpp_cmd_cfg_object_params_volume *vol_pan)
744{
745 audpp_cmd_cfg_object_params_volume cmd;
746 unsigned short *id_ptr = (unsigned short *)&cmd;
747
748 if (id > 6)
749 return -EINVAL;
750
751 memset(&cmd, 0, sizeof(cmd));
752 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
753 cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
754
755 cmd.volume = vol_pan->volume;
756 cmd.pan = vol_pan->pan;
757
758 return audpp_send_queue3(&cmd, sizeof(cmd));
759}
760EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
761
762int audpp_pause(unsigned id, int pause)
763{
764 /* pause 1 = pause 0 = resume */
765 u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
766
767 if (id >= CH_COUNT)
768 return -EINVAL;
769
770 memset(pause_cmd, 0, sizeof(pause_cmd));
771
772 pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
773 if (pause == 1)
774 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
775 else if (pause == 0)
776 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
777 else
778 return -EINVAL;
779
780 return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
781}
782EXPORT_SYMBOL(audpp_pause);
783
784int audpp_flush(unsigned id)
785{
786 u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
787
788 if (id >= CH_COUNT)
789 return -EINVAL;
790
791 memset(flush_cmd, 0, sizeof(flush_cmd));
792
793 flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
794 flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
795
796 return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
797}
798EXPORT_SYMBOL(audpp_flush);
799
800/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
801 * like mp3, aac, wma etc ... *
802 * = 15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
803 * = 31:16, reserved */
804int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
805 unsigned *queueid)
806{
807 struct audpp_state *audpp = &the_audpp_state;
808 int decid = -1, idx, lidx, mode, codec;
809 int codecs_supported, min_codecs_supported;
810 unsigned int *concurrency_entry;
811 mutex_lock(audpp->lock_dec);
812 /* Represents in bit mask */
813 mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
814 codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
815 /* Point to Last entry of the row */
816 concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
817 ((audpp->concurrency + 1) *
818 (audpp->dec_database->num_dec))) - 1);
819
820 lidx = audpp->dec_database->num_dec;
821 min_codecs_supported = sizeof(unsigned int) * 8;
822
823 MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
824
825 for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
826 if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
827 if ((mode & *concurrency_entry) &&
828 (codec & *concurrency_entry)) {
829 /* Check supports minimum number codecs */
830 codecs_supported =
831 audpp->dec_database->dec_info_list[idx -
832 1].
833 nr_codec_support;
834 if (codecs_supported < min_codecs_supported) {
835 lidx = idx - 1;
836 min_codecs_supported = codecs_supported;
837 }
838 }
839 }
840 }
841
842 if (lidx < audpp->dec_database->num_dec) {
843 audpp->dec_inuse |= (1 << lidx);
844 *module_name =
845 audpp->dec_database->dec_info_list[lidx].module_name;
846 *queueid =
847 audpp->dec_database->dec_info_list[lidx].module_queueid;
848 decid = audpp->dec_database->dec_info_list[lidx].module_decid;
849 audpp->dec_info_table[lidx].codec =
850 (dec_attrb & AUDPP_CODEC_MASK);
851 audpp->dec_info_table[lidx].pid = current->pid;
852 /* point to row to get supported operation */
853 concurrency_entry =
854 ((audpp->dec_database->dec_concurrency_table +
855 ((audpp->concurrency) * (audpp->dec_database->num_dec))) +
856 lidx);
857 decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
858 MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n",
859 decid, *module_name, *queueid);
860 }
861 mutex_unlock(audpp->lock_dec);
862 return decid;
863
864}
865EXPORT_SYMBOL(audpp_adec_alloc);
866
867void audpp_adec_free(int decid)
868{
869 struct audpp_state *audpp = &the_audpp_state;
870 int idx;
871 mutex_lock(audpp->lock_dec);
872 for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
873 if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
874 decid) {
875 audpp->dec_inuse &= ~(1 << (idx - 1));
876 audpp->dec_info_table[idx - 1].codec = -1;
877 audpp->dec_info_table[idx - 1].pid = 0;
878 MM_INFO("free decid =%d \n", decid);
879 break;
880 }
881 }
882 mutex_unlock(audpp->lock_dec);
883 return;
884
885}
886EXPORT_SYMBOL(audpp_adec_free);
887
888static ssize_t concurrency_show(struct device *dev,
889 struct device_attribute *attr, char *buf)
890{
891 struct audpp_state *audpp = &the_audpp_state;
892 int rc;
893 mutex_lock(audpp->lock_dec);
894 rc = sprintf(buf, "%ld\n", audpp->concurrency);
895 mutex_unlock(audpp->lock_dec);
896 return rc;
897}
898
899static ssize_t concurrency_store(struct device *dev,
900 struct device_attribute *attr,
901 const char *buf, size_t count)
902{
903 struct audpp_state *audpp = &the_audpp_state;
904 unsigned long concurrency;
905 int rc = -1;
906 mutex_lock(audpp->lock_dec);
907 if (audpp->dec_inuse) {
908 MM_ERR("Can not change profile, while playback in progress\n");
909 goto done;
910 }
911 rc = strict_strtoul(buf, 10, &concurrency);
912 if (!rc &&
913 (concurrency < audpp->dec_database->num_concurrency_support)) {
914 audpp->concurrency = concurrency;
915 MM_DBG("Concurrency case %ld\n", audpp->concurrency);
916 rc = count;
917 } else {
918 MM_ERR("Not a valid Concurrency case\n");
919 rc = -EINVAL;
920 }
921done:
922 mutex_unlock(audpp->lock_dec);
923 return rc;
924}
925
926static ssize_t decoder_info_show(struct device *dev,
927 struct device_attribute *attr, char *buf);
928static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
929 __ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
930 __ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
931 __ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
932 __ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
933 __ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
934};
935
936static ssize_t decoder_info_show(struct device *dev,
937 struct device_attribute *attr, char *buf)
938{
939 int cpy_sz = 0;
940 struct audpp_state *audpp = &the_audpp_state;
941 const ptrdiff_t off = attr - dev_attr_decoder; /* decoder number */
942 mutex_lock(audpp->lock_dec);
943 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
944 audpp->dec_info_table[off].codec);
945 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
946 audpp->dec_info_table[off].pid);
947 mutex_unlock(audpp->lock_dec);
948 return cpy_sz;
949}
950
951static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
952 concurrency_store);
953static int audpp_probe(struct platform_device *pdev)
954{
955 int rc, idx;
956 struct audpp_state *audpp = &the_audpp_state;
957 audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
958 audpp->dec_database =
959 (struct msm_adspdec_database *)pdev->dev.platform_data;
960
961 MM_INFO("Number of decoder supported %d\n",
962 audpp->dec_database->num_dec);
963 MM_INFO("Number of concurrency supported %d\n",
964 audpp->dec_database->num_concurrency_support);
965
966 init_waitqueue_head(&audpp->event_wait);
967
Manish Dewangan0f90d472012-02-25 14:09:23 +0530968 spin_lock_init(&audpp->avsync_lock);
969
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
971 audpp->dec_info_table[idx].codec = -1;
972 audpp->dec_info_table[idx].pid = 0;
973 MM_INFO("module_name:%s\n",
974 audpp->dec_database->dec_info_list[idx].module_name);
975 MM_INFO("queueid:%d\n",
976 audpp->dec_database->dec_info_list[idx].module_queueid);
977 MM_INFO("decid:%d\n",
978 audpp->dec_database->dec_info_list[idx].module_decid);
979 MM_INFO("nr_codec_support:%d\n",
980 audpp->dec_database->dec_info_list[idx].
981 nr_codec_support);
982 }
983
984 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
985 rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
986 if (rc)
987 goto err;
988 }
989 rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
990 if (rc)
991 goto err;
992 else
993 goto done;
994err:
995 while (idx--)
996 device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
997done:
998 return rc;
999}
1000
1001static struct platform_driver audpp_plat_driver = {
1002 .probe = audpp_probe,
1003 .driver = {
1004 .name = "msm_adspdec",
1005 .owner = THIS_MODULE,
1006 },
1007};
1008
1009static int __init audpp_init(void)
1010{
1011 return platform_driver_register(&audpp_plat_driver);
1012}
1013
1014device_initcall(audpp_init);