aboutsummaryrefslogtreecommitdiffstats
path: root/sound/aoa/soundbus
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-02-08 08:25:39 -0500
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:04:02 -0500
commit547ac2ae3890b8e17bcfea4ba8840a10f3496da4 (patch)
tree723d9b290f2f7b47be61c00badd1eecb6aa20468 /sound/aoa/soundbus
parent2cf9f0fc69358e15e78f936c220cfe8aa208111d (diff)
[ALSA] aoa i2sbus: Stop Apple i2s DMA gracefully
This fixes the problem of getting extra bytes inserted at the beginning of a recording when using the Apple i2s interface and DBDMA controller. It turns out that we can't just abort the DMA; we have to let it stop at the end of a command, and then wait for the S7 bit to be set before turning off the DBDMA controller. Doing that for playback doesn't seem to be necessary, but doesn't hurt either. We use the technique used by the Darwin driver: make each transfer command branch to a stop command if the S0 status bit is set. Thus we can ask the DMA controller to stop at the end of the current command by setting S0. The interrupt routine now looks at and clears the status word of the DBDMA command ring. This is necessary so it can know when the DBDMA controller has seen that S0 is set, and so when it should look for the DBDMA controller being stopped and S7 being set. This also ended up simplifying the calculation in i2sbus_pcm_pointer. Tested on a 15 inch albook. [Addition by Johannes] I modified this patch and added the suspend/resume bits to it to get my powermac into a decent state when playing sound across suspend to disk that has a different bitrate from what the firmware programs the hardware to. I also added the SNDRV_PCM_INFO_JOINT_DUPLEX flag because it seemed the right thing to do and I was looking at the info stuff. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/aoa/soundbus')
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-core.c22
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-pcm.c328
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus.h6
3 files changed, 210 insertions, 146 deletions
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
index e593a1333fe3..e36f6aa448d4 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
@@ -41,8 +41,8 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
41 struct dbdma_command_mem *r, 41 struct dbdma_command_mem *r,
42 int numcmds) 42 int numcmds)
43{ 43{
44 /* one more for rounding */ 44 /* one more for rounding, one for branch back, one for stop command */
45 r->size = (numcmds+1) * sizeof(struct dbdma_cmd); 45 r->size = (numcmds + 3) * sizeof(struct dbdma_cmd);
46 /* We use the PCI APIs for now until the generic one gets fixed 46 /* We use the PCI APIs for now until the generic one gets fixed
47 * enough or until we get some macio-specific versions 47 * enough or until we get some macio-specific versions
48 */ 48 */
@@ -377,11 +377,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
377 if (i2sdev->sound.pcm) { 377 if (i2sdev->sound.pcm) {
378 /* Suspend PCM streams */ 378 /* Suspend PCM streams */
379 snd_pcm_suspend_all(i2sdev->sound.pcm); 379 snd_pcm_suspend_all(i2sdev->sound.pcm);
380 /* Probably useless as we handle
381 * power transitions ourselves */
382 snd_power_change_state(i2sdev->sound.pcm->card,
383 SNDRV_CTL_POWER_D3hot);
384 } 380 }
381
385 /* Notify codecs */ 382 /* Notify codecs */
386 list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { 383 list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
387 err = 0; 384 err = 0;
@@ -390,7 +387,11 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
390 if (err) 387 if (err)
391 ret = err; 388 ret = err;
392 } 389 }
390
391 /* wait until streams are stopped */
392 i2sbus_wait_for_stop_both(i2sdev);
393 } 393 }
394
394 return ret; 395 return ret;
395} 396}
396 397
@@ -402,6 +403,9 @@ static int i2sbus_resume(struct macio_dev* dev)
402 int err, ret = 0; 403 int err, ret = 0;
403 404
404 list_for_each_entry(i2sdev, &control->list, item) { 405 list_for_each_entry(i2sdev, &control->list, item) {
406 /* reset i2s bus format etc. */
407 i2sbus_pcm_prepare_both(i2sdev);
408
405 /* Notify codecs so they can re-initialize */ 409 /* Notify codecs so they can re-initialize */
406 list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { 410 list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
407 err = 0; 411 err = 0;
@@ -410,12 +414,6 @@ static int i2sbus_resume(struct macio_dev* dev)
410 if (err) 414 if (err)
411 ret = err; 415 ret = err;
412 } 416 }
413 /* Notify Alsa */
414 if (i2sdev->sound.pcm) {
415 /* Same comment as above, probably useless */
416 snd_power_change_state(i2sdev->sound.pcm->card,
417 SNDRV_CTL_POWER_D0);
418 }
419 } 417 }
420 418
421 return ret; 419 return ret;
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
index 7c81db7e52c1..c6b42f9bdbc9 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
@@ -125,7 +125,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
125 } 125 }
126 /* bus dependent stuff */ 126 /* bus dependent stuff */
127 hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 127 hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
128 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME; 128 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
129 SNDRV_PCM_INFO_JOINT_DUPLEX;
129 130
130 CHECK_RATE(5512); 131 CHECK_RATE(5512);
131 CHECK_RATE(8000); 132 CHECK_RATE(8000);
@@ -245,18 +246,78 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
245 return err; 246 return err;
246} 247}
247 248
249static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev,
250 struct pcm_info *pi)
251{
252 unsigned long flags;
253 struct completion done;
254 long timeout;
255
256 spin_lock_irqsave(&i2sdev->low_lock, flags);
257 if (pi->dbdma_ring.stopping) {
258 init_completion(&done);
259 pi->stop_completion = &done;
260 spin_unlock_irqrestore(&i2sdev->low_lock, flags);
261 timeout = wait_for_completion_timeout(&done, HZ);
262 spin_lock_irqsave(&i2sdev->low_lock, flags);
263 pi->stop_completion = NULL;
264 if (timeout == 0) {
265 /* timeout expired, stop dbdma forcefully */
266 printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n");
267 /* make sure RUN, PAUSE and S0 bits are cleared */
268 out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
269 pi->dbdma_ring.stopping = 0;
270 timeout = 10;
271 while (in_le32(&pi->dbdma->status) & ACTIVE) {
272 if (--timeout <= 0)
273 break;
274 udelay(1);
275 }
276 }
277 }
278 spin_unlock_irqrestore(&i2sdev->low_lock, flags);
279}
280
281#ifdef CONFIG_PM
282void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
283{
284 struct pcm_info *pi;
285
286 get_pcm_info(i2sdev, 0, &pi, NULL);
287 i2sbus_wait_for_stop(i2sdev, pi);
288 get_pcm_info(i2sdev, 1, &pi, NULL);
289 i2sbus_wait_for_stop(i2sdev, pi);
290}
291#endif
292
248static int i2sbus_hw_params(struct snd_pcm_substream *substream, 293static int i2sbus_hw_params(struct snd_pcm_substream *substream,
249 struct snd_pcm_hw_params *params) 294 struct snd_pcm_hw_params *params)
250{ 295{
251 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); 296 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
252} 297}
253 298
254static int i2sbus_hw_free(struct snd_pcm_substream *substream) 299static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
255{ 300{
301 struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
302 struct pcm_info *pi;
303
304 get_pcm_info(i2sdev, in, &pi, NULL);
305 if (pi->dbdma_ring.stopping)
306 i2sbus_wait_for_stop(i2sdev, pi);
256 snd_pcm_lib_free_pages(substream); 307 snd_pcm_lib_free_pages(substream);
257 return 0; 308 return 0;
258} 309}
259 310
311static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
312{
313 return i2sbus_hw_free(substream, 0);
314}
315
316static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
317{
318 return i2sbus_hw_free(substream, 1);
319}
320
260static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) 321static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
261{ 322{
262 /* whee. Hard work now. The user has selected a bitrate 323 /* whee. Hard work now. The user has selected a bitrate
@@ -264,7 +325,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
264 * I2S controller appropriately. */ 325 * I2S controller appropriately. */
265 struct snd_pcm_runtime *runtime; 326 struct snd_pcm_runtime *runtime;
266 struct dbdma_cmd *command; 327 struct dbdma_cmd *command;
267 int i, periodsize; 328 int i, periodsize, nperiods;
268 dma_addr_t offset; 329 dma_addr_t offset;
269 struct bus_info bi; 330 struct bus_info bi;
270 struct codec_info_item *cii; 331 struct codec_info_item *cii;
@@ -274,6 +335,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
274 struct pcm_info *pi, *other; 335 struct pcm_info *pi, *other;
275 int cnt; 336 int cnt;
276 int result = 0; 337 int result = 0;
338 unsigned int cmd, stopaddr;
277 339
278 mutex_lock(&i2sdev->lock); 340 mutex_lock(&i2sdev->lock);
279 341
@@ -283,6 +345,13 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
283 result = -EBUSY; 345 result = -EBUSY;
284 goto out_unlock; 346 goto out_unlock;
285 } 347 }
348 if (pi->dbdma_ring.stopping)
349 i2sbus_wait_for_stop(i2sdev, pi);
350
351 if (!pi->substream || !pi->substream->runtime) {
352 result = -EINVAL;
353 goto out_unlock;
354 }
286 355
287 runtime = pi->substream->runtime; 356 runtime = pi->substream->runtime;
288 pi->active = 1; 357 pi->active = 1;
@@ -297,24 +366,43 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
297 i2sdev->rate = runtime->rate; 366 i2sdev->rate = runtime->rate;
298 367
299 periodsize = snd_pcm_lib_period_bytes(pi->substream); 368 periodsize = snd_pcm_lib_period_bytes(pi->substream);
369 nperiods = pi->substream->runtime->periods;
300 pi->current_period = 0; 370 pi->current_period = 0;
301 371
302 /* generate dbdma command ring first */ 372 /* generate dbdma command ring first */
303 command = pi->dbdma_ring.cmds; 373 command = pi->dbdma_ring.cmds;
374 memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd));
375
376 /* commands to DMA to/from the ring */
377 /*
378 * For input, we need to do a graceful stop; if we abort
379 * the DMA, we end up with leftover bytes that corrupt
380 * the next recording. To do this we set the S0 status
381 * bit and wait for the DMA controller to stop. Each
382 * command has a branch condition to
383 * make it branch to a stop command if S0 is set.
384 * On input we also need to wait for the S7 bit to be
385 * set before turning off the DMA controller.
386 * In fact we do the graceful stop for output as well.
387 */
304 offset = runtime->dma_addr; 388 offset = runtime->dma_addr;
305 for (i = 0; i < pi->substream->runtime->periods; 389 cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS;
306 i++, command++, offset += periodsize) { 390 stopaddr = pi->dbdma_ring.bus_cmd_start +
307 memset(command, 0, sizeof(struct dbdma_cmd)); 391 (nperiods + 1) * sizeof(struct dbdma_cmd);
308 command->command = 392 for (i = 0; i < nperiods; i++, command++, offset += periodsize) {
309 cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS); 393 command->command = cpu_to_le16(cmd);
394 command->cmd_dep = cpu_to_le32(stopaddr);
310 command->phy_addr = cpu_to_le32(offset); 395 command->phy_addr = cpu_to_le32(offset);
311 command->req_count = cpu_to_le16(periodsize); 396 command->req_count = cpu_to_le16(periodsize);
312 command->xfer_status = cpu_to_le16(0);
313 } 397 }
314 /* last one branches back to first */ 398
315 command--; 399 /* branch back to beginning of ring */
316 command->command |= cpu_to_le16(BR_ALWAYS); 400 command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
317 command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start); 401 command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start);
402 command++;
403
404 /* set stop command */
405 command->command = cpu_to_le16(DBDMA_STOP);
318 406
319 /* ok, let's set the serial format and stuff */ 407 /* ok, let's set the serial format and stuff */
320 switch (runtime->format) { 408 switch (runtime->format) {
@@ -435,16 +523,18 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
435 return result; 523 return result;
436} 524}
437 525
438static struct dbdma_cmd STOP_CMD = { 526#ifdef CONFIG_PM
439 .command = __constant_cpu_to_le16(DBDMA_STOP), 527void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev)
440}; 528{
529 i2sbus_pcm_prepare(i2sdev, 0);
530 i2sbus_pcm_prepare(i2sdev, 1);
531}
532#endif
441 533
442static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) 534static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
443{ 535{
444 struct codec_info_item *cii; 536 struct codec_info_item *cii;
445 struct pcm_info *pi; 537 struct pcm_info *pi;
446 int timeout;
447 struct dbdma_cmd tmp;
448 int result = 0; 538 int result = 0;
449 unsigned long flags; 539 unsigned long flags;
450 540
@@ -464,92 +554,50 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
464 cii->codec->start(cii, pi->substream); 554 cii->codec->start(cii, pi->substream);
465 pi->dbdma_ring.running = 1; 555 pi->dbdma_ring.running = 1;
466 556
467 /* reset dma engine */ 557 if (pi->dbdma_ring.stopping) {
468 out_le32(&pi->dbdma->control, 558 /* Clear the S0 bit, then see if we stopped yet */
469 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); 559 out_le32(&pi->dbdma->control, 1 << 16);
470 timeout = 100; 560 if (in_le32(&pi->dbdma->status) & ACTIVE) {
471 while (in_le32(&pi->dbdma->status) & RUN && timeout--) 561 /* possible race here? */
472 udelay(1); 562 udelay(10);
473 if (timeout <= 0) { 563 if (in_le32(&pi->dbdma->status) & ACTIVE) {
474 printk(KERN_ERR 564 pi->dbdma_ring.stopping = 0;
475 "i2sbus: error waiting for dma reset\n"); 565 goto out_unlock; /* keep running */
476 result = -ENXIO; 566 }
477 goto out_unlock; 567 }
478 } 568 }
479 569
570 /* make sure RUN, PAUSE and S0 bits are cleared */
571 out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
572
573 /* set branch condition select register */
574 out_le32(&pi->dbdma->br_sel, (1 << 16) | 1);
575
480 /* write dma command buffer address to the dbdma chip */ 576 /* write dma command buffer address to the dbdma chip */
481 out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); 577 out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
482 /* post PCI write */
483 mb();
484 (void)in_le32(&pi->dbdma->status);
485
486 /* change first command to STOP */
487 tmp = *pi->dbdma_ring.cmds;
488 *pi->dbdma_ring.cmds = STOP_CMD;
489
490 /* set running state, remember that the first command is STOP */
491 out_le32(&pi->dbdma->control, RUN | (RUN << 16));
492 timeout = 100;
493 /* wait for STOP to be executed */
494 while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--)
495 udelay(1);
496 if (timeout <= 0) {
497 printk(KERN_ERR "i2sbus: error waiting for dma stop\n");
498 result = -ENXIO;
499 goto out_unlock;
500 }
501 /* again, write dma command buffer address to the dbdma chip,
502 * this time of the first real command */
503 *pi->dbdma_ring.cmds = tmp;
504 out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
505 /* post write */
506 mb();
507 (void)in_le32(&pi->dbdma->status);
508
509 /* reset dma engine again */
510 out_le32(&pi->dbdma->control,
511 0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
512 timeout = 100;
513 while (in_le32(&pi->dbdma->status) & RUN && timeout--)
514 udelay(1);
515 if (timeout <= 0) {
516 printk(KERN_ERR
517 "i2sbus: error waiting for dma reset\n");
518 result = -ENXIO;
519 goto out_unlock;
520 }
521 578
522 /* wake up the chip with the next descriptor */ 579 /* initialize the frame count and current period */
523 out_le32(&pi->dbdma->control, 580 pi->current_period = 0;
524 (RUN | WAKE) | ((RUN | WAKE) << 16));
525 /* get the frame count */
526 pi->frame_count = in_le32(&i2sdev->intfregs->frame_count); 581 pi->frame_count = in_le32(&i2sdev->intfregs->frame_count);
527 582
583 /* set the DMA controller running */
584 out_le32(&pi->dbdma->control, (RUN << 16) | RUN);
585
528 /* off you go! */ 586 /* off you go! */
529 break; 587 break;
588
530 case SNDRV_PCM_TRIGGER_STOP: 589 case SNDRV_PCM_TRIGGER_STOP:
531 case SNDRV_PCM_TRIGGER_SUSPEND: 590 case SNDRV_PCM_TRIGGER_SUSPEND:
532 if (!pi->dbdma_ring.running) { 591 if (!pi->dbdma_ring.running) {
533 result = -EALREADY; 592 result = -EALREADY;
534 goto out_unlock; 593 goto out_unlock;
535 } 594 }
595 pi->dbdma_ring.running = 0;
536 596
537 /* turn off all relevant bits */ 597 /* Set the S0 bit to make the DMA branch to the stop cmd */
538 out_le32(&pi->dbdma->control, 598 out_le32(&pi->dbdma->control, (1 << 16) | 1);
539 (RUN | WAKE | FLUSH | PAUSE) << 16); 599 pi->dbdma_ring.stopping = 1;
540 {
541 /* FIXME: move to own function */
542 int timeout = 5000;
543 while ((in_le32(&pi->dbdma->status) & RUN)
544 && --timeout > 0)
545 udelay(1);
546 if (!timeout)
547 printk(KERN_ERR
548 "i2sbus: timed out turning "
549 "off dbdma engine!\n");
550 }
551 600
552 pi->dbdma_ring.running = 0;
553 list_for_each_entry(cii, &i2sdev->sound.codec_list, list) 601 list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
554 if (cii->codec->stop) 602 if (cii->codec->stop)
555 cii->codec->stop(cii, pi->substream); 603 cii->codec->stop(cii, pi->substream);
@@ -574,70 +622,82 @@ static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
574 fc = in_le32(&i2sdev->intfregs->frame_count); 622 fc = in_le32(&i2sdev->intfregs->frame_count);
575 fc = fc - pi->frame_count; 623 fc = fc - pi->frame_count;
576 624
577 return (bytes_to_frames(pi->substream->runtime, 625 if (fc >= pi->substream->runtime->buffer_size)
578 pi->current_period * 626 fc %= pi->substream->runtime->buffer_size;
579 snd_pcm_lib_period_bytes(pi->substream)) 627 return fc;
580 + fc) % pi->substream->runtime->buffer_size;
581} 628}
582 629
583static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) 630static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
584{ 631{
585 struct pcm_info *pi; 632 struct pcm_info *pi;
586 u32 fc; 633 u32 fc, nframes;
587 u32 delta; 634 u32 status;
635 int timeout, i;
636 int dma_stopped = 0;
637 struct snd_pcm_runtime *runtime;
588 638
589 spin_lock(&i2sdev->low_lock); 639 spin_lock(&i2sdev->low_lock);
590 get_pcm_info(i2sdev, in, &pi, NULL); 640 get_pcm_info(i2sdev, in, &pi, NULL);
591 641 if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping)
592 if (!pi->dbdma_ring.running) {
593 /* there was still an interrupt pending
594 * while we stopped. or maybe another
595 * processor (not the one that was stopping
596 * the DMA engine) was spinning above
597 * waiting for the lock. */
598 goto out_unlock; 642 goto out_unlock;
599 }
600 643
601 fc = in_le32(&i2sdev->intfregs->frame_count); 644 i = pi->current_period;
602 /* a counter overflow does not change the calculation. */ 645 runtime = pi->substream->runtime;
603 delta = fc - pi->frame_count; 646 while (pi->dbdma_ring.cmds[i].xfer_status) {
604 647 if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT)
605 /* update current_period */ 648 /*
606 while (delta >= pi->substream->runtime->period_size) { 649 * BT is the branch taken bit. If it took a branch
607 pi->current_period++; 650 * it is because we set the S0 bit to make it
608 delta = delta - pi->substream->runtime->period_size; 651 * branch to the stop command.
609 } 652 */
610 653 dma_stopped = 1;
611 if (unlikely(delta)) { 654 pi->dbdma_ring.cmds[i].xfer_status = 0;
612 /* Some interrupt came late, so check the dbdma. 655
613 * This special case exists to syncronize the frame_count with 656 if (++i >= runtime->periods) {
614 * the dbdma transfer, but is hit every once in a while. */ 657 i = 0;
615 int period; 658 pi->frame_count += runtime->buffer_size;
616
617 period = (in_le32(&pi->dbdma->cmdptr)
618 - pi->dbdma_ring.bus_cmd_start)
619 / sizeof(struct dbdma_cmd);
620 pi->current_period = pi->current_period
621 % pi->substream->runtime->periods;
622
623 while (pi->current_period != period) {
624 pi->current_period++;
625 pi->current_period %= pi->substream->runtime->periods;
626 /* Set delta to zero, as the frame_count value is too
627 * high (otherwise the code path will not be executed).
628 * This corrects the fact that the frame_count is too
629 * low at the beginning due to buffering. */
630 delta = 0;
631 } 659 }
660 pi->current_period = i;
661
662 /*
663 * Check the frame count. The DMA tends to get a bit
664 * ahead of the frame counter, which confuses the core.
665 */
666 fc = in_le32(&i2sdev->intfregs->frame_count);
667 nframes = i * runtime->period_size;
668 if (fc < pi->frame_count + nframes)
669 pi->frame_count = fc - nframes;
632 } 670 }
633 671
634 pi->frame_count = fc - delta; 672 if (dma_stopped) {
635 pi->current_period %= pi->substream->runtime->periods; 673 timeout = 1000;
674 for (;;) {
675 status = in_le32(&pi->dbdma->status);
676 if (!(status & ACTIVE) && (!in || (status & 0x80)))
677 break;
678 if (--timeout <= 0) {
679 printk(KERN_ERR "i2sbus: timed out "
680 "waiting for DMA to stop!\n");
681 break;
682 }
683 udelay(1);
684 }
685
686 /* Turn off DMA controller, clear S0 bit */
687 out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
636 688
689 pi->dbdma_ring.stopping = 0;
690 if (pi->stop_completion)
691 complete(pi->stop_completion);
692 }
693
694 if (!pi->dbdma_ring.running)
695 goto out_unlock;
637 spin_unlock(&i2sdev->low_lock); 696 spin_unlock(&i2sdev->low_lock);
638 /* may call _trigger again, hence needs to be unlocked */ 697 /* may call _trigger again, hence needs to be unlocked */
639 snd_pcm_period_elapsed(pi->substream); 698 snd_pcm_period_elapsed(pi->substream);
640 return; 699 return;
700
641 out_unlock: 701 out_unlock:
642 spin_unlock(&i2sdev->low_lock); 702 spin_unlock(&i2sdev->low_lock);
643} 703}
@@ -718,7 +778,7 @@ static struct snd_pcm_ops i2sbus_playback_ops = {
718 .close = i2sbus_playback_close, 778 .close = i2sbus_playback_close,
719 .ioctl = snd_pcm_lib_ioctl, 779 .ioctl = snd_pcm_lib_ioctl,
720 .hw_params = i2sbus_hw_params, 780 .hw_params = i2sbus_hw_params,
721 .hw_free = i2sbus_hw_free, 781 .hw_free = i2sbus_playback_hw_free,
722 .prepare = i2sbus_playback_prepare, 782 .prepare = i2sbus_playback_prepare,
723 .trigger = i2sbus_playback_trigger, 783 .trigger = i2sbus_playback_trigger,
724 .pointer = i2sbus_playback_pointer, 784 .pointer = i2sbus_playback_pointer,
@@ -788,7 +848,7 @@ static struct snd_pcm_ops i2sbus_record_ops = {
788 .close = i2sbus_record_close, 848 .close = i2sbus_record_close,
789 .ioctl = snd_pcm_lib_ioctl, 849 .ioctl = snd_pcm_lib_ioctl,
790 .hw_params = i2sbus_hw_params, 850 .hw_params = i2sbus_hw_params,
791 .hw_free = i2sbus_hw_free, 851 .hw_free = i2sbus_record_hw_free,
792 .prepare = i2sbus_record_prepare, 852 .prepare = i2sbus_record_prepare,
793 .trigger = i2sbus_record_trigger, 853 .trigger = i2sbus_record_trigger,
794 .pointer = i2sbus_record_pointer, 854 .pointer = i2sbus_record_pointer,
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
index ec20ee615d7f..ff29654782c9 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus.h
+++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
@@ -10,6 +10,7 @@
10#include <linux/interrupt.h> 10#include <linux/interrupt.h>
11#include <linux/spinlock.h> 11#include <linux/spinlock.h>
12#include <linux/mutex.h> 12#include <linux/mutex.h>
13#include <linux/completion.h>
13 14
14#include <sound/pcm.h> 15#include <sound/pcm.h>
15 16
@@ -34,6 +35,7 @@ struct dbdma_command_mem {
34 void *space; 35 void *space;
35 int size; 36 int size;
36 u32 running:1; 37 u32 running:1;
38 u32 stopping:1;
37}; 39};
38 40
39struct pcm_info { 41struct pcm_info {
@@ -45,6 +47,7 @@ struct pcm_info {
45 u32 frame_count; 47 u32 frame_count;
46 struct dbdma_command_mem dbdma_ring; 48 struct dbdma_command_mem dbdma_ring;
47 volatile struct dbdma_regs __iomem *dbdma; 49 volatile struct dbdma_regs __iomem *dbdma;
50 struct completion *stop_completion;
48}; 51};
49 52
50enum { 53enum {
@@ -101,6 +104,9 @@ i2sbus_tx_intr(int irq, void *devid);
101extern irqreturn_t 104extern irqreturn_t
102i2sbus_rx_intr(int irq, void *devid); 105i2sbus_rx_intr(int irq, void *devid);
103 106
107extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev);
108extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev);
109
104/* control specific functions */ 110/* control specific functions */
105extern int i2sbus_control_init(struct macio_dev* dev, 111extern int i2sbus_control_init(struct macio_dev* dev,
106 struct i2sbus_control **c); 112 struct i2sbus_control **c);