diff options
| -rw-r--r-- | sound/soc/sh/fsi.c | 93 |
1 files changed, 86 insertions, 7 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 9742a280ba15..e1a3d1a2b4c8 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
| @@ -447,6 +447,75 @@ static int fsi_data_push(struct fsi_priv *fsi) | |||
| 447 | return 0; | 447 | return 0; |
| 448 | } | 448 | } |
| 449 | 449 | ||
| 450 | static int fsi_data_pop(struct fsi_priv *fsi) | ||
| 451 | { | ||
| 452 | struct snd_pcm_runtime *runtime; | ||
| 453 | struct snd_pcm_substream *substream = NULL; | ||
| 454 | int free; | ||
| 455 | int fifo_fill; | ||
| 456 | int width; | ||
| 457 | u8 *start; | ||
| 458 | int i; | ||
| 459 | |||
| 460 | if (!fsi || | ||
| 461 | !fsi->substream || | ||
| 462 | !fsi->substream->runtime) | ||
| 463 | return -EINVAL; | ||
| 464 | |||
| 465 | runtime = fsi->substream->runtime; | ||
| 466 | |||
| 467 | /* FSI FIFO has limit. | ||
| 468 | * So, this driver can not send periods data at a time | ||
| 469 | */ | ||
| 470 | if (fsi->byte_offset >= | ||
| 471 | fsi->period_len * (fsi->periods + 1)) { | ||
| 472 | |||
| 473 | substream = fsi->substream; | ||
| 474 | fsi->periods = (fsi->periods + 1) % runtime->periods; | ||
| 475 | |||
| 476 | if (0 == fsi->periods) | ||
| 477 | fsi->byte_offset = 0; | ||
| 478 | } | ||
| 479 | |||
| 480 | /* get 1 channel data width */ | ||
| 481 | width = frames_to_bytes(runtime, 1) / fsi->chan; | ||
| 482 | |||
| 483 | /* get free space for alsa */ | ||
| 484 | free = (fsi->buffer_len - fsi->byte_offset) / width; | ||
| 485 | |||
| 486 | /* get recv size */ | ||
| 487 | fifo_fill = fsi_get_fifo_residue(fsi, 0); | ||
| 488 | |||
| 489 | if (free < fifo_fill) | ||
| 490 | fifo_fill = free; | ||
| 491 | |||
| 492 | start = runtime->dma_area; | ||
| 493 | start += fsi->byte_offset; | ||
| 494 | |||
| 495 | switch (width) { | ||
| 496 | case 2: | ||
| 497 | for (i = 0; i < fifo_fill; i++) | ||
| 498 | *((u16 *)start + i) = | ||
| 499 | (u16)(fsi_reg_read(fsi, DIDT) >> 8); | ||
| 500 | break; | ||
| 501 | case 4: | ||
| 502 | for (i = 0; i < fifo_fill; i++) | ||
| 503 | *((u32 *)start + i) = fsi_reg_read(fsi, DIDT); | ||
| 504 | break; | ||
| 505 | default: | ||
| 506 | return -EINVAL; | ||
| 507 | } | ||
| 508 | |||
| 509 | fsi->byte_offset += fifo_fill * width; | ||
| 510 | |||
| 511 | fsi_irq_enable(fsi, 0); | ||
| 512 | |||
| 513 | if (substream) | ||
| 514 | snd_pcm_period_elapsed(substream); | ||
| 515 | |||
| 516 | return 0; | ||
| 517 | } | ||
| 518 | |||
| 450 | static irqreturn_t fsi_interrupt(int irq, void *data) | 519 | static irqreturn_t fsi_interrupt(int irq, void *data) |
| 451 | { | 520 | { |
| 452 | u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; | 521 | u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; |
| @@ -460,6 +529,10 @@ static irqreturn_t fsi_interrupt(int irq, void *data) | |||
| 460 | fsi_data_push(&master->fsia); | 529 | fsi_data_push(&master->fsia); |
| 461 | if (int_st & INT_B_OUT) | 530 | if (int_st & INT_B_OUT) |
| 462 | fsi_data_push(&master->fsib); | 531 | fsi_data_push(&master->fsib); |
| 532 | if (int_st & INT_A_IN) | ||
| 533 | fsi_data_pop(&master->fsia); | ||
| 534 | if (int_st & INT_B_IN) | ||
| 535 | fsi_data_pop(&master->fsib); | ||
| 463 | 536 | ||
| 464 | fsi_master_write(INT_ST, 0x0000000); | 537 | fsi_master_write(INT_ST, 0x0000000); |
| 465 | 538 | ||
| @@ -612,16 +685,12 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
| 612 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 685 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
| 613 | int ret = 0; | 686 | int ret = 0; |
| 614 | 687 | ||
| 615 | /* capture not supported */ | ||
| 616 | if (!is_play) | ||
| 617 | return -ENODEV; | ||
| 618 | |||
| 619 | switch (cmd) { | 688 | switch (cmd) { |
| 620 | case SNDRV_PCM_TRIGGER_START: | 689 | case SNDRV_PCM_TRIGGER_START: |
| 621 | fsi_stream_push(fsi, substream, | 690 | fsi_stream_push(fsi, substream, |
| 622 | frames_to_bytes(runtime, runtime->buffer_size), | 691 | frames_to_bytes(runtime, runtime->buffer_size), |
| 623 | frames_to_bytes(runtime, runtime->period_size)); | 692 | frames_to_bytes(runtime, runtime->period_size)); |
| 624 | ret = fsi_data_push(fsi); | 693 | ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); |
| 625 | break; | 694 | break; |
| 626 | case SNDRV_PCM_TRIGGER_STOP: | 695 | case SNDRV_PCM_TRIGGER_STOP: |
| 627 | fsi_irq_disable(fsi, is_play); | 696 | fsi_irq_disable(fsi, is_play); |
| @@ -757,7 +826,12 @@ struct snd_soc_dai fsi_soc_dai[] = { | |||
| 757 | .channels_min = 1, | 826 | .channels_min = 1, |
| 758 | .channels_max = 8, | 827 | .channels_max = 8, |
| 759 | }, | 828 | }, |
| 760 | /* capture not supported */ | 829 | .capture = { |
| 830 | .rates = FSI_RATES, | ||
| 831 | .formats = FSI_FMTS, | ||
| 832 | .channels_min = 1, | ||
| 833 | .channels_max = 8, | ||
| 834 | }, | ||
| 761 | .ops = &fsi_dai_ops, | 835 | .ops = &fsi_dai_ops, |
| 762 | }, | 836 | }, |
| 763 | { | 837 | { |
| @@ -769,7 +843,12 @@ struct snd_soc_dai fsi_soc_dai[] = { | |||
| 769 | .channels_min = 1, | 843 | .channels_min = 1, |
| 770 | .channels_max = 8, | 844 | .channels_max = 8, |
| 771 | }, | 845 | }, |
| 772 | /* capture not supported */ | 846 | .capture = { |
| 847 | .rates = FSI_RATES, | ||
| 848 | .formats = FSI_FMTS, | ||
| 849 | .channels_min = 1, | ||
| 850 | .channels_max = 8, | ||
| 851 | }, | ||
| 773 | .ops = &fsi_dai_ops, | 852 | .ops = &fsi_dai_ops, |
| 774 | }, | 853 | }, |
| 775 | }; | 854 | }; |
