diff options
author | Kuninori Morimoto <morimoto.kuninori@renesas.com> | 2009-10-29 23:02:44 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-10-30 06:35:30 -0400 |
commit | 07102f3cefc93aa742af91186830e282c0347e41 (patch) | |
tree | 417731c7492ecabed293bc82177dd6efbbb4eb9b /sound/soc/sh | |
parent | 9ddc9aa910687a8787dbbdc53dcd48e738b197d9 (diff) |
ASoC: sh: FSI: Add capture support
Signed-off-by: Kuninori Morimoto <morimoto.kuninori@renesas.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/sh')
-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 | }; |