blob: 712c9f323517379340caa8f7be73b0e7f6d3d224 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * pcm audio output device
3 *
4 * Copyright (C) 2008 Google, Inc.
5 * Copyright (C) 2008 HTC Corporation
Sidipotu Ashok6ba18202012-09-27 17:02:52 +05306 * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007 *
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 */
Santosh Mardifdc227a2011-07-11 17:20:34 +053018#include <asm/atomic.h>
19#include <asm/ioctls.h>
20
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021#include <linux/module.h>
22#include <linux/fs.h>
23#include <linux/miscdevice.h>
24#include <linux/uaccess.h>
25#include <linux/kthread.h>
26#include <linux/wait.h>
27#include <linux/dma-mapping.h>
28#include <linux/debugfs.h>
29#include <linux/delay.h>
30#include <linux/wakelock.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053031#include <linux/memory_alloc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <linux/msm_audio.h>
Stephen Boyd2fcabf92012-05-30 10:41:11 -070033#include <linux/pm_qos.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#include <mach/msm_adsp.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053036#include <mach/iommu.h>
37#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#include <mach/qdsp5v2/qdsp5audppcmdi.h>
39#include <mach/qdsp5v2/qdsp5audppmsg.h>
40#include <mach/qdsp5v2/audio_dev_ctl.h>
41#include <mach/qdsp5v2/audpp.h>
42#include <mach/qdsp5v2/audio_dev_ctl.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053043#include <mach/msm_memtypes.h>
Stephen Boyd2fcabf92012-05-30 10:41:11 -070044#include <mach/cpuidle.h>
Sidipotu Ashok6ba18202012-09-27 17:02:52 +053045#include <linux/msm_ion.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046#include <mach/htc_pwrsink.h>
47#include <mach/debug_mm.h>
48
49#define BUFSZ (960 * 5)
50#define DMASZ (BUFSZ * 2)
51
52#define HOSTPCM_STREAM_ID 5
53
54struct buffer {
55 void *data;
56 unsigned size;
57 unsigned used;
58 unsigned addr;
59};
60
61struct audio {
62 struct buffer out[2];
63
64 spinlock_t dsp_lock;
65
66 uint8_t out_head;
67 uint8_t out_tail;
68 uint8_t out_needed; /* number of buffers the dsp is waiting for */
69
70 atomic_t out_bytes;
71
72 struct mutex lock;
73 struct mutex write_lock;
74 wait_queue_head_t wait;
75
76 /* configuration to use on next enable */
77 uint32_t out_sample_rate;
78 uint32_t out_channel_mode;
79 uint32_t out_weight;
80 uint32_t out_buffer_size;
81 uint32_t device_events;
82 int16_t source;
83
84 /* data allocated for various buffers */
85 char *data;
86 dma_addr_t phys;
Laura Abbott61399692012-04-30 14:25:46 -070087 void *map_v_write;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088 int teos; /* valid only if tunnel mode & no data left for decoder */
89 int opened;
90 int enabled;
91 int running;
92 int stopped; /* set when stopped, cleared on flush */
93 uint16_t dec_id;
94 int voice_state;
95
96 struct wake_lock wakelock;
Stephen Boyd2fcabf92012-05-30 10:41:11 -070097 struct pm_qos_request pm_qos_req;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098
99 struct audpp_cmd_cfg_object_params_volume vol_pan;
Sidipotu Ashok6ba18202012-09-27 17:02:52 +0530100 struct ion_client *client;
101 struct ion_handle *buff_handle;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102};
103
104static void audio_out_listener(u32 evt_id, union auddev_evt_data *evt_payload,
105 void *private_data)
106{
107 struct audio *audio = private_data;
108 switch (evt_id) {
109 case AUDDEV_EVT_DEV_RDY:
110 MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
111 audio->source |= (0x1 << evt_payload->routing_id);
112 if (audio->running == 1 && audio->enabled == 1)
113 audpp_route_stream(audio->dec_id, audio->source);
114 break;
115 case AUDDEV_EVT_DEV_RLS:
116 MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
117 audio->source &= ~(0x1 << evt_payload->routing_id);
118 if (audio->running == 1 && audio->enabled == 1)
119 audpp_route_stream(audio->dec_id, audio->source);
120 break;
121 case AUDDEV_EVT_STREAM_VOL_CHG:
122 audio->vol_pan.volume = evt_payload->session_vol;
123 MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
124 audio->vol_pan.volume);
125 if (audio->running)
126 audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
127 POPP);
128 break;
129 case AUDDEV_EVT_VOICE_STATE_CHG:
130 MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n",
131 evt_payload->voice_state);
132 audio->voice_state = evt_payload->voice_state;
133 /* Voice uplink Rx case */
134 if (audio->running &&
135 (audio->source & AUDPP_MIXER_UPLINK_RX) &&
136 (audio->voice_state == VOICE_STATE_OFFCALL)) {
137 MM_DBG("Voice is terminated, Wake up write: %x %x\n",
138 audio->voice_state, audio->source);
139 wake_up(&audio->wait);
140 }
141 break;
142 default:
143 MM_ERR("ERROR:wrong event\n");
144 break;
145 }
146}
147
148static void audio_prevent_sleep(struct audio *audio)
149{
150 MM_DBG("\n"); /* Macro prints the file name and function */
151 wake_lock(&audio->wakelock);
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700152 pm_qos_update_request(&audio->pm_qos_req,
153 msm_cpuidle_get_deep_idle_latency());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154}
155
156static void audio_allow_sleep(struct audio *audio)
157{
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700158 pm_qos_update_request(&audio->pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 wake_unlock(&audio->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 MM_DBG("\n"); /* Macro prints the file name and function */
161}
162
163static int audio_dsp_out_enable(struct audio *audio, int yes);
164static int audio_dsp_send_buffer(struct audio *audio, unsigned id,
165 unsigned len);
166
167static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
168
169/* must be called with audio->lock held */
170static int audio_enable(struct audio *audio)
171{
172 MM_DBG("\n"); /* Macro prints the file name and function */
173
174 if (audio->enabled)
175 return 0;
176
177 /* refuse to start if we're not ready */
178 if (!audio->out[0].used || !audio->out[1].used)
179 return -EIO;
180
181 /* we start buffers 0 and 1, so buffer 0 will be the
182 * next one the dsp will want
183 */
184 audio->out_tail = 0;
185 audio->out_needed = 0;
186
187 audio_prevent_sleep(audio);
188
189 if (audpp_enable(-1, audio_dsp_event, audio)) {
190 MM_ERR("audpp_enable() failed\n");
191 audio_allow_sleep(audio);
192 return -ENODEV;
193 }
194
195 audio->enabled = 1;
196 htc_pwrsink_set(PWRSINK_AUDIO, 100);
197 return 0;
198}
199
200/* must be called with audio->lock held */
201static int audio_disable(struct audio *audio)
202{
203 MM_DBG("\n"); /* Macro prints the file name and function */
204 if (audio->enabled) {
205 audio->enabled = 0;
206 audio_dsp_out_enable(audio, 0);
207
208 audpp_disable(-1, audio);
209
210 wake_up(&audio->wait);
211 audio->out_needed = 0;
212 audio_allow_sleep(audio);
213 }
214 return 0;
215}
216
217/* ------------------- dsp --------------------- */
218static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
219{
220 struct audio *audio = private;
221 struct buffer *frame;
222 unsigned long flags;
223 static unsigned long pcmdmamsd_time;
224
225 switch (id) {
226 case AUDPP_MSG_HOST_PCM_INTF_MSG: {
227 unsigned id = msg[3];
228 unsigned idx = msg[4] - 1;
229
230 MM_DBG("HOST_PCM id %d idx %d\n", id, idx);
231 if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
232 MM_ERR("bogus id\n");
233 break;
234 }
235 if (idx > 1) {
236 MM_ERR("bogus buffer idx\n");
237 break;
238 }
239 spin_lock_irqsave(&audio->dsp_lock, flags);
240 if (audio->running) {
241 atomic_add(audio->out[idx].used, &audio->out_bytes);
242 audio->out[idx].used = 0;
243 frame = audio->out + audio->out_tail;
244 if (frame->used) {
245 /* Reset teos flag to avoid stale
246 * PCMDMAMISS been considered
247 */
248 audio->teos = 0;
249 audio_dsp_send_buffer(
250 audio, audio->out_tail, frame->used);
251 audio->out_tail ^= 1;
252 } else {
253 audio->out_needed++;
254 }
255 wake_up(&audio->wait);
256 }
257 spin_unlock_irqrestore(&audio->dsp_lock, flags);
258 break;
259 }
260 case AUDPP_MSG_PCMDMAMISSED:
261 /* prints only if 1 second is elapsed since the last time
262 * this message has been printed */
263 if (printk_timed_ratelimit(&pcmdmamsd_time, 1000))
264 printk(KERN_INFO "[%s:%s] PCMDMAMISSED %d\n",
265 __MM_FILE__, __func__, msg[0]);
266 audio->teos++;
267 MM_DBG("PCMDMAMISSED Count per Buffer %d\n", audio->teos);
268 wake_up(&audio->wait);
269 break;
270 case AUDPP_MSG_CFG_MSG:
271 if (msg[0] == AUDPP_MSG_ENA_ENA) {
272 MM_DBG("CFG_MSG ENABLE\n");
273 audio->out_needed = 0;
274 audio->running = 1;
275 audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
276 POPP);
277 audpp_route_stream(audio->dec_id, audio->source);
278 audio_dsp_out_enable(audio, 1);
279 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
280 MM_DBG("CFG_MSG DISABLE\n");
281 audio->running = 0;
282 } else {
283 MM_ERR("CFG_MSG %d?\n", msg[0]);
284 }
285 break;
286 default:
287 MM_ERR("UNKNOWN (%d)\n", id);
288 }
289}
290
291static int audio_dsp_out_enable(struct audio *audio, int yes)
292{
293 struct audpp_cmd_pcm_intf cmd;
294
295 memset(&cmd, 0, sizeof(cmd));
296 cmd.cmd_id = AUDPP_CMD_PCM_INTF;
297 cmd.stream = AUDPP_CMD_POPP_STREAM;
298 cmd.stream_id = audio->dec_id;
299 cmd.config = AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
300 cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
301
302 if (yes) {
303 cmd.write_buf1LSW = audio->out[0].addr;
304 cmd.write_buf1MSW = audio->out[0].addr >> 16;
305 if (audio->out[0].used)
306 cmd.write_buf1_len = audio->out[0].used;
307 else
308 cmd.write_buf1_len = audio->out[0].size;
309 cmd.write_buf2LSW = audio->out[1].addr;
310 cmd.write_buf2MSW = audio->out[1].addr >> 16;
311 if (audio->out[1].used)
312 cmd.write_buf2_len = audio->out[1].used;
313 else
314 cmd.write_buf2_len = audio->out[1].size;
315 cmd.arm_to_rx_flag = AUDPP_CMD_PCM_INTF_ENA_V;
316 cmd.weight_decoder_to_rx = audio->out_weight;
317 cmd.weight_arm_to_rx = 1;
318 cmd.partition_number_arm_to_dsp = 0;
319 cmd.sample_rate = audio->out_sample_rate;
320 cmd.channel_mode = audio->out_channel_mode;
321 }
322
323 return audpp_send_queue2(&cmd, sizeof(cmd));
324}
325
326static int audio_dsp_send_buffer(struct audio *audio, unsigned idx,
327 unsigned len)
328{
329 struct audpp_cmd_pcm_intf_send_buffer cmd;
330
331 cmd.cmd_id = AUDPP_CMD_PCM_INTF;
332 cmd.stream = AUDPP_CMD_POPP_STREAM;
333 cmd.stream_id = audio->dec_id;
334 cmd.config = AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
335 cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
336 cmd.dsp_to_arm_buf_id = 0;
337 cmd.arm_to_dsp_buf_id = idx + 1;
338 cmd.arm_to_dsp_buf_len = len;
339
340 return audpp_send_queue2(&cmd, sizeof(cmd));
341}
342
343/* ------------------- device --------------------- */
344static void audio_flush(struct audio *audio)
345{
346 audio->out[0].used = 0;
347 audio->out[1].used = 0;
348 audio->out_head = 0;
349 audio->out_tail = 0;
350 audio->stopped = 0;
351}
352
353static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
354{
355 struct audio *audio = file->private_data;
356 int rc = -EINVAL;
357 unsigned long flags = 0;
358
359 if (cmd == AUDIO_GET_STATS) {
360 struct msm_audio_stats stats;
361 stats.byte_count = atomic_read(&audio->out_bytes);
362 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
363 return -EFAULT;
364 return 0;
365 }
366
367 switch (cmd) {
368 case AUDIO_SET_VOLUME:
369 spin_lock_irqsave(&audio->dsp_lock, flags);
370 audio->vol_pan.volume = arg;
371 if (audio->running)
372 audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
373 POPP);
374 spin_unlock_irqrestore(&audio->dsp_lock, flags);
375 return 0;
376
377 case AUDIO_SET_PAN:
378 spin_lock_irqsave(&audio->dsp_lock, flags);
379 audio->vol_pan.pan = arg;
380 if (audio->running)
381 audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
382 POPP);
383 spin_unlock_irqrestore(&audio->dsp_lock, flags);
384 return 0;
385 }
386
387 mutex_lock(&audio->lock);
388 switch (cmd) {
389 case AUDIO_START:
390 if ((audio->voice_state != VOICE_STATE_INCALL)
391 && (audio->source & AUDPP_MIXER_UPLINK_RX)) {
392 MM_ERR("Unable to Start : state %d source %d\n",
393 audio->voice_state, audio->source);
394 rc = -EPERM;
395 break;
396 }
397 rc = audio_enable(audio);
398 break;
399 case AUDIO_STOP:
400 rc = audio_disable(audio);
401 audio->stopped = 1;
402 break;
403 case AUDIO_FLUSH:
404 if (audio->stopped) {
405 /* Make sure we're stopped and we wake any threads
406 * that might be blocked holding the write_lock.
407 * While audio->stopped write threads will always
408 * exit immediately.
409 */
410 wake_up(&audio->wait);
411 mutex_lock(&audio->write_lock);
412 audio_flush(audio);
413 mutex_unlock(&audio->write_lock);
414 }
415 case AUDIO_SET_CONFIG: {
416 struct msm_audio_config config;
417 if (copy_from_user(&config, (void *) arg, sizeof(config))) {
418 rc = -EFAULT;
419 break;
420 }
421 if (config.channel_count == 1)
422 config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
423 else if (config.channel_count == 2)
424 config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
425 else {
426 rc = -EINVAL;
427 break;
428 }
429 audio->out_sample_rate = config.sample_rate;
430 audio->out_channel_mode = config.channel_count;
431 rc = 0;
432 break;
433 }
434 case AUDIO_GET_CONFIG: {
435 struct msm_audio_config config;
436 config.buffer_size = BUFSZ;
437 config.buffer_count = 2;
438 config.sample_rate = audio->out_sample_rate;
439 if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
440 config.channel_count = 1;
441 else
442 config.channel_count = 2;
443
444 config.unused[0] = 0;
445 config.unused[1] = 0;
446 config.unused[2] = 0;
447 if (copy_to_user((void *) arg, &config, sizeof(config)))
448 rc = -EFAULT;
449 else
450 rc = 0;
451 break;
452 }
453 case AUDIO_GET_SESSION_ID: {
454 if (copy_to_user((void *) arg, &audio->dec_id,
455 sizeof(unsigned short)))
456 return -EFAULT;
457 rc = 0;
458 break;
459 }
460 default:
461 rc = -EINVAL;
462 }
463 mutex_unlock(&audio->lock);
464 return rc;
465}
466
467/* Only useful in tunnel-mode */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700468static int audio_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469{
470 struct audio *audio = file->private_data;
471 int rc = 0;
472
473 if (!audio->running)
474 return -EINVAL;
475
476 mutex_lock(&audio->write_lock);
477
478 /* PCM DMAMISS message is sent only once in
479 * hpcm interface. So, wait for buffer complete
480 * and teos flag.
481 */
482 rc = wait_event_interruptible(audio->wait,
483 (!audio->out[0].used &&
484 !audio->out[1].used));
485
486 if (rc < 0)
487 goto done;
488
489 rc = wait_event_interruptible(audio->wait,
490 audio->teos);
491done:
492 mutex_unlock(&audio->write_lock);
493 return rc;
494}
495
496static ssize_t audio_read(struct file *file, char __user *buf,
497 size_t count, loff_t *pos)
498{
499 return -EINVAL;
500}
501
502static inline int rt_policy(int policy)
503{
504 if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
505 return 1;
506 return 0;
507}
508
509static inline int task_has_rt_policy(struct task_struct *p)
510{
511 return rt_policy(p->policy);
512}
513
514static ssize_t audio_write(struct file *file, const char __user *buf,
515 size_t count, loff_t *pos)
516{
517 struct sched_param s = { .sched_priority = 1 };
518 struct audio *audio = file->private_data;
519 unsigned long flags;
520 const char __user *start = buf;
521 struct buffer *frame;
522 size_t xfer;
523 int old_prio = current->rt_priority;
524 int old_policy = current->policy;
525 int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
526 int rc = 0;
527
528
529 if ((audio->voice_state == VOICE_STATE_OFFCALL)
530 && (audio->source & AUDPP_MIXER_UPLINK_RX) &&
531 audio->running) {
532 MM_ERR("Not Permitted Voice Terminated: state %d source %x \
533 running %d\n",
534 audio->voice_state, audio->source, audio->running);
535 return -EPERM;
536 }
537 /* just for this write, set us real-time */
538 if (!task_has_rt_policy(current)) {
539 struct cred *new = prepare_creds();
540 cap_raise(new->cap_effective, CAP_SYS_NICE);
541 commit_creds(new);
542 if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
543 MM_ERR("sched_setscheduler failed\n");
544 }
545
546 mutex_lock(&audio->write_lock);
547 while (count > 0) {
548 frame = audio->out + audio->out_head;
549
550 rc = wait_event_interruptible(audio->wait,
551 (frame->used == 0) || (audio->stopped) ||
552 ((audio->voice_state == VOICE_STATE_OFFCALL) &&
553 (audio->source & AUDPP_MIXER_UPLINK_RX)));
554
555 if (rc < 0)
556 break;
557 if (audio->stopped) {
558 rc = -EBUSY;
559 break;
560 } else if ((audio->voice_state == VOICE_STATE_OFFCALL) &&
561 (audio->source & AUDPP_MIXER_UPLINK_RX)) {
562 MM_ERR("Not Permitted Voice Terminated: %d\n",
563 audio->voice_state);
564 rc = -EPERM;
565 break;
566 }
567
568 xfer = count > frame->size ? frame->size : count;
569 if (copy_from_user(frame->data, buf, xfer)) {
570 rc = -EFAULT;
571 break;
572 }
573 frame->used = xfer;
574 audio->out_head ^= 1;
575 count -= xfer;
576 buf += xfer;
577
578 spin_lock_irqsave(&audio->dsp_lock, flags);
579 frame = audio->out + audio->out_tail;
580 if (frame->used && audio->out_needed) {
581 /* Reset teos flag to avoid stale
582 * PCMDMAMISS been considered
583 */
584 audio->teos = 0;
585 audio_dsp_send_buffer(audio, audio->out_tail,
586 frame->used);
587 audio->out_tail ^= 1;
588 audio->out_needed--;
589 }
590 spin_unlock_irqrestore(&audio->dsp_lock, flags);
591 }
592
593 mutex_unlock(&audio->write_lock);
594
595 /* restore scheduling policy and priority */
596 if (!rt_policy(old_policy)) {
597 struct sched_param v = { .sched_priority = old_prio };
598 if ((sched_setscheduler(current, old_policy, &v)) < 0)
599 MM_ERR("sched_setscheduler failed\n");
600 if (likely(!cap_nice)) {
601 struct cred *new = prepare_creds();
602 cap_lower(new->cap_effective, CAP_SYS_NICE);
603 commit_creds(new);
604 }
605 }
606
607 if (buf > start)
608 return buf - start;
609 return rc;
610}
611
612static int audio_release(struct inode *inode, struct file *file)
613{
614 struct audio *audio = file->private_data;
615
616 mutex_lock(&audio->lock);
617 auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
618 audio_disable(audio);
619 audio_flush(audio);
620 audio->opened = 0;
621 mutex_unlock(&audio->lock);
622 htc_pwrsink_set(PWRSINK_AUDIO, 0);
623 return 0;
624}
625
626static struct audio the_audio;
627
628static int audio_open(struct inode *inode, struct file *file)
629{
630 struct audio *audio = &the_audio;
631 int rc;
632
633 mutex_lock(&audio->lock);
634
635 if (audio->opened) {
636 MM_ERR("busy\n");
637 rc = -EBUSY;
638 goto done;
639 }
640
641
642 audio->dec_id = HOSTPCM_STREAM_ID;
643
644 audio->out_buffer_size = BUFSZ;
645 audio->out_sample_rate = 44100;
646 audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
647 audio->out_weight = 100;
648
649 audio->out[0].data = audio->data + 0;
650 audio->out[0].addr = audio->phys + 0;
651 audio->out[0].size = BUFSZ;
652
653 audio->out[1].data = audio->data + BUFSZ;
654 audio->out[1].addr = audio->phys + BUFSZ;
655 audio->out[1].size = BUFSZ;
656
657 audio->vol_pan.volume = 0x2000;
658 audio->vol_pan.pan = 0x0;
659 audio->source = 0x0;
660
661 audio_flush(audio);
662 audio->voice_state = msm_get_voice_state();
663 MM_DBG("voice_state = %x\n", audio->voice_state);
664 audio->device_events = AUDDEV_EVT_DEV_RDY
665 |AUDDEV_EVT_DEV_RLS|
666 AUDDEV_EVT_STREAM_VOL_CHG|
667 AUDDEV_EVT_VOICE_STATE_CHG;
668
669 MM_DBG("register for event callback pdata %p\n", audio);
670 rc = auddev_register_evt_listner(audio->device_events,
671 AUDDEV_CLNT_DEC,
672 audio->dec_id,
673 audio_out_listener,
674 (void *)audio);
675 if (rc) {
676 MM_ERR("%s: failed to register listener\n", __func__);
677 goto done;
678 }
679
680 file->private_data = audio;
681 audio->opened = 1;
682 rc = 0;
683done:
684 mutex_unlock(&audio->lock);
685 return rc;
686}
687
688static const struct file_operations audio_fops = {
689 .owner = THIS_MODULE,
690 .open = audio_open,
691 .release = audio_release,
692 .read = audio_read,
693 .write = audio_write,
694 .unlocked_ioctl = audio_ioctl,
695 .fsync = audio_fsync,
696};
697
698struct miscdevice audio_misc = {
699 .minor = MISC_DYNAMIC_MINOR,
700 .name = "msm_pcm_out",
701 .fops = &audio_fops,
702};
703
704static int __init audio_init(void)
705{
Sidipotu Ashok6ba18202012-09-27 17:02:52 +0530706 unsigned long ionflag = 0;
707 ion_phys_addr_t addr = 0;
708 int rc;
709 int len = 0;
710 struct ion_handle *handle = NULL;
711 struct ion_client *client = NULL;
712
713 client = msm_ion_client_create(UINT_MAX, "HostPCM");
714 if (IS_ERR_OR_NULL(client)) {
715 MM_ERR("Unable to create ION client\n");
716 rc = -ENOMEM;
717 goto client_create_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718 }
Sidipotu Ashok6ba18202012-09-27 17:02:52 +0530719 the_audio.client = client;
720
721 handle = ion_alloc(client, DMASZ, SZ_4K,
722 ION_HEAP(ION_AUDIO_HEAP_ID), 0);
723 if (IS_ERR_OR_NULL(handle)) {
724 MM_ERR("Unable to create allocate O/P buffers\n");
725 rc = -ENOMEM;
726 goto buff_alloc_error;
727 }
728 the_audio.buff_handle = handle;
729
730 rc = ion_phys(client, handle, &addr, &len);
731 if (rc) {
732 MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
733 (unsigned int) addr, (unsigned int) len);
734 goto buff_get_phys_error;
735 } else
736 MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
737 (unsigned int) addr, (unsigned int) len);
738 the_audio.phys = (int32_t)addr;
739
740 rc = ion_handle_get_flags(client, handle, &ionflag);
741 if (rc) {
742 MM_ERR("could not get flags for the handle\n");
743 goto buff_get_flags_error;
744 }
745
746 the_audio.map_v_write = ion_map_kernel(client, handle);
747 if (IS_ERR(the_audio.map_v_write)) {
748 MM_ERR("could not map write buffers\n");
749 rc = -ENOMEM;
750 goto buff_map_error;
751 }
752 the_audio.data = (char *)the_audio.map_v_write;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700753 MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
754 (int) the_audio.data, (int) the_audio.phys);
755 mutex_init(&the_audio.lock);
756 mutex_init(&the_audio.write_lock);
757 spin_lock_init(&the_audio.dsp_lock);
758 init_waitqueue_head(&the_audio.wait);
759 wake_lock_init(&the_audio.wakelock, WAKE_LOCK_SUSPEND, "audio_pcm");
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700760 pm_qos_add_request(&the_audio.pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
761 PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700762 return misc_register(&audio_misc);
Sidipotu Ashok6ba18202012-09-27 17:02:52 +0530763buff_map_error:
764buff_get_phys_error:
765buff_get_flags_error:
766 ion_free(client, the_audio.buff_handle);
767buff_alloc_error:
768 ion_client_destroy(client);
769client_create_error:
770 return rc;
771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772}
773
774late_initcall(audio_init);