2 /* arch/arm/mach-msm/qdsp5/audpp.c
4 * common code to deal with the AUDPP dsp task (audio postproc)
6 * Copyright (C) 2008 Google, Inc.
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/wait.h>
22 #include <linux/delay.h>
24 #include <asm/atomic.h>
25 #include <asm/ioctls.h>
26 #include <mach/msm_adsp.h>
30 #include <mach/qdsp5/qdsp5audppcmdi.h>
31 #include <mach/qdsp5/qdsp5audppmsg.h>
33 /* for queue ids - should be relative to module number*/
47 static const char *dsp_log_strings
[] = {
55 DECLARE_LOG(dsp_log
, 64, dsp_log_strings
);
57 static int __init
_dsp_log_init(void)
59 return ev_log_init(&dsp_log
);
61 module_init(_dsp_log_init
);
62 #define LOG(id,arg) ev_log_write(&dsp_log, id, arg)
64 static DEFINE_MUTEX(audpp_lock
);
67 #define AUDPP_CLNT_MAX_COUNT 6
68 #define AUDPP_AVSYNC_INFO_SIZE 7
71 struct msm_adsp_module
*mod
;
72 audpp_event_func func
[AUDPP_CLNT_MAX_COUNT
];
73 void *private[AUDPP_CLNT_MAX_COUNT
];
78 /* which channels are actually enabled */
81 /* flags, 48 bits sample/bytes counter per channel */
82 uint16_t avsync
[CH_COUNT
* AUDPP_CLNT_MAX_COUNT
+ 1];
85 struct audpp_state the_audpp_state
= {
89 int audpp_send_queue1(void *cmd
, unsigned len
)
91 return msm_adsp_write(the_audpp_state
.mod
,
92 QDSP_uPAudPPCmd1Queue
, cmd
, len
);
94 EXPORT_SYMBOL(audpp_send_queue1
);
96 int audpp_send_queue2(void *cmd
, unsigned len
)
98 return msm_adsp_write(the_audpp_state
.mod
,
99 QDSP_uPAudPPCmd2Queue
, cmd
, len
);
101 EXPORT_SYMBOL(audpp_send_queue2
);
103 int audpp_send_queue3(void *cmd
, unsigned len
)
105 return msm_adsp_write(the_audpp_state
.mod
,
106 QDSP_uPAudPPCmd3Queue
, cmd
, len
);
108 EXPORT_SYMBOL(audpp_send_queue3
);
110 static int audpp_dsp_config(int enable
)
114 cmd
.cmd_id
= AUDPP_CMD_CFG
;
115 cmd
.cfg
= enable
? AUDPP_CMD_CFG_ENABLE
: AUDPP_CMD_CFG_SLEEP
;
117 return audpp_send_queue1(&cmd
, sizeof(cmd
));
120 static void audpp_broadcast(struct audpp_state
*audpp
, unsigned id
,
124 for (n
= 0; n
< AUDPP_CLNT_MAX_COUNT
; n
++) {
126 audpp
->func
[n
] (audpp
->private[n
], id
, msg
);
130 static void audpp_notify_clnt(struct audpp_state
*audpp
, unsigned clnt_id
,
131 unsigned id
, uint16_t *msg
)
133 if (clnt_id
< AUDPP_CLNT_MAX_COUNT
&& audpp
->func
[clnt_id
])
134 audpp
->func
[clnt_id
] (audpp
->private[clnt_id
], id
, msg
);
137 static void audpp_dsp_event(void *data
, unsigned id
, size_t len
,
138 void (*getevent
)(void *ptr
, size_t len
))
140 struct audpp_state
*audpp
= data
;
143 if (id
== AUDPP_MSG_AVSYNC_MSG
) {
144 getevent(audpp
->avsync
, sizeof(audpp
->avsync
));
146 /* mask off any channels we're not watching to avoid
147 * cases where we might get one last update after
148 * disabling avsync and end up in an odd state when
151 audpp
->avsync
[0] &= audpp
->avsync_mask
;
155 getevent(msg
, sizeof(msg
));
157 LOG(EV_EVENT
, (id
<< 16) | msg
[0]);
158 LOG(EV_DATA
, (msg
[1] << 16) | msg
[2]);
161 case AUDPP_MSG_STATUS_MSG
:{
162 unsigned cid
= msg
[0];
163 pr_info("audpp: status %d %d %d\n", cid
, msg
[1],
165 if ((cid
< 5) && audpp
->func
[cid
])
166 audpp
->func
[cid
] (audpp
->private[cid
], id
, msg
);
169 case AUDPP_MSG_HOST_PCM_INTF_MSG
:
171 audpp
->func
[5] (audpp
->private[5], id
, msg
);
173 case AUDPP_MSG_PCMDMAMISSED
:
174 pr_err("audpp: DMA missed obj=%x\n", msg
[0]);
176 case AUDPP_MSG_CFG_MSG
:
177 if (msg
[0] == AUDPP_MSG_ENA_ENA
) {
178 pr_info("audpp: ENABLE\n");
180 audpp_broadcast(audpp
, id
, msg
);
181 } else if (msg
[0] == AUDPP_MSG_ENA_DIS
) {
182 pr_info("audpp: DISABLE\n");
184 audpp_broadcast(audpp
, id
, msg
);
186 pr_err("audpp: invalid config msg %d\n", msg
[0]);
189 case AUDPP_MSG_ROUTING_ACK
:
190 audpp_broadcast(audpp
, id
, msg
);
192 case AUDPP_MSG_FLUSH_ACK
:
193 audpp_notify_clnt(audpp
, msg
[0], id
, msg
);
196 pr_info("audpp: unhandled msg id %x\n", id
);
200 static struct msm_adsp_ops adsp_ops
= {
201 .event
= audpp_dsp_event
,
204 static void audpp_fake_event(struct audpp_state
*audpp
, int id
,
205 unsigned event
, unsigned arg
)
209 audpp
->func
[id
] (audpp
->private[id
], event
, msg
);
212 int audpp_enable(int id
, audpp_event_func func
, void *private)
214 struct audpp_state
*audpp
= &the_audpp_state
;
217 if (id
< -1 || id
> 4)
223 mutex_lock(audpp
->lock
);
224 if (audpp
->func
[id
]) {
229 audpp
->func
[id
] = func
;
230 audpp
->private[id
] = private;
233 if (audpp
->open_count
++ == 0) {
234 pr_info("audpp: enable\n");
235 res
= msm_adsp_get("AUDPPTASK", &audpp
->mod
, &adsp_ops
, audpp
);
237 pr_err("audpp: cannot open AUDPPTASK\n");
238 audpp
->open_count
= 0;
239 audpp
->func
[id
] = NULL
;
240 audpp
->private[id
] = NULL
;
244 msm_adsp_enable(audpp
->mod
);
248 local_irq_save(flags
);
250 audpp_fake_event(audpp
, id
,
251 AUDPP_MSG_CFG_MSG
, AUDPP_MSG_ENA_ENA
);
252 local_irq_restore(flags
);
257 mutex_unlock(audpp
->lock
);
260 EXPORT_SYMBOL(audpp_enable
);
262 void audpp_disable(int id
, void *private)
264 struct audpp_state
*audpp
= &the_audpp_state
;
267 if (id
< -1 || id
> 4)
273 mutex_lock(audpp
->lock
);
275 if (!audpp
->func
[id
])
277 if (audpp
->private[id
] != private)
280 local_irq_save(flags
);
281 audpp_fake_event(audpp
, id
, AUDPP_MSG_CFG_MSG
, AUDPP_MSG_ENA_DIS
);
282 audpp
->func
[id
] = NULL
;
283 audpp
->private[id
] = NULL
;
284 local_irq_restore(flags
);
286 if (--audpp
->open_count
== 0) {
287 pr_info("audpp: disable\n");
290 msm_adsp_disable(audpp
->mod
);
291 msm_adsp_put(audpp
->mod
);
295 mutex_unlock(audpp
->lock
);
297 EXPORT_SYMBOL(audpp_disable
);
299 #define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
301 void audpp_avsync(int id
, unsigned rate
)
304 audpp_cmd_avsync cmd
;
309 local_irq_save(flags
);
311 the_audpp_state
.avsync_mask
|= (1 << id
);
313 the_audpp_state
.avsync_mask
&= (~(1 << id
));
314 the_audpp_state
.avsync
[0] &= the_audpp_state
.avsync_mask
;
315 local_irq_restore(flags
);
317 cmd
.cmd_id
= AUDPP_CMD_AVSYNC
;
318 cmd
.object_number
= id
;
319 cmd
.interrupt_interval_lsw
= rate
;
320 cmd
.interrupt_interval_msw
= rate
>> 16;
321 audpp_send_queue1(&cmd
, sizeof(cmd
));
323 EXPORT_SYMBOL(audpp_avsync
);
325 unsigned audpp_avsync_sample_count(int id
)
327 uint16_t *avsync
= the_audpp_state
.avsync
;
336 id
= id
* AUDPP_AVSYNC_INFO_SIZE
+ 2;
337 local_irq_save(flags
);
338 if (avsync
[0] & mask
)
339 val
= (avsync
[id
] << 16) | avsync
[id
+ 1];
342 local_irq_restore(flags
);
346 EXPORT_SYMBOL(audpp_avsync_sample_count
);
348 unsigned audpp_avsync_byte_count(int id
)
350 uint16_t *avsync
= the_audpp_state
.avsync
;
359 id
= id
* AUDPP_AVSYNC_INFO_SIZE
+ 5;
360 local_irq_save(flags
);
361 if (avsync
[0] & mask
)
362 val
= (avsync
[id
] << 16) | avsync
[id
+ 1];
365 local_irq_restore(flags
);
369 EXPORT_SYMBOL(audpp_avsync_byte_count
);
371 #define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
372 #define AUDPP_CMD_VOLUME_PAN 0
374 int audpp_set_volume_and_pan(unsigned id
, unsigned volume
, int pan
)
376 /* cmd, obj_cfg[7], cmd_type, volume, pan */
382 memset(cmd
, 0, sizeof(cmd
));
383 cmd
[0] = AUDPP_CMD_CFG_OBJECT_PARAMS
;
384 cmd
[1 + id
] = AUDPP_CMD_CFG_OBJ_UPDATE
;
385 cmd
[8] = AUDPP_CMD_VOLUME_PAN
;
389 return audpp_send_queue3(cmd
, sizeof(cmd
));
391 EXPORT_SYMBOL(audpp_set_volume_and_pan
);
393 int audpp_pause(unsigned id
, int pause
)
395 /* pause 1 = pause 0 = resume */
396 u16 pause_cmd
[AUDPP_CMD_DEC_CTRL_LEN
/ sizeof(unsigned short)];
401 memset(pause_cmd
, 0, sizeof(pause_cmd
));
403 pause_cmd
[0] = AUDPP_CMD_DEC_CTRL
;
405 pause_cmd
[1 + id
] = AUDPP_CMD_UPDATE_V
| AUDPP_CMD_PAUSE_V
;
407 pause_cmd
[1 + id
] = AUDPP_CMD_UPDATE_V
| AUDPP_CMD_RESUME_V
;
411 return audpp_send_queue1(pause_cmd
, sizeof(pause_cmd
));
413 EXPORT_SYMBOL(audpp_pause
);
415 int audpp_flush(unsigned id
)
417 u16 flush_cmd
[AUDPP_CMD_DEC_CTRL_LEN
/ sizeof(unsigned short)];
422 memset(flush_cmd
, 0, sizeof(flush_cmd
));
424 flush_cmd
[0] = AUDPP_CMD_DEC_CTRL
;
425 flush_cmd
[1 + id
] = AUDPP_CMD_UPDATE_V
| AUDPP_CMD_FLUSH_V
;
427 return audpp_send_queue1(flush_cmd
, sizeof(flush_cmd
));
429 EXPORT_SYMBOL(audpp_flush
);