diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus-core.c | 22 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | 328 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus.h | 6 |
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 | ||
249 | static 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 | ||
282 | void 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 | |||
248 | static int i2sbus_hw_params(struct snd_pcm_substream *substream, | 293 | static 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 | ||
254 | static int i2sbus_hw_free(struct snd_pcm_substream *substream) | 299 | static 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 | ||
311 | static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream) | ||
312 | { | ||
313 | return i2sbus_hw_free(substream, 0); | ||
314 | } | ||
315 | |||
316 | static int i2sbus_record_hw_free(struct snd_pcm_substream *substream) | ||
317 | { | ||
318 | return i2sbus_hw_free(substream, 1); | ||
319 | } | ||
320 | |||
260 | static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | 321 | static 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 | ||
438 | static struct dbdma_cmd STOP_CMD = { | 526 | #ifdef CONFIG_PM |
439 | .command = __constant_cpu_to_le16(DBDMA_STOP), | 527 | void 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 | ||
442 | static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) | 534 | static 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 | ||
583 | static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) | 630 | static 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 | ||
39 | struct pcm_info { | 41 | struct 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 | ||
50 | enum { | 53 | enum { |
@@ -101,6 +104,9 @@ i2sbus_tx_intr(int irq, void *devid); | |||
101 | extern irqreturn_t | 104 | extern irqreturn_t |
102 | i2sbus_rx_intr(int irq, void *devid); | 105 | i2sbus_rx_intr(int irq, void *devid); |
103 | 106 | ||
107 | extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev); | ||
108 | extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev); | ||
109 | |||
104 | /* control specific functions */ | 110 | /* control specific functions */ |
105 | extern int i2sbus_control_init(struct macio_dev* dev, | 111 | extern int i2sbus_control_init(struct macio_dev* dev, |
106 | struct i2sbus_control **c); | 112 | struct i2sbus_control **c); |