blob: 2dbb5dc0d721525a3707ef7ad590304de66b79f2 [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
Manish Dewangan0f90d472012-02-25 14:09:23 +0530127 spinlock_t avsync_lock;
128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 wait_queue_head_t event_wait;
130};
131
132struct audpp_state the_audpp_state = {
133 .lock = &audpp_lock,
134 .lock_dec = &audpp_dec_lock,
135};
136
137int audpp_send_queue1(void *cmd, unsigned len)
138{
139 return msm_adsp_write(the_audpp_state.mod,
140 QDSP_uPAudPPCmd1Queue, cmd, len);
141}
142EXPORT_SYMBOL(audpp_send_queue1);
143
144int audpp_send_queue2(void *cmd, unsigned len)
145{
146 return msm_adsp_write(the_audpp_state.mod,
147 QDSP_uPAudPPCmd2Queue, cmd, len);
148}
149EXPORT_SYMBOL(audpp_send_queue2);
150
151int audpp_send_queue3(void *cmd, unsigned len)
152{
153 return msm_adsp_write(the_audpp_state.mod,
154 QDSP_uPAudPPCmd3Queue, cmd, len);
155}
156EXPORT_SYMBOL(audpp_send_queue3);
157
158static int audpp_dsp_config(int enable)
159{
160 audpp_cmd_cfg cmd;
161
162 cmd.cmd_id = AUDPP_CMD_CFG;
163 cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
164
165 return audpp_send_queue1(&cmd, sizeof(cmd));
166}
167
168int is_audpp_enable(void)
169{
170 struct audpp_state *audpp = &the_audpp_state;
171
172 return audpp->enabled;
173}
174EXPORT_SYMBOL(is_audpp_enable);
175
176int audpp_register_event_callback(struct audpp_event_callback *ecb)
177{
178 struct audpp_state *audpp = &the_audpp_state;
179 int i;
180
181 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
182 if (NULL == audpp->cb_tbl[i]) {
183 audpp->cb_tbl[i] = ecb;
184 return 0;
185 }
186 }
187 return -1;
188}
189EXPORT_SYMBOL(audpp_register_event_callback);
190
191int audpp_unregister_event_callback(struct audpp_event_callback *ecb)
192{
193 struct audpp_state *audpp = &the_audpp_state;
194 int i;
195
196 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
197 if (ecb == audpp->cb_tbl[i]) {
198 audpp->cb_tbl[i] = NULL;
199 return 0;
200 }
201 }
202 return -1;
203}
204EXPORT_SYMBOL(audpp_unregister_event_callback);
205
206static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
207 uint16_t *msg)
208{
209 unsigned n;
210 for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
211 if (audpp->func[n])
212 audpp->func[n] (audpp->private[n], id, msg);
213 }
214
215 for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
216 if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
217 audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private, id,
218 msg);
219}
220
221static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
222 unsigned id, uint16_t *msg)
223{
224 if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
225 audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
226}
227
228static void audpp_handle_pcmdmamiss(struct audpp_state *audpp,
229 uint16_t bit_mask)
230{
231 uint8_t b_index;
232
233 for (b_index = 0; b_index < AUDPP_CLNT_MAX_COUNT; b_index++) {
234 if (bit_mask & (0x1 << b_index))
235 if (audpp->func[b_index])
236 audpp->func[b_index] (audpp->private[b_index],
237 AUDPP_MSG_PCMDMAMISSED,
238 &bit_mask);
239 }
240}
241
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530242static void audpp_fake_event(struct audpp_state *audpp, int id,
243 unsigned event, unsigned arg)
244{
245 uint16_t msg[1];
246 msg[0] = arg;
247 audpp->func[id] (audpp->private[id], event, msg);
248}
249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250static void audpp_dsp_event(void *data, unsigned id, size_t len,
251 void (*getevent) (void *ptr, size_t len))
252{
253 struct audpp_state *audpp = data;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530254 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255 uint16_t msg[8];
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530256 int cid = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257
258 if (id == AUDPP_MSG_AVSYNC_MSG) {
Manish Dewangan0f90d472012-02-25 14:09:23 +0530259 spin_lock_irqsave(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260 getevent(audpp->avsync, sizeof(audpp->avsync));
261
262 /* mask off any channels we're not watching to avoid
263 * cases where we might get one last update after
264 * disabling avsync and end up in an odd state when
265 * we next read...
266 */
267 audpp->avsync[0] &= audpp->avsync_mask;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530268 spin_unlock_irqrestore(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 return;
270 }
271
272 getevent(msg, sizeof(msg));
273
274 LOG(EV_EVENT, (id << 16) | msg[0]);
275 LOG(EV_DATA, (msg[1] << 16) | msg[2]);
276
277 switch (id) {
278 case AUDPP_MSG_STATUS_MSG:{
279 unsigned cid = msg[0];
280 MM_DBG("status %d %d %d\n", cid, msg[1], msg[2]);
281 if ((cid < 5) && audpp->func[cid])
282 audpp->func[cid] (audpp->private[cid], id, msg);
283 break;
284 }
285 case AUDPP_MSG_HOST_PCM_INTF_MSG:
286 if (audpp->func[5])
287 audpp->func[5] (audpp->private[5], id, msg);
288 break;
289 case AUDPP_MSG_PCMDMAMISSED:
290 audpp_handle_pcmdmamiss(audpp, msg[0]);
291 break;
292 case AUDPP_MSG_CFG_MSG:
293 if (msg[0] == AUDPP_MSG_ENA_ENA) {
294 MM_INFO("ENABLE\n");
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530295 if (!audpp->enabled) {
296 audpp->enabled = 1;
297 audpp_broadcast(audpp, id, msg);
298 } else {
299 cid = msg[1];
300 audpp_fake_event(audpp, cid,
301 id, AUDPP_MSG_ENA_ENA);
302 }
303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530305 if (audpp->open_count == 0) {
306 MM_INFO("DISABLE\n");
307 audpp->enabled = 0;
308 wake_up(&audpp->event_wait);
309 audpp_broadcast(audpp, id, msg);
310 } else {
311 cid = msg[1];
312 audpp_fake_event(audpp, cid,
313 id, AUDPP_MSG_ENA_DIS);
314 audpp->func[cid] = NULL;
315 audpp->private[cid] = NULL;
316 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 } else {
318 MM_ERR("invalid config msg %d\n", msg[0]);
319 }
320 break;
321 case AUDPP_MSG_ROUTING_ACK:
322 audpp_notify_clnt(audpp, msg[0], id, msg);
323 break;
324 case AUDPP_MSG_FLUSH_ACK:
325 audpp_notify_clnt(audpp, msg[0], id, msg);
326 break;
327 case ADSP_MESSAGE_ID:
328 MM_DBG("Received ADSP event: module enable/disable(audpptask)");
329 break;
330 default:
331 MM_ERR("unhandled msg id %x\n", id);
332 }
333}
334
335static struct msm_adsp_ops adsp_ops = {
336 .event = audpp_dsp_event,
337};
338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339int audpp_enable(int id, audpp_event_func func, void *private)
340{
341 struct audpp_state *audpp = &the_audpp_state;
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530342 uint16_t msg[8];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 int res = 0;
344
345 if (id < -1 || id > 4)
346 return -EINVAL;
347
348 if (id == -1)
349 id = 5;
350
351 mutex_lock(audpp->lock);
352 if (audpp->func[id]) {
353 res = -EBUSY;
354 goto out;
355 }
356
357 audpp->func[id] = func;
358 audpp->private[id] = private;
359
360 LOG(EV_ENABLE, 1);
361 if (audpp->open_count++ == 0) {
362 MM_DBG("enable\n");
363 res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
364 if (res < 0) {
365 MM_ERR("cannot open AUDPPTASK\n");
366 audpp->open_count = 0;
367 audpp->func[id] = NULL;
368 audpp->private[id] = NULL;
369 goto out;
370 }
371 LOG(EV_ENABLE, 2);
372 msm_adsp_enable(audpp->mod);
373 audpp_dsp_config(1);
374 } else {
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530375 if (audpp->enabled) {
376 msg[0] = AUDPP_MSG_ENA_ENA;
377 msg[1] = id;
378 res = msm_adsp_generate_event(audpp, audpp->mod,
379 AUDPP_MSG_CFG_MSG, sizeof(msg),
380 sizeof(uint16_t), (void *)msg);
381 if (res < 0)
382 goto out;
383 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 }
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;
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530396 uint16_t msg[8];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 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
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530412 msg[0] = AUDPP_MSG_ENA_DIS;
413 msg[1] = id;
414 rc = msm_adsp_generate_event(audpp, audpp->mod,
415 AUDPP_MSG_CFG_MSG, sizeof(msg),
416 sizeof(uint16_t), (void *)msg);
417 if (rc < 0)
418 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419
420 if (--audpp->open_count == 0) {
421 MM_DBG("disable\n");
422 LOG(EV_DISABLE, 2);
423 audpp_dsp_config(0);
424 rc = wait_event_interruptible(audpp->event_wait,
425 (audpp->enabled == 0));
426 if (audpp->enabled == 0)
427 MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
428 else
429 MM_ERR("Didn't receive CFG_MSG DISABLE \
430 message from ADSP\n");
431 msm_adsp_disable(audpp->mod);
432 msm_adsp_put(audpp->mod);
433 audpp->mod = NULL;
434 }
435out:
436 mutex_unlock(audpp->lock);
437}
438EXPORT_SYMBOL(audpp_disable);
439
440#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
441
442void audpp_avsync(int id, unsigned rate)
443{
444 unsigned long flags;
445 audpp_cmd_avsync cmd;
446
447 if (BAD_ID(id))
448 return;
449
Manish Dewangan0f90d472012-02-25 14:09:23 +0530450 spin_lock_irqsave(&the_audpp_state.avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451 if (rate)
452 the_audpp_state.avsync_mask |= (1 << id);
453 else
454 the_audpp_state.avsync_mask &= (~(1 << id));
455 the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530456 spin_unlock_irqrestore(&the_audpp_state.avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457
458 cmd.cmd_id = AUDPP_CMD_AVSYNC;
459 cmd.object_number = id;
460 cmd.interrupt_interval_lsw = rate;
461 cmd.interrupt_interval_msw = rate >> 16;
462 audpp_send_queue1(&cmd, sizeof(cmd));
463}
464EXPORT_SYMBOL(audpp_avsync);
465
466unsigned audpp_avsync_sample_count(int id)
467{
Manish Dewangan0f90d472012-02-25 14:09:23 +0530468 struct audpp_state *audpp = &the_audpp_state;
469 uint16_t *avsync = audpp->avsync;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 unsigned val;
471 unsigned long flags;
472 unsigned mask;
473
474 if (BAD_ID(id))
475 return 0;
476
477 mask = 1 << id;
478 id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530479 spin_lock_irqsave(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 if (avsync[0] & mask)
481 val = (avsync[id] << 16) | avsync[id + 1];
482 else
483 val = 0;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530484 spin_unlock_irqrestore(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485
486 return val;
487}
488EXPORT_SYMBOL(audpp_avsync_sample_count);
489
490unsigned audpp_avsync_byte_count(int id)
491{
Manish Dewangan0f90d472012-02-25 14:09:23 +0530492 struct audpp_state *audpp = &the_audpp_state;
493 uint16_t *avsync = audpp->avsync;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494 unsigned val;
495 unsigned long flags;
496 unsigned mask;
497
498 if (BAD_ID(id))
499 return 0;
500
501 mask = 1 << id;
502 id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530503 spin_lock_irqsave(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 if (avsync[0] & mask)
505 val = (avsync[id] << 16) | avsync[id + 1];
506 else
507 val = 0;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530508 spin_unlock_irqrestore(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509
510 return val;
511}
512EXPORT_SYMBOL(audpp_avsync_byte_count);
513
514int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan)
515{
516 /* cmd, obj_cfg[7], cmd_type, volume, pan */
517 uint16_t cmd[11];
518
519 if (id > 6)
520 return -EINVAL;
521
522 memset(cmd, 0, sizeof(cmd));
523 cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
524 cmd[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
525 cmd[8] = AUDPP_CMD_VOLUME_PAN;
526 cmd[9] = volume;
527 cmd[10] = pan;
528
529 return audpp_send_queue3(cmd, sizeof(cmd));
530}
531EXPORT_SYMBOL(audpp_set_volume_and_pan);
532
533/* Implementation of COPP features */
534int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
535 audpp_cmd_cfg_object_params_mbadrc *mbadrc)
536{
537 audpp_cmd_cfg_object_params_mbadrc cmd;
538
539 if (id != 6)
540 return -EINVAL;
541
542 memset(&cmd, 0, sizeof(cmd));
543 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
544 cmd.common.command_type = AUDPP_CMD_MBADRC;
545
546 if (enable) {
547 memcpy(&cmd.num_bands, &mbadrc->num_bands,
548 sizeof(*mbadrc) -
549 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
550 cmd.enable = AUDPP_CMD_ADRC_FLAG_ENA;
551 } else
552 cmd.enable = AUDPP_CMD_ADRC_FLAG_DIS;
553
554 /*order the writes to mbadrc */
555 dma_coherent_pre_ops();
556 return audpp_send_queue3(&cmd, sizeof(cmd));
557}
558EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
559
560int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
561 audpp_cmd_cfg_object_params_qconcert *
562 qconcert_plus)
563{
564 audpp_cmd_cfg_object_params_qconcert cmd;
565 if (id != 6)
566 return -EINVAL;
567
568 memset(&cmd, 0, sizeof(cmd));
569 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
570 cmd.common.command_type = AUDPP_CMD_QCONCERT;
571
572 if (enable) {
573 memcpy(&cmd.op_mode, &qconcert_plus->op_mode,
574 sizeof(audpp_cmd_cfg_object_params_qconcert) -
575 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
576 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
577 } else
578 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
579
580 return audpp_send_queue3(&cmd, sizeof(cmd));
581}
582
583int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
584 audpp_cmd_cfg_object_params_pcm *iir)
585{
586 audpp_cmd_cfg_object_params_pcm cmd;
587
588 if (id != 6)
589 return -EINVAL;
590
591 memset(&cmd, 0, sizeof(cmd));
592 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
593 cmd.common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
594
595 if (enable) {
596 cmd.active_flag = AUDPP_CMD_IIR_FLAG_ENA;
597 cmd.num_bands = iir->num_bands;
598 memcpy(&cmd.params_filter, &iir->params_filter,
599 sizeof(iir->params_filter));
600 } else
601 cmd.active_flag = AUDPP_CMD_IIR_FLAG_DIS;
602
603 return audpp_send_queue3(&cmd, sizeof(cmd));
604}
605EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
606
607/* Implementation Of COPP + POPP */
608int audpp_dsp_set_eq(unsigned id, unsigned enable,
609 audpp_cmd_cfg_object_params_eqalizer *eq)
610{
611 audpp_cmd_cfg_object_params_eqalizer cmd;
612 unsigned short *id_ptr = (unsigned short *)&cmd;
613
614 if (id > 6 || id == 5)
615 return -EINVAL;
616
617 memset(&cmd, 0, sizeof(cmd));
618 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
619 cmd.common.command_type = AUDPP_CMD_EQUALIZER;
620
621 if (enable) {
622 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
623 cmd.num_bands = eq->num_bands;
624 memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
625 } else
626 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
627
628 return audpp_send_queue3(&cmd, sizeof(cmd));
629}
630EXPORT_SYMBOL(audpp_dsp_set_eq);
631
632int audpp_dsp_set_vol_pan(unsigned id,
633 audpp_cmd_cfg_object_params_volume *vol_pan)
634{
635 audpp_cmd_cfg_object_params_volume cmd;
636 unsigned short *id_ptr = (unsigned short *)&cmd;
637
638 if (id > 6)
639 return -EINVAL;
640
641 memset(&cmd, 0, sizeof(cmd));
642 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
643 cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
644
645 cmd.volume = vol_pan->volume;
646 cmd.pan = vol_pan->pan;
647
648 return audpp_send_queue3(&cmd, sizeof(cmd));
649}
650EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
651
652int audpp_pause(unsigned id, int pause)
653{
654 /* pause 1 = pause 0 = resume */
655 u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
656
657 if (id >= CH_COUNT)
658 return -EINVAL;
659
660 memset(pause_cmd, 0, sizeof(pause_cmd));
661
662 pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
663 if (pause == 1)
664 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
665 else if (pause == 0)
666 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
667 else
668 return -EINVAL;
669
670 return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
671}
672EXPORT_SYMBOL(audpp_pause);
673
674int audpp_flush(unsigned id)
675{
676 u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
677
678 if (id >= CH_COUNT)
679 return -EINVAL;
680
681 memset(flush_cmd, 0, sizeof(flush_cmd));
682
683 flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
684 flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
685
686 return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
687}
688EXPORT_SYMBOL(audpp_flush);
689
690/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
691 * like mp3, aac, wma etc ... *
692 * = 15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
693 * = 31:16, reserved */
694int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
695 unsigned *queueid)
696{
697 struct audpp_state *audpp = &the_audpp_state;
698 int decid = -1, idx, lidx, mode, codec;
699 int codecs_supported, min_codecs_supported;
700 unsigned int *concurrency_entry;
701 mutex_lock(audpp->lock_dec);
702 /* Represents in bit mask */
703 mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
704 codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
705 /* Point to Last entry of the row */
706 concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
707 ((audpp->concurrency + 1) *
708 (audpp->dec_database->num_dec))) - 1);
709
710 lidx = audpp->dec_database->num_dec;
711 min_codecs_supported = sizeof(unsigned int) * 8;
712
713 MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
714
715 for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
716 if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
717 if ((mode & *concurrency_entry) &&
718 (codec & *concurrency_entry)) {
719 /* Check supports minimum number codecs */
720 codecs_supported =
721 audpp->dec_database->dec_info_list[idx -
722 1].
723 nr_codec_support;
724 if (codecs_supported < min_codecs_supported) {
725 lidx = idx - 1;
726 min_codecs_supported = codecs_supported;
727 }
728 }
729 }
730 }
731
732 if (lidx < audpp->dec_database->num_dec) {
733 audpp->dec_inuse |= (1 << lidx);
734 *module_name =
735 audpp->dec_database->dec_info_list[lidx].module_name;
736 *queueid =
737 audpp->dec_database->dec_info_list[lidx].module_queueid;
738 decid = audpp->dec_database->dec_info_list[lidx].module_decid;
739 audpp->dec_info_table[lidx].codec =
740 (dec_attrb & AUDPP_CODEC_MASK);
741 audpp->dec_info_table[lidx].pid = current->pid;
742 /* point to row to get supported operation */
743 concurrency_entry =
744 ((audpp->dec_database->dec_concurrency_table +
745 ((audpp->concurrency) * (audpp->dec_database->num_dec))) +
746 lidx);
747 decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
748 MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n",
749 decid, *module_name, *queueid);
750 }
751 mutex_unlock(audpp->lock_dec);
752 return decid;
753
754}
755EXPORT_SYMBOL(audpp_adec_alloc);
756
757void audpp_adec_free(int decid)
758{
759 struct audpp_state *audpp = &the_audpp_state;
760 int idx;
761 mutex_lock(audpp->lock_dec);
762 for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
763 if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
764 decid) {
765 audpp->dec_inuse &= ~(1 << (idx - 1));
766 audpp->dec_info_table[idx - 1].codec = -1;
767 audpp->dec_info_table[idx - 1].pid = 0;
768 MM_INFO("free decid =%d \n", decid);
769 break;
770 }
771 }
772 mutex_unlock(audpp->lock_dec);
773 return;
774
775}
776EXPORT_SYMBOL(audpp_adec_free);
777
778static ssize_t concurrency_show(struct device *dev,
779 struct device_attribute *attr, char *buf)
780{
781 struct audpp_state *audpp = &the_audpp_state;
782 int rc;
783 mutex_lock(audpp->lock_dec);
784 rc = sprintf(buf, "%ld\n", audpp->concurrency);
785 mutex_unlock(audpp->lock_dec);
786 return rc;
787}
788
789static ssize_t concurrency_store(struct device *dev,
790 struct device_attribute *attr,
791 const char *buf, size_t count)
792{
793 struct audpp_state *audpp = &the_audpp_state;
794 unsigned long concurrency;
795 int rc = -1;
796 mutex_lock(audpp->lock_dec);
797 if (audpp->dec_inuse) {
798 MM_ERR("Can not change profile, while playback in progress\n");
799 goto done;
800 }
801 rc = strict_strtoul(buf, 10, &concurrency);
802 if (!rc &&
803 (concurrency < audpp->dec_database->num_concurrency_support)) {
804 audpp->concurrency = concurrency;
805 MM_DBG("Concurrency case %ld\n", audpp->concurrency);
806 rc = count;
807 } else {
808 MM_ERR("Not a valid Concurrency case\n");
809 rc = -EINVAL;
810 }
811done:
812 mutex_unlock(audpp->lock_dec);
813 return rc;
814}
815
816static ssize_t decoder_info_show(struct device *dev,
817 struct device_attribute *attr, char *buf);
818static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
819 __ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
820 __ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
821 __ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
822 __ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
823 __ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
824};
825
826static ssize_t decoder_info_show(struct device *dev,
827 struct device_attribute *attr, char *buf)
828{
829 int cpy_sz = 0;
830 struct audpp_state *audpp = &the_audpp_state;
831 const ptrdiff_t off = attr - dev_attr_decoder; /* decoder number */
832 mutex_lock(audpp->lock_dec);
833 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
834 audpp->dec_info_table[off].codec);
835 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
836 audpp->dec_info_table[off].pid);
837 mutex_unlock(audpp->lock_dec);
838 return cpy_sz;
839}
840
841static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
842 concurrency_store);
843static int audpp_probe(struct platform_device *pdev)
844{
845 int rc, idx;
846 struct audpp_state *audpp = &the_audpp_state;
847 audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
848 audpp->dec_database =
849 (struct msm_adspdec_database *)pdev->dev.platform_data;
850
851 MM_INFO("Number of decoder supported %d\n",
852 audpp->dec_database->num_dec);
853 MM_INFO("Number of concurrency supported %d\n",
854 audpp->dec_database->num_concurrency_support);
855
856 init_waitqueue_head(&audpp->event_wait);
857
Manish Dewangan0f90d472012-02-25 14:09:23 +0530858 spin_lock_init(&audpp->avsync_lock);
859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
861 audpp->dec_info_table[idx].codec = -1;
862 audpp->dec_info_table[idx].pid = 0;
863 MM_INFO("module_name:%s\n",
864 audpp->dec_database->dec_info_list[idx].module_name);
865 MM_INFO("queueid:%d\n",
866 audpp->dec_database->dec_info_list[idx].module_queueid);
867 MM_INFO("decid:%d\n",
868 audpp->dec_database->dec_info_list[idx].module_decid);
869 MM_INFO("nr_codec_support:%d\n",
870 audpp->dec_database->dec_info_list[idx].
871 nr_codec_support);
872 }
873
874 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
875 rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
876 if (rc)
877 goto err;
878 }
879 rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
880 if (rc)
881 goto err;
882 else
883 goto done;
884err:
885 while (idx--)
886 device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
887done:
888 return rc;
889}
890
891static struct platform_driver audpp_plat_driver = {
892 .probe = audpp_probe,
893 .driver = {
894 .name = "msm_adspdec",
895 .owner = THIS_MODULE,
896 },
897};
898
899static int __init audpp_init(void)
900{
901 return platform_driver_register(&audpp_plat_driver);
902}
903
904device_initcall(audpp_init);