blob: 09611a552cedf02fb9ff88fb463d68f67fd57a40 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * Common code to deal with the AUDPREPROC dsp task (audio preprocessing)
3 *
4 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
5 *
6 * Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
7 *
8 * Copyright (C) 2008 Google, Inc.
9 *
10 * This software is licensed under the terms of the GNU General Public
11 * License version 2, as published by the Free Software Foundation, and
12 * may be copied, distributed, and modified under those terms.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 *
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/wakelock.h>
23#include <mach/msm_adsp.h>
24#include <mach/qdsp5v2/audio_acdbi.h>
25#include <mach/qdsp5v2/audpreproc.h>
26#include <mach/debug_mm.h>
27#include <mach/qdsp5v2/qdsp5audpreprocmsg.h>
28
29static DEFINE_MUTEX(audpreproc_lock);
30static struct wake_lock audpre_wake_lock;
31static struct wake_lock audpre_idle_wake_lock;
32
33struct msm_adspenc_info {
34 const char *module_name;
35 unsigned module_queueids;
36 int module_encid; /* streamid */
37 int enc_formats; /* supported formats */
38 int nr_codec_support; /* number of codec suported */
39};
40
41#define ENC_MODULE_INFO(name, queueids, encid, formats, nr_codec) \
42 {.module_name = name, .module_queueids = queueids, \
43 .module_encid = encid, .enc_formats = formats, \
44 .nr_codec_support = nr_codec }
45
46#define MAX_EVENT_CALLBACK_CLIENTS 1
47
48#define ENC0_FORMAT ((1<<MSM_ADSP_ENC_CODEC_WAV)| \
49 (1<<MSM_ADSP_ENC_CODEC_SBC) | (1<<MSM_ADSP_ENC_CODEC_EXT_WAV))
50
51#define ENC1_FORMAT ((1<<MSM_ADSP_ENC_CODEC_WAV)| \
52 (1<<MSM_ADSP_ENC_CODEC_AAC) | (1<<MSM_ADSP_ENC_CODEC_AMRNB) | \
53 (1<<MSM_ADSP_ENC_CODEC_EVRC) | (1<<MSM_ADSP_ENC_CODEC_QCELP) | \
54 (1<<MSM_ADSP_ENC_CODEC_EXT_WAV))
55
56#define ENC2_FORMAT ((1<<MSM_ADSP_ENC_CODEC_WAV) | \
57 (1<<MSM_ADSP_ENC_CODEC_EXT_WAV))
58
59struct msm_adspenc_database {
60 unsigned num_enc;
61 struct msm_adspenc_info *enc_info_list;
62};
63
64static struct msm_adspenc_info enc_info_list[] = {
65 ENC_MODULE_INFO("AUDREC0TASK", \
66 ((QDSP_uPAudRec0BitStreamQueue << 16)| \
67 QDSP_uPAudRec0CmdQueue), 0, \
68 (ENC0_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL)), 3),
69
70 ENC_MODULE_INFO("AUDREC1TASK", \
71 ((QDSP_uPAudRec1BitStreamQueue << 16)| \
72 QDSP_uPAudRec1CmdQueue), 1, \
73 (ENC1_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL) | \
74 (1 << MSM_ADSP_ENC_MODE_NON_TUNNEL)), 6),
75
76 ENC_MODULE_INFO("AUDREC2TASK", \
77 ((QDSP_uPAudRec2BitStreamQueue << 16)| \
78 QDSP_uPAudRec2CmdQueue), 2, \
79 (ENC2_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL)), 2),
80
81};
82
83static struct msm_adspenc_database msm_enc_database = {
84 .num_enc = ARRAY_SIZE(enc_info_list),
85 .enc_info_list = enc_info_list,
86};
87
88
89static struct audrec_session_info
90 session_info[MAX_ENC_COUNT] = { {0, 0}, {0, 0}, {0, 0} };
91
92struct audpreproc_state {
93 struct msm_adsp_module *mod;
94 audpreproc_event_func func[MAX_ENC_COUNT];
95 void *private[MAX_ENC_COUNT];
96 struct mutex *lock;
97 unsigned open_count;
98 unsigned enc_inuse;
99 struct audpreproc_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
100};
101
102static struct audpreproc_state the_audpreproc_state = {
103 .lock = &audpreproc_lock,
104};
105
106static inline void prevent_suspend(void)
107{
108 wake_lock(&audpre_wake_lock);
109 wake_lock(&audpre_idle_wake_lock);
110}
111static inline void allow_suspend(void)
112{
113 wake_unlock(&audpre_wake_lock);
114 wake_unlock(&audpre_idle_wake_lock);
115}
116
117/* DSP preproc event handler */
118static void audpreproc_dsp_event(void *data, unsigned id, size_t len,
119 void (*getevent)(void *ptr, size_t len))
120{
121 struct audpreproc_state *audpreproc = data;
122 int n = 0;
123
124 switch (id) {
125 case AUDPREPROC_CMD_CFG_DONE_MSG: {
126 struct audpreproc_cmd_cfg_done_msg cfg_done_msg;
127
128 getevent(&cfg_done_msg, AUDPREPROC_CMD_CFG_DONE_MSG_LEN);
129 MM_DBG("AUDPREPROC_CMD_CFG_DONE_MSG: stream id %d preproc \
130 type %x\n", cfg_done_msg.stream_id, \
131 cfg_done_msg.aud_preproc_type);
132 if ((cfg_done_msg.stream_id < MAX_ENC_COUNT) &&
133 audpreproc->func[cfg_done_msg.stream_id])
134 audpreproc->func[cfg_done_msg.stream_id](
135 audpreproc->private[cfg_done_msg.stream_id], id,
136 &cfg_done_msg);
137 break;
138 }
139 case AUDPREPROC_ERROR_MSG: {
140 struct audpreproc_err_msg err_msg;
141
142 getevent(&err_msg, AUDPREPROC_ERROR_MSG_LEN);
143 MM_DBG("AUDPREPROC_ERROR_MSG: stream id %d err idx %d\n",
144 err_msg.stream_id, err_msg.aud_preproc_err_idx);
145 if ((err_msg.stream_id < MAX_ENC_COUNT) &&
146 audpreproc->func[err_msg.stream_id])
147 audpreproc->func[err_msg.stream_id](
148 audpreproc->private[err_msg.stream_id], id,
149 &err_msg);
150 break;
151 }
152 case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
153 struct audpreproc_cmd_enc_cfg_done_msg enc_cfg_msg;
154
155 getevent(&enc_cfg_msg, AUDPREPROC_CMD_ENC_CFG_DONE_MSG_LEN);
156 MM_DBG("AUDPREPROC_CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
157 %d\n", enc_cfg_msg.stream_id, enc_cfg_msg.rec_enc_type);
158 if ((enc_cfg_msg.stream_id < MAX_ENC_COUNT) &&
159 audpreproc->func[enc_cfg_msg.stream_id])
160 audpreproc->func[enc_cfg_msg.stream_id](
161 audpreproc->private[enc_cfg_msg.stream_id], id,
162 &enc_cfg_msg);
163 for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n) {
164 if (audpreproc->cb_tbl[n] &&
165 audpreproc->cb_tbl[n]->fn) {
166 audpreproc->cb_tbl[n]->fn( \
167 audpreproc->cb_tbl[n]->private, \
168 id, (void *) &enc_cfg_msg);
169 }
170 }
171 break;
172 }
173 case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
174 struct audpreproc_cmd_enc_param_cfg_done_msg enc_param_msg;
175
176 getevent(&enc_param_msg,
177 AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG_LEN);
178 MM_DBG("AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: stream id %d\n",
179 enc_param_msg.stream_id);
180 if ((enc_param_msg.stream_id < MAX_ENC_COUNT) &&
181 audpreproc->func[enc_param_msg.stream_id])
182 audpreproc->func[enc_param_msg.stream_id](
183 audpreproc->private[enc_param_msg.stream_id], id,
184 &enc_param_msg);
185 break;
186 }
187 case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
188 struct audpreproc_afe_cmd_audio_record_cfg_done
189 record_cfg_done;
190 getevent(&record_cfg_done,
191 AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG_LEN);
192 MM_DBG("AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: \
193 stream id %d\n", record_cfg_done.stream_id);
194 if ((record_cfg_done.stream_id < MAX_ENC_COUNT) &&
195 audpreproc->func[record_cfg_done.stream_id])
196 audpreproc->func[record_cfg_done.stream_id](
197 audpreproc->private[record_cfg_done.stream_id], id,
198 &record_cfg_done);
199 break;
200 }
201 case AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: {
202 struct audpreproc_cmd_routing_mode_done routing_mode_done;
203
204 getevent(&routing_mode_done,
205 AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG_LEN);
206 MM_DBG("AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: \
207 stream id %d\n", routing_mode_done.stream_id);
208 if ((routing_mode_done.stream_id < MAX_ENC_COUNT) &&
209 audpreproc->func[routing_mode_done.stream_id])
210 audpreproc->func[routing_mode_done.stream_id](
211 audpreproc->private[routing_mode_done.stream_id], id,
212 &routing_mode_done);
213 break;
214 }
215#ifdef CONFIG_DEBUG_FS
216 case AUDPREPROC_MSG_FEAT_QUERY_DM_DONE:
217 {
218 uint16_t msg[3];
219 getevent(msg, sizeof(msg));
220 MM_INFO("RTC ACK --> %x %x %x\n", msg[0], msg[1], msg[2]);
221 acdb_rtc_set_err(msg[2]);
222 }
223 break;
224#endif
225 case ADSP_MESSAGE_ID: {
226 MM_DBG("Received ADSP event:module audpreproctask\n");
227 break;
228 }
229 default:
230 MM_ERR("Unknown Event %d\n", id);
231 }
232 return;
233}
234
235static struct msm_adsp_ops adsp_ops = {
236 .event = audpreproc_dsp_event,
237};
238
239/* EXPORTED API's */
240int audpreproc_enable(int enc_id, audpreproc_event_func func, void *private)
241{
242 struct audpreproc_state *audpreproc = &the_audpreproc_state;
243 int res = 0;
244
245 if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
246 return -EINVAL;
247
248 mutex_lock(audpreproc->lock);
249 if (audpreproc->func[enc_id]) {
250 res = -EBUSY;
251 goto out;
252 }
253
254 audpreproc->func[enc_id] = func;
255 audpreproc->private[enc_id] = private;
256
257 /* First client to enable preproc task */
258 if (audpreproc->open_count++ == 0) {
259 MM_DBG("Get AUDPREPROCTASK\n");
260 res = msm_adsp_get("AUDPREPROCTASK", &audpreproc->mod,
261 &adsp_ops, audpreproc);
262 if (res < 0) {
263 MM_ERR("Can not get AUDPREPROCTASK\n");
264 audpreproc->open_count = 0;
265 audpreproc->func[enc_id] = NULL;
266 audpreproc->private[enc_id] = NULL;
267 goto out;
268 }
269 prevent_suspend();
270 if (msm_adsp_enable(audpreproc->mod)) {
271 MM_ERR("Can not enable AUDPREPROCTASK\n");
272 audpreproc->open_count = 0;
273 audpreproc->func[enc_id] = NULL;
274 audpreproc->private[enc_id] = NULL;
275 msm_adsp_put(audpreproc->mod);
276 audpreproc->mod = NULL;
277 res = -ENODEV;
278 allow_suspend();
279 goto out;
280 }
281 }
282 res = 0;
283out:
284 mutex_unlock(audpreproc->lock);
285 return res;
286}
287EXPORT_SYMBOL(audpreproc_enable);
288
289int audpreproc_update_audrec_info(
290 struct audrec_session_info *audrec_session_info)
291{
292 if (!audrec_session_info) {
293 MM_ERR("error in audrec session info address\n");
294 return -EINVAL;
295 }
296 if (audrec_session_info->session_id < MAX_ENC_COUNT) {
297 memcpy(&session_info[audrec_session_info->session_id],
298 audrec_session_info,
299 sizeof(struct audrec_session_info));
300 return 0;
301 }
302 return -EINVAL;
303}
304EXPORT_SYMBOL(audpreproc_update_audrec_info);
305
306void audpreproc_disable(int enc_id, void *private)
307{
308 struct audpreproc_state *audpreproc = &the_audpreproc_state;
309
310 if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
311 return;
312
313 mutex_lock(audpreproc->lock);
314 if (!audpreproc->func[enc_id])
315 goto out;
316 if (audpreproc->private[enc_id] != private)
317 goto out;
318
319 audpreproc->func[enc_id] = NULL;
320 audpreproc->private[enc_id] = NULL;
321
322 /* Last client then disable preproc task */
323 if (--audpreproc->open_count == 0) {
324 msm_adsp_disable(audpreproc->mod);
325 MM_DBG("Put AUDPREPROCTASK\n");
326 msm_adsp_put(audpreproc->mod);
327 audpreproc->mod = NULL;
328 allow_suspend();
329 }
330out:
331 mutex_unlock(audpreproc->lock);
332 return;
333}
334EXPORT_SYMBOL(audpreproc_disable);
335
336
337int audpreproc_register_event_callback(struct audpreproc_event_callback *ecb)
338{
339 struct audpreproc_state *audpreproc = &the_audpreproc_state;
340 int i;
341
342 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
343 if (NULL == audpreproc->cb_tbl[i]) {
344 audpreproc->cb_tbl[i] = ecb;
345 return 0;
346 }
347 }
348 return -1;
349}
350EXPORT_SYMBOL(audpreproc_register_event_callback);
351
352int audpreproc_unregister_event_callback(struct audpreproc_event_callback *ecb)
353{
354 struct audpreproc_state *audpreproc = &the_audpreproc_state;
355 int i;
356
357 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
358 if (ecb == audpreproc->cb_tbl[i]) {
359 audpreproc->cb_tbl[i] = NULL;
360 return 0;
361 }
362 }
363 return -1;
364}
365EXPORT_SYMBOL(audpreproc_unregister_event_callback);
366
367
368/* enc_type = supported encode format *
369 * like pcm, aac, sbc, evrc, qcelp, amrnb etc ... *
370 */
371int audpreproc_aenc_alloc(unsigned enc_type, const char **module_name,
372 unsigned *queue_ids)
373{
374 struct audpreproc_state *audpreproc = &the_audpreproc_state;
375 int encid = -1, idx, lidx, mode, codec;
376 int codecs_supported, min_codecs_supported;
377 static int wakelock_init;
378
379 mutex_lock(audpreproc->lock);
380 /* Represents in bit mask */
381 mode = ((enc_type & AUDPREPROC_MODE_MASK) << 16);
382 codec = (1 << (enc_type & AUDPREPROC_CODEC_MASK));
383
384 lidx = msm_enc_database.num_enc;
385 min_codecs_supported = sizeof(unsigned int) * 8;
386 MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
387
388 for (idx = lidx-1; idx >= 0; idx--) {
389 /* encoder free and supports the format */
390 if (!(audpreproc->enc_inuse & (1 << (idx))) &&
391 ((mode & msm_enc_database.enc_info_list[idx].enc_formats)
392 == mode) && ((codec &
393 msm_enc_database.enc_info_list[idx].enc_formats)
394 == codec)){
395 /* Check supports minimum number codecs */
396 codecs_supported =
397 msm_enc_database.enc_info_list[idx].nr_codec_support;
398 if (codecs_supported < min_codecs_supported) {
399 lidx = idx;
400 min_codecs_supported = codecs_supported;
401 }
402 }
403 }
404
405 if (lidx < msm_enc_database.num_enc) {
406 audpreproc->enc_inuse |= (1 << lidx);
407 *module_name =
408 msm_enc_database.enc_info_list[lidx].module_name;
409 *queue_ids =
410 msm_enc_database.enc_info_list[lidx].module_queueids;
411 encid = msm_enc_database.enc_info_list[lidx].module_encid;
412 }
413
414 if (!wakelock_init) {
415 wake_lock_init(&audpre_wake_lock, WAKE_LOCK_SUSPEND, "audpre");
416 wake_lock_init(&audpre_idle_wake_lock, WAKE_LOCK_IDLE,
417 "audpre_idle");
418 wakelock_init = 1;
419 }
420
421 mutex_unlock(audpreproc->lock);
422 return encid;
423}
424EXPORT_SYMBOL(audpreproc_aenc_alloc);
425
426void audpreproc_aenc_free(int enc_id)
427{
428 struct audpreproc_state *audpreproc = &the_audpreproc_state;
429 int idx;
430
431 mutex_lock(audpreproc->lock);
432 for (idx = 0; idx < msm_enc_database.num_enc; idx++) {
433 if (msm_enc_database.enc_info_list[idx].module_encid ==
434 enc_id) {
435 audpreproc->enc_inuse &= ~(1 << idx);
436 break;
437 }
438 }
439 mutex_unlock(audpreproc->lock);
440 return;
441
442}
443EXPORT_SYMBOL(audpreproc_aenc_free);
444
445int audpreproc_send_preproccmdqueue(void *cmd, unsigned len)
446{
447 return msm_adsp_write(the_audpreproc_state.mod,
448 QDSP_uPAudPreProcCmdQueue, cmd, len);
449}
450EXPORT_SYMBOL(audpreproc_send_preproccmdqueue);
451
452int audpreproc_send_audreccmdqueue(void *cmd, unsigned len)
453{
454 return msm_adsp_write(the_audpreproc_state.mod,
455 QDSP_uPAudPreProcAudRecCmdQueue, cmd, len);
456}
457EXPORT_SYMBOL(audpreproc_send_audreccmdqueue);
458
459int audpreproc_send_audrec2cmdqueue(void *cmd, unsigned len)
460{
461 return msm_adsp_write(the_audpreproc_state.mod,
462 QDSP_uPAudRec2CmdQueue, cmd, len);
463}
464EXPORT_SYMBOL(audpreproc_send_audrec2cmdqueue);
465
466int audpreproc_dsp_set_agc(struct audpreproc_cmd_cfg_agc_params *agc,
467 unsigned len)
468{
469 return msm_adsp_write(the_audpreproc_state.mod,
470 QDSP_uPAudPreProcCmdQueue, agc, len);
471}
472EXPORT_SYMBOL(audpreproc_dsp_set_agc);
473
474int audpreproc_dsp_set_agc2(struct audpreproc_cmd_cfg_agc_params_2 *agc2,
475 unsigned len)
476{
477 return msm_adsp_write(the_audpreproc_state.mod,
478 QDSP_uPAudPreProcCmdQueue, agc2, len);
479}
480EXPORT_SYMBOL(audpreproc_dsp_set_agc2);
481
482int audpreproc_dsp_set_ns(struct audpreproc_cmd_cfg_ns_params *ns,
483 unsigned len)
484{
485 return msm_adsp_write(the_audpreproc_state.mod,
486 QDSP_uPAudPreProcCmdQueue, ns, len);
487}
488EXPORT_SYMBOL(audpreproc_dsp_set_ns);
489
490int audpreproc_dsp_set_iir(
491struct audpreproc_cmd_cfg_iir_tuning_filter_params *iir, unsigned len)
492{
493 return msm_adsp_write(the_audpreproc_state.mod,
494 QDSP_uPAudPreProcCmdQueue, iir, len);
495}
496EXPORT_SYMBOL(audpreproc_dsp_set_iir);
497
498int audpreproc_dsp_set_gain_tx(
499 struct audpreproc_cmd_cfg_cal_gain *calib_gain_tx, unsigned len)
500{
501 return msm_adsp_write(the_audpreproc_state.mod,
502 QDSP_uPAudPreProcCmdQueue, calib_gain_tx, len);
503}
504EXPORT_SYMBOL(audpreproc_dsp_set_gain_tx);
505
506void get_audrec_session_info(int id, struct audrec_session_info *info)
507{
508 if (id >= MAX_ENC_COUNT) {
509 MM_ERR("invalid session id = %d\n", id);
510 return;
511 }
512 memcpy(info, &session_info[id], sizeof(struct audrec_session_info));
513}
514EXPORT_SYMBOL(get_audrec_session_info);
515
516int audpreproc_dsp_set_lvnv(
517 struct audpreproc_cmd_cfg_lvnv_param *preproc_lvnv, unsigned len)
518{
519 return msm_adsp_write(the_audpreproc_state.mod,
520 QDSP_uPAudPreProcCmdQueue, preproc_lvnv, len);
521}
522EXPORT_SYMBOL(audpreproc_dsp_set_lvnv);
523