Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / dream / qdsp5 / audpp.c
blobd06556eda316e77022a5f2375870b484f2975317
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>
28 #include "audmgr.h"
30 #include <mach/qdsp5/qdsp5audppcmdi.h>
31 #include <mach/qdsp5/qdsp5audppmsg.h>
33 /* for queue ids - should be relative to module number*/
34 #include "adsp.h"
36 #include "evlog.h"
39 enum {
40 EV_NULL,
41 EV_ENABLE,
42 EV_DISABLE,
43 EV_EVENT,
44 EV_DATA,
47 static const char *dsp_log_strings[] = {
48 "NULL",
49 "ENABLE",
50 "DISABLE",
51 "EVENT",
52 "DATA",
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);
66 #define CH_COUNT 5
67 #define AUDPP_CLNT_MAX_COUNT 6
68 #define AUDPP_AVSYNC_INFO_SIZE 7
70 struct audpp_state {
71 struct msm_adsp_module *mod;
72 audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
73 void *private[AUDPP_CLNT_MAX_COUNT];
74 struct mutex *lock;
75 unsigned open_count;
76 unsigned enabled;
78 /* which channels are actually enabled */
79 unsigned avsync_mask;
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 = {
86 .lock = &audpp_lock,
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)
112 audpp_cmd_cfg cmd;
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,
121 uint16_t *msg)
123 unsigned n;
124 for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
125 if (audpp->func[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;
141 uint16_t msg[8];
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
149 * we next read...
151 audpp->avsync[0] &= audpp->avsync_mask;
152 return;
155 getevent(msg, sizeof(msg));
157 LOG(EV_EVENT, (id << 16) | msg[0]);
158 LOG(EV_DATA, (msg[1] << 16) | msg[2]);
160 switch (id) {
161 case AUDPP_MSG_STATUS_MSG:{
162 unsigned cid = msg[0];
163 pr_info("audpp: status %d %d %d\n", cid, msg[1],
164 msg[2]);
165 if ((cid < 5) && audpp->func[cid])
166 audpp->func[cid] (audpp->private[cid], id, msg);
167 break;
169 case AUDPP_MSG_HOST_PCM_INTF_MSG:
170 if (audpp->func[5])
171 audpp->func[5] (audpp->private[5], id, msg);
172 break;
173 case AUDPP_MSG_PCMDMAMISSED:
174 pr_err("audpp: DMA missed obj=%x\n", msg[0]);
175 break;
176 case AUDPP_MSG_CFG_MSG:
177 if (msg[0] == AUDPP_MSG_ENA_ENA) {
178 pr_info("audpp: ENABLE\n");
179 audpp->enabled = 1;
180 audpp_broadcast(audpp, id, msg);
181 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
182 pr_info("audpp: DISABLE\n");
183 audpp->enabled = 0;
184 audpp_broadcast(audpp, id, msg);
185 } else {
186 pr_err("audpp: invalid config msg %d\n", msg[0]);
188 break;
189 case AUDPP_MSG_ROUTING_ACK:
190 audpp_broadcast(audpp, id, msg);
191 break;
192 case AUDPP_MSG_FLUSH_ACK:
193 audpp_notify_clnt(audpp, msg[0], id, msg);
194 break;
195 default:
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)
207 uint16_t msg[1];
208 msg[0] = 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;
215 int res = 0;
217 if (id < -1 || id > 4)
218 return -EINVAL;
220 if (id == -1)
221 id = 5;
223 mutex_lock(audpp->lock);
224 if (audpp->func[id]) {
225 res = -EBUSY;
226 goto out;
229 audpp->func[id] = func;
230 audpp->private[id] = private;
232 LOG(EV_ENABLE, 1);
233 if (audpp->open_count++ == 0) {
234 pr_info("audpp: enable\n");
235 res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
236 if (res < 0) {
237 pr_err("audpp: cannot open AUDPPTASK\n");
238 audpp->open_count = 0;
239 audpp->func[id] = NULL;
240 audpp->private[id] = NULL;
241 goto out;
243 LOG(EV_ENABLE, 2);
244 msm_adsp_enable(audpp->mod);
245 audpp_dsp_config(1);
246 } else {
247 unsigned long flags;
248 local_irq_save(flags);
249 if (audpp->enabled)
250 audpp_fake_event(audpp, id,
251 AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
252 local_irq_restore(flags);
255 res = 0;
256 out:
257 mutex_unlock(audpp->lock);
258 return res;
260 EXPORT_SYMBOL(audpp_enable);
262 void audpp_disable(int id, void *private)
264 struct audpp_state *audpp = &the_audpp_state;
265 unsigned long flags;
267 if (id < -1 || id > 4)
268 return;
270 if (id == -1)
271 id = 5;
273 mutex_lock(audpp->lock);
274 LOG(EV_DISABLE, 1);
275 if (!audpp->func[id])
276 goto out;
277 if (audpp->private[id] != private)
278 goto out;
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");
288 LOG(EV_DISABLE, 2);
289 audpp_dsp_config(0);
290 msm_adsp_disable(audpp->mod);
291 msm_adsp_put(audpp->mod);
292 audpp->mod = NULL;
294 out:
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)
303 unsigned long flags;
304 audpp_cmd_avsync cmd;
306 if (BAD_ID(id))
307 return;
309 local_irq_save(flags);
310 if (rate)
311 the_audpp_state.avsync_mask |= (1 << id);
312 else
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;
328 unsigned val;
329 unsigned long flags;
330 unsigned mask;
332 if (BAD_ID(id))
333 return 0;
335 mask = 1 << id;
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];
340 else
341 val = 0;
342 local_irq_restore(flags);
344 return val;
346 EXPORT_SYMBOL(audpp_avsync_sample_count);
348 unsigned audpp_avsync_byte_count(int id)
350 uint16_t *avsync = the_audpp_state.avsync;
351 unsigned val;
352 unsigned long flags;
353 unsigned mask;
355 if (BAD_ID(id))
356 return 0;
358 mask = 1 << id;
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];
363 else
364 val = 0;
365 local_irq_restore(flags);
367 return val;
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 */
377 uint16_t cmd[11];
379 if (id > 6)
380 return -EINVAL;
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;
386 cmd[9] = volume;
387 cmd[10] = 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)];
398 if (id >= CH_COUNT)
399 return -EINVAL;
401 memset(pause_cmd, 0, sizeof(pause_cmd));
403 pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
404 if (pause == 1)
405 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
406 else if (pause == 0)
407 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
408 else
409 return -EINVAL;
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)];
419 if (id >= CH_COUNT)
420 return -EINVAL;
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);