Ensure FMODE_NONOTIFY is not set by userspace
[pandora-kernel.git] / drivers / staging / dream / qdsp5 / audpp.c
1
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.
7  *
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.
11  *
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.
16  *
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/wait.h>
22 #include <linux/delay.h>
23
24 #include <asm/atomic.h>
25 #include <asm/ioctls.h>
26 #include <mach/msm_adsp.h>
27
28 #include "audmgr.h"
29
30 #include <mach/qdsp5/qdsp5audppcmdi.h>
31 #include <mach/qdsp5/qdsp5audppmsg.h>
32
33 /* for queue ids - should be relative to module number*/
34 #include "adsp.h"
35
36 #include "evlog.h"
37
38
39 enum {
40         EV_NULL,
41         EV_ENABLE,
42         EV_DISABLE,
43         EV_EVENT,
44         EV_DATA,
45 };
46
47 static const char *dsp_log_strings[] = {
48         "NULL",
49         "ENABLE",
50         "DISABLE",
51         "EVENT",
52         "DATA",
53 };
54
55 DECLARE_LOG(dsp_log, 64, dsp_log_strings);
56
57 static int __init _dsp_log_init(void)
58 {
59         return ev_log_init(&dsp_log);
60 }
61 module_init(_dsp_log_init);
62 #define LOG(id,arg) ev_log_write(&dsp_log, id, arg)
63
64 static DEFINE_MUTEX(audpp_lock);
65
66 #define CH_COUNT 5
67 #define AUDPP_CLNT_MAX_COUNT 6
68 #define AUDPP_AVSYNC_INFO_SIZE 7
69
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;
77
78         /* which channels are actually enabled */
79         unsigned avsync_mask;
80
81         /* flags, 48 bits sample/bytes counter per channel */
82         uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
83 };
84
85 struct audpp_state the_audpp_state = {
86         .lock = &audpp_lock,
87 };
88
89 int audpp_send_queue1(void *cmd, unsigned len)
90 {
91         return msm_adsp_write(the_audpp_state.mod,
92                               QDSP_uPAudPPCmd1Queue, cmd, len);
93 }
94 EXPORT_SYMBOL(audpp_send_queue1);
95
96 int audpp_send_queue2(void *cmd, unsigned len)
97 {
98         return msm_adsp_write(the_audpp_state.mod,
99                               QDSP_uPAudPPCmd2Queue, cmd, len);
100 }
101 EXPORT_SYMBOL(audpp_send_queue2);
102
103 int audpp_send_queue3(void *cmd, unsigned len)
104 {
105         return msm_adsp_write(the_audpp_state.mod,
106                               QDSP_uPAudPPCmd3Queue, cmd, len);
107 }
108 EXPORT_SYMBOL(audpp_send_queue3);
109
110 static int audpp_dsp_config(int enable)
111 {
112         audpp_cmd_cfg cmd;
113
114         cmd.cmd_id = AUDPP_CMD_CFG;
115         cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
116
117         return audpp_send_queue1(&cmd, sizeof(cmd));
118 }
119
120 static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
121                             uint16_t *msg)
122 {
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);
127         }
128 }
129
130 static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
131                               unsigned id, uint16_t *msg)
132 {
133         if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
134                 audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
135 }
136
137 static void audpp_dsp_event(void *data, unsigned id, size_t len,
138                             void (*getevent)(void *ptr, size_t len))
139 {
140         struct audpp_state *audpp = data;
141         uint16_t msg[8];
142
143         if (id == AUDPP_MSG_AVSYNC_MSG) {
144                 getevent(audpp->avsync, sizeof(audpp->avsync));
145
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...
150                  */
151                 audpp->avsync[0] &= audpp->avsync_mask;
152                 return;
153         }
154
155         getevent(msg, sizeof(msg));
156
157         LOG(EV_EVENT, (id << 16) | msg[0]);
158         LOG(EV_DATA, (msg[1] << 16) | msg[2]);
159
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;
168                 }
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]);
187                 }
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);
197         }
198 }
199
200 static struct msm_adsp_ops adsp_ops = {
201         .event = audpp_dsp_event,
202 };
203
204 static void audpp_fake_event(struct audpp_state *audpp, int id,
205                              unsigned event, unsigned arg)
206 {
207         uint16_t msg[1];
208         msg[0] = arg;
209         audpp->func[id] (audpp->private[id], event, msg);
210 }
211
212 int audpp_enable(int id, audpp_event_func func, void *private)
213 {
214         struct audpp_state *audpp = &the_audpp_state;
215         int res = 0;
216
217         if (id < -1 || id > 4)
218                 return -EINVAL;
219
220         if (id == -1)
221                 id = 5;
222
223         mutex_lock(audpp->lock);
224         if (audpp->func[id]) {
225                 res = -EBUSY;
226                 goto out;
227         }
228
229         audpp->func[id] = func;
230         audpp->private[id] = private;
231
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;
242                 }
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);
253         }
254
255         res = 0;
256 out:
257         mutex_unlock(audpp->lock);
258         return res;
259 }
260 EXPORT_SYMBOL(audpp_enable);
261
262 void audpp_disable(int id, void *private)
263 {
264         struct audpp_state *audpp = &the_audpp_state;
265         unsigned long flags;
266
267         if (id < -1 || id > 4)
268                 return;
269
270         if (id == -1)
271                 id = 5;
272
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;
279
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);
285
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;
293         }
294 out:
295         mutex_unlock(audpp->lock);
296 }
297 EXPORT_SYMBOL(audpp_disable);
298
299 #define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
300
301 void audpp_avsync(int id, unsigned rate)
302 {
303         unsigned long flags;
304         audpp_cmd_avsync cmd;
305
306         if (BAD_ID(id))
307                 return;
308
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);
316
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));
322 }
323 EXPORT_SYMBOL(audpp_avsync);
324
325 unsigned audpp_avsync_sample_count(int id)
326 {
327         uint16_t *avsync = the_audpp_state.avsync;
328         unsigned val;
329         unsigned long flags;
330         unsigned mask;
331
332         if (BAD_ID(id))
333                 return 0;
334
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);
343
344         return val;
345 }
346 EXPORT_SYMBOL(audpp_avsync_sample_count);
347
348 unsigned audpp_avsync_byte_count(int id)
349 {
350         uint16_t *avsync = the_audpp_state.avsync;
351         unsigned val;
352         unsigned long flags;
353         unsigned mask;
354
355         if (BAD_ID(id))
356                 return 0;
357
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);
366
367         return val;
368 }
369 EXPORT_SYMBOL(audpp_avsync_byte_count);
370
371 #define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
372 #define AUDPP_CMD_VOLUME_PAN 0
373
374 int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan)
375 {
376         /* cmd, obj_cfg[7], cmd_type, volume, pan */
377         uint16_t cmd[11];
378
379         if (id > 6)
380                 return -EINVAL;
381
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;
388
389         return audpp_send_queue3(cmd, sizeof(cmd));
390 }
391 EXPORT_SYMBOL(audpp_set_volume_and_pan);
392
393 int audpp_pause(unsigned id, int pause)
394 {
395         /* pause 1 = pause 0 = resume */
396         u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
397
398         if (id >= CH_COUNT)
399                 return -EINVAL;
400
401         memset(pause_cmd, 0, sizeof(pause_cmd));
402
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;
410
411         return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
412 }
413 EXPORT_SYMBOL(audpp_pause);
414
415 int audpp_flush(unsigned id)
416 {
417         u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
418
419         if (id >= CH_COUNT)
420                 return -EINVAL;
421
422         memset(flush_cmd, 0, sizeof(flush_cmd));
423
424         flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
425         flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
426
427         return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
428 }
429 EXPORT_SYMBOL(audpp_flush);