blob: b4ead5c234f075cb5f2503cceece9ce3f88ea887 [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>
Manish Dewanganfa8a6b62012-07-09 16:23:27 +053037#include <mach/qdsp5/qdsp5audpp.h>
Manish Dewanganca859722012-07-09 18:21:42 +053038#include <mach/qdsp5v2/audio_acdbi.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039#include <mach/debug_mm.h>
40
41#include "evlog.h"
42
43enum {
44 EV_NULL,
45 EV_ENABLE,
46 EV_DISABLE,
47 EV_EVENT,
48 EV_DATA,
49};
50
51static const char *dsp_log_strings[] = {
52 "NULL",
53 "ENABLE",
54 "DISABLE",
55 "EVENT",
56 "DATA",
57};
58
59DECLARE_LOG(dsp_log, 64, dsp_log_strings);
60
61static int __init _dsp_log_init(void)
62{
63 return ev_log_init(&dsp_log);
64}
65
66module_init(_dsp_log_init);
67#define LOG(id,arg) ev_log_write(&dsp_log, id, arg)
68
69static DEFINE_MUTEX(audpp_lock);
70static DEFINE_MUTEX(audpp_dec_lock);
71
72#define CH_COUNT 5
73#define AUDPP_CLNT_MAX_COUNT 6
74#define AUDPP_AVSYNC_INFO_SIZE 7
75
Sidipotu Ashok3144aa22012-03-16 10:55:24 +053076#define AUDPP_SRS_PARAMS 2
77#define AUDPP_SRS_PARAMS_G 0
78#define AUDPP_SRS_PARAMS_W 1
79#define AUDPP_SRS_PARAMS_C 2
80#define AUDPP_SRS_PARAMS_H 3
81#define AUDPP_SRS_PARAMS_P 4
82#define AUDPP_SRS_PARAMS_L 5
83
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
85#define AUDPP_CMD_EQ_FLAG_DIS 0x0000
86#define AUDPP_CMD_EQ_FLAG_ENA -1
87#define AUDPP_CMD_IIR_FLAG_DIS 0x0000
88#define AUDPP_CMD_IIR_FLAG_ENA -1
89
Manish Dewanganca859722012-07-09 18:21:42 +053090#define MAX_EVENT_CALLBACK_CLIENTS 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091
92#define AUDPP_CONCURRENCY_DEFAULT 6 /* All non tunnel mode */
93#define AUDPP_MAX_DECODER_CNT 5
94#define AUDPP_CODEC_MASK 0x000000FF
95#define AUDPP_MODE_MASK 0x00000F00
96#define AUDPP_OP_MASK 0xF0000000
97
98struct audpp_decoder_info {
99 unsigned int codec;
100 pid_t pid;
101};
102
103struct audpp_state {
104 struct msm_adsp_module *mod;
105 audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
106 void *private[AUDPP_CLNT_MAX_COUNT];
107 struct mutex *lock;
108 unsigned open_count;
109 unsigned enabled;
110
111 /* Related to decoder allocation */
112 struct mutex *lock_dec;
113 struct msm_adspdec_database *dec_database;
114 struct audpp_decoder_info dec_info_table[AUDPP_MAX_DECODER_CNT];
115 unsigned dec_inuse;
116 unsigned long concurrency;
117
118 /* which channels are actually enabled */
119 unsigned avsync_mask;
120
121 /* flags, 48 bits sample/bytes counter per channel */
122 uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
123 struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
124
Manish Dewangan0f90d472012-02-25 14:09:23 +0530125 spinlock_t avsync_lock;
126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 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;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530252 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 uint16_t msg[8];
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530254 int cid = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255
256 if (id == AUDPP_MSG_AVSYNC_MSG) {
Manish Dewangan0f90d472012-02-25 14:09:23 +0530257 spin_lock_irqsave(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 getevent(audpp->avsync, sizeof(audpp->avsync));
259
260 /* mask off any channels we're not watching to avoid
261 * cases where we might get one last update after
262 * disabling avsync and end up in an odd state when
263 * we next read...
264 */
265 audpp->avsync[0] &= audpp->avsync_mask;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530266 spin_unlock_irqrestore(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 return;
268 }
269
270 getevent(msg, sizeof(msg));
271
272 LOG(EV_EVENT, (id << 16) | msg[0]);
273 LOG(EV_DATA, (msg[1] << 16) | msg[2]);
274
275 switch (id) {
276 case AUDPP_MSG_STATUS_MSG:{
277 unsigned cid = msg[0];
278 MM_DBG("status %d %d %d\n", cid, msg[1], msg[2]);
279 if ((cid < 5) && audpp->func[cid])
280 audpp->func[cid] (audpp->private[cid], id, msg);
281 break;
282 }
283 case AUDPP_MSG_HOST_PCM_INTF_MSG:
284 if (audpp->func[5])
285 audpp->func[5] (audpp->private[5], id, msg);
286 break;
287 case AUDPP_MSG_PCMDMAMISSED:
288 audpp_handle_pcmdmamiss(audpp, msg[0]);
289 break;
290 case AUDPP_MSG_CFG_MSG:
291 if (msg[0] == AUDPP_MSG_ENA_ENA) {
292 MM_INFO("ENABLE\n");
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530293 if (!audpp->enabled) {
294 audpp->enabled = 1;
295 audpp_broadcast(audpp, id, msg);
296 } else {
297 cid = msg[1];
298 audpp_fake_event(audpp, cid,
299 id, AUDPP_MSG_ENA_ENA);
300 }
301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530303 if (audpp->open_count == 0) {
304 MM_INFO("DISABLE\n");
305 audpp->enabled = 0;
306 wake_up(&audpp->event_wait);
307 audpp_broadcast(audpp, id, msg);
308 } else {
309 cid = msg[1];
310 audpp_fake_event(audpp, cid,
311 id, AUDPP_MSG_ENA_DIS);
312 audpp->func[cid] = NULL;
313 audpp->private[cid] = NULL;
314 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 } else {
316 MM_ERR("invalid config msg %d\n", msg[0]);
317 }
318 break;
319 case AUDPP_MSG_ROUTING_ACK:
320 audpp_notify_clnt(audpp, msg[0], id, msg);
321 break;
322 case AUDPP_MSG_FLUSH_ACK:
323 audpp_notify_clnt(audpp, msg[0], id, msg);
324 break;
325 case ADSP_MESSAGE_ID:
326 MM_DBG("Received ADSP event: module enable/disable(audpptask)");
327 break;
Manish Dewanganca859722012-07-09 18:21:42 +0530328 case AUDPP_MSG_FEAT_QUERY_DM_DONE:
329 MM_INFO(" RTC ACK --> %x %x %x\n", msg[0],\
330 msg[1], msg[2]);
331 acdb_rtc_set_err(msg[2]);
332 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 default:
334 MM_ERR("unhandled msg id %x\n", id);
335 }
336}
337
338static struct msm_adsp_ops adsp_ops = {
339 .event = audpp_dsp_event,
340};
341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342int audpp_enable(int id, audpp_event_func func, void *private)
343{
344 struct audpp_state *audpp = &the_audpp_state;
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530345 uint16_t msg[8];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 int res = 0;
347
348 if (id < -1 || id > 4)
349 return -EINVAL;
350
351 if (id == -1)
352 id = 5;
353
354 mutex_lock(audpp->lock);
355 if (audpp->func[id]) {
356 res = -EBUSY;
357 goto out;
358 }
359
360 audpp->func[id] = func;
361 audpp->private[id] = private;
362
363 LOG(EV_ENABLE, 1);
364 if (audpp->open_count++ == 0) {
365 MM_DBG("enable\n");
366 res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
367 if (res < 0) {
368 MM_ERR("cannot open AUDPPTASK\n");
369 audpp->open_count = 0;
370 audpp->func[id] = NULL;
371 audpp->private[id] = NULL;
372 goto out;
373 }
374 LOG(EV_ENABLE, 2);
375 msm_adsp_enable(audpp->mod);
376 audpp_dsp_config(1);
377 } else {
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530378 if (audpp->enabled) {
379 msg[0] = AUDPP_MSG_ENA_ENA;
380 msg[1] = id;
381 res = msm_adsp_generate_event(audpp, audpp->mod,
382 AUDPP_MSG_CFG_MSG, sizeof(msg),
383 sizeof(uint16_t), (void *)msg);
384 if (res < 0)
385 goto out;
386 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 }
388
389 res = 0;
390out:
391 mutex_unlock(audpp->lock);
392 return res;
393}
394EXPORT_SYMBOL(audpp_enable);
395
396void audpp_disable(int id, void *private)
397{
398 struct audpp_state *audpp = &the_audpp_state;
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530399 uint16_t msg[8];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400 int rc;
401
402 if (id < -1 || id > 4)
403 return;
404
405 if (id == -1)
406 id = 5;
407
408 mutex_lock(audpp->lock);
409 LOG(EV_DISABLE, 1);
410 if (!audpp->func[id])
411 goto out;
412 if (audpp->private[id] != private)
413 goto out;
414
Manish Dewangan8e87bc12012-02-09 20:25:15 +0530415 msg[0] = AUDPP_MSG_ENA_DIS;
416 msg[1] = id;
417 rc = msm_adsp_generate_event(audpp, audpp->mod,
418 AUDPP_MSG_CFG_MSG, sizeof(msg),
419 sizeof(uint16_t), (void *)msg);
420 if (rc < 0)
421 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422
423 if (--audpp->open_count == 0) {
424 MM_DBG("disable\n");
425 LOG(EV_DISABLE, 2);
426 audpp_dsp_config(0);
427 rc = wait_event_interruptible(audpp->event_wait,
428 (audpp->enabled == 0));
429 if (audpp->enabled == 0)
430 MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
431 else
432 MM_ERR("Didn't receive CFG_MSG DISABLE \
433 message from ADSP\n");
434 msm_adsp_disable(audpp->mod);
435 msm_adsp_put(audpp->mod);
436 audpp->mod = NULL;
437 }
438out:
439 mutex_unlock(audpp->lock);
440}
441EXPORT_SYMBOL(audpp_disable);
442
443#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
444
445void audpp_avsync(int id, unsigned rate)
446{
447 unsigned long flags;
448 audpp_cmd_avsync cmd;
449
450 if (BAD_ID(id))
451 return;
452
Manish Dewangan0f90d472012-02-25 14:09:23 +0530453 spin_lock_irqsave(&the_audpp_state.avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 if (rate)
455 the_audpp_state.avsync_mask |= (1 << id);
456 else
457 the_audpp_state.avsync_mask &= (~(1 << id));
458 the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530459 spin_unlock_irqrestore(&the_audpp_state.avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460
461 cmd.cmd_id = AUDPP_CMD_AVSYNC;
462 cmd.object_number = id;
463 cmd.interrupt_interval_lsw = rate;
464 cmd.interrupt_interval_msw = rate >> 16;
465 audpp_send_queue1(&cmd, sizeof(cmd));
466}
467EXPORT_SYMBOL(audpp_avsync);
468
469unsigned audpp_avsync_sample_count(int id)
470{
Manish Dewangan0f90d472012-02-25 14:09:23 +0530471 struct audpp_state *audpp = &the_audpp_state;
472 uint16_t *avsync = audpp->avsync;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 unsigned val;
474 unsigned long flags;
475 unsigned mask;
476
477 if (BAD_ID(id))
478 return 0;
479
480 mask = 1 << id;
481 id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530482 spin_lock_irqsave(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 if (avsync[0] & mask)
484 val = (avsync[id] << 16) | avsync[id + 1];
485 else
486 val = 0;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530487 spin_unlock_irqrestore(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488
489 return val;
490}
491EXPORT_SYMBOL(audpp_avsync_sample_count);
492
493unsigned audpp_avsync_byte_count(int id)
494{
Manish Dewangan0f90d472012-02-25 14:09:23 +0530495 struct audpp_state *audpp = &the_audpp_state;
496 uint16_t *avsync = audpp->avsync;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 unsigned val;
498 unsigned long flags;
499 unsigned mask;
500
501 if (BAD_ID(id))
502 return 0;
503
504 mask = 1 << id;
505 id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530506 spin_lock_irqsave(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 if (avsync[0] & mask)
508 val = (avsync[id] << 16) | avsync[id + 1];
509 else
510 val = 0;
Manish Dewangan0f90d472012-02-25 14:09:23 +0530511 spin_unlock_irqrestore(&audpp->avsync_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512
513 return val;
514}
515EXPORT_SYMBOL(audpp_avsync_byte_count);
516
517int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan)
518{
519 /* cmd, obj_cfg[7], cmd_type, volume, pan */
520 uint16_t cmd[11];
521
522 if (id > 6)
523 return -EINVAL;
524
525 memset(cmd, 0, sizeof(cmd));
526 cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
527 cmd[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
528 cmd[8] = AUDPP_CMD_VOLUME_PAN;
529 cmd[9] = volume;
530 cmd[10] = pan;
531
532 return audpp_send_queue3(cmd, sizeof(cmd));
533}
534EXPORT_SYMBOL(audpp_set_volume_and_pan);
535
536/* Implementation of COPP features */
537int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
538 audpp_cmd_cfg_object_params_mbadrc *mbadrc)
539{
540 audpp_cmd_cfg_object_params_mbadrc cmd;
541
542 if (id != 6)
543 return -EINVAL;
544
545 memset(&cmd, 0, sizeof(cmd));
546 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
547 cmd.common.command_type = AUDPP_CMD_MBADRC;
548
549 if (enable) {
550 memcpy(&cmd.num_bands, &mbadrc->num_bands,
551 sizeof(*mbadrc) -
552 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
553 cmd.enable = AUDPP_CMD_ADRC_FLAG_ENA;
554 } else
555 cmd.enable = AUDPP_CMD_ADRC_FLAG_DIS;
556
557 /*order the writes to mbadrc */
558 dma_coherent_pre_ops();
559 return audpp_send_queue3(&cmd, sizeof(cmd));
560}
561EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
562
563int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
564 audpp_cmd_cfg_object_params_qconcert *
565 qconcert_plus)
566{
567 audpp_cmd_cfg_object_params_qconcert cmd;
568 if (id != 6)
569 return -EINVAL;
570
571 memset(&cmd, 0, sizeof(cmd));
572 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
573 cmd.common.command_type = AUDPP_CMD_QCONCERT;
574
575 if (enable) {
576 memcpy(&cmd.op_mode, &qconcert_plus->op_mode,
577 sizeof(audpp_cmd_cfg_object_params_qconcert) -
578 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
579 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
580 } else
581 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
582
583 return audpp_send_queue3(&cmd, sizeof(cmd));
584}
585
586int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
587 audpp_cmd_cfg_object_params_pcm *iir)
588{
589 audpp_cmd_cfg_object_params_pcm cmd;
590
591 if (id != 6)
592 return -EINVAL;
593
594 memset(&cmd, 0, sizeof(cmd));
595 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
596 cmd.common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
597
598 if (enable) {
599 cmd.active_flag = AUDPP_CMD_IIR_FLAG_ENA;
600 cmd.num_bands = iir->num_bands;
601 memcpy(&cmd.params_filter, &iir->params_filter,
602 sizeof(iir->params_filter));
603 } else
604 cmd.active_flag = AUDPP_CMD_IIR_FLAG_DIS;
605
606 return audpp_send_queue3(&cmd, sizeof(cmd));
607}
608EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
609
Sidipotu Ashok3144aa22012-03-16 10:55:24 +0530610int audpp_dsp_set_rx_srs_trumedia_g(
611 struct audpp_cmd_cfg_object_params_srstm_g *srstm)
612{
613 struct audpp_cmd_cfg_object_params_srstm_g cmd;
614
615 MM_DBG("%s\n", __func__);
616 memset(&cmd, 0, sizeof(cmd));
617 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
618 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
619 cmd.common.command_type = AUDPP_SRS_PARAMS_G;
620
621 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
622
623 return audpp_send_queue3(&cmd, sizeof(cmd));
624}
625EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_g);
626
627int audpp_dsp_set_rx_srs_trumedia_w(
628 struct audpp_cmd_cfg_object_params_srstm_w *srstm)
629{
630 struct audpp_cmd_cfg_object_params_srstm_w cmd;
631
632 MM_DBG("%s\n", __func__);
633 memset(&cmd, 0, sizeof(cmd));
634 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
635 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
636 cmd.common.command_type = AUDPP_SRS_PARAMS_W;
637
638 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
639
640 return audpp_send_queue3(&cmd, sizeof(cmd));
641}
642EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_w);
643
644int audpp_dsp_set_rx_srs_trumedia_c(
645 struct audpp_cmd_cfg_object_params_srstm_c *srstm)
646{
647 struct audpp_cmd_cfg_object_params_srstm_c cmd;
648
649 MM_DBG("%s\n", __func__);
650 memset(&cmd, 0, sizeof(cmd));
651 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
652 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
653 cmd.common.command_type = AUDPP_SRS_PARAMS_C;
654
655 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
656
657 return audpp_send_queue3(&cmd, sizeof(cmd));
658}
659EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_c);
660
661int audpp_dsp_set_rx_srs_trumedia_h(
662 struct audpp_cmd_cfg_object_params_srstm_h *srstm)
663{
664 struct audpp_cmd_cfg_object_params_srstm_h cmd;
665
666 MM_DBG("%s\n", __func__);
667 memset(&cmd, 0, sizeof(cmd));
668 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
669 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
670 cmd.common.command_type = AUDPP_SRS_PARAMS_H;
671
672 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
673
674 return audpp_send_queue3(&cmd, sizeof(cmd));
675}
676EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_h);
677
678int audpp_dsp_set_rx_srs_trumedia_p(
679 struct audpp_cmd_cfg_object_params_srstm_p *srstm)
680{
681 struct audpp_cmd_cfg_object_params_srstm_p cmd;
682
683 MM_DBG("%s\n", __func__);
684 memset(&cmd, 0, sizeof(cmd));
685 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
686 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
687 cmd.common.command_type = AUDPP_SRS_PARAMS_P;
688
689 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
690
691 return audpp_send_queue3(&cmd, sizeof(cmd));
692}
693EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_p);
694
695int audpp_dsp_set_rx_srs_trumedia_l(
696 struct audpp_cmd_cfg_object_params_srstm_l *srstm)
697{
698 struct audpp_cmd_cfg_object_params_srstm_l cmd;
699
700 MM_DBG("%s\n", __func__);
701 memset(&cmd, 0, sizeof(cmd));
702 cmd.common.cmd_id = AUDPP_SRS_PARAMS;
703 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
704 cmd.common.command_type = AUDPP_SRS_PARAMS_L;
705
706 memcpy(cmd.v, srstm->v, sizeof(srstm->v));
707
708 return audpp_send_queue3(&cmd, sizeof(cmd));
709}
710EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_l);
711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712/* Implementation Of COPP + POPP */
713int audpp_dsp_set_eq(unsigned id, unsigned enable,
714 audpp_cmd_cfg_object_params_eqalizer *eq)
715{
716 audpp_cmd_cfg_object_params_eqalizer cmd;
717 unsigned short *id_ptr = (unsigned short *)&cmd;
718
719 if (id > 6 || id == 5)
720 return -EINVAL;
721
722 memset(&cmd, 0, sizeof(cmd));
723 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
724 cmd.common.command_type = AUDPP_CMD_EQUALIZER;
725
726 if (enable) {
727 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
728 cmd.num_bands = eq->num_bands;
729 memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
730 } else
731 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
732
733 return audpp_send_queue3(&cmd, sizeof(cmd));
734}
735EXPORT_SYMBOL(audpp_dsp_set_eq);
736
737int audpp_dsp_set_vol_pan(unsigned id,
738 audpp_cmd_cfg_object_params_volume *vol_pan)
739{
740 audpp_cmd_cfg_object_params_volume cmd;
741 unsigned short *id_ptr = (unsigned short *)&cmd;
742
743 if (id > 6)
744 return -EINVAL;
745
746 memset(&cmd, 0, sizeof(cmd));
747 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
748 cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
749
750 cmd.volume = vol_pan->volume;
751 cmd.pan = vol_pan->pan;
752
753 return audpp_send_queue3(&cmd, sizeof(cmd));
754}
755EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
756
757int audpp_pause(unsigned id, int pause)
758{
759 /* pause 1 = pause 0 = resume */
760 u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
761
762 if (id >= CH_COUNT)
763 return -EINVAL;
764
765 memset(pause_cmd, 0, sizeof(pause_cmd));
766
767 pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
768 if (pause == 1)
769 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
770 else if (pause == 0)
771 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
772 else
773 return -EINVAL;
774
775 return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
776}
777EXPORT_SYMBOL(audpp_pause);
778
779int audpp_flush(unsigned id)
780{
781 u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
782
783 if (id >= CH_COUNT)
784 return -EINVAL;
785
786 memset(flush_cmd, 0, sizeof(flush_cmd));
787
788 flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
789 flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
790
791 return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
792}
793EXPORT_SYMBOL(audpp_flush);
794
795/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
796 * like mp3, aac, wma etc ... *
797 * = 15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
798 * = 31:16, reserved */
799int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
800 unsigned *queueid)
801{
802 struct audpp_state *audpp = &the_audpp_state;
803 int decid = -1, idx, lidx, mode, codec;
804 int codecs_supported, min_codecs_supported;
805 unsigned int *concurrency_entry;
806 mutex_lock(audpp->lock_dec);
807 /* Represents in bit mask */
808 mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
809 codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
810 /* Point to Last entry of the row */
811 concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
812 ((audpp->concurrency + 1) *
813 (audpp->dec_database->num_dec))) - 1);
814
815 lidx = audpp->dec_database->num_dec;
816 min_codecs_supported = sizeof(unsigned int) * 8;
817
818 MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
819
820 for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
821 if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
822 if ((mode & *concurrency_entry) &&
823 (codec & *concurrency_entry)) {
824 /* Check supports minimum number codecs */
825 codecs_supported =
826 audpp->dec_database->dec_info_list[idx -
827 1].
828 nr_codec_support;
829 if (codecs_supported < min_codecs_supported) {
830 lidx = idx - 1;
831 min_codecs_supported = codecs_supported;
832 }
833 }
834 }
835 }
836
837 if (lidx < audpp->dec_database->num_dec) {
838 audpp->dec_inuse |= (1 << lidx);
839 *module_name =
840 audpp->dec_database->dec_info_list[lidx].module_name;
841 *queueid =
842 audpp->dec_database->dec_info_list[lidx].module_queueid;
843 decid = audpp->dec_database->dec_info_list[lidx].module_decid;
844 audpp->dec_info_table[lidx].codec =
845 (dec_attrb & AUDPP_CODEC_MASK);
846 audpp->dec_info_table[lidx].pid = current->pid;
847 /* point to row to get supported operation */
848 concurrency_entry =
849 ((audpp->dec_database->dec_concurrency_table +
850 ((audpp->concurrency) * (audpp->dec_database->num_dec))) +
851 lidx);
852 decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
853 MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n",
854 decid, *module_name, *queueid);
855 }
856 mutex_unlock(audpp->lock_dec);
857 return decid;
858
859}
860EXPORT_SYMBOL(audpp_adec_alloc);
861
862void audpp_adec_free(int decid)
863{
864 struct audpp_state *audpp = &the_audpp_state;
865 int idx;
866 mutex_lock(audpp->lock_dec);
867 for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
868 if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
869 decid) {
870 audpp->dec_inuse &= ~(1 << (idx - 1));
871 audpp->dec_info_table[idx - 1].codec = -1;
872 audpp->dec_info_table[idx - 1].pid = 0;
873 MM_INFO("free decid =%d \n", decid);
874 break;
875 }
876 }
877 mutex_unlock(audpp->lock_dec);
878 return;
879
880}
881EXPORT_SYMBOL(audpp_adec_free);
882
883static ssize_t concurrency_show(struct device *dev,
884 struct device_attribute *attr, char *buf)
885{
886 struct audpp_state *audpp = &the_audpp_state;
887 int rc;
888 mutex_lock(audpp->lock_dec);
889 rc = sprintf(buf, "%ld\n", audpp->concurrency);
890 mutex_unlock(audpp->lock_dec);
891 return rc;
892}
893
894static ssize_t concurrency_store(struct device *dev,
895 struct device_attribute *attr,
896 const char *buf, size_t count)
897{
898 struct audpp_state *audpp = &the_audpp_state;
899 unsigned long concurrency;
900 int rc = -1;
901 mutex_lock(audpp->lock_dec);
902 if (audpp->dec_inuse) {
903 MM_ERR("Can not change profile, while playback in progress\n");
904 goto done;
905 }
906 rc = strict_strtoul(buf, 10, &concurrency);
907 if (!rc &&
908 (concurrency < audpp->dec_database->num_concurrency_support)) {
909 audpp->concurrency = concurrency;
910 MM_DBG("Concurrency case %ld\n", audpp->concurrency);
911 rc = count;
912 } else {
913 MM_ERR("Not a valid Concurrency case\n");
914 rc = -EINVAL;
915 }
916done:
917 mutex_unlock(audpp->lock_dec);
918 return rc;
919}
920
921static ssize_t decoder_info_show(struct device *dev,
922 struct device_attribute *attr, char *buf);
923static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
924 __ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
925 __ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
926 __ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
927 __ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
928 __ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
929};
930
931static ssize_t decoder_info_show(struct device *dev,
932 struct device_attribute *attr, char *buf)
933{
934 int cpy_sz = 0;
935 struct audpp_state *audpp = &the_audpp_state;
936 const ptrdiff_t off = attr - dev_attr_decoder; /* decoder number */
937 mutex_lock(audpp->lock_dec);
938 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
939 audpp->dec_info_table[off].codec);
940 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
941 audpp->dec_info_table[off].pid);
942 mutex_unlock(audpp->lock_dec);
943 return cpy_sz;
944}
945
946static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
947 concurrency_store);
948static int audpp_probe(struct platform_device *pdev)
949{
950 int rc, idx;
951 struct audpp_state *audpp = &the_audpp_state;
952 audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
953 audpp->dec_database =
954 (struct msm_adspdec_database *)pdev->dev.platform_data;
955
956 MM_INFO("Number of decoder supported %d\n",
957 audpp->dec_database->num_dec);
958 MM_INFO("Number of concurrency supported %d\n",
959 audpp->dec_database->num_concurrency_support);
960
961 init_waitqueue_head(&audpp->event_wait);
962
Manish Dewangan0f90d472012-02-25 14:09:23 +0530963 spin_lock_init(&audpp->avsync_lock);
964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
966 audpp->dec_info_table[idx].codec = -1;
967 audpp->dec_info_table[idx].pid = 0;
968 MM_INFO("module_name:%s\n",
969 audpp->dec_database->dec_info_list[idx].module_name);
970 MM_INFO("queueid:%d\n",
971 audpp->dec_database->dec_info_list[idx].module_queueid);
972 MM_INFO("decid:%d\n",
973 audpp->dec_database->dec_info_list[idx].module_decid);
974 MM_INFO("nr_codec_support:%d\n",
975 audpp->dec_database->dec_info_list[idx].
976 nr_codec_support);
977 }
978
979 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
980 rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
981 if (rc)
982 goto err;
983 }
984 rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
985 if (rc)
986 goto err;
987 else
988 goto done;
989err:
990 while (idx--)
991 device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
992done:
993 return rc;
994}
995
996static struct platform_driver audpp_plat_driver = {
997 .probe = audpp_probe,
998 .driver = {
999 .name = "msm_adspdec",
1000 .owner = THIS_MODULE,
1001 },
1002};
1003
1004static int __init audpp_init(void)
1005{
1006 return platform_driver_register(&audpp_plat_driver);
1007}
1008
1009device_initcall(audpp_init);